feat(announcements,messaging,notifications): 实现所有长期问题 — SSE 实时推送 + 通知日志持久化 + 优先级/归档 + 消息星标/草稿 + 公告已读回执/置顶 + 分类筛选/桌面推送 + 测试覆盖
P1-8 通知实时推送(SSE): - 新增 /api/notifications/stream SSE 端点(15 秒推送,5 分钟超时) - 新增 useNotificationStream Hook(SSE + 轮询降级) - NotificationDropdown 改用 SSE 实时推送 P2-12 测试覆盖: - notifications/dispatcher.test.ts(6 个测试,渠道选择逻辑) - notifications/channels/in-app-channel.test.ts(9 个测试,类型映射) - messaging/schema.test.ts(34 个测试,Zod 校验) - tests/e2e/messages.spec.ts(消息模块 E2E 测试) - vitest.unit.config.ts 添加 server-only stub P2-13a 通知发送日志持久化: - 新增 notification_logs 表(userId/title/channel/status/messageId/error/sentAt) - logNotificationSend 改为 async 写入 DB(失败降级 console) - dispatcher 传递 payload 用于持久化 P2-13b 通知优先级和归档: - messageNotifications 表新增 priority(low/normal/high/urgent)和 isArchived 字段 - getNotifications 支持归档和优先级筛选 - 新增 archiveNotificationAction - NotificationList 显示优先级 Badge 和归档按钮 P2-13c 消息星标和草稿: - messages 表新增 isStarred 字段 - 新增 message_drafts 表 - 新增 toggleMessageStar + 草稿 CRUD Server Actions - 新增 5 个草稿 data-access 函数 P2-13d 公告已读回执和置顶: - announcements 表新增 isPinned 字段 - 新增 announcement_reads 表(唯一索引保证幂等) - 新增 toggleAnnouncementPinAction + markAnnouncementAsReadAction - getAnnouncements 排序置顶优先 P2-13e 通知分类筛选和桌面推送: - NotificationList 添加按类型筛选按钮组 - 新增 useDesktopNotifications Hook(浏览器 Notification API) - NotificationDropdown 集成桌面推送(新通知触发) 架构图同步: - 004 和 005 均已更新(新增表、Action、Hook、组件描述)
This commit is contained in:
@@ -21,7 +21,10 @@
|
||||
"status": {
|
||||
"draft": "Draft",
|
||||
"published": "Published",
|
||||
"archived": "Archived"
|
||||
"archived": "Archived",
|
||||
"pinned": "Pinned",
|
||||
"read": "Read",
|
||||
"unread": "Unread"
|
||||
},
|
||||
"type": {
|
||||
"school": "School",
|
||||
@@ -52,7 +55,10 @@
|
||||
"archive": "Archive",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"back": "Back"
|
||||
"back": "Back",
|
||||
"pin": "Pin",
|
||||
"unpin": "Unpin",
|
||||
"markRead": "Mark as Read"
|
||||
},
|
||||
"messages": {
|
||||
"created": "Announcement created",
|
||||
@@ -67,7 +73,9 @@
|
||||
"archiveFailed": "Failed to archive",
|
||||
"deleteFailed": "Failed to delete",
|
||||
"invalidForm": "Invalid form data",
|
||||
"invalidState": "Invalid form state"
|
||||
"invalidState": "Invalid state",
|
||||
"pinToggled": "Pin status updated",
|
||||
"markedRead": "Marked as read"
|
||||
},
|
||||
"meta": {
|
||||
"publishedAt": "Published {date}",
|
||||
|
||||
@@ -21,7 +21,11 @@
|
||||
"send": "Send",
|
||||
"sending": "Sending...",
|
||||
"cancel": "Cancel",
|
||||
"back": "Back"
|
||||
"back": "Back",
|
||||
"star": "Star",
|
||||
"unstar": "Unstar",
|
||||
"saveDraft": "Save Draft",
|
||||
"deleteDraft": "Delete Draft"
|
||||
},
|
||||
"form": {
|
||||
"to": "To",
|
||||
@@ -55,7 +59,9 @@
|
||||
"sentEmpty": "No sent messages",
|
||||
"sentEmptyDesc": "You have not sent any messages yet.",
|
||||
"deleteTitle": "Delete message",
|
||||
"deleteDesc": "This will permanently delete the message \"{subject}\"."
|
||||
"deleteDesc": "This will permanently delete the message \"{subject}\".",
|
||||
"noDrafts": "No drafts",
|
||||
"noStarred": "No starred messages"
|
||||
},
|
||||
"messages": {
|
||||
"sent": "Message sent",
|
||||
@@ -66,7 +72,10 @@
|
||||
"deleteFailed": "Failed to delete",
|
||||
"notFound": "Message not found",
|
||||
"invalidId": "Invalid message id",
|
||||
"selectRecipient": "Please select a recipient"
|
||||
"selectRecipient": "Please select a recipient",
|
||||
"draftSaved": "Draft saved",
|
||||
"draftDeleted": "Draft deleted",
|
||||
"starToggled": "Star status updated"
|
||||
},
|
||||
"notification": {
|
||||
"messageTitle": "New message: {subject}",
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
"markRead": "Mark as read",
|
||||
"markAllRead": "Mark all as read",
|
||||
"viewAll": "View all notifications",
|
||||
"view": "View"
|
||||
"view": "View",
|
||||
"archive": "Archive",
|
||||
"unarchive": "Unarchive"
|
||||
},
|
||||
"type": {
|
||||
"message": "Message",
|
||||
@@ -18,18 +20,30 @@
|
||||
"homework": "Homework",
|
||||
"grade": "Grade"
|
||||
},
|
||||
"filter": {
|
||||
"all": "All"
|
||||
},
|
||||
"priority": {
|
||||
"low": "Low",
|
||||
"normal": "Normal",
|
||||
"high": "High",
|
||||
"urgent": "Urgent"
|
||||
},
|
||||
"status": {
|
||||
"new": "New"
|
||||
},
|
||||
"empty": {
|
||||
"noNotifications": "No notifications",
|
||||
"noNotificationsDesc": "You have no notifications yet.",
|
||||
"noNotificationsDropdown": "No notifications"
|
||||
"noNotificationsDropdown": "No notifications",
|
||||
"noFilterResults": "No results",
|
||||
"noFilterResultsDesc": "No notifications match the current filter."
|
||||
},
|
||||
"messages": {
|
||||
"allMarkedRead": "All notifications marked as read",
|
||||
"notificationMarkedRead": "Notification marked as read",
|
||||
"markReadFailed": "Failed to mark as read"
|
||||
"markReadFailed": "Failed to mark as read",
|
||||
"archiveFailed": "Archive failed"
|
||||
},
|
||||
"error": {
|
||||
"loadFailed": "Failed to load notifications",
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
"status": {
|
||||
"draft": "草稿",
|
||||
"published": "已发布",
|
||||
"archived": "已归档"
|
||||
"archived": "已归档",
|
||||
"pinned": "已置顶",
|
||||
"read": "已读",
|
||||
"unread": "未读"
|
||||
},
|
||||
"type": {
|
||||
"school": "全校",
|
||||
@@ -52,7 +55,10 @@
|
||||
"archive": "归档",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"back": "返回"
|
||||
"back": "返回",
|
||||
"pin": "置顶",
|
||||
"unpin": "取消置顶",
|
||||
"markRead": "标记已读"
|
||||
},
|
||||
"messages": {
|
||||
"created": "公告已创建",
|
||||
@@ -67,7 +73,9 @@
|
||||
"archiveFailed": "归档失败",
|
||||
"deleteFailed": "删除失败",
|
||||
"invalidForm": "表单数据无效",
|
||||
"invalidState": "表单状态无效"
|
||||
"invalidState": "表单状态无效",
|
||||
"pinToggled": "置顶状态已更新",
|
||||
"markedRead": "已标记为已读"
|
||||
},
|
||||
"meta": {
|
||||
"publishedAt": "发布于 {date}",
|
||||
|
||||
@@ -21,7 +21,11 @@
|
||||
"send": "发送",
|
||||
"sending": "发送中...",
|
||||
"cancel": "取消",
|
||||
"back": "返回"
|
||||
"back": "返回",
|
||||
"star": "星标",
|
||||
"unstar": "取消星标",
|
||||
"saveDraft": "保存草稿",
|
||||
"deleteDraft": "删除草稿"
|
||||
},
|
||||
"form": {
|
||||
"to": "收件人",
|
||||
@@ -55,7 +59,9 @@
|
||||
"sentEmpty": "无已发送消息",
|
||||
"sentEmptyDesc": "您还没有发送任何消息。",
|
||||
"deleteTitle": "删除消息",
|
||||
"deleteDesc": "此操作将永久删除消息{subject}。"
|
||||
"deleteDesc": "此操作将永久删除消息{subject}。",
|
||||
"noDrafts": "暂无草稿",
|
||||
"noStarred": "暂无星标消息"
|
||||
},
|
||||
"messages": {
|
||||
"sent": "消息已发送",
|
||||
@@ -66,7 +72,10 @@
|
||||
"deleteFailed": "删除失败",
|
||||
"notFound": "消息不存在",
|
||||
"invalidId": "消息 ID 无效",
|
||||
"selectRecipient": "请选择收件人"
|
||||
"selectRecipient": "请选择收件人",
|
||||
"draftSaved": "草稿已保存",
|
||||
"draftDeleted": "草稿已删除",
|
||||
"starToggled": "星标状态已更新"
|
||||
},
|
||||
"notification": {
|
||||
"messageTitle": "新消息:{subject}",
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
"markRead": "标记已读",
|
||||
"markAllRead": "全部标记已读",
|
||||
"viewAll": "查看全部通知",
|
||||
"view": "查看"
|
||||
"view": "查看",
|
||||
"archive": "归档",
|
||||
"unarchive": "取消归档"
|
||||
},
|
||||
"type": {
|
||||
"message": "消息",
|
||||
@@ -18,18 +20,30 @@
|
||||
"homework": "作业",
|
||||
"grade": "成绩"
|
||||
},
|
||||
"filter": {
|
||||
"all": "全部"
|
||||
},
|
||||
"priority": {
|
||||
"low": "低",
|
||||
"normal": "普通",
|
||||
"high": "高",
|
||||
"urgent": "紧急"
|
||||
},
|
||||
"status": {
|
||||
"new": "新"
|
||||
},
|
||||
"empty": {
|
||||
"noNotifications": "暂无通知",
|
||||
"noNotificationsDesc": "您还没有任何通知。",
|
||||
"noNotificationsDropdown": "暂无通知"
|
||||
"noNotificationsDropdown": "暂无通知",
|
||||
"noFilterResults": "无筛选结果",
|
||||
"noFilterResultsDesc": "当前筛选条件下没有通知。"
|
||||
},
|
||||
"messages": {
|
||||
"allMarkedRead": "全部已标记为已读",
|
||||
"notificationMarkedRead": "通知已标记为已读",
|
||||
"markReadFailed": "标记已读失败"
|
||||
"markReadFailed": "标记已读失败",
|
||||
"archiveFailed": "归档失败"
|
||||
},
|
||||
"error": {
|
||||
"loadFailed": "通知加载失败",
|
||||
|
||||
Reference in New Issue
Block a user