hyapp-server/docs/语音房房间用户列表前端接入文档.md

421 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 语音房房间用户列表前端接入文档
## 1. 接入范围
- 房间在线用户列表接口。
- 设置或取消房间管理员接口。
- 相关腾讯云 IM 房间系统消息。
- 前端错误处理建议。
## 2. 通用约定
### 2.1 鉴权
所有接口都需要登录态:
```http
Authorization: Bearer <access_token>
```
### 2.2 ID 类型
HTTP 返回里的用户 ID 统一按字符串处理,避免 JavaScript 大整数精度问题。
示例:
```json
{
"user_id": "10001"
}
```
### 2.3 时间类型
所有时间字段都是毫秒时间戳:
```json
{
"server_time_ms": 1760000006000
}
```
### 2.4 房间身份
房间用户身份拆成两个字段:
| 字段 | 说明 |
| --- | --- |
| `is_owner` | 是否是当前房间房主 |
| `room_role` | 是否是当前房间管理员,只表示管理员集合 |
`room_role` 只会返回:
| 值 | 说明 |
| --- | --- |
| `normal` | 当前房间普通用户 |
| `admin` | 当前房间管理员 |
注意:
- 房主不是管理员,房主用户返回 `is_owner = true`
- 房主如果不在管理员集合里,`room_role` 返回 `normal`
- 前端展示“房主”标识时看 `is_owner`,展示“管理员”标识时看 `room_role = admin`
- 当前登录用户是否展示管理员操作入口,优先看房间详情里的 `permissions.is_owner`;如果只在用户列表内判断,则看当前登录用户对应 item 的 `is_owner`
- `role` 是进房 presence 角色,例如 `audience`,不要用于判断房主或管理员。
## 3. 查询房间在线用户列表
### 3.1 接口定义
```http
GET /api/v1/rooms/{room_id}/online-users
```
### 3.2 Path 参数
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `room_id` | string | 是 | 房间 ID |
### 3.3 Query 参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `page` | int | 否 | `1` | 页码,从 `1` 开始 |
| `page_size` | int | 否 | `50` | 每页数量,最大 `100` |
| `sort` | string | 否 | `online` | `online` 按在线活跃排序;`gift_value` 按礼物价值排序 |
### 3.4 请求示例
```bash
curl -H "Authorization: Bearer $TOKEN" \
"https://api.global-interaction.com/api/v1/rooms/room_10001/online-users?page=1&page_size=50"
```
### 3.5 返回示例
```json
{
"items": [
{
"user_id": "10001",
"role": "audience",
"is_owner": true,
"room_role": "normal",
"gift_value": 188800,
"joined_at_ms": 1760000000000,
"last_seen_at_ms": 1760000005000,
"profile": {
"nickname": "Alice",
"avatar_url": "https://example.com/a.png"
}
},
{
"user_id": "10002",
"role": "audience",
"is_owner": false,
"room_role": "admin",
"gift_value": 0,
"joined_at_ms": 1760000001000,
"last_seen_at_ms": 1760000004000,
"profile": {
"nickname": "Bob",
"avatar_url": "https://example.com/b.png"
}
}
],
"total": 2,
"page": 1,
"page_size": 50,
"server_time_ms": 1760000006000
}
```
### 3.6 返回字段
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `items` | array | 当前页在线用户 |
| `items[].user_id` | string | 用户 ID |
| `items[].role` | string | 进房 presence 角色 |
| `items[].is_owner` | bool | 是否是当前房间房主 |
| `items[].room_role` | string | 当前房间管理员身份:`normal``admin` |
| `items[].gift_value` | int64 | 当前房间内累计送礼价值,未送礼返回 `0` |
| `items[].joined_at_ms` | int64 | 进房时间 |
| `items[].last_seen_at_ms` | int64 | 最近房间业务心跳时间 |
| `items[].profile.nickname` | string | 用户昵称 |
| `items[].profile.avatar_url` | string | 用户头像 |
| `total` | int64 | 在线用户总数 |
| `page` | int | 当前页 |
| `page_size` | int | 当前每页数量 |
| `server_time_ms` | int64 | 服务端时间 |
### 3.7 前端展示建议
- `gift_value` 展示的是该用户在当前房间内“送出”的礼物价值,不是收到的礼物价值。
- `gift_value = 0` 时仍然展示该用户。
- 房主标识看 `is_owner = true`
- 管理员标识看 `room_role = admin`
- 房主不是管理员,不要因为 `is_owner = true` 就把管理员标识点亮。
- 用户列表弹窗打开时,可以先拉第一页;滚动到底再拉下一页。
- 收到相关 IM 后,如果列表弹窗正在展示,可以局部更新;状态不确定时重新拉接口。
## 4. 设置或取消管理员,只有房主才显示
### 4.1 接口定义
```http
POST /api/v1/rooms/admin/set
Content-Type: application/json
```
### 4.2 请求参数
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `room_id` | string | 是 | 房间 ID |
| `command_id` | string | 是 | 客户端生成的幂等 ID重试同一次操作时保持不变 |
| `target_user_id` | string/int64 | 是 | 被设置或取消管理员的用户 ID |
| `enabled` | bool | 是 | `true` 设置管理员;`false` 取消管理员 |
### 4.3 设置管理员请求示例
```json
{
"room_id": "room_10001",
"command_id": "cmd-10001",
"target_user_id": "10002",
"enabled": true
}
```
### 4.4 取消管理员请求示例
```json
{
"room_id": "room_10001",
"command_id": "cmd-10002",
"target_user_id": "10002",
"enabled": false
}
```
### 4.5 返回示例
建议后端返回:
```json
{
"result": {
"applied": true,
"room_version": 12
},
"target_user_id": "10002",
"room_role": "admin",
"server_time_ms": 1760000006000
}
```
字段说明:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `result.applied` | bool | 本次请求是否实际改变了房间状态 |
| `result.room_version` | int64 | 房间状态版本 |
| `target_user_id` | string | 被操作用户 |
| `room_role` | string | 操作后的身份,`admin``normal` |
| `server_time_ms` | int64 | 服务端时间 |
如果后端第一版仍直接返回完整 room-service gRPC 结构,前端只需要关注命令是否成功;最终用户列表状态以接口重拉或 IM 刷新为准。
### 4.6 前端操作边界
- 只有房主可以设置或取消管理员。
- 房主可以操作所有非房主用户的管理员身份。
- 管理员之间不可互相设置或取消管理员。
- 房主不是管理员,不允许对房主执行设置或取消管理员。
- 目标用户必须当前在房间内。
- 前端重试同一次操作时,必须复用同一个 `command_id`
- 操作成功后,可以等待 `room_admin_changed` IM也可以直接刷新用户列表。
## 5. 错误处理
### 5.1 通用错误
| HTTP 状态 | 场景 | 前端处理 |
| --- | --- | --- |
| `401` | 未登录或 token 失效 | 跳登录或刷新登录态 |
| `403` | 无权限,例如用户不在房间或不是房主 | 提示无权限,并刷新房间状态 |
| `404` | 房间不存在或目标用户不在房间 | 提示目标不存在或用户已离开 |
| `409` | 状态冲突,例如目标用户是房主 | 提示当前状态不允许操作,并刷新用户列表 |
| `5xx` | 服务端异常 | 保留当前 UI提示稍后重试 |
### 5.2 查询用户列表错误
| 场景 | 前端处理 |
| --- | --- |
| 当前用户不在房间 | 关闭用户列表弹窗,刷新当前房间状态 |
| 分页为空 | 正常展示空列表或结束加载更多 |
| `page_size` 超过上限 | 使用服务端返回的 `page_size` 为准 |
### 5.3 设置管理员错误
| 场景 | 前端处理 |
| --- | --- |
| 非房主操作 | 隐藏或禁用管理入口,提示无权限 |
| 操作目标是房主 | 不展示管理员操作入口;如果服务端返回错误,刷新列表 |
| 目标用户已离房 | 提示用户已离开,刷新列表 |
| 重复点击 | 前端按钮进入 loading同一次请求复用同一个 `command_id` |
| 请求超时 | 可以用同一个 `command_id` 重试 |
## 6. 相关 IM
### 6.1 IM 消息形态
房间系统消息通过腾讯云 IM `TIMCustomElem` 下发。
前端解析入口:
```text
TIMCustomElem.MsgContent.Data
```
`Data` 是 JSON 字符串。
示例:
```json
{
"event_id": "evt-admin-10001",
"room_id": "room_10001",
"event_type": "room_admin_changed",
"actor_user_id": 10001,
"target_user_id": 10002,
"room_version": 12,
"attributes": {
"enabled": "true"
}
}
```
通用字段:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `event_id` | string | 事件唯一 ID前端用于去重 |
| `room_id` | string | 房间 ID |
| `event_type` | string | 事件类型 |
| `actor_user_id` | int64 | 操作人 |
| `target_user_id` | int64 | 被操作人 |
| `room_version` | int64 | 房间版本 |
| `attributes` | object | 字符串键值扩展字段 |
### 6.2 管理员变更 IM
事件类型:
```text
room_admin_changed
```
消息示例:
```json
{
"event_id": "evt-admin-10001",
"room_id": "room_10001",
"event_type": "room_admin_changed",
"actor_user_id": 10001,
"target_user_id": 10002,
"room_version": 12,
"attributes": {
"enabled": "true"
}
}
```
字段说明:
| 字段 | 说明 |
| --- | --- |
| `actor_user_id` | 发起操作的房主 |
| `target_user_id` | 被设置或取消管理员的用户 |
| `attributes.enabled` | `"true"` 设置管理员;`"false"` 取消管理员 |
前端处理:
- 使用 `event_id` 去重。
- 如果当前用户是 `target_user_id`,更新当前用户管理权限 UI。
- 如果用户列表已打开,更新对应用户的 `room_role`
- 如果列表数据不完整,重新请求在线用户列表接口。
### 6.3 送礼成功 IM
事件类型:
```text
room_gift_sent
```
消息示例:
```json
{
"event_id": "evt-gift-10001",
"room_id": "room_10001",
"event_type": "room_gift_sent",
"actor_user_id": 10002,
"target_user_id": 10003,
"gift_value": 5200,
"room_heat": 999999,
"room_version": 13,
"attributes": {
"gift_id": "rose",
"pool_id": "",
"gift_count": "10",
"billing_receipt_id": "receipt-10001",
"coin_spent": "5200",
"gift_point_added": "5200",
"price_version": "v1"
}
}
```
字段说明:
| 字段 | 说明 |
| --- | --- |
| `actor_user_id` | 送礼用户,用户列表里需要累加 `gift_value` 的用户 |
| `target_user_id` | 收礼用户 |
| `gift_value` | 本次送礼价值增量 |
| `room_heat` | 送礼后的房间热度 |
| `attributes.gift_id` | 礼物 ID |
| `attributes.gift_count` | 礼物数量,字符串 |
| `attributes.billing_receipt_id` | 钱包结算流水 |
前端处理:
- 如果用户列表已打开,并且当前页包含 `actor_user_id`,可以执行 `gift_value += event.gift_value`
- 如果当前列表按 `gift_value` 排序,建议重新拉接口,避免分页顺序错乱。
- 如果当前页不包含 `actor_user_id`,不要手动插入用户,分页完整性以接口为准。
### 6.4 进出房 IM
用户列表也会受进出房影响:
| 事件 | 建议处理 |
| --- | --- |
| `room_user_joined` | 用户列表打开时重新拉列表 |
| `room_user_left` | 用户列表打开时移除用户或重新拉列表 |
## 7. 前端刷新策略
推荐策略:
1. 打开用户列表弹窗时,请求 `GET /api/v1/rooms/{room_id}/online-users`
2. 收到 `room_admin_changed` 时,局部更新 `room_role`;不确定时重拉。
3. 收到 `room_gift_sent` 时,局部累加 `gift_value`;如果当前排序依赖礼物价值,重拉。
4. 收到 `room_user_joined``room_user_left` 时,列表打开状态下重拉。
5. 所有 IM 使用 `event_id` 去重。