feat(notifications): add notification system and wire order/dispute events
This commit is contained in:
@@ -56,7 +56,7 @@ export default function NotificationsPage() {
|
|||||||
const systemNotifs = notifications.filter((notification) => notification.type === "system")
|
const systemNotifs = notifications.filter((notification) => notification.type === "system")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-2xl space-y-6">
|
<div className="max-w-2xl mx-auto space-y-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<h1 className="text-2xl font-bold">通知中心</h1>
|
<h1 className="text-2xl font-bold">通知中心</h1>
|
||||||
@@ -76,13 +76,21 @@ export default function NotificationsPage() {
|
|||||||
<TabsTrigger value="system">系统</TabsTrigger>
|
<TabsTrigger value="system">系统</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="all" className="space-y-2 mt-4">
|
<TabsContent value="all" className="space-y-3 mt-4">
|
||||||
{notifications.map((notification) => (
|
{notifications.length === 0 ? (
|
||||||
<NotificationItem key={notification.id} notification={notification} />
|
<Card>
|
||||||
))}
|
<CardContent className="py-8 text-center text-sm text-muted-foreground">
|
||||||
|
暂无通知
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
notifications.map((notification) => (
|
||||||
|
<NotificationItem key={notification.id} notification={notification} />
|
||||||
|
))
|
||||||
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="order" className="space-y-2 mt-4">
|
<TabsContent value="order" className="space-y-3 mt-4">
|
||||||
{orderNotifs.length === 0 ? (
|
{orderNotifs.length === 0 ? (
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="py-8 text-center text-sm text-muted-foreground">
|
<CardContent className="py-8 text-center text-sm text-muted-foreground">
|
||||||
@@ -94,7 +102,7 @@ export default function NotificationsPage() {
|
|||||||
)}
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="community" className="space-y-2 mt-4">
|
<TabsContent value="community" className="space-y-3 mt-4">
|
||||||
{communityNotifs.length === 0 ? (
|
{communityNotifs.length === 0 ? (
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="py-8 text-center text-sm text-muted-foreground">
|
<CardContent className="py-8 text-center text-sm text-muted-foreground">
|
||||||
@@ -106,7 +114,7 @@ export default function NotificationsPage() {
|
|||||||
)}
|
)}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="system" className="space-y-2 mt-4">
|
<TabsContent value="system" className="space-y-3 mt-4">
|
||||||
{systemNotifs.length === 0 ? (
|
{systemNotifs.length === 0 ? (
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="py-8 text-center text-sm text-muted-foreground">
|
<CardContent className="py-8 text-center text-sm text-muted-foreground">
|
||||||
|
|||||||
@@ -17,7 +17,15 @@ import type { UserRole } from "@/lib/types"
|
|||||||
import { useAuthStore } from "@/store/auth"
|
import { useAuthStore } from "@/store/auth"
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const { currentRole, verifiedRoles, switchRole, user, updateProfile } = useAuthStore()
|
const {
|
||||||
|
currentRole,
|
||||||
|
verifiedRoles,
|
||||||
|
switchRole,
|
||||||
|
user,
|
||||||
|
updateProfile,
|
||||||
|
notificationPrefs,
|
||||||
|
setNotificationPref,
|
||||||
|
} = useAuthStore()
|
||||||
const [nickname, setNickname] = useState(user?.nickname ?? "")
|
const [nickname, setNickname] = useState(user?.nickname ?? "")
|
||||||
const [bio, setBio] = useState(user?.bio ?? "")
|
const [bio, setBio] = useState(user?.bio ?? "")
|
||||||
const [avatar, setAvatar] = useState(user?.avatar ?? "")
|
const [avatar, setAvatar] = useState(user?.avatar ?? "")
|
||||||
@@ -26,7 +34,7 @@ export default function SettingsPage() {
|
|||||||
const isRoleVerified = (role: UserRole) => verifiedRoles.includes(role)
|
const isRoleVerified = (role: UserRole) => verifiedRoles.includes(role)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-2xl space-y-6">
|
<div className="max-w-2xl mx-auto space-y-6">
|
||||||
<h1 className="text-2xl font-bold">个人设置</h1>
|
<h1 className="text-2xl font-bold">个人设置</h1>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
@@ -176,7 +184,10 @@ export default function SettingsPage() {
|
|||||||
<p className="text-sm font-medium">订单通知</p>
|
<p className="text-sm font-medium">订单通知</p>
|
||||||
<p className="text-xs text-muted-foreground">接单、完成、争议等状态变更</p>
|
<p className="text-xs text-muted-foreground">接单、完成、争议等状态变更</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch defaultChecked />
|
<Switch
|
||||||
|
checked={notificationPrefs.order}
|
||||||
|
onCheckedChange={(checked) => setNotificationPref("order", checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Separator />
|
<Separator />
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -184,7 +195,10 @@ export default function SettingsPage() {
|
|||||||
<p className="text-sm font-medium">社区通知</p>
|
<p className="text-sm font-medium">社区通知</p>
|
||||||
<p className="text-xs text-muted-foreground">点赞、评论、关注</p>
|
<p className="text-xs text-muted-foreground">点赞、评论、关注</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch defaultChecked />
|
<Switch
|
||||||
|
checked={notificationPrefs.community}
|
||||||
|
onCheckedChange={(checked) => setNotificationPref("community", checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Separator />
|
<Separator />
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -192,7 +206,10 @@ export default function SettingsPage() {
|
|||||||
<p className="text-sm font-medium">系统通知</p>
|
<p className="text-sm font-medium">系统通知</p>
|
||||||
<p className="text-xs text-muted-foreground">平台公告、活动推送</p>
|
<p className="text-xs text-muted-foreground">平台公告、活动推送</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch />
|
<Switch
|
||||||
|
checked={notificationPrefs.system}
|
||||||
|
onCheckedChange={(checked) => setNotificationPref("system", checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,5 +1,33 @@
|
|||||||
|
import { allow, deny } from "@/lib/policy/assert"
|
||||||
|
import type { Notification } from "@/lib/types"
|
||||||
|
import { useAuthStore } from "@/store/auth"
|
||||||
import { useNotificationStore } from "@/store/notifications"
|
import { useNotificationStore } from "@/store/notifications"
|
||||||
|
|
||||||
export function listNotifications() {
|
export function listNotifications() {
|
||||||
return useNotificationStore.getState().notifications
|
return useNotificationStore.getState().notifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isNotificationEnabled(type: Notification["type"]) {
|
||||||
|
const prefs = useAuthStore.getState().notificationPrefs
|
||||||
|
if (type === "order") return prefs.order
|
||||||
|
if (type === "community") return prefs.community
|
||||||
|
return prefs.system
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addNotification(input: {
|
||||||
|
type: Notification["type"]
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
link?: string
|
||||||
|
}) {
|
||||||
|
if (!isNotificationEnabled(input.type)) {
|
||||||
|
return deny("IDEMPOTENT_NOOP", "该类通知已关闭")
|
||||||
|
}
|
||||||
|
|
||||||
|
useNotificationStore.getState().addNotification(input)
|
||||||
|
return allow()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function markNotificationAsRead(notificationId: string) {
|
||||||
|
useNotificationStore.getState().markAsRead(notificationId)
|
||||||
|
}
|
||||||
|
|||||||
+26
-2
@@ -1,17 +1,31 @@
|
|||||||
import { create } from "zustand"
|
import { create } from "zustand"
|
||||||
import type { User, UserRole, VerificationStatus } from "@/lib/types"
|
import type { User, UserRole, VerificationStatus } from "@/lib/types"
|
||||||
|
|
||||||
|
interface NotificationPrefs {
|
||||||
|
order: boolean
|
||||||
|
community: boolean
|
||||||
|
system: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultNotificationPrefs: NotificationPrefs = {
|
||||||
|
order: true,
|
||||||
|
community: true,
|
||||||
|
system: false,
|
||||||
|
}
|
||||||
|
|
||||||
interface AuthState {
|
interface AuthState {
|
||||||
isAuthenticated: boolean
|
isAuthenticated: boolean
|
||||||
currentRole: UserRole
|
currentRole: UserRole
|
||||||
verifiedRoles: UserRole[]
|
verifiedRoles: UserRole[]
|
||||||
verificationStatus: Partial<Record<UserRole, VerificationStatus>>
|
verificationStatus: Partial<Record<UserRole, VerificationStatus>>
|
||||||
verificationReasons: Partial<Record<UserRole, string>>
|
verificationReasons: Partial<Record<UserRole, string>>
|
||||||
|
notificationPrefs: NotificationPrefs
|
||||||
user: User | null
|
user: User | null
|
||||||
switchRole: (role: UserRole) => void
|
switchRole: (role: UserRole) => void
|
||||||
submitVerification: (role: UserRole) => void
|
submitVerification: (role: UserRole) => void
|
||||||
approveVerification: (role: UserRole) => void
|
approveVerification: (role: UserRole) => void
|
||||||
rejectVerification: (role: UserRole, reason: string) => void
|
rejectVerification: (role: UserRole, reason: string) => void
|
||||||
|
setNotificationPref: (type: keyof NotificationPrefs, enabled: boolean) => void
|
||||||
updateProfile: (patch: { nickname?: string; bio?: string; avatar?: string }) => void
|
updateProfile: (patch: { nickname?: string; bio?: string; avatar?: string }) => void
|
||||||
login: (user: User, verifiedRoles?: UserRole[]) => void
|
login: (user: User, verifiedRoles?: UserRole[]) => void
|
||||||
logout: () => void
|
logout: () => void
|
||||||
@@ -23,6 +37,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
|||||||
verifiedRoles: ["consumer"],
|
verifiedRoles: ["consumer"],
|
||||||
verificationStatus: { consumer: "approved" },
|
verificationStatus: { consumer: "approved" },
|
||||||
verificationReasons: {},
|
verificationReasons: {},
|
||||||
|
notificationPrefs: defaultNotificationPrefs,
|
||||||
user: null,
|
user: null,
|
||||||
switchRole: (role) => {
|
switchRole: (role) => {
|
||||||
const { verifiedRoles } = get()
|
const { verifiedRoles } = get()
|
||||||
@@ -84,6 +99,13 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
setNotificationPref: (type, enabled) =>
|
||||||
|
set((state) => ({
|
||||||
|
notificationPrefs: {
|
||||||
|
...state.notificationPrefs,
|
||||||
|
[type]: enabled,
|
||||||
|
},
|
||||||
|
})),
|
||||||
updateProfile: (patch) =>
|
updateProfile: (patch) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
if (!state.user) return state
|
if (!state.user) return state
|
||||||
@@ -98,7 +120,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
login: (user, verifiedRoles = ["consumer"]) =>
|
login: (user, verifiedRoles = ["consumer"]) =>
|
||||||
set({
|
set((state) => ({
|
||||||
isAuthenticated: true,
|
isAuthenticated: true,
|
||||||
user,
|
user,
|
||||||
currentRole: user.role,
|
currentRole: user.role,
|
||||||
@@ -111,7 +133,8 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
|||||||
{},
|
{},
|
||||||
),
|
),
|
||||||
verificationReasons: {},
|
verificationReasons: {},
|
||||||
}),
|
notificationPrefs: state.notificationPrefs,
|
||||||
|
})),
|
||||||
logout: () =>
|
logout: () =>
|
||||||
set({
|
set({
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
@@ -119,6 +142,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
|||||||
verifiedRoles: ["consumer"],
|
verifiedRoles: ["consumer"],
|
||||||
verificationStatus: { consumer: "approved" },
|
verificationStatus: { consumer: "approved" },
|
||||||
verificationReasons: {},
|
verificationReasons: {},
|
||||||
|
notificationPrefs: defaultNotificationPrefs,
|
||||||
user: null,
|
user: null,
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import type { Actor } from "@/lib/policy/actor"
|
|||||||
import type { PolicyDecision } from "@/lib/policy/decision"
|
import type { PolicyDecision } from "@/lib/policy/decision"
|
||||||
import { mockDisputes } from "@/lib/mock"
|
import { mockDisputes } from "@/lib/mock"
|
||||||
import type { Dispute } from "@/lib/types"
|
import type { Dispute } from "@/lib/types"
|
||||||
|
import { useAuthStore } from "@/store/auth"
|
||||||
|
import { useNotificationStore } from "@/store/notifications"
|
||||||
import { useOrderStore } from "@/store/orders"
|
import { useOrderStore } from "@/store/orders"
|
||||||
|
|
||||||
type DisputeTimelineType = "created" | "response" | "reviewing" | "resolved" | "appealed"
|
type DisputeTimelineType = "created" | "response" | "reviewing" | "resolved" | "appealed"
|
||||||
@@ -120,6 +122,19 @@ function asRecord(dispute: Dispute): DisputeRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function notifyDispute(orderId: string, title: string, content: string) {
|
||||||
|
if (!useAuthStore.getState().notificationPrefs.order) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
useNotificationStore.getState().addNotification({
|
||||||
|
type: "order",
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
link: `/dispute/${orderId}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const useDisputeStore = create<DisputeState>((set, get) => {
|
export const useDisputeStore = create<DisputeState>((set, get) => {
|
||||||
const scheduleProgress = (disputeId: string) => {
|
const scheduleProgress = (disputeId: string) => {
|
||||||
clearProgressTimers(disputeId)
|
clearProgressTimers(disputeId)
|
||||||
@@ -148,11 +163,14 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
|||||||
}, DISPUTE_TO_REVIEWING_MS)
|
}, DISPUTE_TO_REVIEWING_MS)
|
||||||
|
|
||||||
const toResolved = setTimeout(() => {
|
const toResolved = setTimeout(() => {
|
||||||
|
let resolvedOrderId: string | null = null
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
disputes: state.disputes.map((dispute) => {
|
disputes: state.disputes.map((dispute) => {
|
||||||
if (dispute.id !== disputeId) return dispute
|
if (dispute.id !== disputeId) return dispute
|
||||||
if (dispute.status !== "reviewing" && dispute.status !== "appealed") return dispute
|
if (dispute.status !== "reviewing" && dispute.status !== "appealed") return dispute
|
||||||
|
|
||||||
|
resolvedOrderId = dispute.orderId
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...dispute,
|
...dispute,
|
||||||
status: "resolved",
|
status: "resolved",
|
||||||
@@ -169,6 +187,11 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
if (resolvedOrderId) {
|
||||||
|
notifyDispute(resolvedOrderId, "争议已处理", "平台已给出争议处理结果")
|
||||||
|
}
|
||||||
|
|
||||||
clearProgressTimers(disputeId)
|
clearProgressTimers(disputeId)
|
||||||
}, DISPUTE_TO_RESOLVED_MS)
|
}, DISPUTE_TO_RESOLVED_MS)
|
||||||
|
|
||||||
@@ -275,6 +298,8 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
|||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
notifyDispute(dispute.orderId, "争议收到回应", "对方已提交争议回应材料")
|
||||||
|
|
||||||
return allow()
|
return allow()
|
||||||
},
|
},
|
||||||
submitAppeal: (disputeId, actorId, reason) => {
|
submitAppeal: (disputeId, actorId, reason) => {
|
||||||
@@ -322,6 +347,8 @@ export const useDisputeStore = create<DisputeState>((set, get) => {
|
|||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
notifyDispute(dispute.orderId, "争议已申诉", "申诉已提交,平台将继续复核")
|
||||||
|
|
||||||
scheduleProgress(disputeId)
|
scheduleProgress(disputeId)
|
||||||
return allow()
|
return allow()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,14 +1,47 @@
|
|||||||
import { create } from "zustand"
|
import { create } from "zustand"
|
||||||
|
import { generateId } from "@/lib/id"
|
||||||
import { mockNotifications } from "@/lib/mock"
|
import { mockNotifications } from "@/lib/mock"
|
||||||
import type { Notification } from "@/lib/types"
|
import type { Notification } from "@/lib/types"
|
||||||
|
|
||||||
|
interface CreateNotificationInput {
|
||||||
|
type: Notification["type"]
|
||||||
|
title: string
|
||||||
|
content: string
|
||||||
|
link?: string
|
||||||
|
}
|
||||||
|
|
||||||
interface NotificationState {
|
interface NotificationState {
|
||||||
notifications: Notification[]
|
notifications: Notification[]
|
||||||
|
addNotification: (input: CreateNotificationInput) => Notification
|
||||||
|
markAsRead: (notificationId: string) => void
|
||||||
markAllAsRead: () => void
|
markAllAsRead: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useNotificationStore = create<NotificationState>((set) => ({
|
export const useNotificationStore = create<NotificationState>((set) => ({
|
||||||
notifications: mockNotifications,
|
notifications: mockNotifications,
|
||||||
|
addNotification: (input) => {
|
||||||
|
const notification: Notification = {
|
||||||
|
id: generateId("notif"),
|
||||||
|
type: input.type,
|
||||||
|
title: input.title,
|
||||||
|
content: input.content,
|
||||||
|
link: input.link,
|
||||||
|
read: false,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
|
||||||
|
set((state) => ({
|
||||||
|
notifications: [notification, ...state.notifications],
|
||||||
|
}))
|
||||||
|
|
||||||
|
return notification
|
||||||
|
},
|
||||||
|
markAsRead: (notificationId) =>
|
||||||
|
set((state) => ({
|
||||||
|
notifications: state.notifications.map((notification) =>
|
||||||
|
notification.id === notificationId ? { ...notification, read: true } : notification,
|
||||||
|
),
|
||||||
|
})),
|
||||||
markAllAsRead: () =>
|
markAllAsRead: () =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
notifications: state.notifications.map((notification) => ({ ...notification, read: true })),
|
notifications: state.notifications.map((notification) => ({ ...notification, read: true })),
|
||||||
|
|||||||
+62
-2
@@ -7,7 +7,9 @@ import type { Actor } from "@/lib/policy/actor"
|
|||||||
import type { PolicyDecision } from "@/lib/policy/decision"
|
import type { PolicyDecision } from "@/lib/policy/decision"
|
||||||
import { mockOrders } from "@/lib/mock"
|
import { mockOrders } from "@/lib/mock"
|
||||||
import type { Order, OrderStatus, PlayerService } from "@/lib/types"
|
import type { Order, OrderStatus, PlayerService } from "@/lib/types"
|
||||||
|
import { useAuthStore } from "@/store/auth"
|
||||||
import { useChatStore } from "@/store/chat"
|
import { useChatStore } from "@/store/chat"
|
||||||
|
import { useNotificationStore } from "@/store/notifications"
|
||||||
import { useWalletStore } from "@/store/wallet"
|
import { useWalletStore } from "@/store/wallet"
|
||||||
|
|
||||||
interface CreateOrderInput {
|
interface CreateOrderInput {
|
||||||
@@ -191,6 +193,55 @@ function scheduleOrderTimeout(orderId: string, status: OrderStatus) {
|
|||||||
orderTimeouts.set(orderId, timer)
|
orderTimeouts.set(orderId, timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function notifyOrderStatus(order: Order) {
|
||||||
|
if (!useAuthStore.getState().notificationPrefs.order) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapping: Partial<Record<OrderStatus, { title: string; content: string }>> = {
|
||||||
|
pending_accept: {
|
||||||
|
title: "订单待接单",
|
||||||
|
content: `${order.service.title} 已支付,等待接单`,
|
||||||
|
},
|
||||||
|
in_progress: {
|
||||||
|
title: "订单已接单",
|
||||||
|
content: `${order.playerName} 已开始服务`,
|
||||||
|
},
|
||||||
|
pending_close: {
|
||||||
|
title: "订单发起结单",
|
||||||
|
content: `订单 ${order.id} 等待确认结单`,
|
||||||
|
},
|
||||||
|
pending_review: {
|
||||||
|
title: "订单待评价",
|
||||||
|
content: "服务已结束,可提交双向评价",
|
||||||
|
},
|
||||||
|
completed: {
|
||||||
|
title: "订单已完成",
|
||||||
|
content: `订单 ${order.id} 已完成`,
|
||||||
|
},
|
||||||
|
cancelled: {
|
||||||
|
title: "订单已取消",
|
||||||
|
content: `订单 ${order.id} 已取消`,
|
||||||
|
},
|
||||||
|
disputed: {
|
||||||
|
title: "订单进入争议",
|
||||||
|
content: "已发起争议,等待平台处理",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = mapping[order.status]
|
||||||
|
if (!payload) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
useNotificationStore.getState().addNotification({
|
||||||
|
type: "order",
|
||||||
|
title: payload.title,
|
||||||
|
content: payload.content,
|
||||||
|
link: `/order/${order.id}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const useOrderStore = create<OrderState>((set, get) => {
|
export const useOrderStore = create<OrderState>((set, get) => {
|
||||||
const applyTransition = (
|
const applyTransition = (
|
||||||
orderId: string,
|
orderId: string,
|
||||||
@@ -226,7 +277,13 @@ export const useOrderStore = create<OrderState>((set, get) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (previousOrder.status !== "completed" && updatedOrder.status === "completed") {
|
if (previousOrder.status !== "completed" && updatedOrder.status === "completed") {
|
||||||
useWalletStore.getState().addIncome(updatedOrder.id, updatedOrder.totalPrice)
|
useWalletStore
|
||||||
|
.getState()
|
||||||
|
.addIncome(updatedOrder.id, updatedOrder.totalPrice, updatedOrder.shopId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousOrder.status !== updatedOrder.status) {
|
||||||
|
notifyOrderStatus(updatedOrder)
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldRefund =
|
const shouldRefund =
|
||||||
@@ -299,6 +356,7 @@ export const useOrderStore = create<OrderState>((set, get) => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
useChatStore.getState().ensureOrderSession(order)
|
useChatStore.getState().ensureOrderSession(order)
|
||||||
|
notifyOrderStatus(order)
|
||||||
return { decision: allow(), order }
|
return { decision: allow(), order }
|
||||||
},
|
},
|
||||||
payOrder: (orderId, actor) => applyTransition(orderId, "PAY", actor),
|
payOrder: (orderId, actor) => applyTransition(orderId, "PAY", actor),
|
||||||
@@ -323,7 +381,9 @@ export const useOrderStore = create<OrderState>((set, get) => {
|
|||||||
|
|
||||||
if (previousOrder && updatedOrder) {
|
if (previousOrder && updatedOrder) {
|
||||||
if (previousOrder.status !== "completed" && updatedOrder.status === "completed") {
|
if (previousOrder.status !== "completed" && updatedOrder.status === "completed") {
|
||||||
useWalletStore.getState().addIncome(updatedOrder.id, updatedOrder.totalPrice)
|
useWalletStore
|
||||||
|
.getState()
|
||||||
|
.addIncome(updatedOrder.id, updatedOrder.totalPrice, updatedOrder.shopId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previousOrder.status === "pending_accept" && updatedOrder.status === "cancelled") {
|
if (previousOrder.status === "pending_accept" && updatedOrder.status === "cancelled") {
|
||||||
|
|||||||
Reference in New Issue
Block a user