db = $db; } public function index() { $this->checkLogin(); $gameId = $this->getGameId(); $periods = $this->db->select('periods', '*', [ 'game_id' => $gameId, 'ORDER' => ['id' => 'DESC'], 'LIMIT' => 50 ]); // 附加pk10_results foreach ($periods as &$p) { $p['pk10'] = $this->db->get('pk10_results', '*', ['period_id' => $p['id']]); } $current = $this->db->get('periods', '*', [ 'game_id' => $gameId, 'status[!]' => 'settled', 'ORDER' => ['id' => 'DESC'] ]); if ($current) { $current['pk10'] = $this->db->get('pk10_results', '*', ['period_id' => $current['id']]); } $stats = [ 'total' => $this->db->count('periods', ['game_id' => $gameId]), 'pending' => $this->db->count('periods', ['game_id' => $gameId, 'status' => 'pending']), 'drawn' => $this->db->count('periods', ['game_id' => $gameId, 'status' => 'drawn']), 'settled' => $this->db->count('periods', ['game_id' => $gameId, 'status' => 'settled']), ]; $this->render('Admin/pk10_periods.php', compact('periods', 'current', 'stats', 'gameId')); } public function start() { $this->checkLogin(); $gameId = $this->getGameId(); // 检查是否有未结算期号 $active = $this->db->get('periods', 'id', [ 'game_id' => $gameId, 'status[!]' => 'settled' ]); if ($active) { $this->json(['status' => 'error', 'message' => 'There is an active period. Please settle it first.']); return; } $periodNumber = PK10Algorithm::generatePeriodNumber($gameId); $this->db->insert('periods', [ 'game_id' => $gameId, 'period_number' => $periodNumber, 'status' => 'pending', 'created_at' => date('Y-m-d H:i:s'), ]); $this->json(['status' => 'success', 'message' => 'New period started', 'period_number' => $periodNumber]); } public function lock() { $this->checkLogin(); $data = json_decode(file_get_contents('php://input'), true); $periodId = (int)($data['period_id'] ?? 0); $period = $this->db->get('periods', '*', ['id' => $periodId]); if (!$period || $period['status'] !== 'pending') { $this->json(['status' => 'error', 'message' => 'Invalid period or status']); return; } $this->db->update('periods', ['status' => 'locked'], ['id' => $periodId]); $this->json(['status' => 'success', 'message' => 'Period locked']); } public function draw() { $this->checkLogin(); $data = json_decode(file_get_contents('php://input'), true); $periodId = (int)($data['period_id'] ?? 0); $manual = $data['manual'] ?? false; $period = $this->db->get('periods', '*', ['id' => $periodId]); if (!$period || !in_array($period['status'], ['pending', 'locked'])) { $this->json(['status' => 'error', 'message' => 'Invalid period or status']); return; } $gameId = $period['game_id']; if ($manual && !empty($data['result'])) { // 手动补开奖 $result = array_map('intval', $data['result']); if (count($result) !== 10 || count(array_unique($result)) !== 10) { $this->json(['status' => 'error', 'message' => 'Result must be 10 unique numbers 1-10']); return; } } else { // 自动开奖(带放水机制) $waterConfig = []; $wc = $this->db->select('water_control', '*', ['game_id' => $gameId, 'enabled' => 1]); foreach ($wc as $w) { $waterConfig[$w['bet_type']] = (float)$w['win_rate_pct']; } $bets = $this->db->select('bets', '*', [ 'period_id' => $periodId, 'status' => 'pending', 'is_virtual' => 0 ]); if (!empty($waterConfig) && !empty($bets)) { $result = PK10Algorithm::generateControlledResult($bets, $waterConfig); } else { $result = PK10Algorithm::generateResult(); } } $sum = $result[0] + $result[1]; $resultJson = json_encode($result); $this->db->medoo->pdo->beginTransaction(); try { $this->db->update('periods', [ 'status' => 'drawn', 'result' => $resultJson, 'draw_time' => date('Y-m-d H:i:s'), ], ['id' => $periodId]); // 删除旧结果(如果手动修改) $this->db->delete('pk10_results', ['period_id' => $periodId]); $this->db->insert('pk10_results', [ 'period_id' => $periodId, 'rank_1' => $result[0], 'rank_2' => $result[1], 'rank_3' => $result[2], 'rank_4' => $result[3], 'rank_5' => $result[4], 'rank_6' => $result[5], 'rank_7' => $result[6], 'rank_8' => $result[7], 'rank_9' => $result[8], 'rank_10' => $result[9], 'champion_sum' => $sum, ]); $this->db->medoo->pdo->commit(); } catch (\Throwable $e) { $this->db->medoo->pdo->rollBack(); $this->json(['status' => 'error', 'message' => 'Draw failed: ' . $e->getMessage()]); return; } $this->json(['status' => 'success', 'message' => 'Draw completed', 'result' => $result, 'sum' => $sum]); } public function settle() { $this->checkLogin(); $data = json_decode(file_get_contents('php://input'), true); $periodId = (int)($data['period_id'] ?? 0); $period = $this->db->get('periods', '*', ['id' => $periodId]); if (!$period || $period['status'] !== 'drawn') { $this->json(['status' => 'error', 'message' => 'Period must be drawn first']); return; } $result = json_decode($period['result'], true); if (!$result || count($result) !== 10) { $this->json(['status' => 'error', 'message' => 'Invalid result data']); return; } $bets = $this->db->select('bets', '*', ['period_id' => $periodId, 'status' => 'pending']); if (empty($bets)) { $this->db->update('periods', ['status' => 'settled'], ['id' => $periodId]); $this->json(['status' => 'success', 'message' => 'No bets to settle', 'wins' => 0, 'losses' => 0]); return; } $wins = 0; $losses = 0; $totalPayout = 0; $this->db->medoo->pdo->beginTransaction(); try { foreach ($bets as $bet) { $isWin = PK10Algorithm::checkWin($result, $bet['bet_type'], $bet['bet_value']); $betAmount = (float)$bet['amount']; $odds = (float)$bet['odds']; if ($isWin) { $winAmount = $betAmount * $odds; $payout = $betAmount + $winAmount; $this->db->update('bets', [ 'status' => 'win', 'win_amount' => $winAmount, ], ['id' => $bet['id']]); $stmt = $this->db->medoo->pdo->prepare("SELECT balance FROM users WHERE id = :id FOR UPDATE"); $stmt->execute([':id' => $bet['user_id']]); $user = $stmt->fetch(\PDO::FETCH_ASSOC); $newBalance = (float)$user['balance'] + $payout; $this->db->update('users', ['balance' => $newBalance], ['id' => $bet['user_id']]); $this->db->insert('transactions', [ 'user_id' => $bet['user_id'], 'type' => 'win', 'amount' => $payout, 'balance_before' => $user['balance'], 'balance_after' => $newBalance, 'related_id' => $periodId, 'description' => 'PK10 Win - Period ' . $period['period_number'], 'is_virtual' => $bet['is_virtual'], 'created_at' => date('Y-m-d H:i:s'), ]); $totalPayout += $payout; $wins++; } else { $this->db->update('bets', ['status' => 'lose', 'win_amount' => 0], ['id' => $bet['id']]); $losses++; } } // 计算代理佣金 $this->settleAgentCommissions($bets, $periodId); $this->db->update('periods', ['status' => 'settled'], ['id' => $periodId]); $this->db->medoo->pdo->commit(); } catch (\Throwable $e) { $this->db->medoo->pdo->rollBack(); $this->json(['status' => 'error', 'message' => 'Settle failed: ' . $e->getMessage()]); return; } $this->json(['status' => 'success', 'message' => 'Settlement completed', 'wins' => $wins, 'losses' => $losses, 'total_payout' => $totalPayout]); } private function settleAgentCommissions(array $bets, int $periodId) { $agentBets = []; foreach ($bets as $bet) { if ((int)$bet['is_virtual']) continue; $user = $this->db->get('users', ['agent_id'], ['id' => $bet['user_id']]); if (!$user || !$user['agent_id']) continue; $agentId = $user['agent_id']; if (!isset($agentBets[$agentId])) $agentBets[$agentId] = 0; $agentBets[$agentId] += (float)$bet['amount']; } foreach ($agentBets as $agentId => $totalBet) { $agent = $this->db->get('agents', '*', ['id' => $agentId, 'status' => 1]); if (!$agent) continue; $commission = $totalBet * $agent['commission_rate'] / 100; if ($commission <= 0) continue; $this->db->insert('agent_commissions', [ 'agent_id' => $agentId, 'from_user_id' => 0, 'period_id' => $periodId, 'bet_amount' => $totalBet, 'commission' => $commission, 'type' => 'bet', 'created_at' => date('Y-m-d H:i:s'), ]); // 佣金加到代理用户余额 $agentUserId = $agent['user_id']; $stmt = $this->db->medoo->pdo->prepare("SELECT balance FROM users WHERE id = :id FOR UPDATE"); $stmt->execute([':id' => $agentUserId]); $au = $stmt->fetch(\PDO::FETCH_ASSOC); $newBal = (float)$au['balance'] + $commission; $this->db->update('users', ['balance' => $newBal], ['id' => $agentUserId]); $this->db->insert('transactions', [ 'user_id' => $agentUserId, 'type' => 'commission', 'amount' => $commission, 'balance_before' => $au['balance'], 'balance_after' => $newBal, 'related_id' => $periodId, 'description' => 'Agent commission', 'created_at' => date('Y-m-d H:i:s'), ]); } } public function get($id) { $this->checkLogin(); $period = $this->db->get('periods', '*', ['id' => (int)$id]); if ($period) { $period['pk10'] = $this->db->get('pk10_results', '*', ['period_id' => $period['id']]); } $this->json(['status' => 'success', 'data' => $period]); } private function getGameId(): int { $game = $this->db->get('games', 'id', ['code' => 'pk10']); return $game ? (int)$game : 0; } private function json(array $data) { header('Content-Type: application/json'); echo json_encode($data); } }