d0d21fa935
Unify user-facing role terminology by replacing 消费者 with 客户 while keeping role keys unchanged. This aligns account settings, header role switch, global role labels, and order list role text.
189 lines
7.2 KiB
TypeScript
189 lines
7.2 KiB
TypeScript
"use client"
|
|
|
|
import { Clock, MessageSquare, RefreshCw } from "lucide-react"
|
|
import Link from "next/link"
|
|
import { useEffect, 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 { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
import { statusLabels } from "@/lib/constants"
|
|
import type { OrderStatus, UserRole } from "@/lib/types"
|
|
import { cn } from "@/lib/utils"
|
|
import { useAuthStore } from "@/store/auth"
|
|
import { useChatStore } from "@/store/chat"
|
|
import { useOrderStore } from "@/store/orders"
|
|
|
|
const statusColors: Record<OrderStatus, string> = {
|
|
pending_payment: "bg-yellow-100 text-yellow-800",
|
|
pending_accept: "bg-blue-100 text-blue-800",
|
|
in_progress: "bg-green-100 text-green-800",
|
|
pending_close: "bg-orange-100 text-orange-800",
|
|
pending_review: "bg-purple-100 text-purple-800",
|
|
disputed: "bg-red-100 text-red-800",
|
|
completed: "bg-gray-100 text-gray-800",
|
|
cancelled: "bg-gray-100 text-gray-500",
|
|
}
|
|
|
|
type TabFilter = "all" | "active" | "completed" | "disputed"
|
|
|
|
const consumerTabs = [
|
|
{ value: "all", label: "全部" },
|
|
{ value: "active", label: "进行中" },
|
|
{ value: "completed", label: "已完成" },
|
|
{ value: "disputed", label: "争议" },
|
|
]
|
|
|
|
const playerTabs = [
|
|
{ value: "all", label: "全部" },
|
|
{ value: "pending", label: "待接单" },
|
|
{ value: "active", label: "进行中" },
|
|
{ value: "completed", label: "已完成" },
|
|
]
|
|
|
|
const ownerTabs = [
|
|
{ value: "all", label: "全部" },
|
|
{ value: "pending", label: "待派单" },
|
|
{ value: "active", label: "进行中" },
|
|
{ value: "completed", label: "已完成" },
|
|
{ value: "disputed", label: "争议" },
|
|
]
|
|
|
|
export default function OrderListPage() {
|
|
const { currentRole, user } = useAuthStore()
|
|
const userId = user?.id ?? "u1"
|
|
|
|
return <OrderListContent key={currentRole} currentRole={currentRole} userId={userId} />
|
|
}
|
|
|
|
function OrderListContent({ currentRole, userId }: { currentRole: UserRole; userId: string }) {
|
|
const [tab, setTab] = useState<TabFilter | "pending">("all")
|
|
const orders = useOrderStore((state) => state.orders)
|
|
const sessions = useChatStore((state) => state.sessions)
|
|
const ensureOrderSession = useChatStore((state) => state.ensureOrderSession)
|
|
const ownerShopId = "shop1"
|
|
|
|
const tabs =
|
|
currentRole === "consumer" ? consumerTabs : currentRole === "player" ? playerTabs : ownerTabs
|
|
|
|
useEffect(() => {
|
|
orders.forEach((order) => {
|
|
if (order.status === "pending_payment" || order.status === "cancelled") return
|
|
ensureOrderSession(order)
|
|
})
|
|
}, [orders, ensureOrderSession])
|
|
|
|
const roleFiltered = orders.filter((order) => {
|
|
if (currentRole === "consumer") return order.consumerId === userId
|
|
if (currentRole === "player") return order.playerId === userId
|
|
return order.shopId === ownerShopId
|
|
})
|
|
|
|
const filtered = roleFiltered.filter((order) => {
|
|
if (tab === "pending") return order.status === "pending_accept"
|
|
if (tab === "active") {
|
|
return [
|
|
"pending_payment",
|
|
"pending_accept",
|
|
"in_progress",
|
|
"pending_close",
|
|
"pending_review",
|
|
].includes(order.status)
|
|
}
|
|
if (tab === "completed") return order.status === "completed" || order.status === "cancelled"
|
|
if (tab === "disputed") return order.status === "disputed"
|
|
return true
|
|
})
|
|
|
|
return (
|
|
<div className="container mx-auto py-8 px-4">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<h1 className="text-2xl font-bold">我的订单</h1>
|
|
<Badge variant="outline" className="text-xs">
|
|
{currentRole === "consumer"
|
|
? "客户视角"
|
|
: currentRole === "player"
|
|
? "打手视角"
|
|
: "店主视角"}
|
|
</Badge>
|
|
</div>
|
|
|
|
<Tabs value={tab} onValueChange={(v) => setTab(v as TabFilter | "pending")}>
|
|
<TabsList>
|
|
{tabs.map((item) => (
|
|
<TabsTrigger key={item.value} value={item.value}>
|
|
{item.label}
|
|
</TabsTrigger>
|
|
))}
|
|
</TabsList>
|
|
|
|
<TabsContent value={tab} className="mt-4 space-y-3">
|
|
{filtered.length === 0 ? (
|
|
<div className="text-center py-12 text-muted-foreground">暂无订单</div>
|
|
) : (
|
|
filtered.map((order) => (
|
|
<Card key={order.id}>
|
|
<CardHeader className="pb-3">
|
|
<div className="flex items-center justify-between">
|
|
<CardTitle className="text-base">{order.service.title}</CardTitle>
|
|
<Badge className={cn("text-xs", statusColors[order.status])}>
|
|
{statusLabels[order.status]}
|
|
</Badge>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
{currentRole === "consumer"
|
|
? `打手: ${order.playerName}`
|
|
: currentRole === "player"
|
|
? `客户: ${order.consumerName}`
|
|
: `客户: ${order.consumerName} · 打手: ${order.playerName}`}
|
|
</p>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
|
<span className="font-medium text-foreground">¥{order.totalPrice}</span>
|
|
<span className="flex items-center gap-1">
|
|
<Clock className="h-3.5 w-3.5" />
|
|
{new Date(order.createdAt).toLocaleDateString("zh-CN")}
|
|
</span>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
{(() => {
|
|
if (order.status !== "in_progress" && order.status !== "pending_close")
|
|
return null
|
|
const session = sessions.find(
|
|
(item) => item.type === "order" && item.orderId === order.id,
|
|
)
|
|
if (!session) return null
|
|
return (
|
|
<Button variant="outline" size="sm" asChild>
|
|
<Link href={`/chat/${session.id}`}>
|
|
<MessageSquare className="mr-1 h-3.5 w-3.5" />
|
|
聊天
|
|
</Link>
|
|
</Button>
|
|
)
|
|
})()}
|
|
{order.status === "completed" && (
|
|
<Button variant="outline" size="sm" asChild>
|
|
<Link href={`/order/new?serviceId=${order.service.id}`}>
|
|
<RefreshCw className="mr-1 h-3.5 w-3.5" />
|
|
再来一单
|
|
</Link>
|
|
</Button>
|
|
)}
|
|
<Button size="sm" asChild>
|
|
<Link href={`/order/${order.id}`}>查看详情</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))
|
|
)}
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
)
|
|
}
|