273 lines
12 KiB
Markdown
273 lines
12 KiB
Markdown
# coach-detail 页面数据来源排查
|
||
|
||
> 排查日期:2026-03-18
|
||
> 页面路径:pages/coach-detail/coach-detail
|
||
|
||
## 概览
|
||
|
||
| 分类 | 数量 | 说明 |
|
||
|------|------|------|
|
||
| A. Mock 数据(页面内联) | 7 组 | 页面 .ts 文件顶部定义的大量 mock 常量 |
|
||
| A. Mock 数据(mock-data.ts) | 1 处 | 仅引用 `mockCoaches` 做 ID→名称匹配 |
|
||
| B. 硬编码数据 | 12 处 | perfCards 文案/sub、tierNodes、动画参数、avatar 路径等 |
|
||
| C. 已对接 API | 0 | 全部数据均为 mock,无真实 API 调用 |
|
||
| D. 前端计算/派生 | 8 处 | perfCards 组装、incomeTotal、perfPercent、进度条参数等 |
|
||
| E. 路由参数 | 1 个 | `options.id` → `coachId` |
|
||
| F. WXML 硬编码文案 | 22 处 | 各 section 标题、按钮文案、空态提示等 |
|
||
|
||
---
|
||
|
||
## 一、Mock 数据
|
||
|
||
### A1. 页面内联 Mock(coach-detail.ts 顶部常量)
|
||
|
||
| 变量名 | 类型 | 字段数 | 用途 | 联调替换目标 |
|
||
|--------|------|--------|------|-------------|
|
||
| `mockCoachDetail` | `CoachDetail` | 12 个顶层字段 | 助教基本信息 + 绩效 + 收入 + 备注 | `GET /api/xcx/coaches/:id` |
|
||
| `mockVisibleTasks` | `TaskItem[]` | 6 条 | 当前可见任务列表 | `GET /api/xcx/coaches/:id/tasks` |
|
||
| `mockHiddenTasks` | `TaskItem[]` | 3 条 | 折叠区任务列表 | 同上(分页/分组) |
|
||
| `mockAbandonedTasks` | `AbandonedTask[]` | 2 条 | 已放弃任务 | 同上(status=abandoned) |
|
||
| `mockTopCustomers` | `TopCustomer[]` | 20 条 | 客户关系 TOP20 | `GET /api/xcx/coaches/:id/top-customers` |
|
||
| `mockServiceRecords` | `ServiceRecord[]` | 4 条 | 近期服务明细 | `GET /api/xcx/coaches/:id/service-records` |
|
||
| `mockHistoryMonths` | `HistoryMonth[]` | 5 条 | 历史月度汇总 | `GET /api/xcx/coaches/:id/history` |
|
||
|
||
#### mockCoachDetail 字段明细
|
||
|
||
| 字段路径 | Mock 值 | 说明 |
|
||
|----------|---------|------|
|
||
| `id` | `'coach-001'` | 助教 ID |
|
||
| `name` | `'小燕'` | 助教姓名 |
|
||
| `avatar` | `'/assets/images/avatar-coach.png'` | 头像(硬编码路径) |
|
||
| `level` | `'星级'` | 助教等级 |
|
||
| `skills` | `['中🎱', '🎯斯诺克']` | 技能标签 |
|
||
| `workYears` | `3` | 工龄 |
|
||
| `customerCount` | `68` | 客户数 |
|
||
| `hireDate` | `'2023-03-15'` | 入职日期 |
|
||
| `performance.monthlyHours` | `87.5` | 本月定档业绩(小时) |
|
||
| `performance.monthlySalary` | `6950` | 本月工资(预估) |
|
||
| `performance.customerBalance` | `86200` | 客源储值余额 |
|
||
| `performance.tasksCompleted` | `38` | 本月任务完成数 |
|
||
| `performance.perfCurrent` | `80` | 绩效当前值 |
|
||
| `performance.perfTarget` | `100` | 绩效目标值 |
|
||
| `income.thisMonth[]` | 4 条 | 本月收入明细(基础课时费/激励课时费/充值提成/酒水提成) |
|
||
| `income.lastMonth[]` | 4 条 | 上月收入明细 |
|
||
| `notes[]` | 3 条 | 备注记录 |
|
||
|
||
#### mockVisibleTasks / mockHiddenTasks 字段明细
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `typeLabel` | 任务类型文案(高优先召回/优先召回/关系构建/客户回访) |
|
||
| `typeClass` | 样式类名 |
|
||
| `customerName` | 客户姓名 |
|
||
| `noteCount` | 备注数量 |
|
||
| `pinned` | 是否置顶 |
|
||
| `notes[]` | 备注列表(pinned/text/date) |
|
||
|
||
#### mockAbandonedTasks 字段明细
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `customerName` | 客户姓名 |
|
||
| `reason` | 放弃原因(客户拒绝/超时未响应) |
|
||
|
||
#### mockTopCustomers 字段明细(20 条)
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `id` | 客户 ID |
|
||
| `name` | 客户姓名 |
|
||
| `initial` | 姓氏首字(头像占位) |
|
||
| `avatarGradient` | 头像渐变色 key |
|
||
| `heartEmoji` | 爱心 emoji(💖/🧡/💛/💙) |
|
||
| `score` | 亲密度评分 |
|
||
| `scoreColor` | 评分颜色 key |
|
||
| `serviceCount` | 服务次数 |
|
||
| `balance` | 储值余额 |
|
||
| `consume` | 消费金额 |
|
||
|
||
#### mockServiceRecords 字段明细(4 条)
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `customerId` | 客户 ID(可选) |
|
||
| `customerName` | 客户姓名 |
|
||
| `initial` | 姓氏首字 |
|
||
| `avatarGradient` | 头像渐变色 key |
|
||
| `type` | 服务类型(基础课/激励课) |
|
||
| `typeClass` | 样式类名 |
|
||
| `table` | 台号 |
|
||
| `duration` | 时长 |
|
||
| `income` | 收入 |
|
||
| `date` | 日期 |
|
||
| `perfHours` | 定档绩效时长(可选) |
|
||
|
||
#### mockHistoryMonths 字段明细(5 条)
|
||
|
||
| 字段 | 说明 |
|
||
|------|------|
|
||
| `month` | 月份标签(本月/上月/4月/3月/2月) |
|
||
| `estimated` | 是否预估 |
|
||
| `customers` | 服务客户数 |
|
||
| `hours` | 业绩时长 |
|
||
| `salary` | 工资 |
|
||
| `callbackDone` | 回访完成数 |
|
||
| `recallDone` | 召回完成数 |
|
||
|
||
### A2. 外部 Mock 引用(mock-data.ts)
|
||
|
||
| 引用 | 用途 | 代码位置 |
|
||
|------|------|----------|
|
||
| `mockCoaches` | `loadData()` 中通过 `mockCoaches.find(c => c.id === id)` 匹配助教 ID,取 `id` 和 `name` 覆盖 mockCoachDetail | `coach-detail.ts` L197-198 |
|
||
|
||
> `mockCoaches` 来自 `utils/mock-data.ts`,类型为 `CoachCard[]`,含 3 条记录(coach-001/002/003)。
|
||
|
||
---
|
||
|
||
## 二、硬编码数据
|
||
|
||
| 位置 | 硬编码内容 | 说明 |
|
||
|------|-----------|------|
|
||
| `loadData()` perfCards[0].sub | `'折算前 89.0h'` | 应由 API 返回折算前时长 |
|
||
| `loadData()` perfCards[1].sub | `'含预估部分'` | 固定文案 |
|
||
| `loadData()` perfCards[2].sub | `` `${detail.customerCount}位客户合计` `` | 模板拼接,customerCount 来自 mock |
|
||
| `loadData()` perfCards[3].sub | `'覆盖 22 位客户'` | 应由 API 返回覆盖客户数 |
|
||
| `loadData()` tierNodes | `[0, 100, 130, 160, 190, 220]` | 绩效档位节点,注释标注"Mock,实际由接口返回" |
|
||
| `loadData()` maxHours | `220` | 进度条最大值,应与 tierNodes 联动 |
|
||
| `data.taskStats` | `{ recall: 24, callback: 14 }` | 任务统计,应由 API 返回 |
|
||
| 动画常量 SHINE_SPEED | `70` | 进度条动画速度 |
|
||
| 动画常量 SPARK_DELAY_MS | `-150` | 火花延迟 |
|
||
| 动画常量 SPARK_DUR_MS | `1400` | 火花持续时间 |
|
||
| 动画常量 NEXT_LOOP_DELAY_MS | `400` | 下一轮延迟 |
|
||
| 动画常量 SHINE_WIDTH_RPX / TRACK_WIDTH_RPX | `120 / 634` | 进度条尺寸参数(UI 常量,非业务数据) |
|
||
|
||
---
|
||
|
||
## 三、已对接 API
|
||
|
||
**无。** 当前页面 0 个真实 API 调用。
|
||
|
||
`loadData()` 使用 `setTimeout(500ms)` 模拟异步加载,内部全部使用 mock 数据。
|
||
|
||
代码中有两处 TODO 注释标记了待对接接口:
|
||
1. `// TODO: 替换为真实 API 调用 GET /api/coaches/:id` — `loadData()` 内
|
||
2. `// TODO: 替换为真实 API 调用 POST /api/xcx/notes` — `onNoteConfirm()` 内
|
||
|
||
---
|
||
|
||
## 四、前端计算/派生数据
|
||
|
||
| 字段 | 计算逻辑 | 依赖数据 |
|
||
|------|----------|----------|
|
||
| `perfCards[]` | 由 `detail.performance` 各字段组装为展示卡片数组 | `performance.*` (mock) |
|
||
| `perfGap` | `perfTarget - perfCurrent` | `performance.perfTarget/perfCurrent` (mock) |
|
||
| `perfPercent` | `Math.min(Math.round(perfCurrent/perfTarget*100), 100)` | 同上 |
|
||
| `pbFilledPct` | `Math.min(100, Math.round(totalHours/maxHours*1000)/10)` | `performance.monthlyHours` + 硬编码 `maxHours=220` |
|
||
| `pbCurrentTier` | 遍历 tierNodes 找到当前所在档位 | `performance.monthlyHours` + 硬编码 `tierNodes` |
|
||
| `pbTicks[]` | `buildTicks(tierNodes, maxHours)` — 计算每个档位的 left 百分比 | 硬编码 `tierNodes` + `maxHours` |
|
||
| `incomeTotal` | `items.reduce()` 累加当前 tab 的收入金额 | `detail.income.thisMonth/lastMonth` (mock) |
|
||
| `currentIncome` | 根据 `incomeTab` 切换本月/上月数据 | `detail.income.*` (mock) |
|
||
| `sortedNotes` | `sortByTimestamp(detail.notes, 'timestamp')` 按时间降序排列 | `detail.notes` (mock) |
|
||
| `pbShineDurMs` | `calcShineDur(filledPct)` — 根据填充百分比计算动画时长 | `pbFilledPct` (派生) |
|
||
| `pbClampedSparkPct` | `Math.max(0, Math.min(100, pbFilledPct))` | `pbFilledPct` (派生) |
|
||
| 新备注 `newNote` | `onNoteConfirm()` 中用 `Date.now()` 生成 ID 和时间 | 用户输入 `content` + 当前时间 |
|
||
|
||
---
|
||
|
||
## 五、路由参数
|
||
|
||
| 参数 | 来源 | 用途 |
|
||
|------|------|------|
|
||
| `options.id` | `onLoad(options)` 从页面路由 query 获取 | 赋值给 `coachId`,传入 `loadData(id)` 用于匹配 mockCoaches |
|
||
|
||
---
|
||
|
||
## 六、WXML 硬编码文案
|
||
|
||
| 文案 | 位置 | 说明 |
|
||
|------|------|------|
|
||
| `加载中...` | 加载态 toast | 状态提示 |
|
||
| `未找到助教信息` | 空态 | 状态提示 |
|
||
| `加载失败` | 错误态 | 状态提示 |
|
||
| `点击重试` | 错误态按钮 | 操作文案 |
|
||
| `绩效概览` | section 标题 | 固定文案 |
|
||
| `绩效档位进度` | 进度条标题 | 固定文案 |
|
||
| `距下一档还差 {{perfGap}}h` | 进度条提示 | 模板 + 派生数据 |
|
||
| `收入明细` | section 标题 | 固定文案 |
|
||
| `本月` / `上月` | 收入 Tab | 固定文案 |
|
||
| `预估` | 收入 Tab 标签 | 固定文案 |
|
||
| `合计(预估)` / `合计` | 收入合计行 | 条件文案 |
|
||
| `任务执行` | section 标题 | 固定文案 |
|
||
| `本月完成` | 任务统计标签 | 固定文案 |
|
||
| `回访` / `召回` + `个` | 任务统计 | 固定文案 |
|
||
| `收起 ↑` / `展开全部 ↓` | 任务折叠按钮 | 条件文案 |
|
||
| `客户关系 TOP20` | section 标题 | 固定文案 |
|
||
| `近60天` | 客户关系副标题 | 固定文案(应由 API 返回时间范围) |
|
||
| `近期服务明细` | section 标题 | 固定文案 |
|
||
| `查看更多服务记录 →` | 服务明细底部 | 操作文案 |
|
||
| `更多信息` | section 标题 | 固定文案 |
|
||
| `入职日期` | 更多信息标签 | 固定文案 |
|
||
| `备注记录` + `共 {{sortedNotes.length}} 条` | section 标题 | 固定 + 动态 |
|
||
| `暂无备注` | 备注空态 | 状态提示 |
|
||
| `问问助手` | 底部按钮 | 操作文案 |
|
||
| `备注` | 底部按钮 | 操作文案 |
|
||
| `备注已保存` | Toast 提示 | 操作反馈 |
|
||
| `页面跳转失败` | 多处 navigateTo fail | 错误提示 |
|
||
| 历史表头:`月份` / `服务客户` / `访/召完成` / `业绩时长` / `工资` | 历史月度表格 | 固定文案 |
|
||
|
||
---
|
||
|
||
## 七、引用组件
|
||
|
||
| 组件 | 路径 | 用途 |
|
||
|------|------|------|
|
||
| `coach-level-tag` | `/components/coach-level-tag/` | 助教等级标签(接收 `level` prop) |
|
||
| `perf-progress-bar` | `/components/perf-progress-bar/` | 绩效进度条(接收多个动画参数 prop) |
|
||
| `note-modal` | `/components/note-modal/` | 备注弹窗(接收 `visible`/`customerName`,emit `confirm`/`cancel`) |
|
||
| `dev-fab` | `/components/dev-fab/` | 开发调试浮动按钮 |
|
||
| `t-loading` | TDesign | 加载动画 |
|
||
| `t-icon` | TDesign | 图标 |
|
||
| `t-tag` | TDesign | 标签(已注册但 WXML 中未使用) |
|
||
|
||
---
|
||
|
||
## 八、引用工具函数
|
||
|
||
| 函数 | 来源 | 用途 |
|
||
|------|------|------|
|
||
| `sortByTimestamp` | `utils/sort.ts` | 对备注列表按 `timestamp` 字段降序排序 |
|
||
|
||
---
|
||
|
||
## 九、联调 TODO 清单
|
||
|
||
### 优先级 P0 — 核心数据
|
||
|
||
| # | 待对接接口 | 替换目标 | 涉及字段 |
|
||
|---|-----------|----------|----------|
|
||
| 1 | `GET /api/xcx/coaches/:id` | `mockCoachDetail` 全部字段 | 基本信息、绩效、收入、备注 |
|
||
| 2 | `GET /api/xcx/coaches/:id/tasks` | `mockVisibleTasks` + `mockHiddenTasks` + `mockAbandonedTasks` | 任务列表(含备注) |
|
||
| 3 | `GET /api/xcx/coaches/:id/top-customers` | `mockTopCustomers` | 客户关系 TOP20 |
|
||
| 4 | `GET /api/xcx/coaches/:id/service-records` | `mockServiceRecords` | 近期服务明细 |
|
||
| 5 | `GET /api/xcx/coaches/:id/history` | `mockHistoryMonths` | 历史月度汇总 |
|
||
| 6 | `POST /api/xcx/notes` | `onNoteConfirm()` 内联构造 | 新增备注 |
|
||
|
||
### 优先级 P1 — 硬编码需接口化
|
||
|
||
| # | 硬编码项 | 当前值 | 建议 |
|
||
|---|---------|--------|------|
|
||
| 7 | `tierNodes` | `[0,100,130,160,190,220]` | 由接口 #1 返回绩效档位配置 |
|
||
| 8 | `taskStats` | `{recall:24, callback:14}` | 由接口 #2 返回任务统计汇总 |
|
||
| 9 | perfCards[0].sub `'折算前 89.0h'` | 硬编码 | 由接口 #1 返回折算前时长 |
|
||
| 10 | perfCards[3].sub `'覆盖 22 位客户'` | 硬编码 | 由接口 #1 返回覆盖客户数 |
|
||
| 11 | WXML `近60天` | 硬编码 | 由接口 #3 返回统计时间范围 |
|
||
|
||
### 优先级 P2 — 清理项
|
||
|
||
| # | 项目 | 说明 |
|
||
|---|------|------|
|
||
| 12 | 删除页面内联 mock 常量 | 7 个 mock 变量 + 接口类型定义迁移到 types |
|
||
| 13 | 移除 `import { mockCoaches }` | 联调后不再需要 mock-data.ts 依赖 |
|
||
| 14 | 移除 `setTimeout(500ms)` 模拟延迟 | 替换为真实异步请求 |
|
||
| 15 | `t-tag` 组件注册但未使用 | 从 JSON 中移除或确认是否需要 |
|