diff --git a/docs/superpowers/plans/2026-08-25-yunke-staff-chat-window.md b/docs/superpowers/plans/2026-08-25-yunke-staff-chat-window.md index 320eda1..62757fa 100644 --- a/docs/superpowers/plans/2026-08-25-yunke-staff-chat-window.md +++ b/docs/superpowers/plans/2026-08-25-yunke-staff-chat-window.md @@ -220,6 +220,12 @@ Run: `.venv/Scripts/python.exe -m pytest tests/test_scrape_moments.py -v` → PA - [ ] **Step 7: full_sync_all.sh 加步**(media 步前):`echo "== moments ==" && python scripts/scrape_via_page.py --entity moments || true`(沿用脚本内既有步骤格式) +- [ ] **Step 7b: 调度接入 + 图片本地化**(spec §4.2 两项) + - 调度:`app/sync/scheduler.py` 的 4h job 是子进程跑 `--entity messages`——在该 job 的子进程序列**追加一次** `--entity moments --max-pages 3`(浅扫第一页有新才继续,朋友圈更新频率低);镜像现有 `_page_subprocess` 调用模式,勿新增 job + - 图片:`moments_post.image_urls` 是 OSS 直链(`wx.oss.yunkecn.com/friendstr/...`)。在 `scrape_media` 的媒体发现段加一个 moments 源(SELECT 未处理的 moments 行,image_urls 灌入 media 表,复用 message 图片的 URL 型下载路径);若 media 表按 `(kind, source_id)` 去重,kind 用 `moments_image`。执行时先读 `scrape_via_page.py:1838` 的 scrape_media 结构再动笔 + +- [ ] **Step 7c: 上面两处各加最小测试**(scheduler 若为纯配置列表则断言 moments 在序列;media 源加一行 fixtures 用例断言 URL 入 media 表) + - [ ] **Step 8: Commit** ```bash @@ -279,7 +285,7 @@ async def test_groups_owner_fields(make_client): - [ ] **Step 5: 回填脚本** `scripts/backfill_chat_group_fields.py`——镜像 `backfill_customer_add_time.py` 模式:SELECT 全部群,`raw_json` 缺列则提取 UPDATE;幂等;末尾打印 `backfilled N/M rows` -- [ ] **Step 6: schemas.py `GroupOut` 加 6 字段 + groups.py 路由输出**(该路由是显式构建 dict 的模式——找到构建处加键即可) +- [ ] **Step 6: schemas.py `GroupOut` 加 6 字段**——groups.py 用的是 `GroupOut.model_validate(row, from_attributes=True)`(groups.py:75 模式),**只需在 schema 加字段即可自动输出**,路由无需改 - [ ] **Step 7: 跑测试 + 回填存量** @@ -887,7 +893,9 @@ async function runSearch() { - [ ] **Step 1: 实现** -顶部:`微信客户|微信群` el-tabs + 搜索框(客户 tab placeholder 对齐云客「支持微信昵称、微信号、备注名、手机号搜索」→ 调 `/api/customers?q=` 检查现有参数名,若无 q 用 `keyword`——**查 customer.py 现有过滤参数后对齐**;群 tab placeholder「请输入群名称」→ `/api/groups` 的 room_name 过滤,无则前端过滤当前页)+ 按钮 `查询/导出(CSV复用 csvExport.ts 模式)/导出聊天记录(勾选后启用,串行 downloadBlob /export/chat-html)`。 +顶部:`微信客户|微信群` el-tabs + 搜索框 + 按钮 `查询/导出(CSV复用 csvExport.ts 模式)/导出聊天记录(勾选后启用,串行 downloadBlob /export/chat-html)`。 + +**搜索实现前置**:`/api/customers`(customer.py)现状**没有**任何文本搜索参数(只有 channel/department_id/owner_account_id/friend_id/user_id/add_time_since/last_chat_since)。本任务先给 customer.py 加 `q: str | None`(`sa.or_(friend_nickname.like, friend_remark.like, friend_id.like, phone.like)`,几行+1 测试),客户 tab 搜索走它(placeholder 对齐云客「支持微信昵称、微信号、备注名、手机号搜索」);群 tab placeholder「请输入群名称」→ `/api/groups` 无 room_name 参数则前端过滤当前页。 客户表列(对齐云客 7+1):复选框(el-table selection)/客户微信(头像+昵称+friend_id 复用 StaffList 富单元格手法)/数据来源(固定「工作手机」)/客户备注名(friend_remark)/最近沟通时间(last_chat_time)/发送条数(send_num)/接收条数(receive_num)/操作(查看聊天记录→emit 跳 single+talkerId;导出HTML聊天记录→downloadBlob)。 @@ -960,7 +968,7 @@ async function viewChat(row: Account) { // openCustomerChat 同理 wechat 分支 → { name: 'staff-chat', params: { ownerId, tab: 'single', talkerId } } + query 保留 start/end/msgid ``` -- [ ] **Step 2: CustomerList.vue** 微信 tab「查看聊天记录」同样 wechat 分支切 staff-chat(找到现有跳转处,约 line 301 操作列) +- [ ] **Step 2: CustomerList.vue** 微信 tab「查看聊天记录」同样 wechat 分支切 staff-chat(现有跳转在 ~line 252-267 的 viewChat 及其 drawer 包装处,以「查看聊天记录」grep 定位为准) - [ ] **Step 3: 全链路手动/Playwright 走查**(对照云客真机,逐项勾): - 员工列表昵称→新页;资料卡四要素;5 导航切换 URL/内容 - 单聊:置顶区/已删除 tab/双模式搜索/默认窗/类型过滤/导出/msgid 定位