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

715 lines
22 KiB
PHP
Executable File
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.
<?php
namespace App\Controllers\Admin;
use App\Core\AdminBaseController;
use Db\Database;
class XocdiaPeriodController extends AdminBaseController {
private $gameType = 'xocdia';
public function __construct() {
$this->checkLogin();
$this->checkAdmin();
}
/**
* Xóc Đĩa 游戏期号列表页面
*/
public function index() {
$db = new Database();
try {
// 获取 Xóc Đĩa 游戏列表
$gamesList = $db->select('games', ['id', 'name'], [
'type' => $this->gameType,
'status' => 1,
'ORDER' => ['id' => 'ASC']
]);
if (!is_array($gamesList)) {
$gamesList = [];
}
// 获取所有 Xóc Đĩa 游戏的game_id
$gameIds = array_column($gamesList, 'id');
// 获取 Xóc Đĩa 游戏的期号列表
$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'];
}
// 为每个 Xóc Đĩa 游戏获取当前期号
$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/xocdia_periods.php', [
'currentPeriods' => $currentPeriods,
'periods' => $periods,
'games' => $games,
'gamesList' => $gamesList,
'title' => 'Xóc Đĩa 游戏期号管理'
]);
}
/**
* 获取单个期号数据
*/
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) {
// 验证是否为 Xóc Đĩa 游戏期号
$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' => '期号不属于 Xóc Đĩa 游戏'
]);
}
} 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;
}
// 验证是否为 Xóc Đĩa 游戏
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
if (!$game || $game['type'] !== $this->gameType) {
echo json_encode([
'success' => false,
'message' => '期号不属于 Xóc Đĩa 游戏'
]);
return;
}
// 检查期号状态
if ($period['status'] === 'settled') {
echo json_encode([
'success' => false,
'message' => '该期号已结算,无法修改'
]);
return;
}
$auto = isset($data['auto']) ? (bool)$data['auto'] : false;
// 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),
'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
];
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' => '游戏不属于 Xóc Đĩa 游戏'
]);
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;
}
// 验证是否为 Xóc Đĩa 游戏
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
if (!$game || $game['type'] !== $this->gameType) {
echo json_encode([
'success' => false,
'message' => '期号不属于 Xóc Đĩa 游戏'
]);
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;
}
// 验证是否为 Xóc Đĩa 游戏
$game = $db->get('games', ['type'], ['id' => $period['game_id']]);
if (!$game || $game['type'] !== $this->gameType) {
echo json_encode([
'success' => false,
'message' => '期号不属于 Xóc Đĩa 游戏'
]);
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;
};
// Xóc Đĩa 游戏结算逻辑
$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];
}
/**
* 计算 Xóc Đĩa 开奖结果
*/
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';
}
}
}