完善接口和后台页面

This commit is contained in:
2026-04-18 15:19:36 +08:00
parent a4878a9bbd
commit e3f26ba1f7
45 changed files with 3071 additions and 232 deletions

View File

@@ -56,6 +56,9 @@ final class GameBetSettleService
continue;
}
// 结算刚刚成功status 1 → 2把本单下注总额 1:1 累加到用户打码量
self::creditUserBetFlow($bet, $now);
if (bccomp($win, '0', 4) <= 0) {
continue;
}
@@ -106,7 +109,7 @@ final class GameBetSettleService
}
/**
* 单注应付派彩:命中开奖号码 unit × (连胜+1) × 33与 GameLiveService 一致)。
* 应付派彩:开奖号码 ∈ pick_numbers 即中奖;整笔 total_amount × (连胜+1) × 33与 GameLiveService 一致)。
*/
public static function computeWinAmount(array $bet, int $resultNumber): string
{
@@ -121,11 +124,41 @@ final class GameBetSettleService
if (!in_array($resultNumber, array_map('intval', $pickNumbers), true)) {
return '0.0000';
}
$unit = (string) ($bet['unit_amount'] ?? '0');
$total = (string) ($bet['total_amount'] ?? '0');
$streak = (int) ($bet['streak_at_bet'] ?? 0);
$odds = (string) (($streak + 1) * self::BASE_ODDS);
return bcmul($unit, $odds, 4);
return bcmul($total, $odds, 4);
}
/**
* 累加玩家打码量(流水):按本注单 total_amount 1:1 加到 user.bet_flow_coin。
*
* 幂等性由调用点保证:只有 bet_order 首次从 status=1 变更为 status=2返回 $affected=1
* 时才会调用本方法,重复结算不会触发。
*/
private static function creditUserBetFlow(array $bet, int $now): void
{
$userId = isset($bet['user_id']) && is_numeric($bet['user_id']) ? intval($bet['user_id']) : 0;
if ($userId <= 0) {
return;
}
$totalRaw = $bet['total_amount'] ?? '0';
$total = is_string($totalRaw) ? trim($totalRaw) : (is_numeric($totalRaw) ? strval($totalRaw) : '0');
if ($total === '' || !is_numeric($total)) {
return;
}
$flow = bcadd($total, '0', 4);
if (bccomp($flow, '0', 4) <= 0) {
return;
}
// 原子加法:避免读-改-写导致的并发覆盖;$flow 已由 bcadd 归一化为纯数字字符串,不存在 SQL 注入
Db::name('user')
->where('id', $userId)
->update([
'bet_flow_coin' => Db::raw('bet_flow_coin + ' . $flow),
'update_time' => $now,
]);
}
private static function creditUserPayout(array $bet, int $betId, string $winAmount, int $now): void

View File

@@ -89,7 +89,6 @@ final class GameLiveService
'user_id' => (int) $row['user_id'],
'period_no' => (string) $row['period_no'],
'pick_numbers' => $row['pick_numbers'],
'unit_amount' => (string) $row['unit_amount'],
'total_amount' => (string) $row['total_amount'],
'streak_at_bet' => (int) $row['streak_at_bet'],
'create_time' => (int) $row['create_time'],
@@ -303,10 +302,10 @@ final class GameLiveService
if (!in_array($number, array_map('intval', $pickNumbers), true)) {
continue;
}
$unit = (string) ($bet['unit_amount'] ?? '0');
$total = (string) ($bet['total_amount'] ?? '0');
$streak = (int) ($bet['streak_at_bet'] ?? 0);
$odds = (string) (($streak + 1) * self::BASE_ODDS);
$orderPayout = bcmul($unit, $odds, 4);
$orderPayout = bcmul($total, $odds, 4);
$payout = bcadd($payout, $orderPayout, 4);
}
return $payout;

View File

@@ -82,7 +82,7 @@ final class GameRecordStatService
}
/**
* 与 GameLiveService::estimateLossForNumber 中单注派彩一致:命中号码时 unit × (streak+1) × 33。
* 与 GameLiveService::estimateLossForNumber 中派彩一致:命中号码时 total_amount × (streak+1) × 33。
*/
private static function estimatePayoutForBet(array $bet, int $resultNumber): string
{
@@ -97,10 +97,10 @@ final class GameRecordStatService
if (!in_array($resultNumber, array_map('intval', $pickNumbers), true)) {
return '0.0000';
}
$unit = (string) ($bet['unit_amount'] ?? '0');
$total = (string) ($bet['total_amount'] ?? '0');
$streak = (int) ($bet['streak_at_bet'] ?? 0);
$odds = (string) (($streak + 1) * self::BASE_ODDS);
return bcmul($unit, $odds, 4);
return bcmul($total, $odds, 4);
}
}