From bad6641eeb8c6ec1739c17648f9061b6dfaba2a0 Mon Sep 17 00:00:00 2001 From: zhenhui <1276357500@qq.com> Date: Tue, 26 May 2026 11:13:35 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BC=98=E5=8C=96ws=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E5=AF=B9=E5=B1=80=E6=8E=A8=E9=80=81=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/service/GameLiveService.php | 41 ++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/app/common/service/GameLiveService.php b/app/common/service/GameLiveService.php index cde4276..f8cef97 100644 --- a/app/common/service/GameLiveService.php +++ b/app/common/service/GameLiveService.php @@ -608,7 +608,7 @@ final class GameLiveService } catch (Throwable) { } self::publishPublicPeriodOpened((string) $record['period_no'], $finalNumber, $now); - self::publishPublicPeriodPayout((string) $record['period_no'], $finalNumber, $payoutUntil); + self::publishPublicPeriodPayout($rid, (string) $record['period_no'], $finalNumber, $payoutUntil, $now); $jackpotHits = is_array($settleOut['jackpot_hits'] ?? null) ? $settleOut['jackpot_hits'] : []; GameWebSocketEventBus::publish('admin.live.opened', [ 'period_id' => $rid, @@ -661,6 +661,11 @@ final class GameLiveService return; } try { + $periodNo = is_string($row['period_no'] ?? null) ? (string) $row['period_no'] : ''; + $resultNumber = filter_var($row['result_number'] ?? 0, FILTER_VALIDATE_INT); + if ($resultNumber === false || $resultNumber < 1) { + $resultNumber = null; + } Db::startTrans(); try { Db::name('game_record')->where('id', $id)->update([ @@ -676,6 +681,7 @@ final class GameLiveService } GameHotDataCoordinator::afterGameRecordCommitted($id); GameRecordStatService::refreshForRecordId($id); + self::publishPublicPeriodFinished($id, $periodNo, $resultNumber); self::publishSnapshot(null); } finally { GameHotDataLock::release(GameHotDataLock::TYPE_GAME_RECORD, (string) $id, $lock['token'], $lock['redis_lock']); @@ -1003,14 +1009,43 @@ final class GameLiveService } /** - * 派彩阶段开始(开奖后宽限期内推送) + * 派彩阶段开始(开奖后宽限期内推送)。 + * 客户端应以 payout_until 与 server_time 做倒计时,勿用 period.tick 或上期 countdown。 */ - private static function publishPublicPeriodPayout(string $periodNo, int $resultNumber, int $payoutUntil): void + private static function publishPublicPeriodPayout(int $periodId, string $periodNo, int $resultNumber, int $payoutUntil, int $serverTime): void { + $grace = self::getPayoutGraceSeconds(); + $remaining = max(0, $payoutUntil - $serverTime); GameWebSocketEventBus::publish(self::EVT_PERIOD_PAYOUT, [ + 'period_id' => $periodId, 'period_no' => $periodNo, 'result_number' => $resultNumber, 'payout_until' => $payoutUntil, + 'payout_seconds' => $grace, + 'payout_remaining_seconds' => $remaining, + 'server_time' => $serverTime, + ]); + } + + /** + * 派彩宽限期结束、进入下一期前:推送本期收尾帧(每期一次)。 + */ + private static function publishPublicPeriodFinished(int $periodId, string $periodNo, ?int $resultNumber): void + { + if ($periodNo === '') { + return; + } + if (!self::markBoundaryFrameOnce($periodNo, 'finished')) { + return; + } + GameWebSocketEventBus::publish(self::EVT_PERIOD_TICK, [ + 'period_id' => $periodId, + 'period_no' => $periodNo, + 'status' => 'finished', + 'countdown' => 0, + 'bet_close_in' => 0, + 'result_number' => $resultNumber, + 'runtime_enabled' => GameRecordService::isLiveRuntimeEnabled(), 'server_time' => time(), ]); }