Initial commit: 投注游戏平台初始化
This commit is contained in:
Executable
+957
@@ -0,0 +1,957 @@
|
||||
<?php
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Core\AdminBaseController;
|
||||
use Db\Database;
|
||||
|
||||
class PeriodController extends AdminBaseController {
|
||||
public function __construct() {
|
||||
$this->checkLogin();
|
||||
$this->checkAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 期号列表页面
|
||||
*/
|
||||
public function index() {
|
||||
$db = new Database();
|
||||
try {
|
||||
// 获取所有期号列表
|
||||
$periods = $db->select('periods', '*', [
|
||||
'ORDER' => ['id' => 'DESC'],
|
||||
'LIMIT' => 100
|
||||
]);
|
||||
|
||||
if (!is_array($periods)) {
|
||||
$periods = [];
|
||||
}
|
||||
|
||||
// 获取游戏列表(用于关联显示)
|
||||
$games = [];
|
||||
$gamesList = [];
|
||||
try {
|
||||
$gamesList = $db->select('games', ['id', 'name'], [
|
||||
'status' => 1,
|
||||
'ORDER' => ['id' => 'ASC']
|
||||
]);
|
||||
if (is_array($gamesList)) {
|
||||
foreach ($gamesList as $game) {
|
||||
$games[$game['id']] = $game['name'];
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 忽略错误
|
||||
}
|
||||
|
||||
// 为每个游戏获取当前期号
|
||||
$currentPeriods = [];
|
||||
foreach ($gamesList as $game) {
|
||||
$currentPeriod = $db->get('periods', '*', [
|
||||
'game_id' => $game['id'],
|
||||
'ORDER' => ['id' => 'DESC']
|
||||
]);
|
||||
if ($currentPeriod) {
|
||||
$currentPeriods[$game['id']] = $currentPeriod;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$periods = [];
|
||||
$games = [];
|
||||
$gamesList = [];
|
||||
$currentPeriods = [];
|
||||
}
|
||||
|
||||
$this->render('Admin/periods.php', [
|
||||
'currentPeriods' => $currentPeriods, // 改为多个游戏的当前期号
|
||||
'periods' => $periods,
|
||||
'games' => $games,
|
||||
'gamesList' => $gamesList, // 完整的游戏列表
|
||||
'title' => '期号管理'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个期号数据
|
||||
*/
|
||||
public function get($id) {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if (empty($id) || !is_numeric($id)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '无效的期号ID'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = new Database();
|
||||
try {
|
||||
$period = $db->get('periods', '*', [
|
||||
'id' => $id
|
||||
]);
|
||||
|
||||
if ($period) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'data' => $period
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '期号不存在'
|
||||
]);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '获取数据失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建期号
|
||||
*/
|
||||
public function create() {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$data = $_POST;
|
||||
if (empty($data)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '未接收到数据'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = new Database();
|
||||
|
||||
$gameId = isset($data['game_id']) ? (int)$data['game_id'] : null;
|
||||
|
||||
// 如果关联了游戏,从游戏中获取直播流地址
|
||||
$streamUrl = null;
|
||||
if ($gameId) {
|
||||
try {
|
||||
$game = $db->get('games', ['stream_url'], ['id' => $gameId]);
|
||||
if ($game && !empty($game['stream_url'])) {
|
||||
$streamUrl = $game['stream_url'];
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 忽略错误,继续使用 null
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前登录的管理员ID
|
||||
$createdBy = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
|
||||
|
||||
// 生成期号
|
||||
$periodNumber = $this->generatePeriodNumber($db, $gameId);
|
||||
|
||||
// 准备数据
|
||||
$periodData = [
|
||||
'period_number' => $periodNumber,
|
||||
'status' => 'pending',
|
||||
'game_id' => $gameId ?: null,
|
||||
'stream_url' => $streamUrl,
|
||||
'start_time' => date('Y-m-d H:i:s'),
|
||||
'created_by' => $createdBy,
|
||||
'auto_generated' => 0, // 手动创建
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
try {
|
||||
$id = $db->insert('periods', $periodData);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => '期号创建成功',
|
||||
'data' => ['id' => $id, 'period_number' => $periodNumber]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '创建失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 录入开奖结果
|
||||
*/
|
||||
public function draw() {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$data = $_POST;
|
||||
if (empty($data)) {
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '未接收到数据'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = new Database();
|
||||
$id = isset($data['id']) ? (int)$data['id'] : 0;
|
||||
|
||||
if ($id <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '无效的期号ID'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取期号信息
|
||||
$period = $db->get('periods', '*', ['id' => $id]);
|
||||
if (!$period) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '期号不存在'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查期号状态
|
||||
if ($period['status'] === 'settled') {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '该期号已结算,无法修改'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取游戏类型
|
||||
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
|
||||
$gameType = $game['type'] ?? 'dice';
|
||||
|
||||
$auto = isset($data['auto']) ? (bool)$data['auto'] : false;
|
||||
|
||||
// 根据游戏类型处理开奖结果
|
||||
if ($gameType === 'xocdia') {
|
||||
// Xóc Đĩa 开奖逻辑
|
||||
if ($auto) {
|
||||
// 自动生成:4个硬币随机红/白
|
||||
$coins = [];
|
||||
for ($i = 0; $i < 4; $i++) {
|
||||
$coins[] = (rand(0, 1) === 0) ? 'red' : 'white';
|
||||
}
|
||||
} else {
|
||||
// 手动输入:从前端获取
|
||||
$coins = isset($data['coins']) ? $data['coins'] : [];
|
||||
if (!is_array($coins) || count($coins) !== 4) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Xóc Đĩa 必须提供4个硬币的颜色(red/white)'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
// 验证颜色
|
||||
foreach ($coins as $coin) {
|
||||
if (!in_array($coin, ['red', 'white'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '硬币颜色只能是 red 或 white'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算结果
|
||||
$redCount = count(array_filter($coins, fn($c) => $c === 'red'));
|
||||
$result = $this->calculateXocdiaResult($redCount);
|
||||
|
||||
// 获取当前登录的管理员ID(审核人)
|
||||
$approvedBy = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
|
||||
|
||||
// 更新期号数据
|
||||
$updateData = [
|
||||
'result' => json_encode($coins), // 存储JSON数组
|
||||
'dice1' => $redCount, // 复用字段:红色数量
|
||||
'dice2' => 4 - $redCount, // 复用字段:白色数量
|
||||
'dice3' => null,
|
||||
'total' => null,
|
||||
'status' => 'drawn',
|
||||
'draw_time' => date('Y-m-d H:i:s'),
|
||||
'approved_by' => $approvedBy,
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
$responseData = [
|
||||
'coins' => $coins,
|
||||
'red_count' => $redCount,
|
||||
'white_count' => 4 - $redCount,
|
||||
'result' => $result
|
||||
];
|
||||
} else {
|
||||
// 骰子游戏开奖逻辑(原逻辑)
|
||||
if ($auto) {
|
||||
$dice1 = rand(1, 6);
|
||||
$dice2 = rand(1, 6);
|
||||
$dice3 = rand(1, 6);
|
||||
} else {
|
||||
$dice1 = isset($data['dice1']) ? (int)$data['dice1'] : 0;
|
||||
$dice2 = isset($data['dice2']) ? (int)$data['dice2'] : 0;
|
||||
$dice3 = isset($data['dice3']) ? (int)$data['dice3'] : 0;
|
||||
|
||||
// 验证骰子点数
|
||||
if ($dice1 < 1 || $dice1 > 6 || $dice2 < 1 || $dice2 > 6 || $dice3 < 1 || $dice3 > 6) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '骰子点数必须在1-6之间'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 计算总和
|
||||
$total = $dice1 + $dice2 + $dice3;
|
||||
|
||||
// 计算结果
|
||||
$result = $this->calculateResult($dice1, $dice2, $dice3, $total);
|
||||
|
||||
// 获取当前登录的管理员ID(审核人)
|
||||
$approvedBy = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
|
||||
|
||||
// 更新期号数据
|
||||
$updateData = [
|
||||
'dice1' => $dice1,
|
||||
'dice2' => $dice2,
|
||||
'dice3' => $dice3,
|
||||
'total' => $total,
|
||||
'result' => $result,
|
||||
'status' => 'drawn',
|
||||
'draw_time' => date('Y-m-d H:i:s'),
|
||||
'approved_by' => $approvedBy,
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
$responseData = [
|
||||
'dice1' => $dice1,
|
||||
'dice2' => $dice2,
|
||||
'dice3' => $dice3,
|
||||
'total' => $total,
|
||||
'result' => $result
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$db->update('periods', $updateData, ['id' => $id]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => '开奖结果已录入',
|
||||
'data' => $responseData
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '录入失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动新一期(开始下注)
|
||||
*/
|
||||
public function start() {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$data = $_POST;
|
||||
if (empty($data)) {
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
}
|
||||
|
||||
$gameId = isset($data['game_id']) ? (int)$data['game_id'] : 0;
|
||||
|
||||
if ($gameId <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '请选择游戏'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = new Database();
|
||||
|
||||
// 检查该游戏是否有未结束的期号
|
||||
$activePeriod = $db->get('periods', '*', [
|
||||
'game_id' => $gameId,
|
||||
'status' => ['pending', 'locked', 'drawn']
|
||||
]);
|
||||
|
||||
if ($activePeriod) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '该游戏当前有未结束的期号,无法开始新一轮'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 生成期号
|
||||
$periodNumber = $this->generatePeriodNumber($db, $gameId);
|
||||
|
||||
// 从游戏配置��取stream_url
|
||||
$streamUrl = null;
|
||||
$game = $db->get('games', ['stream_url'], ['id' => $gameId]);
|
||||
if ($game && !empty($game['stream_url'])) {
|
||||
$streamUrl = $game['stream_url'];
|
||||
}
|
||||
|
||||
$periodData = [
|
||||
'period_number' => $periodNumber,
|
||||
'status' => 'pending',
|
||||
'game_id' => $gameId,
|
||||
'stream_url' => $streamUrl,
|
||||
'start_time' => date('Y-m-d H:i:s'),
|
||||
'auto_generated' => 0, // 手动点击开始
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
try {
|
||||
$id = $db->insert('periods', $periodData);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => '新一期已启动,开始下注',
|
||||
'data' => [
|
||||
'id' => $id,
|
||||
'period_number' => $periodNumber,
|
||||
'start_time' => $periodData['start_time']
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '启动失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认开奖并结算(自动创建下一期)
|
||||
*/
|
||||
public function settle() {
|
||||
ob_clean();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$data = $_POST;
|
||||
if (empty($data)) {
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
}
|
||||
|
||||
$id = isset($data['id']) ? (int)$data['id'] : 0;
|
||||
|
||||
if ($id <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '无效的期号ID'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = new Database();
|
||||
|
||||
// 获取期号信息
|
||||
$period = $db->get('periods', '*', ['id' => $id]);
|
||||
if (!$period) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '期号不存在'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查期号状态
|
||||
if ($period['status'] !== 'drawn') {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '该期号还未开奖,无法结算'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($period['status'] === 'settled') {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '该期号已结算'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 开启事务
|
||||
$db->medoo->pdo->beginTransaction();
|
||||
|
||||
// 1. 获取本期所有待结算注单
|
||||
$bets = $db->select('bets', '*', [
|
||||
'period_id' => $id,
|
||||
'status' => 'pending'
|
||||
]);
|
||||
|
||||
// 2. 遍历注单进行结算
|
||||
if ($bets) {
|
||||
foreach ($bets as $bet) {
|
||||
$checkResult = $this->checkWin($bet, $period);
|
||||
$isWin = $checkResult['win'];
|
||||
$winAmount = $checkResult['amount']; // 纯赢金额
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
if ($isWin) {
|
||||
$payout = $bet['amount'] + $winAmount; // 本金 + 盈利
|
||||
|
||||
// 更新注单状态
|
||||
$db->update('bets', [
|
||||
'status' => 'win',
|
||||
'win_amount' => $winAmount,
|
||||
'settled_at' => $now,
|
||||
'updated_at' => $now
|
||||
], ['id' => $bet['id']]);
|
||||
|
||||
// 更新用户余额
|
||||
$db->update('users', [
|
||||
'balance[+]' => $payout
|
||||
], ['id' => $bet['user_id']]);
|
||||
|
||||
// 获取更新后的余额(用于记录流水)
|
||||
$user = $db->get('users', ['balance'], ['id' => $bet['user_id']]);
|
||||
$balanceAfter = $user['balance'];
|
||||
$balanceBefore = $balanceAfter - $payout;
|
||||
|
||||
// 写入资金流水
|
||||
$db->insert('transactions', [
|
||||
'user_id' => $bet['user_id'],
|
||||
'type' => 'win',
|
||||
'amount' => $payout,
|
||||
'balance_before' => $balanceBefore,
|
||||
'balance_after' => $balanceAfter,
|
||||
'related_id' => $bet['id'],
|
||||
'description' => "中奖 - 期号: " . $period['period_number'],
|
||||
'created_at' => $now
|
||||
]);
|
||||
|
||||
} else {
|
||||
// 未中奖
|
||||
$db->update('bets', [
|
||||
'status' => 'lose',
|
||||
'win_amount' => 0,
|
||||
'settled_at' => $now,
|
||||
'updated_at' => $now
|
||||
], ['id' => $bet['id']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新期号状态为已结算
|
||||
$db->update('periods', [
|
||||
'status' => 'settled',
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
], ['id' => $id]);
|
||||
|
||||
// 移除自动创建下一期的逻辑,改为由管理员手动点击"开始下注"
|
||||
/*
|
||||
// 自动创建下一期
|
||||
$nextPeriodNumber = $this->generatePeriodNumber($db);
|
||||
|
||||
// 如果当前期号没有 stream_url,尝试从关联游戏中获取
|
||||
$nextStreamUrl = $period['stream_url'];
|
||||
if (empty($nextStreamUrl) && !empty($period['game_id'])) {
|
||||
try {
|
||||
$game = $db->get('games', ['stream_url'], ['id' => $period['game_id']]);
|
||||
if ($game && !empty($game['stream_url'])) {
|
||||
$nextStreamUrl = $game['stream_url'];
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// 忽略错误,继续使用原值
|
||||
}
|
||||
}
|
||||
|
||||
$nextPeriodData = [
|
||||
'period_number' => $nextPeriodNumber,
|
||||
'status' => 'pending',
|
||||
'game_id' => $period['game_id'],
|
||||
'stream_url' => $nextStreamUrl,
|
||||
'start_time' => date('Y-m-d H:i:s'),
|
||||
'auto_generated' => 1, // 自动生成
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
$nextPeriodId = $db->insert('periods', $nextPeriodData);
|
||||
*/
|
||||
$nextPeriodId = 0;
|
||||
$nextPeriodNumber = '';
|
||||
|
||||
// 提交事务
|
||||
$db->medoo->pdo->commit();
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => '结算成功,请点击"开始下注"启动下一期',
|
||||
'data' => [
|
||||
'current_period_id' => $id,
|
||||
// 'next_period_id' => $nextPeriodId,
|
||||
// 'next_period_number' => $nextPeriodNumber
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
// 回滚事务
|
||||
if (isset($db->medoo->pdo)) {
|
||||
$db->medoo->pdo->rollBack();
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '结算失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 封盘
|
||||
*/
|
||||
public function lock() {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$data = $_POST;
|
||||
if (empty($data)) {
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
}
|
||||
$id = isset($data['id']) ? (int)$data['id'] : 0;
|
||||
|
||||
if ($id <= 0) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '无效的期号ID'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$db = new Database();
|
||||
|
||||
// 获取期号信息
|
||||
$period = $db->get('periods', '*', ['id' => $id]);
|
||||
if (!$period) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '期号不存在'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查期号状态
|
||||
if ($period['status'] !== 'pending') {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '该期号状态不允许封盘'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$db->update('periods', [
|
||||
'status' => 'locked',
|
||||
'end_time' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
], ['id' => $id]);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => '封盘成功'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => '封盘失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成期号
|
||||
* 格式:G{GameID}{YYYYMMDD}{NNNN}
|
||||
* 例如:G1202512240001
|
||||
*/
|
||||
private function generatePeriodNumber($db, $gameId = null) {
|
||||
// 如果没有指定游戏ID,默认使用1
|
||||
$gameId = $gameId ?: 1;
|
||||
|
||||
$now = new \DateTime();
|
||||
$dateStr = $now->format('Ymd');
|
||||
$prefix = "G{$gameId}{$dateStr}";
|
||||
|
||||
// 查询当天该游戏最大的期号
|
||||
try {
|
||||
$lastPeriod = $db->get('periods', 'period_number', [
|
||||
'period_number[~]' => $prefix . '%',
|
||||
'ORDER' => ['period_number' => 'DESC']
|
||||
]);
|
||||
|
||||
if ($lastPeriod) {
|
||||
// 提取序号并+1
|
||||
$lastSeq = substr($lastPeriod, strlen($prefix));
|
||||
$newSeq = (int)$lastSeq + 1;
|
||||
$seqStr = str_pad((string)$newSeq, 4, '0', STR_PAD_LEFT);
|
||||
} else {
|
||||
// 当天第一期
|
||||
$seqStr = '0001';
|
||||
}
|
||||
|
||||
return $prefix . $seqStr;
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
// 发生错误时回退到时间戳随机数,防止阻塞
|
||||
return $prefix . time();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查注单是否中奖
|
||||
*/
|
||||
private function checkWin($bet, $period) {
|
||||
$betType = $bet['bet_type'];
|
||||
$betValue = $bet['bet_value'];
|
||||
$betAmount = (float)$bet['amount'];
|
||||
$gameId = $period['game_id'] ?? 1;
|
||||
|
||||
$db = new Database();
|
||||
|
||||
// 获取游戏类型
|
||||
$game = $db->get('games', ['type'], ['id' => $gameId]);
|
||||
$gameType = $game['type'] ?? 'dice';
|
||||
|
||||
// 获取该游戏的所有赔率配置
|
||||
static $oddsCache = [];
|
||||
if (!isset($oddsCache[$gameId])) {
|
||||
$oddsData = $db->select('game_odds', '*', ['game_id' => $gameId]);
|
||||
$oddsCache[$gameId] = [];
|
||||
foreach ($oddsData as $odd) {
|
||||
$key = $odd['type'] . '_' . $odd['target'];
|
||||
$oddsCache[$gameId][$key] = (float)$odd['odds'];
|
||||
}
|
||||
}
|
||||
|
||||
$isWin = false;
|
||||
$payoutMultiplier = 0;
|
||||
|
||||
// 辅助函数:获取赔率
|
||||
$getOdds = function($type, $target = 'all') use ($oddsCache, $gameId) {
|
||||
$key = $type . '_' . $target;
|
||||
// 如果找不到特定target的赔率,尝试查找 'all'
|
||||
if (isset($oddsCache[$gameId][$key])) {
|
||||
return $oddsCache[$gameId][$key];
|
||||
}
|
||||
$allKey = $type . '_all';
|
||||
return $oddsCache[$gameId][$allKey] ?? 0;
|
||||
};
|
||||
|
||||
// Xóc Đĩa 游戏结算逻辑
|
||||
if ($gameType === 'xocdia') {
|
||||
// 从 result 字段解析硬币颜色数组
|
||||
$coins = json_decode($period['result'], true);
|
||||
if (!is_array($coins) || count($coins) !== 4) {
|
||||
return ['win' => false, 'amount' => 0];
|
||||
}
|
||||
|
||||
$redCount = count(array_filter($coins, fn($c) => $c === 'red'));
|
||||
$whiteCount = 4 - $redCount;
|
||||
|
||||
switch ($betType) {
|
||||
case 'chan': // 双(偶): 4红 或 4白 或 2红2白
|
||||
if (in_array($redCount, [0, 2, 4])) {
|
||||
$isWin = true;
|
||||
$payoutMultiplier = $getOdds('chan', $betValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'le': // 单(奇): 3红1白 或 3白1红
|
||||
if (in_array($redCount, [1, 3])) {
|
||||
$isWin = true;
|
||||
$payoutMultiplier = $getOdds('le', $betValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'exact': // 精确颜色组合
|
||||
switch ($betValue) {
|
||||
case '4red':
|
||||
if ($redCount === 4) $isWin = true;
|
||||
break;
|
||||
case '4white':
|
||||
if ($redCount === 0) $isWin = true;
|
||||
break;
|
||||
case '3red1white':
|
||||
if ($redCount === 3) $isWin = true;
|
||||
break;
|
||||
case '3white1red':
|
||||
if ($redCount === 1) $isWin = true;
|
||||
break;
|
||||
}
|
||||
if ($isWin) {
|
||||
$payoutMultiplier = $getOdds('exact', $betValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($isWin && $payoutMultiplier > 0) {
|
||||
return [
|
||||
'win' => true,
|
||||
'amount' => $betAmount * $payoutMultiplier
|
||||
];
|
||||
}
|
||||
|
||||
return ['win' => false, 'amount' => 0];
|
||||
}
|
||||
|
||||
// 骰子游戏结算逻辑(原逻辑)
|
||||
$dice1 = (int)$period['dice1'];
|
||||
$dice2 = (int)$period['dice2'];
|
||||
$dice3 = (int)$period['dice3'];
|
||||
$total = (int)$period['total'];
|
||||
|
||||
switch ($betType) {
|
||||
case 'xiu': // 小 (4-10)
|
||||
// 爆子处理:1-3为小,4-6为大
|
||||
if ($dice1 == $dice2 && $dice2 == $dice3) {
|
||||
if ($dice1 <= 3) $isWin = true;
|
||||
} else {
|
||||
if ($total >= 4 && $total <= 10) $isWin = true;
|
||||
}
|
||||
$payoutMultiplier = $getOdds('xiu');
|
||||
break;
|
||||
|
||||
case 'tai': // 大 (11-17)
|
||||
// 爆子处理:1-3为小,4-6为大
|
||||
if ($dice1 == $dice2 && $dice2 == $dice3) {
|
||||
if ($dice1 >= 4) $isWin = true;
|
||||
} else {
|
||||
if ($total >= 11 && $total <= 17) $isWin = true;
|
||||
}
|
||||
$payoutMultiplier = $getOdds('tai');
|
||||
break;
|
||||
|
||||
case 'chan': // 偶数
|
||||
if ($total % 2 == 0) $isWin = true;
|
||||
$payoutMultiplier = $getOdds('chan');
|
||||
break;
|
||||
|
||||
case 'le': // 奇数
|
||||
if ($total % 2 != 0) $isWin = true;
|
||||
$payoutMultiplier = $getOdds('le');
|
||||
break;
|
||||
|
||||
case 'number': // 单数字 (Sum)
|
||||
if ($total == (int)$betValue) {
|
||||
$isWin = true;
|
||||
$payoutMultiplier = $getOdds('sum', $betValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'dice': // 单个骰子
|
||||
$count = 0;
|
||||
if ($dice1 == (int)$betValue) $count++;
|
||||
if ($dice2 == (int)$betValue) $count++;
|
||||
if ($dice3 == (int)$betValue) $count++;
|
||||
|
||||
if ($count > 0) {
|
||||
$isWin = true;
|
||||
// 单个骰子赔率通常是 1:1, 1:2, 1:3
|
||||
// 但数据库中只存了基础赔率 (e.g. 0.97 or 1.0)
|
||||
// 这里我们假设数据库存的是 1赔X 的 X
|
||||
// 如果是双骰或三骰,通常规则是:
|
||||
// 1个: 1倍
|
||||
// 2个: 2倍
|
||||
// 3个: 3倍
|
||||
// 我们读取基础赔率,然后乘以数量
|
||||
$baseOdds = $getOdds('dice', $betValue);
|
||||
$payoutMultiplier = $baseOdds * $count;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'combo': // 豹子 (Specific Triple)
|
||||
// betValue 存储的是总和 (3, 6, ..., 18) 或 'any_triple'
|
||||
if ($betValue === 'any_triple') {
|
||||
if ($dice1 == $dice2 && $dice2 == $dice3) {
|
||||
$isWin = true;
|
||||
$payoutMultiplier = $getOdds('combo', 'any_triple');
|
||||
}
|
||||
} else {
|
||||
if ($dice1 == $dice2 && $dice2 == $dice3 && $total == (int)$betValue) {
|
||||
$isWin = true;
|
||||
$payoutMultiplier = $getOdds('combo', 'specific_triple');
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($isWin && $payoutMultiplier > 0) {
|
||||
return [
|
||||
'win' => true,
|
||||
'amount' => $betAmount * $payoutMultiplier
|
||||
];
|
||||
}
|
||||
|
||||
return ['win' => false, 'amount' => 0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算开奖结果(骰子游戏)
|
||||
* @param int $dice1 骰子1点数
|
||||
* @param int $dice2 骰子2点数
|
||||
* @param int $dice3 骰子3点数
|
||||
* @param int $total 总和
|
||||
* @return string 结果:Xỉu/Tài/Bão
|
||||
*/
|
||||
private function calculateResult($dice1, $dice2, $dice3, $total) {
|
||||
// 检查是否为爆子(三个骰子相同)
|
||||
if ($dice1 === $dice2 && $dice2 === $dice3) {
|
||||
// 爆子根据点数判断:1-3为Xỉu,4-6为Tài
|
||||
if ($dice1 <= 3) {
|
||||
return 'Xỉu';
|
||||
} else {
|
||||
return 'Tài';
|
||||
}
|
||||
}
|
||||
|
||||
// 普通大小判断:4-10点为小(Xỉu),11-17点为大(Tài)
|
||||
if ($total >= 4 && $total <= 10) {
|
||||
return 'Xỉu';
|
||||
} else {
|
||||
return 'Tài';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算 Xóc Đĩa 开奖结果
|
||||
* @param int $redCount 红色硬币数量
|
||||
* @return string 结果描述
|
||||
*/
|
||||
private function calculateXocdiaResult($redCount) {
|
||||
switch ($redCount) {
|
||||
case 0:
|
||||
return '4 Trắng (Chẵn)';
|
||||
case 1:
|
||||
return '3 Trắng 1 Đỏ (Lẻ)';
|
||||
case 2:
|
||||
return '2 Trắng 2 Đỏ (Chẵn)';
|
||||
case 3:
|
||||
return '3 Đỏ 1 Trắng (Lẻ)';
|
||||
case 4:
|
||||
return '4 Đỏ (Chẵn)';
|
||||
default:
|
||||
return 'Không xác định';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user