refactor(order): rewrite store around state machine transitions

This commit is contained in:
zetaloop
2026-02-23 11:04:00 +08:00
parent f8c4c87c61
commit 385dac2d49
4 changed files with 411 additions and 104 deletions
+85 -16
View File
@@ -10,10 +10,12 @@ import {
XCircle,
} from "lucide-react"
import Link from "next/link"
import { useEffect } from "react"
import { useCallback, useEffect } from "react"
import { Button } from "@/components/ui/button"
import { notifySuccess } from "@/lib/toast"
import type { Actor } from "@/lib/policy/actor"
import { notifyInfo, notifySuccess } from "@/lib/toast"
import type { OrderStatus } from "@/lib/types"
import { useAuthStore } from "@/store/auth"
import { useChatStore } from "@/store/chat"
import { useOrderStore } from "@/store/orders"
import { useShopStore } from "@/store/shops"
@@ -35,10 +37,21 @@ export default function OrderActions({
chatSessionId,
serviceId,
}: OrderActionsProps) {
const currentRole = useAuthStore((state) => state.currentRole)
const currentUserId = useAuthStore((state) => state.user?.id)
const payOrder = useOrderStore((state) => state.payOrder)
const acceptOrder = useOrderStore((state) => state.acceptOrder)
const requestClose = useOrderStore((state) => state.requestClose)
const confirmClose = useOrderStore((state) => state.confirmClose)
const cancelPreAccept = useOrderStore((state) => state.cancelPreAccept)
const order = useOrderStore((state) => state.orders.find((item) => item.id === orderId))
const updateOrderStatus = useOrderStore((state) => state.updateOrderStatus)
const sessions = useChatStore((state) => state.sessions)
const ensureOrderSession = useChatStore((state) => state.ensureOrderSession)
const actorShopId = useShopStore((state) => {
if (!currentUserId || currentRole !== "owner") return undefined
const owned = state.shops.find((shop) => shop.owner.id === currentUserId)
return owned?.id
})
const dispatchMode = useShopStore((state) => {
if (!order?.shopId) return "manual"
const shop = state.shops.find((item) => item.id === order.shopId)
@@ -49,6 +62,25 @@ export default function OrderActions({
sessions.find((session) => session.type === "order" && session.orderId === orderId)?.id
const status = order?.status ?? initialStatus
const actor: Actor | undefined = currentUserId
? {
userId: currentUserId,
role: currentRole,
shopId: actorShopId,
}
: undefined
const handleDecision = useCallback(
(okMessage: string, result: { decision: { ok: boolean; message?: string } }) => {
if (result.decision.ok) {
showFeedback(okMessage)
return
}
notifyInfo(result.decision.message ?? "当前操作不允许")
},
[],
)
useEffect(() => {
if (chatSessionId || !order || resolvedChatSessionId) return
@@ -62,12 +94,17 @@ export default function OrderActions({
if (dispatchMode !== "auto") return
const timer = setTimeout(() => {
updateOrderStatus(orderId, "in_progress")
showFeedback("系统已自动派单")
const systemActor: Actor = {
userId: order.playerId,
role: "player",
shopId: order.shopId,
}
const result = acceptOrder(orderId, systemActor)
handleDecision("系统已自动派单", result)
}, 3000)
return () => clearTimeout(timer)
}, [dispatchMode, order, orderId, updateOrderStatus])
}, [acceptOrder, dispatchMode, handleDecision, order, orderId])
return (
<div className="flex gap-2 flex-wrap">
@@ -76,8 +113,13 @@ export default function OrderActions({
<Button
variant="outline"
onClick={() => {
updateOrderStatus(orderId, "cancelled")
showFeedback("订单已取消")
if (!actor) {
notifyInfo("请先登录")
return
}
const result = cancelPreAccept(orderId, actor)
handleDecision("订单已取消", result)
}}
>
<XCircle className="mr-1 h-4 w-4" />
@@ -85,7 +127,13 @@ export default function OrderActions({
</Button>
<Button
onClick={() => {
updateOrderStatus(orderId, "pending_accept")
if (!actor) {
notifyInfo("请先登录")
return
}
const result = payOrder(orderId, actor)
handleDecision("订单支付成功", result)
}}
>
<CheckCircle2 className="mr-1 h-4 w-4" />
@@ -99,8 +147,13 @@ export default function OrderActions({
<Button
variant="outline"
onClick={() => {
updateOrderStatus(orderId, "cancelled")
showFeedback("订单已取消")
if (!actor) {
notifyInfo("请先登录")
return
}
const result = cancelPreAccept(orderId, actor)
handleDecision("订单已取消", result)
}}
>
<XCircle className="mr-1 h-4 w-4" />
@@ -114,8 +167,13 @@ export default function OrderActions({
) : (
<Button
onClick={() => {
updateOrderStatus(orderId, "in_progress")
showFeedback("已接单")
if (!actor) {
notifyInfo("请先登录")
return
}
const result = acceptOrder(orderId, actor)
handleDecision("已接单", result)
}}
>
<CheckCircle2 className="mr-1 h-4 w-4" />
@@ -138,8 +196,13 @@ export default function OrderActions({
<>
<Button
onClick={() => {
updateOrderStatus(orderId, "pending_close")
showFeedback("已发起结单")
if (!actor) {
notifyInfo("请先登录")
return
}
const result = requestClose(orderId, actor)
handleDecision("已发起结单", result)
}}
>
@@ -157,7 +220,13 @@ export default function OrderActions({
<>
<Button
onClick={() => {
updateOrderStatus(orderId, "pending_review")
if (!actor) {
notifyInfo("请先登录")
return
}
const result = confirmClose(orderId, actor)
handleDecision("已确认结单", result)
}}
>