# task-list 页面数据来源排查 > 排查日期:2026-03-18 > 页面路径:pages/task-list/task-list > 引用文件:`utils/mock-data.ts`、`utils/money.ts`、`utils/time.ts`、`utils/request.ts`(未使用) ## 概览 | 分类 | 数量 | 说明 | |------|------|------| | Mock 数据 | 28 个字段 | 全部任务列表 + 业绩进度卡片均来自 mock | | 硬编码数据 | 12 个字段 | 用户信息、头像、动画参数、AI 建议文案等 | | 已对接 API | 0 个接口 | 页面当前无任何真实 API 调用 | | 前端计算/派生 | 14 个字段 | enrichTask 派生字段 + 进度条动画计算 | | 路由参数 | 0 个 | onLoad 未读取 options | | WXML 硬编码文案 | 5 处 | 标题、分组标签等 UI 文案 | --- ## 一、Mock 数据 ### 1.1 来自 mock-data.ts #### 1.1.1 `mockTasks` — 任务列表主数据 | 字段 | 类型 | 说明 | 联调替换 API | |------|------|------|-------------| | `id` | `string` | 任务 ID | `GET /api/xcx/tasks` | | `customerName` | `string` | 客户姓名 | 同上 | | `customerAvatar` | `string` | 客户头像 URL | 同上 | | `taskType` | `TaskType` | 任务类型枚举:`callback` / `priority_recall` / `relationship` / `high_priority` | 同上 | | `taskTypeLabel` | `string` | 任务类型中文标签 | 同上(或前端根据 taskType 映射) | | `deadline` | `string` | 截止日期 ISO 字符串 | 同上 | | `heartScore` | `number` | 爱心评分 0-10 | 同上 | | `hobbies` | `string[]` | 客户爱好标签 | 同上 | | `isPinned` | `boolean` | 是否置顶 | 同上 | | `hasNote` | `boolean` | 是否有备注 | 同上 | | `status` | `'pending' \| 'completed' \| 'abandoned'` | 任务状态 | 同上 | - 导入方式:`import { mockTasks } from '../../utils/mock-data'`(task-list.ts L2) - `loadData()` 中直接展开 `mockTasks` 并追加了一条内联 mock 任务 `task-007`(见 1.2 节) #### 1.1.2 `mockPerformance` — 绩效概览数据 | 字段 | 类型 | 当前 Mock 值 | 联调替换 API | |------|------|-------------|-------------| | `monthlyIncome` | `number` | `12680` | `GET /api/xcx/performance/summary` | | `incomeChange` | `number` | `15.3` | 同上 | | `currentTier` | `string` | `'银牌助教'` | 同上 | | `nextTierGap` | `number` | `3320` | 同上 | | `todayServiceCount` | `number` | `4` | 同上 | | `weekServiceCount` | `number` | `18` | 同上 | | `monthServiceCount` | `number` | `67` | 同上 | - 导入方式:`import { mockPerformance } from '../../utils/mock-data'`(task-list.ts L2) - 当前仅用 `mockPerformance.currentTier` 赋值给 `bannerTitle`(L233) ### 1.2 页面内联 Mock #### 1.2.1 `task-007` 内联任务(loadData 内,约 L213-L225) ```typescript { id: 'task-007', customerName: '孙丽', customerAvatar: '/assets/images/avatar-default.png', taskType: 'callback', taskTypeLabel: '客户回访', deadline: '2026-03-06', heartScore: 3.5, hobbies: [], isPinned: false, hasNote: false, status: 'abandoned', } ``` - 联调时需删除,改为 API 返回的完整任务列表 #### 1.2.2 `buildPerfData()` — 业绩进度卡片构造函数(约 L130-L160) | 字段 | Mock 值 | 说明 | 联调替换 API | |------|---------|------|-------------| | `nextTierHours` | `100` | 下一档位小时数 | `GET /api/xcx/performance/progress` | | `remainHours` | `12.5` | 距下一档剩余小时 | 同上 | | `currentTier` | `1` | 当前档位序号 | 同上 | | `tierProgress` | `58` | 当前段内进度% | 同上(或前端计算) | | `filledPct` | `39.8`(87.5/220×100) | 总进度条百分比 | 同上(或前端计算) | | `ticks` | `buildTicks([0,100,130,160,190,220], 220)` | 刻度数组 | 同上(档位节点由接口返回) | | `basicHours` | `'77.5'` | 基础课时 | 同上 | | `bonusHours` | `'12'` | 激励课时 | 同上 | | `totalHours` | `'87.5'` | 总课时 | 同上 | | `tierCompleted` | `true` | 是否达标 | 同上 | | `bonusMoney` | `'800'` | 达标奖金(元) | 同上 | | `incomeMonth` | `'2月'` | 收入月份 | 同上 | | `prevMonth` | `'1月'` | 对比月份 | 同上 | | `incomeFormatted` | `'6,206'` | 预计收入格式化 | 同上 | | `incomeTrend` | `'↓368'` | 收入趋势文案 | 同上 | | `incomeTrendDir` | `'down'` | 趋势方向 | 同上 | #### 1.2.3 `enrichTask()` 内联 Mock 逻辑(约 L100-L125) | 派生字段 | Mock 算法 | 说明 | |----------|-----------|------| | `lastVisitDays` | `(id.charCodeAt(last) % 15) + 1` | 伪随机天数,联调时应由 API 返回 | | `balanceLabel` | `formatMoney((id.charCodeAt(last) * 137) % 5000 + 200)` | 伪随机余额,联调时应由 API 返回 | | `aiSuggestion` | 从 5 条硬编码文案中按 id 取模选取 | 联调时应由 AI 接口返回 | 5 条硬编码 AI 建议文案: 1. `'建议推荐斯诺克进阶课程,提升客户粘性'` 2. `'客户近期消费下降,建议电话关怀了解原因'` 3. `'适合推荐周末球友赛活动,增强社交体验'` 4. `'高价值客户,建议维护关系并推荐VIP权益'` 5. `'新客户首次体验后未续费,建议跟进意向'` #### 1.2.4 `loadData()` 中的 600ms 模拟延迟 ```typescript setTimeout(() => { /* 全部数据构造逻辑 */ }, 600) ``` - 联调时替换为真实 API 请求 --- ## 二、硬编码数据 | 字段 | 当前值 | 应改为 | 风险 | 所在位置 | |------|--------|--------|------|----------| | `userName` | `'小燕'` | `globalData.userInfo.name` 或登录 API | 高 | data 初始化 | | `userRole` | `'助教'` | `globalData.userInfo.role` 或登录 API | 高 | data 初始化 | | `storeName` | `'广州朗朗桌球'` | `globalData.storeInfo.name` 或登录 API | 高 | data 初始化 | | `avatarUrl` | `'/assets/images/avatar-coach.png'` | `globalData.userInfo.avatar` 或登录 API | 中 | data 初始化 | | `DETAIL_ROUTE` | `'/pages/task-detail/task-detail'` | 保持硬编码(路由常量) | 低 | 常量定义 | | `tierNodes` | `[0, 100, 130, 160, 190, 220]` | 业绩进度 API 返回 | 高 | `buildPerfData()` + `_applyDebugHours()` | | `maxHours` | `220` | 业绩进度 API 返回 | 高 | `buildPerfData()` | | `total` | `87.5` | 业绩进度 API 返回 | 高 | `buildPerfData()` | | `aiColor` | 随机选取 `['red','orange','yellow','blue','indigo','purple']` | 可保持前端随机(纯 UI) | 低 | `onLoad()` / `onShow()` | | `abandonReason` | `'客户已转至其他门店'` | API 返回(放弃原因由用户输入) | 中 | `enrichTask()` | | `suggestions[]` | 5 条固定文案 | AI 建议 API 返回 | 高 | `enrichTask()` | | `hasMore` | `true` → 触底后 `false` | 分页 API 返回 `has_next` | 中 | `loadData()` / `onReachBottom()` | --- ## 三、已对接 API **当前页面无任何真实 API 调用。** - `utils/request.ts` 已导出 `request()` 函数(支持 token 自动附加、401 刷新重试) - task-list.ts 未 import `request`,所有数据均来自 mock --- ## 四、前端计算/派生数据 ### 4.1 任务分组(loadData 内) | 派生字段 | 计算逻辑 | 依赖源数据 | |----------|----------|-----------| | `pinnedTasks` | `enriched.filter(t => t.isPinned && !t.isAbandoned)` | `allTasks` | | `normalTasks` | `enriched.filter(t => !t.isPinned && !t.isAbandoned && t.status === 'pending')` | `allTasks` | | `abandonedTasks` | `enriched.filter(t => t.isAbandoned)` | `allTasks` | | `taskCount` | `pinnedTasks.length + normalTasks.length + abandonedTasks.length` | 三组任务 | | `pageState` | `totalCount > 0 ? 'normal' : 'empty'` | `taskCount` | ### 4.2 enrichTask 派生字段 | 派生字段 | 计算逻辑 | 依赖 | |----------|----------|------| | `isAbandoned` | `task.status === 'abandoned'` | `task.status` | | `deadlineLabel` | `formatDeadline(task.deadline).text` | `task.deadline` + `utils/time.ts` | | `deadlineStyle` | `formatDeadline(task.deadline).style` | `task.deadline` + `utils/time.ts` | | `balanceLabel` | `formatMoney(balanceSeedNum)` | Mock 种子值 + `utils/money.ts`(联调后改为 API 余额) | ### 4.3 进度条动画计算 | 派生字段 | 计算逻辑 | 依赖 | |----------|----------|------| | `filledPct` | `Math.min(100, (total / 220) * 100)` | `total`、`maxHours` | | `clampedSparkPct` | `Math.max(0, Math.min(100, filledPct))` | `filledPct` | | `shineDurMs` | `calcShineDur(filledPct)` — 基于 `SHINE_SPEED` 和进度百分比 | `filledPct`、`SHINE_SPEED` | | `ticks[]` | `buildTicks(tierNodes, maxHours)` — 计算每个刻度的 `left` 百分比位置 | `tierNodes`、`maxHours` | ### 4.4 调试面板计算(`_applyDebugHours`) | 派生字段 | 说明 | |----------|------| | `currentTier` | 遍历 tiers 数组确定当前档位 | | `tierProgress` | 当前段内进度百分比 | | `remainHours` | `nextTierHours - total` | | `tierCompleted` | `total >= 220` | > 调试面板仅开发阶段使用,联调时可保留或移除。 --- ## 五、路由参数 `onLoad()` 未读取任何 `options` 参数。页面作为 TabBar 页面,不接收路由参数。 --- ## 六、WXML 中的硬编码文案 | 文案 | 位置 | 类型 | 说明 | |------|------|------|------| | `'今日 客户维护'` | section-header | UI 文案 | 可保持硬编码,或由 API 返回标题 | | `'📌 置顶'` | group-label--pinned | UI 文案 | 保持硬编码 | | `'正常任务'` | group-label--normal | UI 文案 | 保持硬编码 | | `'已放弃'` | group-label--abandoned | UI 文案 | 保持硬编码 | | `'暂无待办任务'` | state-empty | UI 文案 | 保持硬编码 | | `'加载失败,请重试'` | state-error | UI 文案 | 保持硬编码 | | `'没有更多了'` | load-more | UI 文案 | 保持硬编码 | | `'最近到店:{{...}}天前 · 余额:{{...}}'` | card-row-2 | 模板文案 | 保持硬编码(数据部分由变量填充) | | `'放弃原因:{{...}}'` | card-row-abandon | 模板文案 | 保持硬编码 | | `'基础课 \| 激励课 \| 全部'` | hours-label | UI 文案 | 保持硬编码 | > 以上均为 UI 展示文案,非业务数据硬编码,联调时无需替换。 --- ## 七、联调 TODO ### 高优先(P0 — 页面核心功能) - [ ] 替换 `mockTasks` + 内联 `task-007` 为 `GET /api/xcx/tasks` API 调用 - [ ] 替换 `buildPerfData()` 为 `GET /api/xcx/performance/progress` API 调用 - [ ] 从 `globalData` 或登录 API 获取 `userName`、`userRole`、`storeName`、`avatarUrl` - [ ] 替换 `enrichTask()` 中的 mock 派生字段(`lastVisitDays`、`balanceLabel`)为 API 返回字段 - [ ] 替换 `enrichTask()` 中的 `aiSuggestion` 硬编码文案为 AI 建议 API - [ ] 替换 `mockPerformance` 引用为真实绩效 API - [ ] 档位节点 `tierNodes` 和 `maxHours` 改为 API 返回 ### 中优先(P1 — 交互完整性) - [ ] 实现分页加载:`onReachBottom` 对接分页 API(`page` / `cursor` 参数) - [ ] `onCtxPin` 置顶操作对接 `POST /api/xcx/tasks/{id}/pin` API - [ ] `onCtxAbandon` / `onAbandonConfirm` 放弃操作对接 `POST /api/xcx/tasks/{id}/abandon` API - [ ] `onCtxCancelAbandon` 取消放弃对接 `POST /api/xcx/tasks/{id}/cancel-abandon` API - [ ] `onNoteConfirm` 备注保存对接 `POST /api/xcx/tasks/{id}/notes` API - [ ] `loadData` 中移除 `setTimeout 600ms` 模拟延迟 ### 低优先(P2 — 可后续处理) - [ ] 移除 `enrichTask()` 函数(字段由 API 直接返回) - [ ] 移除 `buildPerfData()` 函数(数据由 API 直接返回) - [ ] 移除 `buildTicks()` 函数(或保留为前端工具函数,接收 API 返回的 tierNodes) - [ ] 评估是否保留调试面板(`showDebugPanel` 相关逻辑) - [ ] 清理 `mock-data.ts` 中 task-list 不再使用的导出 --- ## 八、依赖组件清单 | 组件 | 路径 | 数据来源 | |------|------|----------| | `perf-progress-bar` | `/components/perf-progress-bar/` | 接收 `perfData.*` 属性(全部 mock) | | `heart-icon` | `/components/heart-icon/` | 接收 `item.heartScore`(mock) | | `ai-inline-icon` | `/components/ai-inline-icon/` | 接收 `aiColor`(前端随机) | | `ai-float-button` | `/components/ai-float-button/` | 无数据依赖 | | `note-modal` | `/components/note-modal/` | 接收 `noteTarget.customerName`(mock) | | `abandon-modal` | `/components/abandon-modal/` | 接收 `abandonTarget.customerName`(mock) | | `dev-fab` | `/components/dev-fab/` | 无数据依赖(开发工具) | | `t-icon` | TDesign 组件 | 无业务数据依赖 | --- ## 九、风险总结 | 风险项 | 等级 | 说明 | |--------|------|------| | 全页面零 API 调用 | 🔴 高 | 联调时需一次性替换所有数据源,工作量集中 | | 用户信息硬编码 | 🔴 高 | `userName`/`userRole`/`storeName` 写死,多用户场景必崩 | | AI 建议文案固定 | 🔴 高 | 5 条文案轮转,联调时需对接 AI 服务 | | 业绩进度全量 mock | 🔴 高 | 档位、课时、收入全部硬编码,数值与真实数据无关 | | 分页未实现 | 🟡 中 | `onReachBottom` 仅显示"没有更多了",无真实分页 | | 操作无持久化 | 🟡 中 | 置顶/放弃/备注仅修改本地 data,刷新即丢失 | | `enrichTask` 伪随机 | 🟡 中 | `lastVisitDays`/`balanceLabel` 由 id 字符码计算,非真实数据 |