323 lines
9.4 KiB
Markdown
323 lines
9.4 KiB
Markdown
# 房内猜拳 Flutter 对接
|
||
|
||
本文只记录房内猜拳 App 端 HTTP 接口和腾讯 IM 自定义消息字段。独立猜拳本阶段不接入。
|
||
|
||
## 1. 基本约定
|
||
|
||
- 所有 HTTP 地址都有 `/api/v1` 前缀。
|
||
- 所有接口都需要 `Authorization: Bearer <access_token>`。
|
||
- 成功响应统一是 gateway envelope:
|
||
|
||
```json
|
||
{
|
||
"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. 查询配置
|
||
|
||
地址:
|
||
|
||
```http
|
||
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. 查询房间挑战单
|
||
|
||
地址:
|
||
|
||
```http
|
||
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. 发起挑战
|
||
|
||
地址:
|
||
|
||
```http
|
||
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`。 |
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"room_id": "room_1001",
|
||
"gift_id": 10001,
|
||
"gesture": "rock"
|
||
}
|
||
```
|
||
|
||
返回值:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| `challenge` | object | 挑战单,结构见通用挑战单字段。 |
|
||
| `server_time_ms` | number | 服务端时间。 |
|
||
|
||
相关 IM:`room_rps_challenge_created`。
|
||
|
||
## 6. 应战
|
||
|
||
地址:
|
||
|
||
```http
|
||
POST /api/v1/games/room-rps/challenges/{challenge_id}/accept
|
||
Content-Type: application/json
|
||
```
|
||
|
||
参数:
|
||
|
||
| 字段 | 位置 | 必填 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `challenge_id` | path | 是 | 挑战单 ID。 |
|
||
| `gesture` | body | 是 | `rock`、`paper`、`scissors`。 |
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"gesture": "paper"
|
||
}
|
||
```
|
||
|
||
返回值:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| `challenge` | object | 应战后的挑战单,结构见通用挑战单字段。 |
|
||
| `server_time_ms` | number | 服务端时间。 |
|
||
|
||
相关 IM:
|
||
|
||
- `room_rps_challenge_accepted`
|
||
- `room_rps_reveal_countdown`
|
||
- `room_rps_finished`
|
||
|
||
## 7. 查询挑战详情
|
||
|
||
地址:
|
||
|
||
```http
|
||
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 示例:
|
||
|
||
```json
|
||
{
|
||
"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
|
||
}
|
||
}
|
||
```
|
||
|