1.优化ws游戏对局推送消息-小奖为bet.win

This commit is contained in:
2026-05-26 12:31:33 +08:00
parent 7edc3ec010
commit ae7af24565
5 changed files with 101 additions and 17 deletions

View File

@@ -26,13 +26,18 @@ class GameCurrentStatus extends Backend
$subscribeTopics = [
'period.tick',
'user.streak',
'period.opened',
'period.locked',
'period.opened',
'period.payout',
'bet.accepted',
'period.payout.tick',
'bet.win',
'user.streak',
'wallet.changed',
'bet.accepted',
'jackpot.hit',
'auto.spin.progress',
'admin.live.snapshot',
'admin.live.opened',
];
$oddsPushTopics = GameWebSocketPayloadHelper::ODDS_PUSH_TOPICS;

View File

@@ -22,17 +22,23 @@ final class GameBetSettleService
public const CONFIG_KEY_JACKPOT_MAX_AMOUNT = 'jackpot_max_amount';
/** 小奖(非大奖档)中奖:移动端弹窗/通知专用 */
public const TOPIC_BET_WIN = 'bet.win';
/**
* 对指定期次按开奖号码结算所有「待开奖」注单;同一注单幂等(仅 status=1 会更新)。
*
* @return array{jackpot_hits: list<array{user_id: int, nickname: string, period_no: string, total_win: string, result_number: int}>}
* @return array{
* jackpot_hits: list<array{user_id: int, nickname: string, period_no: string, total_win: string, result_number: int}>,
* bet_wins: list<array<string, mixed>>
* }
*
* @throws Throwable
*/
public static function settleBetsForDraw(int $recordId, int $resultNumber): array
{
if ($recordId <= 0 || $resultNumber < 1) {
return ['jackpot_hits' => []];
return ['jackpot_hits' => [], 'bet_wins' => []];
}
$now = time();
@@ -53,6 +59,9 @@ final class GameBetSettleService
/** @var array<int, true> */
$jackpotNotify = [];
/** @var array<int, array{user_id: int, period_id: int, period_no: string, result_number: int, total_win: string, balance_after: string, bets: list<array{bet_id: int, win_amount: string}>}> */
$smallWinByUser = [];
foreach ($bets as $bet) {
$betId = (int) ($bet['id'] ?? 0);
if ($betId <= 0) {
@@ -103,10 +112,30 @@ final class GameBetSettleService
$balanceAfter = (string) (Db::name('user')->where('id', $userId)->value('coin') ?? '0');
if (!$needReview && bccomp($win, '0', 2) > 0) {
$paid = self::creditUserPayout($bet, $betId, $win, $now, null, '压注派彩');
$paid = self::creditUserPayout($bet, $betId, $win, $now, null, '压注派彩', $resultNumber);
if ($paid !== null) {
$balanceAfter = $paid;
}
$streakAtBet = (int) ($bet['streak_at_bet'] ?? 0);
if ($paid !== null && !StreakWinReward::isJackpotForStreakAtBet($streakAtBet)) {
if (!isset($smallWinByUser[$userId])) {
$smallWinByUser[$userId] = [
'user_id' => $userId,
'period_id' => $recordId,
'period_no' => (string) ($bet['period_no'] ?? ''),
'result_number' => $resultNumber,
'total_win' => '0.00',
'balance_after' => $balanceAfter,
'bets' => [],
];
}
$smallWinByUser[$userId]['total_win'] = bcadd($smallWinByUser[$userId]['total_win'], $win, 2);
$smallWinByUser[$userId]['balance_after'] = $balanceAfter;
$smallWinByUser[$userId]['bets'][] = [
'bet_id' => $betId,
'win_amount' => $win,
];
}
}
$periodNo = (string) ($bet['period_no'] ?? '');
@@ -170,7 +199,32 @@ final class GameBetSettleService
];
}
return ['jackpot_hits' => $jackpotHits];
$betWins = array_values($smallWinByUser);
return ['jackpot_hits' => $jackpotHits, 'bet_wins' => $betWins];
}
/**
* 事务提交后推送小奖中奖bet.win
*
* @param list<array<string, mixed>> $betWins
*/
public static function publishBetWinsAfterCommit(array $betWins): void
{
foreach ($betWins as $payload) {
if (!is_array($payload) || empty($payload['user_id'])) {
continue;
}
$userId = filter_var($payload['user_id'], FILTER_VALIDATE_INT);
if ($userId === false || $userId <= 0) {
continue;
}
$data = array_merge($payload, [
'is_jackpot' => false,
'server_time' => time(),
]);
GameWebSocketEventBus::publish(self::TOPIC_BET_WIN, $data);
}
}
/**
@@ -408,7 +462,7 @@ final class GameBetSettleService
/**
* @return string|null 派彩后余额;已幂等入账过时返回当前余额;失败或未执行派彩返回 null
*/
private static function creditUserPayout(array $bet, int $betId, string $winAmount, int $now, ?int $operatorAdminId, string $remark): ?string
private static function creditUserPayout(array $bet, int $betId, string $winAmount, int $now, ?int $operatorAdminId, string $remark, ?int $resultNumber = null): ?string
{
$userId = (int) ($bet['user_id'] ?? 0);
if ($userId <= 0) {
@@ -451,13 +505,20 @@ final class GameBetSettleService
'update_time' => $now,
]);
GameHotDataCoordinator::afterUserCommitted($userId);
GameWebSocketEventBus::publish('wallet.changed', GameWebSocketPayloadHelper::mergeUserStreakInto([
$walletPayload = [
'user_id' => $userId,
'balance_after' => $after,
'biz_type' => 'payout',
'ref_id' => $betId,
'amount' => $winAmount,
'period_no' => (string) ($bet['period_no'] ?? ''),
'period_id' => isset($bet['period_id']) && is_numeric($bet['period_id']) ? (int) $bet['period_id'] : 0,
'changed_at' => $now,
], $userId));
];
if ($resultNumber !== null && $resultNumber > 0) {
$walletPayload['result_number'] = $resultNumber;
}
GameWebSocketEventBus::publish('wallet.changed', GameWebSocketPayloadHelper::mergeUserStreakInto($walletPayload, $userId));
return $after;
}

