小程序 Storyboard 走查报告 — 助教视角(小燕)
走查日期:2026-03-18
走查角色:助教"小燕",已登录,status=approved
对照文档:docs/miniprogram-dev/API-contract.md(契约)、docs/prd/Neo_Specs/NS1-xcx-backend-api.md(spec)
目标:提取 spec 未记录的接口需求细节
场景 1:登录 → 任务列表(app.ts)
API 调用
checkAuthStatus() → GET /api/xcx/me → 返回 ApiUserInfo
- 参数来源:token 从
wx.getStorageSync('token') 读取
- 成功后根据
data.status 路由:approved → reLaunch('/pages/task-list/task-list')
前端期望字段(/api/xcx/me 响应)
| 字段 |
类型 |
说明 |
契约定义 |
user_id |
number |
用户 ID |
✅ |
status |
enum |
new/pending/approved/rejected/disabled |
✅ |
nickname |
string |
昵称 |
✅ |
role |
string |
角色 |
✅ REQ-4 |
store_name |
string |
门店名 |
✅ REQ-4 |
coach_level |
string? |
助教等级 |
✅ REQ-4 |
avatar |
string? |
头像 URL |
✅ REQ-4 |
globalData 结构
spec 未记录的 Gap
- GAP-01:
globalData.authUser 未存储 role、store_name、coach_level、avatar,但下游页面(task-list banner、performance banner、performance-records banner)需要这些字段。前端需扩展 globalData.authUser 或各页面单独请求 /me。
场景 2:任务列表页(task-list.ts)
API 调用
fetchTasks(params?) → GET /api/xcx/tasks?status=&page=&pageSize=
- 返回:
{ tasks: Task[], performance: PerformanceData, total: number, hasMore: boolean }
- 页面加载时无参数调用(获取全部任务)
前端期望字段 — Task(任务卡片)
| 字段 |
类型 |
说明 |
契约 TASK-1 |
id |
string |
任务 ID |
✅ |
customerName |
string |
客户姓名 |
✅ |
customerAvatar |
string |
客户头像 |
✅ |
taskType |
enum |
callback/priority_recall/relationship/high_priority |
✅ |
taskTypeLabel |
string |
类型中文标签 |
✅ |
deadline |
string |
截止日期 ISO 8601 |
✅ |
heartScore |
number |
爱心评分 0-10 |
✅ |
hobbies |
string[] |
爱好标签 |
✅ |
isPinned |
boolean |
是否置顶 |
✅ |
hasNote |
boolean |
是否有备注 |
✅ |
status |
enum |
pending/completed/abandoned |
✅ |
前端期望字段 — PerformanceData(绩效概览卡片)
| 字段 |
类型 |
说明 |
契约 TASK-1 performance |
前端实际使用 |
monthlyIncome |
number |
月收入 |
❌ 契约仅有 total_income |
buildPerfData() 用 |
incomeChange |
number |
收入变化百分比 |
❌ 契约无 |
incomeTrend 展示 |
currentTier |
string |
当前档位名称 |
❌ 契约无 |
bannerTitle |
nextTierGap |
number |
距下一档差距 |
❌ 契约无 |
remainHours |
todayServiceCount |
number |
今日服务次数 |
❌ 契约无 |
未使用 |
weekServiceCount |
number |
本周服务次数 |
❌ 契约无 |
未使用 |
monthServiceCount |
number |
本月服务次数 |
❌ 契约无 |
未使用 |
前端期望字段 — buildPerfData() 需要后端返回的绩效字段
| 字段 |
类型 |
说明 |
契约/spec 定义 |
tierNodes |
number[] |
档位节点数组,如 [0,100,130,160,190,220] |
❌ 未定义 |
totalHours |
number |
当月总工时(折算后) |
契约有 total_hours |
basicHours |
number |
基础课时 |
❌ 未定义 |
bonusHours |
number |
激励课时 |
❌ 未定义 |
currentTier |
number |
当前档位索引 |
❌ 未定义 |
nextTierHours |
number |
下一档位工时阈值 |
❌ 未定义 |
tierCompleted |
boolean |
是否已达标(满档) |
❌ 未定义 |
bonusMoney |
number |
升档奖金 |
❌ 未定义 |
incomeFormatted |
string |
格式化收入 |
契约有 total_income |
incomeTrend |
string |
收入趋势(如 ↓368) |
❌ 未定义 |
incomeTrendDir |
enum |
up/down |
❌ 未定义 |
incomeMonth |
string |
当前月份标签 |
契约有 month_label |
prevMonth |
string |
上月标签 |
❌ 未定义 |
enrichTask() 需要后端返回的扩展字段
| 字段 |
类型 |
说明 |
契约/spec 定义 |
lastVisitDays |
number |
距上次到店天数 |
❌ 前端 mock 计算,后端需返回 |
balance |
number |
客户余额 |
❌ 未定义在 TASK-1 |
aiSuggestion |
string |
AI 建议摘要 |
❌ 未定义在 TASK-1 |
页面跳转
| 操作 |
目标 |
参数 |
| 点击任务卡片 |
/pages/task-detail/task-detail |
?id={taskId} |
| 点击绩效卡片 |
/pages/performance/performance |
无参数 |
| 长按→AI助手 |
/pages/ai-chat/ai-chat |
?taskId={id}&customerName={name} |
写操作
| 操作 |
API |
请求体 |
成功后行为 |
| 长按→置顶/取消置顶 |
POST /tasks/{id}/pin 或 /unpin |
无 |
本地更新 isPinned,重新分组 |
| 长按→放弃 |
POST /tasks/{id}/abandon |
{ reason: string } |
本地移至 abandonedTasks |
| 长按→取消放弃 |
POST /tasks/{id}/restore |
无 |
本地移至 normalTasks |
| 长按→添加备注 |
POST /notes |
{ content, taskId?, customerId? } |
Toast 提示 |
spec 未记录的 Gap
- GAP-02:契约 TASK-1
performance 仅有 4 个字段(total_hours/total_income/total_customers/month_label),但前端 buildPerfData() 需要 15+ 个字段(tierNodes、basicHours、bonusHours、currentTier、nextTierHours、tierCompleted、bonusMoney、incomeTrend、incomeTrendDir、prevMonth 等)。这是最大的 Gap。
- GAP-03:
enrichTask() 需要 lastVisitDays(距上次到店天数)、balance(客户余额)、aiSuggestion(AI 建议),这 3 个字段在 TASK-1 契约中未定义。后端需在任务列表 item 中附带这些字段,或前端改为进入详情页后再加载。
- GAP-04:
pin/unpin 操作的 API 端点在契约中未定义。spec 提到已实现 pin/unpin,但 api.ts 中无对应函数,前端仅做本地状态更新。需确认 API 路径(POST /tasks/{id}/pin 和 POST /tasks/{id}/unpin)。
- GAP-05:
createNote 的 score 参数 — 前端备注弹窗 onNoteConfirm 传递 { score, content },但 api.ts 的 createNote 签名仅有 { content, taskId?, customerId? },缺少 score 字段。
场景 3:任务详情页(task-detail.ts)
API 调用
fetchTaskDetail(taskId) → GET /api/xcx/tasks/{taskId}
- 参数来源:
options.id(从 task-list 跳转传入)
deleteNote(noteId) → DELETE /api/xcx/notes/{noteId}
前端期望字段 — TaskDetail(完整清单)
基础信息(继承 Task)
同 TASK-1 item 字段,契约已覆盖。
维客线索 retentionClues(内联 mock,8 条)
| 字段 |
类型 |
说明 |
契约 TASK-2 |
tag |
string |
线索大类标签(如 "客户\n基础") |
❌ 契约用 tag 但格式不同 |
tagColor |
enum |
primary/success/purple/error |
✅ tag_color |
emoji |
string |
表情符号 |
✅ |
text |
string |
线索摘要 |
✅ |
source |
string |
来源(如 "By:系统"、"By:小燕") |
⚠️ 契约有 source 但格式不同 |
desc |
string? |
详细描述(展开后显示) |
✅ |
expanded |
boolean |
展开状态(前端本地) |
— |
话术参考 talkingPoints(内联 mock,5 条)
| 字段 |
类型 |
说明 |
契约 TASK-2 |
talkingPoints |
string[] |
话术文本数组 |
✅ |
服务记录 serviceRecords(内联 mock,4 条)
| 字段 |
类型 |
说明 |
契约 TASK-2 |
table |
string |
台桌号 |
✅ |
type |
string |
课程类型标签 |
✅ |
typeClass |
enum |
basic/vip/tip/recharge/incentive |
✅ type_class |
recordType |
enum? |
course/recharge |
✅ record_type |
duration |
number |
折算后课时(小时) |
✅ |
durationRaw |
number? |
折算前课时(小时) |
✅ duration_raw |
income |
number |
收入(元) |
✅ |
isEstimate |
boolean? |
是否预估金额 |
✅ is_estimate |
drinks |
string |
酒水描述 |
✅ |
date |
string |
日期(格式化后) |
✅ |
服务汇总 serviceSummary
| 字段 |
类型 |
说明 |
契约 TASK-2 |
totalHours |
number |
总工时 |
✅ |
totalIncome |
number |
总收入 |
✅ |
avgIncome |
number |
平均收入 |
✅ |
AI 分析 aiAnalysis
| 字段 |
类型 |
说明 |
契约 TASK-2 |
summary |
string |
AI 分析摘要 |
✅ |
suggestions |
string[] |
AI 建议列表 |
✅ |
备注 notes(内联 mock,5 条)
| 字段 |
类型 |
说明 |
契约 TASK-2 |
id |
string |
备注 ID |
✅ |
content |
string |
备注内容 |
✅ |
tagType |
enum |
customer/coach/system |
✅ tag_type |
tagLabel |
string |
标签文案 |
✅ tag_label |
createdAt |
string |
创建时间 |
✅ created_at |
score |
number? |
满意度评分 0-10 |
✅ |
页面跳转
| 操作 |
目标 |
参数 |
| 问问助手 |
/pages/chat/chat |
?customerId={detail.id} |
| 查看全部服务记录 |
/pages/customer-service-records/customer-service-records |
?customerId={detail.id} |
写操作
| 操作 |
API |
请求体 |
成功后行为 |
| 添加备注 |
POST /notes |
{ content } |
本地 prepend 到 sortedNotes |
| 删除备注 |
DELETE /notes/{noteId} |
无 |
本地 filter 移除 |
| 放弃任务 |
POST /tasks/{id}/abandon |
{ reason } |
更新 detail.status='abandoned' |
| 取消放弃 |
POST /tasks/{id}/restore |
无 |
更新 detail.status='pending' |
spec 未记录的 Gap
- GAP-06:维客线索的
tag 字段格式不一致 — 前端内联 mock 使用 "客户\n基础" 格式(含换行符),契约定义为普通 string。后端需明确 tag 的取值枚举和格式。
- GAP-07:维客线索的
source 字段格式不一致 — 前端显示 "By:系统"、"By:小燕",但 mock-data.ts 中 RetentionClue.source 定义为 'manual' | 'ai_consumption' | 'ai_note'。前端内联 mock 与类型定义不匹配,后端需明确返回格式。
- GAP-08:
aiAnalysis 数据来源 — spec §3.2 提到来自 biz.ai_cache(app4/app5/app6/app7),但契约未说明 cache_type 映射关系。需明确:ai_analysis.summary 来自哪个 cache_type?talking_points 来自哪个 cache_type?
- GAP-09:task-detail 跳转 chat 时传
customerId={detail.id},但 detail.id 实际是 taskId 不是 customerId。前端需要一个 customerId 字段(TASK-2 响应中需包含 customer_id)。
- GAP-10:task-detail 跳转 customer-service-records 时同样传
customerId={detail.id},存在同样的 taskId/customerId 混淆问题。TASK-2 响应需包含 customer_id。
- GAP-11:
storageLevel(储值等级,如"非常多")和 relationLevel/relationLevelText/relationColor(关系等级)在前端本地计算,但后端未定义这些字段。后端是否需要返回,还是前端根据 heartScore 自行计算?
场景 4:绩效概览页(performance.ts)
API 调用
fetchPerformanceOverview({ year, month }) → GET /api/xcx/performance?year=&month=
- 参数来源:
new Date() 取当前年月
- 返回类型:
PerformanceData(mock-data.ts 定义)
前端期望字段 — 完整清单(对比契约 PERF-1)
Banner 数据(内联 mock,非 API 返回)
| 字段 |
类型 |
说明 |
契约 PERF-1 |
数据源 |
coachName |
string |
助教姓名 '小燕' |
❌ 未定义 |
应从 globalData.authUser 或 /me |
coachRole |
string |
角色 '助教' |
❌ 未定义 |
同上 |
storeName |
string |
门店名 '广州朗朗桌球' |
❌ 未定义 |
同上 |
monthlyIncome |
string |
本月收入 '¥6,206' |
⚠️ 契约有 total_income 但是 number |
需格式化 |
lastMonthIncome |
string |
上月收入 '¥16,880' |
❌ 未定义 |
需后端额外返回 |
收入档位(内联 mock)
| 字段 |
类型 |
说明 |
契约 PERF-1 |
currentTier.basicRate |
number |
当前档基础费率 80 |
❌ 未定义 |
currentTier.incentiveRate |
number |
当前档激励费率 95 |
❌ 未定义 |
nextTier.basicRate |
number |
下一档基础费率 90 |
❌ 未定义 |
nextTier.incentiveRate |
number |
下一档激励费率 114 |
❌ 未定义 |
upgradeHoursNeeded |
number |
距升档所需工时 15 |
❌ 未定义 |
upgradeBonus |
number |
升档奖金 800 |
❌ 未定义 |
收入明细 incomeItems(内联 mock,4 项)
| 项目 |
icon |
desc 格式 |
契约 PERF-1 |
| 基础课 |
🎱 |
80元/h × 75h |
⚠️ 契约有 income_items 但字段不同 |
| 激励课 |
⭐ |
95.05元/h × 10h |
同上 |
| 充值激励 |
💰 |
客户充值返佣 |
同上 |
| TOP3 销冠奖 |
🏆 |
全店业绩前三名奖励 |
同上 |
契约 income_items 定义:Array<{ label, amount, icon }>,缺少 desc 字段。
服务记录 thisMonthRecords(内联 mock,按日期分组)
| 字段 |
类型 |
说明 |
契约 PERF-1 |
date |
string |
日期标签 '2月7日' |
❌ 契约 this_month_records 结构完全不同 |
totalHours |
string |
当日总工时 '4.0h' |
❌ |
totalIncome |
string |
当日总收入 '¥350' |
❌ |
records[].customerName |
string |
客户名 |
⚠️ 契约有 customer_name |
records[].avatarChar |
string |
头像首字 |
❌ |
records[].avatarColor |
string |
头像颜色 |
❌ |
records[].timeRange |
string |
时间段 '20:00-22:00' |
❌ |
records[].hours |
string |
工时 '2.0h' |
⚠️ 契约有 hours 但是 number |
records[].courseType |
string |
课程类型 |
❌ |
records[].courseTypeClass |
string |
样式类 |
❌ |
records[].location |
string |
台号 |
❌ |
records[].income |
string |
收入 '¥160' |
⚠️ 契约有 income 但是 number |
新客列表 newCustomers
| 字段 |
类型 |
说明 |
契约 PERF-1 |
name |
string |
客户名 |
✅ |
avatarChar |
string |
头像首字 |
❌ 契约有 avatar_char |
avatarColor |
string |
头像颜色 |
❌ 未定义 |
lastService |
string |
最后服务日期 |
❌ 未定义 |
count |
number |
服务次数 |
❌ 未定义 |
常客列表 regularCustomers
| 字段 |
类型 |
说明 |
契约 PERF-1 |
name |
string |
客户名 |
✅ |
avatarChar |
string |
头像首字 |
❌ 契约有 avatar_char |
avatarColor |
string |
头像颜色 |
❌ 未定义 |
hours |
number |
总工时 |
❌ 未定义 |
income |
string |
总收入 |
❌ 未定义 |
count |
number |
到店次数 |
⚠️ 契约有 visits |
页面跳转
| 操作 |
目标 |
参数 |
| 查看全部记录 |
/pages/performance-records/performance-records |
无参数 |
| 点击客户卡片 |
/pages/task-detail/task-detail |
?customerName={name} |
| 点击服务记录 |
/pages/task-detail/task-detail |
?customerName={name}&taskId={taskId} |
| 点击收入概览 |
/pages/performance-records/performance-records |
无参数 |
spec 未记录的 Gap
- GAP-12:契约 PERF-1
this_month_records 是扁平数组 Array<{ customer_name, hours, income, date }>,但前端需要 按日期分组的 DateGroup 结构(含 date、totalHours、totalIncome、records[]),且每条记录需要 timeRange、courseType、courseTypeClass、location 等字段。契约需大幅扩展。
- GAP-13:收入档位数据(
currentTier、nextTier、upgradeHoursNeeded、upgradeBonus)在契约 PERF-1 中完全未定义。这些数据来自 dws_assistant_salary_calc,后端需返回。
- GAP-14:
lastMonthIncome(上月收入)在契约中未定义,前端 Banner 需要展示。
- GAP-15:
incomeItems 的 desc 字段(如 "80元/h × 75h")在契约中未定义。后端需返回费率和工时的拆分数据,或直接返回格式化的 desc 字符串。
- GAP-16:
newCustomers 缺少 lastService(最后服务日期)和 count(服务次数)字段;regularCustomers 缺少 hours(总工时)和 income(总收入)字段。
- GAP-17:跳转 task-detail 时传
customerName 而非 taskId,但 task-detail 页面 onLoad 读取的是 options.id。参数传递不匹配,联调时会导致页面无法加载正确数据。
- GAP-18:页面无月份切换功能(F8),API 支持
year/month 参数但页面固定当前月。
场景 5:绩效明细页(performance-records.ts)
API 调用
fetchPerformanceRecords({ year, month }) → GET /api/xcx/performance/records?year=&month=&page=&pageSize=
- 参数来源:
currentYear/currentMonth(页面 data,支持月份切换)
- Banner 数据从
getApp().globalData.authUser 读取
前端期望字段 — summary
| 字段 |
类型 |
说明 |
契约 PERF-2 |
totalCount |
number |
总笔数 32 |
✅ total_count |
totalHours |
number |
总工时 59.0 |
✅ total_hours |
totalHoursRaw |
number |
折算前总工时 63.5 |
✅ total_hours_raw |
totalIncome |
number |
总收入 4720 |
✅ total_income |
前端期望字段 — dateGroups(按日期分组)
| 字段 |
类型 |
说明 |
契约 PERF-2 |
date |
string |
日期标签 '2月7日' |
✅ |
totalHours |
number |
当日总工时 |
✅ |
totalIncome |
number |
当日总收入 |
✅ |
records[].id |
string |
记录 ID |
✅ |
records[].customerName |
string |
客户名 |
✅ |
records[].avatarChar |
string |
头像首字 |
❌ 未定义 |
records[].avatarColor |
string |
头像颜色 |
❌ 未定义 |
records[].timeRange |
string |
时间段 |
✅ |
records[].hours |
number |
折算后工时 |
✅ |
records[].hoursRaw |
number? |
折算前工时 |
✅ |
records[].courseType |
string |
课程类型 |
✅ |
records[].courseTypeClass |
string |
样式类 |
✅ |
records[].location |
string |
台号 |
✅ |
records[].income |
number |
收入 |
✅ |
courseTypeClass 完整枚举
前端使用的样式类:tag-basic(基础课)、tag-vip(包厢课)、tag-tip(打赏课)。
契约定义的 course_type_class:未明确枚举值。
spec 未记录的 Gap
- GAP-19:
avatarChar(头像首字)和 avatarColor(头像颜色)在契约 PERF-2 中未定义。前端通过 nameToAvatarColor() 工具函数从姓名生成,但后端是否需要返回?建议前端自行计算。
- GAP-20:
courseTypeClass 的完整枚举值未在契约中明确。前端使用 tag-basic/tag-vip/tag-tip,但后端返回的是 basic/vip/tip 还是带 tag- 前缀?需统一。
- GAP-21:月份切换时未重置分页(F9 bug),
switchMonth() 中 page 未重置为 1。
- GAP-22:Banner 字段
coachName/coachLevel/storeName 从 globalData.authUser 读取,但 authUser 当前未存储 coachLevel 和 storeName(见 GAP-01)。
场景 6:客户详情页(customer-detail.ts)
API 调用
fetchCustomerDetail(customerId) → GET /api/xcx/customers/{customerId}
- 参数来源:页面路由参数(但当前代码从
__route__ 解析,有 bug)
前端期望字段 — 完整清单
客户基本信息(内联 mock)
| 字段 |
类型 |
说明 |
契约 CUST-1 |
id |
string |
客户 ID |
✅ |
name |
string |
客户名 |
✅ |
avatarChar |
string |
头像首字 |
❌ 未定义 |
phone |
string |
手机号(完整) |
⚠️ 契约有 phone(脱敏)和 phone_full(完整) |
balance |
string |
余额 '8,600' |
❌ 未定义 |
consumption60d |
string |
近60天消费 '2,800' |
❌ 未定义 |
idealInterval |
string |
理想到店间隔 '7天' |
❌ 未定义 |
daysSinceVisit |
string |
距上次到店 '12天' |
❌ 未定义 |
AI 洞察 aiInsight(内联 mock)
| 字段 |
类型 |
说明 |
契约 CUST-1 |
summary |
string |
AI 分析摘要 |
❌ 未定义 |
strategies |
Array<{color, text}> |
策略建议列表 |
❌ 未定义 |
维客线索 clues(内联 mock,7 条)
| 字段 |
类型 |
说明 |
契约 CUST-1 |
category |
string |
线索大类(含换行符) |
⚠️ 契约说"同 TASK-2 格式" |
categoryColor |
string |
颜色 |
⚠️ |
text |
string |
含 emoji 的摘要 |
⚠️ |
source |
string |
来源 '系统'/'小燕' |
⚠️ |
detail |
string? |
详细描述 |
⚠️ |
关联助教 coachTasks(内联 mock,4 位助教)
| 字段 |
类型 |
说明 |
契约 CUST-1 |
name |
string |
助教名 |
❌ 完全未定义 |
level |
string |
等级 senior/middle/junior |
❌ |
levelColor |
string |
等级颜色 |
❌ |
taskType |
string |
任务类型标签 |
❌ |
taskColor |
string |
任务颜色 |
❌ |
bgClass |
string |
背景样式类 |
❌ |
status |
string |
状态 normal/pinned/abandoned |
❌ |
lastService |
string |
最后服务 '02-20 21:30 · 2.5h' |
❌ |
metrics |
Array<{label,value,color}> |
指标(近60天次数/总时长/次均时长) |
❌ |
最亲密助教 favoriteCoaches(内联 mock,2 位)
| 字段 |
类型 |
说明 |
契约 CUST-1 |
emoji |
string |
爱心 emoji |
❌ 完全未定义 |
name |
string |
助教名 |
❌ |
relationIndex |
string |
关系指数 '9.2' |
❌ |
indexColor |
string |
指数颜色 |
❌ |
bgClass |
string |
背景样式类 |
❌ |
stats |
Array<{label,value,color}> |
统计(基础/激励/上课/充值) |
❌ |
消费记录 consumptionRecords(内联 mock,3 条,3 种类型)
| 字段 |
类型 |
说明 |
契约 CUST-1 |
id |
string |
记录 ID |
✅ |
type |
enum |
table/shop/recharge |
⚠️ 契约有 type 但枚举不同 |
date |
string |
日期 |
✅ |
tableName |
string? |
台桌名 |
❌ 契约有 table |
startTime |
string? |
开始时间 |
❌ 未定义 |
endTime |
string? |
结束时间 |
❌ 未定义 |
duration |
string? |
时长 '3h 20min' |
⚠️ 契约有 duration 但是 number |
tableFee |
number? |
台费 |
❌ 未定义 |
tableOrigPrice |
number? |
台费原价 |
❌ 未定义 |
coaches |
Array<{name,level,levelColor,courseType,hours,perfHours?,fee}> |
助教服务明细 |
❌ 完全未定义 |
foodAmount |
number? |
酒水金额 |
❌ 未定义 |
foodOrigPrice |
number? |
酒水原价 |
❌ 未定义 |
totalAmount |
number? |
总金额 |
⚠️ 契约有 amount |
totalOrigPrice |
number? |
总原价 |
❌ 未定义 |
payMethod |
string? |
支付方式 |
❌ 未定义 |
rechargeAmount |
number? |
充值金额 |
❌ 未定义 |
备注 sortedNotes(内联 mock,3 条)
| 字段 |
类型 |
说明 |
契约 CUST-1 |
id |
string |
备注 ID |
❌ 契约无备注字段 |
tagLabel |
string |
标签 |
❌ |
createdAt |
string |
创建时间 |
❌ |
content |
string |
内容 |
❌ |
页面跳转
| 操作 |
目标 |
参数 |
| 查看服务记录 |
/pages/customer-service-records/customer-service-records |
无参数(⚠️ 未传 customerId) |
| 问问助手 |
/pages/chat/chat |
无参数(⚠️ 未传 customerId) |
spec 未记录的 Gap
- GAP-23:
balance(余额)、consumption60d(近60天消费)、idealInterval(理想到店间隔)、daysSinceVisit(距上次到店天数)在契约 CUST-1 中完全未定义。这些是客户详情页 Banner 的核心展示字段。
- GAP-24:
aiInsight(AI 洞察:summary + strategies)在契约 CUST-1 中完全未定义。数据来源应为 biz.ai_cache,但 cache_type 未明确(可能是 app4_analysis 或新增类型)。
- GAP-25:
coachTasks(关联助教任务列表)在契约 CUST-1 中完全未定义。这是一个复杂的数据结构,需要从 biz.coach_tasks + fdw_etl.v_dwd_assistant_service_log 聚合。每位助教需返回:任务类型、状态、最后服务时间、近60天服务次数/总时长/次均时长。
- GAP-26:
favoriteCoaches(最亲密助教)在契约 CUST-1 中完全未定义。需要从 fdw_etl.v_dws_member_assistant_relation_index 获取关系指数,并聚合基础课时/激励课时/上课次数/充值金额。
- GAP-27:消费记录的
coaches 子数组(助教服务明细,含 perfHours 折算工时)在契约中完全未定义。这需要从 fdw_etl.v_dwd_assistant_service_log 按结算单关联查询。
- GAP-28:消费记录的
tableFee/tableOrigPrice/foodAmount/foodOrigPrice/totalOrigPrice/payMethod 等拆分字段在契约中未定义。契约仅有 amount(总金额)。
- GAP-29:消费记录的
type 枚举不一致 — 前端使用 table/shop/recharge(3 种),契约使用 type_class(未明确枚举)。
- GAP-30:备注列表在契约 CUST-1 中未定义。前端需要展示客户相关的备注。
- GAP-31:跳转 customer-service-records 和 chat 时未传
customerId 参数,联调时目标页面无法获取客户 ID。
场景 7:客户服务记录页(customer-service-records.ts)
API 调用
fetchCustomerRecords({ customerId, year?, month?, table? }) → GET /api/xcx/customers/{customerId}/records
- 参数来源:
options.customerId 或 options.id
- 当前实现:首次加载拉取全部记录,月份切换仅本地过滤
前端期望字段 — ServiceRecord
| 字段 |
类型 |
说明 |
契约 CUST-2 |
table |
string |
台桌号 |
✅ |
type |
string |
课程类型标签 |
✅ |
typeClass |
enum |
basic/vip/tip/recharge |
✅ type_class |
recordType |
enum |
course/recharge |
❌ 未定义 |
duration |
number |
折算后小时 |
✅ |
durationRaw |
number |
折算前小时 |
✅ duration_raw |
income |
number |
到手金额 |
✅ |
isEstimate |
boolean |
是否预估 |
❌ 未定义 |
drinks |
string |
饮品描述 |
✅ |
date |
string |
显示日期 |
✅ |
页面头部字段
| 字段 |
类型 |
说明 |
契约 CUST-2 |
customerName |
string |
客户名 |
✅ |
customerPhone |
string |
脱敏手机号 |
✅ customer_phone |
customerPhoneFull |
string |
完整手机号 |
❌ 未定义(需从 CUST-1 获取) |
relationIndex |
string |
关系指数 |
✅ |
totalServiceCount |
number |
累计服务次数 |
❌ 未定义 |
monthCount |
string |
当月次数 |
❌ 需前端计算 |
monthHours |
string |
当月工时 |
❌ 需前端计算 |
monthRelation |
string |
当月关系指数 |
❌ 未定义 |
spec 未记录的 Gap
- GAP-32:
recordType(course/recharge)和 isEstimate(是否预估)在契约 CUST-2 中未定义。
- GAP-33:
customerPhoneFull(完整手机号)在 CUST-2 响应中未定义,前端需要点击查看完整号码。
- GAP-34:
totalServiceCount(累计服务次数)在 CUST-2 中未定义。
- GAP-35:月份切换采用本地筛选(F10),联调后数据量大时需改为按月请求 API。
场景 8:备注列表页(notes.ts)
API 调用
fetchNotes({ page?, pageSize? }) → GET /api/xcx/notes?page=&pageSize=
deleteNote(noteId) → DELETE /api/xcx/notes/{noteId}
前端期望字段 — Note
| 字段 |
类型 |
说明 |
契约 NOTE-1 |
id |
string |
备注 ID |
✅ |
content |
string |
备注内容 |
✅ |
tagType |
enum |
customer/coach/system |
✅ tag_type |
tagLabel |
string |
标签文案 |
✅ tag_label |
createdAt |
string |
创建时间 |
✅ created_at |
score |
number? |
满意度评分 |
✅ |
timeLabel |
string |
格式化时间(前端计算) |
— |
写操作
| 操作 |
API |
成功后行为 |
| 删除备注 |
DELETE /notes/{noteId} |
本地 filter 移除 + Toast |
spec 未记录的 Gap
- GAP-36:无触底加载逻辑(F11),API 支持分页但
onReachBottom() 未实现。
- GAP-37:
tagType 枚举 — mock 数据中有 'system' 类型,但契约 NOTE-1 仅定义 customer/coach/system。需确认 system 类型的备注由谁创建、如何展示。
场景 9:助教详情页(coach-detail.ts)
API 调用
fetchCoachDetail(coachId) → GET /api/xcx/coaches/{coachId}
- 参数来源:
options.id
- 返回类型:
CoachCard(api.ts 定义),但前端实际需要远超 CoachCard 的数据
前端期望字段 — CoachDetail(完整清单)
基本信息
| 字段 |
类型 |
说明 |
契约 COACH-1 |
id |
string |
助教 ID |
✅ |
name |
string |
助教名 |
✅ |
avatar |
string |
头像 |
✅ |
level |
string |
等级 '星级' |
✅ |
skills |
string[] |
技能 |
✅ |
workYears |
number |
工龄 3 |
❌ 未定义 |
customerCount |
number |
客户数 68 |
❌ 未定义 |
hireDate |
string |
入职日期 |
❌ 未定义 |
store_name |
string |
门店名 |
✅ |
绩效指标 performance(6 个指标)
| 字段 |
类型 |
说明 |
契约 COACH-1 |
monthlyHours |
number |
本月工时 87.5 |
❌ 未定义 |
monthlySalary |
number |
本月工资 6950 |
❌ 未定义 |
customerBalance |
number |
客源储值余额 86200 |
❌ 未定义 |
tasksCompleted |
number |
任务完成数 38 |
❌ 未定义 |
perfCurrent |
number |
当前绩效 80 |
❌ 未定义 |
perfTarget |
number |
目标绩效 100 |
❌ 未定义 |
绩效指标卡片 perfCards(4 张)
| 卡片 |
需要字段 |
契约 |
| 本月定档业绩 |
monthlyHours + 折算前工时 |
❌ |
| 本月工资(预估) |
monthlySalary |
❌ |
| 客源储值余额 |
customerBalance + customerCount |
❌ |
| 本月任务完成 |
tasksCompleted + 覆盖客户数 |
❌ |
进度条数据
| 字段 |
类型 |
说明 |
契约 |
tierNodes |
number[] |
档位节点 [0,100,130,160,190,220] |
❌ 未定义 |
收入明细 income(本月/上月各 4 项)
| 项目 |
说明 |
契约 |
| 基础课时费 |
¥3,500 |
❌ 未定义 |
| 激励课时费 |
¥1,800 |
❌ 未定义 |
| 充值提成 |
¥1,200 |
❌ 未定义 |
| 酒水提成 |
¥450 |
❌ 未定义 |
任务执行
| 字段 |
类型 |
说明 |
契约 COACH-1 |
visibleTasks |
TaskItem[] |
可见任务(active) |
⚠️ 契约说"同 TASK-1 item 格式"但实际需要更多字段 |
hiddenTasks |
TaskItem[] |
隐藏任务(inactive) |
⚠️ |
abandonedTasks |
AbandonedTask[] |
已放弃任务 |
⚠️ |
TaskItem 需要的字段(超出 TASK-1 item):
| 字段 |
类型 |
说明 |
typeLabel |
string |
任务类型标签 |
typeClass |
string |
样式类 high-priority/priority/relationship/callback |
customerName |
string |
客户名 |
noteCount |
number |
备注数量 |
pinned |
boolean |
是否置顶 |
notes |
Array<{pinned?,text,date}> |
备注列表(含置顶标记) |
AbandonedTask 字段:
| 字段 |
类型 |
说明 |
customerName |
string |
客户名 |
reason |
string |
放弃原因 |
客户关系 TOP20 — TopCustomer
| 字段 |
类型 |
说明 |
契约 COACH-1 |
id |
string |
客户 ID |
✅ |
name |
string |
客户名 |
✅ |
initial |
string |
姓名首字 |
❌ |
avatarGradient |
string |
头像渐变色 |
❌ |
heartEmoji |
string |
爱心 emoji ❤️/💛/🤍 |
❌ |
score |
string |
关系指数 '9.5' |
❌ 契约有 total_spend/visit_count 但无 score |
scoreColor |
string |
指数颜色 |
❌ |
serviceCount |
number |
服务次数 |
⚠️ 契约有 visit_count |
balance |
string |
余额 '¥8,600' |
❌ 未定义 |
consume |
string |
消费 '¥12,800' |
⚠️ 契约有 total_spend |
近期服务明细 — ServiceRecord
| 字段 |
类型 |
说明 |
契约 COACH-1 |
customerId |
string? |
客户 ID |
❌ |
customerName |
string |
客户名 |
⚠️ |
initial |
string |
姓名首字 |
❌ |
avatarGradient |
string |
头像渐变色 |
❌ |
type |
string |
课程类型 |
⚠️ |
typeClass |
string |
样式类 |
⚠️ |
table |
string |
台号 |
⚠️ |
duration |
string |
时长 '2.5h' |
⚠️ |
income |
string |
收入 '¥200' |
⚠️ |
date |
string |
日期时间 |
⚠️ |
perfHours |
string? |
折算工时 '2h' |
❌ 未定义 |
历史月份统计 — HistoryMonth
| 字段 |
类型 |
说明 |
契约 COACH-1 |
month |
string |
月份标签 '本月'/'上月'/'4月' |
❌ 完全未定义 |
estimated |
boolean |
是否预估 |
❌ |
customers |
string |
客户数 '22人' |
❌ |
hours |
string |
工时 '87.5h' |
❌ |
salary |
string |
工资 '¥6,950' |
❌ |
callbackDone |
number |
回访完成数 |
❌ |
recallDone |
number |
召回完成数 |
❌ |
页面跳转
| 操作 |
目标 |
参数 |
| 点击任务项 |
/pages/customer-detail/customer-detail |
?name={customerName} |
| 点击客户卡片 |
/pages/customer-detail/customer-detail |
?id={customerId} |
| 点击服务记录 |
/pages/customer-detail/customer-detail |
?id={customerId} |
| 查看更多服务记录 |
/pages/performance-records/performance-records |
?coachId={coachId} |
| 问问助手 |
/pages/chat/chat |
?coachId={coachId} |
spec 未记录的 Gap
- GAP-38:契约 COACH-1 严重不完整。前端需要
performance(6 个绩效指标)、income(本月/上月各 4 项收入明细)、tierNodes(档位节点数组),契约均未定义。
- GAP-39:
TopCustomer 需要 heartEmoji、score(关系指数)、scoreColor、balance(余额)、consume(消费),契约仅有 total_spend/visit_count。
- GAP-40:
ServiceRecord.perfHours(折算工时)在契约中未定义。
- GAP-41:
HistoryMonth(历史月份统计)在契约中完全未定义。需要返回最近 N 个月的汇总数据(客户数、工时、工资、回访/召回完成数)。
- GAP-42:
TaskItem.notes(任务关联的备注列表,含置顶标记)在契约中未定义。契约的 visible_tasks 说"同 TASK-1 item 格式",但前端需要额外的 noteCount、pinned、notes[] 字段。
- GAP-43:
AbandonedTask.reason(放弃原因)在契约中未定义。
- GAP-44:
workYears(工龄)、hireDate(入职日期)在契约中未定义。
场景 10:对话页面(chat.ts + chat-history.ts)
chat.ts — API 调用
fetchChatMessages(customerId) → GET /api/xcx/chat/{chatId}/messages
- ⚠️ 注意:前端传入的是
customerId(或 'default'),但 API 路径参数是 chatId。参数语义不匹配。
sendChatMessage(chatId, content) → POST /api/xcx/chat/{chatId}/messages
- 页面参数:
options.customerId
chat.ts — 前端期望字段 — ChatMessage
| 字段 |
类型 |
说明 |
契约 CHAT-2 |
id |
string |
消息 ID |
✅ |
role |
enum |
user/assistant |
✅ |
content |
string |
消息内容 |
✅ |
timestamp |
string |
时间戳 |
⚠️ 契约用 created_at |
referenceCard |
object? |
引用卡片 |
❌ 完全未定义 |
referenceCard.type |
enum |
customer/record |
❌ |
referenceCard.title |
string |
卡片标题 |
❌ |
referenceCard.summary |
string |
卡片摘要 |
❌ |
referenceCard.data |
Record<string,string> |
键值对数据 |
❌ |
chat.ts — SSE 流式回复
- 前端
simulateStreamOutput() 模拟流式输出(逐字显示)
- 联调时需替换为真实 SSE 连接(
POST /api/xcx/chat/stream)
- spec R3 已确认保留 SSE 流式端点
chat.ts — 页面参数
| 来源页面 |
传递参数 |
用途 |
| task-detail |
?customerId={taskId} |
⚠️ 实际传的是 taskId |
| customer-detail |
无参数 |
⚠️ 未传 customerId |
| coach-detail |
?coachId={coachId} |
助教 ID |
| chat-history |
?historyId={id} |
历史对话 ID |
chat-history.ts — API 调用
fetchChatHistory({ page?, pageSize? }) → GET /api/xcx/chat/history
- 返回:
{ items: ChatHistoryItem[], total, hasMore }
chat-history.ts — 前端期望字段 — ChatHistoryItem
| 字段 |
类型 |
说明 |
契约 CHAT-1 |
id |
string |
对话 ID |
✅ |
title |
string |
对话标题 |
❌ 契约无 title |
lastMessage |
string |
最后消息 |
✅ last_message |
timestamp |
string |
时间戳 |
⚠️ 契约用 last_time |
customerName |
string? |
关联客户名 |
✅ |
chat-history.ts — 页面跳转
| 操作 |
目标 |
参数 |
| 点击对话记录 |
/pages/chat/chat |
?historyId={id} |
spec 未记录的 Gap
- GAP-45:
ChatMessage.referenceCard(引用卡片)在契约 CHAT-2 中完全未定义。前端需要展示客户概览卡片(含键值对数据),后端需在消息中附带结构化引用数据。
- GAP-46:
ChatMessage.timestamp vs 契约 created_at — 字段名不一致,前端使用 timestamp,契约定义 created_at。
- GAP-47:
ChatHistoryItem.title(对话标题)在契约 CHAT-1 中未定义。契约仅有 customer_name/last_message/last_time/unread_count。
- GAP-48:
ChatHistoryItem.timestamp vs 契约 last_time — 字段名不一致。
- GAP-49:chat 页面接收
customerId 参数但 API 路径需要 chatId。前端需要一个"根据 customerId 查找或创建对话"的机制,或 API 支持 customerId 作为查询参数。
- GAP-50:chat 页面还接收
historyId(从 chat-history 跳转)和 coachId(从 coach-detail 跳转),但 loadMessages() 仅使用 customerId。多种入口参数的路由逻辑未实现。
- GAP-51:SSE 流式端点
POST /api/xcx/chat/stream 在契约中未定义(spec R3 已确认需补充)。
汇总:Gap 清单
一、架构级 Gap(影响多个页面)
| # |
Gap |
严重度 |
影响页面 |
说明 |
| GAP-01 |
globalData.authUser 缺少 role/store_name/coach_level/avatar |
🟠 中 |
task-list, performance, performance-records |
多个页面 Banner 需要这些字段,当前硬编码 |
| GAP-04 |
pin/unpin API 端点未在契约中定义 |
🔴 高 |
task-list |
api.ts 无对应函数,前端仅本地更新 |
| GAP-05 |
createNote 缺少 score 参数 |
🟠 中 |
task-list, task-detail |
前端传 score 但 api.ts 签名无此字段 |
| GAP-09/10 |
task-detail 跳转 chat/customer-service-records 时传 taskId 而非 customerId |
🔴 高 |
task-detail → chat/customer-service-records |
TASK-2 响应需包含 customer_id |
| GAP-31 |
customer-detail 跳转时未传 customerId |
🔴 高 |
customer-detail → chat/customer-service-records |
联调时目标页面无法获取客户 ID |
| GAP-17 |
performance 跳转 task-detail 传 customerName 而非 taskId |
🟠 中 |
performance → task-detail |
参数不匹配 |
二、TASK-1 扩展 Gap(任务列表绩效卡片)
| # |
Gap |
严重度 |
说明 |
| GAP-02 |
performance 字段严重不足(需 15+ 字段,契约仅 4 个) |
🔴 高 |
tierNodes、basicHours、bonusHours、currentTier、nextTierHours、tierCompleted、bonusMoney、incomeTrend、incomeTrendDir、prevMonth 等 |
| GAP-03 |
enrichTask 需要 lastVisitDays/balance/aiSuggestion |
🟠 中 |
任务卡片扩展字段 |
三、PERF-1 Gap(绩效概览)
| # |
Gap |
严重度 |
说明 |
| GAP-12 |
this_month_records 需要 DateGroup 分组结构 |
🔴 高 |
契约是扁平数组,前端需按日期分组 + timeRange/courseType/location |
| GAP-13 |
收入档位数据完全未定义 |
🔴 高 |
currentTier/nextTier/upgradeHoursNeeded/upgradeBonus |
| GAP-14 |
lastMonthIncome 未定义 |
🟠 中 |
Banner 需展示上月收入 |
| GAP-15 |
incomeItems.desc 未定义 |
🟠 中 |
需费率×工时的拆分描述 |
| GAP-16 |
newCustomers/regularCustomers 缺少多个字段 |
🟠 中 |
lastService/count/hours/income |
| GAP-18 |
页面无月份切换功能 |
🟡 低 |
F8 前端修复项 |
四、CUST-1 Gap(客户详情 — 最大 Gap 集中区)
| # |
Gap |
严重度 |
说明 |
| GAP-23 |
balance/consumption60d/idealInterval/daysSinceVisit 未定义 |
🔴 高 |
Banner 核心展示字段 |
| GAP-24 |
aiInsight (summary + strategies) 未定义 |
🔴 高 |
AI 洞察模块 |
| GAP-25 |
coachTasks(关联助教任务列表)未定义 |
🔴 高 |
复杂数据结构,需多表聚合 |
| GAP-26 |
favoriteCoaches(最亲密助教)未定义 |
🔴 高 |
需关系指数 + 服务统计 |
| GAP-27 |
消费记录 coaches 子数组(助教服务明细)未定义 |
🔴 高 |
含 perfHours 折算工时 |
| GAP-28 |
消费记录拆分字段(tableFee/foodAmount/totalOrigPrice 等)未定义 |
🟠 中 |
契约仅有 amount |
| GAP-29 |
消费记录 type 枚举不一致 |
🟠 中 |
前端 table/shop/recharge vs 契约未明确 |
| GAP-30 |
备注列表未定义 |
🟠 中 |
客户详情需展示备注 |
五、COACH-1 Gap(助教详情 — 第二大 Gap 集中区)
| # |
Gap |
严重度 |
说明 |
| GAP-38 |
performance/income/tierNodes 未定义 |
🔴 高 |
6 个绩效指标 + 本月/上月各 4 项收入 + 档位节点 |
| GAP-39 |
TopCustomer 缺少 heartEmoji/score/scoreColor/balance |
🔴 高 |
客户关系 TOP20 核心字段 |
| GAP-40 |
ServiceRecord.perfHours 未定义 |
🟠 中 |
折算工时 |
| GAP-41 |
HistoryMonth 完全未定义 |
🔴 高 |
历史月份统计(5+ 个月) |
| GAP-42 |
TaskItem.notes(含置顶标记)未定义 |
🟠 中 |
任务关联备注 |
| GAP-43 |
AbandonedTask.reason 未定义 |
🟡 低 |
放弃原因 |
| GAP-44 |
workYears/hireDate 未定义 |
🟡 低 |
助教基本信息 |
六、CHAT 模块 Gap
| # |
Gap |
严重度 |
说明 |
| GAP-45 |
ChatMessage.referenceCard 未定义 |
🔴 高 |
引用卡片(客户概览数据) |
| GAP-46 |
timestamp vs created_at 字段名不一致 |
🟠 中 |
前端用 timestamp,契约用 created_at |
| GAP-47 |
ChatHistoryItem.title 未定义 |
🟠 中 |
对话标题 |
| GAP-48 |
ChatHistoryItem.timestamp vs last_time 不一致 |
🟠 中 |
字段名不一致 |
| GAP-49 |
customerId → chatId 映射机制缺失 |
🔴 高 |
前端传 customerId 但 API 需要 chatId |
| GAP-50 |
多入口参数路由逻辑未实现 |
🟠 中 |
historyId/coachId/customerId 三种入口 |
| GAP-51 |
SSE 流式端点未在契约中定义 |
🟠 中 |
spec 已确认需补充 |
七、其他 Gap
| # |
Gap |
严重度 |
说明 |
| GAP-06 |
维客线索 tag 格式不一致(含换行符) |
🟡 低 |
需统一 |
| GAP-07 |
维客线索 source 格式不一致 |
🟡 低 |
mock 用 'By:系统',类型定义用 'manual' |
| GAP-08 |
aiAnalysis/talkingPoints 的 ai_cache cache_type 未明确 |
🟠 中 |
需明确映射 |
| GAP-11 |
storageLevel/relationLevel 计算逻辑未明确 |
🟡 低 |
前端本地计算 |
| GAP-19 |
avatarChar/avatarColor 是否后端返回 |
🟡 低 |
建议前端自行计算 |
| GAP-20 |
courseTypeClass 枚举值前缀不统一 |
🟡 低 |
tag-basic vs basic |
| GAP-21 |
月份切换未重置分页 |
🟡 低 |
F9 前端 bug |
| GAP-22 |
performance-records Banner 字段来源 |
🟡 低 |
依赖 GAP-01 |
| GAP-32 |
recordType/isEstimate 未定义 |
🟡 低 |
CUST-2 扩展字段 |
| GAP-33 |
customerPhoneFull 未定义 |
🟡 低 |
CUST-2 需完整手机号 |
| GAP-34 |
totalServiceCount 未定义 |
🟡 低 |
CUST-2 累计次数 |
| GAP-35 |
月份切换本地筛选需改 API 请求 |
🟡 低 |
F10 前端修复 |
| GAP-36 |
notes 页无触底加载 |
🟡 低 |
F11 前端修复 |
| GAP-37 |
Note.tagType 'system' 类型语义 |
🟡 低 |
需确认 |
统计
| 严重度 |
数量 |
说明 |
| 🔴 高 |
17 |
阻塞联调,必须在后端开发前解决 |
| 🟠 中 |
19 |
影响功能完整性,需在联调前补充 |
| 🟡 低 |
15 |
可联调后修复或前端自行处理 |
| 合计 |
51 |
|
最高优先级修复建议
- 契约大幅扩展 CUST-1:客户详情是 Gap 最集中的页面(GAP-23~30),需新增
balance、consumption60d、idealInterval、daysSinceVisit、aiInsight、coachTasks、favoriteCoaches、消费记录拆分字段、备注列表。
- 契约大幅扩展 COACH-1:助教详情是第二大 Gap 集中区(GAP-38~44),需新增
performance(6 指标)、income(8 项)、tierNodes、TopCustomer 扩展字段、HistoryMonth、ServiceRecord.perfHours。
- 契约扩展 PERF-1:绩效概览需要 DateGroup 分组结构(GAP-12)和收入档位数据(GAP-13)。
- 契约扩展 TASK-1 performance:绩效卡片需要 15+ 字段(GAP-02)。
- 修复 customerId/taskId 混淆:TASK-2 响应需包含
customer_id(GAP-09/10),customer-detail 跳转需传参(GAP-31)。
- 补充 CHAT 模块:referenceCard(GAP-45)、customerId→chatId 映射(GAP-49)、SSE 端点定义(GAP-51)。