# 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 小程序页面
