Files
Neo-ZQYY/docs/prd/specs/board-detail-gap-analysis.md
Neo 6f8f12314f feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本
包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 00:03:48 +08:00

26 KiB
Raw Permalink Blame History

看板 & 详情页差距分析与实施指南

调研日期2026-03-28 范围:小程序看板(助教/客户列表)、助教详情页、客户详情页 目的:全面梳理前后端完成度差距,为后续联调实施提供完整依据


一、总体完成度

模块 后端接口 前端页面 真实数据对接 完成度 主要差距
助教看板 BOARD-1 Mock ~60% 前端用 Mockskills 为空;环比字段为 None
客户看板 BOARD-2 Mock ~60% 前端用 Mockloyal 缺 coachDetails排序规则需修正
助教详情 COACH-1 ⚠️ 部分 ~40% API 已调用但 Mock 覆盖大部分字段
客户详情 CUST-1 ⚠️ 部分 ~35% API 已调用但只映射了 id/name/phone
客户服务记录 CUST-2 真实 ~90% 已完成联调
看板 Tab 切换 N/A N/A 需重构 当前是页面跳转,需改为同页切换

二、问题清单(按优先级排列)

P1看板 Tab 切换改为同页切换

现状三个看板页面board-finance / board-customer / board-coach各自独立通过 wx.navigateTo()wx.switchTab() 跳转。

问题

  • board-coach.ts 第 245 行 onTabChange()wx.navigateTo / wx.switchTab
  • board-customer.ts 第 277 行 onTabChange():同上
  • board-finance.ts 第 473 行 onTabChange():同上

目标:改为同一页面内的 tab 切换(无页面跳转感),类似 wx:ifhidden 控制显示/隐藏。

实施方案选项

  1. 方案 A合并为单页:将三个看板合并到一个页面(如 board/board),用 wx:if="{{activeTab === 'finance'}}" 切换内容区。优点:切换无延迟;缺点:单页代码量大,首次加载慢。
  2. 方案 Bwx.redirectTo 替代:用 wx.redirectTo 替代 wx.navigateTo,避免页面栈堆积。优点:改动最小;缺点:仍有页面切换闪烁。
  3. 方案 C组件化:将三个看板内容抽为自定义组件,在一个容器页面中按 tab 切换。优点:代码隔离好、切换流畅;缺点:需要重构。

建议:方案 C组件化兼顾代码隔离和切换体验。

影响范围

  • 前端:pages/board-finance/pages/board-customer/pages/board-coach/ → 抽为组件
  • 路由:app.json 页面注册需调整
  • 权限守卫:checkPageAccess 需适配新路由
  • custom-tab-bar如果 board-finance 是 tabBar 页面,需要调整

P2助教详情页 Mock → 真实 API 映射

现状coach-detail.ts 第 297-370 行 loadData()

  • 已调用 fetchCoachDetail(id) 获取后端数据
  • 但只映射了 idname,其余全部用 mockCoachDetail 覆盖
  • 档位节点硬编码为 [0, 100, 130, 160, 190, 220](实际应为 [0, 120, 150, 180, 210]

后端 SchemaCoachDetailResponse)已返回的完整字段:

id, name, avatar, level, skills, work_years, customer_count, hire_date,
performance { monthly_hours, monthly_salary, customer_balance, tasks_completed,
              perf_current, perf_target },
income { this_month[], last_month[] },
tier_nodes[],
visible_tasks[], hidden_tasks[], abandoned_tasks[],
top_customers[], service_records[], history_months[], notes[]

前端需要映射但当前被 Mock 覆盖的字段

字段 Mock 变量 说明
tier_nodes 硬编码 [0, 100, 130, 160, 190, 220] 档位节点,后端从 cfg_performance_tier 读取
visible_tasks mockVisibleTasks 可见任务列表
hidden_tasks mockHiddenTasks 隐藏任务列表
abandoned_tasks mockAbandonedTasks 已放弃任务列表
top_customers mockTopCustomers TOP 客户列表
service_records mockServiceRecords 近期服务记录
history_months mockHistoryMonths 历史月份数据
notes Mock 内嵌 备注列表(已部分映射)
income Mock 内嵌 收入明细(本月/上月)
performance 全部子字段 mockCoachDetail.performance 绩效数据

