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>
11 KiB
yunkes 前端页面对齐云客后台 — 设计文档
- 日期:2026-08-05
- 分支:feat/yunke-data-mirror
- 状态:待评审
背景
yunkes 是云客 CRM(crm2.yunkecn.com)数据镜像的查看后台(Vue3 + Element Plus)。当前各列表/详情页的表格列结构与交互均与云客后台(Ant Design Vue)不一致,用户在两套系统间切换认知成本高。
需将所有"有云客对应"的页面列结构 + 交互功能对齐云客。StaffList(员工列表)已于 2026-08-05 完成列结构对齐(待补交互),验证了采集与改造方法。
目标
所有有云客对应的列表/详情页:
- 列结构(列名、顺序、操作按钮、复合单元格字段组合)与云客一致
- 交互功能(可点元素 + 点击行为:跳转/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。回填脚本只覆盖历史,同步层覆盖增量,两者都要做。
顺序
- 全量采集(plan 第 0 步,必做):对每个待做页面,用 Playwright 采云客的列结构 + 可点元素 + 交互行为,dump 对应 raw_json 核字段,产出每页"目标列 + 交互映射 + 字段覆盖"清单。把当前的外推假设变成事实,避免返工。当前仅 WhatsApp 员工表 + 聊天页结构是已采事实,其余为外推。
- StaffList 补交互(已采,先闭环):数字 modal + 操作跳转 + 昵称聊天 + 后端 customer 筛选参数
- CustomerList:列对齐 + 可点元素交互(预计含跳客户详情、消息数 modal 等)
- GroupList:列对齐 + 交互 + 后端 group user_id
- CallList + SmsList(并行):列对齐 + 交互
- ChatTimeline:对齐云客只读聊天查看器——左侧会话列表(好友/群聊 tab + 今日消息数 + 最近联系时间)+ 右侧消息流 + 查询/导出按钮;新增
/api/sessions聚合端点(工作量较大,单独评估) - SearchView:搜索结果布局对齐 + 交互
- 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(通话类型),保留其 LOCALcallType筛选。 - 不引入云客有但后端不支持的功能(导出/查询等装饰按钮),除非单独要求。
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 -bexit 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 按"页面 × 阶段"分解,每页可独立交付,不阻塞整体。