task-detail 页面数据来源排查
排查日期:2026-03-18
页面路径:pages/task-detail/task-detail
概览
| 分类 |
数量 |
说明 |
| Mock 数据 |
12 个字段 |
来自 mock-data.ts 的 mockTaskDetails + 页面内联 mock 备注 |
| 硬编码数据 |
18 个字段/数组 |
维客线索、话术参考、服务记录、服务汇总、手机号、储值等级等 |
| 已对接 API |
0 个接口 |
当前无任何真实 API 调用 |
| 前端计算/派生 |
7 个字段 |
关系等级、Banner 背景、AI 配色、时间标签等 |
| 路由参数 |
1 个 |
id(任务 ID) |
| WXML 硬编码文案 |
6 处 |
建议文案、section 标题等 |
一、Mock 数据
1.1 来自 mock-data.ts(mockTaskDetails)
页面通过 import { mockTaskDetails } from '../../utils/mock-data' 引入,在 loadData() 中使用 setTimeout 模拟异步加载。
| 字段 |
类型 |
来源路径 |
联调替换 API |
detail(整体) |
TaskDetail |
mockTaskDetails.find(t => t.id === id) || mockTaskDetails[0] |
GET /api/tasks/{id} |
detail.id |
string |
TaskDetail.id |
同上 |
detail.customerName |
string |
TaskDetail.customerName |
同上 |
detail.customerAvatar |
string |
TaskDetail.customerAvatar |
同上 |
detail.taskType |
TaskType |
TaskDetail.taskType('callback' | 'priority_recall' | 'relationship' | 'high_priority') |
同上 |
detail.taskTypeLabel |
string |
TaskDetail.taskTypeLabel |
同上 |
detail.heartScore |
number |
TaskDetail.heartScore |
同上 |
detail.status |
'pending' | 'completed' | 'abandoned' |
TaskDetail.status |
同上 |
detail.aiAnalysis.summary |
string |
TaskDetail.aiAnalysis.summary |
GET /api/tasks/{id}/ai-analysis |
detail.aiAnalysis.suggestions |
string[] |
TaskDetail.aiAnalysis.suggestions |
同上 |
detail.hobbies |
string[] |
TaskDetail.hobbies |
GET /api/tasks/{id} |
detail.deadline |
string |
TaskDetail.deadline |
同上 |
mock-data.ts 中 TaskDetail 扩展字段(已定义但页面未直接渲染):
| 字段 |
类型 |
说明 |
lastVisitDate |
string? |
最后到店日期,页面未使用 |
lastSpendAmount |
number? |
最后消费金额,页面未使用 |
callbackReason |
string? |
回访原因,页面未使用 |
daysAbsent |
number? |
缺席天数,页面未使用 |
spendTrend |
'up' | 'down' | 'flat'? |
消费趋势,页面未使用 |
churnRisk |
'high' | 'medium' | 'low'? |
流失风险,页面未使用 |
preferences |
string[]? |
偏好,页面未使用 |
consumptionHabits |
string? |
消费习惯,页面未使用 |
socialPreference |
string? |
社交偏好,页面未使用 |
1.2 页面内联 Mock 备注
loadData() 方法内部硬编码了 5 条 mock 备注(mockNotes 局部变量,L107-L113),覆盖了 mockTaskDetails 中的 notes 字段:
| 字段 |
当前值 |
联调替换 API |
mockNotes[0] |
'已通过微信联系王先生...',score=10 |
GET /api/tasks/{id}/notes |
mockNotes[1] |
'王先生最近出差较多...',score=7.5 |
同上 |
mockNotes[2] |
'上次到店时推荐了会员续费活动...',score=6 |
同上 |
mockNotes[3] |
'客户对今天的服务非常满意...',score=9.5 |
同上 |
mockNotes[4] |
'完成高优先召回任务...',score=8 |
同上 |
二、硬编码数据
2.1 维客线索(retentionClues)
风险:高 — 8 条完整的维客线索数据直接写死在 data 对象中(L68-L77),应从 API 获取。
| 索引 |
tag |
text(摘要) |
source |
所在行 |
应改为 |
| 0 |
客户基础 |
'生日 3月15日 · VIP会员 · 注册2年' |
By:系统 |
L69 |
GET /api/tasks/{id}/retention-clues |
| 1 |
消费习惯 |
'常来夜场 · 月均4-5次' |
By:系统 |
L70 |
同上 |
| 2 |
消费习惯 |
'高客单价'(含 desc) |
By:系统 |
L71 |
同上 |
| 3 |
玩法偏好 |
'偏爱中式八球 · 斯诺克进阶中...'(含 desc) |
By:系统 |
L72 |
同上 |
| 4 |
重要反馈 |
'上次提到想练斯诺克走位'(含 desc) |
By:小燕 |
L73 |
同上 |
| 5 |
社交偏好 |
'喜欢带朋友来玩 · 社交型客户'(含 desc) |
By:系统 |
L74 |
同上 |
| 6 |
消费习惯 |
'酒水消费占比高 · 偏好高端酒水'(含 desc) |
By:系统 |
L75 |
同上 |
| 7 |
重要反馈 |
'上次提到想办生日派对'(含 desc) |
By:Lucy |
L76 |
同上 |
注意:mock-data.ts 中已定义 mockRetentionClues 和 RetentionClue 接口,但页面未使用,而是自行硬编码了不同结构的数据。联调时应统一数据结构。
2.2 话术参考(talkingPoints)
风险:高 — 5 条话术直接写死在 data 对象中(L80-L86),应由 AI 生成或从 API 获取。
| 索引 |
内容摘要 |
所在行 |
应改为 |
| 0 |
'王哥您好,好久不见!最近店里新到了...' |
L81 |
GET /api/tasks/{id}/talking-points 或 AI 生成接口 |
| 1 |
'王哥,最近忙吗?这周末我们有个...' |
L82 |
同上 |
| 2 |
'王哥好呀,上次您提到想练练...' |
L83 |
同上 |
| 3 |
'王哥,好久没见您了,您的老位置...' |
L84 |
同上 |
| 4 |
'王哥您好,我们这个月推出了...' |
L85 |
同上 |
2.3 近期服务记录(serviceRecords)
风险:高 — 4 条服务记录直接写死在 data 对象中(L91-L96),应从 API 获取。
| 索引 |
table |
type |
income |
date |
所在行 |
应改为 |
| 0 |
A12号台 |
基础课 |
¥200 |
2月7日 21:30 |
L92 |
GET /api/tasks/{id}/service-records |
| 1 |
3号台 |
基础课 |
¥160 |
2月1日 20:30 |
L93 |
同上 |
| 2 |
VIP1号房 |
包厢课 |
¥150 |
1月28日 19:00 |
L94 |
同上 |
| 3 |
(空) |
充值 |
¥80 |
1月15日 10:00 |
L95 |
同上 |
2.4 服务汇总(serviceSummary)
风险:高 — 汇总数据直接写死(L90),应由后端计算或前端根据服务记录列表聚合。
| 字段 |
当前值 |
所在行 |
应改为 |
totalHours |
6.0 |
L90 |
后端返回或前端聚合 serviceRecords |
totalIncome |
510 |
L90 |
同上 |
avgIncome |
170 |
L90 |
同上 |
2.5 手机号
风险:高 — 手机号硬编码在两处。
| 位置 |
当前值 |
所在行 |
应改为 |
WXML 中 phone 显示 |
'138****5678'(脱敏)/ '13812345678'(明文) |
wxml L38 |
从 detail 对象获取,API 返回脱敏版 |
onCopyPhone() 方法 |
'13812345678' |
ts L175 |
调用 API 获取明文手机号 GET /api/customers/{id}/phone |
2.6 储值等级
风险:中 — 直接写死在 data 中。
| 字段 |
当前值 |
所在行 |
应改为 |
storageLevel |
'非常多' |
ts L101 |
从 detail 或客户信息 API 获取 |
2.7 关系等级初始值
风险:低 — 初始值会被 updateRelationshipDisplay() 覆盖,但仍属于硬编码。
| 字段 |
当前值 |
所在行 |
说明 |
relationLevel |
'excellent' |
ts L104 |
初始值,loadData 后被覆盖 |
relationLevelText |
'很好' |
ts L105 |
同上 |
relationColor |
'#e91e63' |
ts L106 |
同上 |
2.8 任务建议文案
风险:中 — WXML 中硬编码了建议引导文案。
| 位置 |
当前值 |
所在行 |
应改为 |
suggestion-intro |
'该客户已有 15 天未到店,存在流失风险。建议通过微信联系:' |
wxml L82 |
从 detail.aiAnalysis 获取或后端生成 |
三、已对接 API
当前无任何真实 API 调用。
loadData() 使用 setTimeout + mockTaskDetails 模拟异步请求(L128-L155)。所有数据操作(放弃任务、保存备注、删除备注)均为本地 setData 操作,未与后端通信。
涉及的伪操作:
| 操作 |
当前实现 |
需对接 API |
| 加载任务详情 |
mockTaskDetails.find() |
GET /api/tasks/{id} |
| 放弃任务 |
setData({ 'detail.status': 'abandoned' }) |
POST /api/tasks/{id}/abandon |
| 取消放弃 |
setData({ 'detail.status': 'pending' }) |
POST /api/tasks/{id}/cancel-abandon |
| 保存备注 |
setData({ sortedNotes: [...] }) |
POST /api/tasks/{id}/notes |
| 删除备注 |
filter 本地数组 |
DELETE /api/tasks/{id}/notes/{noteId} |
四、前端计算/派生数据
| 字段 |
计算逻辑 |
所在方法 |
依赖数据 |
relationLevel |
heartScore 分段映射:>8.5→excellent, ≥6→good, ≥3.5→normal, <3.5→poor |
updateRelationshipDisplay() L157 |
detail.heartScore |
relationLevelText |
同上分段映射为中文:很好/良好/一般/待发展 |
同上 |
同上 |
relationColor |
同上分段映射为颜色值 |
同上 |
同上 |
bannerBgSvg |
根据 detail.taskType 映射 SVG 路径 |
loadData() L133-L142 |
detail.taskType |
sortedNotes |
mockNotes → 附加 timeLabel(formatRelativeTime)→ sortByTimestamp 排序 |
loadData() L116-L118 |
mock 备注数据 |
aiColor |
随机从 6 色中选取 |
onLoad() L124 |
无(随机) |
copiedIndex |
复制话术后设为当前索引,2 秒后重置为 -1 |
onCopySpeech() L189 |
用户交互 |
pageState |
加载状态机:loading → normal/empty/error |
loadData() |
数据加载结果 |
phoneVisible |
手机号显示/隐藏切换 |
onTogglePhone() L173 |
用户交互 |
noteModalVisible |
备注弹窗显隐 |
onAddNote()/onNoteConfirm()/onNoteCancel() |
用户交互 |
abandonModalVisible |
放弃弹窗显隐 |
onAbandon()/onAbandonConfirm()/onAbandonCancel() |
用户交互 |
formatServiceDate() 返回值 |
ISO 日期 → M月D日 HH:mm 中文短格式 |
页面顶部函数 L55 |
服务记录日期字符串 |
五、路由参数
| 参数 |
来源 |
用途 |
所在行 |
options.id |
onLoad(options) |
任务 ID,用于查找 mock 数据;缺失时回退空字符串 |
ts L123 |
六、WXML 中的硬编码文案
| 文案 |
位置 |
类型 |
说明 |
'该客户已有 15 天未到店,存在流失风险。建议通过微信联系:' |
wxml L82 |
业务数据 |
应从 AI 分析结果获取 |
'💡 建议执行' |
wxml L79 |
UI 文案 |
可保留 |
'💬 话术参考' |
wxml L89 |
UI 文案 |
可保留 |
'60天内服务记录' |
wxml L121 |
UI 文案 |
"60天"为业务规则,可保留但需确认是否动态 |
'未找到任务信息' / '加载失败' / '加载中...' |
wxml L7-L15 |
状态文案 |
可保留 |
'暂无备注' |
wxml L117 |
空态文案 |
可保留 |
七、引用的工具函数
| 函数 |
来源文件 |
用途 |
mockTaskDetails |
utils/mock-data.ts |
Mock 任务详情数据 |
TaskDetail, Note |
utils/mock-data.ts |
类型定义 |
sortByTimestamp |
utils/sort.ts |
备注按时间降序排序 |
formatRelativeTime |
utils/time.ts |
备注时间 → 相对时间文案 |
formatMoney |
utils/money.ts |
金额格式化(已 import 但页面 TS 中未直接调用,WXML 使用 WXS 版) |
fmt.toFixed |
utils/format.wxs |
WXML 中数字保留小数 |
fmt.money |
utils/format.wxs |
WXML 中金额格式化 |
fmt.hours |
utils/format.wxs |
WXML 中课时格式化 |
八、引用的自定义组件
| 组件 |
路径 |
用途 |
note-modal |
/components/note-modal/note-modal |
备注弹窗 |
abandon-modal |
/components/abandon-modal/abandon-modal |
放弃任务弹窗 |
star-rating |
/components/star-rating/star-rating |
星级评分展示 |
heart-icon |
/components/heart-icon/heart-icon |
爱心图标(关系等级) |
ai-inline-icon |
/components/ai-inline-icon/ai-inline-icon |
AI 内联图标 |
ai-title-badge |
/components/ai-title-badge/ai-title-badge |
AI 标题徽章 |
clue-card |
/components/clue-card/clue-card |
维客线索卡片 |
service-record-card |
/components/service-record-card/service-record-card |
服务记录卡片 |
dev-fab |
/components/dev-fab/dev-fab |
开发调试浮动按钮(JSON 注册但 WXML 未使用) |
九、调试面板数据
页面包含一个调试面板(showDebugPanel),用于开发阶段切换任务类型和关系数值。联调前应移除或隐藏。
| 字段 |
用途 |
所在行 |
showDebugPanel |
调试面板显隐 |
ts L110 |
debugTaskType |
调试用任务类型 |
ts L111 |
debugHeartScore |
调试用关系数值 |
ts L112 |
debugShowExpandBtn |
调试用展开按钮开关 |
ts L113 |
十、联调 TODO
高优先级(数据完全依赖 Mock/硬编码)
中优先级(操作类接口)
低优先级(优化项)