# 多游戏独立期号系统更新说明
## 更新日期
2026-01-08
## 问题描述
原系统存在以下问题:
1. **所有游戏共用一个期号队列** - 骰子游戏和 Xóc Đĩa 无法同时运行
2. **开始下注时没有游戏选择** - 系统自动使用上一期的游戏ID
3. **前台获取期号不区分游戏** - 导致不同游戏显示相同期号
## 解决方案
实现**每个游戏独立维护自己的期号队列**,允许多个游戏同时运行。
---
## 修改的文件
### 1. 后端控制器
#### `App/Controllers/Admin/PeriodController.php`
**修改 `start()` 方法**:
- 添加 `game_id` 参数验证
- 检查该游戏是否有未结束的期号(而不是全局检查)
- 生成期号时传递 `game_id`
```php
public function start() {
// 接收 game_id 参数
$gameId = isset($data['game_id']) ? (int)$data['game_id'] : 0;
// 检查该游戏是否有未结束的期号
$activePeriod = $db->get('periods', '*', [
'game_id' => $gameId,
'status' => ['pending', 'locked', 'drawn']
]);
// 生成期号时传递 game_id
$periodNumber = $this->generatePeriodNumber($db, $gameId);
}
```
#### `App/Controllers/Web/PeriodController.php`
**修改 `getCurrent()` 方法**:
- 添加 `game_id` 参数验证
- 按游戏ID过滤期号
```php
public function getCurrent() {
$gameId = isset($_GET['game_id']) ? (int)$_GET['game_id'] : 0;
// 获取该游戏最新的期号
$currentPeriod = $db->get('periods', '*', [
'game_id' => $gameId,
'ORDER' => ['id' => 'DESC']
]);
}
```
#### `App/Controllers/Web/HomeController.php`
**已经正确实现**:
- `live()` 方法已经按 `game_id` 过滤期号
---
### 2. 后台视图
#### `App/Views/Admin/periods.php`
**添加游戏选择下拉框**:
```html
```
**修改开奖模态框**:
- 添加游戏类型隐藏字段
- 添加 Xóc Đĩa 硬币输入界面
- 根据游戏类型动态显示输入界面
```html
```
**修改JavaScript**:
```javascript
// 开始下注
async function startPeriod() {
const gameId = document.getElementById('startGameSelect').value;
if (!gameId) {
layer.msg('请先选择游戏', {icon: 2});
return;
}
fetch('/admin/periods/start', {
method: 'POST',
body: JSON.stringify({game_id: parseInt(gameId)})
});
}
// 打开开奖模态框
function openDrawPeriodModal(periodId) {
// 获取期号信息
fetch(`/admin/periods/${periodId}`)
.then(res => res.json())
.then(data => {
const gameId = data.data.game_id;
// 获取游戏类型
fetch(`/admin/games/${gameId}`)
.then(res => res.json())
.then(gameData => {
const gameType = gameData.data.type;
// 根据游戏类型显示不同界面
if (gameType === 'xocdia') {
document.getElementById('diceInputSection').classList.add('hidden');
document.getElementById('xocdiaInputSection').classList.remove('hidden');
} else {
document.getElementById('diceInputSection').classList.remove('hidden');
document.getElementById('xocdiaInputSection').classList.add('hidden');
}
});
});
}
// 提交开奖
async function submitDrawPeriod() {
const gameType = document.getElementById('drawGameType').value;
const data = {id: periodId, auto: false};
if (gameType === 'xocdia') {
// 收集硬币颜色
data.coins = [
document.getElementById('coin1').value,
document.getElementById('coin2').value,
document.getElementById('coin3').value,
document.getElementById('coin4').value
];
} else {
// 收集骰子点数
data.dice1 = parseInt(drawDice1.value);
data.dice2 = parseInt(drawDice2.value);
data.dice3 = parseInt(drawDice3.value);
}
fetch('/admin/periods/draw', {
method: 'POST',
body: JSON.stringify(data)
});
}
```
---
### 3. 前台视图
#### `App/Views/Web/live.php`
**修改期号轮询**:
```javascript
function checkPeriodStatus() {
fetch('/api/period/current?game_id=' + currentGameId)
.then(res => res.json())
.then(data => {
// 更新期号状态
});
}
```
---
## 使用流程
### 后台管理员操作
1. **开始新一期**
- 进入后台 → 期号管理
- 从下拉框选择游戏(骰子游戏 或 Xóc Đĩa)
- 点击"开始下注"按钮
- 系统创建该游戏的新期号
2. **录入开奖结果**
- 点击期号列表中的"录入开奖"按钮
- 系统自动识别游戏类型:
- **骰子游戏**:显示3个骰子输入框
- **Xóc Đĩa**:显示4个硬币颜色选择框
- 输入开奖结果并确认
3. **结算**
- 点击"确认结算"按钮
- 系统自动结算所有投注
- 可以继续为该游戏或其他游戏开始新一期
### 前台用户体验
1. **进入游戏**
- 访问首页,点击游戏卡片
- 系统自动获取该游戏的当前期号
2. **投注**
- 页面显示该游戏的倒计时和期号
- 只能对当前游戏的期号进行投注
3. **多游戏并行**
- 骰子游戏和 Xóc Đĩa 可以同时运行
- 每个游戏独立维护期号队列
- 互不干扰
---
## 数据库变更
**无需修改数据库结构**,现有的 `periods` 表已经包含 `game_id` 字段。
---
## 验证步骤
### 1. 后台验证
```bash
# 1. 访问后台期号管理
http://yourdomain.com/admin/periods
# 2. 选择"骰子游戏",点击"开始下注"
# 应该看到:新期号创建成功,期号格式为 G1YYYYMMDDNNNN
# 3. 选择"Xóc Đĩa",点击"开始下注"
# 应该看到:新期号创建成功,期号格式为 G2YYYYMMDDNNNN
# 4. 期号列表应该显示两个游戏的期号
```
### 2. 前台验证
```bash
# 1. 访问骰子游戏
http://yourdomain.com/live?game_id=1
# 应该看到:骰子游戏的期号和倒计时
# 2. 访问 Xóc Đĩa 游戏
http://yourdomain.com/live?game_id=2
# 应该看到:Xóc Đĩa 游戏的期号和倒计时
# 3. 两个游戏的期号应该不同
```
### 3. 开奖验证
```bash
# 1. 后台点击骰子游戏的"录入开奖"
# 应该看到:3个骰子输入框
# 2. 后台点击 Xóc Đĩa 的"录入开奖"
# 应该看到:4个硬币颜色选择框
```
---
## 故障排查
### 问题1:点击"开始下注"提示"请先选择游戏"
**原因**:未选择游戏
**解决**:从下拉框选择游戏后再点击按钮
---
### 问题2:前台显示"缺少游戏ID参数"
**原因**:URL 中没有 `game_id` 参数
**解决**:
```bash
# 错误的URL
http://yourdomain.com/live
# 正确的URL
http://yourdomain.com/live?game_id=1 # 骰子游戏
http://yourdomain.com/live?game_id=2 # Xóc Đĩa
```
---
### 问题3:开奖模态框显示错误的输入界面
**原因**:游戏类型获取失败
**解决**:
1. 检查游戏记录的 `type` 字段是否正确
```sql
SELECT id, name, type FROM games;
-- 应该看到:
-- 1 | Tài Xỉu | dice
-- 2 | Xóc Đĩa | xocdia
```
2. 如果类型不正确,执行修复SQL
```sql
UPDATE games SET type='xocdia' WHERE name LIKE '%Xóc%';
```
---
## 技术细节
### 期号格式
```
G{GameID}{YYYYMMDD}{NNNN}
示例:
G120260108001 # 骰子游戏(game_id=1)2026年1月8日第1期
G220260108001 # Xóc Đĩa(game_id=2)2026年1月8日第1期
```
### 期号状态流转
```
pending (待开奖)
↓
locked (已封盘)
↓
drawn (已开奖)
↓
settled (已结算)
```
### 并发控制
- 每个游戏独立检查是否有未结束的期号
- 允许多个游戏同时处于 `pending` 状态
- 不允许同一游戏有多个未结束的期号
---
## 兼容性说明
### 向后兼容
- 现有的骰子游戏功能完全保留
- 数据库结构无变更
- 前台URL需要添加 `game_id` 参数
### 升级建议
1. **更新前台链接**
- 将所有 `/live` 链接改为 `/live?game_id=X`
- 首页游戏卡片已经正确传递 `game_id`
2. **清理旧期号**(可选)
- 如果有未关联游戏的期号,建议手动关联
```sql
UPDATE periods SET game_id=1 WHERE game_id IS NULL OR game_id=0;
```
---
## 最后更新
2026-01-08
## 相关文档
- [Xóc Đĩa 集成指南](./XOCDIA_INTEGRATION_GUIDE.md)
- [宝塔快速部署修复指南](./BAOTA_DEPLOYMENT_QUICK_FIX.md)