Commit Graph

11 Commits

Author SHA1 Message Date
浅念 80b721b84f fix(groups): 字节序排序按方言——MySQL CAST AS BINARY / SQLite COLLATE BINARY
collate("BINARY") 被 SQLAlchemy 反引号成标识符致 MySQL 500;SQLite 的
CAST AS BINARY 语义不符(排序键失效退化 room_id 序,测试失去判别力)。
按 session.bind.dialect 分支,两库都用真字节序。

726 测试绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:37:07 +08:00
浅念 acd6997bf0 fix(groups): 排序终判——owner 二进制字符串序(云客逐位吻合),弃 list_order
上版按 list_order 排不对:云客员工列表序 ≠ 群统计页员工序。真机对照
切换点员工终判:群统计员工顺序 = owner(微信号/wxid 混存)的**区分大小写
二进制字符串升序**(Nancyjade < csf7169708 < wxid_01gv…,大写在小写前,
逐位吻合),组内 room_id 字符串升序。COLLATE BINARY 双库通用,且无需
JOIN wechat_account。

726 测试绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:23:43 +08:00
浅念 253be99eca fix(groups): 微信群排序复刻云客+群详情去掉重复的「成员列表」字段
用户报:①群详情有成员墙后「成员列表」原始串字段重复;②排序与云客不一致。

- 排序:云客「微信群统计」真机判别=员工分组(云客员工列表序)+
  组内 chatRoomId 字符串升序——/api/groups 微信路径改 JOIN
  wechat_account 按 list_order(NULL 垫底按 owner asc)+room_id asc;
  WA 保持最近活跃优先
- 群详情:memberIds 从「其他字段」兜底区排除(成员墙已替代,不再
  以原始 wxid 串重复出现)

726 测试绿(默认排序断言更新为员工分组序)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:11:13 +08:00
浅念 b0ebe8a15a feat(group-stats): 微信群列表对齐云客「微信群统计」——getChatroomList 数据源+窗内统计
用户报微信群列表数据/内容不对,应对齐云客「沟通→微信号管理→微信群统计」
(/cms/wechat/wechatgroup)。真机探明(表单登录+页面导航抓 network):

- 数据源=POST /wechatweb/chatroom/getChatroomList(form:departmentId+
  startTime/endTime 窗+分页;信封 data.overviews[]/totalCount 1,854 行)
- 云客窗是任意时间窗实时算:沟通消息数实测同群全史 417/7天 36/单日 6
- **修正存量映射错误**:member_count 原存 friendNum(员工好友数),真群成员
  数是 friendCount/getChatroomList.memberCount
- 新增/退出成员数云客按窗实时算,本地无事件流 → 按天积累

实现:
- ChatGroup 补 group_remark 列(备注仅 friend_list/es 携带,两归一化均
  「有值才写」防互清);迁移含存量 raw_json 回填(须先于基线抓取执行)
- 新表 chat_group_member_stats(渠道×账号×群×天一行 added/lost)
- 新实体 chatroom-stats:全窗刷档案列(真成员数/群备注/员工信息,owner
  经 wechat_account alias 解析)+ --day 单日窗落进出日行;full_sync 5c 步
- /api/groups 扩展:msg_start/msg_end 窗内聚合(window_msg_count=
  msg_daily_stats 按天和、window_added/lost=日表和)、last_start/end
  最新消息窗、group_remark 子串;行补员工微信/员工信息关联列
- GroupList 微信 tab:统计时段(默认近7天)/最新消息时间段/群名称/群备注/
  员工下拉/查询 + 9 列(群信息|群备注|员工微信|员工信息|群成员数量|
  新增成员数|退出成员数|沟通消息数|操作);WA tab 不动

700 测试绿(新增窗聚合/筛选/员工列 3 例)。本地实测:基线 1,854 群=云客
total 一字不差,今日日窗 added 407/lost 166 落表,页面 9 列/员工列渲染正常。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-09 18:09:20 +08:00
浅念 35bfebd3e3 chore(backend): list_order迁移补齐+Task14类型修正落链+moments每页日志+MsgTypeParam派生+3处文档修正+Dockerfile打包migrations+DEPLOY补迁移步骤
- 9b0d0c133035: wechat_account.list_order 进迁移链(此前仅模型声明,
  干净库 /api/accounts 即 500);sa.inspect 幂等守卫兼容已手动加列的
  smoke.db
