board-customer 页面数据来源排查
排查日期:2026-03-18
页面路径:pages/board-customer/board-customer
引用文件:board-customer.ts / .wxml / .wxss / .json
外部依赖:utils/ai-color-manager.ts(initPageAiColor,已导入但未调用)
概览
| 分类 |
数量 |
说明 |
| A. Mock 数据 |
1 组(3 条记录,~30 个字段/条) |
页面内联 MOCK_CUSTOMERS 常量,未引用 utils/mock-data.ts |
| B. 硬编码数据 |
5 处 |
维度选项、项目选项、Tab 列表、列表标题、加载延迟 |
| C. 已对接 API |
0 |
无任何 wx.request / API 调用 |
| D. 前端计算/派生 |
3 处 |
dimType 映射、滚动隐藏筛选栏、空/错误态判断 |
| E. 路由参数 |
0 |
onLoad 无参数读取 |
| F. WXML 硬编码文案 |
12 处 |
Tab 文案、列表标题、网格标签、状态提示等 |
一、Mock 数据
1.1 MOCK_CUSTOMERS(页面内联,第 72–178 行)
页面顶部定义的 const MOCK_CUSTOMERS: CustomerItem[],包含 3 条客户记录(王先生 / 李女士 / 张先生),在 loadData() 中通过 setTimeout(400ms) 模拟异步加载。
未引用 utils/mock-data.ts:该文件中有 mockCustomers: CustomerCard[],但 board-customer 页面使用了自己定义的 CustomerItem 接口(字段更丰富,支持 8 维度卡片)。
字段清单(每条 CustomerItem)
| 字段 |
示例值(王先生) |
数据类型 |
联调时对应 API 字段 |
id |
'u1' |
string |
客户 ID(member_id) |
name |
'王先生' |
string |
客户姓名(dim_member.nickname,注意 DQ-6 断档) |
initial |
'王' |
string |
前端从 name 截取首字 |
avatarCls |
'avatar--amber' |
string |
前端根据规则分配头像色 |
idealDays |
7 |
number |
理想到店间隔天数(DWS 计算) |
elapsedDays |
15 |
number |
距上次到店已过天数(DWS 计算) |
overdueDays |
8 |
number |
超期天数 = elapsedDays - idealDays |
visits30d |
3 |
number |
近 30 天到店次数 |
balance |
'¥2,680' |
string |
当前余额(储值卡) |
recallIndex |
'9.2' |
string |
召回指数(DWS 综合评分) |
potentialTags |
[{text:'高频',theme:'primary'}] |
array |
消费潜力标签(后端计算) |
spend30d |
'¥4,200' |
string |
近 30 天消费金额 |
avgVisits |
'6.2次' |
string |
月均到店次数 |
avgSpend |
'¥680' |
string |
次均消费金额 |
lastVisit |
'3天前' |
string |
最近到店(相对时间) |
monthlyConsume |
'¥3,500' |
string |
月均消耗金额 |
availableMonths |
'约0.8个月' |
string |
余额可用月数 = balance / monthlyConsume |
lastRecharge |
'2月15日' |
string |
最后充值日期 |
rechargeAmount |
'¥5,000' |
string |
最后充值金额 |
recharges60d |
'2次' |
string |
近 60 天充值次数 |
currentBalance |
'¥2,680' |
string |
当前余额(与 balance 重复) |
spend60d |
'¥8,400' |
string |
近 60 天消费金额 |
visits60d |
'12' |
string |
近 60 天到店次数 |
highSpendTag |
true |
boolean |
是否高消费标签 |
avgInterval |
'5.0天' |
string |
平均到店间隔 |
intimacy |
'92' |
string |
专一度指数 |
topCoachName |
'小燕' |
string |
最亲密助教姓名 |
topCoachHeart |
9.2 |
number |
最亲密助教关系指数 |
topCoachScore |
'9.2' |
string |
同上(字符串版) |
coachDetails |
2 条明细 |
array |
助教服务明细表 |
weeklyVisits |
8 周数据 |
array |
8 周到店频率(迷你柱状图) |
coachName |
'小燕' |
string |
主助教姓名 |
coachRatio |
'78%' |
string |
主助教服务占比 |
visitFreq |
'6.2次/月' |
string |
到店频率 |
daysAgo |
3 |
number |
距上次到店天数 |
assistants |
2 条 |
array |
助教列表(底部行) |
coachDetails 子字段
| 字段 |
示例值 |
说明 |
name |
'小燕' |
助教姓名 |
cls |
'assistant--assignee' |
样式类(跟/弃/普通) |
heartScore |
9.2 |
关系指数 |
badge |
'跟' |
跟/弃标签 |
avgDuration |
'2.3h' |
次均服务时长 |
serviceCount |
'14' |
服务次数 |
coachSpend |
'¥4,200' |
助教消费金额 |
relationIdx |
9.2 |
关系指数(数值版) |
assistants 子字段
| 字段 |
示例值 |
说明 |
name |
'小燕' |
助教姓名 |
cls |
'assistant--assignee' |
样式类 |
heartScore |
9.2 |
关系指数 |
badge |
'跟' |
跟/弃标签(可选) |
badgeCls |
'assistant-badge--follow' |
badge 样式类(可选) |
二、硬编码数据
2.1 DIMENSION_OPTIONS(维度下拉选项)
| 风险 |
字段 |
当前值 |
应从何处获取 |
| 🟡 低 |
DIMENSION_OPTIONS |
8 个维度选项(recall/potential/balance/recharge/recent/spend60/freq60/loyal) |
前端枚举,可保留硬编码;若后端支持动态维度则需 API |
2.2 PROJECT_OPTIONS(项目筛选选项)
| 风险 |
字段 |
当前值 |
应从何处获取 |
| 🟡 低 |
PROJECT_OPTIONS |
5 个项目选项(all/chinese/snooker/mahjong/karaoke) |
前端枚举,可保留;若门店项目可配置则需 API |
2.3 DIMENSION_TO_DIM 映射表
| 风险 |
字段 |
说明 |
| 🟢 无 |
DIMENSION_TO_DIM |
纯前端映射,维度 value → DimType,无需替换 |
2.4 loadData() 中的 setTimeout(400ms)
| 风险 |
位置 |
当前值 |
说明 |
| 🔴 高 |
loadData() |
setTimeout(() => {...}, 400) |
模拟网络延迟,联调时必须替换为真实 wx.request |
2.5 onPullDownRefresh() 中的 setTimeout(500ms)
| 风险 |
位置 |
当前值 |
说明 |
| 🟡 中 |
onPullDownRefresh() |
setTimeout(() => wx.stopPullDownRefresh(), 500) |
联调时应在 API 回调中调用 wx.stopPullDownRefresh() |
三、已对接 API
无。 页面中没有任何 wx.request、wx.cloud.callFunction 或封装的 API 调用。
loadData() 当前实现:
四、前端计算/派生数据
| 字段/逻辑 |
位置 |
说明 |
dimType |
onDimensionChange() |
由 DIMENSION_TO_DIM[selectedDimension] 映射得出,控制 WXML 卡片模板切换 |
filterBarVisible |
onPageScroll() |
滚动方向 + 累积距离判断,纯 UI 交互逻辑 |
pageState |
loadData() |
根据数据加载结果设置 'loading' / 'empty' / 'normal' / 'error' |
totalCount |
loadData() |
data.length,由返回数据长度计算 |
overdueDays > 7 |
WXML |
控制超期标签颜色(danger / warn),纯前端判断 |
item.highSpendTag |
WXML |
控制是否显示"高消费"标签,值来自 mock 数据 |
柱状图 opacity |
WXML |
0.2 + wIdx * 0.057,渐变透明度,纯 UI 计算 |
cd.relationIdx >= 8 |
WXML |
控制关系指数颜色(primary / gray),纯前端判断 |
五、路由参数
无。 onLoad() 不接收任何参数,直接调用 loadData()。
页面作为导航目标时的入口:
board-finance.ts → wx.navigateTo({ url: '/pages/board-customer/board-customer' })
board-coach.ts → wx.navigateTo({ url: '/pages/board-customer/board-customer' })
dev-tools.ts → 开发工具页面列表
六、WXML 中的硬编码文案
| 位置 |
硬编码文案 |
风险 |
说明 |
| 加载态 |
加载中... |
🟢 无 |
通用 UI 文案 |
| 空状态 |
暂无客户数据 |
🟢 无 |
通用 UI 文案 |
| 错误态 |
加载失败 |
🟢 无 |
通用 UI 文案 |
| 错误态按钮 |
点击重试 |
🟢 无 |
通用 UI 文案 |
| Tab 栏 |
财务 / 客户 / 助教 |
🟢 无 |
固定导航文案 |
| 列表标题 |
客户列表 |
🟢 无 |
固定标题 |
| 列表副标题 |
· 前100名 |
🟡 低 |
若后端支持分页/动态 TopN,需改为动态值 |
| 列表计数 |
共{{totalCount}}名客户 |
🟢 无 |
动态绑定 |
| 召回维度标签 |
理想 / 已过 / 超期 / 天 |
🟢 无 |
固定维度标签 |
| 网格标签 |
30天消费 / 月均到店 / 余额 / 次均消费 / 月均消耗 / 可用 / 最后充值 / 充值 / 60天充值 / 当前余额 / 近60天消费 / 到店次数 |
🟢 无 |
固定维度标签 |
| 频率维度 |
60天到店 / 次 / 8周前 / 本周 |
🟢 无 |
固定维度标签 |
| 专一维度表头 |
助教 / 次均时长 / 服务次数 / 助教消费 / 关系指数 |
🟢 无 |
固定表头 |
| 助教标签 |
助教: / 跟 / 弃 |
🟢 无 |
固定 UI 文案 |
| 最近到店 |
天前到店 / 理想间隔 / 60天到店 / 次均消费 |
🟢 无 |
固定维度标签 |
| 频率中间行 |
平均间隔 / 60天消费 |
🟢 无 |
固定维度标签 |
| 召回中间行 |
30天到店 / 余额 / 召回指数 |
🟢 无 |
固定维度标签 |
| 最近到店右上角 |
天前到店 |
🟢 无 |
固定维度标签 |
七、引用组件清单
| 组件 |
路径 |
数据来源 |
说明 |
filter-dropdown |
/components/filter-dropdown/ |
父组件传入 options / value |
纯展示组件,无自有数据 |
heart-icon |
/components/heart-icon/ |
父组件传入 score |
纯展示组件,根据分数渲染心形图标 |
ai-float-button |
/components/ai-float-button/ |
自有逻辑 |
AI 悬浮按钮,独立组件 |
board-tab-bar |
/custom-tab-bar/index |
active="board" |
底部导航栏,当前 mock 3 按钮 |
dev-fab |
/components/dev-fab/ |
— |
开发调试按钮,wx:if="{{false}}" 已隐藏 |
t-loading / t-empty / t-icon / t-tag |
TDesign |
— |
第三方 UI 组件 |
八、联调 TODO
🔴 P0 — 必须替换
| # |
任务 |
当前状态 |
目标 |
| 1 |
替换 MOCK_CUSTOMERS 为 API 调用 |
页面内联 3 条 mock 数据 |
调用后端客户看板 API,传入 dimension + project 参数 |
| 2 |
实现 loadData() 真实请求 |
setTimeout(400ms) 模拟 |
wx.request → 后端 API,处理 loading/error/empty 三态 |
| 3 |
下拉刷新对接 |
setTimeout(500ms) 后停止 |
API 回调中 wx.stopPullDownRefresh() |
| 4 |
维度切换重新请求 |
onDimensionChange 仅切换 dimType |
切换维度后重新调用 API(不同维度返回不同排序/字段) |
| 5 |
项目筛选重新请求 |
onProjectChange 仅更新 selectedProject |
切换项目后重新调用 API(按项目类型过滤) |
🟡 P1 — 建议优化
| # |
任务 |
说明 |
| 6 |
分页/滚动加载 |
当前一次性加载全部,"前 100 名"硬编码;若数据量大需分页 |
| 7 |
initPageAiColor 调用 |
已导入但未在 onLoad 中调用,需补充 |
| 8 |
金额字段格式化 |
Mock 中金额为预格式化字符串('¥2,680'),联调后需前端格式化 |
| 9 |
相对时间计算 |
lastVisit: '3天前'、daysAgo: 3 等,联调后需从时间戳计算 |
| 10 |
balance 与 currentBalance 去重 |
Mock 中两字段值相同,API 设计时应统一 |
🟢 P2 — 可保留
| # |
项目 |
说明 |
| 11 |
DIMENSION_OPTIONS |
前端枚举,维度列表固定,可保留硬编码 |
| 12 |
PROJECT_OPTIONS |
前端枚举,若门店项目固定可保留 |
| 13 |
DIMENSION_TO_DIM 映射 |
纯前端逻辑,保留 |
| 14 |
WXML 固定文案 |
维度标签、表头等,保留 |
九、待确认 API 设计
联调前需与后端确认以下接口设计:
关键字段口径注意:
- 金额字段(
balance、spend30d、spend60d 等):后端返回 numeric(2) 原始数值,前端负责 ¥ 前缀 + 千分位格式化
- 会员姓名:通过
member_id JOIN dim_member.nickname(DQ-6 断档,禁止直接用 member_name)
- 储值卡余额:DWS 层
balance_pay(总额)= recharge_card_pay + gift_card_pay
- 消费金额:使用
items_sum 口径,禁止直接使用 consume_money(三种历史口径混合)