0) { $pid = Db::name('game_play_record')->where('id', $playId)->value('period_id'); $periodId = is_numeric((string) $pid) ? (int) $pid : 0; echo "play_record_id={$playId} => period_id={$periodId}" . PHP_EOL; } } if ($periodId <= 0 && isset($opts['period-no'])) { $periodNo = trim((string) $opts['period-no']); if ($periodNo !== '') { $pid = Db::name('game_record')->where('period_no', $periodNo)->value('id'); $periodId = is_numeric((string) $pid) ? (int) $pid : 0; echo "period_no={$periodNo} => period_id={$periodId}" . PHP_EOL; } } if ($periodId <= 0) { fwrite(STDERR, "请指定 --period-id、--play-record-id 或 --period-no\n"); exit(1); } $row = Db::name('game_record')->where('id', $periodId)->find(); if (!is_array($row)) { fwrite(STDERR, "对局不存在: period_id={$periodId}\n"); exit(1); } $resultNumber = filter_var($row['result_number'] ?? 0, FILTER_VALIDATE_INT); if ($resultNumber === false || $resultNumber < 1) { fwrite(STDERR, "对局尚未开奖,无法补发\n"); exit(1); } $periodNo = (string) ($row['period_no'] ?? ''); $drawMode = filter_var($row['draw_mode'] ?? 0, FILTER_VALIDATE_INT); $payoutUntil = filter_var($row['payout_until'] ?? 0, FILTER_VALIDATE_INT); $openTime = filter_var($row['update_time'] ?? time(), FILTER_VALIDATE_INT); if ($openTime === false || $openTime <= 0) { $openTime = time(); } if ($force) { try { Redis::del('dfw:v1:ws:period_opened:' . $periodId); Redis::del('dfw:v1:ws:period_payout:' . $periodId); } catch (Throwable) { } $payloads = GameBetSettleService::buildBetWinPayloadsFromSettledOrders($periodId, $resultNumber); foreach ($payloads as $payload) { $uid = (int) ($payload['user_id'] ?? 0); if ($uid > 0) { try { Redis::del('dfw:v1:ws:betwin:' . $periodId . ':' . $uid); } catch (Throwable) { } } } echo "已清除 dedup 键(--force)\n"; } GameLiveService::ensurePeriodDrawNotifications( $periodId, $periodNo, $resultNumber, $drawMode === false ? 0 : $drawMode, $payoutUntil !== false && $payoutUntil > 0 ? $payoutUntil : time(), $openTime ); $payloads = GameBetSettleService::buildBetWinPayloadsFromSettledOrders($periodId, $resultNumber); if ($payloads !== []) { // 同时触发 jackpot.hit(若 bet.win 判定为大奖则应广播);publishSettlementWinsAfterCommit 内含 jackpot.hit 独立去重与从 bet_wins 重建兜底 GameBetSettleService::publishSettlementWinsAfterCommit([ 'jackpot_hits' => [], 'bet_wins' => $payloads, 'user_streak_events' => [], 'wallet_events' => [], 'settled_order_count' => 0, ], $periodId, $periodNo, $resultNumber); GameBetSettleService::publishBetWinsAfterCommit($payloads, $periodId); echo 'bet.win republished for user_ids: ' . implode(',', array_map(static fn (array $p): int => (int) ($p['user_id'] ?? 0), $payloads)) . PHP_EOL; } else { echo "本期无已结算中奖注单。\n"; } echo "done period_id={$periodId} period_no={$periodNo} result={$resultNumber}\n";