Files
pk10/App/Controllers/Admin/DicePeriodController.php
T

735 lines
22 KiB
PHP
Executable File

<?php
namespace App\Controllers\Admin;
use App\Core\AdminBaseController;
use Db\Database;
class DicePeriodController extends AdminBaseController {
private $gameType = 'dice';
public function __construct() {
$this->checkLogin();
$this->checkAdmin();
}
/**
* 骰子游戏期号列表页面
*/
public function index() {
$db = new Database();
try {
// 获取骰子游戏列表
$gamesList = $db->select('games', ['id', 'name'], [
'type' => $this->gameType,
'status' => 1,
'ORDER' => ['id' => 'ASC']
]);
if (!is_array($gamesList)) {
$gamesList = [];
}
// 获取所有骰子游戏的game_id
$gameIds = array_column($gamesList, 'id');
// 获取骰子游戏的期号列表
$periods = [];
if (!empty($gameIds)) {
$periods = $db->select('periods', '*', [
'game_id' => $gameIds,
'ORDER' => ['id' => 'DESC'],
'LIMIT' => 100
]);
}
if (!is_array($periods)) {
$periods = [];
}
// 构建游戏名称映射
$games = [];
foreach ($gamesList as $game) {
$games[$game['id']] = $game['name'];
}
// 为每个骰子游戏获取当前期号
$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/dice_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) {
// 验证是否为骰子游戏期号
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
if ($game && $game['type'] === $this->gameType) {
echo json_encode([
'success' => true,
'data' => $period
]);
} else {
echo json_encode([
'success' => false,
'message' => '期号不属于骰子游戏'
]);
}
} else {
echo json_encode([
'success' => false,
'message' => '期号不存在'
]);
}
} catch (\Throwable $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;
}
// 验证是否为骰子游戏
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
if (!$game || $game['type'] !== $this->gameType) {
echo json_encode([
'success' => false,
'message' => '期号不属于骰子游戏'
]);
return;
}
// 检查期号状态
if ($period['status'] === 'settled') {
echo json_encode([
'success' => false,
'message' => '该期号已结算,无法修改'
]);
return;
}
$auto = isset($data['auto']) ? (bool)$data['auto'] : false;
// 骰子游戏开奖逻辑
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();
// 验证游戏类型
$game = $db->get('games', ['type', 'stream_url'], ['id' => $gameId]);
if (!$game || $game['type'] !== $this->gameType) {
echo json_encode([
'success' => false,
'message' => '游戏不属于骰子游戏'
]);
return;
}
// 检查该游戏是否有未结束的期号
$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 = !empty($game['stream_url']) ? $game['stream_url'] : null;
$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;
}
// 验证是否为骰子游戏
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
if (!$game || $game['type'] !== $this->gameType) {
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();
// 获取本期所有待结算注单
$bets = $db->select('bets', '*', [
'period_id' => $id,
'status' => 'pending'
]);
// 遍历注单进行结算
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]);
// 提交事务
$db->medoo->pdo->commit();
echo json_encode([
'success' => true,
'message' => '结算成功,请点击"开始下注"启动下一期',
'data' => [
'current_period_id' => $id
]
]);
} 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;
}
// 验证是否为骰子游戏
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
if (!$game || $game['type'] !== $this->gameType) {
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()
]);
}
}
/**
* 生成期号
*/
private function generatePeriodNumber($db, $gameId) {
$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) {
$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'];
$db = new Database();
// 获取赔率配置
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;
if (isset($oddsCache[$gameId][$key])) {
return $oddsCache[$gameId][$key];
}
$allKey = $type . '_all';
return $oddsCache[$gameId][$allKey] ?? 0;
};
// 骰子游戏结算逻辑
$dice1 = (int)$period['dice1'];
$dice2 = (int)$period['dice2'];
$dice3 = (int)$period['dice3'];
$total = (int)$period['total'];
switch ($betType) {
case 'xiu': // 小 (4-10)
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)
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;
$baseOdds = $getOdds('dice', $betValue);
$payoutMultiplier = $baseOdds * $count;
}
break;
case 'combo': // 豹子
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];
}
/**
* 计算开奖结果
*/
private function calculateResult($dice1, $dice2, $dice3, $total) {
// 检查是否为爆子
if ($dice1 === $dice2 && $dice2 === $dice3) {
if ($dice1 <= 3) {
return 'Xỉu';
} else {
return 'Tài';
}
}
// 普通大小判断
if ($total >= 4 && $total <= 10) {
return 'Xỉu';
} else {
return 'Tài';
}
}
}