# 站内信「打开会话」合并为 1 个接口(元信息+订单卡+首屏消息+合并未读+标记已读)+ 订单消息跳转用 conversationKey > 模块:管理后台 · 站内信聊天(打开对话 + 订单消息行跳转) > 类型:后端合并优化(已合并 dev-v3 + 部署测试服 + API 实测闭环)+ 前端对接 > 日期:2026-06-30 > 关联:PR #4666(打开会话合并)、#4664(会话浮现 last_message_at);**取代 58_ 的"单独调 conversations 取订单卡"** —— 订单卡现已直接在打开会话接口返回 ## 一、打开会话:5 接口 → 1 接口(前端必改) 前端反馈"打开一个对话要调 5 个接口太多、已读不该有独立接口"。已合并优化:**打开会话只调 1 个接口**,且**查询即已读**。 ### 唯一需要调的接口(按场景三选一,都返回同一个 `ChatOpenFullRespVO`) | 场景 | 接口 | |------|------| | 定制师↔房务 订单会话 | `POST /admin/message/chat/open-house` body `{orderId, peerAdminId?}` | | 组长↔房务 订单会话 | `POST /admin/message/chat/open-house-lead` body `{orderId, peerAdminId}` | | 普通 1:1(非订单) | `POST /admin/message/chat/open` body `{peerAdminId, bizModule, bizId}` | **这一个接口一次性返回打开会话所需全部数据,并已把本会话标记为已读**(不必再调 `/read`)。 ### `ChatOpenFullRespVO` 返回结构 ```json { "conversationKey": "HOUSE:2071784830965620737", "peerAdminId": 2021059720172838914, "peerName": "王骁", "peerRole": "CUSTOMIZER", "peerRoleLabel": "定制师", "peerOnline": true, "unreadCount": 0, // 本会话未读(打开即已读,恒 0) "isNew": false, "unreadTotal": 3, // 我的合并未读总数(NOTIFY+CHAT,标记本会话已读后的最新值),刷顶部角标用 "order": { // 订单卡:仅 HOUSE/HOUSE_LEAD 会话有;非订单会话/ order-v3 不可达为 null "orderNo": "HL20260630103610215", "customerName": "吕思远", "destination": "海拉尔", "tripDays": 3, "bizStatusLabel": "配房中", "progressDesc": "已配 2/4 间", "productName": "游牧的森林-短途版", "adultCount": 2, "childCount": 1, "requirementId": 70456 }, "thread": { // 首屏消息(最新一页 20 条;上滑更早历史走 GET messages) "conversationKey": "HOUSE:2071784830965620737", "hasMore": false, "nextCursor": null, "list": [ { "messageId":"2071792080350236674","senderAdminId":"2021059720172838914","senderName":"王骁", "senderRole":"CUSTOMIZER","msgType":"TEXT","priority":"NORMAL","content":"77721", "isMine":false,"readByPeer":false,"sentAt":"2026-06-30 11:04:59" } ] } } ``` ### 优化后的完整交互(满足「≤2 普通接口 + 1 SSE」) - **打开会话** → 1 个普通接口:`POST …/open-house`(拿到 元信息 + 订单卡 + 首屏消息 + 合并未读,且已标记已读)。 - **上滑加载更早历史** → `GET /admin/message/chat/{conversationKey}/messages?beforeId={上次最小id}&pageSize=20`(纯分页读,无副作用)。 - **发消息** → `POST /admin/message/chat/{conversationKey}/messages`。 - **实时收消息/未读/已读回执** → 1 个 SSE(既有 `admin-notify`)。 ### 【前端必改】 1. 打开会话**只调 open/open-house/open-house-lead 之一**,用返回的 `order` 渲染订单信息条、`thread` 渲染消息、`unreadTotal` 刷顶部角标。 2. **删掉打开时的这些调用**:原单独的 `GET .../messages`(首屏改用 open 返回的 `thread`)、`POST .../read`(打开即已读,`unreadTotal` 已是标记后的值)、`GET .../conversations?bizId=`(订单卡改用 open 返回的 `order`,**取代 58_**)、`GET /admin/message/unread-count`(用 open 返回的 `unreadTotal`)。 3. `/read`、`/unread-count`、`conversations` 接口仍保留(会话列表视图仍用 conversations),但**打开会话流程不再需要它们**。 4. `messages`(GET) 只在上滑加载更早历史时调(用 `thread.nextCursor`/最小 messageId 作 `beforeId`)。 ## 二、订单消息行的「跳转按钮」用 conversationKey(前端处理) 收件箱「订单消息」行(kind=CHAT)跳转按钮消失了。后端数据一直都在,前端按字段渲染即可: - **普通消息(NOTIFY)**:用 `link` 跳对应页面(不变)。 - **订单消息(CHAT)**:用该行的 **`conversationKey`** 跳转 = 打开会话(即调上面的 open-house,conversationKey 形如 `HOUSE:{orderId}`,orderId 也可取行内 `bizId`)。这正是它之前的跳转行为,切到 `list?messageType=ORDER`(57_)后行组件漏带了 conversationKey,补回即可。 ## 备注 - 订单卡 `order` 仅 HOUSE/HOUSE_LEAD 订单会话有,非订单会话或 order-v3 暂不可达时为 null,前端隐藏订单信息条即可,不报错。 - 打开历史老会话时后端会顺手对齐该会话"最后活跃",使其正常出现在会话列表(修复个别老会话在列表里看不到的问题,#4664)。