1.优化开奖和推送

2.新增控制连续开奖赔率
This commit is contained in:
2026-04-20 10:02:27 +08:00
parent c184fa8a46
commit 24aab111b5
18 changed files with 749 additions and 37 deletions

View File

@@ -4,25 +4,27 @@ declare(strict_types=1);
namespace app\common\service;
use app\common\library\game\StreakWinReward;
use support\think\Db;
use Throwable;
/**
* 开奖后结算注单:写入 win_amount、status=已结算;中奖时入账并记 user_wallet_recordbiz_type=payout
* 连胜赔率来自 game_config.streak_win_reward结算后更新 user.current_streak未中奖则连胜归 0
*/
final class GameBetSettleService
{
private const BASE_ODDS = 33;
/**
* 对指定期次按开奖号码结算所有「待开奖」注单;同一注单幂等(仅 status=1 会更新)。
*
* @return array{jackpot_hits: list<array{user_id: int, period_no: string, total_win: string, result_number: int}>}
*
* @throws Throwable
*/
public static function settleBetsForDraw(int $recordId, int $resultNumber): void
public static function settleBetsForDraw(int $recordId, int $resultNumber): array
{
if ($recordId <= 0 || $resultNumber < 1) {
return;
return ['jackpot_hits' => []];
}
$now = time();
@@ -36,12 +38,26 @@ final class GameBetSettleService
/** @var array<int, array{period_no: string, total_win: string, balance_after: string, orders: list<array{order_no: string, win_amount: string, hit: bool}>}> */
$aggregateByUser = [];
/** @var array<int, array{streak_at: int, had_win: bool}> */
$userOutcome = [];
/** @var array<int, true> */
$jackpotNotify = [];
foreach ($bets as $bet) {
$betId = (int) ($bet['id'] ?? 0);
if ($betId <= 0) {
continue;
}
$userId = (int) ($bet['user_id'] ?? 0);
if ($userId > 0 && !isset($userOutcome[$userId])) {
$userOutcome[$userId] = [
'streak_at' => (int) ($bet['streak_at_bet'] ?? 0),
'had_win' => false,
];
}
$win = self::computeWinAmount($bet, $resultNumber);
$jackpot = '0.0000';
@@ -59,10 +75,17 @@ final class GameBetSettleService
continue;
}
// 结算刚刚成功status 1 → 2把本单下注总额 1:1 累加到用户打码量
self::creditUserBetFlow($bet, $now);
$userId = (int) ($bet['user_id'] ?? 0);
if ($userId > 0) {
if (bccomp($win, '0', 4) > 0) {
$userOutcome[$userId]['had_win'] = true;
}
if (bccomp($win, '0', 4) > 0 && StreakWinReward::isJackpotForStreakAtBet((int) ($bet['streak_at_bet'] ?? 0))) {
$jackpotNotify[$userId] = true;
}
}
if ($userId <= 0) {
continue;
}
@@ -93,6 +116,23 @@ final class GameBetSettleService
];
}
foreach ($userOutcome as $userId => $info) {
$streakAt = (int) ($info['streak_at'] ?? 0);
$hadWin = (bool) ($info['had_win'] ?? false);
if ($hadWin) {
$next = $streakAt + 1;
if ($next > 10) {
$next = 10;
}
} else {
$next = 0;
}
Db::name('user')->where('id', $userId)->update([
'current_streak' => $next,
'update_time' => $now,
]);
}
foreach ($aggregateByUser as $userId => $agg) {
$hitOrderCount = 0;
foreach ($agg['orders'] as $o) {
@@ -119,6 +159,25 @@ final class GameBetSettleService
]);
}
}
$jackpotHits = [];
foreach ($jackpotNotify as $uid => $_) {
if (!isset($aggregateByUser[$uid])) {
continue;
}
$agg = $aggregateByUser[$uid];
if (bccomp($agg['total_win'], '0', 4) <= 0) {
continue;
}
$jackpotHits[] = [
'user_id' => (int) $uid,
'period_no' => (string) ($agg['period_no'] ?? ''),
'total_win' => (string) $agg['total_win'],
'result_number' => $resultNumber,
];
}
return ['jackpot_hits' => $jackpotHits];
}
/**
@@ -150,8 +209,9 @@ final class GameBetSettleService
}
Db::startTrans();
try {
self::settleBetsForDraw($rid, $rn);
$out = self::settleBetsForDraw($rid, $rn);
Db::commit();
JackpotPushService::publishHits($out['jackpot_hits'] ?? []);
$count++;
} catch (Throwable $e) {
Db::rollback();
@@ -163,7 +223,7 @@ final class GameBetSettleService
}
/**
* 应付派彩:开奖号码 ∈ pick_numbers 即中奖;整笔 total_amount × (连胜+1) × 33与 GameLiveService 一致)。
* 应付派彩:开奖号码 ∈ pick_numbers 即中奖;整笔 total_amount × odds_factorodds_factor 来自连胜奖励表对应档位)。
*/
public static function computeWinAmount(array $bet, int $resultNumber): string
{
@@ -180,7 +240,7 @@ final class GameBetSettleService
}
$total = (string) ($bet['total_amount'] ?? '0');
$streak = (int) ($bet['streak_at_bet'] ?? 0);
$odds = (string) (($streak + 1) * self::BASE_ODDS);
$odds = StreakWinReward::totalOddsMultiplierForStreakAtBet($streak);
return bcmul($total, $odds, 4);
}
@@ -206,7 +266,6 @@ final class GameBetSettleService
if (bccomp($flow, '0', 4) <= 0) {
return;
}
// 原子加法:避免读-改-写导致的并发覆盖;$flow 已由 bcadd 归一化为纯数字字符串,不存在 SQL 注入
Db::name('user')
->where('id', $userId)
->update([