feat: batch update - gift card breakdown spec, backend APIs, miniprogram pages, ETL finance recharge, docs & migrations

This commit is contained in:
Neo
2026-03-20 01:43:48 +08:00
parent 075caf067f
commit 79f9a0e1da
437 changed files with 118603 additions and 976 deletions

View File

@@ -0,0 +1,212 @@
# performance 页面数据来源排查
> 排查日期2026-03-18
> 页面路径pages/performance/performance
## 概览
| 分类 | 数量 | 说明 |
|------|------|------|
| A. Mock 数据(页面内联) | 4 组 | incomeItems / thisMonthRecords / newCustomers / regularCustomers全部在 `loadData()``setTimeout` 中硬构造 |
| B. 硬编码数据 | 11 个字段 | Banner 个人信息、收入档位、月度合计等,写死在 `data` 初始值中 |
| C. 已对接 API | 0 | 页面无任何 `wx.request` 调用,无 API 对接 |
| D. 前端计算/派生数据 | 3 个 | 展开/收起状态、AI 配色、pageState |
| E. 路由参数 | 0 | `onLoad()` 未读取任何路由参数 |
| F. WXML 硬编码文案 | 28+ 处 | 标题、标签、提示文字等 |
---
## 一、Mock 数据(页面内联 mock`loadData()` 内 setTimeout 构造)
> 页面未 import `utils/mock-data.ts`,所有 mock 数据均为 `loadData()` 方法内局部变量。
| # | 字段/变量 | 类型 | 位置 | 说明 |
|---|-----------|------|------|------|
| A1 | `incomeItems` | `IncomeItem[]` | `loadData()` 局部变量 | 4 条业绩明细:基础课 / 激励课 / 充值激励 / TOP3 销冠奖icon + label + desc + value 全部硬写 |
| A2 | `thisMonthRecords` | `DateGroup[]` | `loadData()` 局部变量 | 4 个日期组、共 7 条服务记录,含客户名 / 头像 / 时间 / 课时 / 课程类型 / 台位 / 收入 |
| A3 | `newCustomers` | `Array<{...}>` | `loadData()` 局部变量 | 8 条新客数据:姓名 / 头像 / 最近服务日期 / 服务次数 |
| A4 | `regularCustomers` | `Array<{...}>` | `loadData()` 局部变量 | 8 条常客数据:姓名 / 头像 / 累计课时 / 累计收入 / 服务次数 |
| A5 | `gradients` | `string[]` | `loadData()` 局部变量 | 头像配色数组 `['blue','pink','teal',...]`,用于给 mock 数据分配 avatarColor |
### Mock 数据内部字段明细
**incomeItems 每条字段:**
| 字段 | 示例值 | 联调时对应 API 字段(待定) |
|------|--------|---------------------------|
| `icon` | `'🎱'` | — |
| `label` | `'基础课'` | 收入类型名称 |
| `desc` | `'80元/h × 75h'` | 单价 × 课时的计算描述 |
| `value` | `'¥6,000'` | 该类型收入金额 |
**thisMonthRecords → DateGroup 字段:**
| 字段 | 示例值 | 联调时对应 API 字段(待定) |
|------|--------|---------------------------|
| `date` | `'2月7日'` | 服务日期 |
| `totalHours` | `'4.0h'` | 当日总课时 |
| `totalIncome` | `'¥350'` | 当日总收入 |
**thisMonthRecords → ServiceRecord 字段:**
| 字段 | 示例值 | 联调时对应 API 字段(待定) |
|------|--------|---------------------------|
| `customerName` | `'王先生'` | 客户姓名 |
| `avatarChar` | `'王'` | 姓氏首字(前端可派生) |
| `avatarColor` | `'blue'` | 头像配色(前端可派生) |
| `timeRange` | `'20:00-22:00'` | 服务时间段 |
| `hours` | `'2.0h'` | 服务时长 |
| `courseType` | `'基础课'` | 课程类型 |
| `courseTypeClass` | `'tag-basic'` | CSS 类名(前端派生) |
| `location` | `'3号台'` | 台位/包厢 |
| `income` | `'¥160'` | 该次服务预估收入 |
**newCustomers 每条字段:**
| 字段 | 示例值 | 联调时对应 API 字段(待定) |
|------|--------|---------------------------|
| `name` | `'王先生'` | 客户姓名 |
| `avatarChar` | `'王'` | 姓氏首字(前端可派生) |
| `avatarColor` | `'blue'` | 头像配色(前端可派生) |
| `lastService` | `'2月7日'` | 最近服务日期 |
| `count` | `2` | 服务次数 |
**regularCustomers 每条字段:**
| 字段 | 示例值 | 联调时对应 API 字段(待定) |
|------|--------|---------------------------|
| `name` | `'张先生'` | 客户姓名 |
| `avatarChar` | `'张'` | 姓氏首字(前端可派生) |
| `avatarColor` | `'teal'` | 头像配色(前端可派生) |
| `hours` | `12` | 累计课时number |
| `income` | `'¥960'` | 累计收入 |
| `count` | `6` | 服务次数 |
---
## 二、硬编码数据(`Page.data` 初始值)
| # | 字段 | 硬编码值 | 说明 |
|---|------|----------|------|
| B1 | `coachName` | `'小燕'` | 助教姓名,应从登录态/API 获取 |
| B2 | `coachRole` | `'助教'` | 角色标签,应从用户信息获取 |
| B3 | `storeName` | `'广州朗朗桌球'` | 门店名称,应从用户绑定门店获取 |
| B4 | `monthlyIncome` | `'¥6,206'` | 本月预计收入,应从 API 获取 |
| B5 | `lastMonthIncome` | `'¥16,880'` | 上月收入,应从 API 获取 |
| B6 | `currentTier.basicRate` | `80` | 当前档位基础课单价(元/h |
| B7 | `currentTier.incentiveRate` | `95` | 当前档位激励课单价(元/h |
| B8 | `nextTier.basicRate` | `90` | 下一档位基础课单价(元/h |
| B9 | `nextTier.incentiveRate` | `114` | 下一档位激励课单价(元/h |
| B10 | `upgradeHoursNeeded` | `15` | 距下一阶段所需课时 |
| B11 | `upgradeBonus` | `800` | 到达下一阶段奖金(元) |
| B12 | `monthlyTotal` | `'¥6,950.5'` | 本月合计预估收入 |
| B13 | `visibleRecordGroups` | `2` | 默认显示前 N 条日期组UI 配置,可保留硬编码) |
---
## 三、已对接 API
**无。** 页面中不存在任何 `wx.request`、API 服务调用、或从 `getApp()` 获取全局数据的逻辑。
`loadData()` 使用 `setTimeout(500ms)` 模拟异步加载,内部全部为内联 mock 数据。
文件头部注释明确标注:`// TODO: 联调时替换为真实 API 调用`
---
## 四、前端计算/派生数据
| # | 字段 | 来源 | 说明 |
|---|------|------|------|
| D1 | `pageState` | 前端状态机 | `'loading' → 'normal' / 'error' / 'empty'`,由 `loadData()` 控制 |
| D2 | `aiColor` | `initPageAiColor('performance')` | 从 `utils/ai-color-manager.ts` 获取,固定返回 `'blue'` |
| D3 | `thisMonthRecordsExpanded` | 前端 toggle | 服务记录展开/收起状态,默认 `false` |
| D4 | `newCustomerExpanded` | 前端 toggle | 新客列表展开/收起状态,默认 `false` |
| D5 | `regularCustomerExpanded` | 前端 toggle | 常客列表展开/收起状态,默认 `false` |
---
## 五、路由参数
**无。** `onLoad()` 未接收任何路由参数(`options` 未使用)。
页面作为业绩总览入口,当前设计不依赖路由传参。联调后可能需要接收 `coachId` / `month` 等参数。
---
## 六、WXML 硬编码文案
| # | 文案内容 | 位置 | 说明 |
|---|----------|------|------|
| F1 | `加载中...` | 加载态 toast | 可保留 |
| F2 | `暂无业绩数据` | 空数据态 | 可保留 |
| F3 | `加载失败,请点击重试` | 错误态 | 可保留 |
| F4 | `重试` | 错误态按钮 | 可保留 |
| F5 | `本月预计收入` | Banner 收入卡片标签 | 可保留 |
| F6 | `上月收入` | Banner 收入卡片标签 | 可保留 |
| F7 | `收入情况` | section 标题 | 可保留 |
| F8 | `当前档位`×2 | 档位卡片 badge + label | 可保留 |
| F9 | `元/h`×4 | 费率单位 | 可保留 |
| F10 | `基础课到手`×2 | 费率描述 | 可保留 |
| F11 | `激励课到手`×2 | 费率描述 | 可保留 |
| F12 | `下一阶段`×2 | 档位卡片 badge + label | 可保留 |
| F13 | `距离下一阶段` | 升级提示标签 | 可保留 |
| F14 | `需完成 ... 小时` | 升级提示(含动态插值) | 可保留 |
| F15 | `到达即得` | 升级奖金标签 | 可保留 |
| F16 | `元`(奖金后缀) | 升级奖金值 | 可保留 |
| F17 | `本月业绩 预估` | section 标题 | 可保留 |
| F18 | `本月合计 预估` | 合计行标签 | 可保留 |
| F19 | `📋 我的服务记录明细` | 服务记录 header | 可保留 |
| F20 | `展开更多` / `收起` | 服务记录 toggle | 可保留 |
| F21 | `查看全部` | 跳转业绩记录按钮 | 可保留 |
| F22 | `我的预估收入` | 服务记录行内文案 | 可保留 |
| F23 | `我的新客` | section 标题 | 可保留 |
| F24 | `最近服务:` | 新客详情前缀 | 可保留 |
| F25 | `次` | 新客服务次数后缀 | 可保留 |
| F26 | `查看更多 ↓` / `收起 ↑` | 新客/常客 toggle | 可保留 |
| F27 | `我的常客` | section 标题 | 可保留 |
| F28 | `📊` / `🎯` / `⏱️` | 档位/升级提示 emoji | 可保留 |
| F29 | `业绩详情` | `performance.json``navigationBarTitleText` | 可保留 |
---
## 七、联调 TODO
### 7.1 需要对接的 API按优先级排序
| 优先级 | API 用途 | 涉及字段 | 备注 |
|--------|----------|----------|------|
| P0 | 助教个人信息 | B1 `coachName`, B2 `coachRole`, B3 `storeName` | 可从登录态/全局 store 获取 |
| P0 | 本月/上月收入概览 | B4 `monthlyIncome`, B5 `lastMonthIncome` | Banner 核心数据 |
| P0 | 收入档位信息 | B6-B9 `currentTier.*`, `nextTier.*`, B10 `upgradeHoursNeeded`, B11 `upgradeBonus` | 档位规则可能来自配置表 |
| P0 | 本月业绩明细 | A1 `incomeItems`, B12 `monthlyTotal` | 基础课/激励课/充值激励/奖金 |
| P1 | 服务记录列表(按日期分组) | A2 `thisMonthRecords` | 需支持分页或按月查询 |
| P1 | 新客列表 | A3 `newCustomers` | 本月新服务的客户 |
| P1 | 常客列表 | A4 `regularCustomers` | 累计服务数据 |
### 7.2 联调时需要处理的事项
- [ ] 移除 `loadData()` 中的 `setTimeout` 模拟延迟
- [ ] 移除所有内联 mock 数据incomeItems / thisMonthRecords / newCustomers / regularCustomers
- [ ] 替换 Banner 区域硬编码字段coachName / coachRole / storeName / monthlyIncome / lastMonthIncome
- [ ] 替换收入档位硬编码currentTier / nextTier / upgradeHoursNeeded / upgradeBonus / monthlyTotal
- [ ] 添加 `wx.request` 或封装的 API 调用
- [ ] 处理 API 错误 → 设置 `pageState: 'error'`
- [ ] 处理空数据 → 设置 `pageState: 'empty'`
- [ ] `avatarChar` / `avatarColor` / `courseTypeClass` 等前端派生字段需确认是后端返回还是前端计算
- [ ] `onLoad()` 可能需要接收路由参数(如 `coachId``month`
- [ ] 金额格式化(`¥` 前缀、千分位)确认由后端返回还是前端处理
- [ ] 服务记录的 `taskId` 字段当前 mock 中未提供,但 `onRecordTap` 已预留读取逻辑
### 7.3 页面引用的外部依赖
| 依赖 | 类型 | 来源 | 数据影响 |
|------|------|------|----------|
| `ai-color-manager.ts` | 工具函数 | `utils/` | 仅提供 AI 图标配色,无业务数据 |
| `ai-float-button` | 自定义组件 | `components/` | AI 悬浮按钮,无业务数据 |
| `dev-fab` | 自定义组件 | `components/` | 开发调试按钮,无业务数据 |
| `metric-card` | 自定义组件 | `components/` | 已注册但 WXML 中未使用 |
| `t-icon` / `t-loading` | TDesign 组件 | `tdesign-miniprogram` | UI 组件,无业务数据 |
| `mock-data.ts` | Mock 数据文件 | `utils/` | **未被本页面引用**(页面使用内联 mock |
### 7.4 注意事项
1. 页面文件头部已有 `// TODO: 联调时替换为真实 API 调用` 注释
2. `loadData()` 内部也有 `// TODO: 替换为真实 API` 注释
3. `performance.json` 中注册了 `metric-card` 组件但 WXML 中未使用,联调时可清理或启用
4. 金额字段涉及助教收入计算,联调时需参考 DWD-DOC 标杆文档中的助教费用拆分规则(`assistant_pd_money` 陪打 / `assistant_cx_money` 超休)