Files
zt-closet-wxmini-frontend/.codebuddy/plans/我的页面通知栏显示未读数量红点_5d52a12d.md
2026-09-13 02:44:41 +08:00

87 lines
6.1 KiB
Markdown
Raw Permalink 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.
---
name: 我的页面通知栏显示未读数量红点
overview: 在「我的」页面「通知」栏右侧显示未读消息数量红点,让用户知道 tabBar 上的红点来自通知,并与 tabBar 红点数量保持一致。
todos:
- id: tabbar-set-unread
content: 在 utils/tabbar.ts 新增 setTabBarUnread,用已知数量直接更新 tabBar 红点
status: completed
- id: profile-fetch-unread
content: profile.ts 新增 unread 与 fetchUnread,onShow 中刷新并同步 tabBar
status: completed
dependencies:
- tabbar-set-unread
- id: profile-badge-ui
content: profile.wxml 通知行加数量徽标,profile.wxss 新增 menu-badge 样式
status: completed
dependencies:
- profile-fetch-unread
- id: verify-badge-flow
content: 用 [skill:lsp-code-analysis] 校验未读红点数据流与引用完整性
status: completed
dependencies:
- profile-badge-ui
---
## 产品概述
「我的」页底部 tabBar 的红色数字徽标当前只出现在 tab 图标上,用户看到红点却不知道来自哪个功能。本次在「我的」页面内对应的功能行(「通知」)上同步展示相同数量红点,让红点来源一目了然。
## 核心功能
- 「我的」页面「通知」一行右侧展示与 tabBar 一致的未读数量红点(超过 99 显示「99+」)
- 红点数量与 tabBar 完全同源(通知未读数),保证两处数字始终一致
- 进入或切回「我的」页时自动刷新未读数:在通知页读完消息返回后,行内红点与 tabBar 红点同步消失
- 未读数为 0 时该红点不渲染;接口失败时静默降级,不报错、不阻塞页面其他内容
- 其余功能行(我的额度、我的订单、我的收藏、额度明细)无独立未读数据源,保持原样
## 视觉与交互
- 「通知」行内、右侧箭头左侧新增红色胶囊数字徽标,样式与 tabBar 徽标统一(红底白字、圆角胶囊)
- 页面其余布局与交互不变
## 技术栈
- 微信小程序原生框架(TypeScript + WXML + WXSS),沿用现有 `utils/request.ts`、`utils/logger.ts`、`utils/config.ts`、`utils/tabbar.ts` 等工具模块,无新增依赖
## 实现方案
- 数据源唯一:未读数来自 `GET /notification/unread` 的 `unread_count`,与 `custom-tab-bar/index.ts` 的 `syncUnread()` 使用同一接口,缓存 key 复用 `STORAGE_KEYS.UNREAD`,避免出现两个红点数量不一致
- 页面侧新增 `fetchUnread()`:在 `profile.ts` 的 `onShow` 中调用(tab 页每次切回都会触发,天然满足「从通知页返回后刷新」的诉求),成功后 `setData({ unread })` 并写回 `STORAGE_KEYS.UNREAD` 缓存
- 复用既有同步模式:参考 `pages/notification/notification.ts` 的 `fetchUnread()`——拿到最新数量后直接更新 tabBar 实例(不发第二次请求)。当前 `utils/tabbar.ts` 只导出会触发请求的 `syncTabBarUnread()`,因此新增一个「用已知数量直接更新」的导出函数 `setTabBarUnread(count)`,与既有 `getTabBarInstance()` / `setTabBarSelected()` 风格保持一致,不改变 tabBar 组件本身
- 首帧安全:项目多处注释指出首帧渲染未结束就 setData 会触发「Expected updated data but get first rendering data」导致渲染失败。请求回调中的 setData 天然异步、安全;若要用缓存值立即渲染以减少红点出现延迟,必须放在 `wx.nextTick` 内(与 `pages/outfit/outfit.ts` 首次 onShow 的处理方式一致)
- 性能:单次网络请求(与 tabBar 自身的 30s 节流请求并行、互不干扰),无额外遍历或渲染开销;失败时静默降级,不重试、不阻塞
## 实现注意
- 只在已登录分支执行(`profile.onShow` 中 `auth.isLoggedIn()` 校验之后),未登录直接早返回,不会产生必然 401 的请求
- 不改动 `custom-tab-bar` 组件逻辑、`STORAGE_KEYS` 既有 key、以及页面其他功能行
- 日志沿用 `logger.debug/warn`,模块名保持 `const LOG = 'profile'`
- 徽标样式对齐 `custom-tab-bar/index.wxss` 的 `.tab-badge`(`#FF3B30` 底、白字、胶囊圆角),保持全局视觉统一
## 架构与数据流
简单链路补充,无需架构图。数据流:
`profile.onShow` → `fetchUnread()` → `GET /notification/unread` → `setData({ unread })`(渲染行内红点)+ 写缓存 `STORAGE_KEYS.UNREAD` + `setTabBarUnread(unread)`(tabBar 红点不发新请求即同步)
## 目录结构
本次改动共涉及 4 个文件,均在现有架构内按既有模式修改:
```
miniprogram/
├── utils/
│ └── tabbar.ts # [MODIFY] 新增导出 setTabBarUnread(count: number):取 tabBar 实例并调用其 setUnread(已知数量),不发请求;取不到实例时静默跳过,风格对齐现有 syncTabBarUnread / setTabBarSelected
└── pages/
└── profile/
├── profile.ts # [MODIFY] data 新增 unread: 0;新增 fetchUnread()(请求 /notification/unread,成功 setData + 写 STORAGE_KEYS.UNREAD 缓存 + setTabBarUnread 同步,失败 logger.warn 静默降级);onShow 登录校验后调用;首帧用缓存值渲染时须包在 wx.nextTick 内;补充 setTabBarUnread 导入
├── profile.wxml # [MODIFY] 「通知」行在 menu-arrow 前插入 wx:if="{{unread > 0}}" 的数量徽标,文案 {{unread > 99 ? '99+' : unread}}
└── profile.wxss # [MODIFY] 新增 .menu-badge 样式:红色 #FF3B30 胶囊、白字、font-size 20rpx、line-height/min-width/height 对齐 tabBar 的 .tab-badge,margin-left: 12rpx、flex-shrink: 0,与 .menu-arrow 间距协调
```
## Agent Extensions
### Skill
- **lsp-code-analysis**
- Purpose: 校验未读红点数据流的调用链完整性——确认 `fetchUnread`、`setTabBarUnread`、`setUnread` 的引用关系正确,且「我的」页「通知」行绑定与 tabBar 红点数据源唯一,无遗漏或重复渲染路径
- Expected outcome: 输出 `setTabBarUnread` / `fetchUnread` / `onTapNotification` / `unread` 的引用清单,确认改动覆盖完整、无其他页面存在同类「红点来源不明」的遗留入口