docs(changelog-v2): 站内信升级聊天 P1 — 6 个管理端 1:1 会话接口 (#4020)
这个提交包含在:
父节点
76b2e4cc0b
当前提交
b23de77d92
@ -0,0 +1,197 @@
|
||||
# 站内信升级聊天(1:1 会话)P1 — 6 个管理端接口
|
||||
|
||||
- **变更类型**:新增接口
|
||||
- **端类型**:管理后台
|
||||
- **日期**:2026-06-19
|
||||
- **Issue**:[#4020](https://git.1814.love:8443/wx/HL/issues/4020)
|
||||
- **PR**:[#4028](https://git.1814.love:8443/wx/HL/pulls/4028)(+ hotfix [#4030](https://git.1814.love:8443/wx/HL/pulls/4030) / [#4031](https://git.1814.love:8443/wx/HL/pulls/4031))
|
||||
- **后端负责人**:王骁
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 关键说明(前端务必先读)
|
||||
|
||||
1. **本期 P1 没有实时推送(SSE)**。聊天靠「发消息 + 拉线程 + 轮询未读」的请求/响应模式工作;实时角标冒泡(顶部铃铛实时 +1、打开的会话 live append 新气泡)是 **P2** 再上。P1 阶段前端可用**轮询**(如进入会话时拉线程、定时拉 `unread-total`)先把界面跑起来。
|
||||
2. **能力归属 user-service,复用现有站内信**。聊天行和系统通知行同表(`admin_message`),顶部**合并未读角标**(聊天+通知合计)继续走现有 `GET /admin/message/unread-count`,本次**不变**;本期新增的 `GET /admin/message/chat/unread-total` 只给「聊天 Tab」单独展示聊天未读数。
|
||||
3. **一个订单 × 一对人 = 一个对话框**(不是整单一个群)。会话靠 `conversationKey` 唯一定位,订单 ID 已编入键;订单详情页「围绕这个订单的全部对话」= 调会话列表接口按 `bizModule=HOUSE&bizId=订单ID` 过滤。
|
||||
4. **前端不传 adminId / 姓名**。当前操作人由网关注入的 token 解析;发件人姓名后端快照写入,直接展示。
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景
|
||||
|
||||
房务(定制师↔房务·配房沟通)、车务(车管↔定制师·派车沟通)都需要内部员工之间的 **1:1 实时聊天**。后端把现有「单向系统通知站内信」升级为「通知 + 1:1 聊天」统一消息中心:同一套收件箱 / 未读 / (未来)实时通道,新增「谁发的 + 成线程 + 双向」三要素。
|
||||
|
||||
本期 **P1** 交付 **6 个管理端接口**(admin 后台用),是聊天的核心读写能力。SSE 实时(P2)、跨服务接入与业务列表红点透传(P3 房务 / P4 车务)后续迭代。
|
||||
|
||||
---
|
||||
|
||||
## 2. 变更清单
|
||||
|
||||
| 序号 | 接口 | 说明 | 变更类型 |
|
||||
|------|------|------|----------|
|
||||
| 1 | `POST /admin/message/chat/open` | 打开 / 找回 1:1 会话(幂等) | ✨ 新增接口 |
|
||||
| 2 | `GET /admin/message/chat/conversations` | 我的会话列表(支持按订单聚合) | ✨ 新增接口 |
|
||||
| 3 | `GET /admin/message/chat/{conversationKey}/messages` | 拉线程消息(游标分页) | ✨ 新增接口 |
|
||||
| 4 | `POST /admin/message/chat/{conversationKey}/messages` | 发一条消息 | ✨ 新增接口 |
|
||||
| 5 | `POST /admin/message/chat/{conversationKey}/read` | 标记已读到最新 | ✨ 新增接口 |
|
||||
| 6 | `GET /admin/message/chat/unread-total` | 我的聊天未读总数 | ✨ 新增接口 |
|
||||
|
||||
- **认证**:全部 Bearer JWT(管理后台 Token),经网关 `https://api.test.1814.love:9443`。
|
||||
- **网关路由**:复用现有 `/admin/message/**` 路由,无新增。
|
||||
- **DDL**:`admin_message` 扩 8 列 + 新表 `admin_conversation_member`(前端无感)。
|
||||
- **顶部合并角标**:仍走 `GET /admin/message/unread-count`,本次不变。
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心概念:conversationKey(会话键)
|
||||
|
||||
```
|
||||
conversationKey = {bizModule}:{bizId}:{minAdminId}:{maxAdminId}
|
||||
例: HOUSE:70123:1001:2046065465288949761
|
||||
```
|
||||
|
||||
- `bizModule`:`HOUSE`(房务)/ `FLEET`(车务)/ `DIRECT`(纯私聊,无业务对象)。
|
||||
- `bizId`:业务对象 id(房务=订单ID,车务=派车单/车辆ID);`DIRECT` 时后端按 `0` 处理。
|
||||
- 两人 adminId **小的在前**(后端规范化),保证 A↔B 双向命中**同一会话**,不分叉。
|
||||
- **前端拿到 `conversationKey` 后,作为路径参数透传**(含冒号,直接放进 URL path,无需手动编码也可;若用 encodeURIComponent 编码同样可用)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 接口详情
|
||||
|
||||
### 4.1 `POST /admin/message/chat/open` — 打开 / 找回会话
|
||||
|
||||
幂等:同两人同业务对象重复调用返回**同一个** `conversationKey`(`isNew=false`),不会重复建会话。
|
||||
|
||||
**入参(RequestBody)**
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `bizModule` | String | 是 | `HOUSE` / `FLEET` / `DIRECT` |
|
||||
| `bizId` | String | 否 | 业务对象 id(HOUSE=订单ID;DIRECT 留空) |
|
||||
| `peerAdminId` | String | 是 | 对端员工 adminId(雪花,字符串透传) |
|
||||
|
||||
**出参 `data`**
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `conversationKey` | String | 规范化会话键 |
|
||||
| `peerAdminId` | String | 对方 adminId |
|
||||
| `peerName` | String | 对方姓名快照 |
|
||||
| `peerRole` | String | 对方角色(P1 admin 端开会话暂为 null,P3 业务侧接入后带值) |
|
||||
| `unreadCount` | Integer | 我在该会话的未读数 |
|
||||
| `isNew` | Boolean | true=新建,false=找回已存在 |
|
||||
|
||||
### 4.2 `GET /admin/message/chat/conversations` — 我的会话列表
|
||||
|
||||
| 查询参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `bizModule` | String | 否 | 过滤业务分类,空=全部 |
|
||||
| `bizId` | Long | 否 | 过滤业务对象。**传 `bizModule=HOUSE&bizId=订单ID` 即「围绕这个订单的全部对话」** |
|
||||
| `pageNo` | Integer | 否 | 页码,默认 1 |
|
||||
| `pageSize` | Integer | 否 | 每页,默认 20 |
|
||||
|
||||
返回分页 `data.records[]`,每项:`conversationKey` / `bizModule` / `bizId` / `peerAdminId` / `peerName` / `peerRole` / `unreadCount` / `lastMessagePreview` / `lastMessageAt` / `status`,按 `lastMessageAt` 倒序。
|
||||
|
||||
### 4.3 `GET /admin/message/chat/{conversationKey}/messages` — 拉线程(游标分页)
|
||||
|
||||
| 参数 | 位置 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| `conversationKey` | Path | String | 是 | 会话键 |
|
||||
| `beforeId` | Query | String | 否 | 游标:拉该 messageId 之前的历史(首屏不传=拉最新一页) |
|
||||
| `pageSize` | Query | Integer | 否 | 每页,默认 20 |
|
||||
|
||||
返回 `data`:`conversationKey` / `hasMore` / `nextCursor`(下次 `beforeId`)/ `list[]`。每条消息:`messageId` / `senderAdminId` / `senderName` / `senderRole` / `msgType` / `priority` / `content` / `isMine`(是否我发的,用于左右气泡)/ `sentAt`。列表按时间正序(从旧到新)。
|
||||
|
||||
### 4.4 `POST /admin/message/chat/{conversationKey}/messages` — 发一条
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `content` | String | 是 | 文本内容(≤ 1000 字;命中本地敏感词后端替换为 `*`,不报错) |
|
||||
| `priority` | String | 否 | `NORMAL`(默认)/ `URGENT`(加急;P1 不触发实时强提示,P2 起生效) |
|
||||
| `msgType` | String | 否 | `TEXT`(默认)/ `IMAGE`(content 存图 URL) |
|
||||
|
||||
返回 `data`:`messageId` / `conversationKey` / `sentAt`。**前端不传发件人/收件人**,后端按会话键解析。
|
||||
|
||||
### 4.5 `POST /admin/message/chat/{conversationKey}/read` — 标记已读到最新
|
||||
|
||||
无请求体。把该会话标记为已读到最新:该会话未读清零、已读水位推进、对应站内信行置已读(顶部合并角标相应回落)。返回 `data`:`conversationKey` / `unreadCount`(=0)/ `lastReadMessageId`。
|
||||
|
||||
### 4.6 `GET /admin/message/chat/unread-total` — 我的聊天未读总数
|
||||
|
||||
无参数。返回 `data.chatUnreadTotal`(仅 kind=CHAT 的未读数,供「聊天 Tab」单独展示)。
|
||||
|
||||
> 顶部**合并角标**(聊天+通知)请继续用 `GET /admin/message/unread-count`,本端点不替代它。
|
||||
|
||||
---
|
||||
|
||||
## 5. 错误码
|
||||
|
||||
| 错误码 | 说明 | 触发 |
|
||||
|--------|------|------|
|
||||
| `281002` | 无权访问该会话 | 操作人不是该会话成员(越权) |
|
||||
| `281005` | 不能与自己创建会话 | open 时 peerAdminId == 当前登录人 |
|
||||
| `281010` | 目标员工不存在或已离职 | open 的 peerAdminId 无效 |
|
||||
| `281011` | 消息内容不合法 | content 为空或超 1000 字 |
|
||||
| `281004` | 发送过于频繁,请稍后再试 | 发消息超限流(每人 20 条/分钟) |
|
||||
|
||||
> HTTP 恒 200,业务结果看 `code`(成功 `code=200`、`success=true`)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 典型调用流程(示例)
|
||||
|
||||
```http
|
||||
# 1) 打开会话(房务给订单 70123 的定制师留言)
|
||||
POST /admin/message/chat/open
|
||||
Authorization: Bearer <admin-token>
|
||||
{ "bizModule": "HOUSE", "bizId": "70123", "peerAdminId": "2046065465288949761" }
|
||||
--> data: { "conversationKey": "HOUSE:70123:1001:2046065465288949761", "peerName": "cz", "isNew": true, "unreadCount": 0 }
|
||||
|
||||
# 2) 发消息
|
||||
POST /admin/message/chat/HOUSE:70123:1001:2046065465288949761/messages
|
||||
{ "content": "标间超预算了,客人要不要升一档?", "priority": "NORMAL" }
|
||||
--> data: { "messageId": "2067795811529314306", "sentAt": "2026-06-19 10:25:13" }
|
||||
|
||||
# 3) 拉线程
|
||||
GET /admin/message/chat/HOUSE:70123:1001:2046065465288949761/messages?pageSize=20
|
||||
--> data.list[]: 含双方消息,每条带 senderName / isMine
|
||||
|
||||
# 4) 标记已读
|
||||
POST /admin/message/chat/HOUSE:70123:1001:2046065465288949761/read
|
||||
--> data: { "unreadCount": 0, "lastReadMessageId": "2067795811529314306" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 本期范围与后续
|
||||
|
||||
| 阶段 | 内容 | 状态 |
|
||||
|------|------|------|
|
||||
| **P1(本次)** | 6 个 admin 端点(open / 列表 / 线程 / 发消息 / 已读 / 聊天未读) | ✅ 已上测试服 |
|
||||
| P2 | SSE 实时(角标实时刷 + 打开会话 live append + URGENT 强提示)+ 敏感词词库完善 | ⏳ 待开发 |
|
||||
| P3 | 房务(order-v3)接入:配房页开会话 + 订单列表「未读红点」透传 | ⏳ 待开发 |
|
||||
| P4 | 车务(fleet)接入 | ⏳ 待开发 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 注意事项
|
||||
|
||||
1. **P1 无实时**:前端先用轮询(拉线程 + 定时拉 `unread-total`)做交互;不要等 SSE,SSE 在 P2。
|
||||
2. **会话键透传**:`conversationKey` 含冒号,作为 path 参数直接用即可(encodeURIComponent 也兼容)。
|
||||
3. **雪花 id 用字符串**:`peerAdminId` / `messageId` / `conversationKey` 内嵌的 adminId 均以字符串处理,禁做数值运算(防精度丢失)。
|
||||
4. **顶部角标不变**:继续用 `GET /admin/message/unread-count`(合并聊天+通知);本期 `unread-total` 仅细分聊天数。
|
||||
5. **重复 open 安全**:同两人同对象重复 open 返回同一会话(`isNew=false`),可放心在进入会话时每次调用。
|
||||
|
||||
---
|
||||
|
||||
## 9. 关联 / 联系人
|
||||
|
||||
| 项目 | 链接 |
|
||||
|------|------|
|
||||
| Issue | https://git.1814.love:8443/wx/HL/issues/4020 |
|
||||
| PR(P1) | https://git.1814.love:8443/wx/HL/pulls/4028 |
|
||||
| PR(hotfix bean 名冲突) | https://git.1814.love:8443/wx/HL/pulls/4030 |
|
||||
| PR(hotfix open 幂等语义) | https://git.1814.love:8443/wx/HL/pulls/4031 |
|
||||
| 后端负责人 | 王骁 |
|
||||
正在加载...
x
在新工单中引用
屏蔽一个用户