# 即时通讯模块 REST API (IM) > 通用规范(认证方式、响应格式、错误码)见 [README.md](../README.md) > 消息的实时收发(发送/撤回/标记已读/正在输入)通过 WebSocket 完成,见 [websocket.md](../websocket.md) > 本文档中的接口用于会话管理和消息历史查询等非实时操作。 > **最后更新:** 2026-03-03(Phase 2d 文件上传 API 新增) --- ## 接口列表 | 方法 | 路径 | 权限 | 说明 | |------|------|------|------| | GET | /api/v1/im/conversations | 需认证 | 获取会话列表 | | GET | /api/v1/im/messages | 需认证 | 获取历史消息(游标分页) | | PUT | /api/v1/im/conversations/:id/pin | 需认证 | 置顶/取消置顶 | | PUT | /api/v1/im/conversations/:id/dnd | 需认证 | 设置/取消消息免打扰 | | DELETE | /api/v1/im/conversations/:id | 需认证 | 删除会话(软删除) | | DELETE | /api/v1/im/conversations/:id/messages | 需认证 | 清空聊天记录(个人视图) | | GET | /api/v1/im/messages/search | 需认证 | 全局消息搜索 | | GET | /api/v1/im/unread | 需认证 | 获取全局未读消息总数 | | GET | /api/v1/im/messages/:id/reads | 需认证 | 获取消息已读详情 | | POST | /api/v1/upload/image | 需认证 | 图片上传(含缩略图生成)[Phase 2d] | | POST | /api/v1/upload/voice | 需认证 | 语音上传(含时长校验)[Phase 2d] | | POST | /api/v1/upload | 需认证 | 通用文件上传(最大 50MB)[Phase 2d] | --- ## 1. 获取会话列表 `GET /api/v1/im/conversations` **权限:** 需认证 **说明:** 返回当前用户的所有会话,排序:置顶优先 → 最后消息时间降序。已软删除的会话不返回。通过 LEFT JOIN 一次获取单聊对方用户 ID,避免 N+1 查询。 **成功响应:** ```json { "code": 0, "message": "success", "data": { "list": [ { "id": 1, "type": 1, "peer_user_id": 2, "peer_nickname": "李四", "peer_avatar": "https://...", "last_msg_content": "你好", "last_msg_time": "2026-03-03 10:30:00", "last_msg_sender_id": 2, "is_pinned": false, "unread_count": 3 } ] } } ``` --- ## 2. 获取历史消息 `GET /api/v1/im/messages` **权限:** 需认证,且为该会话成员 **查询参数:** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | conversation_id | int | 是 | - | 会话 ID | | before_id | int | 否 | 0 | 游标:查询 ID 小于此值的消息,0=最新 | | limit | int | 否 | 30 | 每次获取数量,最大 100 | **说明:** 支持 `clear_before_msg_id` 个人视图过滤(清空聊天记录后,仅过滤当前用户视图,不影响对方)。 **成功响应:** ```json { "code": 0, "message": "success", "data": { "list": [ { "id": 99, "conversation_id": 1, "sender_id": 2, "type": 1, "content": "你好", "status": 1, "client_msg_id": "", "created_at": "2026-03-03 10:29:00" } ], "has_more": true } } ``` --- ## 3. 置顶/取消置顶会话 `PUT /api/v1/im/conversations/:id/pin` **权限:** 需认证,且为该会话成员 **请求参数:** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | is_pinned | bool | 是 | true=置顶, false=取消 | --- ## 3.5 设置/取消消息免打扰 `PUT /api/v1/im/conversations/:id/dnd` **权限:** 需认证,且为该会话成员 **请求参数:** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | is_do_not_disturb | bool | 是 | true=开启免打扰, false=关闭 | **说明:** 免打扰模式下,新消息仍计入会话 unread_count,但不递增 Redis 全局未读数,前端会话列表中以灰色数字展示未读数。 --- ## 4. 删除会话 `DELETE /api/v1/im/conversations/:id` **权限:** 需认证,且为该会话成员 **说明:** 软删除,仅影响当前用户视图,不影响对方。同时清零未读数并更新 Redis 全局未读。 --- ## 5. 清空聊天记录 `DELETE /api/v1/im/conversations/:id/messages` **权限:** 需认证,且为该会话成员 **说明:** 个人视图操作,不影响对方的消息。实现方式:记录清空时的最后消息 ID(`clear_before_msg_id`),后续查询历史消息时过滤。同时清零该会话未读数。 --- ## 6. 全局消息搜索 `GET /api/v1/im/messages/search` **权限:** 需认证 **查询参数:** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | keyword | string | 是 | - | 搜索关键词 | | limit | int | 否 | 50 | 返回条数上限 | **说明:** 使用 PostgreSQL GIN 全文索引(`to_tsvector('simple', content) @@ plainto_tsquery('simple', ?)`),仅搜索用户所在会话的消息。 **成功响应:** ```json { "code": 0, "message": "success", "data": { "list": [ { "id": 99, "conversation_id": 1, "sender_id": 2, "type": 1, "content": "你好世界", "status": 1, "created_at": "2026-03-03 10:29:00", "sender_nickname": "李四", "sender_avatar": "https://..." } ] } } ``` --- ## 7. 获取全局未读消息总数 `GET /api/v1/im/unread` **权限:** 需认证 **说明:** 从 Redis STRING 读取全局未读总数,用于 TabBar badge 显示。 **成功响应:** ```json { "code": 0, "message": "success", "data": { "total_unread": 5 } } ``` --- ## 8. 获取消息已读详情 `GET /api/v1/im/messages/:id/reads` **权限:** 需认证,且为该会话成员 **说明:** 返回指定消息的已读/未读用户列表。群聊场景下,已设群昵称的用户会额外返回 `group_nickname` 字段。 **成功响应:** ```json { "code": 0, "message": "success", "data": { "read_list": [ { "user_id": 4, "user_nickname": "张三", "user_avatar": "https://...", "group_nickname": "群昵称A", "read_at": "" } ], "unread_list": [ { "user_id": 5, "user_nickname": "李四", "user_avatar": "https://..." } ], "read_count": 1, "total_count": 3 } } ``` **字段说明:** | 字段 | 说明 | |------|------| | group_nickname | 群内昵称,仅群聊有效且已设置时返回(omitempty) | | read_at | 已读时间(当前暂为空,预留字段) | | total_count | 群成员总数(不含消息发送者本人) |