Files
Neo-ZQYY/docs/miniprogram-dev/api-audit/customer-service-records.md

9.8 KiB
Raw Blame History

customer-service-records 页面数据来源排查

排查日期2026-03-18 页面路径pages/customer-service-records/customer-service-records

概览

分类 数量 说明
A. Mock 数据 5 来自 mock-data.tsmockCustomers + mockCustomerDetail
B. 硬编码数据 8 页面 data 初始值、辅助函数内联常量
C. 已对接 API 0 全部数据均为 Mock无真实 API 调用
D. 前端计算/派生 12 月份筛选、统计汇总、格式转换等
E. 路由参数 1 customerId / id
F. WXML 硬编码文案 10 状态提示、标签文字、按钮文案等

一、Mock 数据(来自 mock-data.ts

所有业务数据均通过 loadData() 中的 setTimeout 模拟异步获取,数据源为 mock-data.ts

# 字段 / 数据 Mock 来源 说明
A1 mockCustomers 列表 mock-data.ts → mockCustomers 用于按 id 查找客户基本信息(id, name
A2 mockCustomerDetail mock-data.ts → mockCustomerDetail 客户详情,提供 nameconsumptionRecords
A3 consumptionRecords 数组 mockCustomerDetail.consumptionRecords 5 条消费记录,字段:id, date, project, duration, amount, coachName
A4 customerName / customerInitial mockCustomerDetail.namemockCustomers[].name 取值 客户姓名及首字
A5 allRecords detail.consumptionRecordssortByTimestamp 排序 全量消费记录(降序)

Mock 数据结构ConsumptionRecord

interface ConsumptionRecord {
  id: string        // 如 'cr-001'
  date: string      // 如 '2026-03-05'
  project: string   // 如 '中式台球 1v1'、'会员充值'
  duration: number  // 分钟数,如 90
  amount: number    // 金额,如 380
  coachName: string // 助教名,如 '王芳'
}

二、硬编码数据

# 字段 / 数据 位置 硬编码值 说明
B1 customerPhone data 初始值 '139****5678' 脱敏手机号,应从 API 获取
B2 customerPhoneFull data 初始值 '13900005678' 完整手机号,应从 API 获取
B3 relationIndex data 初始值 '0.85' 关系指数,应从 API 获取
B4 monthRelation data 初始值 '0.85' 月度关系指数,应从 API 获取WXML 中绑定展示)
B5 minYearMonth data 初始值 202601 数据起始年月,应从 API 返回的最早记录推算
B6 maxYearMonth data 初始值 202602 数据截止年月,应取当前月份动态计算
B7 currentYear / currentMonth data 初始值 2026 / 2 当前年月,应取系统时间动态计算
B8 tables 数组 getTableNo() 方法 ['A12号台', '3号台', 'VIP1号房', '5号台', 'VIP2号房', '8号台'] 模拟台号,应从消费记录 API 返回

三、已对接 API

# 接口 状态
无。页面当前 0 个真实 API 调用。

loadData() 方法中有明确 TODO 注释:

// TODO: 替换为真实 API 调用

四、前端计算/派生数据

# 字段 / 数据 计算逻辑 来源依赖
D1 customerInitial name[0] || '?' Mock → detail.name
D2 totalServiceCount allRecords.length Mock → consumptionRecords
D3 monthLabel `${currentYear}年${currentMonth}月` 硬编码 currentYear / currentMonth
D4 records(当月记录) allRecords.filter(r => r.date.startsWith(monthPrefix)).map() 转换 Mock → allRecords + 硬编码年月
D5 monthCount monthRecords.length + '次' D4 筛选结果
D6 monthHours (totalMinutes / 60).toFixed(1) + 'h'totalMinutes = reduce(sum + r.duration) D4 筛选结果
D7 canPrev / canNext yearMonth > minYearMonth / yearMonth < maxYearMonth 硬编码边界
D8 pageState 根据 records.length === 0 && allRecords.length === 0 判断 'empty' / 'normal' D4 + A5
D9 ServiceRecord.table getTableNo(r.id) — 按 id 数字取模从硬编码数组选取 硬编码 B8
D10 ServiceRecord.type / typeClass getTypeLabel(r.project) / getTypeClass(r.project) — 按 project 字符串 includes 匹配 Mock → project 字段
D11 ServiceRecord.duration parseFloat((r.duration / 60).toFixed(1))(充值记录为 0 Mock → duration(分钟)
D12 ServiceRecord.date(展示用) 格式化为 "X月X日 HH:MM - HH:MM",时间段由 generateTimeRange() 随机生成 Mock → date + 随机数

辅助函数详情

函数 逻辑 数据来源
generateTimeRange(durationMin) 随机起始小时 14-19计算结束时间 入参 durationMock + Math.random()
getTypeLabel(project) includes('小组')→'小组课'includes('1v1')→'基础课'includes('充值')→'充值'includes('斯诺克')→'斯诺克'、默认 '基础课' 硬编码映射规则
getTypeClass(project) includes('充值')→'recharge'includes('小组'/'斯诺克')→'vip'、默认 'basic' 硬编码映射规则
getTableNo(id) id 提取数字 → 取模 → 从 6 元素数组选取 硬编码台号数组
sortByTimestamp(list, field) 按指定字段降序排序(utils/sort.ts 纯工具函数

固定为默认值的 ServiceRecord 字段

字段 固定值 说明
durationRaw 0 折算前小时数,未实现
isEstimate false 是否预估金额,未实现
drinks '' 商品/饮品描述,未实现
income r.amount(直接透传) 到手金额 = 消费金额,未做提成计算
recordType project.includes('充值') ? 'recharge' : 'course' 仅按项目名判断

五、路由参数

# 参数 取值逻辑 说明
E1 customerId options?.customerId || options?.id || '' 从上级页面传入,支持两种参数名

六、WXML 硬编码文案

# 文案 位置 说明
F1 "加载中..." 加载态 toast 状态提示
F2 "暂无服务记录" <t-empty> description 空态提示
F3 "加载失败,请点击重试" 错误态文案 错误提示
F4 "重试" 错误态按钮 按钮文案
F5 "服务 {{totalServiceCount}} 次" Banner 徽章 模板 + 动态数据
F6 "查看" / "复制" 手机号操作按钮 根据 phoneVisible 切换
F7 "本月服务" / "服务时长" / "关系指数" 月度统计标签 固定标签文案
F8 "本月暂无服务记录" 当月无数据提示 空月提示
F9 "— 已加载全部记录 —" 列表底部 底部提示
F10 "手机号码已复制" onCopyPhone() Toast JS 中的提示文案

七、引用组件

组件 路径 用途
service-record-card /components/service-record-card/ 服务记录卡片,接收 ServiceRecord 各字段
ai-float-button /components/ai-float-button/ AI 悬浮按钮,传入 customerId
dev-fab /components/dev-fab/ 开发调试浮动按钮
t-loading TDesign 加载动画
t-icon TDesign 图标
t-empty TDesign 空态组件

八、联调 TODO

需要对接的 API 清单

优先级 API 用途 替换目标
P0 GET /api/customers/{id}/service-records 获取客户服务记录列表(支持月份筛选、分页) loadData() 中的 mockCustomerDetail.consumptionRecords
P0 GET /api/customers/{id} 获取客户基本信息(姓名、手机号、关系指数) mockCustomers.find() + mockCustomerDetail + 硬编码手机号
P1 GET /api/customers/{id}/monthly-stats 获取月度统计(服务次数、时长、关系指数) 前端 reduce 计算的 monthCountmonthHours + 硬编码 monthRelation

联调时需处理的改动点

# 改动点 当前状态 联调要求
T1 移除 mock-data.ts 导入 import { mockCustomerDetail, mockCustomers } 替换为 API 请求模块
T2 loadData() 改为真实请求 setTimeout + Mock 查找 wx.request 或封装的 HTTP 客户端
T3 手机号从 API 获取 硬编码 '139****5678' / '13900005678' API 返回脱敏 + 完整手机号(或按需请求完整号)
T4 关系指数从 API 获取 硬编码 '0.85' API 返回 relationIndex / monthRelation
T5 台桌号从 API 获取 getTableNo() 硬编码数组取模 消费记录 API 返回 tableNo 字段
T6 时间段从 API 获取 generateTimeRange() 随机生成 消费记录 API 返回 startTime / endTime
T7 年月边界动态计算 硬编码 minYearMonth=202601 / maxYearMonth=202602 从 API 返回的最早记录推算 minmax 取当前月
T8 currentYear / currentMonth 动态化 硬编码 2026 / 2 new Date() 当前年月
T9 分页加载 onReachBottom 空实现 对接分页 APIpage / pageSize 参数)
T10 durationRaw 字段 固定 0 API 返回折算前时长
T11 drinks 字段 固定 '' API 返回商品/饮品信息
T12 isEstimate 字段 固定 false API 返回是否预估标记
T13 income 字段 直接透传 amount API 返回助教到手金额(需提成计算)
T14 错误处理 pageState='error' 触发路径 API 失败时 setData({ pageState: 'error' })