# chat-history 页面数据来源排查

> 排查日期：2026-03-18
> 页面路径：pages/chat-history/chat-history
> 排查范围：chat-history.ts / .wxml / .wxss / .json + 引用的 mock-data.ts / sort.ts / time.ts

## 概览

| 分类 | 数量 | 说明 |
|------|------|------|
| A. Mock 数据 | 5 字段 | 全部列表数据来自 `mockChatHistory`，无真实 API |
| B. 硬编码数据 | 5 处 | `ICON_GRADIENTS` 配色、延迟常量、回退值、跳转路径 |
| C. 已对接 API | 0 | 页面尚未对接任何后端接口 |
| D. 前端计算/派生 | 4 字段 | `timeLabel`、`iconGradient`、`pageState`、`statusBarHeight` |
| E. 路由参数 | 0 | 本页无接收路由参数（跳转时传出 `historyId`） |
| F. WXML 硬编码文案 | 6 处 | 加载/错误/空态/底部提示等 UI 文案 |

---

## 一、Mock 数据（来自 mock-data.ts）

数据源：`import { mockChatHistory } from '../../utils/mock-data'`
类型定义：`ChatHistoryItem`

| # | 字段 | 类型 | Mock 值示例 | 说明 |
|---|------|------|-------------|------|
| 1 | `id` | `string` | `'chat-001'` | 对话记录唯一 ID |
| 2 | `title` | `string` | `'张伟消费分析'` | 对话标题 |
| 3 | `lastMessage` | `string` | `'已记录。下次回访张伟时...'` | 最后一条消息摘要 |
| 4 | `timestamp` | `string` | `'2026-03-05T14:02:03+08:00'` | ISO 8601 时间戳 |
| 5 | `customerName` | `string?` | `'张伟'` / `undefined` | 可选，关联客户名 |

Mock 数据条数：4 条（`mockChatHistory` 数组长度）

---

## 二、硬编码数据

| # | 位置 | 值 | 说明 |
|---|------|-----|------|
| 1 | `chat-history.ts` 顶部常量 `ICON_GRADIENTS` | 6 组 CSS 渐变色 | VI 规范 §6.2 AI 图标配色系统（indigo/purple/red/orange/yellow/blue） |
| 2 | `chat-history.ts` → `loadData()` | `setTimeout(..., 400)` | 模拟网络延迟 400ms，联调时需替换为真实异步调用 |
| 3 | `chat-history.ts` → `onPullDownRefresh()` | `setTimeout(() => wx.stopPullDownRefresh(), 600)` | 下拉刷新 600ms 后停止，联调时需与真实请求回调绑定 |
| 4 | `chat-history.ts` → `onLoad()` | `sysInfo.statusBarHeight \|\| 44` | 状态栏高度回退值 44（当前 WXML 中未消费该值） |
| 5 | `chat-history.ts` → `onItemTap()` | `'/pages/chat/chat?historyId=' + id` | 跳转路径硬编码 |

---

## 三、已对接 API

**无。** 页面当前 0 个真实 API 调用。

代码中有明确 TODO 注释：
```typescript
// TODO: 替换为真实 API 调用
const sorted = sortByTimestamp(mockChatHistory)
```

---

## 四、前端计算/派生数据

| # | 字段 | 计算逻辑 | 依赖 |
|---|------|----------|------|
| 1 | `timeLabel` | `formatRelativeTime(item.timestamp)` | `time.ts` → 将 ISO 时间戳转为「刚刚/N分钟前/N小时前/N天前/MM-DD/YYYY-MM-DD」 |
| 2 | `iconGradient` | `ICON_GRADIENTS[Math.floor(Math.random() * ICON_GRADIENTS.length)]` | 从 6 色渐变数组中随机取一个（每次渲染结果不同） |
| 3 | `pageState` | 状态机：`'loading'` → `'normal'` / `'empty'` / `'error'` | 根据 `list.length === 0` 判断空态，`catch` 进入错误态 |
| 4 | `statusBarHeight` | `wx.getWindowInfo().statusBarHeight \|\| 44` | 系统 API 获取（当前 WXML 未消费此值） |