实施要点

  1. 移除 mockCoachDetail 及所有 mock* 变量
  2. 直接使用 fetchCoachDetail(id) 返回的完整对象
  3. 注意 camelCase 转换(后端 snake_case → 前端 camelCase 自动转换)
  4. tier_nodes 使用后端返回值fallback 用 _FALLBACK_TIER_NODES = [0, 120, 150, 180, 210]
  5. 数值字段传原始数字给 setDataWXML 中用 WXS 格式化TS 与 WXS 格式化互斥规则)
  6. null 值清洗:?? 0 / ?? ''(组件 property 收到 null 不走默认值)

P3客户详情页 Mock → 真实 API 映射

现状customer-detail.ts 第 97-120 行 loadDetail()

  • 已调用 fetchCustomerDetail(id) 获取后端数据
  • 只映射了 idnamephone 三个字段
  • 其余模块Banner、AI 洞察、维客线索、助教任务、最亲密助教、消费记录、备注)全部使用 data 中的初始空值

后端 SchemaCustomerDetailResponse)已返回的完整字段:

id, name, phone, phone_full, avatar, member_level, relation_index, tags[],
balance, consumption_60d, ideal_interval, days_since_visit,
ai_insight { summary, strategies[] },
coach_tasks[], favorite_coaches[], retention_clues[],
consumption_records[], notes[]

前端需要映射但当前未映射的字段

字段 前端 data key 说明
phone_full detail.phone 完整手机号(用于复制)
avatar 未使用 头像 URL
member_level 未使用 会员等级
relation_index 未使用 关系指数
tags 未使用 标签数组
balance detail.balance 卡余额
consumption_60d detail.consumption60d 60天消费
ideal_interval detail.idealInterval 理想到店间隔
days_since_visit detail.daysSinceVisit 距上次到店天数
ai_insight aiInsight AI 洞察(暂不处理)
coach_tasks coachTasks 关联助教任务
favorite_coaches favoriteCoaches 最亲密助教
retention_clues clues 维客线索
consumption_records consumptionRecords 消费记录
notes sortedNotes 备注

实施要点

  1. loadDetail 中将 fetchCustomerDetail(id) 返回的完整对象映射到 data
  2. AI 相关字段(ai_insight)暂不处理,保持空值
  3. Banner 四项指标balance / consumption60d / idealInterval / daysSinceVisit直接映射
  4. 子模块coachTasks / favoriteCoaches / clues / consumptionRecords / notes直接映射
  5. null 值清洗规则同 P2

P4助教看板 Mock → 真实 API

现状board-coach.ts 第 195-215 行 loadData()

  • 使用 setTimeout + MOCK_COACHES 模拟加载
  • 未调用任何 API

后端接口GET /api/xcx/board/coaches?sort=perf_desc&skill=ALL&time=month

后端返回结构

{
  "items": [
    {
      "id": 123,
      "name": "张三",
      "initial": "张",
      "avatar_gradient": "",
      "level": "senior",
      "skills": [],
      "top_customers": ["李四", "王五"],
      "perf_hours": 156.5,
      "perf_hours_before": null,
      "perf_gap": null,
      "perf_reached": false,
      "salary": 18500.0,
      "salary_perf_hours": 156.5,
      "salary_perf_before": null,
      "sv_amount": 45000.0,
      "sv_customer_count": 12,
      "sv_consume": 8500.0,
      "task_recall": 5,
      "task_callback": 8
    }
  ],
  "dim_type": "perf"
}

实施要点

  1. 替换 setTimeout + MOCK_COACHES 为真实 API 调用
  2. 筛选参数sort / skill / time传给 API
  3. 筛选变更时重新请求(当前只在前端过滤 Mock 数据)
  4. 注意 skills 字段当前为空数组(见 P6
  5. perf_hours_before / salary_perf_before 当前为 null见 P7

P5客户看板 Mock → 真实 API

现状board-customer.ts 第 218-235 行 loadData()

  • 使用 setTimeout + MOCK_CUSTOMERS 模拟加载
  • 未调用任何 API

后端接口GET /api/xcx/board/customers?dimension=recall&project=ALL&page=1&page_size=20

实施要点

  1. 替换 Mock 为真实 API 调用
  2. 维度切换时重新请求(不同维度调用不同 FDW 查询函数)
  3. 项目筛选传给 API
  4. 分页支持page / page_size
  5. 注意前端字段名与后端返回的映射camelCase 自动转换)

客户看板前端字段 → 后端字段映射

