hl-api-changelog/changelogs-v2/2026-06/19_4020_站内信升级聊天P1-1对1会话6个管理端接口-新增接口-管理后台.md

13 KiB

站内信升级聊天1:1 会话P1 — 6 个管理端接口

  • 变更类型:新增接口
  • 端类型:管理后台
  • 日期2026-06-19
  • Issue#4020
  • PR#4028+ hotfix #4030 / #4031
  • 后端负责人:王骁

🛑 前端暂不需要接入2026-06-19 更新,最高优先级)

本次仅「后端 P1」就绪,前端聊天 UI 集成暂缓——收到本文先不用动工。 本文档是后端接口的提前留档/参考不是开工通知;待产品排期、正式通知前端接入时再据此对接。下方接口说明仅供后端联调与未来参考。


⚠️ 关键说明(前端正式接入时再读)

  1. 本期 P1 没有实时推送SSE。聊天靠「发消息 + 拉线程 + 轮询未读」的请求/响应模式工作;实时角标冒泡(顶部铃铛实时 +1、打开的会话 live append 新气泡)是 P2 再上。前端正式接入时可用轮询(如进入会话时拉线程、定时拉 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/** 路由,无新增。
  • DDLadmin_message 扩 8 列 + 新表 admin_conversation_member(前端无感)。
  • 顶部合并角标:仍走 GET /admin/message/unread-count,本次不变。

3. 核心概念conversationKey会话键

conversationKey = {bizModule}:{bizId}:{minAdminId}:{maxAdminId}
例: HOUSE:70123:1001:2046065465288949761
  • bizModuleHOUSE(房务)/ FLEET(车务)/ DIRECT(纯私聊,无业务对象)。
  • bizId:业务对象 id房务=订单ID,车务=派车单/车辆IDDIRECT 时后端按 0 处理。
  • 两人 adminId 小的在前(后端规范化),保证 A↔B 双向命中同一会话,不分叉。
  • 前端拿到 conversationKey 后,作为路径参数透传(含冒号,直接放进 URL path,无需手动编码也可;若用 encodeURIComponent 编码同样可用)。

4. 接口详情

4.1 POST /admin/message/chat/open — 打开 / 找回会话

幂等:同两人同业务对象重复调用返回同一个 conversationKeyisNew=false),不会重复建会话。

入参RequestBody

字段 类型 必填 说明
bizModule String HOUSE / FLEET / DIRECT
bizId String 业务对象 idHOUSE=订单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

返回 dataconversationKey / 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(默认)/ IMAGEcontent 存图 URL

返回 datamessageId / conversationKey / sentAt前端不传发件人/收件人,后端按会话键解析。

4.5 POST /admin/message/chat/{conversationKey}/read — 标记已读到最新

无请求体。把该会话标记为已读到最新:该会话未读清零、已读水位推进、对应站内信行置已读(顶部合并角标相应回落)。返回 dataconversationKey / 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=200success=true)。


6. 典型调用流程(示例)

# 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 实时推送CHAT 走新增 im-chat 事件,含 URGENT priority+ 敏感词 DFAHutool 已上测试服后端就绪,前端接入时用,见下「SSE 实时契约」)
P3 房务order-v3接入房务「我的接单」列表 + 订单详情的 unreadMessageCount 接真聊天未读(经 internal Feign 透传,原占位恒 0 已上测试服后端透传就绪,见下「P3 房务红点」)
P4 车务fleet接入 待开发

P3 房务红点(后端已就绪)

房务「我的接单」列表项 HouseMyOrderItemRespVO.unreadMessageCount 与订单详情 tabCounts.unreadMessageCount 从此返真聊天未读(此前恒 0 占位order-v3 服务端组装列表/详情时经 Feign 调 user-service POST /internal/message/chat/biz-unread-batch 批量取「当前登录房务在该订单(bizModule=HOUSE)上的会话未读」。前端无需改调用——字段同名,值从 0 变真;可据 unreadMessageCount > 0 显红点、按它排序(列表 sortBy=unreadMessageCount,desc 已支持。user 不可达时降级回 0,不阻断列表。仍待前端排期接入展示。

SSE 实时契约P2 后端已就绪,前端接入时用)

复用现有 SSE 长连接 GET /ws/admin-msg/streamEventSource,网关注入鉴权不新增连接。一条连接上按 event 名分发:

  • message 事件(现有系统通知,行为不变):前端原有监听不用动
  • im-chat 事件P2 新增,聊天专用)对端在线时实时收到,payload
{
  "type": "CHAT",
  "adminId": "收件方adminId",
  "unreadCount": 9,                  // 合并未读(聊天+通知),直接刷顶部角标
  "conversationKey": "HOUSE:70123:101:205",
  "senderName": "房务·小呼",
  "preview": "标间超预算了…",
  "priority": "URGENT"               // URGENT 时前端做强提示(弹窗/声音)
}

前端用法:监听 im-chatunreadCount 刷顶部角标;conversationKey 命中当前打开的会话则 live append 新气泡;priority=URGENT 强提示。P2 是后端能力,前端接入仍待排期通知。


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 wx/HL#4020
PRP1 wx/HL#4028
PRhotfix bean 名冲突) wx/HL#4030
PRhotfix open 幂等语义) wx/HL#4031
后端负责人 王骁