refactor(store): adapt Zustand stores to backend-aligned types
- orders: remove name fields from creation, keep dispatchMode logic - chat: remove readonly/senderName/senderAvatar references - reviews: remove fromUserAvatar/toUserId, simplify participant check - disputes: remove initiatorId/initiatorName from creation - posts: remove authorRole/quotedPostId, keep linkedOrderId as number - comments: remove postId from creation - wallet: use string amounts
This commit is contained in:
+7
-39
@@ -14,10 +14,6 @@ function resolveAvatar(_userId: string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
function shouldReadonly(status: Order["status"]) {
|
||||
return status === "pending_review" || status === "completed" || status === "cancelled"
|
||||
}
|
||||
|
||||
export const useChatStore = create<ChatState>((set, get) => ({
|
||||
sessions: [],
|
||||
messages: [],
|
||||
@@ -26,17 +22,8 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
(session) => session.type === "order" && session.orderId === order.id,
|
||||
)
|
||||
|
||||
const readonly = shouldReadonly(order.status)
|
||||
|
||||
if (existing) {
|
||||
if (existing.readonly !== readonly) {
|
||||
set((state) => ({
|
||||
sessions: state.sessions.map((session) =>
|
||||
session.id === existing.id ? { ...session, readonly } : session,
|
||||
),
|
||||
}))
|
||||
}
|
||||
return get().sessions.find((session) => session.id === existing.id) ?? existing
|
||||
return existing
|
||||
}
|
||||
|
||||
const session: ChatSession = {
|
||||
@@ -46,17 +33,16 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
participants: [
|
||||
{
|
||||
id: order.consumerId,
|
||||
name: order.consumerName,
|
||||
nickname: "",
|
||||
avatar: resolveAvatar(order.consumerId),
|
||||
},
|
||||
{
|
||||
id: order.playerId,
|
||||
name: order.playerName,
|
||||
nickname: "",
|
||||
avatar: resolveAvatar(order.playerId),
|
||||
},
|
||||
],
|
||||
unreadCount: 0,
|
||||
readonly,
|
||||
}
|
||||
|
||||
set((state) => ({
|
||||
@@ -69,7 +55,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
const text = content.trim()
|
||||
if (!text) return
|
||||
const session = get().sessions.find((item) => item.id === sessionId)
|
||||
if (!session || session.readonly) return
|
||||
if (!session) return
|
||||
|
||||
const sender = session.participants.find((participant) => participant.id === actorId)
|
||||
if (!sender) return
|
||||
@@ -79,8 +65,6 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
id: generateId("msg"),
|
||||
sessionId,
|
||||
senderId: actorId,
|
||||
senderName: sender.name,
|
||||
senderAvatar: sender.avatar,
|
||||
type: "text",
|
||||
content: text,
|
||||
createdAt: now,
|
||||
@@ -88,22 +72,14 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
|
||||
set((state) => ({
|
||||
messages: [...state.messages, message],
|
||||
sessions: state.sessions.map((session) =>
|
||||
session.id === sessionId
|
||||
? {
|
||||
...session,
|
||||
lastMessage: text,
|
||||
lastMessageAt: now,
|
||||
}
|
||||
: session,
|
||||
),
|
||||
sessions: state.sessions.map((s) => (s.id === sessionId ? { ...s, lastMessage: text } : s)),
|
||||
}))
|
||||
},
|
||||
sendImageMessage: (sessionId, actorId, imageUrl) => {
|
||||
const content = imageUrl.trim()
|
||||
if (!content) return
|
||||
const session = get().sessions.find((item) => item.id === sessionId)
|
||||
if (!session || session.readonly) return
|
||||
if (!session) return
|
||||
|
||||
const sender = session.participants.find((participant) => participant.id === actorId)
|
||||
if (!sender) return
|
||||
@@ -113,8 +89,6 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
id: generateId("msg"),
|
||||
sessionId,
|
||||
senderId: actorId,
|
||||
senderName: sender.name,
|
||||
senderAvatar: sender.avatar,
|
||||
type: "image",
|
||||
content,
|
||||
createdAt: now,
|
||||
@@ -123,13 +97,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
set((state) => ({
|
||||
messages: [...state.messages, message],
|
||||
sessions: state.sessions.map((item) =>
|
||||
item.id === sessionId
|
||||
? {
|
||||
...item,
|
||||
lastMessage: "[图片]",
|
||||
lastMessageAt: now,
|
||||
}
|
||||
: item,
|
||||
item.id === sessionId ? { ...item, lastMessage: "[图片]" } : item,
|
||||
),
|
||||
}))
|
||||
},
|
||||
|
||||
@@ -16,7 +16,6 @@ export const useCommentStore = create<CommentState>((set) => ({
|
||||
|
||||
const comment: Comment = {
|
||||
id: generateId("comment"),
|
||||
postId,
|
||||
author,
|
||||
content: normalizedContent,
|
||||
likeCount: 0,
|
||||
|
||||
+7
-10
@@ -28,8 +28,6 @@ export interface DisputeRecord extends Dispute {
|
||||
|
||||
interface SubmitDisputeInput {
|
||||
orderId: string
|
||||
initiatorId: string
|
||||
initiatorName: string
|
||||
reason: string
|
||||
evidence: string[]
|
||||
}
|
||||
@@ -180,7 +178,7 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
||||
return { decision: deny(400, "请填写争议原因") }
|
||||
}
|
||||
|
||||
const actor = resolveParticipantActor(input.orderId, input.initiatorId)
|
||||
const actor = resolveParticipantActor(input.orderId, useAuthStore.getState().user?.id ?? "")
|
||||
if (!actor) {
|
||||
return { decision: deny(403, "仅订单参与方可发起争议") }
|
||||
}
|
||||
@@ -194,8 +192,6 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
||||
const dispute: DisputeRecord = {
|
||||
id: generateId("disp"),
|
||||
orderId: input.orderId,
|
||||
initiatorId: input.initiatorId,
|
||||
initiatorName: input.initiatorName,
|
||||
reason: input.reason.trim(),
|
||||
evidence: input.evidence,
|
||||
status: "open",
|
||||
@@ -205,7 +201,7 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
||||
{
|
||||
id: generateId("timeline"),
|
||||
type: "created",
|
||||
content: `${input.initiatorName} 提交争议`,
|
||||
content: "争议已提交",
|
||||
createdAt,
|
||||
},
|
||||
],
|
||||
@@ -221,15 +217,16 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
||||
return deny(404, "争议不存在")
|
||||
}
|
||||
|
||||
const order = useOrderStore.getState().orders.find((item) => item.id === dispute.orderId)
|
||||
if (!order) {
|
||||
return deny(404, "关联订单不存在")
|
||||
}
|
||||
|
||||
const actor = resolveParticipantActor(dispute.orderId, actorId)
|
||||
if (!actor) {
|
||||
return deny(403, "仅订单参与方可提交回应")
|
||||
}
|
||||
|
||||
if (actorId === dispute.initiatorId) {
|
||||
return deny(403, "争议发起方不可提交回应")
|
||||
}
|
||||
|
||||
if (dispute.respondentReason) {
|
||||
return deny(400, "回应已提交")
|
||||
}
|
||||
|
||||
+1
-34
@@ -14,7 +14,6 @@ import { useChatStore } from "@/store/chat"
|
||||
import { useNotificationStore } from "@/store/notifications"
|
||||
import { usePlayerStore } from "@/store/players"
|
||||
import { useServiceStore } from "@/store/services"
|
||||
import { useShopStore } from "@/store/shops"
|
||||
import { useWalletStore } from "@/store/wallet"
|
||||
import { create } from "zustand"
|
||||
|
||||
@@ -112,22 +111,15 @@ function applyStatus(order: Order, status: OrderStatus): Order {
|
||||
acceptedAt: order.acceptedAt ?? now,
|
||||
}
|
||||
case "pending_close":
|
||||
return {
|
||||
...order,
|
||||
status,
|
||||
closedAt: order.closedAt ?? now,
|
||||
}
|
||||
case "pending_review":
|
||||
return {
|
||||
...order,
|
||||
status,
|
||||
closedAt: order.closedAt ?? now,
|
||||
}
|
||||
case "completed":
|
||||
return {
|
||||
...order,
|
||||
status,
|
||||
closedAt: order.closedAt ?? now,
|
||||
completedAt: order.completedAt ?? now,
|
||||
}
|
||||
default:
|
||||
@@ -205,7 +197,7 @@ function notifyOrderStatus(order: Order) {
|
||||
},
|
||||
in_progress: {
|
||||
title: "订单已接单",
|
||||
content: `${order.playerName} 已开始服务`,
|
||||
content: `订单 ${order.service.title} 已开始服务`,
|
||||
},
|
||||
pending_close: {
|
||||
title: "订单发起结单",
|
||||
@@ -332,10 +324,6 @@ export const useOrderStore = create<OrderState>((set, get) => {
|
||||
return { decision: deny(400, "店铺信息与打手不匹配") }
|
||||
}
|
||||
|
||||
const resolvedShopName = resolvedShopId
|
||||
? useShopStore.getState().shops.find((item) => item.id === resolvedShopId)?.name
|
||||
: undefined
|
||||
|
||||
const quantity = Number.isFinite(input.quantity) ? Math.floor(input.quantity) : Number.NaN
|
||||
if (!quantity || quantity < 1) {
|
||||
return { decision: deny(400, "数量不合法") }
|
||||
@@ -345,11 +333,8 @@ export const useOrderStore = create<OrderState>((set, get) => {
|
||||
const order: Order = {
|
||||
id: generateId("ord"),
|
||||
consumerId: consumer.id,
|
||||
consumerName: consumer.nickname,
|
||||
playerId: player.id,
|
||||
playerName: player.user.nickname,
|
||||
shopId: resolvedShopId,
|
||||
shopName: resolvedShopName,
|
||||
service,
|
||||
status: "pending_payment",
|
||||
totalPrice,
|
||||
@@ -395,10 +380,6 @@ export const useOrderStore = create<OrderState>((set, get) => {
|
||||
return { decision: deny(400, "店铺信息与打手不匹配") }
|
||||
}
|
||||
|
||||
const resolvedShopName = resolvedShopId
|
||||
? useShopStore.getState().shops.find((item) => item.id === resolvedShopId)?.name
|
||||
: undefined
|
||||
|
||||
const quantity = Number.isFinite(input.quantity) ? Math.floor(input.quantity) : Number.NaN
|
||||
if (!quantity || quantity < 1) {
|
||||
return { decision: deny(400, "数量不合法") }
|
||||
@@ -420,11 +401,8 @@ export const useOrderStore = create<OrderState>((set, get) => {
|
||||
const order: Order = {
|
||||
id: orderId,
|
||||
consumerId: consumer.id,
|
||||
consumerName: consumer.nickname,
|
||||
playerId: player.id,
|
||||
playerName: player.user.nickname,
|
||||
shopId: resolvedShopId,
|
||||
shopName: resolvedShopName,
|
||||
service,
|
||||
status: "pending_accept",
|
||||
totalPrice,
|
||||
@@ -465,17 +443,6 @@ useOrderStore.subscribe((state, prevState) => {
|
||||
const prevOrder = prevState.orders.find((item) => item.id === order.id)
|
||||
if (!prevOrder || prevOrder.status !== order.status) {
|
||||
scheduleOrderTimeout(order.id, order.status)
|
||||
if (order.status === "pending_accept" && order.shopId) {
|
||||
const shop = useShopStore.getState().shops.find((s) => s.id === order.shopId)
|
||||
if (shop?.dispatchMode === "auto") {
|
||||
setTimeout(() => {
|
||||
const current = useOrderStore.getState().orders.find((o) => o.id === order.id)
|
||||
if (!current || current.status !== "pending_accept") return
|
||||
const actor: Actor = { userId: order.playerId, role: "player", shopId: order.shopId }
|
||||
useOrderStore.getState().acceptOrder(order.id, actor)
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
prevState.orders.forEach((order) => {
|
||||
|
||||
+3
-7
@@ -1,16 +1,14 @@
|
||||
import { generateId } from "@/lib/id"
|
||||
import type { Post, User, UserRole } from "@/lib/types"
|
||||
import type { Post, User } from "@/lib/types"
|
||||
import { create } from "zustand"
|
||||
|
||||
interface CreatePostInput {
|
||||
author: User
|
||||
authorRole: UserRole
|
||||
title: string
|
||||
content: string
|
||||
images: string[]
|
||||
tags: string[]
|
||||
linkedOrderId?: string
|
||||
quotedPostId?: string
|
||||
}
|
||||
|
||||
interface PostState {
|
||||
@@ -26,17 +24,15 @@ export const usePostStore = create<PostState>((set) => ({
|
||||
const post: Post = {
|
||||
id: generateId("post"),
|
||||
author: input.author,
|
||||
authorRole: input.authorRole,
|
||||
title: input.title.trim(),
|
||||
content: input.content.trim(),
|
||||
images: input.images,
|
||||
tags: input.tags,
|
||||
linkedOrderId: input.linkedOrderId,
|
||||
quotedPostId: input.quotedPostId,
|
||||
linkedOrderId: input.linkedOrderId ? Number(input.linkedOrderId) : undefined,
|
||||
pinned: false,
|
||||
likeCount: 0,
|
||||
commentCount: 0,
|
||||
liked: false,
|
||||
pinned: false,
|
||||
createdAt: new Date().toISOString(),
|
||||
}
|
||||
|
||||
|
||||
+5
-29
@@ -19,29 +19,6 @@ interface ReviewState {
|
||||
hasUserReviewed: (orderId: string, userId: string) => boolean
|
||||
}
|
||||
|
||||
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: [],
|
||||
getReviewsByOrder: (orderId) => get().reviews.filter((review) => review.orderId === orderId),
|
||||
@@ -65,8 +42,9 @@ export const useReviewStore = create<ReviewState>((set, get) => ({
|
||||
return deny(400, "仅待评价订单可提交评价")
|
||||
}
|
||||
|
||||
const relation = resolveOrderUser(input.orderId, input.fromUserId)
|
||||
if (!relation) {
|
||||
const isParticipant =
|
||||
order.consumerId === input.fromUserId || order.playerId === input.fromUserId
|
||||
if (!isParticipant) {
|
||||
return deny(403, "仅订单参与方可评价")
|
||||
}
|
||||
|
||||
@@ -81,11 +59,9 @@ export const useReviewStore = create<ReviewState>((set, get) => ({
|
||||
id: generateId("rev"),
|
||||
orderId: input.orderId,
|
||||
fromUserId: input.fromUserId,
|
||||
fromUserName: relation.fromUserName,
|
||||
fromUserAvatar: "",
|
||||
toUserId: relation.toUserId,
|
||||
fromUserName: "",
|
||||
rating: input.rating,
|
||||
content: input.content?.trim() || undefined,
|
||||
content: input.content?.trim() ?? "",
|
||||
sealed: true,
|
||||
createdAt,
|
||||
}
|
||||
|
||||
+5
-5
@@ -27,7 +27,7 @@ export const useWalletStore = create<WalletState>((set, get) => ({
|
||||
{
|
||||
id: generateId("tx"),
|
||||
type: "topup",
|
||||
amount,
|
||||
amount: String(amount),
|
||||
description: "充值",
|
||||
createdAt: now,
|
||||
},
|
||||
@@ -43,7 +43,7 @@ export const useWalletStore = create<WalletState>((set, get) => ({
|
||||
{
|
||||
id: generateId("tx"),
|
||||
type: "withdrawal",
|
||||
amount: -amount,
|
||||
amount: String(-amount),
|
||||
description: "提现到银行卡",
|
||||
createdAt: now,
|
||||
},
|
||||
@@ -69,7 +69,7 @@ export const useWalletStore = create<WalletState>((set, get) => ({
|
||||
{
|
||||
id: generateId("tx"),
|
||||
type: "payment",
|
||||
amount: -amount,
|
||||
amount: String(-amount),
|
||||
description: `支付订单 ${orderId}`,
|
||||
createdAt: now,
|
||||
},
|
||||
@@ -100,7 +100,7 @@ export const useWalletStore = create<WalletState>((set, get) => ({
|
||||
{
|
||||
id: generateId("tx"),
|
||||
type: "refund",
|
||||
amount,
|
||||
amount: String(amount),
|
||||
description: `订单 ${orderId} 退款`,
|
||||
createdAt: now,
|
||||
},
|
||||
@@ -130,7 +130,7 @@ export const useWalletStore = create<WalletState>((set, get) => ({
|
||||
{
|
||||
id: generateId("tx"),
|
||||
type: "income",
|
||||
amount: income,
|
||||
amount: String(income),
|
||||
description: `订单 ${orderId} 收入(${commissionLabel})`,
|
||||
createdAt: now,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user