feat: add conversation system action messages

This commit is contained in:
richjohnrambo
2026-09-01 13:12:24 +08:00
parent 39e7e019c7
commit edced2675b
8 changed files with 213 additions and 41 deletions
+33 -1
View File
@@ -314,6 +314,38 @@ X-MeetingIM-APIKey: <预置的普通 API Key>
| @所有人 | `{"pub":{"id":"pub-all-1","topic":"grp...","head":{"mime":"application/json","x-im-schema":1,"x-im-type":"text","x-im-client-mid":"mid_all_1","mention_all":true},"content":{"text":"@所有人 开会"}}}` | 无权限时 `{"ctrl":{"id":"pub-all-1","code":403,"text":"permission denied","params":{"reason":"MENTION_ALL_FORBIDDEN"}}}` |
| 重复 `client_mid` 重试 | 与第一次发送完全相同,复用 `x-im-client-mid:"mid_1"` | 目标行为:返回第一次成功的同一 `seq`;不得落两条消息 |
##### 0.5.4.3.1 会话内系统提示和可点击动作消息
截图中的灰色提示、入群邀请说明、好友已添加提示等属于会话内系统消息,必须进入对应 P2P 或群 Topic 的消息流,占用 `seq`,参与历史拉取、重连补偿和多端同步。它们不是 `info` 实时业务事件,也不是系统通知列表记录;`info` 只负责触发刷新,真正需要在聊天窗口长期展示的内容必须以 `{data}` 下发并入库。
客户端不得主动发送 `system_notice`、`system_action`;这两类消息只能由服务端受控身份生成。服务端下发时 `data.from` 可以为空,客户端以 `head.x-im-from="system"` 判断系统身份,不依赖真实用户头像。客户端收到未知 `template` 或未知 `action.type` 时,展示 `content.text`,忽略不可识别动作,不允许执行任意 URL、脚本或非白名单路由。
| 类型 | 适用场景 | 服务端下行示例 | 客户端渲染 |
| --- | --- | --- | --- |
| `system_notice` | “你已添加了安妮,现在可以开始聊天了”、撤回提示、群名修改、成员进出群等纯提示 | `{"data":{"topic":"p2p...","seq":19,"from":"","head":{"x-im-schema":1,"x-im-type":"system_notice","x-im-template":"friend_added","x-im-from":"system"},"content":{"text":"你已添加了安妮,现在可以开始聊天了。","level":"normal","template":"friend_added","actors":[{"user_id":"usr_anne","name":"安妮"}],"actions":[]}}}` | 居中灰色提示;不显示发送人头像;如 `actors.click` 为空则不可点 |
| `system_action` | 群邀请确认说明、审批入口、群设置入口、可点击人名或群名提示 | `{"data":{"topic":"grp...","seq":20,"from":"","head":{"x-im-schema":1,"x-im-type":"system_action","x-im-template":"group_invite_confirm_enabled","x-im-from":"system"},"content":{"text":"安妮邀请栗子来了加入了群聊","template":"group_invite_confirm_enabled","actors":[{"user_id":"usr_anne","name":"安妮","click":{"type":"user_profile","target_id":"usr_anne"}},{"user_id":"usr_lizi","name":"栗子来了","click":{"type":"user_profile","target_id":"usr_lizi"}}],"actions":[{"type":"open_group_invite_settings","label":"群聊邀请确认","target_id":"grp..."}]}}}` | 居中灰色或业务提示样式;可点击片段按 `actors.click` 高亮;按钮或文字入口按 `actions` 渲染 |
`content` 字段约定:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `text` | string | 是 | 降级展示文案;客户端可直接展示,也可按 `template` 重新排版 |
| `template` | string | 是 | 服务端稳定模板编码,例如 `friend_added`、`group_member_joined`、`group_invite_confirm_enabled` |
| `level` | string | 否 | `normal`、`warning`、`danger`,影响颜色和强调程度 |
| `actors` | array | 否 | 文案中的用户、群、文件等实体;支持局部高亮和点击 |
| `actions` | array | 否 | 当前消息可触发的操作入口;只允许客户端白名单动作 |
| `extra` | object | 否 | 模板扩展参数;客户端不得依赖未知字段完成关键流程 |
`actors[].click` 和 `actions[]` 的 `type` 首版白名单:
| 类型 | 参数 | 行为 |
| --- | --- | --- |
| `user_profile` | `target_id` | 打开用户资料页 |
| `group_profile` | `target_id` | 打开群资料页 |
| `open_group_invite_settings` | `target_id` | 打开群邀请确认设置 |
| `open_group_join_requests` | `target_id` | 打开群入群审批列表 |
| `open_message` | `topic,seq` | 定位到指定消息 |
##### 0.5.4.4 回执、正在输入、删除和清空记录
| 场景 | 客户端发送 | 服务端返回/下行示例 |
@@ -453,7 +485,7 @@ X-MeetingIM-APIKey: <预置的普通 API Key>
`x-im-client-mid` 由客户端生成 ULID/UUID,作用域为“租户 + 发送人”,断线重试必须复用;服务端目标实现应返回第一次写入的同一 `seq`。未知 `x-im-type` 显示“暂不支持的消息”,不得崩溃或删除消息。
消息类型首版固定为:`text`、`image`、`video`、`voice`、`file`、`contact_card`、`link`、`forward_bundle`、`call`、`system_event`。自定义表情启用后追加 `sticker`。媒体内容只保存 `file_id`、文件元数据和缩略图 ID,不保存可长期绕过鉴权的公共 URL。
消息类型首版固定为:`text`、`image`、`video`、`voice`、`file`、`contact_card`、`link`、`forward_bundle`、`call`、`system_notice`、`system_action`、`system_event`。自定义表情启用后追加 `sticker`。媒体内容只保存 `file_id`、文件元数据和缩略图 ID,不保存可长期绕过鉴权的公共 URL。`system_notice` 和 `system_action` 只能由服务端生成,普通用户构造后发送必须被服务端拒绝。
### 0.7 HTTP 幂等、重试和安全