feat(message): add message center module (Phase 5)

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>
This commit is contained in:
iven
2026-04-11 12:25:05 +08:00
parent 91ecaa3ed7
commit 5ceed71e62
35 changed files with 2252 additions and 15 deletions

View File

@@ -1,17 +1,18 @@
import { Layout, Menu, theme, Avatar, Space, Dropdown, Button } from 'antd';
import NotificationPanel from '../components/NotificationPanel';
import {
HomeOutlined,
UserOutlined,
SafetyOutlined,
ApartmentOutlined,
BellOutlined,
SettingOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
PartitionOutlined,
LogoutOutlined,
MessageOutlined,
} from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAppStore } from '../stores/app';
import { useAuthStore } from '../stores/auth';
@@ -23,6 +24,7 @@ const menuItems = [
{ key: '/roles', icon: <SafetyOutlined />, label: '权限管理' },
{ key: '/organizations', icon: <ApartmentOutlined />, label: '组织架构' },
{ key: '/workflow', icon: <PartitionOutlined />, label: '工作流' },
{ key: '/messages', icon: <MessageOutlined />, label: '消息中心' },
{ key: '/settings', icon: <SettingOutlined />, label: '系统设置' },
];
@@ -31,6 +33,8 @@ export default function MainLayout({ children }: { children: React.ReactNode })
const { user, logout } = useAuthStore();
const { token } = theme.useToken();
const navigate = useNavigate();
const location = useLocation();
const currentPath = location.pathname || '/';
const userMenuItems = [
{
@@ -64,7 +68,7 @@ export default function MainLayout({ children }: { children: React.ReactNode })
theme="dark"
mode="inline"
items={menuItems}
defaultSelectedKeys={['/']}
selectedKeys={[currentPath]}
onClick={({ key }) => navigate(key)}
/>
</Sider>
@@ -87,7 +91,7 @@ export default function MainLayout({ children }: { children: React.ReactNode })
/>
</Space>
<Space size="middle">
<BellOutlined style={{ fontSize: 18, cursor: 'pointer' }} />
<NotificationPanel />
<Dropdown menu={{ items: userMenuItems }} placement="bottomRight">
<Space style={{ cursor: 'pointer' }}>
<Avatar icon={<UserOutlined />} />