Files
Neo-ZQYY/docs/_overview/02a-miniprogram-page-matrix.md
Neo 509cf43284 chore(docs): Wave 0 调研产出 + P0/P1/P2 反馈调研
建立项目级标杆文档 docs/_overview/ 作为产品全景索引,
解决"PRD 零碎、文档膨胀、跨子系统调研无入口"的问题。

主要内容:
- 00-index 总索引 + 维护协议 + 与 CLAUDE.md 关系
- 01-product-overview 产品全景脑图(6 角色 / 6 子系统 / 数据流 /
  7 业务概念 / 8+1 AI 矩阵 / 22 术语)
- 02a-miniprogram-page-matrix 小程序 21 页业务指纹
- 02b-adminweb-page-matrix admin-web 19 路由业务指纹
- 03-test-spec 测试规范 (L1-L5 分层 + 走查模板 + 75-95 case 估算)
- 04-doc-conflicts 39 条冲突索引(P0×8 / P1×13 / P2×13 + 5 子项)
- 04a/b/c-conflicts-*-detail 业务故事卡(7 字段:关联/逻辑/影响/选项/判定)
- 05-orphan-pages-cleanup admin-web 6 孤儿页面处置(1 归档 + 4 保留)
- WAVES-MASTER-PLAN.md 全 Wave 主计划(0-5,共 22-32 工作日)
- WAVE-1-KICKOFF.md Wave 1 实施 kickoff
- GLOBAL-DECISION-DASHBOARD.md 全局决策仪表板

反馈调研产物:
- 04a-feedback/ P0 两轮反馈(8+8 项决策 + D-1/2/3 + F-1/2 子代理产出)
- 04b-feedback/ P1 两轮反馈(13+1+5 项 + E-1/2/3/4 + G-1/2 子代理产出)
- 04c-feedback/ P2 反馈(13 项 + 5 子项 + H-1/2/3 子代理产出)
- NEO-DECISIONS-LOG 累积决策记录

关键追加发现 8 处 D Bug(原蓝本 0):
- P0-3 看板沙箱接入(Wave 1 W1-T1)
- P0-5 致命 1 (4 处 fdw_etl 残留, 已修 commit 17f045a)
- P0-5 致命 2 (JWT aud 缺失, 已修 commit 17f045a)
- P0-6 clearAllTasks 守卫 (Wave 3)
- P0-8 DBViewer 黑名单漏 (已修 commit 17f045a)
- P1-3 task-detail 跳转传 task_id 而非 customer_id
- P2-7 board-finance 隐式 null
- 2 个独立 Bug (page_context.created_at + ClueCategory 字典)

参考: docs/_overview/00-index.md
2026-05-04 07:38:28 +08:00

