feat: search, player detail, shop detail, order flow, chat, review, and dispute pages

This commit is contained in:
zetaloop
2026-02-20 15:10:31 +08:00
parent e2b47681a3
commit 6ae5e533c1
10 changed files with 1865 additions and 34 deletions
+172 -4
View File
@@ -1,8 +1,176 @@
export default function DisputePage({ params: _params }: { params: Promise<{ id: string }> }) {
"use client"
import { AlertTriangle, ArrowLeft, Clock, FileText } from "lucide-react"
import Link from "next/link"
import { use, 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 { Label } from "@/components/ui/label"
import { Separator } from "@/components/ui/separator"
import { Textarea } from "@/components/ui/textarea"
import { mockDisputes, mockOrders } from "@/lib/mock-data"
const disputeStatusLabels: Record<string, string> = {
open: "已提交",
reviewing: "审核中",
resolved: "已解决",
appealed: "申诉中",
}
export default function DisputePage({ params }: { params: Promise<{ id: string }> }) {
const { id } = use(params)
const order = mockOrders.find((o) => o.id === id)
const existingDispute = mockDisputes.find((d) => d.orderId === id)
const [reason, setReason] = useState("")
const [submitted, setSubmitted] = useState(false)
if (!order) {
return (
<div className="container mx-auto py-8 px-4 text-center text-muted-foreground">
</div>
)
}
if (existingDispute) {
return (
<div className="container mx-auto py-8 px-4 max-w-lg">
<Link
href={`/order/${id}`}
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4"
>
<ArrowLeft className="h-4 w-4" />
</Link>
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle></CardTitle>
<Badge variant="outline">{disputeStatusLabels[existingDispute.status]}</Badge>
</div>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<div className="flex items-center gap-2 text-sm">
<FileText className="h-4 w-4 text-muted-foreground" />
<span className="text-muted-foreground">:</span>
{existingDispute.initiatorName}
</div>
<div className="flex items-center gap-2 text-sm">
<Clock className="h-4 w-4 text-muted-foreground" />
<span className="text-muted-foreground">:</span>
{new Date(existingDispute.createdAt).toLocaleString("zh-CN")}
</div>
</div>
<Separator />
<div>
<Label className="text-muted-foreground"></Label>
<p className="mt-1 text-sm">{existingDispute.reason}</p>
</div>
{existingDispute.evidence.length > 0 && (
<div>
<Label className="text-muted-foreground"></Label>
<div className="mt-1 flex gap-2">
{existingDispute.evidence.map((url) => (
<div
key={url}
className="h-20 w-20 rounded border bg-muted flex items-center justify-center text-xs text-muted-foreground"
>
</div>
))}
</div>
</div>
)}
{existingDispute.result && (
<>
<Separator />
<div>
<Label className="text-muted-foreground"></Label>
<p className="mt-1 text-sm font-medium">
{existingDispute.result === "full_refund"
? "全额退款"
: existingDispute.result === "full_payment"
? "全额支付给打手"
: "部分退款"}
</p>
</div>
</>
)}
</CardContent>
</Card>
</div>
)
}
if (submitted) {
return (
<div className="container mx-auto py-8 px-4 max-w-lg text-center space-y-4">
<AlertTriangle className="h-12 w-12 mx-auto text-yellow-500" />
<h2 className="text-xl font-bold"></h2>
<p className="text-sm text-muted-foreground">
3 使
</p>
<Button asChild>
<Link href={`/order/${id}`}></Link>
</Button>
</div>
)
}
return (
<div className="container mx-auto py-8 px-4">
<h1 className="text-2xl font-bold"></h1>
<p className="mt-2 text-muted-foreground"></p>
<div className="container mx-auto py-8 px-4 max-w-lg">
<Link
href={`/order/${id}`}
className="inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-4"
>
<ArrowLeft className="h-4 w-4" />
</Link>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<AlertTriangle className="h-5 w-5 text-yellow-500" />
</CardTitle>
<p className="text-sm text-muted-foreground">
{order.service.title} · {order.playerName}
</p>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="dispute-reason"></Label>
<Textarea
id="dispute-reason"
placeholder="请详细描述你遇到的问题..."
value={reason}
onChange={(e) => setReason(e.target.value)}
rows={4}
/>
</div>
<div className="space-y-2">
<Label></Label>
<div className="border-2 border-dashed rounded-md p-6 text-center text-sm text-muted-foreground">
5
</div>
</div>
<div className="rounded-md bg-muted/50 p-3 text-xs text-muted-foreground space-y-1">
<p>· </p>
<p>· </p>
<p>· 3 </p>
<p>· </p>
</div>
<Button className="w-full" disabled={!reason.trim()} onClick={() => setSubmitted(true)}>
</Button>
</CardContent>
</Card>
</div>
)
}