feat(order): add sealed review reveal, timeout rules, and dispatch behavior

This commit is contained in:
zetaloop
2026-02-22 08:16:35 +08:00
parent 33b7e4d0b9
commit a7d56240ff
5 changed files with 288 additions and 19 deletions
+115
View File
@@ -0,0 +1,115 @@
import { create } from "zustand"
import { generateId } from "@/lib/id"
import { mockReviews, mockUsers } from "@/lib/mock"
import type { Review } from "@/lib/types"
import { useOrderStore } from "@/store/orders"
interface SubmitReviewInput {
orderId: string
fromUserId: string
rating: number
content?: string
}
interface ReviewState {
reviews: Review[]
submitReview: (input: SubmitReviewInput) => void
getReviewsByOrder: (orderId: string) => Review[]
hasUserReviewed: (orderId: string, userId: string) => boolean
}
const autoReplyTimers = new Map<string, ReturnType<typeof setTimeout>>()
function resolveUser(userId: string) {
return mockUsers.find((user) => user.id === userId)
}
function resolveOrderUser(orderId: string, userId: string) {
const order = useOrderStore.getState().orders.find((item) => item.id === orderId)
if (!order) return null
if (order.consumerId === userId) {
return {
fromUserName: order.consumerName,
toUserId: order.playerId,
toUserName: order.playerName,
}
}
if (order.playerId === userId) {
return {
fromUserName: order.playerName,
toUserId: order.consumerId,
toUserName: order.consumerName,
}
}
return null
}
export const useReviewStore = create<ReviewState>((set, get) => ({
reviews: mockReviews,
getReviewsByOrder: (orderId) => get().reviews.filter((review) => review.orderId === orderId),
hasUserReviewed: (orderId, userId) =>
get().reviews.some((review) => review.orderId === orderId && review.fromUserId === userId),
submitReview: (input) => {
const relation = resolveOrderUser(input.orderId, input.fromUserId)
if (!relation) return
const exists = get().hasUserReviewed(input.orderId, input.fromUserId)
if (exists) return
const fromUser = resolveUser(input.fromUserId)
const createdAt = new Date().toISOString()
const review: Review = {
id: generateId("rev"),
orderId: input.orderId,
fromUserId: input.fromUserId,
fromUserName: relation.fromUserName,
fromUserAvatar: fromUser?.avatar ?? "",
toUserId: relation.toUserId,
rating: input.rating,
content: input.content?.trim() || undefined,
sealed: true,
createdAt,
}
set((state) => ({ reviews: [...state.reviews, review] }))
const orderReviews = get().getReviewsByOrder(input.orderId)
if (orderReviews.length >= 2) {
const timer = autoReplyTimers.get(input.orderId)
if (timer) {
clearTimeout(timer)
autoReplyTimers.delete(input.orderId)
}
set((state) => ({
reviews: state.reviews.map((item) =>
item.orderId === input.orderId ? { ...item, sealed: false } : item,
),
}))
useOrderStore.getState().updateOrderStatus(input.orderId, "completed")
return
}
if (autoReplyTimers.has(input.orderId)) return
const timer = setTimeout(() => {
autoReplyTimers.delete(input.orderId)
if (get().hasUserReviewed(input.orderId, relation.toUserId)) {
return
}
get().submitReview({
orderId: input.orderId,
fromUserId: relation.toUserId,
rating: 5,
content: `收到 ${relation.toUserName} 的评价,感谢本次对局。`,
})
}, 3000)
autoReplyTimers.set(input.orderId, timer)
},
}))