调整客服自动接待和手动排队规则
This commit is contained in:
@@ -31,6 +31,7 @@ PowerShell 下把目录和 `-g '*.py'` 分开传给 `rg`。报价字典可能整
|
||||
| 订单测试表 | `logistics_chat/order_data.py`:`init_order_table`、`import_records`、`lookup_order`、`answer_query` | SQLite `order_test_data` 为可编辑快照;按订单号、入仓码、Shipment ID 精确查表。将来 MCP 在取数层替换 `lookup_order`,不让模型拼 SQL |
|
||||
| AI 与 SSE | `logistics_chat/chat_service.py`:`create_chat_stream`、`sse`;`ai_client.py`:`post_completion`、`compress_answer`、`gen_followups` | `routes/chat.py`:`stream_chat`;客户端 `doSend`、`renderError`、`renderFollowups` |
|
||||
| 人工会话 | `logistics_chat/human_service.py`:`human_*`(含转接、备注、撤回);对应 `routes/human.py` | 输入状态在 `app.extensions['human_typing']`;客户 `startHumanPoll`;客服 `loadQueue`、`poll`、`sendReply`;人工申请每天 8:00–22:00 |
|
||||
| 客服分组与分配 | `logistics_chat/routing_service.py`:`assign_new_session`、`update_presence`、`reassign_session`;`routes/routing.py` | `static/js/admin_routing.js`;版本 5;默认综合客服,手动上线,20 秒心跳与 90 秒在线期限,空闲时自动接一个新客户、队列手动领取、原子领取与改派记录;[使用说明](staff-routing.md) |
|
||||
| 附件 | `logistics_chat/file_service.py`:`upload_file`、`cleanup_uploads`;`routes/files.py`:`uploaded_file` | 扩展名/大小/目录由配置提供;客户端 `addMsg`,客服端 `appendMsg` |
|
||||
| 登录、统计、订单、留言、导出 | `logistics_chat/business_service.py`:`admin_login`、`admin_stats`、`my_orders`、`add_ticket`、`list_tickets`、`export_chat` | `routes/admin.py`、`routes/business.py`;登录页 `static/js/admin_login.js` |
|
||||
| 离线留言处理 | `logistics_chat/ticket_service.py`:`init_ticket_tables`、`init_ticket_history`、`get_ticket`、`list_tickets`、`claim_ticket`、`update_ticket`、`ticket_events` | `routes/business.py`;`static/js/admin_tickets.js`:`AdminTickets.create`;`tickets` 负责人、乐观锁与领取计时,`ticket_events` 同事务处理记录,迁移版本 3 |
|
||||
@@ -100,6 +101,7 @@ tests/ # 按业务模块组织的回归
|
||||
- 客户页 `resetConversation` 统一处理新建、快捷问题和历史切换;人工路由同时绑定 `humanConvId` 与当前会话版本。旧建会话、历史、人工申请和轮询的异步结果不得覆盖新话题。三个业务快捷入口开启独立 AI 对话,联系人工入口才进入人工模式;排队/接待状态常驻输入框上方,可用「返回 AI 问答」结束人工会话。人工消息确认成功后才清空草稿,失败保留输入;服务端校验可选 `conv_id` 并拒绝已关闭会话。
|
||||
- 客服工作台默认只展示会话列表和全高聊天区;统计使用原生 `details` 收在「数据概览」。`setSessionTab` 切换接待/排队列表,`setChatView` 与 `showSessionList` 控制 720px 及以下的整屏导航,不结束当前会话。`setToolsOpen` 控制默认关闭的服务资料:1200px 以上为侧栏,较窄屏为抽屉;列表入口让未选会话的手机用户也能查看留言。
|
||||
- 人工排队接口按服务端北京时间计算 `waiting_minutes`,等候超过 5 分钟返回超时状态和超时分钟数。`loadQueue` 对每条会话仅在首次进入超时时通知一次,队列计数常驻标签,卡片标红;离开超时队列后清除去重状态。
|
||||
- 人工会话持久化分组和负责人;仅在新会话创建时自动分配,选择有效登录且心跳有效、当前无活动会话的同组在线客服,依次比较上次分配时间与账号。每位客服自动接待一个进行中的客户,手动领取和指定负责人改派可多接;已排队或转回队列的会话始终等待手动接入。分配/领取/改派/记录在同一写事务内完成。后台活动列表仅返回本人负责会话;无负责人的旧活动会话在队列中供人工领取。改派版本与前端异步代次分别防止并发覆盖和迟到响应覆盖;旧负责人草稿保留在当前页面恢复区。分组管理沿用同级客服权限,不能代替客户租户授权;所有新接口默认受后台会话与 CSRF 保护。
|
||||
- 离线留言的 `admin_tickets.js` 在 `admin.js` 之前加载,由后者注入带超时、CSRF 和登录失效处理的请求函数。后台按当前登录账号领取,领取原子比较待处理状态;仅负责人可更新处理中留言,版本冲突返回 409,已完成只读。页面草稿按留言 ID 和原始版本保留,轮询不会隐式重置草稿版本;冲突须人工核对。客户提交接口不接受负责人或处理状态,不能访问后台处理接口。
|
||||
- 留言搜索由 `ticket_service.list_tickets(query=...)` 统一叠加状态及游标条件,LIKE 参数转义通配符;列表继续返回数组。`ticket_summary(after)` 单独提供不受筛选影响的总待处理数量与新增数量,使用状态索引和主键范围查询。`refreshSummary` 与列表轮询独立,不因查看旧页、搜索或写请求停止;首次结果作为提醒基线,之后只提醒超过已见编号的新记录。
|
||||
- 留言超时由服务端按待领取 30 分钟、领取后处理 20 分钟计算,备注修改不重置 `claimed_at`;列表 `overdue=1` 与全局 summary 使用一致截止时间,完成记录不计入。处理事件与操作同事务保存,只有后台可读,以事件 ID 分页;前端独立加载记录并隔离迟到响应。旧数据只保留升级状态,领取时间估算有显式标识。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 数据库升级、备份与恢复
|
||||
|
||||
普通启动会先在写锁保护下检查数据库版本。已有数据库先生成 `pre-migration-时间-随机值.db` 并执行 SQLite 完整性检查,再按 `MIGRATIONS` 的版本顺序升级;`schema_meta.schema_version` 记录成功版本。当前版本为 3;版本 2 为离线留言增加负责人、处理备注、更新时间、完成时间和并发版本号,版本 3 增加领取时间及处理记录表,既有留言和客服账号保留。旧留言只生成一条升级状态快照,不补造历史;原处理中留言以有效的最后更新时间估算领取时间并标记,无法估算时保留为空。保留既有旧表兼容检查,因此同版本启动也会先保存快照再校验表结构。更新和版本号提交位于同一事务,失败回滚并终止启动;备份失败不执行升级,未来版本的数据库拒绝降级。首次空库无需升级前快照。
|
||||
普通启动会先在写锁保护下检查数据库版本。已有数据库先生成 `pre-migration-时间-随机值.db` 并执行 SQLite 完整性检查,再按 `MIGRATIONS` 的版本顺序升级;`schema_meta.schema_version` 记录成功版本。当前版本为 5;版本 2 为离线留言增加负责人、处理备注、更新时间、完成时间和并发版本号,版本 3 增加领取时间及处理记录表,版本 4 增加订单导入批次及撤销记录,版本 5 增加客服分组、在线心跳、会话负责人及分配记录,既有留言和客服账号保留。旧留言只生成一条升级状态快照,不补造历史;原处理中留言以有效的最后更新时间估算领取时间并标记,无法估算时保留为空。旧人工会话不猜测负责人,无负责人的活动会话可从排队列表手动接入。保留既有旧表兼容检查,因此同版本启动也会先保存快照再校验表结构。更新和版本号提交位于同一事务,失败回滚并终止启动;备份失败不执行升级,未来版本的数据库拒绝降级。首次空库无需升级前快照。
|
||||
|
||||
新增结构变更时,在 `logistics_chat/db.py` 增加顺序迁移函数并递增 `SCHEMA_VERSION`,加入 `MIGRATIONS`;迁移函数必须使用传入连接,不得自行提交、使用 `executescript` 隐式提交或执行外部副作用。补充旧库升级、失败回滚和重复启动测试。
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# 客服分组与会话分配
|
||||
|
||||
客服登录后台后默认离线,在左侧「上线接待」手动开启自动分配;刷新页面保留当前登录会话已确认的状态。切换离线停止接收新会话,已接待的会话仍由原负责人处理。页面每 20 秒发送心跳,超过 90 秒无有效心跳,或登录过期、退出后,不再参与新分配;心跳恢复不会把已超时的客服自动上线,需要手动确认。
|
||||
|
||||
「客服分组与分配」打开服务资料中的配置区,可以创建分组、把已有客服加入某一组、查看在线状态及当前会话数。新咨询默认进入「综合客服」;目前不根据客户文字猜测业务组,客服可将会话改派至其他组。每个客服只属于一个组;改组不搬移已经接待的会话。新建客服账号沿用现有开户工具,本功能不创建账号或修改密码。
|
||||
|
||||
新人工咨询创建时只尝试一次自动分配:仅选择同组在线且当前没有活动会话的客服,先比较上次分配时间,再按账号名稳定排序。在线状态同时要求有效的后台登录会话。每位客服有一个进行中的客户后,不再自动接入新客户;手动领取和明确指定负责人的改派允许同时多接。没有合适客服时进入队列,保留现有五分钟排队超时提醒。已排队的客户始终等待手动接入;客服结束会话、上线、心跳、改组、刷新或客户重复申请均不会自动领取旧队列。客服再次空闲后仍可自动接入随后到来的新客户。
|
||||
|
||||
人工「接入会话」仍可手动领取未分配会话,在线状态仅控制自动分配。领取、自动分配和改派均在 SQLite 写事务中确认,竞争领取只有一人成功。只有会话负责人可发送、修改备注、撤回、转接或标记已读;待接入会话可由后台结束,客户仍可结束自己的会话。旧版无负责人的活动会话显示在排队列表供人工领取,不猜测历史负责人。
|
||||
|
||||
后台「管理分组与改派」选择会话、目标组及负责人;负责人只能选择目标组内的在线客服。未指定负责人时只转入目标组队列,等待手动接入。改派使用独立版本号,信息已改变时返回 409,需要重新选择会话确认,后台刷新不会偷偷更新正在编辑的版本。普通「转接」也回到队列,等待客服手动接入。
|
||||
|
||||
改派后旧负责人不能继续回复。当前页面检测到改派会移除旧接待入口,并在服务资料的「改派后保留的未发送草稿」中保留文字和备注,供复制;这些草稿只在当前页面内存中保存,刷新或退出不保留,也不会发给新负责人。
|
||||
|
||||
自动分配、领取、改派、转回队列和结束会话都与业务操作同事务写入 `routing_events`,记录操作者、分组、负责人及北京时间;后台展示最近 50 条,数据库保留全部记录。客户轮询不返回内部备注、客服账号或分配记录。当前后台沿用所有客服同级管理的权限模型,分组用于业务分派,不作为客户租户数据授权;管理层级及主管专属权限不在本次范围内。
|
||||
|
||||
数据库版本 5 新增 `support_groups`、`staff_routing`、`staff_presence`、`routing_events` 及 `human_sessions` 的分组、负责人、领取时间、版本号和上一负责人字段。`agents` 原有三列不变,兼容旧账号结构。正常启动时沿用升级前快照、完整性检查和事务迁移;本次不修改真实账号、订单或留言内容。
|
||||
|
||||
服务端实现:`logistics_chat/routing_service.py`、`routes/routing.py` 与 `human_service.py`。页面控制:`static/js/admin_routing.js`,由 `admin.js` 注入统一超时、CSRF 和登录失效处理,退出时统一停止心跳。
|
||||
|
||||
验证:`python -m unittest discover -s tests -p test_staff_routing.py -v`;前端运行 `node --test tests/frontend/admin.test.cjs tests/frontend/admin_routing.test.cjs`。所有客服测试通过真实登录接口获取会话和 CSRF,使用独立临时数据库。
|
||||
Reference in New Issue
Block a user