1.优化ws游戏对局推送消息-小奖为bet.win
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user