前端字段 后端字段 维度
idealDays ideal_days recall
elapsedDays elapsed_days recall
overdueDays overdue_days recall
visits30d visits_30d recall
balance balance recall / balance
recallIndex recall_index recall
spend30d spend_30d potential
avgVisits avg_visits potential
avgSpend avg_spend potential
lastVisit last_visit balance / recent
monthlyConsume monthly_consume balance
availableMonths available_months balance
lastRecharge last_recharge recharge
rechargeAmount recharge_amount recharge
recharges60d recharges_60d recharge
currentBalance current_balance recharge
spend60d spend_60d spend60
visits60d visits_60d spend60 / freq60
avgInterval avg_interval_days freq60
weeklyVisits weekly_visits freq60
intimacy intimacy loyal
topCoachName top_coach_name loyal
topCoachHeart top_coach_heart loyal
coachDetails 后端未返回 loyal
daysAgo days_ago recent
assistants assistants 所有维度

P6助教 Skills 字段为空

现状

  • 后端 get_coach_board() 返回 "skills": [](第 316 行注释:v_dim_assistant 无 skill 列,暂返回空
  • 后端 get_coach_detail() 同样返回空 skills
  • 前端 WXML 已有 skills 标签渲染逻辑

调研发现——"技能"的两层含义

  1. 课程类型skill_id:指助教能教的课程类型

    • 基础课(陪打/PDskill_id = 2791903611396869
    • 附加课(超休/CXskill_id = 2807440316432197
    • 包厢课:归入基础课口径
    • 配置表:cfg_skill_typeskill_id → course_type_code: BASE/BONUS/ROOM
    • 这不是看板需要展示的"技能"
  2. 项目类型area_category:指助教擅长的运动项目

    • BILLIARD🎱 中式/追分、SNOOKER斯诺克、MAHJONG🀄 麻将/棋牌、KTV🎤 团建/K歌
    • 配置表:cfg_area_category(台桌 → 区域 → 项目类型映射)
    • 视图:app.v_cfg_area_category(去重到 category 级别)
    • 这才是看板需要展示的"技能标签"

看板中 skills 的业务含义

  • 前端 SKILL_CLASS 映射:'🎱' → 'skill--chinese''斯' → 'skill--snooker''🀄' → 'skill--mahjong''🎤' → 'skill--karaoke'
  • 即:助教擅长哪些项目类型(台球/斯诺克/麻将/KTV

数据来源方案

  • dwd_assistant_service_log 按助教聚合历史服务的 area_category_code,取去重后的项目类型列表
  • SQL 示例:
    SELECT DISTINCT asl.area_category_code
    FROM dwd.dwd_assistant_service_log asl
    WHERE asl.assistant_id = %s
      AND asl.is_delete = 0
      AND asl.area_category_code IS NOT NULL
    
  • 或者:在 v_dim_assistant 视图中新增 skills 列(从服务记录聚合)

实施建议

  1. fdw_queries 中新增 get_assistant_skills_batch(conn, site_id, assistant_ids) 函数
  2. v_dwd_assistant_service_log 按助教聚合 area_category_code
  3. 映射为前端需要的格式:["BILLIARD", "SNOOKER"]
  4. get_coach_board()get_coach_detail() 中调用并填充 skills 字段

P7助教看板"折前"字段perf_hours_before / salary_perf_before

现状

  • 后端 get_coach_board() 返回 perf_hours_before: Nonesalary_perf_before: None
  • 前端 WXML 已有条件渲染:wx:if="{{item.perfHoursBeforeLabel}}" 显示"折前 XX.Xh"

业务含义

  • perf_hours = 折算后的定档业绩课时effective_hours
  • perf_hours_before = 折算前的原始课时base_hours + bonus_hours + room_hours
  • 折算规则:同一台桌同一时段 >2 名助教重叠挂台时,计算 per_hour_contribution = base_ledger_amount / base_hours / overlap_count,若 < 24 元/小时则按比例扣减 penalty_minutes
  • 豁免条件:is_exempt = true(客人真实需求,前台核实并绑定客人信息)
  • 只要 effective_hours != raw_hours 就显示折前课时,与新入职无关

注意:这不是"环比",而是"折算前 vs 折算后"的对比。前端 WXML 中的 perfHoursBeforeLabel 显示的是"折前 XX.Xh",不是"上期 XX.Xh"。

数据来源

  • dws_assistant_salary_calc 表中应有 raw_hours(折算前)和 effective_hours(折算后)
  • 需确认 DWS 表是否已有 raw_hours 字段
  • 如果没有,需要在 DWS 任务中补充计算

P8客户看板 loyal 维度缺少 coachDetails 子数组

现状

  • 前端 WXML 已有完整的助教服务明细表渲染(board-customer.wxml 第 254-277 行)
  • 表头:助教 | 次均时长 | 服务次数 | 助教消费 | 关系指数
  • 数据绑定:wx:for="{{item.coachDetails}}"
  • 但后端 get_customer_board_loyal() 只返回了 top_assistant_idtop_coach_name,没有返回 coach_details 数组

用户明确的排列规则

  • 客户-助教对RSI 从高到低排列
  • 客户不重复,排重规则是放在最高对的位置
  • 每个卡片展示客户信息 + 该客户对应所有助教 RSI 值从高到低排列
  • 右上位置展示最高 RSI 值助教

当前后端实现fdw_queries.py 第 2272-2340 行):

WITH member_top AS (
    SELECT ri.member_id,
           MAX(ri.rs_display) AS max_rs,
           (ARRAY_AGG(ri.assistant_id ORDER BY ri.rs_display DESC))[1] AS top_assistant_id,
           (ARRAY_AGG(ri.rs_display ORDER BY ri.rs_display DESC))[1] AS top_rs
    FROM app.v_dws_member_assistant_relation_index ri
    GROUP BY ri.member_id
    ORDER BY MAX(ri.rs_display) DESC
    LIMIT %s OFFSET %s
)
  • 排序正确:按 max_rs DESC(最高 RSI 降序)
  • 客户不重复:GROUP BY ri.member_id
  • 右上角最高 RSI 助教:top_assistant_id + top_coach_name
  • 缺少:每个客户对应的所有助教明细

需要补充的后端逻辑get_customer_board_loyal() 返回 items 后,批量查询每个客户的所有助教 RSI 明细:

SELECT ri.member_id,
       ri.assistant_id,
       COALESCE(da.real_name, da.nickname, '') AS name,
       ri.rs_display,
       ri.service_count,
       ri.total_hours,
       ri.total_income
FROM app.v_dws_member_assistant_relation_index ri
LEFT JOIN app.v_dim_assistant da
    ON ri.assistant_id = da.assistant_id AND da.scd2_is_current = 1
WHERE ri.member_id = ANY(%s)
ORDER BY ri.member_id, ri.rs_display DESC

前端 coachDetails 字段结构

interface CoachDetail {
  name: string          // 助教姓名
  cls: string           // 样式类
  heartScore: number    // RSI 值0-10
  badge?: string        // "跟" / "弃"
  avgDuration: string   // 次均时长
  serviceCount: string  // 服务次数
  coachSpend: string    // 助教消费金额
  relationIdx: number   // 关系指数
}

计算规则

  • avgDuration = total_hours / service_count(次均时长)
  • serviceCount = service_count(服务次数)
  • coachSpend = total_income(助教消费金额,即该客户在该助教处的消费)
  • relationIdx = rs_displayRSI 值)
  • heartScore = rs_display(用于 heart-icon 组件)
  • badge:跟/弃标记来源待确认(可能来自 coach_tasks 表的任务状态)

P9客户看板项目筛选枚举不一致

现状

  • board-customer.tsPROJECT_OPTIONS 使用旧枚举值:
    { value: 'all', text: '全部' },
    { value: 'chinese', text: '🎱 中式/追分' },
    { value: 'snooker', text: '斯诺克' },
    { value: 'mahjong', text: '🀄 麻将/棋牌' },
    { value: 'karaoke', text: '🎤 团建/K歌' },
    
  • board-coach.tsSKILL_OPTIONS 已修正为数据库枚举值2026-03-20 修复):
    { value: 'ALL', text: '不限' },
    { value: 'BILLIARD', text: '🎱 中式/追分' },
    { value: 'SNOOKER', text: '斯诺克' },
    { value: 'MAHJONG', text: '🀄 麻将/棋牌' },
    { value: 'KTV', text: '🎤 团建/K歌' },
    

问题:客户看板的 project 参数值(all/chinese/snooker/mahjong/karaoke)与后端枚举(ALL/BILLIARD/SNOOKER/MAHJONG/KTV不一致API 调用会失败。

修复:将 PROJECT_OPTIONS 的 value 改为 ALL/BILLIARD/SNOOKER/MAHJONG/KTV


三、环比字段分布

根据调研,环比字段的分布如下:

3.1 财务看板BOARD-3— 已实现环比

后端 get_finance_board() 接受 compare 参数0/1compare=1 时计算环比。

环比字段分布(xcx_board.py Schema

  • OverviewPanel8 项核心指标各有 *_compare / *_down / *_flat 三元组
  • RechargePanel:储值卡各项 + 全类别余额合计
  • RevenuePanel:总发生额 / 优惠总计 / 确认收入
  • CashflowPanel:充值合计
  • ExpensePanel:支出合计
  • CoachAnalysisPanelpay / share / hourly 各有环比

前端 WXML 使用 fmt.compareText() + fmt.compareClass() WXS 函数渲染。

3.2 助教看板BOARD-1— 非环比字段

perf_hours_before / salary_perf_before 不是环比,而是"折算前课时"

  • 前端 WXML 显示为"折前 XX.Xh"
  • 只有新入职助教才有折算值
  • 数据来源DWS dws_assistant_salary_calcraw_hours 字段

3.3 客户看板BOARD-2— 无环比

当前无环比字段设计。

3.4 助教详情页COACH-1— 无环比

当前无环比字段设计。

3.5 客户详情页CUST-1— 无环比

当前无环比字段设计。


四、统计规则详解

4.1 助教看板四维度

定档业绩维度perf

  • 排序字段:effective_hours(折算后工时)
  • 升序/降序:perf_desc / perf_asc
  • 卡片展示:定档课时、折前课时(新入职才有)、距升档差距、是否达标
  • 数据来源:dws_assistant_salary_calc.effective_hours

工资维度salary

  • 排序字段:gross_salary
  • 计算公式:assistant_pd_money_total + assistant_cx_money_total + bonus_money + room_income
  • 卡片展示:工资金额、定档课时、折前课时
  • 数据来源:dws_assistant_salary_calc

客源储值维度sv

  • 排序字段:sv_amount(客户余额合计)
  • 卡片展示:储值金额、储值客户数、储值消耗
  • 数据来源:fdw_queries.get_coach_sv_data()
  • 互斥规则:time=last_6m 时不支持此维度HTTP 400

任务维度task

  • 排序字段:task_totalrecall + callback
  • 卡片展示:回访完成数、召回完成数
  • 数据来源:业务库 biz.coach_taskstask_type 分类统计

4.2 客户看板八维度

最应召回recall

  • 排序:自定义排序(综合理想间隔、已过天数、余额等因素)
  • 展示理想间隔天数、已过天数、逾期天数、30天到店次数、余额、召回指数
  • 数据来源:v_dws_member_consumption_summary + v_dws_member_winback_index

最大消费潜力potential

  • 排序:自定义评分
  • 展示潜力标签、30天消费、平均到店频率、平均客单价
  • 数据来源:v_dws_member_consumption_summary

最高余额balance

  • 排序:total_card_balance DESC(卡余额快照值)
  • 展示:最后到店日期、月消费、可用月数
  • 数据来源:v_dim_member_card_account(快照值,取最后一天)
  • ⚠️ 余额是快照值,禁止 SUM

最近充值recharge

  • 排序:recharge_amount DESC
  • 展示最后充值日期、充值金额、60天充值次数、当前余额
  • 数据来源:v_dws_member_consumption_summary

最近到店recent

  • 排序:last_visit_date DESC
  • 展示距今天数、60天到店次数
  • 数据来源:v_dws_member_consumption_summary

最高消费 近60天spend60

  • 排序:consume_amount_60d DESC
  • 展示60天消费金额、60天到店次数、高消费标签
  • 数据来源:v_dws_member_consumption_summary

最频繁 近60天freq60

  • 排序:visit_count_60d DESC
  • 展示平均间隔天数、8周柱状图
  • 数据来源:v_dws_member_consumption_summary(汇总)+ v_dwd_assistant_service_log(周粒度)

8 周柱状图统计规则(已实现,_get_weekly_visits_batch()

  • 时间范围:最近 56 天8 个自然周)
  • 分组:按 ISO 周(DATE_TRUNC('week', create_time::date)
  • 每周统计到店次数(COUNT(*)
  • val:该周到店次数
  • pct:相对于 8 周中最高值的百分比(val / max_val * 100
  • 固定返回 8 个元素,无数据的周 val=0, pct=0

最专一 近60天loyal

  • 排序:max_rs DESC(最高 RSI 降序)
  • 展示:最高 RSI 助教(右上角)、助教服务明细表
  • 数据来源:v_dws_member_assistant_relation_index

排列规则(用户明确):

  1. 客户-助教对RSI 从高到低排列
  2. 客户不重复,排重规则是放在最高对的位置
  3. 每个卡片展示客户信息 + 该客户对应所有助教 RSI 值从高到低排列
  4. 右上位置展示最高 RSI 值助教

RSI关系指数

  • 存储:dws_member_assistant_relation_index
  • 展示值:rs_display0-10 刻度)
  • Emoji 四级映射:>8.5→💖 / >7→🧡 / >5→💛 / ≤5→💙
  • 计算:由 DWS 层 DWS_RELATION_INDEX 任务产出RS/OS/MS/ML 四个子指数)

4.3 薪酬计算规则DWS 需求文档 3.2 节)

现行方案2026-03-01 起)

档位 总业绩小时数阈值 专业课抽成(元/h 打赏课抽成 次月休假
0档 淘汰压力 H < 120 28 50% 3天
1档 及格档 120 ≤ H < 150 18 40% 4天
2档 良好档 150 ≤ H < 180 13 35% 5天
3档 优秀档 180 ≤ H < 210 10 30% 6天
4档 销冠竞争 H ≥ 210 8 25% 休假自由
  • 过档后所有时长按新档位计算
  • 新入职助教:按日均 × 30 折算定档25日后入职最高定档至 2档
  • 折算仅用于定档,不适用于 Top3 奖
  • 档位节点:[0, 120, 150, 180, 210](从 cfg_performance_tier 配置表读取)

五、数据层依赖

5.1 DWS 表

表名 用途 使用页面
dws_assistant_salary_calc 助教绩效/工资 BOARD-1、COACH-1
dws_member_consumption_summary 客户消费汇总 BOARD-26个维度
dws_member_assistant_relation_index 客户-助教关系指数 BOARD-2loyal、CUST-1
dws_member_winback_index 客户召回指数 BOARD-2recall

5.2 DWD 表

表名 用途 使用页面
dwd_assistant_service_log 服务记录明细 BOARD-2freq60 周粒度、COACH-1
dim_member 会员维度表 所有页面JOIN 取姓名)
dim_assistant 助教维度表 所有页面JOIN 取姓名)
dim_member_card_account 会员卡账户 BOARD-2balance、CUST-1

5.3 配置表

表名 用途
cfg_performance_tier 绩效档位节点
cfg_bonus_rules 奖金规则
cfg_skill_type 课程类型映射skill_id → BASE/BONUS/ROOM
cfg_area_category 区域-项目类型映射BILLIARD/SNOOKER/MAHJONG/KTV

5.4 业务库表

表名 用途 使用页面
biz.coach_tasks 助教任务 BOARD-1任务维度、COACH-1、CUST-1
biz.notes 备注 COACH-1、CUST-1
biz.ai_cache AI 洞察缓存 CUST-1暂不处理
public.member_retention_clue 维客线索 CUST-1

六、实施顺序建议

Phase 1 — 基础联调(前端 Mock → 真实 API
  ├── P9: 修复客户看板项目筛选枚举5 分钟)
  ├── P4: 助教看板 Mock → 真实 API
  ├── P5: 客户看板 Mock → 真实 API
  ├── P2: 助教详情页 Mock → 真实 API
  └── P3: 客户详情页 Mock → 真实 APIAI 相关暂跳过)

Phase 2 — 数据补全
  ├── P6: 助教 skills 字段填充
  ├── P7: 助教看板折前课时字段
  └── P8: 客户看板 loyal 维度 coachDetails 子数组

Phase 3 — 交互优化
  └── P1: 看板 Tab 切换改为同页切换

七、风险点

  1. TS 与 WXS 格式化互斥:替换 Mock 时,setData 必须传原始数字,禁止用 formatMoney() 预格式化
  2. null 值清洗:后端返回 null 的字段,前端必须 ?? 0 / ?? '' 清洗后再传给组件
  3. Pydantic 静默丢弃:后端 service 新增返回字段时,必须同步更新 Schema否则数据被静默丢弃
  4. 余额快照值balance 是日末快照,禁止 SUM 聚合
  5. 档位节点:前端硬编码的 [0, 100, 130, 160, 190, 220] 与实际 [0, 120, 150, 180, 210] 不一致
  6. 看板 Tab 重构:如果 board-finance 是 tabBar 页面,合并后需要调整 app.json 和 custom-tab-bar
  7. 助教姓名:所有助教必须显示昵称/花名(nickname),禁止显示真实姓名(real_name。SQL 统一用 COALESCE(nickname, real_name, '')