9.4 KiB
9.4 KiB
房内猜拳 Flutter 对接
本文只记录房内猜拳 App 端 HTTP 接口和腾讯 IM 自定义消息字段。独立猜拳本阶段不接入。
1. 基本约定
- 所有 HTTP 地址都有
/api/v1前缀。 - 所有接口都需要
Authorization: Bearer <access_token>。 - 成功响应统一是 gateway envelope:
{
"code": "OK",
"message": "ok",
"request_id": "req_xxx",
"data": {}
}
- 所有时间字段都是 Unix epoch milliseconds。
- Flutter 模型里用户 ID、挑战 ID、礼物 ID 建议统一按
String保存。 - HTTP 返回的发起人和应战人资料在
challenge.initiator.user、challenge.challenger.user。 - IM 里的发起人和应战人也必须带
nickname和avatar;客户端不要为了基础展示再查用户资料。
2. 通用挑战单字段
challenge 字段在列表、详情、发起、应战接口中结构一致。
| 字段 | 类型 | 说明 |
|---|---|---|
challenge_id |
string | 挑战单 ID。 |
room_id |
string | 房间 ID。 |
region_id |
number | 用户语区 ID。 |
status |
string | pending、matched、revealing、finished、timeout、settlement_failed、cancelled。 |
stake_gift_id |
string | 下注礼物 ID,Flutter 优先用这个字段。 |
stake_gift_id_number |
number | 下注礼物 ID 数字值。 |
stake_coin |
number | 本局礼物对应金币价值。 |
initiator |
object | 发起人。 |
challenger |
object | 应战人;pending 时可能为空用户。 |
winner_user_id |
string | 胜者用户 ID;平局或未结算为空或 0。 |
winner_user_id_number |
number | 胜者用户 ID 数字值。 |
settlement_status |
string | 结算状态,例如 pending、settled、failed。 |
failure_reason |
string | 结算失败原因。 |
timeout_at_ms |
number | 无人应战自动过期时间。 |
reveal_at_ms |
number | 揭晓时间。 |
created_at_ms |
number | 创建时间。 |
matched_at_ms |
number | 应战成功时间。 |
settled_at_ms |
number | 结算时间。 |
updated_at_ms |
number | 更新时间。 |
initiator 和 challenger 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
user_id |
string | 用户 ID,Flutter 优先用这个字段。 |
user_id_number |
number | 用户 ID 数字值。 |
gesture |
string | rock、paper、scissors。 |
result |
string | win、lose、draw;未结算时为空。 |
balance_after |
number | 结算后的金币余额。 |
joined_at_ms |
number | 参与时间。 |
user.user_id |
string | 展示用户 ID。 |
user.display_user_id |
string | 短号或展示号。 |
user.nickname |
string | 昵称;发起人和应战人都要有。 |
user.avatar |
string | 头像;发起人和应战人都要有。 |
3. 查询配置
地址:
GET /api/v1/games/room-rps/config
参数:无。
返回值:
| 字段 | 类型 | 说明 |
|---|---|---|
config.status |
string | active 或 disabled。 |
config.challenge_timeout_ms |
number | 发起后无人应战的超时时间,默认 10 分钟。 |
config.reveal_countdown_ms |
number | 双方出拳后的揭晓倒计时,默认 3 秒。 |
config.stake_gifts |
array | 礼物下注档位,固定 4 档。 |
server_time_ms |
number | 服务端时间。 |
stake_gifts 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
gift_id |
string | 礼物 ID,Flutter 优先用这个字段提交。 |
gift_id_number |
number | 礼物 ID 数字值。 |
gift_name |
string | 礼物名称。 |
gift_icon_url |
string | 礼物图标。 |
gift_price_coin |
number | 礼物价格金币。 |
enabled |
bool | 是否启用。 |
sort_order |
number | 排序。 |
相关 IM:无。
4. 查询房间挑战单
地址:
GET /api/v1/games/room-rps/challenges
参数:
| 字段 | 位置 | 必填 | 说明 |
|---|---|---|---|
room_id |
query | 是 | 房间 ID。 |
status |
query | 否 | 挑战状态。 |
page_size |
query | 否 | 页大小,默认 20。 |
cursor |
query | 否 | 下一页游标。 |
返回值:
| 字段 | 类型 | 说明 |
|---|---|---|
challenges |
array | 挑战单列表,结构见通用挑战单字段。 |
next_cursor |
string | 下一页游标。 |
page_size |
number | 本次页大小。 |
server_time_ms |
number | 服务端时间。 |
相关 IM:无。客户端漏掉 IM 后,用这个接口补拉当前房间挑战单。
5. 发起挑战
地址:
POST /api/v1/games/room-rps/challenges/create
Content-Type: application/json
参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
room_id |
string | 是 | 房间 ID。 |
gift_id |
number | 是 | 后台配置的礼物档位 ID。 |
gesture |
string | 是 | rock、paper、scissors。 |
请求示例:
{
"room_id": "room_1001",
"gift_id": 10001,
"gesture": "rock"
}
返回值:
| 字段 | 类型 | 说明 |
|---|---|---|
challenge |
object | 挑战单,结构见通用挑战单字段。 |
server_time_ms |
number | 服务端时间。 |
相关 IM:room_rps_challenge_created。
6. 应战
地址:
POST /api/v1/games/room-rps/challenges/{challenge_id}/accept
Content-Type: application/json
参数:
| 字段 | 位置 | 必填 | 说明 |
|---|---|---|---|
challenge_id |
path | 是 | 挑战单 ID。 |
gesture |
body | 是 | rock、paper、scissors。 |
请求示例:
{
"gesture": "paper"
}
返回值:
| 字段 | 类型 | 说明 |
|---|---|---|
challenge |
object | 应战后的挑战单,结构见通用挑战单字段。 |
server_time_ms |
number | 服务端时间。 |
相关 IM:
room_rps_challenge_acceptedroom_rps_reveal_countdownroom_rps_finished
7. 查询挑战详情
地址:
GET /api/v1/games/room-rps/challenges/{challenge_id}
参数:
| 字段 | 位置 | 必填 | 说明 |
|---|---|---|---|
challenge_id |
path | 是 | 挑战单 ID。 |
返回值:
| 字段 | 类型 | 说明 |
|---|---|---|
challenge |
object | 挑战单,结构见通用挑战单字段。 |
server_time_ms |
number | 服务端时间。 |
相关 IM:无。客户端收到 IM 后,可以用这个接口刷新挑战事实。
8. 腾讯 IM 字段
房间群消息使用腾讯 IM TIMCustomElem,data 是 JSON 字符串。Flutter 只需要解析下面字段。
通用字段:
| 字段 | 类型 | 说明 |
|---|---|---|
event_id |
string | IM 事件 ID,客户端用它去重。 |
event_type |
string | 事件类型。 |
room_id |
string | 房间 ID。 |
challenge_id |
string | 挑战单 ID。 |
server_time_ms |
number | 服务端时间。 |
challenge |
object | 挑战单快照,结构见通用挑战单字段。 |
challenge.initiator.user 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
user_id |
string | 是 | 发起人用户 ID。 |
display_user_id |
string | 否 | 发起人展示号。 |
nickname |
string | 是 | 发起人昵称。 |
avatar |
string | 是 | 发起人头像。 |
challenge.challenger.user 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
user_id |
string | 应战后是 | 应战人用户 ID。 |
display_user_id |
string | 否 | 应战人展示号。 |
nickname |
string | 应战后是 | 应战人昵称。 |
avatar |
string | 应战后是 | 应战人头像。 |
IM 事件:
event_type |
触发时机 | Flutter 处理 |
|---|---|---|
room_rps_challenge_created |
用户发起挑战后 | 展示 [PK] 入口、发起人头像昵称、礼物和倒计时。此时 challenger 可以为空。 |
room_rps_challenge_accepted |
有用户应战后 | 锁定挑战入口,展示双方头像昵称。 |
room_rps_reveal_countdown |
双方出拳后 | 播放 3 秒揭晓动画,展示双方头像昵称。 |
room_rps_finished |
结算完成或平局退款后 | 展示胜负、双方头像昵称、余额或失败提示。 |
IM 示例:
{
"event_id": "room_rps_finished:rps_10001",
"event_type": "room_rps_finished",
"room_id": "room_1001",
"challenge_id": "rps_10001",
"server_time_ms": 1780000003000,
"challenge": {
"challenge_id": "rps_10001",
"room_id": "room_1001",
"status": "finished",
"stake_gift_id": "10001",
"stake_gift_id_number": 10001,
"stake_coin": 100,
"initiator": {
"user_id": "10001",
"user_id_number": 10001,
"gesture": "rock",
"result": "lose",
"balance_after": 900,
"joined_at_ms": 1780000000000,
"user": {
"user_id": "10001",
"display_user_id": "880001",
"nickname": "Alice",
"avatar": "https://cdn.example/alice.png"
}
},
"challenger": {
"user_id": "10002",
"user_id_number": 10002,
"gesture": "paper",
"result": "win",
"balance_after": 1200,
"joined_at_ms": 1780000001000,
"user": {
"user_id": "10002",
"display_user_id": "880002",
"nickname": "Bob",
"avatar": "https://cdn.example/bob.png"
}
},
"winner_user_id": "10002",
"winner_user_id_number": 10002,
"settlement_status": "settled",
"timeout_at_ms": 1780000600000,
"reveal_at_ms": 1780000003000,
"created_at_ms": 1780000000000,
"matched_at_ms": 1780000001000,
"settled_at_ms": 1780000003000,
"updated_at_ms": 1780000003000
}
}