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:
71
apps/web/src/pages/messages/NotificationPreferences.tsx
Normal file
71
apps/web/src/pages/messages/NotificationPreferences.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Form, Switch, TimePicker, Button, Card, message } from 'antd';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
|
||||
interface PreferencesData {
|
||||
dnd_enabled: boolean;
|
||||
dnd_start?: string;
|
||||
dnd_end?: string;
|
||||
}
|
||||
|
||||
export default function NotificationPreferences() {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dndEnabled, setDndEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// 加载当前偏好设置
|
||||
// 暂时使用默认值,后续连接 API
|
||||
form.setFieldsValue({
|
||||
dnd_enabled: false,
|
||||
});
|
||||
}, [form]);
|
||||
|
||||
const handleSave = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
const req: PreferencesData = {
|
||||
dnd_enabled: values.dnd_enabled || false,
|
||||
dnd_start: values.dnd_range?.[0]?.format('HH:mm'),
|
||||
dnd_end: values.dnd_range?.[1]?.format('HH:mm'),
|
||||
};
|
||||
|
||||
// 调用 API 更新偏好
|
||||
const client = await import('../../api/client').then(m => m.default);
|
||||
await client.put('/message-subscriptions', {
|
||||
dnd_enabled: req.dnd_enabled,
|
||||
dnd_start: req.dnd_start,
|
||||
dnd_end: req.dnd_end,
|
||||
});
|
||||
|
||||
message.success('偏好设置已保存');
|
||||
} catch {
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card title="通知偏好设置" style={{ maxWidth: 600 }}>
|
||||
<Form form={form} layout="vertical">
|
||||
<Form.Item name="dnd_enabled" label="免打扰模式" valuePropName="checked">
|
||||
<Switch onChange={setDndEnabled} />
|
||||
</Form.Item>
|
||||
|
||||
{dndEnabled && (
|
||||
<Form.Item name="dnd_range" label="免打扰时段">
|
||||
<TimePicker.RangePicker format="HH:mm" />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" onClick={handleSave} loading={loading}>
|
||||
保存设置
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user