614680a4eb
Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
11 KiB
云客员工聊天窗口对齐设计(StaffChat 五视图)
- 日期:2026-08-25
- 状态:已批准(用户逐节确认)
- 范围:微信员工列表 → 员工信息列昵称点击进入的聊天窗口页,对齐云客全部 5 个视图(单聊/群聊/朋友圈/通讯录/统计分析),含功能与数据
1. 背景与目标
现有 ChatTimeline.vue(双栏:会话侧栏+消息流)与云客员工聊天窗口差距大。云客真机(2026-08-25 Playwright 实测,员工 wxid_wo97u1u2x11w22)该页面是三栏五视图结构:左侧员工资料卡+导航,中间会话列表,右侧内容区按导航切换五种视图。
目标:新建独立页面完整对齐(布局/交互/数据口径),并与云客保持一致。旧 ChatTimeline 保留给 WhatsApp 渠道,不动。
用户决策记录(2026-08-25 逐项确认)
| 决策点 | 结论 |
|---|---|
| 范围 | 全部 5 个视图(含用户未提的统计分析) |
| 渠道 | 只做微信版;WA 保持现有页面 |
| 删除聊天记录按钮 | 不复刻(镜像数据删了只有重扫能找回) |
| 敏感词统计 | tab 占位空态(待 C1 敏感词功能接入,见 2026-08-24 数据分析方案) |
| 实现方案 | 方案 A:独立新页 StaffChat.vue,组件拆分,旧页不动 |
2. 云客真机事实(对齐依据)
页面 URL:/cms/wechat/salewechat/message/wechat-window/{tab}/{wxId}/{friendId},tab 路径段 1=单聊 2=群聊;朋友圈/通讯录/统计分析是独立路由但共享左栏。
2.1 布局
┌─────────┬──────────────┬────────────────────────┐
│ 员工资料卡 │ 好友/群|聊天记录▼ │ 对话标题 │
│ 昵称 │ [搜索框] │ [近14天窗][关键词][类型▼]│
│ 真名·电话 │ ┌──────────┐ │ [导出聊天记录] │
│ 微信号 │ │聊天好友│已删除│ │ 消息流(加载更多+日期分隔) │
│─────────│ └──────────┘ │ │
│ 单聊/群聊/ │ 📌置顶区(可折叠)│ │
│ 朋友圈/ │ 会话卡列表 │ │
│ 通讯录/ │ (头像+今日N │ │
│ 统计分析 │ +相对时间) │ │
└─────────┴──────────────┴────────────────────────┘
2.2 接口事实(真机抓包)
| 视图 | 接口 | 关键参数/字段 |
|---|---|---|
| 员工资料卡 | GET /wechatweb/wxFriends/getUserAndFriendInfo?wechatId=&friendId= |
saleName 昵称、realName 真名、salePhone、alias/wechatId、HeadImageUrl 头像 |
| 会话列表(单聊) | POST /wechatweb/wxFriends/talkerList form |
`type=1, isDel=0 |
| 会话列表(群聊) | 同上 | type=2(无 isDel);群名不脱敏 |
| 朋友圈 | POST /wechatweb/wechatFriendster/getFriendsterInfo form |
startTime/endTime(空), pageNum, pageSize=10, wechatId;行:id/snsId/friendsterName/friendsterWXIdImg/content/createTime(秒)/type(1图文/28纯文字)/praise[]{name,praiseImg}/comment[]/imgUrlsList[](OSS URL)/praiseNum;头部 saleNickName/headImageUrl/saleAlias/bgImg;hashNext 翻页 |
| 通讯录 | POST /wechatweb/wxFriends/friend_list/es |
即逐员工客户列表(已抓过);表格列:客户微信(昵称+微信号)/数据来源/客户备注名/最近沟通时间/发送条数/接收条数/操作(查看聊天记录+导出HTML聊天记录) |
| 统计计数 | POST /wechatweb/wechatcount/getSaleWechatIdInfoCount |
{addFriend, addGroup, redAndTrans, sensitiveCount, delFriend, blackFriend, weChatVoiceCount} |
| 统计明细 | POST /wechatweb/wxFriends/getAddFriendOrGroup form |
pageNum, pageSize, friendTypeYunke=1, wechatId, startdate, enddate;行:客户微信(可点→聊天)/客户备注/员工微信/时间 |
其他 UI 事实:
- 右列默认日期窗近 14 天(
今日00:00-14天 ~ 今日23:59:59),统计视图默认近 7 天 - 类型下拉 10 类:文本/图片/语音消息/语音通话/视频通话/文件/小程序名片/链接/红包/转账
- 「好友/群|聊天记录」下拉:聊天记录模式=左侧按全量消息关键词搜索
- 置顶区含文件传输助手,可「折叠置顶聊天」
- 已删除好友 tab 存在(实测 3 条老好友,最近联系时间可显示到 2025 年)
- 资料卡 cursor=pointer 但点击无可见行为(不复刻点击)
3. 架构(方案 A)
路由: /staff-chat/:ownerId/:tab(single|group|moments|contacts|stats)/:talkerId?
默认 tab=single;talkerId 可空(账号级入口)
StaffChat.vue (页面骨架)
├── StaffChatSide.vue 左栏: 员工资料卡 + 5 导航按钮
├── tab=single|group → SessionPane.vue (中列) + ChatMain.vue (右列)
├── tab=moments → MomentsPane.vue
├── tab=contacts → ContactsPane.vue
└── tab=stats → StatsPane.vue
SessionPane/ChatMain从ChatSidebar/ChatTimeline复制改造(非原地重构);MessageBubble、buildMessageSections直接复用ChatTimeline.vue/ChatSidebar.vue不动,WA 继续用;未提交 WIP(sidebarProfile传参、delete_flagquery 类型)随本设计消化:ChatTimeline 还原 WIP,delete_flag参数由新 sessions API 取代- 入口改造:
StaffList.vue微信行昵称/主badge →/staff-chat/{account_id}/single;modal 内点客户微信带日期窗 query;CustomerList.vue微信行「查看聊天记录」同步切新页
4. 数据层
4.1 新表 moments_post
| 列 | 类型 | 说明 |
|---|---|---|
| id | VARCHAR(64) PK | 云客 data.id |
| wechat_id | VARCHAR(128) idx | 归属员工 |
| sns_id | VARCHAR(64) | 云客 snsId |
| author_name / author_wxid / author_avatar | VARCHAR | 发布者 |
| content | TEXT | 文案 |
| type_raw | VARCHAR(16) | 1=图文 28=纯文字 |
| create_time | BIGINT idx | 发布时间(ms) |
| praise_json / comment_json / image_urls | JSON | 点赞/评论/图片 |
| raw_json + fetched_at/updated_at | 惯例字段 |
4.2 新抓取实体 moments(页面 fetch 方式)
- 浏览器
fetch POST getFriendsterInfo,pageSize=100逐员工翻页到hashNext=false - 接入
scrape_via_page.py实体注册、full_sync_all.sh加一步、调度 4h 增量(水位=本地 max(create_time),仅扫有新朋友圈的员工——云客接口无 per-员工增量标记,简化为全量浅扫第一页有新才继续) - 图片接入现有 media 本地化批处理(OSS URL 型)
4.3 API 改动
| API | 改动 |
|---|---|
GET /api/accounts |
AccountOut + avatar(从 raw_json.headImageUrl 提取,WA 侧无此键则 null) |
GET /api/sessions |
+ is_del 参数(join customer.delete_flag,NULL 视为 0);行 + pinned(talker_id='filehelper') |
GET /api/moments 新 |
?wechat_id=&page=&page_size= 帖子 desc + 头部 {nickname, avatar, alias} |
GET /api/staff-stats 新 |
?wechat_id=&start=&end= 计数;&kind= 明细行 |
GET /api/messages |
+ msg_type 过滤(映射云客 10 类)+ q 全文关键词(聊天记录模式用) |
4.4 统计口径(现有表本地聚合)
| tab | 口径 |
|---|---|
| 新的客户 | customer.add_time 窗内(实测 62% 有值);缺失兜底=该对话首条消息时间 |
| 新的群 | chat_group 建群时间(无则跳过该 tab 计数,显示现存量) |
| 红包转账 | message.type_raw=49 AND (raw_json.paymsgid 非空 OR text 含 appmsg type 2001/2000),合并一类;明细金额从 XML <feedesc> 提取,失败显 — |
| 删除客户 | customer.delete_flag=1(实测 53 行;无时间字段→计数=现存量,时间列显最近 updated) |
| 拉黑客户 | customer.is_block=1(实测 8 行,同上) |
| 语音通话 | phone_call.user_id=员工 AND start_call_time 窗内 |
| 敏感词 | 占位空态「词库未配置,待 C1 敏感词功能接入」 |
5. 各视图细节(对齐云客)
单聊/群聊
- 中列顶部「好友/群 | 聊天记录」下拉双模式 + 搜索框(昵称/wxid 或全量消息关键词)
- 单聊有
聊天好友|已删除好友tab(群聊无)→ sessionsis_del - 置顶区:filehelper 固定置顶 + 可折叠;置顶不参与今日红点
- 会话卡:头像+昵称+
今日N红点+相对时间(今天HH:mm/昨天/今年M月D日/往年全日期) - 右列:默认近 14 天窗(清空=全部)、关键词、类型下拉 10 类、导出按钮(复用
/export/chat-html) - 消息流:加载更多/上一页 + 日期分隔条;点会话切路由 talkerId
- 已删除好友会话照常显示历史消息
朋友圈
- feed 卡片:作者头像+名 → 内容 → 九宫格图片(点击预览)→ 时间 → 点赞人列表
- 滚动翻页;空态提示先跑 moments 抓取;缺图占位框
通讯录
微信客户|微信群tab + 搜索(昵称/微信号/备注/手机号)- 客户表 7 列:客户微信(头像+昵称+微信号)/数据来源/客户备注名/最近沟通时间/发送条数/接收条数/操作(查看聊天记录+导出HTML聊天记录)
- 微信群 tab:群名/群主/成员数/最近群消息时间/查看群聊
- 复用
/api/customers、/api/groups(owner 过滤已支持)
统计分析
- 7 tab 带计数徽标,默认近 7 天窗
- 明细 4 列:客户微信(可点→聊天)/客户备注/员工微信/时间
- 敏感词空态占位
6. 错误处理
- 每视图独立 loading/error(
el-alert),互不影响 - 翻页失败→显示已加载+重试;图片失效→占位框;缺字段→
— - 统计某类无数据→空表格+计数 0;非法 tab→重定向 single
- 与现有页面一致的后端未起/超时错误条
7. 测试
- 后端 pytest:
test_api_moments.py(分页/排序/空库)、test_api_staff_stats.py(7 类口径+窗口边界+add_time 兜底+红包判定)、sessions 增补(is_del/置顶)、accounts 增补(avatar)、scraper 归一化单测(fixture=真机 JSON) - 前端 vitest:路由跳转、tab 切换、相对时间格式化
- 验收:本地前后端 + Playwright 走查 5 视图,与云客真机对比
8. 实施顺序
- 后端:表+scraper → API(accounts/sessions/messages 改动,moments/staff-stats 新增)
- 前端骨架:路由+左栏+单聊视图
- 群聊/通讯录/统计分析视图
- 朋友圈视图
- 入口改造 + 走查 + 提交