From 1f2dc1434bbc7c0977e400ef5a2fbd0c1d66ee5d Mon Sep 17 00:00:00 2001 From: zetaloop Date: Sun, 22 Feb 2026 15:21:32 +0800 Subject: [PATCH] fix(dispute): enforce participant checks and phase constraints --- app/(order)/dispute/[id]/page.tsx | 45 ++++++++-- store/disputes.ts | 144 ++++++++++++++++++++++++++---- 2 files changed, 164 insertions(+), 25 deletions(-) diff --git a/app/(order)/dispute/[id]/page.tsx b/app/(order)/dispute/[id]/page.tsx index 30a387d..455cf9f 100644 --- a/app/(order)/dispute/[id]/page.tsx +++ b/app/(order)/dispute/[id]/page.tsx @@ -17,6 +17,7 @@ import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { DISPUTE_TO_RESOLVED_MS } from "@/lib/config/demo-timers" +import { notifyInfo } from "@/lib/toast" import { Label } from "@/components/ui/label" import { Separator } from "@/components/ui/separator" import { Textarea } from "@/components/ui/textarea" @@ -108,13 +109,17 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } const handleSubmit = () => { if (!userId || !userName || !reason.trim()) return - submitDispute({ + const result = submitDispute({ orderId: id, initiatorId: userId, initiatorName: userName, reason, evidence: files, }) + if (!result.decision.ok) { + notifyInfo(result.decision.message ?? "提交争议失败") + return + } router.replace(`/dispute/${id}?submitted=1`) } @@ -128,13 +133,26 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } ) } + const isParticipant = Boolean( + userId && (order.consumerId === userId || order.playerId === userId), + ) + if (!isParticipant) { + return ( +
+ 仅该订单参与方可访问争议页面 +
+ ) + } + if (existingDispute) { const isInitiator = userId === existingDispute.initiatorId const canRespond = + isParticipant && !isInitiator && !existingDispute.respondentReason && (existingDispute.status === "open" || existingDispute.status === "reviewing") - const canAppeal = existingDispute.status === "resolved" && !existingDispute.appealedAt + const canAppeal = + isParticipant && existingDispute.status === "resolved" && !existingDispute.appealedAt return (
@@ -267,9 +285,18 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }
)}