|
|
@@ -22,14 +22,149 @@
|
|
|
|
|
|
<div class="section">
|
|
|
<h3>2. 接收消息(拉取 + 推送)</h3>
|
|
|
- <p>推荐双通道方案:先拉取会话/历史,再建立 WebSocket 接收实时消息,断线后补拉历史兜底。</p>
|
|
|
- <ul>
|
|
|
- <li><strong>会话列表</strong>:<code>GET /api/v1/messages/conversations</code></li>
|
|
|
- <li><strong>历史消息</strong>:<code>GET /api/v1/messages/history/{other_user_id}</code></li>
|
|
|
- <li><strong>实时推送</strong>:<code>ws(s)://YOUR_DOMAIN/api/v1/ws/messages?token=JWT_TOKEN</code></li>
|
|
|
- </ul>
|
|
|
+ <p><strong>推荐用法(端到端)</strong></p>
|
|
|
+ <ol>
|
|
|
+ <li><strong>WebSocket 只负责提醒</strong>:长连收到 <code>NEW_MESSAGE</code> 后,不要只靠推送拼 UI;应触发<strong>对话列表刷新</strong>。</li>
|
|
|
+ <li><strong>刷新列表时建议请求两个 HTTP 接口</strong>:① <code>GET /messages/unread-count</code> 获取<strong>全局未读总数</strong>(角标);② <code>GET /messages/conversations</code> 获取<strong>会话列表</strong>(每行含 <code>unread_count</code>)。可并行发起。</li>
|
|
|
+ <li><strong>用户点击某一会话</strong>:用该行的 <code>user_id</code> 作为 <code>other_user_id</code>,调用 <code>GET /messages/history/{other_user_id}</code> 拉聊天记录;进入会话后调用 <code>PUT /messages/history/{other_user_id}/read-all</code>,将该会话内你作为接收方的未读一次性标为已读(与产品「进入即已读」一致)。</li>
|
|
|
+ <li><strong>用户点击「一键已读」</strong>:调用 <code>PUT /messages/read-all</code>,将整个收件箱未读全部标为已读(与按会话已读不同,见下表)。</li>
|
|
|
+ </ol>
|
|
|
+ <p>下列四个 HTTP 接口与「会话维度」共用路径参数 <code>other_user_id</code>(与 <code>conversations[].user_id</code> 相同)。认证均为 <code>Authorization: Bearer <JWT_TOKEN></code>。</p>
|
|
|
+
|
|
|
+ <h4>2.1 四个核心接口总览</h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>接口</th><th>作用</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><code>GET /api/v1/messages/unread-count</code></td><td>当前用户作为<strong>接收方</strong>的<strong>全局</strong>未读消息条数(整数)。</td></tr>
|
|
|
+ <tr><td><code>GET /api/v1/messages/conversations</code></td><td>会话聚合列表,每行含 <code>user_id</code>、<code>unread_count</code>、<code>last_message</code> 等。</td></tr>
|
|
|
+ <tr><td><code>GET /api/v1/messages/history/{other_user_id}</code></td><td>某一会话的聊天记录(分页)。</td></tr>
|
|
|
+ <tr><td><code>PUT /api/v1/messages/history/{other_user_id}/read-all</code></td><td>仅将该会话范围内、你是接收方且未读的消息标为已读。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
|
|
|
- <h4>示例:拉取历史消息</h4>
|
|
|
+ <h4>2.2 <code>other_user_id</code>(路径参数,与 <code>conversations[].user_id</code> 一致)</h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>取值</th><th>含义</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><strong>> 0</strong></td><td>与某用户的私信会话,值为对方用户 ID。</td></tr>
|
|
|
+ <tr><td><strong>= 0</strong></td><td>兼容的「全部系统通知」视图(与 history 接口分支一致)。</td></tr>
|
|
|
+ <tr><td><strong>< 0</strong></td><td>某一应用的系统通知会话,值为 <code>-applications.id</code>(应用表主键取负)。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+
|
|
|
+ <h4>2.3 <code>GET /api/v1/messages/unread-count</code></h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>项目</th><th>说明</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><strong>方法 / 路径</strong></td><td><code>GET /api/v1/messages/unread-count</code></td></tr>
|
|
|
+ <tr><td><strong>请求头</strong></td><td><code>Authorization: Bearer <JWT_TOKEN></code></td></tr>
|
|
|
+ <tr><td><strong>查询参数</strong></td><td>无</td></tr>
|
|
|
+ <tr><td><strong>成功响应</strong></td><td><code>200</code>,响应体为<strong>纯整数</strong>(JSON number),表示你是接收方且 <code>is_read=false</code> 的消息总数(私信 + 通知合计)。</td></tr>
|
|
|
+ <tr><td><strong>说明</strong></td><td>正式接口,用于角标等场景。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ <div class="code-block">
|
|
|
+ <pre>
|
|
|
+GET /api/v1/messages/unread-count HTTP/1.1
|
|
|
+Host: your-domain.example.com
|
|
|
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...</pre>
|
|
|
+ </div>
|
|
|
+ <div class="code-block">
|
|
|
+ <pre>
|
|
|
+HTTP/1.1 200 OK
|
|
|
+Content-Type: application/json
|
|
|
+
|
|
|
+12</pre>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <h4>2.4 <code>GET /api/v1/messages/conversations</code></h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>项目</th><th>说明</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><strong>方法 / 路径</strong></td><td><code>GET /api/v1/messages/conversations</code></td></tr>
|
|
|
+ <tr><td><strong>请求头</strong></td><td><code>Authorization: Bearer <JWT_TOKEN></code></td></tr>
|
|
|
+ <tr><td><strong>查询参数</strong></td><td>无</td></tr>
|
|
|
+ <tr><td><strong>成功响应</strong></td><td><code>200</code>,<code>Content-Type: application/json</code>,Body 为<strong>数组</strong>,元素为会话对象(见下表字段)。</td></tr>
|
|
|
+ <tr><td><strong>说明</strong></td><td>服务端对与你相关的消息做内存聚合,有条数上限;极旧会话可能不出现在列表中。<code>unread_count</code> 仅统计「你是接收方且未读」。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ <p><strong>响应数组元素字段(ConversationResponse)</strong></p>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><code>user_id</code></td><td>number</td><td>会话键,与 <code>history/{other_user_id}</code> 的 <code>other_user_id</code> 相同。</td></tr>
|
|
|
+ <tr><td><code>username</code></td><td>string</td><td>展示用账号(私信多为手机号;系统会话多为应用 ID 等)。</td></tr>
|
|
|
+ <tr><td><code>full_name</code></td><td>string | null</td><td>展示名称。</td></tr>
|
|
|
+ <tr><td><code>unread_count</code></td><td>number</td><td>该会话未读条数(仅你是接收方时计入)。</td></tr>
|
|
|
+ <tr><td><code>last_message</code></td><td>string</td><td>最后一条预览文案。</td></tr>
|
|
|
+ <tr><td><code>last_message_type</code></td><td>string</td><td>内容类型,如 <code>TEXT</code> / <code>IMAGE</code> / <code>USER_NOTIFICATION</code> 等。</td></tr>
|
|
|
+ <tr><td><code>updated_at</code></td><td>string</td><td>该会话最后一条消息时间。</td></tr>
|
|
|
+ <tr><td><code>is_system</code></td><td>boolean</td><td>是否系统/应用通知会话。</td></tr>
|
|
|
+ <tr><td><code>app_id</code></td><td>number | null</td><td>应用主键(通知会话时有值)。</td></tr>
|
|
|
+ <tr><td><code>app_name</code></td><td>string | null</td><td>应用名称。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ <div class="code-block">
|
|
|
+ <pre>
|
|
|
+GET /api/v1/messages/conversations HTTP/1.1
|
|
|
+Authorization: Bearer <JWT_TOKEN></pre>
|
|
|
+ </div>
|
|
|
+ <div class="code-block">
|
|
|
+ <pre>
|
|
|
+HTTP/1.1 200 OK
|
|
|
+Content-Type: application/json
|
|
|
+
|
|
|
+[
|
|
|
+ {
|
|
|
+ "user_id": -101,
|
|
|
+ "username": "oa_system",
|
|
|
+ "full_name": "OA系统",
|
|
|
+ "unread_count": 3,
|
|
|
+ "last_message": "您有一条待审批任务",
|
|
|
+ "last_message_type": "TEXT",
|
|
|
+ "updated_at": "2026-03-18T10:00:00",
|
|
|
+ "is_system": true,
|
|
|
+ "app_id": 101,
|
|
|
+ "app_name": "OA系统"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "user_id": 2048,
|
|
|
+ "username": "13800138000",
|
|
|
+ "full_name": "张三",
|
|
|
+ "unread_count": 1,
|
|
|
+ "last_message": "你好",
|
|
|
+ "last_message_type": "TEXT",
|
|
|
+ "updated_at": "2026-03-18T09:20:00",
|
|
|
+ "is_system": false,
|
|
|
+ "app_id": null,
|
|
|
+ "app_name": null
|
|
|
+ }
|
|
|
+]</pre>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <h4>2.5 <code>GET /api/v1/messages/history/{other_user_id}</code></h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>项目</th><th>说明</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><strong>方法 / 路径</strong></td><td><code>GET /api/v1/messages/history/{other_user_id}</code></td></tr>
|
|
|
+ <tr><td><strong>路径参数</strong></td><td><code>other_user_id</code>:整数,见上文 §2.2。</td></tr>
|
|
|
+ <tr><td><strong>查询参数</strong></td><td><code>skip</code>(默认 0)、<code>limit</code>(默认 50),分页用。</td></tr>
|
|
|
+ <tr><td><strong>请求头</strong></td><td><code>Authorization: Bearer <JWT_TOKEN></code></td></tr>
|
|
|
+ <tr><td><strong>成功响应</strong></td><td><code>200</code>,JSON 数组,元素为消息对象(MessageResponse,见 §2.7)。按创建时间降序(新消息在前)。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
<div class="code-block">
|
|
|
<pre>
|
|
|
GET /api/v1/messages/history/2048?skip=0&limit=50 HTTP/1.1
|
|
|
@@ -56,6 +191,70 @@ Authorization: Bearer <JWT_TOKEN></pre>
|
|
|
}
|
|
|
]</pre>
|
|
|
</div>
|
|
|
+
|
|
|
+ <h4>2.6 <code>PUT /api/v1/messages/history/{other_user_id}/read-all</code></h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>项目</th><th>说明</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><strong>方法 / 路径</strong></td><td><code>PUT /api/v1/messages/history/{other_user_id}/read-all</code></td></tr>
|
|
|
+ <tr><td><strong>路径参数</strong></td><td><code>other_user_id</code>:与当前打开的会话 <code>user_id</code> 一致。</td></tr>
|
|
|
+ <tr><td><strong>请求头</strong></td><td><code>Authorization: Bearer <JWT_TOKEN></code></td></tr>
|
|
|
+ <tr><td><strong>请求体</strong></td><td>无(不需 <code>Content-Type: application/json</code> 亦可)。</td></tr>
|
|
|
+ <tr><td><strong>成功响应</strong></td><td><code>200</code>,JSON 对象:<code>{ "updated_count": <number> }</code>,表示本次更新行数。</td></tr>
|
|
|
+ <tr><td><strong>说明</strong></td><td>只处理你是<strong>接收方</strong>且<strong>未读</strong>的记录;与 <code>history</code> 的会话范围一致。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ <div class="code-block">
|
|
|
+ <pre>
|
|
|
+PUT /api/v1/messages/history/2048/read-all HTTP/1.1
|
|
|
+Authorization: Bearer <JWT_TOKEN></pre>
|
|
|
+ </div>
|
|
|
+ <div class="code-block">
|
|
|
+ <pre>
|
|
|
+{ "updated_count": 3 }</pre>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <h4>2.7 可选:<code>PUT /api/v1/messages/read-all</code>(收件箱全部已读)</h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>项目</th><th>说明</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><strong>方法 / 路径</strong></td><td><code>PUT /api/v1/messages/read-all</code></td></tr>
|
|
|
+ <tr><td><strong>请求头</strong></td><td><code>Authorization: Bearer <JWT_TOKEN></code></td></tr>
|
|
|
+ <tr><td><strong>请求体</strong></td><td>无</td></tr>
|
|
|
+ <tr><td><strong>成功响应</strong></td><td><code>200</code>,<code>{ "updated_count": <number> }</code>,将<strong>所有</strong>你是接收方的未读一次性标为已读。</td></tr>
|
|
|
+ <tr><td><strong>说明</strong></td><td>与 §2.6 区别:不按会话筛选,影响整个收件箱。单条已读 <code>PUT /messages/{id}/read</code> 在 OpenAPI 中仍标记为废弃,优先用按会话已读或本接口。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+
|
|
|
+ <h4>2.8 消息对象字段(MessageResponse,历史接口数组元素)</h4>
|
|
|
+ <table class="param-table">
|
|
|
+ <thead>
|
|
|
+ <tr><th>字段</th><th>说明</th></tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr><td><code>id</code></td><td>消息 ID。</td></tr>
|
|
|
+ <tr><td><code>sender_id</code></td><td>发送方用户 ID;系统通知可能为 <code>null</code>。</td></tr>
|
|
|
+ <tr><td><code>receiver_id</code></td><td>接收方用户 ID(当前登录用户)。</td></tr>
|
|
|
+ <tr><td><code>type</code></td><td><code>MESSAGE</code> 或 <code>NOTIFICATION</code>。</td></tr>
|
|
|
+ <tr><td><code>content_type</code></td><td><code>TEXT</code> / <code>IMAGE</code> / <code>VIDEO</code> / <code>FILE</code> / <code>USER_NOTIFICATION</code> 等。</td></tr>
|
|
|
+ <tr><td><code>title</code> / <code>content</code></td><td>标题与正文;多媒体可能为预签名 URL。</td></tr>
|
|
|
+ <tr><td><code>action_url</code> / <code>action_text</code></td><td>通知按钮;点击跳转前可配合 <code>GET /messages/{id}/callback-url</code>。</td></tr>
|
|
|
+ <tr><td><code>is_read</code> / <code>read_at</code></td><td>是否已读及已读时间。</td></tr>
|
|
|
+ <tr><td><code>app_id</code> / <code>app_name</code></td><td>应用维度信息(通知等场景)。</td></tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+
|
|
|
+ <h4>2.9 WebSocket:连接与收到提醒后行为</h4>
|
|
|
+ <ul>
|
|
|
+ <li><strong>地址</strong>:<code>ws://<主机>/api/v1/ws/messages?token=<JWT></code>(HTTPS 页面用 <code>wss://</code>)。</li>
|
|
|
+ <li><strong>心跳</strong>:建议每 30 秒发送字符串 <code>ping</code>,收到 <code>pong</code>。</li>
|
|
|
+ <li><strong>推送</strong>:JSON 中 <code>type === "NEW_MESSAGE"</code>,业务数据在 <code>data</code>。</li>
|
|
|
+ <li><strong>收到推送后</strong>:触发 §2.3 + §2.4 刷新(或仅刷新会话列表),不要仅依赖推送内容渲染完整列表。</li>
|
|
|
+ </ul>
|
|
|
</div>
|
|
|
|
|
|
<div class="section">
|
|
|
@@ -333,60 +532,8 @@ Authorization: Bearer <JWT_TOKEN></pre>
|
|
|
</div>
|
|
|
|
|
|
<div class="section">
|
|
|
- <h3>5. 对话列表聚合接口</h3>
|
|
|
- <ul>
|
|
|
- <li><strong>接口</strong>:<code>GET /api/v1/messages/conversations</code></li>
|
|
|
- <li><strong>聚合规则</strong>:私信按用户聚合,系统通知按应用拆分会话</li>
|
|
|
- <li><strong>关键字段</strong>:<code>unread_count</code>、<code>last_message</code>、<code>updated_at</code>、<code>is_system</code></li>
|
|
|
- <li><strong>未读建议</strong>:优先本地统计未读;如读取 <code>unread_count</code>,进入聊天界面建议调用 <code>PUT /api/v1/messages/read-all</code> 一键已读保持一致。</li>
|
|
|
- </ul>
|
|
|
-
|
|
|
- <h4>示例:拉取会话列表(聚合)</h4>
|
|
|
- <div class="code-block">
|
|
|
- <pre>
|
|
|
-GET /api/v1/messages/conversations HTTP/1.1
|
|
|
-Authorization: Bearer <JWT_TOKEN></pre>
|
|
|
- </div>
|
|
|
- <div class="code-block">
|
|
|
- <pre>
|
|
|
-[
|
|
|
- {
|
|
|
- "user_id": -101,
|
|
|
- "username": "oa_system",
|
|
|
- "full_name": "OA系统",
|
|
|
- "unread_count": 3,
|
|
|
- "last_message": "您有一条待审批任务",
|
|
|
- "last_message_type": "TEXT",
|
|
|
- "updated_at": "2026-03-18T10:00:00",
|
|
|
- "is_system": true,
|
|
|
- "app_id": 101,
|
|
|
- "app_name": "OA系统"
|
|
|
- },
|
|
|
- {
|
|
|
- "user_id": 2048,
|
|
|
- "username": "13800138000",
|
|
|
- "full_name": "张三",
|
|
|
- "unread_count": 0,
|
|
|
- "last_message": "[IMAGE]",
|
|
|
- "last_message_type": "IMAGE",
|
|
|
- "updated_at": "2026-03-18T09:20:00",
|
|
|
- "is_system": false,
|
|
|
- "app_id": null,
|
|
|
- "app_name": null
|
|
|
- }
|
|
|
-]</pre>
|
|
|
- </div>
|
|
|
-
|
|
|
- <h4>示例:进入聊天界面后一键已读(如你读取/展示 unread_count)</h4>
|
|
|
- <div class="code-block">
|
|
|
- <pre>
|
|
|
-PUT /api/v1/messages/read-all HTTP/1.1
|
|
|
-Authorization: Bearer <JWT_TOKEN></pre>
|
|
|
- </div>
|
|
|
- <div class="code-block">
|
|
|
- <pre>
|
|
|
-{ "updated_count": 10 }</pre>
|
|
|
- </div>
|
|
|
+ <h3>5. 对话列表与未读(索引)</h3>
|
|
|
+ <p>会话列表、全局未读、聊天历史、按会话已读、收件箱全部已读的<strong>完整请求参数、响应字段与推荐调用顺序</strong>见 <strong>第 2 节</strong>。本节仅作导航:聚合规则为私信按用户、系统通知按应用拆分会话;列表项中的 <code>user_id</code> 即后续 <code>history/{other_user_id}</code> 的路径参数。</p>
|
|
|
</div>
|
|
|
|
|
|
<div class="section">
|
|
|
@@ -395,7 +542,7 @@ Authorization: Bearer <JWT_TOKEN></pre>
|
|
|
<li><strong>连接地址</strong>:<code>/api/v1/ws/messages?token=JWT_TOKEN</code></li>
|
|
|
<li><strong>心跳</strong>:客户端每 30 秒发送 <code>ping</code>,服务端回复 <code>pong</code></li>
|
|
|
<li><strong>消息类型</strong>:服务端推送 <code>NEW_MESSAGE</code></li>
|
|
|
- <li><strong>格式与归类</strong>:WS 推送体包含 <code>data.type</code> / <code>data.app_id</code>,用于区分私信与应用通知并做会话归类(详见下载文档第 5 章)。</li>
|
|
|
+ <li><strong>格式与归类</strong>:WS 推送体包含 <code>data.type</code> / <code>data.app_id</code>,用于区分私信与应用通知;收到后请按第 2 节刷新 HTTP 列表。</li>
|
|
|
<li><strong>重连建议</strong>:指数退避重连,并在重连成功后补拉会话和历史</li>
|
|
|
</ul>
|
|
|
|