View File

@@ -101,9 +101,10 @@ final class GameLiveService
$now = time();
$payoutUntil = isset($row['payout_until']) ? (int) $row['payout_until'] : 0;
$settleOut = ['jackpot_hits' => [], 'bet_wins' => []];
Db::startTrans();
try {
GameBetSettleService::settleBetsForDraw($recordId, $resultNumber);
$settleOut = GameBetSettleService::settleBetsForDraw($recordId, $resultNumber);
if ($status === 2) {
if ($payoutUntil <= 0) {
$payoutUntil = $now + self::getPayoutGraceSeconds();
@@ -139,6 +140,9 @@ final class GameLiveService
return;
}
$betWins = is_array($settleOut['bet_wins'] ?? null) ? $settleOut['bet_wins'] : [];
GameBetSettleService::publishBetWinsAfterCommit($betWins);
GameHotDataCoordinator::afterGameRecordCommitted($recordId);
self::publishSnapshot(null);
@@ -585,7 +589,7 @@ final class GameLiveService
$now = time();
$payoutUntil = $now + self::getPayoutGraceSeconds();
$settleOut = ['jackpot_hits' => []];
$settleOut = ['jackpot_hits' => [], 'bet_wins' => []];
Db::startTrans();
try {
Db::name('game_record')->where('id', (int) $record['id'])->update([
@@ -603,6 +607,9 @@ final class GameLiveService
return ['ok' => false, 'msg' => __('Game live: settlement error') . ': ' . $e->getMessage()];
}
$betWins = is_array($settleOut['bet_wins'] ?? null) ? $settleOut['bet_wins'] : [];
GameBetSettleService::publishBetWinsAfterCommit($betWins);
GameHotDataCoordinator::afterGameRecordCommitted($rid);
try {