Files
henan-backend/docs/疯狂转盘接口文档.md
T
2026-09-21 19:21:35 +08:00

728 lines
23 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.
# 疯狂转盘 前端接口文档
> **版本**:v2.0
> **更新时间**:2025-01
> **适用前端**:Web/H5/小程序
> **Base URL**:`{host}/api/wheel`
---
## 📋 目录
1. [玩法概述](#一玩法概述)
2. [通用约定](#二通用约定)
3. [接口清单](#三接口清单)
4. [接口详情](#四接口详情)
5. [时间轴使用指南](#五时间轴使用指南)
6. [前端对接要点](#六前端对接要点)
---
## 一、玩法概述
疯狂转盘是一款 **选颜色+符号 → 下注 → 转盘停 → 命中得饰品** 的真人轮盘游戏。
### 核心规则
| 项目 | 说明 |
|------|------|
| **盘面结构** | 内外圈各 24 格,索引一一对应<br>• 外圈符号:固定布局(A金/B红/C紫/D蓝)<br>• 内圈颜色:每轮随机排布(金6/红8/紫10) |
| **下注方式** | 选 1 个「颜色×符号」组合 + 1 个下注额<br>**每轮每人最多 50 注** |
| **下注额档位** | 10 档:5 / 10 / 20 / 50 / 100 / 200 / 500 / 1000 / 2000 / 5000 元 |
| **倍率** | 12 个倍率(3 色 × 4 符号),所有档位共用<br>例:gold+D 倍率=22,押 100 元中奖得 2200 元 |
| **命中判定** | 下注的 `color+symbol` == 开奖的 `resultColor+resultSymbol` |
| **中奖奖励** | 饰品价值 = **下注额 × 倍率**<br>直接进背包,无需选择"保留/分解" |
| **未中奖励** | 每注发 **0.01 元安慰饰品**(保证每注必有产出) |
| **决策池** | 单一真实奖池,所有人同一个落点<br>• `real`(真实池,参与落点/RTP 决策)= 普通(02)+主播(01)+招商(04)+卡商(05)<br>• `display`(展示,可下注/返奖但不入真实池)= 机器人(03)+白号(06) |
### 一局生命周期
```
newRound 创建
↓
下注期 (30s) ← 玩家可调用 /dobet 下注
↓
封盘期 (2s) ← 不再接受下注,倒计时"即将开奖"
↓
开奖 + 动画 (7s) ← 后端出结果,前端播转盘动画
↓
结果展示 → 下一局
```
---
## 二、通用约定
### 2.1 请求方式
- **协议**:HTTPS
- **Method**:全部 `POST`
- **Content-Type**:`application/json`
- **鉴权**:`Authorization: Bearer {token}`(登录后从响应头或登录接口获取)
> ⚠️ **重要**:`userId` 由后端从 token 解析,**客户端不要传 userId 参数**。
### 2.2 统一响应结构
```json
{
"code": 200,
"msg": "操作成功",
"data": {}
}
```
| code | 含义 | 前端处理 |
|------|------|----------|
| 200 | 成功 | 正常处理 data |
| 500 | 业务失败 | Toast 显示 msg |
| 701 | 未实名认证 | 弹实名认证弹窗 |
| 702 | 账户余额不足 | 提示充值 |
| 703 | 玩家未充值,不能游玩 | 引导首充 |
### 2.3 货币单位
- 所有金额字段为 **String 类型**,单位:**元**(精确到小数点后 2 位)
- 示例:`"balance": "9800.50"` 表示 9800.50 元
### 2.4 时间格式
- **时间戳**:`Long` 类型,**秒级** Unix 时间戳(如 `1738300000`)
- **时间字符串**:`yyyy-MM-dd HH:mm:ss`(东八区)
---
## 三、接口清单
| # | 接口名称 | 路径 | 用途 | 调用时机 |
|---|---------|------|------|---------|
| 1 | ~~获取游戏配置~~ | ~~`/game_config`~~ | **已废弃**,数据已合并到 `/last_round_info` | ~~进入游戏页时调用 1 次~~ |
| 2 | 投注 | `/dobet` | 下注一笔 | 玩家点击下注按钮 |
| 3 | 获取当前局状态 | `/last_round_info` | **一次拿全**:配置+状态+开奖+下注 | **轮询**(1-2 秒间隔) |
| 4 | 我的下注记录 | `/history_bet_info` | 我的全部下注记录(中奖+未中奖,分页) | 打开"记录"页 |
| 5 | 全服中奖记录 | `/round_history_bet_info` | 全服中奖公示(只含真正命中,分页) | 打开"中奖榜"页 |
| 6 | 历史开奖结果 | `/round_results` | 每一轮的开奖符号(分页) | 打开"历史开奖"页 |
---
## 四、接口详情
### 4.1 ~~获取游戏配置~~ (已废弃)
> **⚠️ 已废弃**:本接口数据已全部合并到 `/last_round_info`,前端只需轮询一个接口即可。
> 旧接口保留仅为兼容旧版前端,新前端请直接使用 `/last_round_info`。
---
### 4.2 投注
**`POST /api/wheel/dobet`**
下注一笔。**每轮每人上限 50 注**。
#### 请求参数
```json
{
"bet": 100,
"color": "gold",
"symbol": "D"
}
```
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `bet` | Integer | ✅ | 下注额,必须是 10 档之一 |
| `color` | String | ✅ | 内圈色:`gold` / `red` / `purple` |
| `symbol` | String | ✅ | 外圈符:`A` / `B` / `C` / `D` |
#### 响应示例
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"roundId": 10086,
"cost": "100.00",
"balance": "9700.50",
"credits": "1200.00"
}
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `roundId` | Long | 本回合 ID |
| `cost` | String | 本次扣款(= 下注额) |
| `balance` | String | 下注后余额(金币) |
| `credits` | String | 下注后积分 |
#### 常见错误
| code | msg | 场景 |
|------|-----|------|
| 500 | 网站维护中...... | 全站维护 |
| 500 | 疯狂转盘维护中...... | 转盘维护 |
| 500 | 游戏不在投注期 | 已封盘/开奖中 |
| 500 | 每轮最多下注50注 | 超出上限 |
| 500 | 该下注组合未配置奖品 | 矩阵缺失(联系运营) |
| 702 | 账户余额不足 | 需充值 |
| 703 | 玩家未充值不能游玩任何游戏 | 需首充 |
---
### 4.3 获取当前局状态
**`POST /api/wheel/last_round_info`**
**核心接口**,轮询调用(建议 1-2 秒间隔),**一次返回全部数据**:游戏配置 + 当前回合状态 + 开奖结果 + 我的下注。
#### 请求参数
```json
{}
```
#### 响应示例
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"roundId": 10086,
"periodNo": 202501011,
"serverTime": 1738300050,
"startTime": 1738300000,
"bettedTime": 1738300030,
"spinTime": 1738300032,
"endTime": 1738300039,
"status": "spined",
"outerSymbols": ["A","D","C","D","B","D","C","D","B","C","D","C","A","D","C","D","C","D","B","D","C","D","C","D"],
"bets": [5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000],
"myPoolType": "real",
"rewardMatrix": [
{
"betAmount": 5,
"color": "gold",
"symbol": "D",
"multiplier": 22,
"prizeValue": "110.00",
"prizeName": "黄金玫瑰",
"prizeGrade": 3,
"prizeExterior": "崭新出厂",
"prizeImage": "https://example.com/prize.png",
"prizeLevelImg": "https://example.com/level3.png"
}
],
"innerColors": ["gold","gold","red","purple","purple","red","gold","purple","red","purple","gold","purple","red","purple","gold","gold","purple","purple","red","gold","purple","red","purple"],
"resultIndex": 5,
"resultColor": "gold",
"resultSymbol": "D",
"totalWin": "2200.00",
"userBets": [
{
"color": "gold",
"symbol": "D",
"count": 3,
"totalBet": "300.00"
},
{
"color": "red",
"symbol": "A",
"count": 1,
"totalBet": "50.00"
}
],
"winResult": [
{
"color": "gold",
"symbol": "D",
"hit": true,
"boxRecordId": 123456,
"prizeName": "黄金玫瑰",
"prizeImage": "https://example.com/prize.png",
"prizeGrade": 5,
"prizeLevelImg": "https://example.com/level5.png",
"prizeExterior": "崭新出厂",
"prizeValue": "2200.00"
},
{
"color": "red",
"symbol": "A",
"hit": false,
"boxRecordId": 123457,
"prizeName": "安慰饰品",
"prizeImage": "https://example.com/consolation.png",
"prizeGrade": 1,
"prizeLevelImg": "https://example.com/level1.png",
"prizeExterior": "崭新出厂",
"prizeValue": "0.01"
}
]
}
}
```
#### 响应字段说明
**游戏配置字段**(原 `/game_config` 接口数据,现已合并):
| 字段 | 类型 | 说明 |
|------|------|------|
| `outerSymbols` | Array\<String\> | 外圈 24 格符号固定布局(`A`/`B`/`C`/`D`)<br>例:`["A","D","C","D",...]` |
| `bets` | Array\<Integer\> | 10 档下注额 |
| `myPoolType` | String | 当前用户所属决策池<br>`real`:真实池(普通02/主播01/招商04/卡商05,参与落点与 RTP)<br>`display`:展示(机器人03/白号06,可下注/返奖但不入真实池)<br>`null`:不可参与(如超管99) |
| `rewardMatrix` | Array | 奖励矩阵(120 条,10 档 × 3 色 × 4 符号)<br>每条含 `betAmount`/`color`/`symbol`/`multiplier` 及饰品信息(名称/图片/品质图片/磨损度/价格) |
**当局状态字段**:
| 字段 | 类型 | 说明 |
|------|------|------|
| `roundId` | Long | 回合 ID |
| `periodNo` | Long | 全局唯一期号 |
| `serverTime` | Long | **服务器当前时间**(秒级时间戳)<br>用于和其他时间点对比算倒计时 |
| `startTime` | Long | 本局开始时间 |
| `bettedTime` | Long | **封盘时间点** = startTime + 下注时间<br>到这个时刻后不能再下注 |
| `spinTime` | Long | **开奖时间点** = bettedTime + 封盘时间<br>到这个时刻后开始播转盘动画 |
| `endTime` | Long | **本局结束时间** = spinTime + 开奖动画时间<br>动画播完、下一局即将开始 |
| `status` | String | `betting`:投注期<br>`spined`:封盘/开奖中 |
| `innerColors` | Array\<String\> | **本轮内圈 24 色实际排列**(`gold`/`red`/`purple`)<br>例:`["gold","red","purple",...]` 用于渲染盘面 |
| `resultIndex` | Integer | 开奖格子索引(0-23)<br>未开奖时为 `null` |
| `resultColor` | String | 开奖颜色 `gold`/`red`/`purple`<br>未开奖时为 `null` |
| `resultSymbol` | String | 开奖符号 `A`/`B`/`C`/`D`<br>未开奖时为 `null` |
| `totalWin` | String | 当前用户本轮总返奖(饰品价值合计) |
| `userBets` | Array | **当前用户本轮下注汇总**(按颜色+符号聚合,见下表) |
| `winResult` | Array | **当前用户本轮发奖明细**(每注一条,见下表) |
**userBets 结构**(我的下注汇总,按颜色+符号聚合):
| 字段 | 类型 | 说明 |
|------|------|------|
| `color` | String | 下注的颜色 |
| `symbol` | String | 下注的符号 |
| `count` | Integer | 下注次数 |
| `totalBet` | String | 总下注额 |
**winResult 结构**(我的发奖明细,每注一条):
| 字段 | 类型 | 说明 |
|------|------|------|
| `color` | String | 下注的颜色 |
| `symbol` | String | 下注的符号 |
| `hit` | Boolean | 是否命中(`true`=中奖矩阵饰品,`false`=安慰饰品) |
| `boxRecordId` | Long | **背包记录ID**(用于调用分解/出售接口) |
| `prizeName` | String | 实际发放的饰品名称 |
| `prizeImage` | String | 饰品图片 URL |
| `prizeGrade` | Integer | 饰品品质等级 |
| `prizeLevelImg` | String | 饰品品质图片 URL |
| `prizeExterior` | String | 饰品磨损度 |
| `prizeValue` | String | 饰品价格(命中=下注额×倍率;安慰=0.01) |
> 💡 **前端使用提示**:
> - 未开奖时 `winResult` 为空
> - 已开奖后,`winResult` 每注一条:`hit=true` 是中奖饰品,`hit=false` 是安慰饰品(0.01元)
> - 使用 `boxRecordId` 调用分解/出售接口
---
### 4.4 我的下注记录
**`POST /api/wheel/history_bet_info`**
当前登录用户自己的全部下注记录(中奖+未中奖),分页。未中奖注单(`win = 0.01` 安慰奖)的饰品字段为 `null`。
#### 请求参数
```json
{
"pageNum": 1,
"pageSize": 10
}
```
#### 响应示例
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"total": 25,
"rows": [
{
"periodNo": 2026090725038,
"endTime": "2026-09-07 09:14:49",
"userId": 666299,
"nickName": "李四2",
"avatar": "/profile/upload/xxx.png",
"bet": "5.00",
"betSymbol": "D",
"win": "40.00",
"betCount": 3,
"prizeGrade": 1,
"prizeName": "某某饰品",
"prizeImage": "/profile/upload/xxx.png"
}
]
}
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `total` | Long | 总中奖注数 |
| `rows` | Array | 中奖注单列表 |
| `rows[].periodNo` | Long | 完整期号 |
| `rows[].endTime` | String | 回合结束时间(yyyy-MM-dd HH:mm:ss) |
| `rows[].userId` | Long | 用户 ID |
| `rows[].nickName` | String | 用户昵称(完整,不脱敏) |
| `rows[].avatar` | String | 用户头像 |
| `rows[].bet` | String | 单注下注额 |
| `rows[].betSymbol` | String | 中奖符号 |
| `rows[].win` | String | 中奖额 |
| `rows[].betCount` | Integer | 该中奖符号下注次数 |
| `rows[].prizeGrade` | Integer | 饰品品质等级(对应 tt_ornaments_level.id:1金/2红/3紫/4蓝) |
| `rows[].prizeName` | String | 饰品名称 |
| `rows[].prizeImage` | String | 饰品图片 |
---
### 4.5 全服中奖记录
**`POST /api/wheel/round_history_bet_info`**
全服中奖公示(只保留真正命中 `win > 0.01` 的注单,排除 0.01 安慰奖),分页。结构与 `history_bet_info` 完全一致,只是数据范围为全服所有用户。
#### 请求参数
```json
{
"pageNum": 1,
"pageSize": 30
}
```
#### 响应示例
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"total": 99,
"rows": [
{
"periodNo": 2026090725038,
"endTime": "2026-09-07 09:14:49",
"userId": 666299,
"nickName": "李四2",
"avatar": "/profile/upload/xxx.png",
"bet": "5.00",
"betSymbol": "D",
"win": "40.00",
"betCount": 3,
"prizeGrade": 1,
"prizeName": "某某饰品",
"prizeImage": "/profile/upload/xxx.png"
}
]
}
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `total` | Long | 总中奖注数 |
| `rows` | Array | 中奖注单列表 |
| `rows[].periodNo` | Long | 完整期号 |
| `rows[].endTime` | String | 回合结束时间 |
| `rows[].userId` | Long | 中奖用户 ID |
| `rows[].nickName` | String | 中奖用户昵称(完整,不脱敏) |
| `rows[].avatar` | String | 中奖用户头像 |
| `rows[].bet` | String | 单注下注额 |
| `rows[].betSymbol` | String | 中奖符号 |
| `rows[].win` | String | 中奖额 |
| `rows[].betCount` | Integer | 该中奖符号下注次数 |
| `rows[].prizeGrade` | Integer | 饰品品质等级(对应 tt_ornaments_level.id:1金/2红/3紫/4蓝) |
| `rows[].prizeName` | String | 饰品名称 |
| `rows[].prizeImage` | String | 饰品图片 |
---
### 4.6 历史开奖结果
**`POST /api/wheel/round_results`**
获取每一轮的开奖符号(用于展示历史开奖记录,如右侧滚动的历史中奖列表)。
#### 请求参数
```json
{
"pageNum": 1,
"pageSize": 20
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `pageNum` | Integer | 否 | 页码(默认 1) |
| `pageSize` | Integer | 否 | 每页条数(默认 20) |
#### 响应示例
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"rows": [
{
"periodNo": 2025010100086,
"date": "20250101",
"roundId": 86,
"resultIndex": 5,
"resultColor": "gold",
"resultSymbol": "D",
"endTime": "2025-01-01 12:15:39"
},
{
"periodNo": 2025010100085,
"date": "20250101",
"roundId": 85,
"resultIndex": 12,
"resultColor": "red",
"resultSymbol": "A",
"endTime": "2025-01-01 12:15:00"
}
],
"total": 2156
}
}
```
#### 响应字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `rows` | Array | 历史开奖记录列表 |
| `rows[].periodNo` | Long | **全局唯一期号**(13位,前8位=日期yyyyMMdd,后5位=局号) |
| `rows[].date` | String | **日期**(yyyyMMdd,从 periodNo 拆分而来) |
| `rows[].roundId` | Long | **当天局号**(从 periodNo 拆分而来) |
| `rows[].resultIndex` | Integer | 开奖格子索引(0-23) |
| `rows[].resultColor` | String | 开奖颜色(gold/red/purple) |
| `rows[].resultSymbol` | String | 开奖符号(A/B/C/D) |
| `rows[].endTime` | String | 本局结束时间(yyyy-MM-dd HH:mm:ss) |
| `total` | Long | 总记录数 |
#### 前端展示建议
```javascript
// 展示期号
function formatPeriodNo(periodNo) {
const str = String(periodNo).padStart(13, '0');
const year = str.slice(0, 4);
const month = str.slice(4, 6);
const day = str.slice(6, 8);
const round = parseInt(str.slice(8)); // 去前导零
return `${year}-${month}-${day}-${round}`;
}
// 渲染列表
data.rows.forEach(item => {
// 期号:2025-01-01-86
const periodText = formatPeriodNo(item.periodNo);
// 开奖结果:金色箱子 × 15
const symbolIcon = getSymbolIcon(item.resultColor, item.resultSymbol);
renderHistoryItem(periodText, symbolIcon);
});
```
---
## 五、时间轴使用指南
**核心**:后端返回的是**具体时间点**(startTime/bettedTime/spinTime/endTime),前端根据这些时间点和 `serverTime` 做倒计时和阶段切换。
### 一局的完整时间轴
```
startTime (本局创建)
│
├─ 【下注期】serverTime < bettedTime
│ 前端显示:倒计时 "距封盘 X 秒",接受下注
│ 倒计时 = bettedTime - serverTime
│
├─ bettedTime (封盘时刻)
│
├─ 【封盘期】bettedTime ≤ serverTime < spinTime
│ 前端显示:"封盘中",倒计时 "X 秒后开奖"
│ 倒计时 = spinTime - serverTime
│
├─ spinTime (开奖时刻)
│
├─ 【开奖中】spinTime ≤ serverTime < endTime
│ 前端显示:播转盘旋转动画
│ 指针停在 resultIndex 格,显示 resultColor+resultSymbol
│ 动画时长 = endTime - spinTime(由后台"开奖动画时间"配置)
│
├─ endTime (本局结束)
│
└─ 【等待下一局】serverTime ≥ endTime
前端显示:倒计时 "下一局 X 秒后开始"
继续轮询,拿到新 roundId 进入新一轮
```
### 前端倒计时计算公式
| 阶段 | 判断条件 | 倒计时公式 | 显示文案 |
|------|---------|-----------|---------|
| **下注期** | `serverTime < bettedTime` | `bettedTime - serverTime` | "距封盘 X 秒" |
| **封盘期** | `bettedTime ≤ serverTime < spinTime` | `spinTime - serverTime` | "X 秒后开奖" |
| **开奖中** | `spinTime ≤ serverTime < endTime` | 播动画 | "转盘旋转中" |
| **结果展示** | `serverTime ≥ endTime` | `下一局startTime - serverTime` | "下一局 X 秒后" |
### 关键提醒
1. **后端不返回时长配置**(下注时间/封盘时间/动画时间),只返回时间点。前端不需要自己算,直接用时间点差值。
2. **时间点会随后台配置变化**:运营改"下注时间"从 30→50 秒,新局的 `bettedTime` 就会自动延后,前端倒计时自动变长。
3. **开奖动画时长** = `endTime - spinTime`,这个窗口内播动画 + 展示结果。
---
## 六、前端对接要点
### 6.1 进入游戏页
```javascript
// 只需轮询 /last_round_info,一次拿到配置+状态
setInterval(async () => {
const round = await getLastRoundInfo();
// 首次进入:用配置数据渲染静态元素
if (firstTime) {
renderWheel(round.outerSymbols);
renderBetPanel(round.bets, round.rewardMatrix);
firstTime = false;
}
// 每次轮询:更新动态状态
updateRoundState(round);
}, 2000);
```
```
### 6.2 轮询当前局状态
```javascript
// 每 1-2 秒调用一次
setInterval(async () => {
const round = await getLastRoundInfo();
// 根据 status 和时间点切换 UI
if (round.status === 'betting') {
if (round.serverTime < round.bettedTime) {
// 下注期
showCountdown('距封盘', round.bettedTime - round.serverTime);
enableBetting(true);
} else {
// 封盘期(status 可能还未切到 spined)
showCountdown('即将开奖', round.spinTime - round.serverTime);
enableBetting(false);
}
} else if (round.status === 'spined') {
// 已开奖
if (round.resultIndex !== null) {
// 播转盘动画,指针停在 resultIndex
playSpinAnimation(round.resultIndex, round.innerColors);
// 展示发奖明细(winResult 每注一条,hit 区分中奖/安慰)
showWinResult(round.winResult, round.totalWin);
}
// 倒计时下一局
if (round.serverTime >= round.endTime) {
showCountdown('下一局', estimateNextRound());
}
}
}, 2000);
```
### 6.3 下注
```javascript
async function doBet(color, symbol, bet) {
try {
const res = await api.post('/api/wheel/dobet', { color, symbol, bet });
if (res.code === 200) {
// 扣款成功,更新余额
updateBalance(res.data.balance, res.data.credits);
// Toast 提示
showToast('下注成功');
}
} catch (err) {
if (err.code === 702) {
showToast('余额不足,请充值');
} else if (err.code === 500) {
showToast(err.msg); // "游戏不在投注期" / "每轮最多50注"
}
}
}
```
### 6.4 展示饰品信息
```javascript
// winResult 每注一条,hit 区分中奖/安慰
round.winResult.forEach(item => {
if (item.hit) {
// 中奖,展示矩阵饰品
showPrize({
name: item.prizeName,
image: item.prizeImage,
levelImg: item.prizeLevelImg,
exterior: item.prizeExterior,
value: item.prizeValue,
boxRecordId: item.boxRecordId
});
} else {
// 未中,展示安慰饰品
showConsolation(item.color, item.symbol);
}
});
```
### 6.5 渲染盘面(innerColors)
```javascript
// innerColors 是 24 个元素的数组,已经是 gold/red/purple
// 例:["gold","red","purple",...]
function renderWheel(innerColors, outerSymbols) {
for (let i = 0; i < 24; i++) {
const color = innerColors[i]; // 'gold' / 'red' / 'purple'
const symbol = outerSymbols[i]; // 'A' / 'B' / 'C' / 'D'
// 渲染第 i 格:内圈色 + 外圈符号
renderCell(i, color, symbol);
}
}
```
### 6.6 注意事项
| 注意项 | 说明 |
|-------|------|
| **单接口轮询** | 只需轮询 `/last_round_info`,配置数据已合并,无需单独调 `/game_config` |
| **不要自动重发 dobet** | 下注接口**非幂等**,失败时提示玩家手动重试 |
| **轮询间隔** | 建议 1-2 秒,不要过于频繁 |
| **时区** | 所有时间戳为东八区(UTC+8) |
| **饰品已入背包** | 中奖后饰品直接进背包,无需"保留/分解"抉择<br>要兑现走通用背包分解接口 |
| **维护模式** | 后台"游戏关闭"开关打开后:<br>① 新局无法下注(`dobet` 返回 500 维护提示)<br>② 轮询接口返回 `isMaintenance: true`,前端应弹窗并跳转<br>③ 进行中回合不强制结算,玩家可继续看结果 |
---