"use client" import { AlertTriangle, ArrowLeft, Clock, FileText, Upload, X } from "lucide-react" import Image from "next/image" import Link from "next/link" import { useRouter, useSearchParams } from "next/navigation" import { type ChangeEvent, type Dispatch, type SetStateAction, use, useEffect, useRef, useState, } from "react" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { submitDispute, submitDisputeAppeal, submitDisputeResponse } from "@/lib/api/disputes" 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" import { useAuthStore } from "@/store/auth" import { useDisputeStore } from "@/store/disputes" import { useOrderStore } from "@/store/orders" const disputeStatusLabels: Record = { open: "已提交", reviewing: "审核中", resolved: "已解决", appealed: "申诉中", } export default function DisputePage({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params) const router = useRouter() const searchParams = useSearchParams() const order = useOrderStore((state) => state.orders.find((item) => item.id === id)) const userId = useAuthStore((state) => state.user?.id) const existingDispute = useDisputeStore((state) => state.getDisputeByOrderId(id)) const [reason, setReason] = useState("") const [files, setFiles] = useState([]) const [responseReason, setResponseReason] = useState("") const [responseFiles, setResponseFiles] = useState([]) const [appealReason, setAppealReason] = useState("") const fileInputRef = useRef(null) const responseFileInputRef = useRef(null) const filesRef = useRef([]) const responseFilesRef = useRef([]) useEffect(() => { filesRef.current = files }, [files]) useEffect(() => { responseFilesRef.current = responseFiles }, [responseFiles]) useEffect( () => () => { filesRef.current.forEach((url) => { URL.revokeObjectURL(url) }) responseFilesRef.current.forEach((url) => { URL.revokeObjectURL(url) }) }, [], ) const handleFileSelect = ( event: ChangeEvent, setter: Dispatch>, ) => { const selectedFiles = event.target.files if (!selectedFiles?.length) return setter((prev) => { const remaining = 5 - prev.length if (remaining <= 0) return prev const nextUrls = Array.from(selectedFiles) .slice(0, remaining) .map((file) => URL.createObjectURL(file)) return [...prev, ...nextUrls] }) event.target.value = "" } const removeFile = ( index: number, filesState: string[], setter: Dispatch>, ) => { const removed = filesState[index] if (removed) { URL.revokeObjectURL(removed) } setter((prev) => prev.filter((_, currentIndex) => currentIndex !== index)) } const handleSubmit = () => { if (!userId || !reason.trim()) return const result = submitDispute({ orderId: id, reason, evidence: files, }) if (!result.decision.ok) { notifyInfo(result.decision.message ?? "提交争议失败") return } router.replace(`/dispute/${id}?submitted=1`) } const showSubmitted = searchParams.get("submitted") === "1" && !existingDispute if (!order) { return (
订单不存在
) } 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 = isParticipant && existingDispute.status === "resolved" && !existingDispute.appealedAt return (
返回订单
争议详情 {disputeStatusLabels[existingDispute.status]}
发起人: {existingDispute.initiatorName}
提交时间: {new Date(existingDispute.createdAt).toLocaleString("zh-CN")}

{existingDispute.reason}

{existingDispute.evidence.length > 0 && (
{existingDispute.evidence.map((url) => (
发起方证据
))}
)}
{existingDispute.respondentReason ? ( <>

{existingDispute.respondentReason}

{existingDispute.respondentEvidence.length > 0 && (
{existingDispute.respondentEvidence.map((url) => (
对方证据
))}
)} ) : (

对方暂未提交回应材料。

)}
{canRespond && ( <>