---

## 五、路由参数

**本页无接收路由参数。** `onLoad()` 未读取 `options` 参数。

传出参数（跳转时）：

| 目标页 | 参数 | 来源 |
|--------|------|------|
| `/pages/chat/chat` | `historyId={item.id}` | 列表项的 `id` 字段（当前为 Mock） |

---

## 六、WXML 硬编码文案

| # | 位置 | 文案 | 说明 |
|---|------|------|------|
| 1 | 加载态 toast | `加载中...` | loading 浮层文案 |
| 2 | 错误态 emoji | `😵` | 错误图标（emoji） |
| 3 | 错误态文案 | `加载失败，请重试` | 错误提示 |
| 4 | 错误态按钮 | `重新加载` | 重试按钮文案 |
| 5 | 空态描述 | `暂无对话记录` | `<t-empty description="暂无对话记录" />` |
| 6 | 底部提示 | `— 已加载全部记录 —` | 列表底部 footer |

---

## 七、联调 TODO

### 7.1 必须替换的 Mock 数据

| 优先级 | 改动项 | 当前状态 | 联调目标 |
|--------|--------|----------|----------|
| P0 | `mockChatHistory` → 真实 API | `loadData()` 中直接引用 mock 数组 | 调用后端 `GET /api/chat/history` 或类似接口，返回 `ChatHistoryItem[]` |
| P0 | 移除 `setTimeout(…, 400)` 模拟延迟 | 硬编码 400ms | 替换为 `wx.request` / 封装的 `http.get()` 异步调用 |
| P1 | 下拉刷新绑定真实请求 | `onPullDownRefresh` 中 600ms 后固定停止 | 在 API 回调中调用 `wx.stopPullDownRefresh()` |

### 7.2 需确认的接口契约

| 字段 | 问题 | 建议 |
|------|------|------|
| `id` | Mock 为 `chat-001` 格式，后端实际 ID 格式？ | 确认是 UUID / 自增 ID / 其他 |
| `title` | 对话标题由谁生成？后端还是前端？ | 确认接口是否返回 `title` |
| `lastMessage` | 是否需要截断？最大长度？ | 确认接口返回的是完整消息还是摘要 |
| `timestamp` | 后端返回格式？ISO 8601 / Unix ms？ | `formatRelativeTime` 两种都支持 |
| `customerName` | 可选字段，后端是否一定返回？ | 确认接口契约中该字段的 nullable 语义 |

### 7.3 需关注的前端逻辑

| 项目 | 说明 |
|------|------|
| `iconGradient` 随机分配 | 每次渲染/刷新颜色会变，是否需要按 `id` 哈希固定？ |
| `statusBarHeight` 未使用 | `data.statusBarHeight` 已计算但 WXML 中无消费，可能是自定义导航栏残留代码 |
| 分页/无限滚动 | 当前一次性加载全部，数据量大时需要分页 |
| 错误态重试 | `onRetry` 调用 `loadData()`，联调后需确认错误处理（网络超时/401/500 等） |
| `import { mockChatHistory }` | 联调完成后需删除此 import 及 `mock-data.ts` 中对应导出 |

### 7.4 引用的工具函数（无需改动）

| 函数 | 文件 | 用途 | 联调影响 |
|------|------|------|----------|
| `sortByTimestamp()` | `utils/sort.ts` | 按 `timestamp` 降序排列 | 纯函数，无需改动 |
| `formatRelativeTime()` | `utils/time.ts` | 时间戳 → 相对时间文案 | 纯函数，无需改动 |

### 7.5 引用的组件

| 组件 | 路径 | 数据依赖 |
|------|------|----------|
| `ai-float-button` | `/components/ai-float-button/` | 无 props 传入，组件内部自治 |
| `dev-fab` | `/components/dev-fab/` | 开发调试用浮动按钮，上线前移除 |
| `t-loading` | TDesign | 无数据依赖 |
| `t-icon` | TDesign | `name`/`size`/`color` 硬编码 |
| `t-empty` | TDesign | `description` 硬编码 |
