docs: UI alignment spec + StaffList interaction plan
Spec: align all list/detail pages to 云客 (columns + interactions); covers interaction taxonomy, backend extensions (customer add_time/filters, /api/sessions), phase-0 capture. Plan 1: StaffList interaction closure + customer backend + YkStaffDetailModal. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# yunkes 前端页面对齐云客后台 — 设计文档
|
||||
|
||||
- 日期:2026-08-05
|
||||
- 分支:feat/yunke-data-mirror
|
||||
- 状态:待评审
|
||||
|
||||
## 背景
|
||||
|
||||
yunkes 是云客 CRM(crm2.yunkecn.com)数据镜像的查看后台(Vue3 + Element Plus)。当前各列表/详情页的表格列结构与交互均与云客后台(Ant Design Vue)不一致,用户在两套系统间切换认知成本高。
|
||||
|
||||
需将所有"有云客对应"的页面**列结构 + 交互功能**对齐云客。StaffList(员工列表)已于 2026-08-05 完成列结构对齐(待补交互),验证了采集与改造方法。
|
||||
|
||||
## 目标
|
||||
|
||||
所有有云客对应的列表/详情页:
|
||||
1. **列结构**(列名、顺序、操作按钮、复合单元格字段组合)与云客一致
|
||||
2. **交互功能**(可点元素 + 点击行为:跳转/modal/新 tab)与云客一致
|
||||
|
||||
视觉用 Element Plus 自然样式(不引入 antd,不做像素级复刻)。包含必要的后端筛选参数扩展。
|
||||
|
||||
## 范围
|
||||
|
||||
### 对齐(6 个页面 + StaffList 补交互)
|
||||
| 页面 | 路由 | 云客对应 | 列对齐 | 交互 |
|
||||
|---|---|---|---|---|
|
||||
| StaffList | `/staff` | 员工微信列表 + WhatsApp 员工列表 | ✅ 已完成 | 本轮补 |
|
||||
| CustomerList | `/customers` | 客户列表 | 待做 | 待做 |
|
||||
| GroupList | `/groups` | 群列表/统计 | 待做 | 待做 |
|
||||
| CallList | `/calls` | 语音通话列表 | 待做 | 待做 |
|
||||
| SmsList | `/sms` | 短信记录 | 待做 | 待做 |
|
||||
| ChatTimeline | `/chat`,`/group` | 聊天记录(会话列表+消息流,只读查看器) | 待做 | 待做 |
|
||||
| SearchView | `/search` | 全局搜索 | 待做 | 待做 |
|
||||
|
||||
### 删除
|
||||
- **AccountList `/accounts`** — 云客无此页面,且与 StaffList 内容重复。删除路由 + 文件 + 导航入口,`/accounts` → `/staff` 客户端重定向。
|
||||
|
||||
### 不动
|
||||
- SyncStatus `/sync` — 运维监控页,云客无对应。
|
||||
|
||||
## 列对齐设计
|
||||
|
||||
**对齐**:列名、列顺序、操作按钮(文字/位置)、复合单元格字段组合。
|
||||
**不对齐**:antd vs el-table 像素级视觉(配色/行高/表头用 el-table 默认 + 少量 scoped 微调)。
|
||||
|
||||
**方法**(StaffList 已验证):Playwright `browser_evaluate` 采云客表头 + 复合单元格字段(`td.innerText` 按行拆分)+ 操作按钮文字 → dump smoke.db raw_json 核字段 → 改 `.vue`(el-table 列定义,字段经 `readField` 读)→ 浏览器对比 + `vue-tsc`。
|
||||
|
||||
## 交互对齐设计
|
||||
|
||||
云客列表的可点元素分三类,每类统一处理模式(已在 WhatsApp 员工表验证):
|
||||
|
||||
### 类型 1:跳转到列表页(route push)
|
||||
- **触发**:操作按钮(如"好友列表""群聊")、部分可点数字
|
||||
- **行为**:`router.push` 到目标列表页,带 query 预筛(`?owner_account_id=` 或 `?user_id=`)
|
||||
- **目标页改动**:读 `route.query` 的 owner/user 参数 → 传给 API 筛选 + 顶部显示"按员工 X 筛选"chip + 清除按钮
|
||||
- **云客实例**:WhatsApp 员工表"好友列表"→ `friendlist/0/{userId}`,"群聊"→ `friendlist/1/{userId}`
|
||||
- **后端**:`/api/customers`、`/api/groups` 已支持 `owner_account_id` ✓;新增 `user_id` 筛选(云客按 userId)
|
||||
|
||||
### 类型 2:明细 modal(el-dialog)
|
||||
- **触发**:统计数字(如"添加人数""沟通人数""消息数")
|
||||
- **行为**:弹出 `el-dialog`,内嵌精简明细表格,数据按"该员工 + 该维度"筛
|
||||
- **实现**:通用组件 `YkStaffDetailModal`(props:title / api 函数 / columns / 筛选参数),多页复用。复用 `el-table` + `el-pagination`
|
||||
- **云客实例**:WhatsApp 员工表"添加人数"→ modal 列 `序号/员工信息/员工WhatsApp/客户WhatsApp/添加时间/最后沟通时间`
|
||||
- **后端**(customer raw_json 已确认含 `addTime`/`lastChatTime`/`messageCount`):
|
||||
- 添加人数 → `customer where owner=X AND add_time >= now-N天` → 加 `add_time_since` 参数(依赖新增 `Customer.add_time` 列,见"后端端点需求")
|
||||
- 沟通人数 → `customer where owner=X AND lastChatTime >= now-N天` → 加 `last_chat_since` 参数
|
||||
- 其他维度(消息数/好友数等)执行时确认对应查询条件
|
||||
|
||||
### 类型 3:新 tab 聊天
|
||||
- **触发**:昵称 / 账号
|
||||
- **行为**:`router.push`(或新 tab)到 ChatTimeline `/chat/:channel/:ownerId/:talkerId`
|
||||
- **云客实例**:WhatsApp 员工表 WA 昵称 → `wschatroom/...`(该账号聊天记录)
|
||||
- **后端**:`/api/messages` 已支持 `owner_account_id` ✓;点昵称打开的是**会话列表 + 消息流**视图(已验证云客 wschatroom 即此结构,只读、无发消息),需新增 `/api/sessions` 聚合端点(见后端端点需求)
|
||||
|
||||
### 交互探测方法(每页执行时)
|
||||
用 Playwright 探测脚本(已验证):对每行每个可点元素(`button/a`),点击后记录"URL 变化 / modal title / popup",每次点前回到列表页、关闭残留 modal/tab。产出该页"可点元素 → 行为类型 → 目标"映射表。
|
||||
|
||||
## 后端端点需求
|
||||
|
||||
| 端点 | 扩展 | 依据列 | 用途 |
|
||||
|---|---|---|---|
|
||||
| `GET /api/customers` | 加 `user_id` | `Customer.user_id`(已有列) | 按员工筛客户 |
|
||||
| `GET /api/customers` | 加 `last_chat_since` | `Customer.last_chat_time`(epoch 列) | 沟通人数 modal |
|
||||
| `GET /api/customers` | 加 `add_time_since` | **需新增 `Customer.add_time` 列**(见下) | 添加人数 modal |
|
||||
| `GET /api/groups` | 加 `user_id` | `ChatGroup.owner_user_id`(参数名 `user_id` → 此列,注意映射) | 按员工筛群 |
|
||||
| `GET /api/accounts` | — | 已支持 channel | StaffList 用 |
|
||||
| `GET /api/messages` | — | 已支持 `owner_account_id` | 昵称跳聊天 ✓ |
|
||||
| `GET /api/sessions`(新增) | 按账号列会话:好友(customer)+群聊(group),含今日消息数 + 最近联系时间 | 聚合 customer/group + message(当日计数) | ChatTimeline 会话列表、类型 3 昵称入口 |
|
||||
|
||||
**`user_id` / `last_chat_since`**:直接走现有 router 模式(`Query()` 参数 + `conditions.append`),单测覆盖。
|
||||
|
||||
**`add_time_since` 需要数据模型扩展(本计划唯一 schema 变更)**:`Customer` 当前无 `add_time` 结构化列——`addTime` 仅在 `raw_json` 里且是字符串 `"YYYY-MM-DD HH:mm:ss"`,无法用 `col >= value` 直接筛(JSON-path 查询方言相关且慢,不采用)。方案:新增 `Customer.add_time` 列(BigInteger ms-epoch,对齐 `last_chat_time`)+ Alembic 迁移 + 回填脚本(解析 `raw_json.addTime` 字符串 → epoch)。完成后即可走标准筛选,参照 `last_chat_time` 既有实现与回填方式(项目已有 surrogate 修复回填先例)。
|
||||
|
||||
**同步层适配(关键,易漏)**:增量同步引擎(fetcher/ingest)抓取新 customer 时也必须解析 `raw_json.addTime` 填充 `add_time`,否则回填之后到达的增量数据该字段仍为 null。回填脚本只覆盖历史,同步层覆盖增量,两者都要做。
|
||||
|
||||
## 顺序
|
||||
|
||||
0. **全量采集(plan 第 0 步,必做)**:对每个待做页面,用 Playwright 采云客的列结构 + 可点元素 + 交互行为,dump 对应 raw_json 核字段,产出每页"目标列 + 交互映射 + 字段覆盖"清单。把当前的外推假设变成事实,避免返工。当前仅 WhatsApp 员工表 + 聊天页结构是已采事实,其余为外推。
|
||||
1. **StaffList 补交互**(已采,先闭环):数字 modal + 操作跳转 + 昵称聊天 + 后端 customer 筛选参数
|
||||
2. **CustomerList**:列对齐 + 可点元素交互(预计含跳客户详情、消息数 modal 等)
|
||||
3. **GroupList**:列对齐 + 交互 + 后端 group user_id
|
||||
4. **CallList + SmsList**(并行):列对齐 + 交互
|
||||
5. **ChatTimeline**:对齐云客只读聊天查看器——左侧会话列表(好友/群聊 tab + 今日消息数 + 最近联系时间)+ 右侧消息流 + 查询/导出按钮;新增 `/api/sessions` 聚合端点(工作量较大,单独评估)
|
||||
6. **SearchView**:搜索结果布局对齐 + 交互
|
||||
7. **AccountList 删除**(收尾)
|
||||
|
||||
## 共性策略
|
||||
|
||||
- 沿用统一模式:`useChannelStore`、rtl 全字段抽屉(`build*Sections`)、`[20/50/100]` 分页、`row-click` 开抽屉。
|
||||
- 字段读取复用各 `utils/*Fields.ts` 的 `readField`;新字段补进 `*_FIELD_LABELS`/`*_FIELD_GROUPS`。
|
||||
- **字符串时间修复**:云客 `addTime`/`lastUpdate` 等是 `"YYYY-MM-DD HH:mm:ss"`,旧代码按 number 解析显示 `--`;统一用 `cellTimeText`(字符串直显、number 才 formatTime)。StaffList 已修,其他页一并修。
|
||||
- **明细 modal 抽通用组件**(`YkStaffDetailModal`)——多页多数字复用,值得抽(不违反 YAGNI)。
|
||||
- CallList 的 `channel` 是 `phone_call`/`voice_call`(通话类型),保留其 LOCAL `callType` 筛选。
|
||||
- 不引入云客有但后端不支持的功能(导出/查询等装饰按钮),除非单独要求。
|
||||
|
||||
## AccountList 删除清单
|
||||
|
||||
- `router/index.ts`:移除 `/accounts` 路由记录,新增 `/accounts` → `/staff` 重定向。
|
||||
- 删除 `views/AccountList.vue`。
|
||||
- 清理导航入口(`layouts/MainLayout.vue` 约 line 126 指向 `/accounts` 的菜单项)。
|
||||
- 更新 `StaffList.vue` 两处对 `AccountList.vue` 的注释引用(drawer 实际来自 `accountFields.ts`)。
|
||||
- **保留数据层**:后端 `GET /api/accounts`(yunke-server)与前端 `getAccounts()`(`api/index.ts`,StaffList 依赖)是数据接口,不删。
|
||||
- 全仓 grep `AccountList`、`/accounts` 确认无 UI 残留引用。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 每页列名/顺序/操作按钮与云客一致(截图留档)。
|
||||
- 每页可点元素的行为与云客一致(跳转目标 / modal 列 / 新 tab),探测对比留档。
|
||||
- 数据正确填充(raw_json 读字段,无整列 `--`)。
|
||||
- 字符串时间字段正确显示。
|
||||
- 后端新筛选参数有单测;`Customer.add_time` 迁移 + 回填 + **同步引擎填充**完成;`/api/sessions` 聚合端点有单测;`pytest` 全绿(≥323 测试)。
|
||||
- `vue-tsc -b` exit 0,无 console 报错。
|
||||
- `/accounts` 客户端重定向到 `/staff`(URL 变 `/staff`、StaffList 渲染;非 HTTP 301)。
|
||||
|
||||
## 风险与降级
|
||||
|
||||
- **字段缺口**:某页云客 KPI 字段不在 raw_json → dump 确认;缺失显示 `--`/`0`,不阻塞,记入附录。
|
||||
- **modal 维度查询不明**:某些数字(如"消息数")对应的后端筛选条件云客未必直白 → 以云客 modal 实际返回数据为准,反推查询;无法精确复刻的,降级为跳转到对应列表页。
|
||||
- **会话列表视图(已验证需要)**:云客聊天页 = 会话列表 + 消息流(只读、无发消息),需新增 `/api/sessions` 聚合端点(好友/群聊 + 今日消息数 + 最近联系时间)。今日消息数需按 message 当日计数聚合,注意大数据量下的查询性能。
|
||||
- **modal 统计窗口**:员工列表统计已验证**不依赖日期选择器**(顶部 pickerCount=0,固定统计),但"添加人数 N"的窗口语义(最近几天/全部)仍未确认 → 执行时从 modal 明细的 addTime 范围反推;无法确认时默认取全部或最近 7 天并标注近似。
|
||||
- **采集时效**:云客改版则列/交互会变 → 以采集时刻为准,spec 记录采集日期(2026-08-05)。
|
||||
- **工作量**:列+交互+后端是大工程 → plan 按"页面 × 阶段"分解,每页可独立交付,不阻塞整体。
|
||||
Reference in New Issue
Block a user