- fe63c6789e94(验证中发现的预存缺口,超出原清单): Task 14 的 5 列模型
  类型修正(4×URL String(1024)→Text, db_size Integer→BigInteger)从未落
  链——纯 alembic 新库会复活 >1KB 链接截断;对齐后干净库 alembic check
  全绿。SQLite message 表 batch 重建会掉 FTS 触发器+rowid 脱节(docstring
  记明 ensure_fts+rebuild_fts 修复,smoke.db 已修复验证)
- scrape_via_page: _iter_moments_pages 每页一行进度日志(镜像 _fetch_pages)
- messages: MsgTypeParam=Literal[tuple(_MSG_TYPE_FILTER)] 派生,杜绝
  双处罗列漂移(openapi enum 验证一致,492 绿含 422 行为)
- 文档: ChatGroup 复合PK docstring/groups room_id 多行表述/测试名去
  单行假设;Dockerfile 补 alembic.ini+migrations;DEPLOY 增「数据库
  迁移」节(新库/旧库stamp路径/回填脚本显式DB_URL)+运维表升级行

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 20:32:25 +08:00
浅念 1b66be6a53 feat(api): /api/customers 加 q 文本搜索(昵称/备注/ID/手机号,LIKE转义) + /api/groups 加 q 群名搜索
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 18:55:53 +08:00
浅念 6c9245a682 fix(groups): /api/groups加room_id精确直查(群聊页群名解析,修page_size=200超限422)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-20 10:58:39 +08:00
浅念 2d1943a74e fix(api): 客户/群排序改回last_chat_time DESC(云客按最近沟通优先)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-15 14:18:42 +08:00
浅念 854da6e566 fix(api): 客户/群列表排序改为friend_id/room_id ASC(对齐云客API自然顺序)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-15 14:14:24 +08:00
浅念 dfdd0595d2 feat(staff): action buttons → filtered customer/group list
Adds groups.user_id filter; viewCustomers/viewGroups push owner_account_id query; CustomerList/GroupList read it.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 19:06:27 +08:00
浅念 ff7e9cb1d9 feat: backend read api for all entities (messages/groups/calls/sms/org/sync)
Adds the read-only API surface the upcoming Vue frontend needs to browse all
mirrored entities. Follows the existing customer-router pattern: Annotated
deps, Page[T] envelope, select+where+order_by, count() for total.

Endpoints (all GET):
* /api/departments          -> list[DepartmentOut] (path-ordered, plain list)
* /api/staff                -> Page[StaffOut] (department_id, is_on_job filters)
* /api/accounts             -> Page[AccountOut] (channel filter; unified
                             wechat+whatsapp projection built in memory)
* /api/messages             -> Page[MessageOut] (channel/owner/talker/room/
                             [start,end] filters; ordered timestamp asc)
* /api/groups               -> Page[GroupOut] (channel/owner filters)
* /api/groups/{id}/members  -> list[GroupMemberOut] (404 on unknown room)
* /api/calls                -> Page[PhoneCallOut] (channel/user/time window;
                             ordered start_call_time desc)
* /api/sms                  -> Page[SmsOut] (user/time window; create_time desc)
* /api/sync/status          -> {states, recent_runs} monitor payload

Schemas (Pydantic v2, from_attributes=True): MessageOut, GroupOut,
GroupMemberOut, PhoneCallOut, SmsOut, DepartmentOut, StaffOut, AccountOut
(unified across two tables), SyncStateOut, SyncRunOut, SyncStatusOut.
Only human-relevant fields per entity are exposed.

Tests: per-router TDD via httpx ASGITransport against an in-memory SQLite
override of get_session. A shared make_client factory in conftest.py builds
the seeded client, deduping the ~40-line fixture across the six new files.
41 new tests cover shape + every documented filter + pagination + ordering
(nulls-last verified on all desc/asc time columns).

Suite: 226 -> 267 passing. ruff check clean.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-01 16:15:40 +08:00