498 lines
44 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.
# 小程序 21 页业务指纹矩阵
> 生成日期:2026-05-04
> 用途:每页设计目的 + 测试时的"应当展示"判据
> 数据源:`docs/miniprogram-dev/api-audit/*.md`(19 份) + 3 份页面 ts 源码 + `docs/miniprogram-dev/design-system/*` + `docs/prd/Neo_Specs/storyboard-*.md`
> 注:本矩阵仅做指纹索引,不重复 api-audit 的"硬编码与 Mock 处置方案"
---
## 一、tabBar 与角色映射
小程序 `app.json` 的 tabBar 是固定 3 项("任务 / 看板 / 我的"),但实际渲染走自定义 `custom-tab-bar`,按角色 `visibleTabs` 动态过滤,首登选用第一个可见 tab。来源:`docs/prd/Neo_Specs/storyboard-walkthrough-assistant-view.md` GAP-01、`apps/miniprogram/miniprogram/utils/auth-guard.ts``pages/dev-tools/dev-tools.ts` 中的 ROLE_LIST。
| 角色 (`role_code`) | 中文 | 可见 tab | 默认落地页 | 主要使用范围 |
| --- | --- | --- | --- | --- |
| `coach` | 助教 | 任务、看板(部分)、我的 | `/pages/task-list/task-list` | 教练自己的任务 + 业绩 + 备注/对话 |
| `head_coach` | 教练 | 任务、看板、我的 | `/pages/task-list/task-list` | 上述加上跨助教看板查看 |
| `staff` | 员工 | 看板、我的 | `/pages/board-finance/board-finance` | 顾问视角,无任务 |
| `manager` | 管理人员 | 看板、我的(+dev-tools) | `/pages/board-finance/board-finance` | 全门店看板 + 调试入口 |
| `site_admin` / `tenant_admin` | 门店管理员 | 看板、我的 | `/pages/board-finance/board-finance` | 主要在 `tenant-admin` 后台,小程序仅查阅 |
> 跨店切换、`isCurrentMonth`、当前业务时钟由 `apps/miniprogram/miniprogram/utils/runtime-clock.ts → getBusinessClock()` 提供;非当月走真实时间,sandbox 模式按 `business_year/month` 显示(详见 `pages/customer-records/customer-records.ts` L8-L14)。
---
## 二、页面分组与流转图
```text
[认证流]
login ──(success)──> task-list / reviewing / apply / no-permission
[任务流] (角色: coach / head_coach)
task-list ─tap卡片─> task-detail ─问问助手─> chat
└─tap绩效卡─> performance ──查看全部──> performance-records
[看板流] (角色: head_coach / staff / manager)
board-finance <─tab─> board-customer <─tab─> board-coach
│ │ │
│ └─tap客户卡─> customer-detail
│ │
│ ├─查看消费记录─> customer-records
│ ├─查看服务记录─> customer-service-records
│ └─问问助手──> chat
└─tap助教卡─> coach-detail ─近期服务明细─> coach-service-records
└─问问助手──> chat
[我的/AI 流]
my-profile ─备注记录─> notes
└─对话记录─> chat-history ──tap对话──> chat
[调试]
dev-tools (manager 专属;reLaunch 跳到任意已注册页面,用于切角色 / 切状态)
```
页面共 21 个,分四组:认证 4(login/apply/reviewing/no-permission) + 任务 4(task-list/task-detail/performance/performance-records) + 看板与详情 8(board-finance/board-customer/board-coach/customer-detail/customer-records/customer-service-records/coach-detail/coach-service-records) + 杂项 5(my-profile/notes/chat/chat-history/dev-tools)。
---
## 三、每页指纹卡(21 页 × 9 字段)
### 3.1 pages/login/login
- **入口**:小程序首页(冷启动落地);`reviewing` 页"切换账号"按钮也会回到这里
- **设计目的**:把微信用户换成后端 JWT,并按 `user_status` 路由到下一站
- **适用角色**:全部(未登录态)
- **关键 API**:`POST /api/xcx/dev-login`(127.0.0.1) / `POST /api/xcx/login`(线上,需先 `wx.login()` 拿 code) / `POST /api/xcx/refresh`(401 自动)
- **必现字段**:自定义状态栏占位、应用图标 + "球房运营助手" 标题 + 副标题 "为台球厅提升运营效率的内部管理工具"、3 个功能标签卡片(任务管理/数据看板/智能助手)、协议勾选、"使用微信登录" 按钮(disabled 态需可见但灰)、底部"仅限球房内部员工使用"
- **数据展示标准**:无金额/日期展示;按钮在 `agreed && !loading` 时为 active 蓝
- **空态文案**:无空态(此页是入口,任何情况都展示登录卡)
- **典型异常路径**:403→`账号已被禁用`、401→`登录凭证无效,请重试`、其他→`登录失败,请稍后重试`(统一 toast)
- **测试时校核重点**:`isDevMode` 判断(127.0.0.1 才走 dev-login)、登录成功后按 `user_status` 跳页(approved→task-list,pending→reviewing,new→apply,rejected/disabled→no-permission)。参考 `docs/miniprogram-dev/api-audit/login.md` L84-L94
---
### 3.2 pages/apply/apply
- **入口**:`login → status='new'` 自动 reLaunch;`onShow` 调用 `/me` 重新校验
- **设计目的**:首登未审核员工提交入驻表单(球房 ID + 申请身份 + 手机 + 编号 + 昵称),交付给管理员审核
- **适用角色**:仅 `status='new'` 的用户
- **关键 API**:`GET /api/xcx/me`(进页校验) / `POST /api/xcx/apply`(提交)
- **必现字段**:返回箭头(可选)、自定义导航栏 "申请访问权限"、欢迎语 "欢迎加入球房运营助手"、4 步进度条(提交申请→等待审核→审核通过→开始使用)、5 个表单项(球房 ID/申请身份/手机号/编号(选填)/昵称)、提示 "请认真填写,信息不完整可能导致审核不通过"、"提交申请" 按钮、底部 "审核通常需要 1-3 个工作日"
- **数据展示标准**:球房 ID `maxlength=5`、手机号正则 `^\d{11}$`、空字段不传 `employee_number`(JSON 序列化忽略)
- **空态文案**:无空态(只有表单)
- **典型异常路径**:409→`您已有待审核的申请`、422→`表单信息有误,请检查`、其他→`提交失败,请稍后重试`;成功 toast 后 800ms reLaunch 到 `reviewing`
- **测试时校核重点**:确认表单 5 项必填校验生效;`POST /api/xcx/apply` 字段名要为 snake_case(`site_code/applied_role_text/phone/employee_number/nickname`),与后端 schema 对齐。参考 `docs/miniprogram-dev/api-audit/apply.md` L73-L82
---
### 3.3 pages/reviewing/reviewing
- **入口**:`apply` 提交成功 / `login → status='pending'` 自动 reLaunch;`onShow` + `onPullDownRefresh` 都会重新拉 `/me`
- **设计目的**:告知员工"申请已收到,正在审核",同时持续轮询状态(状态变更后立刻 reLaunch 到目标页)
- **适用角色**:`status='pending'``status='rejected'`(显示拒绝原因)
- **关键 API**:`GET /api/xcx/me`(获取 status + latest_application)
- **必现字段**:自定义导航栏、状态图标(沙漏/失败)、`main-title`(`申请审核中` / `申请未通过`)、`sub-title`(说明文案)、审核进度卡(已提交/审核中/通过 三步骤)、"通常需要 1-3 个工作日" 提示、申请信息卡(球房 ID/申请身份/手机号)、底部 "更换登录账号" 按钮
- **数据展示标准**:`latest_application` 缺失则申请信息卡隐藏;状态切换是 reLaunch 而非 redirectTo
- **空态文案**:`latest_application=null` 时申请信息卡不渲染(不展示空文案)
- **典型异常路径**:`/me` 失败 toast `获取状态失败`;切换账号清 4 个 storage key 后回 login
- **测试时校核重点**:5 种 status 路由是否正确;rejected 时 `reject_reason` 是否展示在拒绝原因卡。参考 `docs/miniprogram-dev/api-audit/reviewing.md` L46-L66
---
### 3.4 pages/no-permission/no-permission
- **入口**:`login`/`apply`/`reviewing` 检测到 `status='rejected' or 'disabled'` 时 reLaunch
- **设计目的**:终态页,告诉员工无访问权限并指明联系人
- **适用角色**:`status` 为 rejected/disabled 的用户
- **关键 API**:`GET /api/xcx/me`(`onShow` 复检,状态恢复时跳走)
- **必现字段**:错误图标、`无访问权限` 标题、说明副标题、3 条原因解释卡片、"如有疑问请联系管理员 厉超"(管理员姓名当前硬编码)、"更换登录账号" 按钮
- **数据展示标准**:无业务数据
- **空态文案**:无空态
- **典型异常路径**:`/me` 失败保持当前 UI 不动
- **测试时校核重点**:管理员姓名硬编码 `厉超`(已记录,需要后端下发后改造);状态从 disabled→approved 时是否立刻 reLaunch。参考 `docs/miniprogram-dev/api-audit/no-permission.md` L37-L51
---
### 3.5 pages/task-list/task-list
- **入口**:tabBar 第 1 项;`login → status='approved'` 默认落地;`reviewing → status='approved'` reLaunch
- **设计目的**:助教/教练每日任务工作台,看到三组任务(置顶/正常/已放弃) + 当月业绩进度卡
- **适用角色**:`coach` / `head_coach`
- **关键 API**:`GET /api/xcx/tasks`(列表+performance) / `POST /tasks/{id}/pin|unpin|abandon|restore`(操作) / `POST /notes`(添加备注)
- **必现字段**:用户 banner(头像 + 昵称"小燕" + 角色"助教" + 门店"广州朗朗桌球")、当月业绩进度卡 perf-progress-bar(档位 0/100/130/160/190/220 刻度 + 当前定档课时数字 + 距升档差距 + 闪光动画 SHINE_SPEED)、"今日 客户维护" section header、3 个分组(📌 置顶 / 正常任务 / 已放弃)、每张任务卡(客户头像 + 客户名 + heart-icon 关系分 + 任务类型徽章 + deadline 标签 + "最近到店:N天前 · 余额:¥X" 行 + AI inline icon + AI 建议截断文案 + hasNote 角标)、放弃任务多了"放弃原因:..."行、空态/加载失败/已加载全部三态、AI 悬浮按钮、自定义 tabBar
- **数据展示标准**:金额走 `formatMoney``¥12,680`(整数千分位);课时走 `formatHours``2h` / `2.5h`;deadline 走 `formatDeadline` → 今天到期(橙)/还剩 N 天(蓝)/MM-DD(灰)/逾期 N 天(红)(参考 DISPLAY-STANDARDS.md §7);进度条 `filledPct = total/220 * 100` clamp 0-100;分页大小由 `hasMore` 控制
- **空态文案**:`暂无待办任务` / 加载失败 `加载失败,请重试` / 已加载全部 `没有更多了`
- **典型异常路径**:零 API 全 mock(联调前需注意);分页未实现仅显示"没有更多了";置顶/放弃刷新即丢失;userName/userRole/storeName 当前硬编码,多用户场景必崩
- **测试时校核重点**:`buildPerfData()` 期望的 15+ 字段(tierNodes/basicHours/bonusHours/currentTier/nextTierHours/tierCompleted/bonusMoney/incomeTrend/incomeTrendDir/prevMonth/incomeMonth 等)是否齐全 — 这是契约 TASK-1 最大 Gap,见 GAP-02;`enrichTask` 期望的 `lastVisitDays/balance/aiSuggestion` 是否后端返回(GAP-03);pin/unpin API 端点契约缺失(GAP-04);createNote 缺 score 参数(GAP-05)。参考 `docs/miniprogram-dev/api-audit/task-list.md` L80-L99 + `docs/prd/Neo_Specs/storyboard-walkthrough-assistant-view.md` L75-L97
---
### 3.6 pages/task-detail/task-detail
- **入口**:`task-list` 卡片 tap;`performance`/`coach-detail` 中点服务记录(传 customerName,有 GAP-17)
- **设计目的**:单任务工单页 — 客户档案 + AI 建议 + 维客线索 + 话术参考 + 60 天服务记录 + 备注
- **适用角色**:`coach` / `head_coach`
- **关键 API**:`GET /api/xcx/tasks/{id}` / `POST /tasks/{id}/abandon|restore` / `POST /notes` / `DELETE /notes/{noteId}`
- **必现字段**:Banner(任务类型 SVG 背景 + 客户头像 + 客户名 + 任务类型标签 + 关系等级心形/文字/分数)、手机号(默认 `138****5678` 脱敏 + "查看/复制" 按钮)、储值等级卡(非常多/多/一般/少)、"💡 建议执行" + AI 建议文案、"💬 话术参考" 5 条(可复制,2 秒后回退)、"维客线索" 8 条(分类标签 + 来源 By:xxx)、"60天内服务记录" + 服务汇总(总课时/总收入/平均)、"备注记录"(按时间倒序 + 满意度 score)、底部"问问助手" + "备注" 按钮
- **数据展示标准**:金额 `¥160`(整数);课时 `2.0h`;关系等级走 `vi-colors.ts → getRelationshipLevel()`(excellent>8.5/good 6-8.5/normal 3.5-6/poor<3.5);备注时间走 `formatRelativeTime`
- **空态文案**:加载中 `加载中...` / 未找到 `未找到任务信息` / 加载失败 `加载失败` / 备注空 `暂无备注`
- **典型异常路径**:`detail.id` 实际是 taskId,跳 chat 时却被当 customerId 用(GAP-09);跳 customer-service-records 同样 bug(GAP-10);需要后端在 TASK-2 响应增加 `customer_id`
- **测试时校核重点**:维客线索的 `tag` 格式(含换行符)、`source` 格式(`By:小燕` vs `manual/ai_consumption/ai_note` 类型定义)是否一致(GAP-06/07);AI 分析的 `cache_type` 来源未明确(GAP-08)。参考 `docs/miniprogram-dev/api-audit/task-detail.md` L67-L130
---
### 3.7 pages/my-profile/my-profile
- **入口**:tabBar 第 3 项
- **设计目的**:用户个人中心 — 看用户信息、跳转备注/对话记录,以及退出登录
- **适用角色**:全部已登录角色
- **关键 API**:目前 0 个(从 `app.globalData.authUser` 读取);需对接 `GET /api/xcx/me` 刷新
- **必现字段**:用户卡片(头像 + 姓名 + 角色标签 + 门店名)、菜单 3 项("备注记录" → notes、"助手对话记录" → chat-history、"退出账号" → 弹窗确认 → login)、AI 悬浮按钮、自定义 tabBar
- **数据展示标准**:头像缺省走 `/assets/images/avatar-coach.png`;角色文案走中文(助教/教练/...)
- **空态文案**:无列表态;`authUser` 缺失时姓名/角色/门店字段会留空
- **典型异常路径**:globalData 字段缺失(authUser 当前未存 storeName/coachLevel/avatar,GAP-01)
- **测试时校核重点**:onShow 是否每次刷新 `authUser`、确认退出弹窗 `confirmColor=#e34d59`(走 `CONFIRM_DANGER_COLOR` 常量)。参考 `docs/miniprogram-dev/api-audit/my-profile.md` L38-L48
---
### 3.8 pages/notes/notes
- **入口**:`my-profile` 菜单 "备注记录"
- **设计目的**:展示当前用户记录过的全部备注(跨客户/跨任务),按时间倒序
- **适用角色**:全部
- **关键 API**:`GET /api/xcx/notes`(待对接) / `DELETE /api/xcx/notes/{noteId}`(待对接)
- **必现字段**:加载中 toast、备注卡片列表(每条:标签 + 客户名/任务名 + 内容 + 相对时间 + 删除图标)、底部 "— 已加载全部记录 —"、AI 悬浮按钮
- **数据展示标准**:时间走 `formatRelativeTime`(刚刚/N分钟前/N小时前/N天前/MM-DD/YYYY-MM-DD);确认删除弹窗 `confirmColor=#e34d59`
- **空态文案**:`暂无备注记录`(t-empty)
- **典型异常路径**:加载失败 `加载失败,请重试` + `重新加载`;触底加载未实现(GAP-36)
- **测试时校核重点**:`tagType` 枚举仅 customer/coach/system 三类(GAP-37);路由参数是否需要按 customerId/taskId 过滤(待 Neo 确认)。参考 `docs/miniprogram-dev/api-audit/notes.md` L23-L32
---
### 3.9 pages/performance/performance
- **入口**:`task-list` 业绩进度卡 tap;tabBar 不直接进
- **设计目的**:助教个人当月业绩总览 — 收入构成 + 档位升级激励 + 服务记录明细 + 新客/常客
- **适用角色**:`coach` / `head_coach`
- **关键 API**:`GET /api/xcx/performance?year=&month=` (待对接,需扩展契约)
- **必现字段**:Banner(头像 + 助教名 + 角色 + 门店 + 本月预估收入 + 上月收入)、"收入情况" 区(4 项 incomeItems:基础课/激励课/充值激励/TOP3 销冠奖,每项 icon+label+desc+value)、当前档位卡(基础课到手/激励课到手 单价)、下一阶段卡 + 升级提示("距离下一阶段 需完成 XXh,到达即得 ¥XXX")、本月合计预估行、"📋 我的服务记录明细" + 默认显示前 2 个日期组 + "展开更多/收起"、"查看全部" 跳 performance-records、"我的新客"(8 条 + 展开)、"我的常客"(8 条 + 展开)、AI 悬浮按钮
- **数据展示标准**:金额 `¥6,206`(千分位整数);课时 `87.5h` / `0h`;新客 `count + '次'` 后缀;常客 `hours` 数值无后缀(WXML `h` 字面量)
- **空态文案**:加载 `加载中...`、空 `暂无业绩数据`、错误 `加载失败,请点击重试`
- **典型异常路径**:`thisMonthRecords` 当前是按日分组的 DateGroup,但契约 PERF-1 是扁平数组(GAP-12);收入档位 currentTier/nextTier/upgradeHoursNeeded/upgradeBonus 全未在契约定义(GAP-13)
- **测试时校核重点**:`incomeItems``desc` 字段(如 `80元/h × 75h`)需后端拆分(GAP-15);跳 task-detail 传 `customerName` 而非 `id`(GAP-17)。参考 `docs/miniprogram-dev/api-audit/performance.md` L82-L99
---
### 3.10 pages/performance-records/performance-records
- **入口**:`performance` 页"查看全部";`task-list` 业绩进度卡也可
- **设计目的**:助教自己的业绩明细 — 月份切换 + 月度统计概览 + 按日期分组的服务记录
- **适用角色**:`coach` / `head_coach`(看自己)
- **关键 API**:`GET /api/xcx/performance/records?year=&month=&page=&pageSize=` (待对接)
- **必现字段**:Banner(coachName/coachLevel/storeName + 珊瑚极光渐变背景)、月份切换器(`<` `2026年2月` `>`,canPrev/canNext 边界)、统计概览(总记录 N笔 / 总业绩时长 Nh + 折前 Nh / 收入 ¥N)、按日期分组的服务卡片(date + totalHoursLabel + totalIncomeLabel + records 列表;每条 record 含 customerName/avatarChar/timeRange/hours/courseType/courseTypeClass/location/income)、底部 `— 已加载全部记录 —`
- **数据展示标准**:总笔数 `formatCount(n,'笔')``32笔`;课时 `formatHours``59h`;金额 `formatMoney``¥4,720`;`hoursRaw` 折前课时仅在 raw≠hours 且 raw>0 时展示;`courseTypeClass``tag-basic/tag-vip/tag-tip` 前缀
- **空态文案**:`暂无数据`、加载失败 `加载失败,请点击重试``重试`
- **典型异常路径**:Banner 字段当前从 `globalData.authUser` 读,但 `coachLevel/storeName` 还没存(GAP-22);月份切换未重置 page=1(GAP-21)
- **测试时校核重点**:折前/折后课时的差额展示规则(只在不同时显示括号);分页参数 `coachId` 是否传(自己 / 管理者两种视角)。参考 `docs/miniprogram-dev/api-audit/performance-records.md` L31-L99 + `docs/miniprogram-dev/design-system/DISPLAY-STANDARDS.md` §2.3
---
### 3.11 pages/board-finance/board-finance
- **入口**:tabBar 第 2 项(看板组首页);staff/manager 默认落地页
- **设计目的**:门店财务全景 — 经营一览 + 6 大板块(预收资产/应计收入/现金流入/现金流出/助教分析) + AI 洞察
- **适用角色**:`head_coach` / `staff` / `manager` / `site_admin` / `tenant_admin`
- **关键 API**:0 个,全量内联 mock(待设计:整体接口或 6 板块拆分)
- **必现字段**:角色 Banner(顶部头部带筛选)、5 区域 segmented(全部/大厅/A/B/C/麻将房/团建房 共 7 项)、时间选择器(本月/上月/...8 项)、环比开关、目录吸顶导航(emoji + 板块名)、6 大板块 sections:
- § 经营一览(8 主指标:发生额/总优惠/优惠占比/确认收入/实收/现金支出/现金结余/结余率,每项含环比)
- § 预收资产(储值实收 + 首充/续费/消耗 + 储值卡余额 + 全类别会员卡余额 + 赠送卡明细 3 行)
- § 应计收入确认(收入结构 9 行 + 项目正价 4 项 + 优惠扣减 4 项 + 收款渠道 3 项)
- § 现金流入(消费收入 3 项 + 充值收入 1 项 + 合计)
- § 现金流出(进货 3 + 固定 4 + 助教薪资 4 + 平台服务费 3)
- § 助教分析(基础课 + 激励课,各 4 等级明细)
- "💡 AI 洞察" 12 项指标卡(优惠率Top/差异最大/建议关注 等)
- **数据展示标准**:金额 `¥823,456`、负数 `-¥113,336`、百分比 `12.5%`、环比方向(↑/↓ + 颜色);助教费用必须区分陪打(`assistant_pd_money`)/超休(`assistant_cx_money`)而非 `service_fee`(踩坑参考 DWD-DOC)
- **空态文案**:`pageState='normal'` 默认直入(联调后需改 `loading`/`empty`/`error`)
- **典型异常路径**:零 API;激励课表格只渲染合计行,缺 `wx:for` 明细(已记录);区域筛选 `areaOptions` 应来自 API 而非硬编码
- **测试时校核重点**:走查时必看的 5 区域 segmented + 台桌占用率卡片 + 近 7 日营收折线 + AI 洞察 12 项指标;`balance_pay = recharge_card_pay + gift_card_pay`(支付渠道恒等式);`discount_manual``discount_other` 互斥;`consume_money` 禁止直接计算 → 用 `items_sum`(参考 ETL DWD-DOC)。参考 `docs/miniprogram-dev/api-audit/board-finance.md` L22-L240
---
### 3.12 pages/board-customer/board-customer
- **入口**:`board-finance` 顶部 Tab 切换;`board-coach` 顶部 Tab 切换
- **设计目的**:客户列表(前 100 名) — 8 维度切换(召回/潜力/余额/充值/最近/60天消费/60天频率/60天专一)展示不同的卡片字段
- **适用角色**:`head_coach` / `staff` / `manager`
- **关键 API**:`GET /api/v1/board/customers?dimension=&project=&limit=100&site_id=`(待开发)
- **必现字段**:Tab 栏(财务/客户/助教,选中"客户")、维度下拉(8 项)、项目下拉(全部/中式追分/斯诺克/麻将棋牌/团建K歌)、列表标题 `客户列表 · 前100名 · 共{{totalCount}}名客户`、客户卡片(每条按维度变换):
- 召回维度:理想间隔/已过/超期(天数 + danger 标签 if overdueDays>7)
- 潜力维度:30天消费/月均到店/余额
- 频率维度:8 周到店柱状图
- 专一维度:Top 助教 + 服务次数表
- 通用底部:主助教 + 服务占比 + 关系指数(>=8 显蓝)
- **数据展示标准**:金额走 `formatMoney`;余额预格式化 `¥2,680`(联调后改前端格式化);`avgInterval=5.0天`;近 30 天到店 `visits30d` 数值
- **空态文案**:加载中 `加载中...`、空 `暂无客户数据`、错误 `加载失败` + `点击重试`
- **典型异常路径**:零 API 全 mock;维度切换仅切 dimType 不重新请求;`initPageAiColor` 已 import 未调用
- **测试时校核重点**:`balance_pay` = `recharge_card_pay + gift_card_pay`;DQ-6 会员姓名必须 JOIN `dim_member.nickname`(`settlement_head.member_phone` 自 2025-12 起 NULL);消费金额用 `items_sum` 而非 `consume_money`。参考 `docs/miniprogram-dev/api-audit/board-customer.md` L24-L93 + L286-L296
---
### 3.13 pages/board-coach/board-coach
- **入口**:`board-finance` / `board-customer` 顶部 Tab 切换
- **设计目的**:助教看板(6 人样例) — 4 维度切换(perf/salary/sv/task)
- **适用角色**:`head_coach` / `staff` / `manager`
- **关键 API**:`GET /api/v1/board/coach/list?sort=&skill=&time=`(待开发)
- **必现字段**:Tab 栏(选中"助教")、排序下拉(perf_desc/perf_asc/salary_desc/...6 项)、技能下拉(全部/🎱中式/斯诺克/🀄麻将/🎤K歌)、时间下拉(month/quarter/last_month/last_3m/last_quarter/last_6m)、助教卡片(头像首字 + 渐变色 + 等级 tag + 技能 tags + Top 客户 3 个 + 4 维度专属字段):
- perf 维度:定档课时 + 折前 + 距升档 hint / ✅已达标
- salary 维度:工资 ¥X + 定档/折前
- sv 维度:储值 ¥X + 客户 N人 / 消耗 ¥X
- task 维度:召回 N次 + 回访 N次
- **数据展示标准**:课时 `formatHours``86.2h`;金额 `formatMoney``¥12,680`;客户/任务计数 `formatCount(n,'人')` / `formatCount(n,'次')`;等级英文 key (`star/senior/middle/junior`,展示文案见 vi-colors)
- **空态文案**:`暂无助教数据``加载失败` + `点击重试`
- **典型异常路径**:零 API;筛选切换不重新请求(F1 已记录);`time=last_6m + sort=sv_desc` 注释标注不兼容
- **测试时校核重点**:契约 BOARD-1 仅 10 字段 vs 前端需 20 字段(GAP-3);`skills` 类型 string[] vs `Array<{text,cls}>`(GAP-3);`topCustomers` 字段缺失(GAP-3)。参考 `docs/miniprogram-dev/api-audit/board-coach.md` L26-L51 + `docs/prd/Neo_Specs/miniprogram-storyboard-walkthrough-gaps.md` L60-L78
---
### 3.14 pages/customer-detail/customer-detail
- **入口**:`board-customer` 客户卡 tap;`task-detail` 跳转(无参 bug GAP-31)
- **设计目的**:单客户全景 — Banner + AI 洞察 + 维客线索 + 助教任务分配 + 最喜欢的助教 + 消费记录 + 备注
- **适用角色**:`head_coach` / `staff` / `manager`(读);`coach` 不进
- **关键 API**:`GET /api/xcx/customer/{member_id}/profile`(待开发) + 消费记录/线索/备注/AI 缓存等 6 个子接口(部分已有)
- **必现字段**:返回箭头、自定义导航 `客户详情`、Banner(头像首字 + 客户名 + 4 项统计:储值余额/60天消费/理想间隔/距今到店)、手机号 `138****5678` + 查看/复制、"AI 智能洞察" 卡片(summary + 3 条策略,色彩区分)、"维客线索" 7 条(分类标签 + emoji + text + source + 详情可展开)、"助教任务分配 · 当前进行中" 4 张助教卡(等级/任务类型/状态:normal/pinned/abandoned + 最后服务 + 3 项 metrics)、"最喜欢的助教 · 近60天" 2 张(emoji + 关系指数 + 4 项 stats)、"消费记录 / 商城订单"(总金额 + 列表;每条:type=table/shop/recharge,台桌行带助教明细 + 食品酒水 + 总原价/优惠 + 支付方式 + 充值额)、"备注"(按时间倒序)、底部 "问问助手" + "备注" 按钮
- **数据展示标准**:金额 `8,600`(无 ¥ 前缀,WXML 字面量加);天数 `12天`;关系指数 `9.2`;消费记录金额需要拆分 tableFee/foodAmount/totalAmount,且区分 `tableOrigPrice/foodOrigPrice`(原价 vs 折后)
- **空态文案**:加载 `加载中...`、空 `未找到客户信息`、错误 `加载失败` + `点击重试`、消费记录空 `暂无消费记录`、备注空 `暂无备注`
- **典型异常路径**:`onLoad(options)` 当前未读取 memberId(GAP-31);跳 chat/customer-service-records 也未传 customerId(GAP-31);手机号脱敏 `'138****5678'` 是 WXML 硬编码,应从 `detail.phone` 派生
- **测试时校核重点**:契约 CUST-1 严重不全 — `balance/consumption60d/idealInterval/daysSinceVisit/aiInsight/coachTasks/favoriteCoaches/消费记录拆分/备注` 9 类字段缺失(GAP-23~30);DQ-6 会员手机号需 JOIN `dim_member.mobile`;助教费用拆分 `assistant_pd_money` / `assistant_cx_money`。参考 `docs/miniprogram-dev/api-audit/customer-detail.md` L42-L120
---
### 3.15 pages/customer-service-records/customer-service-records
- **入口**:`customer-detail` "查看服务记录"(注意 GAP-31 当前未传参);其他详情入口
- **设计目的**:某客户的历史服务流水 — 月份切换 + 当月统计 + 服务记录列表
- **适用角色**:`head_coach` / `staff` / `manager`
- **关键 API**:`GET /api/customers/{id}/service-records`(待开发) + `GET /api/customers/{id}`
- **必现字段**:Banner(客户名首字 + 姓名 + "服务 X 次" 徽章 + 手机号 `139****5678` + 查看/复制)、月份切换 + monthLabel + canPrev/canNext、月度统计 3 项(本月服务 X次 / 服务时长 Xh / 关系指数 0.85)、服务记录卡片列表(每条:台号/课程类型 + typeClass + 时长 + 时间段 + drinks + income + isEstimate)、底部 `— 已加载全部记录 —`
- **数据展示标准**:服务次数 `monthCount + '次'`;时长 `(min/60).toFixed(1) + 'h'`;`recordType=course|recharge`;`typeClass=basic|vip|tip|recharge`
- **空态文案**:`暂无服务记录`、本月空 `本月暂无服务记录``加载失败,请点击重试` + `重试`
- **典型异常路径**:零 API;月份切换是本地筛选(GAP-35);`durationRaw/isEstimate/drinks` 都固定值需后端补;台号当前 `getTableNo(id)` 取模生成
- **测试时校核重点**:`recordType/isEstimate/customerPhoneFull/totalServiceCount` 在契约 CUST-2 缺失(GAP-32~34);时间段 startTime/endTime 当前是 `generateTimeRange()` 随机,需后端真返回。参考 `docs/miniprogram-dev/api-audit/customer-service-records.md` L24-L102
---
### 3.16 pages/customer-records/customer-records
> **api-audit 未覆盖**;以下信息基于源码 `apps/miniprogram/miniprogram/pages/customer-records/customer-records.ts` + AI_CHANGELOG 注释。
- **入口**:`customer-detail` "查看消费记录"(从 customer-detail 复用 Banner + 月份切换);2026-03-29 新建
- **设计目的**:与 customer-service-records 区分 — 这里是**消费**(支付/充值)记录视角,而非"服务"视角
- **适用角色**:`head_coach` / `staff` / `manager`
- **关键 API**:`fetchCustomerConsumptionRecords({ customerId, year, month })`(已对接,见 `services/api.ts`)
- **必现字段**:Banner 复用 customer-detail 头部(姓名首字/客户名/4 项统计/手机号 + 脱敏)、月份切换(走业务时钟 `getBusinessClock()` 而非 `new Date()`,sandbox 模式按 `business_year/month` 显示)、月度汇总(visitCount + consumeTotal + rechargeTotal)、消费记录列表(records 数组)
- **数据展示标准**:`detail.balance/consumption60d/idealInterval/daysSinceVisit` 都是 number 或 null,WXML 端用 `fmt.money` 等格式化;Pydantic 字段名兼容 `consumption_60d``consumption60D`(大写 D,踩坑标注)
- **空态文案**:`pageState='loading'/'error'/'normal'`;monthLoading 二级加载态
- **典型异常路径**:`monthLoading` 时切月份会被防抖;`maxYearMonth` 走业务时钟,sandbox 不会越界到未来
- **测试时校核重点**:`detail.consumption60D` 大写 D 字段名兼容;`minYearMonth=202501` 是硬编码下边界;月份切换逻辑(`onPrevMonth/onNextMonth` 同时检查 `monthLoading`);手机号脱敏正则 `(\d{3})\d{4}(\d{4})`。参考源文件 L1-L158
---
### 3.17 pages/coach-detail/coach-detail
- **入口**:`board-coach` 助教卡 tap(`?id={coachId}`);其他详情页相关跳转
- **设计目的**:助教全景 — Banner + 绩效指标(6 项) + 档位进度条 + 收入明细(本月/上月各 4 项) + 任务执行 + 客户关系 TOP20 + 近期服务 + 历史月份 + 备注
- **适用角色**:`head_coach` / `manager`(管理视角);助教自己看自己也可
- **关键 API**:`GET /api/xcx/coaches/:id`(待对接) + 6 个子接口(tasks/top-customers/service-records/history) + `POST /notes`
- **必现字段**:Banner(头像 + 姓名 + 等级 + 技能 + 工龄/客户数/入职日期)、"绩效概览" 4 张 perfCards(本月定档业绩 + 折算前 / 本月工资预估 / 客源储值余额 + N位客户 / 本月任务完成 + 覆盖客户数)、"绩效档位进度" 进度条(动画:tierNodes [0,100,130,160,190,220] + maxHours=220 + 距升档差距)、"收入明细" 标签切换(本月/上月) + 4 行 income items(基础课时费/激励课时费/充值提成/酒水提成) + 合计行(预估或确认)、"任务执行" 本月完成统计(回访 N 个 / 召回 N 个) + 可见任务列表 + 折叠展开 + 已放弃任务、"客户关系 TOP20 · 近60天"(20 张卡:头像+ 心 emoji + score + 服务次数 + 余额 + 消费)、"近期服务明细" 4 条 + "查看更多服务记录 →" 跳 coach-service-records、"更多信息"(入职日期)、"备注记录 共 N 条"(空态 `暂无备注`)、底部 "问问助手" + "备注"
- **数据展示标准**:金额 `¥6,950`;课时 `87.5h`;tierNodes/maxHours 后端返回;perfCurrent/perfTarget 派生 perfPercent
- **空态文案**:加载 `加载中...`、空 `未找到助教信息`、错误 `加载失败` + `点击重试`、备注空 `暂无备注`
- **典型异常路径**:零 API;`tierNodes` Mock 注释 "实际由接口返回";`taskStats` 应由接口 #2 聚合
- **测试时校核重点**:契约 COACH-1 严重不全(GAP-38~44):performance(6 指标)/income(8 项)/tierNodes/TopCustomer(heartEmoji/score/balance/consume)/HistoryMonth/ServiceRecord.perfHours/TaskItem.notes/AbandonedTask.reason/workYears/hireDate;查看更多服务记录跳 `coach-service-records?coachId=` 而非 performance-records。参考 `docs/miniprogram-dev/api-audit/coach-detail.md` L23-L156
---
### 3.18 pages/coach-service-records/coach-service-records
> **api-audit 未覆盖**;以下信息基于源码 `apps/miniprogram/miniprogram/pages/coach-service-records/coach-service-records.ts` 文件头注释 + 实现。
- **入口**:`coach-detail` "近期服务明细" 卡片"查看更多"按钮(必传 `?coachId=`)
- **设计目的**:**管理者视角**的助教业绩明细页 — 与"任务"tab 下的 performance-records 同源 API,但视角不同(看别人 vs 看自己)
- **适用角色**:`head_coach` / `manager`(`view_board_coach` 权限)
- **关键 API**:`GET /api/xcx/performance/records?coach_id=&year=&month=&page=&pageSize=` + `fetchCoachBanner(coachId)`
- **必现字段**:Banner(走 `fetchCoachBanner` 拿 name/level/storeName,3 字段轻量接口)、自定义页面标题 `<助教名>的业绩`(同步原生 navbar 标题)、月份切换 + monthLabel、统计概览(总笔数/总课时 + 折前/总收入)、按日期分组的 dateGroups(date + totalHours + totalIncome + records 列表;每条 record 含 customerName/memberId/avatarColor/timeRange/hours/courseType/courseTagClass/location/income + isScattered 散客标记)、底部分页 `hasMore` 控制
- **数据展示标准**:金额 `formatMoney`、课时 `formatHours`、笔数 `formatCount(n,'笔')`;单条记录右下角显示"助教预估收入"(去第一人称);记录右下角对照 performance-records 自己看的"我的预估收入"
- **空态文案**:`pageState='loading'/'empty'/'error'/'normal'`
- **典型异常路径**:必传参数 `coachId` 缺失会 toast `缺少助教标识` + navigateBack;`isCurrentMonth` 判断(当月且 day<=5 才标记预估);点击单条记录跳 customer-detail(管理者关心客户),散客 memberId<=0 时 toast `散客无详情可查看`
- **测试时校核重点**:Banner 拼接 `<助教名>的业绩` 是否覆盖原生 navbar;月份切换 reset page=1 + dateGroups=[];`courseTagClass` 走 COURSE_TAG_MAP(陪打/基础课→basic、包厢/包厢课→room、超休/激励课/打赏课→incentive)。参考源文件 L1-L275
---
### 3.19 pages/chat/chat
- **入口**:`task-detail`/`customer-detail`/`coach-detail` 底部"问问助手";`chat-history` 列表项 tap
- **设计目的**:AI 对话页 — 历史消息 + 流式回复 + 引用卡片
- **适用角色**:全部
- **关键 API**:`GET /api/xcx/chat/{chatId}/messages`(待对接) + `POST /api/xcx/chat/stream` SSE(待补)
- **必现字段**:自定义导航栏 `AI 助手` + 状态栏占位、引用卡片(`reference-tag` 标签 + 标题 + 摘要 + 键值对数据,可选)、消息列表(头像 + 气泡 + IM 时间 HH:mm / MM-DD HH:mm + 时间分割线≥5min)、流式输出区(打字指示器 + streamingContent)、空对话提示("你好,我是 AI 助手" + "有什么可以帮你的?")、加载失败 + `重新加载`、输入框 + 发送按钮(`isStreaming` 时禁用)
- **数据展示标准**:`timeLabel`(相对) + `imTimeLabel`(IM 格式)由前端 `formatRelativeTime` / `formatIMTime` 派生;`showTimeDivider` 间隔≥5min 显示
- **空态文案**:`你好,我是 AI 助手` + `有什么可以帮你的?`(空消息态)
- **典型异常路径**:`customerId` vs `chatId` 不匹配(GAP-49) — 前端传 customerId 但 API 路径是 chatId;`historyId/coachId` 多入口路由未实现(GAP-50);流式当前是 `simulateStreamOutput` 模拟逐字 50ms
- **测试时校核重点**:`referenceCard.data` 是否后端结构化下发(GAP-45);`timestamp` 字段名 vs 契约 `created_at`(GAP-46);SSE 端点是否存在(GAP-51)。参考 `docs/miniprogram-dev/api-audit/chat.md` L20-L100
---
### 3.20 pages/chat-history/chat-history
- **入口**:`my-profile` 菜单 "助手对话记录"
- **设计目的**:对话记录列表 — 看历史会话标题 + 最后消息 + 时间
- **适用角色**:全部
- **关键 API**:`GET /api/xcx/chat/history?page=&pageSize=`(待对接)
- **必现字段**:自定义导航栏、对话列表(每条:AI 渐变图标 + title + lastMessage 摘要 + relativeTime + customerName 标签 if 有)、底部 `— 已加载全部记录 —`、AI 悬浮按钮
- **数据展示标准**:时间走 `formatRelativeTime` ISO 8601 输入;icon 走 6 色 ICON_GRADIENTS,2026-03-18 已改为 `hashIndex(id)` 按对话 ID 哈希固定(此前是随机刷新就变)
- **空态文案**:`暂无对话记录`(t-empty)、`加载失败,请重试` + `重新加载`、错误 emoji `😵`
- **典型异常路径**:零 API;`statusBarHeight` 已计算但 WXML 未消费(代码遗留);分页未实现(一次拉全)
- **测试时校核重点**:`title` 字段在契约 CHAT-1 缺失(GAP-47);`timestamp` vs `last_time` 字段名不一致(GAP-48);跳转 chat 传 `historyId`(目标页 GAP-50 未处理)。参考 `docs/miniprogram-dev/api-audit/chat-history.md` L19-L93
---
### 3.21 pages/dev-tools/dev-tools
> **api-audit 未覆盖**;以下信息基于源码 `apps/miniprogram/miniprogram/pages/dev-tools/dev-tools.ts`。开发调试用,无明确产品 spec。
- **入口**:my-profile / 任意页面手动 reLaunch(无生产入口);仅 `manager` 角色可用
- **设计目的**:开发期切换角色/状态/快速跳转任意页,验收用户上下文(roles/permissions/binding/storeName)
- **适用角色**:开发调试,生产环境应隐藏
- **关键 API**:`GET /api/xcx/dev-context`(获取调试上下文) / `POST /api/xcx/dev-switch-role`(切角色重签 token) / `POST /api/xcx/dev-switch-status`(切 user_status 重签 token)
- **必现字段**:当前用户上下文(roles/permissions/binding/storeName 4 行)、角色切换按钮组(coach/staff/head_coach/manager 4 个)、状态切换按钮组(new/pending/approved/rejected/disabled 5 个)、3 段页面跳转列表(正在迁移 4 / 已完成 14 / 未完成 0)、操作消息提示(success/error 3s 自动消失)
- **数据展示标准**:无金额/日期 — 这是调试 UI;按钮 disable 当 code===currentRole;reLaunch 跳转覆盖 tabBar 也能进
- **空态文案**:未登录时 `未登录,请先通过 dev-login 获取 token`
- **典型异常路径**:无 token 时不发请求避免 401 死循环;切角色/切状态失败 toast `切换角色失败: ${detail}`;路径列表写死 18 项页面
- **测试时校核重点**:`/api/xcx/dev-context` 返回字段(roles/permissions/binding{binding_type/assistant_id/staff_id}/status);切角色后 `app.globalData.token/refreshToken` + 4 个 storage 是否同步刷新。参考源文件 L19-L184
---
## 四、跨页共性约定
### 金额展示
- 整数无小数,千分位逗号 → `¥12,680`
- 负数 `-¥368`(负号在 ¥ 前,严禁 `¥-368`)
- 零值 `¥0`(严禁 `¥0.00`)
- 空值 / undefined → `--`(严禁直显 undefined/null/NaN/空串)
- 大额不简写(严禁 `¥12万`)
- Mock 字段统一 `number` 类型,不带 `¥` 前缀(由 `formatMoney` / WXS `fmt.money` 加)
- 来源:`docs/miniprogram-dev/design-system/DISPLAY-STANDARDS.md` §1
### 时间展示
- < 120s → `刚刚`
- 2~59min → `N分钟前`
- 1~23h → `N小时前`
- 1~3d → `N天前`(严禁 4天前/7天前/30天前 之类)
- > 3d 同年 → `MM-DD`(`03-10`)
- > 3d 跨年 → `YYYY-MM-DD`(`2025-08-21`)
- 严禁中文 `年月日`、严禁混 `/` 分隔符、严禁 > 3d 后展示时分秒
- 时间戳基准必须服务端 UTC,前端按设备时区渲染
- IM 场景另用 `formatIMTime``HH:mm` / `MM-DD HH:mm`
- 任务截止日期 `formatDeadline``今天到期 / 还剩 N 天 / MM-DD / 逾期 N 天`
- 来源:`docs/miniprogram-dev/design-system/DATETIME-DISPLAY-STANDARD.md` §2 + DISPLAY-STANDARDS.md §7
### 课时展示
- 整数小时 `2h`、非整数 `2.5h`(保留 1 位)
- 折算备注 `2.0h(折后 2.5h)`(仅当 hoursRaw 存在且≠hours)
- 零值 `0h`、空值 `--`
- 来源:DISPLAY-STANDARDS.md §2
### 计数展示
- 单位前端拼接,Mock 只存 number(`32``32笔`)
- 计数零值/空值都展示 `--`(注:与金额零值 `¥0` 不同)
- 单位:笔(交易/记录) / 次(到店) / 人(客户) / 个(任务) / 年(工龄)
- 来源:DISPLAY-STANDARDS.md §3
### 百分比与进度条
- 文字 `58.3%`(保留 1 位);进度条 CSS 宽度 `width:58.3%` 截断 0~100
- 超 100% 文字正常显示,进度条截断到 100
- 来源:DISPLAY-STANDARDS.md §5
### 等级文案(单一数据源)
- 助教等级:`junior=初级 / middle=中级 / senior=高级 / star=⭐ 星级`(API 用英文 key,渲染层翻中文)
- 关系等级:`excellent=很好(>8.5) / good=良好(6-8.5) / normal=一般(3.5-6) / poor=待发展(<3.5)`
- 客户标签:`basic_info / consumption / play_pref / promo_pref / social / feedback`
- 来源:DISPLAY-STANDARDS.md §6
### 错误兜底
- `--` 占位(严禁 `暂无` / `无` / `N/A` / `-`)
- 列表空走 `<t-empty description="..."/>` 而非 `--`
- 加载失败统一文案 `加载失败,请重试` + `重新加载`(/ `加载失败,请点击重试` + `重试` 两套)
- 网络错误一般 toast,非占位
### 加载态
- 进入页 `pageState='loading'`(走 `g-toast-loading-text` 浮层 `加载中...`)
- 成功后切换到 `'normal'/'empty'`,失败 `'error'`
- 二级加载(月份切换 / 触底)走 `monthLoading=true` + `wx.showLoading`
- 联调前许多页用 `setTimeout(400~600)` 模拟,联调时移除
### 路由跳转
- 进 tabBar 用 `wx.switchTab`、跨 tab 详情用 `wx.navigateTo`、登录/审核状态切用 `wx.reLaunch`
- 跳转失败统一 toast `页面跳转失败`
- 关键参数:`?id=` / `?customerId=` / `?taskId=` / `?coachId=` / `?historyId=`(详见每页"路由参数"段)
### globalData 与 storage
- `globalData.{ token, refreshToken, authUser:{ userId, status, nickname, role?, storeName?, coachLevel?, avatar? } }`
- 4 个 storage key:`token / refreshToken / userId / userStatus`
- `authUser` 当前缺 4 字段是已知 GAP-01,需后端 `/me` 扩展或前端各页二次拉取
---
## 五、设计标准锚点(DISPLAY-STANDARDS-1/2 摘要)
1. 金额绝不简写,绝不 toLocaleString(各设备行为不一致),绝不带 `.00`
2. 时间相对值上限是 3 天,>3 天必须切日期格式;同年省略年份
3. 课时折算用 `hours` + 可选 `hoursRaw`(number 字段),不要把 `(折0.5h)` 字符串塞进金额
4. 等级、客户标签类别统一英文 key,中文文案渲染时再翻;`coach-level-tag` 组件、`vi-colors.ts` 是 SSOT
5. 评分一律 0~10 分制(后端),展示走 `scoreToHalfStar` 映射 0~5 星(支持半星);0/null/undefined 视为未评分,展示 `--`
6. Mock 数据迁移目标:页面内联 mock → `utils/mock-data.ts`,联调时统一替换;字段名与接口契约一致以减少重命名
---
## 六、文档冲突待确认清单
| # | 冲突点 | 涉及文档 | 待 Neo 确认 |
| --- | --- | --- | --- |
| C1 | tabBar 是 3 项还是动态过滤 | `app.json` 写死 3 项 vs `auth-guard.ts` + storyboard 描述按角色过滤 | 待 Neo 确认 — 是否仍用 custom-tab-bar 动态隐藏 |
| C2 | login 跳转 approved → `/pages/mvp/mvp` 还是 `/pages/task-list/task-list` | `_hardcode-summary.md` 第 16-18 项已统一改为 task-list,但 `reviewing.md` L52、`no-permission.md` L50 仍写 `/pages/mvp/mvp` | 待 Neo 确认 — 旧文档过期,以代码为准 |
| C3 | 维客线索 `tag` 字段格式 | task-detail 内联 mock 用 `"客户\n基础"`(含 `\n`) vs `mock-data.ts` 类型定义 vs 契约 TASK-2 | 待 Neo 确认 — 含换行 vs 单字符串 vs 枚举 key |
| C4 | 维客线索 `source` 字段格式 | 前端 mock `'By:小燕'` / `'By:系统'` vs 类型定义 `'manual' \| 'ai_consumption' \| 'ai_note'` | 待 Neo 确认 — 是字符串显示还是枚举 |
| C5 | 课程类型 class 前缀 | performance-records 用 `tag-basic/tag-vip/tag-tip`、coach-service-records 用 `basic/room/incentive` | 待 Neo 确认 — 统一一种 |
| C6 | task-detail 跳 chat/customer-service-records 时传的 id 语义 | 当前传 `detail.id`(taskId),但目标页期望 customerId | 待 Neo 确认 — TASK-2 响应应增加 `customer_id` |
| C7 | performance 跳 task-detail 时传 customerName 而非 id | 不可定位任务 | 待 Neo 确认 — 改为传 task_id |
| C8 | customer-detail "查看消费记录" 跳 customer-records 还是 customer-service-records | 两个页面同时存在但语义不同(消费 vs 服务);customer-records 是 2026-03-29 新建 | 待 Neo 确认 — 两入口都保留还是合并 |
| C9 | chat 入口参数语义 | 多个入口分别传 customerId / historyId / coachId,但 `loadMessages` 仅用 customerId | 待 Neo 确认 — 多入口路由逻辑由谁实现 |
| C10 | ChatMessage.timestamp vs created_at 字段名 | 前端 `timestamp`,契约 `created_at` | 待 Neo 确认 — 前端改还是后端改 |
| C11 | ChatHistoryItem `title` 是否后端返回 | 契约无,前端展示需要 | 待 Neo 确认 — title 是 AI 摘要还是首条消息截断 |
| C12 | board-coach `time=last_6m + sort=sv_desc` 不兼容约束 | 写在前端 TIME_OPTIONS 注释 | 待 Neo 确认 — 是否后端会拒绝该组合 |
| C13 | board-finance "AI 洞察" 12 项指标的 cache_type | 前端 3 行硬编码;后端 `biz.ai_cache` 没有约定 type | 待 Neo 确认 — 新建 cache_type 枚举 |
| C14 | dev-tools 角色列表 vs `auth-guard.ts` 实际枚举 | `ROLE_LIST=[coach,staff,head_coach,manager]` 缺 site_admin/tenant_admin | 待 Neo 确认 — 调试是否需要覆盖全角色 |
| C15 | no-permission 管理员姓名 `厉超` 硬编码 | `_hardcode-summary.md` 第 6 项决策"保持硬编码(只有一个管理员)" | 待 Neo 确认 — 多门店上线时如何下发 |
| C16 | customer-records 字段名 `consumption60D`(大写 D) | Pydantic 反序列化后变 D,代码注释标 "踩坑" | 待 Neo 确认 — 后端 alias 规范统一 |
| C17 | apply 跳 approved 应到 task-list 还是 mvp | `apply.md` L57 仍写 `/pages/mvp/mvp` | 待 Neo 确认 — 与 C2 同源,旧文档过期 |
| C18 | 散客 memberId 取值约定 | coach-service-records 用 `memberId<=0` 判散客,toast `散客无详情可查看` | 待 Neo 确认 — 后端是否真用 0/-1/NULL |
---
> 最后更新:2026-05-04 / 维护者:NeoZQYY 小程序前端组