feat: 重构代码架构 + 新增报表/跟单/输赢统计功能
- 拆分 HomeController → TransactionController, ReportWebController, FollowPlanController - 新增 Service 层: TransactionService, ReportService, FollowPlanService - pk10.php JS 抽离为 4 个独立文件 (sound/race/bet/poll) - 前台新增报表查询页面 (/report) + 跟单计划页面 (/follow-plan) - 后台新增跟单计划管理 + 用户输赢明细统计 - 封盘状态显示倒计时 (x:xx) - 音效仅在开奖弹窗打开时播放 - 路由按模块分组整理 - autoload 支持 App\Services 命名空间
This commit is contained in:
@@ -61,12 +61,23 @@ class PK10PeriodController extends AdminBaseController {
|
||||
}
|
||||
|
||||
$periodNumber = PK10Algorithm::generatePeriodNumber($gameId);
|
||||
$createdAt = date('Y-m-d H:i:s');
|
||||
$this->db->insert('periods', [
|
||||
'game_id' => $gameId,
|
||||
'period_number' => $periodNumber,
|
||||
'status' => 'pending',
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'start_time' => $createdAt,
|
||||
'created_at' => $createdAt,
|
||||
]);
|
||||
$periodId = (int)$this->db->id();
|
||||
|
||||
if ($periodId > 0) {
|
||||
$this->queueCountdownPushes($gameId, [
|
||||
'id' => $periodId,
|
||||
'period_number' => $periodNumber,
|
||||
'created_at' => $createdAt,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->json(['status' => 'success', 'message' => 'New period started', 'period_number' => $periodNumber]);
|
||||
}
|
||||
@@ -83,6 +94,14 @@ class PK10PeriodController extends AdminBaseController {
|
||||
}
|
||||
|
||||
$this->db->update('periods', ['status' => 'locked'], ['id' => $periodId]);
|
||||
$this->queueBotPushByGame($period['game_id'], 'countdown', [
|
||||
'event' => 'period_locked',
|
||||
'period_id' => (int)$period['id'],
|
||||
'period_number' => (string)($period['period_number'] ?? ''),
|
||||
'message' => 'Period locked',
|
||||
], [
|
||||
'remind_close_countdown' => 1,
|
||||
]);
|
||||
$this->json(['status' => 'success', 'message' => 'Period locked']);
|
||||
}
|
||||
|
||||
@@ -122,7 +141,8 @@ class PK10PeriodController extends AdminBaseController {
|
||||
]);
|
||||
|
||||
if (!empty($waterConfig) && !empty($bets)) {
|
||||
$result = PK10Algorithm::generateControlledResult($bets, $waterConfig);
|
||||
$targetProfitRate = floatval(\App\Core\SettingsHelper::get('target_profit_rate'));
|
||||
$result = PK10Algorithm::generateControlledResult($bets, $waterConfig, 100, $targetProfitRate);
|
||||
} else {
|
||||
$result = PK10Algorithm::generateResult();
|
||||
}
|
||||
@@ -150,6 +170,17 @@ class PK10PeriodController extends AdminBaseController {
|
||||
'rank_10' => $result[9], 'champion_sum' => $sum,
|
||||
]);
|
||||
|
||||
$this->queueBotPushByGame($period['game_id'], 'draw', [
|
||||
'event' => 'period_drawn',
|
||||
'period_id' => (int)$period['id'],
|
||||
'period_number' => (string)($period['period_number'] ?? ''),
|
||||
'result' => $result,
|
||||
'champion_sum' => $sum,
|
||||
'manual' => !empty($manual),
|
||||
], [
|
||||
'remind_draw_result' => 1,
|
||||
], (string)($period['period_number'] ?? ''));
|
||||
|
||||
$this->db->medoo->pdo->commit();
|
||||
} catch (\Throwable $e) {
|
||||
$this->db->medoo->pdo->rollBack();
|
||||
@@ -180,6 +211,15 @@ class PK10PeriodController extends AdminBaseController {
|
||||
$bets = $this->db->select('bets', '*', ['period_id' => $periodId, 'status' => 'pending']);
|
||||
if (empty($bets)) {
|
||||
$this->db->update('periods', ['status' => 'settled'], ['id' => $periodId]);
|
||||
$this->queueBotPushByGame($period['game_id'], 'system', [
|
||||
'event' => 'period_settled',
|
||||
'period_id' => (int)$period['id'],
|
||||
'period_number' => (string)($period['period_number'] ?? ''),
|
||||
'wins' => 0,
|
||||
'losses' => 0,
|
||||
'total_payout' => 0,
|
||||
'message' => 'No bets to settle',
|
||||
], [], (string)($period['period_number'] ?? ''));
|
||||
$this->json(['status' => 'success', 'message' => 'No bets to settle', 'wins' => 0, 'losses' => 0]);
|
||||
return;
|
||||
}
|
||||
@@ -230,6 +270,14 @@ class PK10PeriodController extends AdminBaseController {
|
||||
$this->settleAgentCommissions($bets, $periodId);
|
||||
|
||||
$this->db->update('periods', ['status' => 'settled'], ['id' => $periodId]);
|
||||
$this->queueBotPushByGame($period['game_id'], 'system', [
|
||||
'event' => 'period_settled',
|
||||
'period_id' => (int)$period['id'],
|
||||
'period_number' => (string)($period['period_number'] ?? ''),
|
||||
'wins' => $wins,
|
||||
'losses' => $losses,
|
||||
'total_payout' => (float)$totalPayout,
|
||||
], [], (string)($period['period_number'] ?? ''));
|
||||
$this->db->medoo->pdo->commit();
|
||||
} catch (\Throwable $e) {
|
||||
$this->db->medoo->pdo->rollBack();
|
||||
@@ -298,6 +346,90 @@ class PK10PeriodController extends AdminBaseController {
|
||||
return $game ? (int)$game : 0;
|
||||
}
|
||||
|
||||
private function queueCountdownPushes(int $gameId, array $period): void {
|
||||
if ($gameId <= 0 || empty($period['id']) || empty($period['period_number'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$groups = $this->db->select('bot_groups', ['id', 'countdown_config'], [
|
||||
'game_id' => $gameId,
|
||||
'status' => 1,
|
||||
'remind_close_countdown' => 1,
|
||||
]) ?: [];
|
||||
if (empty($groups)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$game = $this->db->get('games', ['period_duration', 'lock_before_end'], ['id' => $gameId]);
|
||||
$periodDuration = (int)($game['period_duration'] ?? 300);
|
||||
$lockBeforeEnd = max(0, (int)($game['lock_before_end'] ?? 30));
|
||||
$periodCreatedAt = strtotime((string)($period['created_at'] ?? ''));
|
||||
if ($periodCreatedAt <= 0) {
|
||||
$periodCreatedAt = time();
|
||||
}
|
||||
$closeAtTs = $periodCreatedAt + max(0, $periodDuration - $lockBeforeEnd);
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
foreach ($groups as $group) {
|
||||
$decoded = json_decode((string)($group['countdown_config'] ?? ''), true);
|
||||
if (!is_array($decoded) || empty($decoded)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$secondsList = array_values(array_unique(array_filter(array_map('intval', $decoded), static function (int $seconds) use ($periodDuration, $lockBeforeEnd) {
|
||||
return $seconds > 0 && $seconds <= max(0, $periodDuration - $lockBeforeEnd);
|
||||
})));
|
||||
rsort($secondsList);
|
||||
|
||||
foreach ($secondsList as $seconds) {
|
||||
$dispatchAtTs = $closeAtTs - $seconds;
|
||||
if ($dispatchAtTs <= $periodCreatedAt) {
|
||||
continue;
|
||||
}
|
||||
$payload = [
|
||||
'event' => 'countdown_tick',
|
||||
'period_id' => (int)$period['id'],
|
||||
'period_number' => (string)$period['period_number'],
|
||||
'countdown_seconds' => $seconds,
|
||||
'dispatch_at' => date('Y-m-d H:i:s', $dispatchAtTs),
|
||||
'message' => sprintf('Bet closes in %d seconds', $seconds),
|
||||
];
|
||||
|
||||
$this->db->insert('bot_push_logs', [
|
||||
'group_id' => (int)$group['id'],
|
||||
'period_number' => (string)$period['period_number'],
|
||||
'push_type' => 'countdown',
|
||||
'payload_json' => json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
'status' => 'pending',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function queueBotPushByGame(int $gameId, string $pushType, array $payload, array $groupFilters = [], ?string $periodNumber = null): void {
|
||||
if ($gameId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$where = array_merge(['game_id' => $gameId, 'status' => 1], $groupFilters);
|
||||
$groups = $this->db->select('bot_groups', ['id'], $where) ?: [];
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$this->db->insert('bot_push_logs', [
|
||||
'group_id' => (int)$group['id'],
|
||||
'period_number' => $periodNumber !== null ? $periodNumber : ((string)($payload['period_number'] ?? '') ?: null),
|
||||
'push_type' => $pushType,
|
||||
'payload_json' => json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
'status' => 'pending',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function json(array $data) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($data);
|
||||
|
||||
Reference in New Issue
Block a user