diff --git a/app/(order)/chat/[id]/page.tsx b/app/(order)/chat/[id]/page.tsx index 8ffb756..c8b06c9 100644 --- a/app/(order)/chat/[id]/page.tsx +++ b/app/(order)/chat/[id]/page.tsx @@ -8,14 +8,15 @@ import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { ScrollArea } from "@/components/ui/scroll-area" -import { mockChatMessages, mockChatSessions } from "@/lib/mock" import { cn } from "@/lib/utils" import { useAuthStore } from "@/store/auth" +import { useChatStore } from "@/store/chat" export default function ChatDetailPage({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params) - const session = mockChatSessions.find((s) => s.id === id) - const messages = mockChatMessages.filter((m) => m.sessionId === id) + const session = useChatStore((state) => state.sessions.find((item) => item.id === id)) + const messages = useChatStore((state) => state.messages.filter((item) => item.sessionId === id)) + const sendTextMessage = useChatStore((state) => state.sendTextMessage) const [input, setInput] = useState("") const { user } = useAuthStore() @@ -103,6 +104,21 @@ export default function ChatDetailPage({ params }: { params: Promise<{ id: strin className="flex gap-2 max-w-2xl mx-auto" onSubmit={(e) => { e.preventDefault() + const text = input.trim() + if (!text) return + + const sender = session.participants.find( + (participant) => participant.id === currentUserId, + ) + sendTextMessage( + session.id, + { + id: currentUserId, + name: sender?.name ?? user?.nickname ?? "", + avatar: sender?.avatar ?? user?.avatar ?? "", + }, + text, + ) setInput("") }} > diff --git a/app/(order)/chat/page.tsx b/app/(order)/chat/page.tsx index 5e2c608..c61572d 100644 --- a/app/(order)/chat/page.tsx +++ b/app/(order)/chat/page.tsx @@ -1,18 +1,26 @@ +"use client" + import { Lock, MessageSquare } from "lucide-react" import Link from "next/link" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" import { Card, CardContent } from "@/components/ui/card" -import { mockChatSessions } from "@/lib/mock" +import { useAuthStore } from "@/store/auth" +import { useChatStore } from "@/store/chat" export default function ChatListPage() { + const sessions = useChatStore((state) => state.sessions) + const userId = useAuthStore((state) => state.user?.id) + return (

消息

- {mockChatSessions.map((session) => { - const other = session.participants[1] + {sessions.map((session) => { + const other = + session.participants.find((participant) => participant.id !== userId) ?? + session.participants[0] return ( @@ -49,7 +57,7 @@ export default function ChatListPage() { ) })} - {mockChatSessions.length === 0 && ( + {sessions.length === 0 && (
暂无消息 diff --git a/app/(order)/dispute/[id]/page.tsx b/app/(order)/dispute/[id]/page.tsx index ec87c45..6a6fcad 100644 --- a/app/(order)/dispute/[id]/page.tsx +++ b/app/(order)/dispute/[id]/page.tsx @@ -11,7 +11,8 @@ 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" +import { mockDisputes } from "@/lib/mock" +import { useOrderStore } from "@/store/orders" const disputeStatusLabels: Record = { open: "已提交", @@ -24,7 +25,8 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } const { id } = use(params) const router = useRouter() const searchParams = useSearchParams() - const order = mockOrders.find((o) => o.id === id) + const order = useOrderStore((state) => state.orders.find((item) => item.id === id)) + const updateOrderStatus = useOrderStore((state) => state.updateOrderStatus) const existingDispute = mockDisputes.find((d) => d.orderId === id) const [reason, setReason] = useState("") const [submitted, setSubmitted] = useState(false) @@ -70,6 +72,7 @@ export default function DisputePage({ params }: { params: Promise<{ id: string } } const handleSubmit = () => { + updateOrderStatus(id, "disputed") setSubmitted(true) router.replace(`/dispute/${id}?submitted=1`) } diff --git a/app/(order)/order/[id]/page.tsx b/app/(order)/order/[id]/page.tsx index 88c103e..c400364 100644 --- a/app/(order)/order/[id]/page.tsx +++ b/app/(order)/order/[id]/page.tsx @@ -1,13 +1,17 @@ +"use client" + import { ArrowLeft, CheckCircle, Clock, Star } from "lucide-react" import Link from "next/link" -import { notFound } from "next/navigation" +import { use, useEffect } from "react" import OrderActions from "@/components/order-actions" import { Badge } from "@/components/ui/badge" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Separator } from "@/components/ui/separator" import { statusLabels } from "@/lib/constants" -import { mockChatSessions, mockOrders, mockReviews } from "@/lib/mock" +import { mockReviews } from "@/lib/mock" import type { OrderStatus } from "@/lib/types" +import { useChatStore } from "@/store/chat" +import { useOrderStore } from "@/store/orders" const normalStatusSteps: OrderStatus[] = [ "pending_payment", @@ -28,13 +32,28 @@ const disputedStatusSteps: OrderStatus[] = [ const cancelledStatusSteps: OrderStatus[] = ["pending_payment", "pending_accept", "cancelled"] -export default async function OrderDetailPage({ params }: { params: Promise<{ id: string }> }) { - const { id } = await params - const order = mockOrders.find((o) => o.id === id) - if (!order) notFound() +export default function OrderDetailPage({ params }: { params: Promise<{ id: string }> }) { + const { id } = use(params) + const order = useOrderStore((state) => state.orders.find((item) => item.id === id)) + const sessions = useChatStore((state) => state.sessions) + const ensureOrderSession = useChatStore((state) => state.ensureOrderSession) + + useEffect(() => { + if (!order) return + if (order.status === "pending_payment" || order.status === "cancelled") return + ensureOrderSession(order) + }, [order, ensureOrderSession]) + + if (!order) { + return ( +
+ 订单不存在 +
+ ) + } const reviews = mockReviews.filter((r) => r.orderId === id) - const chatSession = mockChatSessions.find((s) => s.orderId === id) + const chatSession = sessions.find((session) => session.type === "order" && session.orderId === id) const statusSteps = order.status === "disputed" ? disputedStatusSteps diff --git a/app/(order)/order/new/page.tsx b/app/(order)/order/new/page.tsx index 15424db..17586cc 100644 --- a/app/(order)/order/new/page.tsx +++ b/app/(order)/order/new/page.tsx @@ -11,8 +11,11 @@ import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Separator } from "@/components/ui/separator" import { Textarea } from "@/components/ui/textarea" -import { mockOrders, mockPlayers, mockServices, walletBalance } from "@/lib/mock" +import { mockPlayers, mockServices, walletBalance } from "@/lib/mock" import { useRequireAuth } from "@/lib/use-require-auth" +import { useAuthStore } from "@/store/auth" +import { useChatStore } from "@/store/chat" +import { useOrderStore } from "@/store/orders" function showFeedback(message: string) { if (typeof window === "undefined") return @@ -23,6 +26,8 @@ export default function NewOrderPage() { const router = useRouter() const searchParams = useSearchParams() const { requireAuth } = useRequireAuth() + const createOrder = useOrderStore((state) => state.createOrder) + const ensureOrderSession = useChatStore((state) => state.ensureOrderSession) const serviceId = searchParams.get("serviceId") const service = mockServices.find((s) => s.id === serviceId) @@ -41,8 +46,6 @@ export default function NewOrderPage() { } const totalPrice = service.price * quantity - const redirectOrderId = - mockOrders.find((order) => order.service.id === service.id)?.id ?? mockOrders[0]?.id if (submitted) { return ( @@ -186,15 +189,28 @@ export default function NewOrderPage() { onClick={() => requireAuth(async () => { await new Promise((resolve) => setTimeout(resolve, 500)) + const currentUser = useAuthStore.getState().user + if (!currentUser) return + + const order = createOrder({ + consumerId: currentUser.id, + consumerName: currentUser.nickname, + playerId: player.id, + playerName: player.user.nickname, + shopId: player.shopId, + shopName: player.shopName, + service, + totalPrice, + note, + status: "pending_accept", + }) + + ensureOrderSession(order) setSubmitted(true) showFeedback("下单成功") - if (redirectOrderId) { - setTimeout(() => { - router.push(`/order/${redirectOrderId}`) - }, 800) - return - } - router.push("/orders") + setTimeout(() => { + router.push(`/order/${order.id}`) + }, 800) }) } > diff --git a/app/(order)/orders/page.tsx b/app/(order)/orders/page.tsx index 1bee172..58be893 100644 --- a/app/(order)/orders/page.tsx +++ b/app/(order)/orders/page.tsx @@ -8,10 +8,11 @@ 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 { mockChatSessions, mockOrders } from "@/lib/mock" import type { OrderStatus } 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 = { pending_payment: "bg-yellow-100 text-yellow-800", @@ -51,6 +52,9 @@ const ownerTabs = [ export default function OrderListPage() { const [tab, setTab] = useState("all") const { currentRole, user } = useAuthStore() + const orders = useOrderStore((state) => state.orders) + const sessions = useChatStore((state) => state.sessions) + const ensureOrderSession = useChatStore((state) => state.ensureOrderSession) const currentUserId = user?.id ?? "u1" const ownerShopId = "shop1" @@ -62,7 +66,14 @@ export default function OrderListPage() { const tabs = currentRole === "consumer" ? consumerTabs : currentRole === "player" ? playerTabs : ownerTabs - const roleFiltered = mockOrders.filter((order) => { + 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 === currentUserId if (currentRole === "player") return order.playerId === currentUserId return order.shopId === ownerShopId @@ -70,8 +81,15 @@ export default function OrderListPage() { const filtered = roleFiltered.filter((order) => { if (tab === "pending") return order.status === "pending_accept" - if (tab === "active") - return ["in_progress", "pending_close", "pending_review"].includes(order.status) + 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 @@ -130,20 +148,22 @@ export default function OrderListPage() {
- {order.status === "in_progress" && - (() => { - const session = mockChatSessions.find((s) => s.orderId === order.id) - return ( - session && ( - - ) - ) - })()} + {(() => { + 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 ( + + ) + })()} {order.status === "completed" && (
- diff --git a/components/order-actions.tsx b/components/order-actions.tsx index 091163c..7278ecc 100644 --- a/components/order-actions.tsx +++ b/components/order-actions.tsx @@ -2,9 +2,11 @@ import { AlertTriangle, CheckCircle2, MessageSquare, RefreshCw, Star, XCircle } from "lucide-react" import Link from "next/link" -import { useState } from "react" +import { useEffect, useState } from "react" import { Button } from "@/components/ui/button" import type { OrderStatus } from "@/lib/types" +import { useChatStore } from "@/store/chat" +import { useOrderStore } from "@/store/orders" interface OrderActionsProps { orderId: string @@ -24,16 +26,32 @@ export default function OrderActions({ chatSessionId, serviceId, }: OrderActionsProps) { - const [status, setStatus] = useState(initialStatus) + const order = useOrderStore((state) => state.orders.find((item) => item.id === orderId)) + const updateOrderStatus = useOrderStore((state) => state.updateOrderStatus) + const ensureOrderSession = useChatStore((state) => state.ensureOrderSession) + const [resolvedChatSessionId, setResolvedChatSessionId] = useState(chatSessionId) + + const status = order?.status ?? initialStatus + + useEffect(() => { + if (chatSessionId) { + setResolvedChatSessionId(chatSessionId) + return + } + + if (!order) return + const session = ensureOrderSession(order) + setResolvedChatSessionId(session.id) + }, [chatSessionId, order, ensureOrderSession]) return (
- {status === "pending_accept" && ( + {status === "pending_payment" && ( <> + + )} + + {status === "pending_accept" && ( + <> + +