1. 去掉PK10结算中is_virtual过滤,统一更新余额和写入transactions - PK10PeriodController.php (手动结算) - auto_period_task.php (自动结算) 2. live.php轮询回调增加余额同步显示
306 lines
12 KiB
PHP
306 lines
12 KiB
PHP
<?php
|
|
namespace App\Controllers\Admin;
|
|
|
|
use App\Core\AdminBaseController;
|
|
use App\Core\PK10Algorithm;
|
|
use Db\Database;
|
|
|
|
class PK10PeriodController extends AdminBaseController {
|
|
private $db;
|
|
|
|
public function __construct(Database $db) {
|
|
$this->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);
|
|
}
|
|
}
|