Implement the complete message center with: - Database migrations for message_templates, messages, message_subscriptions tables - erp-message crate with entities, DTOs, services, handlers - Message CRUD, send, read/unread tracking, soft delete - Template management with variable interpolation - Subscription preferences with DND support - Frontend: messages page, notification panel, unread count badge - Server integration with module registration and routing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
48 lines
1.2 KiB
TypeScript
48 lines
1.2 KiB
TypeScript
import { create } from 'zustand';
|
|
import { getUnreadCount, listMessages, markRead, type MessageInfo } from '../api/messages';
|
|
|
|
interface MessageState {
|
|
unreadCount: number;
|
|
recentMessages: MessageInfo[];
|
|
fetchUnreadCount: () => Promise<void>;
|
|
fetchRecentMessages: () => Promise<void>;
|
|
markAsRead: (id: string) => Promise<void>;
|
|
}
|
|
|
|
export const useMessageStore = create<MessageState>((set) => ({
|
|
unreadCount: 0,
|
|
recentMessages: [],
|
|
|
|
fetchUnreadCount: async () => {
|
|
try {
|
|
const result = await getUnreadCount();
|
|
set({ unreadCount: result.count });
|
|
} catch {
|
|
// 静默失败,不影响用户体验
|
|
}
|
|
},
|
|
|
|
fetchRecentMessages: async () => {
|
|
try {
|
|
const result = await listMessages({ page: 1, page_size: 5 });
|
|
set({ recentMessages: result.data });
|
|
} catch {
|
|
// 静默失败
|
|
}
|
|
},
|
|
|
|
markAsRead: async (id: string) => {
|
|
try {
|
|
await markRead(id);
|
|
set((state) => ({
|
|
unreadCount: Math.max(0, state.unreadCount - 1),
|
|
recentMessages: state.recentMessages.map((m) =>
|
|
m.id === id ? { ...m, is_read: true } : m,
|
|
),
|
|
}));
|
|
} catch {
|
|
// 静默失败
|
|
}
|
|
},
|
|
}));
|