6.5 KiB
6.5 KiB
个人信息页用户上麦状态 Flutter 对接
1. 接口职责
个人信息页通过本接口判断被查看用户当前是否占用语音房麦位,并取得可直接交给统一进房入口的房间信息。
- 上麦事实只来自
room-service当前 Room Cell 快照;不要用用户是否为房主、房间搜索结果、IM 本地状态或历史缓存推断。 - 接口返回的是带时间戳的瞬时快照;点击 Live 后仍以
POST /api/v1/rooms/join的实时校验为准。 - 当前接口仅用于客态个人信息页。请求中包含当前登录用户本人时,该项固定返回
not_on_mic。
2. 请求
GET /api/v1/users/voice-room-presence:batch?user_ids=163020,163021
Authorization: Bearer {access_token}
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
user_ids |
string | 是 | 逗号分隔的系统 user_id,不接受展示短号 |
约束:
- 去重后最多 100 个 ID,响应顺序按请求中第一次出现的顺序返回。
- 空值、非数字、
0、负数、空分段或超过上限都会整批返回INVALID_USER_IDS。 viewer_user_id、app_code和request_id由 gateway 从登录态和请求上下文注入,客户端不能提交。- 接口要求有效登录态且用户已完成资料。
3. 成功响应
{
"code": "OK",
"message": "ok",
"request_id": "req_xxx",
"data": {
"items": [
{
"user_id": "163020",
"state": "on_mic",
"seat_no": 3,
"joinable": true,
"observed_at_ms": 1784265600000,
"room": {
"room_id": "100086",
"im_group_id": "100086",
"rtc_room_id": "100086",
"room_short_id": "886688",
"title": "Room name",
"owner_user_id": "12001",
"host_user_id": "12001",
"mode": "voice",
"cover_url": "https://cdn.example.com/room-cover.png",
"background_url": "https://cdn.example.com/room-bg.png",
"online_count": 56,
"seat_count": 10,
"locked": true
}
},
{
"user_id": "163021",
"state": "not_on_mic",
"seat_no": 0,
"joinable": false,
"observed_at_ms": 1784265600000,
"room": null
}
],
"server_time_ms": 1784265600123
}
}
字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
items[].user_id |
string | 系统用户 ID;JSON 中按字符串返回 |
items[].state |
string | on_mic 或 not_on_mic |
items[].seat_no |
int | 当前麦位编号;未上麦为 0 |
items[].joinable |
bool | 当前 viewer 是否允许通过该入口尝试进房 |
items[].observed_at_ms |
int64 | 本批状态完成判定时的 UTC epoch ms |
items[].room |
object/null | 仅 on_mic && joinable 时非空 |
server_time_ms |
int64 | 服务端本批响应时间,UTC epoch ms |
房间字段可以直接构造现有 VoiceRoomEntryArgs:
room_id是业务房间主键。im_group_id当前等于room_id。rtc_room_id当前使用 TRTC string room ID,等于room_id。- 当前房间模型没有独立主持人字段,
host_user_id与owner_user_id一致。 locked=true表示密码房;点击后继续复用现有密码输入和进房流程,不能在个人页自行索取或缓存密码。
4. Flutter 展示和刷新规则
只有下面四个条件全部成立时显示 Live:
final showLive = item.state == 'on_mic' &&
item.joinable &&
item.room != null &&
item.room!.roomId.isNotEmpty;
点击时:
- 调用现有
VoiceRoomNavigation.open()。 - 用
room构造VoiceRoomEntryArgs。 entrySource使用profile_card_live_badge。- 正常调用
POST /api/v1/rooms/join;如果用户已经下麦但房间仍允许进入,可以正常进入。 - 进房返回房间关闭、封禁、密码错误等业务错误时,移除当前 Live 状态并按现有错误规则提示。
刷新时机:
- 首次进入客态个人信息页。
- App 从后台回到前台且个人信息页仍可见。
- 从语音房返回个人信息页。
- 用户手动刷新个人信息页。
不要轮询、持久化或使用上一次成功结果兜底。接口失败时只隐藏 Live,不影响个人信息页其他资料。
5. 后端状态边界
on_mic表示房间仍为active、目标用户仍在房间在线集合中,并且占用一个当前有效麦位。MicUp后的pending_publish和 RTC 已确认的publishing都属于已占麦。- 房主或管理员只有实际占用麦位时才算上麦;身份本身不算。
- 同一 App 的
room_user_presence使用(app_code, user_id)主键定位候选房间,最终状态再由 Room Cell 快照确认。 - 跨
app_code房间不会返回。 - viewer 被目标房间封禁、房间已关闭、presence 已滞后或快照事实不完整时,统一返回
not_on_mic + room:null,不泄露旧房间 ID。 - 密码房允许展示 Live,返回
locked=true,正式进房仍校验密码。 - 当前房间产品模型没有“隐藏房/隐身上麦”字段,用户关系也没有资料位置黑名单能力;本版不做不存在的状态推断。以后增加此类产品能力时,必须在后端权限判断中收敛后再返回,Flutter 不得自行判断。
6. 错误响应
| HTTP | code | 处理方式 |
|---|---|---|
| 400 | INVALID_USER_IDS |
修正参数;不要重试同一请求 |
| 401 | UNAUTHORIZED / ACCESS_TOKEN_EXPIRED |
走现有登录或刷新 token 流程 |
| 403 | PROFILE_REQUIRED |
先完成用户资料 |
| 503 | VOICE_ROOM_PRESENCE_UNAVAILABLE |
隐藏 Live;页面其他内容继续展示 |
示例:
{
"code": "INVALID_USER_IDS",
"message": "invalid user ids",
"request_id": "req_xxx"
}
排障日志只记录接口路径、目标 ID 数量、响应业务码和 request_id;不要记录 access token 或密码房密码。
7. 联调清单
- 未进房、只在房内未上麦:不显示 Live。
- 在自己的房间或其他人的房间实际占麦:显示 Live,并返回实际所在房间。
pending_publish、publishing:都显示 Live。- 下麦、离房、被踢或关房后重新请求:返回
not_on_mic。 - 密码房:显示 Live,点击后进入既有密码流程。
- viewer 被目标房间封禁、跨 App、查询本人:不返回房间定位。
- 一批中混合上麦、未上麦和重复用户:每个去重用户一条结果,顺序稳定。
- 查询成功后立即下麦:点击仍以正式进房接口结果为准。