feat: Brief附件/项目平台/规则AI解析/消息中心修复 + 项目创建通知

- Brief 支持代理商附件上传 (迁移 007)
- 项目新增 platform 字段 (迁移 008),前端创建/展示平台信息
- 修复 AI 规则解析:处理中文引号导致 JSON 解析失败的问题
- 修复消息中心崩溃:补全后端消息类型映射 + fallback 保护
- 项目创建时自动发送消息通知
- .gitignore 排除 backend/data/ 数据库文件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-02-10 19:00:03 +08:00
co-authored by Claude Opus 4.6
parent 58aed5f201
commit 4c9b2f1263
40 changed files with 1479 additions and 360 deletions
+30 -13
View File
@@ -45,6 +45,11 @@ type MessageType =
| 'task_deadline' // 任务截止提醒
| 'brand_brief_updated' // 品牌方更新了Brief
| 'system_notice' // 系统通知
| 'new_task' // 新任务
| 'pass' // 审核通过
| 'reject' // 审核驳回
| 'force_pass' // 强制通过
| 'approve' // 审核批准
interface Message {
id: string
@@ -299,19 +304,31 @@ export default function AgencyMessagesPage() {
}
try {
const res = await api.getMessages({ page: 1, page_size: 50 })
const mapped: Message[] = res.items.map(item => ({
id: item.id,
type: (item.type || 'system_notice') as MessageType,
title: item.title,
content: item.content,
time: item.created_at ? new Date(item.created_at).toLocaleString('zh-CN', { month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '',
read: item.is_read,
icon: Bell,
iconColor: 'text-text-secondary',
bgColor: 'bg-bg-elevated',
taskId: item.related_task_id || undefined,
projectId: item.related_project_id || undefined,
}))
const typeIconMap: Record<string, { icon: typeof Bell; iconColor: string; bgColor: string }> = {
new_task: { icon: FileText, iconColor: 'text-accent-indigo', bgColor: 'bg-accent-indigo/20' },
pass: { icon: CheckCircle, iconColor: 'text-accent-green', bgColor: 'bg-accent-green/20' },
approve: { icon: CheckCircle, iconColor: 'text-accent-green', bgColor: 'bg-accent-green/20' },
reject: { icon: XCircle, iconColor: 'text-accent-coral', bgColor: 'bg-accent-coral/20' },
force_pass: { icon: CheckCircle, iconColor: 'text-accent-amber', bgColor: 'bg-accent-amber/20' },
system_notice: { icon: Bell, iconColor: 'text-text-secondary', bgColor: 'bg-bg-elevated' },
}
const defaultIcon = { icon: Bell, iconColor: 'text-text-secondary', bgColor: 'bg-bg-elevated' }
const mapped: Message[] = res.items.map(item => {
const iconCfg = typeIconMap[item.type] || defaultIcon
return {
id: item.id,
type: (item.type || 'system_notice') as MessageType,
title: item.title,
content: item.content,
time: item.created_at ? new Date(item.created_at).toLocaleString('zh-CN', { month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '',
read: item.is_read,
icon: iconCfg.icon,
iconColor: iconCfg.iconColor,
bgColor: iconCfg.bgColor,
taskId: item.related_task_id || undefined,
projectId: item.related_project_id || undefined,
}
})
setMessages(mapped)
} catch {
// 加载失败保持 mock 数据