feat(shangwutong): sync classifications and update conversations
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
# 商务通分类同步与会话分类配置实施计划
|
||||
|
||||
> 日期:2026-09-11
|
||||
> 状态:首版实现完成,待真实商务通账号灰度验证
|
||||
> 关联调研:[`docs/research/2026-09-11-shangwutong-pc-classification-protocol.md`](../research/2026-09-11-shangwutong-pc-classification-protocol.md)
|
||||
|
||||
## 1. 目标与边界
|
||||
|
||||
为每个对接的商务通账号提供:
|
||||
|
||||
1. 从商务通读取对话分类和客户颜色分类定义;
|
||||
2. 在对应收件箱提供“同步商务通分类”按钮;
|
||||
3. 在商务通会话右侧客户信息中提供两个独立下拉框;
|
||||
4. 修改后通过 Connector 下发到商务通;
|
||||
5. GoChat 不预设、创建、编辑或删除商务通分类定义。
|
||||
|
||||
明确不做:
|
||||
|
||||
- 不把商务通分类写入 GoChat 原生标签定义表;
|
||||
- 不把商务通颜色分类映射为 CRM `CategoryInFo`、`ClientLabelConfig`;
|
||||
- 不为未同步的收件箱生成默认分类;
|
||||
- 不在浏览器直接持有或调用商务通凭据。
|
||||
|
||||
## 2. 已确认的商务通协议
|
||||
|
||||
### 2.1 分类定义
|
||||
|
||||
```text
|
||||
POST {serverurl}/oc/SiteSetting.aspx?sn={sn}&siteid={siteid}&act=load
|
||||
```
|
||||
|
||||
对话分类:
|
||||
|
||||
```text
|
||||
sidkind_share = id,txt,iconindex|id,txt,iconindex|...
|
||||
```
|
||||
|
||||
客户颜色分类:
|
||||
|
||||
```text
|
||||
colorkind0_share = id|id|...
|
||||
colorkind1_share = name|name|...
|
||||
```
|
||||
|
||||
保存/同步请求返回 `r=ok` 或 `r=load ok`。GoChat 只读取定义,不调用保存配置接口。
|
||||
|
||||
### 2.2 会话分类修改
|
||||
|
||||
对话分类:
|
||||
|
||||
```text
|
||||
POST {serverurl}/oc/SetSidKind.aspx
|
||||
sid, oname, siteid, kind
|
||||
```
|
||||
|
||||
客户颜色分类:
|
||||
|
||||
```text
|
||||
POST {serverurl}/oc/changecolor.aspx
|
||||
sid, oname, siteid, c0, c1, cid
|
||||
```
|
||||
|
||||
清除颜色分类的 `RESET` 语义暂不作为首版 UI 能力暴露。
|
||||
|
||||
## 3. 总体架构决定
|
||||
|
||||
采用“GoChat 按收件箱持久化远程分类缓存”的方案:
|
||||
|
||||
```text
|
||||
前端收件箱同步按钮
|
||||
-> GoChat 管理 API
|
||||
-> 已签名的 GoChat -> Connector webhook 控制事件
|
||||
-> Connector 使用账号会话读取商务通
|
||||
-> Connector 回调 GoChat
|
||||
-> GoChat 按 inbox_id 更新缓存
|
||||
-> 前端刷新列表
|
||||
```
|
||||
|
||||
会话修改采用现有 Connector 出站操作队列:
|
||||
|
||||
```text
|
||||
前端下拉修改
|
||||
-> GoChat 校验 inbox/conversation/sid/cid
|
||||
-> 持久化 outbound operation
|
||||
-> Connector 读取 operation
|
||||
-> 调用 SetSidKind.aspx 或 changecolor.aspx
|
||||
-> 回传结果
|
||||
-> GoChat 更新会话分类确认状态
|
||||
```
|
||||
|
||||
分类缓存按 `inbox_id` 隔离。同步失败保留旧缓存,并返回可展示的错误状态。
|
||||
|
||||
## 4. 分步实施清单
|
||||
|
||||
### 阶段 1:协议值对象与 Connector 商务通客户端
|
||||
|
||||
- [x] 增加对话分类、客户颜色分类值对象;
|
||||
- [x] 实现 `SiteSetting.aspx` 读取和严格解析;
|
||||
- [x] 实现 `SetSidKind.aspx`;
|
||||
- [x] 实现 `changecolor.aspx`;
|
||||
- [x] 保留已有认证、超时、响应状态和不确定结果处理;
|
||||
- [x] 为分隔符、空值、重复 ID、平行数组长度不一致增加测试。
|
||||
|
||||
阶段验证:`cd channels/shangwutong && go test ./internal/swt`
|
||||
|
||||
### 阶段 2:GoChat 分类缓存与 Connector 回调
|
||||
|
||||
- [x] 新增按 `inbox_id` 唯一的分类缓存模型及迁移;
|
||||
- [x] 保存对话分类、客户颜色分类、同步时间、同步状态和最后错误;
|
||||
- [x] 增加管理员读取分类缓存 API;
|
||||
- [x] 增加管理员触发同步 API;
|
||||
- [x] 增加 Connector 结果回调 API,验证账号、收件箱和幂等键;
|
||||
- [x] 扩展已签名 webhook 事件 `classification_sync_requested`;
|
||||
- [x] Connector 完成远程读取后回调 GoChat;
|
||||
- [x] 失败时不覆盖上一次成功缓存。
|
||||
|
||||
### 阶段 3:会话分类出站操作
|
||||
|
||||
- [x] 扩展 GoChat 会话分类 API;
|
||||
- [x] 校验会话属于商务通收件箱;
|
||||
- [x] 从会话/联系人渠道元数据取得 `sid` 和 `cid`;
|
||||
- [x] 将 `set_chat_kind`、`set_customer_color` 写入现有出站队列;
|
||||
- [x] Connector 出站 worker 调用对应商务通接口;
|
||||
- [x] 增加操作结果回调和幂等处理;
|
||||
- [x] 只有商务通确认成功后更新确认值,失败/不确定保留状态并提示。
|
||||
|
||||
### 阶段 4:前端收件箱设置
|
||||
|
||||
- [x] 在商务通收件箱设置中增加“同步商务通分类”按钮;
|
||||
- [x] 展示对话分类和客户分类同步结果;
|
||||
- [x] 同步中禁用按钮;
|
||||
- [x] 同步失败保留旧列表;
|
||||
- [x] 不提供分类新增、编辑、删除控件。
|
||||
|
||||
### 阶段 5:前端会话右侧客户信息
|
||||
|
||||
- [x] 仅商务通会话显示“商务通分类”区块;
|
||||
- [x] 增加对话分类下拉;
|
||||
- [x] 增加客户分类下拉;
|
||||
- [x] 未同步、失效或缺少 `cid` 时安全禁用;
|
||||
- [x] 提交中禁用对应控件;
|
||||
- [x] 根据远程确认结果更新或恢复值(轮询会话确认属性,超时显示处理中);
|
||||
- [x] 不复用 GoChat 原生标签组件。
|
||||
|
||||
### 阶段 6:验证与文档
|
||||
|
||||
- [x] Go 单元测试与全模块编译;
|
||||
- [x] SQLite migration/build/test(迁移已通过最小 SQLite 外键/建表冒烟验证);
|
||||
- [x] 前端 production build;
|
||||
- [x] Connector 协议 mock 测试;
|
||||
- [x] 更新调研文档中的实现状态;
|
||||
- [x] 检查无凭据泄漏、跨 inbox 读取和跨账号分类串用。
|
||||
|
||||
## 5. API 草案
|
||||
|
||||
### 5.1 读取缓存
|
||||
|
||||
```http
|
||||
GET /api/v1/accounts/:account_id/inboxes/:inbox_id/shangwutong/classifications
|
||||
```
|
||||
|
||||
### 5.2 触发同步
|
||||
|
||||
```http
|
||||
POST /api/v1/accounts/:account_id/inboxes/:inbox_id/shangwutong/classifications/sync
|
||||
```
|
||||
|
||||
### 5.3 修改会话分类
|
||||
|
||||
```http
|
||||
PATCH /api/v1/accounts/:account_id/conversations/:conversation_id/shangwutong-classifications
|
||||
```
|
||||
|
||||
请求体只允许一个修改目标:
|
||||
|
||||
```json
|
||||
{"chat_kind_id": 2}
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```json
|
||||
{"customer_color_id": 1}
|
||||
```
|
||||
|
||||
### 5.4 Connector 回调
|
||||
|
||||
Connector 专用回调不暴露给普通前端用户,沿用 Connector 平台鉴权和收件箱授权边界。
|
||||
|
||||
## 6. 数据模型草案
|
||||
|
||||
分类定义不是 GoChat 原生标签,建议独立表:
|
||||
|
||||
```text
|
||||
shangwutong_classification_caches
|
||||
- inbox_id unique
|
||||
- conversation_kinds JSON
|
||||
- customer_color_kinds JSON
|
||||
- sync_status pending/succeeded/failed
|
||||
- synced_at nullable
|
||||
- last_error_code nullable
|
||||
- last_error_message nullable
|
||||
- created_at
|
||||
- updated_at
|
||||
```
|
||||
|
||||
分类值只保留商务通远程 ID、名称及图标索引;不生成 GoChat `Tag` 记录。
|
||||
|
||||
## 7. 验收标准
|
||||
|
||||
- 不同步的商务通收件箱不显示伪造分类;
|
||||
- 同步成功后两个列表均可按收件箱读取;
|
||||
- 同步失败不会清空上一次成功结果;
|
||||
- 会话右侧只对商务通显示两个独立下拉;
|
||||
- 选择对话分类最终请求 `SetSidKind.aspx` 的 `kind`;
|
||||
- 选择客户分类最终请求 `changecolor.aspx` 的 `c0/c1/cid`;
|
||||
- `CategoryID`、`LabelID` 不参与上述实时会话接口;
|
||||
- 重复点击和重试不会产生冲突修改;
|
||||
- 远程失败或不确定时 UI 不显示虚假的成功状态;
|
||||
- 不同商务通收件箱的分类 ID 不互相串用。
|
||||
|
||||
## 8. 风险与暂缓项
|
||||
|
||||
1. 商务通 PC 端分类读取响应存在旧式字符串协议,必须拒绝坏格式,不应静默错配两个颜色数组;
|
||||
2. `cid` 是客户级标识,客户颜色修改的跨会话作用范围需灰度账号验证;
|
||||
3. Connector 到 GoChat 的同步回调必须使用幂等键,避免 webhook 重试覆盖更新状态;
|
||||
4. 首版不暴露清除客户分类按钮,待 `RESET` 完整协议验证后再增加;
|
||||
5. 分类定义同步和会话分类修改必须分开建模,不能以“同步成功”代替“会话修改成功”。
|
||||
|
||||
## 9. 首版实现记录
|
||||
|
||||
已落地的主要文件:
|
||||
|
||||
- Connector 协议:`channels/shangwutong/internal/swt/classifications.go`;
|
||||
- Connector 回调客户端:`channels/shangwutong/internal/gochat/classifications.go`;
|
||||
- Connector 会话操作:`channels/shangwutong/internal/delivery/outbound.go`;
|
||||
- Connector webhook 分发:`channels/shangwutong/internal/httpapi/server.go`;
|
||||
- GoChat 缓存模型与迁移:`backend/internal/model/channel_shangwutong_classification_cache.go`、`backend/migrations/000087_*`;
|
||||
- GoChat API 与任务:`backend/internal/handler/api/v1/shangwutong_connector_handler.go`、`backend/internal/service/shangwutong_webhook_delivery.go`;
|
||||
- 前端同步按钮:`frontend/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/ShangwutongConfiguration.vue`;
|
||||
- 前端会话下拉:`frontend/app/javascript/dashboard/routes/dashboard/conversation/ShangwutongClassifications.vue`。
|
||||
|
||||
验证结果:
|
||||
|
||||
```text
|
||||
cd channels/shangwutong && go test ./... && go vet ./...
|
||||
cd backend && GOCHAT_TEST_DB=sqlite go test ./...
|
||||
cd frontend && pnpm build
|
||||
```
|
||||
|
||||
均已通过。前端修改文件的 ESLint 无错误;现有设置组件保留一条既有的动态 i18n key warning。真实商务通账号的灰度协议验证仍待安排。
|
||||
Reference in New Issue
Block a user