first commit

This commit is contained in:
2026-09-21 19:21:35 +08:00
commit 6c944c4ffd
2733 changed files with 296956 additions and 0 deletions
+727
View File
@@ -0,0 +1,727 @@
# 疯狂转盘 前端接口文档
> **版本**: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>③ 进行中回合不强制结算,玩家可继续看结果 |
---