Files
one-pipe-system/openspec/changes/add-notification-center/design.md
luo d1ff4d5f6c
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 4m7s
feat: 顶部通知铃铛与站内通知中心
2026-07-24 17:12:29 +08:00

71 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Context
系统已经存在 `ArtNotification` 顶部通知组件,但组件中的通知、消息和待办列表都是静态数据,顶部通知按钮处于注释状态。新的通知能力需要同时服务顶部快速查看和完整通知中心,并确保用户在任一入口执行已读操作后未读数与列表状态一致。
## Goals / Non-Goals
- Goals: 提供余额预警、临期提醒、审批结果和系统告警统一的站内通知入口。
- Goals: 在顶部快速查看最近 10 条通知,并提供进入通知中心的入口。
- Goals: 支持通知分类、类型、严重级别和已读状态筛选。
- Goals: 将通知点击导航限制在前端认可的业务目标内,禁止任意 URL 跳转。
- Goals: 单条已读、全部已读、抽屉和通知中心共享同一份未读状态。
- Non-Goals: 不实现 C 端通知页面。
- Non-Goals: 不实现推送通道或服务端通知生成规则。
- Non-Goals: 不让前端根据通知正文推断跳转地址。
## Decisions
- Decision: 通知铃铛放在顶部全局导航的设置按钮和用户头像菜单附近。
- Rationale: 该区域已承载全局设置和用户级入口,适合放置跨页面可访问的通知入口,也符合产品指定位置。
- Decision: 顶部抽屉只加载最近 10 条,完整通知中心使用独立路由 `/notifications`
- Rationale: 顶部入口保持轻量,筛选和完整历史查询放在独立页面,避免挤占全局导航空间。
- Decision: 未读数使用独立接口获取,单条通知和全部已读成功后立即更新本地共享状态,并以接口返回值为最终结果。
- Rationale: 未读数是全局状态,不能依赖当前抽屉或列表的局部数量推导。
- Decision: 点击通知先调用单条已读接口,再调用目标接口,根据返回的受控 route name/route params 跳转。
- Rationale: 已读状态必须在导航前落库,目标由后端业务引用解析,前端不执行通知携带的任意 URL。
- Decision: 未知 `ref_type` 或目标接口无可用目标时只展示通知正文和状态,不跳转。
- Rationale: 保证安全,同时让无法关联页面的系统通知仍然可读。
- Decision: `unread-summary` 为顶部抽屉分类提供数据,`notifications` 为通知中心筛选列表提供数据。
- Rationale: 顶部快速查看与完整列表的数据量和筛选职责不同,避免顶部加载完整历史数据。
## Data Contract
- Notification item: id, title, content, category, type, severity, read status, created time and optional `ref_type`/reference ID.
- Unread count: non-negative integer; frontend formats it as `0`, `1`-`99` or `99+`.
- Unread summary: category counts and recent notification items, limited to the latest 10 items for the drawer.
- Notification list: paginated items plus total count, with category, type, severity and read-state filters.
- Target response: controlled internal route information, such as route name/path and route params; no arbitrary executable URL.
## Risks / Trade-offs
- Risk: 后端通知字段或枚举名称与文档不一致。
- Mitigation: 在任务阶段先确认字段契约,类型层保留稳定的可选字段和未知值占位展示。
- Risk: 用户在多个标签页同时读通知,单页本地未读数短暂不一致。
- Mitigation: 操作成功后刷新未读数和当前列表;跨标签实时同步不作为本期强制目标。
- Risk: 目标记录已删除或用户权限发生变化。
- Mitigation: 目标接口返回不可跳转时只展示正文,并处理权限/不存在状态,不回退到任意 URL。
## Migration Plan
1. 确认通知列表、摘要、未读数和目标接口字段及枚举。
2. 新增通知 API service、类型和共享状态。
3. 将顶部通知按钮放入设置/头像区域,接入未读数和最近通知抽屉。
4. 新增 `/notifications` 路由及通知中心页面。
5. 实现筛选、单条已读、全部已读和受控目标跳转。
6. 删除或替换 `ArtNotification` 中的静态 mock 数据,并验证四类通知展示一致。
## Open Questions
- 通知中心是否需要分页参数名称 `page/page_size`,以及默认每页数量需要后端确认。
- `category``type``severity``read_status` 的枚举值及展示名称需要后端确认。
- 目标接口返回 route name、path 还是 route key + params需要与路由菜单契约确认。
- 未读数是否需要页面进入时定时刷新或仅在打开抽屉/完成操作时刷新,本期默认按接口调用时机刷新。
- 通知中心菜单权限和按钮权限编码需要后端权限表确认。