230 lines
10 KiB
Markdown
230 lines
10 KiB
Markdown
# P9:小程序前端 — 详情与对话模块 — miniapp-fe-details
|
||
|
||
> 优先级:P9(依赖 P3 + P4 + P5-A)
|
||
> 预估工作量:大
|
||
> P5-B 承接:T1 同时细化 P5 应用 3/6/7 的 Prompt JSON 结构
|
||
|
||
---
|
||
|
||
## 需求(Requirements)
|
||
|
||
### 用户故事
|
||
|
||
1. 作为助教,我在客户详情页能看到客户全信息、消费记录(三种样式)、指数总览、备注、AI 分析。
|
||
2. 作为助教,我在助教详情页能看到助教信息、客户数、工龄、备注。
|
||
3. 作为助教,我在 AI 对话页能与 AI 流式对话,看到来源页面信息。
|
||
4. 作为助教,我能查看历史 AI 对话记录。
|
||
|
||
### 验收标准
|
||
|
||
- AC1:消费记录区分三种样式(台桌结账→下沉台费明细、商城订单、充值)
|
||
- AC2:消费记录默认 10 条,拉到底懒加载(每次 10 条)
|
||
- AC3:金额为 0 的项不展示;有团购/折扣时展示正价+实付
|
||
- AC4:总金额仅在消费条目 >1 时出现
|
||
- AC5:AI 对话支持流式展示(逐字输出)
|
||
- AC6:从其他页面进入 chat.html 时新开对话,第一条消息为页面上下文
|
||
- AC7:对话历史列表可查看、可继续对话
|
||
|
||
---
|
||
|
||
## 页面清单
|
||
|
||
### customer-detail(客户详情)
|
||
|
||
- 客户信息卡片(昵称、手机、会员卡等级、余额、注册日期)
|
||
- 指数总览(WBI/NCI/SPI 展示分 + 爱心 icon)
|
||
- 消费记录列表(三种样式,懒加载)
|
||
- 台桌结账:下沉到 `dwd_table_fee_log`,每条台费详情,关联总金额汇总
|
||
- 商城订单:助教列表(花名+级别+课程类型+服务时长+定档绩效)、支付金额、食品酒水总金额
|
||
- 充值:充值金额、支付方式
|
||
- 备注列表
|
||
- AI 维客线索(应用 8 整合线索 + 人工,读取 `member_retention_clue`;Emoji 作为二级标签、提供者显示规则见下方"维客线索提供者显示规则"章节)
|
||
- AI 客户分析(应用 7 缓存:运营策略数组 + 总结,结账单出现后自动生成;从 `ai_cache` cache_type=app7_customer_analysis 读取)
|
||
- "问问助手"入口 → chat.html
|
||
|
||
### coach-detail(助教详情)
|
||
|
||
- 助教信息卡片(花名、级别、工龄)
|
||
- 客户数(RS > 2 的客户数量)
|
||
- 备注按钮(查看此助教为该客户做的备注)
|
||
|
||
### customer-service-records(客户服务记录)
|
||
|
||
- 服务记录列表(时间 + 持续时长)
|
||
|
||
### chat(AI 对话)
|
||
|
||
- 来源展示(来源页面 title + 基本信息)
|
||
- 对话界面(IM 风格)
|
||
- AI 回复流式展示(SSE)
|
||
- 消息输入 + 发送
|
||
|
||
### chat-history(对话历史)
|
||
|
||
- 历史对话列表(按时间倒序)
|
||
- 点击进入继续对话
|
||
|
||
---
|
||
|
||
## 后端 API 需求
|
||
|
||
| API | 说明 |
|
||
|-----|------|
|
||
| `GET /api/customers/:id` | 客户详情 |
|
||
| `GET /api/customers/:id/consumption-records` | 消费记录(分页,懒加载) |
|
||
| `GET /api/customers/:id/indexes` | 客户指数总览 |
|
||
| `GET /api/coaches/:id` | 助教详情 |
|
||
| `GET /api/coaches/:id/customer-count` | 助教客户数(RS>2) |
|
||
| `GET /api/customers/:id/service-records` | 客户服务记录 |
|
||
| `POST /api/chat/conversations` | 创建对话 |
|
||
| `POST /api/chat/conversations/:id/messages` | 发送消息(SSE 流式返回) |
|
||
| `GET /api/chat/conversations` | 对话历史列表 |
|
||
| `GET /api/chat/conversations/:id/messages` | 对话消息列表 |
|
||
|
||
### 消费记录 settle_type 区分
|
||
|
||
### settle_type 与消费记录类型映射(已校准,数据源:DWD-DOC 01-业务全景)
|
||
|
||
| settle_type | 含义 | 数量占比 | 消费记录样式 |
|
||
|:-----------:|------|---------|-------------|
|
||
| 1 | 台桌结账 | 78.6% | 下沉到 `dwd_table_fee_log` 台费明细 |
|
||
| 3 | 商城订单 | 21.4% | 助教列表 + 支付金额 + 食品酒水(含 477 笔纯超休/激励课订单) |
|
||
| 5 | 正常充值 | — | 从 `dwd_recharge_order` 单独查询 |
|
||
| 7 | 充值退款 | 极少(10 笔) | 不在消费记录中展示 |
|
||
| 6 | 结算退款 | 极少(1 笔) | 不在消费记录中展示 |
|
||
|
||
### 金额字段说明(已校准,数据源:DWD-DOC 02-账务全景 + consume 口径文档)
|
||
|
||
⚠️ 不得直接使用 `consume_money`(三种历史口径混合,不稳定)。
|
||
|
||
正价金额(消费项目合计,全时期一致):
|
||
```sql
|
||
items_sum = table_charge_money + goods_money + assistant_pd_money
|
||
+ assistant_cx_money + electricity_money
|
||
```
|
||
|
||
实付金额需按支付渠道拆分展示:
|
||
| 支付渠道 | 字段 | 说明 |
|
||
|----------|------|------|
|
||
| 线上支付 | `pay_amount` | 不含 balance,= `point_amount` + `cash_amount` |
|
||
| 储值卡 | `balance_amount` | 独立渠道,= `recharge_card_amount` + `gift_card_amount` |
|
||
| 团购券抵扣 | `coupon_amount` | 门店实际抵扣额 |
|
||
| 会员折扣 | `member_discount_amount` | 仅 settle_type=1 |
|
||
| 台费调整 | `adjust_amount` | 手动调价 |
|
||
| 抹零 | `rounding_amount` | 收支平衡减项 |
|
||
|
||
团购券三层价格体系(展示时注意区分):
|
||
- 顾客支付价 → `PCR.sale_price`
|
||
- 平台结算价 → `SH.pl_coupon_sale_amount`(= SUM(GR.ledger_unit_price))
|
||
- 门店抵扣价 → `SH.coupon_amount`(= SUM(GR.ledger_amount))
|
||
|
||
已知限制:
|
||
- `online_pay_channel` 全为 0,无法区分微信/支付宝(聚合支付接入)
|
||
- `settlement_head_ex` 中 `payment_method`、`is_use_coupon`、`is_activity` 等字段全为 0,不可用
|
||
- 团购券与会员折扣不叠加
|
||
- 2025-11-09 前台费明细 `is_delete=1`,历史数据不完整
|
||
|
||
---
|
||
|
||
## 维客线索提供者显示规则
|
||
|
||
### 后端过滤策略(安全性优先)
|
||
|
||
⚠️ **重要**:维客线索的过滤必须在后端完成,客户端不进行任何过滤逻辑,以防止数据泄露风险。
|
||
|
||
**客户详情页后端返回规则**:
|
||
|
||
后端应返回所有相关的维客线索(包括系统生成、当前用户、他人记录、备注分析),但需要根据用户权限进行脱敏:
|
||
|
||
| 线索类型 | 返回条件 | 说明 |
|
||
|---------|--------|------|
|
||
| 系统生成 | 总是返回 | `source = 'ai_consumption'`,完整返回 |
|
||
| 我的记录 | 总是返回 | `source = 'manual'` 且 `recorded_by_assistant_id = 当前用户ID`,完整返回 |
|
||
| 他人记录 | 返回完整版本 | `source = 'manual'` 且 `recorded_by_assistant_id ≠ 当前用户ID`,返回 `recorded_by_name` |
|
||
| 备注分析 | 返回完整版本 | `source = 'ai_note'`,返回原备注的 `recorded_by_name` |
|
||
|
||
### 前端显示规则
|
||
|
||
**客户详情页**:前端直接显示后端返回的所有维客线索,显示具体人名:
|
||
|
||
| source 值 | 显示文案 |
|
||
|----------|--------|
|
||
| `ai_consumption` | By:系统 |
|
||
| `manual` 且有 `recordedByAssistantId` | By:我 |
|
||
| `manual` 或 `ai_note` 且有 `recordedByName` | By:{recordedByName} |
|
||
|
||
多条线索时,提供者用逗号分隔展示(如"By:系统, 王芳, 李明")
|
||
|
||
**任务详情页**:前端根据后端返回的脱敏数据显示(详见 P6 规范)
|
||
|
||
### 多人情况处理
|
||
|
||
当同一客户有多条维客线索时,前端按以下规则展示:
|
||
|
||
1. **按时间排序**:按 `created_at` 升序排列(最早的在前)
|
||
2. **取最先反馈**:
|
||
- 如果有"By:系统"的线索,优先显示最早的"By:系统"
|
||
- 如果没有"By:系统",则显示最早的"By:我"或其他人名
|
||
3. **单条展示**:维客线索卡片中仅显示一条(最优先的),其他线索可通过"查看全部"或列表展开查看
|
||
|
||
### 前端实现示例
|
||
|
||
```typescript
|
||
// 客户详情页:直接显示后端返回的数据
|
||
function getClueProvider(clue: RetentionClue): string {
|
||
if (clue.source === 'ai_consumption') {
|
||
return 'By:系统'
|
||
}
|
||
if (clue.source === 'manual' && clue.recordedByAssistantId) {
|
||
return 'By:我'
|
||
}
|
||
if (clue.recordedByName) {
|
||
return `By:${clue.recordedByName}`
|
||
}
|
||
return 'By:某人' // 备用
|
||
}
|
||
|
||
// 从多条线索中选择最优先的
|
||
function selectPrimaryClue(clues: RetentionClue[]): RetentionClue {
|
||
const sorted = clues.sort((a, b) =>
|
||
new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
||
)
|
||
|
||
const systemClue = sorted.find(c => c.source === 'ai_consumption')
|
||
if (systemClue) return systemClue
|
||
|
||
return sorted[0]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 小程序前端开发强制规范
|
||
|
||
> 以下规范适用于本 SPEC 中所有小程序页面实现,具有强制约束力。
|
||
|
||
1. **原型图是唯一视觉真相**:`docs/h5_ui/pages/*.html` 中的结构、层次、元素、配色、间距、交互行为是小程序页面实现的唯一参考标准。任何偏离原型图的实现都需要明确的产品确认。
|
||
2. **WXML ≠ HTML**:严禁在小程序中使用 HTML 标签(div/span/p/a/img 等),必须使用小程序原生标签(view/text/image/navigator 等)。
|
||
3. **WXSS ≠ CSS**:使用 rpx 单位、仅支持有限选择器、无 DOM/BOM API、样式隔离机制不同。Tailwind CSS 类名必须手动转换为 WXSS。
|
||
4. **TDesign 优先**:凡 TDesign 组件库能覆盖的 UI 元素,必须使用 TDesign 组件;自定义实现仅限 TDesign 无法覆盖的场景。
|
||
5. **Power 文档优先**:实现前必须加载 `wechat-miniprogram` Power 的相关 steering 文件(`view-layer.md`、`tdesign.md`、`builtin-components.md`),确保语法和组件用法正确。
|
||
6. **项目踩坑指南必读**:实现前必须阅读 `docs/prd/MIGRATION-PLAYBOOK.md` 第六章,该文档是基于本项目实际转换经验的避坑手册,涵盖 WXML/WXSS 差异、事件系统、TDesign 用法、rpx 换算规则及新页面开发 Checklist。
|
||
|
||
---
|
||
|
||
## 任务清单
|
||
|
||
- [ ] T1:实现客户详情 API
|
||
- T1-a:细化 P5 应用 3(维客线索)Prompt JSON 结构,实现 `consumption_records`、`member_cards` 等字段的拼接函数(对应 P5-T6-完整)
|
||
- T1-b:细化 P5 应用 6(备注分析)Prompt JSON 结构,实现 `consumption_data` 字段的拼接函数(对应 P5-T9-完整)
|
||
- T1-c:细化 P5 应用 7(客户分析)Prompt JSON 结构,实现 `objective_data` 字段的拼接函数(对应 P5-T10-完整)
|
||
- [ ] T2:实现消费记录分页 API(三种样式区分 + 懒加载)
|
||
- [ ] T3:实现客户指数总览 API
|
||
- [ ] T4:实现助教详情 API
|
||
- [ ] T5:实现对话 API(创建/发送/历史/消息列表,SSE 流式)
|
||
- [ ] T6:实现 customer-detail 小程序页面
|
||
- [ ] T7:实现 coach-detail 小程序页面
|
||
- [ ] T8:实现 customer-service-records 小程序页面
|
||
- [ ] T9:实现 chat 小程序页面(流式展示 + 来源信息)
|
||
- [ ] T10:实现 chat-history 小程序页面
|