1.优化开奖逻辑
2.优化后台开奖派彩 3.优化接口规范
This commit is contained in:
172
app/common/service/GameBetSettleService.php
Normal file
172
app/common/service/GameBetSettleService.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use support\think\Db;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 开奖后结算注单:写入 win_amount、status=已结算;中奖时入账并记 user_wallet_record(biz_type=payout)。
|
||||
*/
|
||||
final class GameBetSettleService
|
||||
{
|
||||
private const BASE_ODDS = 33;
|
||||
|
||||
/**
|
||||
* 对指定期次按开奖号码结算所有「待开奖」注单;同一注单幂等(仅 status=1 会更新)。
|
||||
*
|
||||
* @throws Throwable
|
||||
*/
|
||||
public static function settleBetsForDraw(int $recordId, int $resultNumber): void
|
||||
{
|
||||
if ($recordId <= 0 || $resultNumber < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$bets = Db::name('bet_order')
|
||||
->where('period_id', $recordId)
|
||||
->where('status', 1)
|
||||
->order('id', 'asc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
foreach ($bets as $bet) {
|
||||
$betId = (int) ($bet['id'] ?? 0);
|
||||
if ($betId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$win = self::computeWinAmount($bet, $resultNumber);
|
||||
$jackpot = '0.0000';
|
||||
|
||||
$affected = Db::name('bet_order')
|
||||
->where('id', $betId)
|
||||
->where('status', 1)
|
||||
->update([
|
||||
'win_amount' => $win,
|
||||
'jackpot_extra_amount' => $jackpot,
|
||||
'status' => 2,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
|
||||
if ($affected === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bccomp($win, '0', 4) <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
self::creditUserPayout($bet, $betId, $win, $now);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 补偿:库中已结束局次但注单仍为待开奖的,可重复调用(幂等)。
|
||||
*/
|
||||
public static function settlePendingForEndedRecords(): int
|
||||
{
|
||||
$rows = Db::name('game_record')
|
||||
->where('status', 4)
|
||||
->whereNotNull('result_number')
|
||||
->field(['id', 'result_number'])
|
||||
->order('id', 'asc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
$count = 0;
|
||||
foreach ($rows as $row) {
|
||||
$rid = (int) ($row['id'] ?? 0);
|
||||
$rn = (int) ($row['result_number'] ?? 0);
|
||||
if ($rid <= 0 || $rn < 1) {
|
||||
continue;
|
||||
}
|
||||
$pending = Db::name('bet_order')
|
||||
->where('period_id', $rid)
|
||||
->where('status', 1)
|
||||
->count();
|
||||
if ($pending === 0) {
|
||||
continue;
|
||||
}
|
||||
Db::startTrans();
|
||||
try {
|
||||
self::settleBetsForDraw($rid, $rn);
|
||||
Db::commit();
|
||||
$count++;
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单注应付派彩:命中开奖号码时 unit × (连胜+1) × 33(与 GameLiveService 一致)。
|
||||
*/
|
||||
public static function computeWinAmount(array $bet, int $resultNumber): string
|
||||
{
|
||||
$pickNumbers = $bet['pick_numbers'] ?? null;
|
||||
if (is_string($pickNumbers)) {
|
||||
$decoded = json_decode($pickNumbers, true);
|
||||
$pickNumbers = is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
if (!is_array($pickNumbers)) {
|
||||
$pickNumbers = [];
|
||||
}
|
||||
if (!in_array($resultNumber, array_map('intval', $pickNumbers), true)) {
|
||||
return '0.0000';
|
||||
}
|
||||
$unit = (string) ($bet['unit_amount'] ?? '0');
|
||||
$streak = (int) ($bet['streak_at_bet'] ?? 0);
|
||||
$odds = (string) (($streak + 1) * self::BASE_ODDS);
|
||||
|
||||
return bcmul($unit, $odds, 4);
|
||||
}
|
||||
|
||||
private static function creditUserPayout(array $bet, int $betId, string $winAmount, int $now): void
|
||||
{
|
||||
$userId = (int) ($bet['user_id'] ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$idem = 'payout_bet_' . $betId;
|
||||
if (Db::name('user_wallet_record')->where('idempotency_key', $idem)->value('id')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = Db::name('user')->where('id', $userId)->find();
|
||||
if (!$user) {
|
||||
return;
|
||||
}
|
||||
|
||||
$before = (string) ($user['coin'] ?? '0');
|
||||
$after = bcadd($before, $winAmount, 4);
|
||||
|
||||
Db::name('user_wallet_record')->insert([
|
||||
'user_id' => $userId,
|
||||
'channel_id' => $bet['channel_id'] ?? null,
|
||||
'biz_type' => 'payout',
|
||||
'direction' => 1,
|
||||
'amount' => $winAmount,
|
||||
'balance_before' => $before,
|
||||
'balance_after' => $after,
|
||||
'ref_type' => 'bet_order',
|
||||
'ref_id' => $betId,
|
||||
'idempotency_key' => $idem,
|
||||
'operator_admin_id' => null,
|
||||
'remark' => '压注派彩',
|
||||
'create_time' => $now,
|
||||
]);
|
||||
|
||||
Db::name('user')->where('id', $userId)->update([
|
||||
'coin' => $after,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user