feat: 彩票业务迁移并补全后台权限与代理结算体系
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Lottery\DrawStatus;
|
||||
use App\Models\DrawResultItem;
|
||||
use App\Models\DrawResultBatch;
|
||||
use App\Lottery\DrawResultBatchStatus;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Services\Jackpot\JackpotSummaryService;
|
||||
use App\Services\LotterySettings;
|
||||
|
||||
@@ -19,6 +20,12 @@ use App\Services\LotterySettings;
|
||||
*/
|
||||
final class DrawHallSnapshotBuilder
|
||||
{
|
||||
private const JACKPOT_CACHE_TTL_SECONDS = 5;
|
||||
|
||||
private const RISK_ALERTS_CACHE_TTL_SECONDS = 2;
|
||||
|
||||
private const RESULT_ITEMS_CACHE_TTL_SECONDS = 5;
|
||||
|
||||
public function __construct(
|
||||
private readonly JackpotSummaryService $jackpotSummary,
|
||||
) {}
|
||||
@@ -108,6 +115,20 @@ final class DrawHallSnapshotBuilder
|
||||
DrawStatus::Settled->value,
|
||||
DrawStatus::Cancelled->value,
|
||||
])
|
||||
->where(function ($q) use ($nowUtc): void {
|
||||
$q->where('status', '!=', DrawStatus::Pending->value)
|
||||
->orWhere(function ($q2) use ($nowUtc): void {
|
||||
$q2->where('status', DrawStatus::Pending->value)
|
||||
->where(function ($q3) use ($nowUtc): void {
|
||||
$q3->whereNull('close_time')
|
||||
->orWhere('close_time', '>', $nowUtc);
|
||||
})
|
||||
->where(function ($q3) use ($nowUtc): void {
|
||||
$q3->whereNull('draw_time')
|
||||
->orWhere('draw_time', '>', $nowUtc);
|
||||
});
|
||||
});
|
||||
})
|
||||
->where(function ($q) use ($nowUtc): void {
|
||||
$q->where(function ($q2) use ($nowUtc): void {
|
||||
$q2->whereNotNull('close_time')
|
||||
@@ -258,56 +279,19 @@ final class DrawHallSnapshotBuilder
|
||||
'cooling_end_time' => $target->cooling_end_time?->toIso8601String(),
|
||||
'seconds_remaining_in_cooldown' => $coolingRemain,
|
||||
'jackpot_currency_code' => $currencyCode,
|
||||
'jackpot' => $this->jackpotSummary->summary($currencyCode),
|
||||
'jackpot' => $this->cachedJackpotSummary($currencyCode),
|
||||
];
|
||||
|
||||
$riskAlerts = RiskPool::query()
|
||||
->where('draw_id', $target->id)
|
||||
->where(function ($q): void {
|
||||
$q->where('sold_out_status', 1)
|
||||
->orWhereRaw('(locked_amount * 1.0 / NULLIF(total_cap_amount, 0)) >= 0.8');
|
||||
})
|
||||
->orderByRaw('(locked_amount * 1.0 / NULLIF(total_cap_amount, 0)) DESC')
|
||||
->orderByDesc('locked_amount')
|
||||
->orderBy('normalized_number')
|
||||
->limit(500)
|
||||
->get(['normalized_number', 'sold_out_status'])
|
||||
->map(fn ($row) => [
|
||||
'normalized_number' => (string) $row->normalized_number,
|
||||
'status' => (int) $row->sold_out_status === 1 ? 'sold_out' : 'warning',
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$payload['risk_pool_alerts'] = $riskAlerts;
|
||||
$payload['risk_pool_alerts'] = $this->cachedRiskAlerts((int) $target->id);
|
||||
|
||||
if ($this->showsPublishedResults((string) $target->status)) {
|
||||
$batchId = DrawResultBatch::query()
|
||||
->where('draw_id', $target->id)
|
||||
->where('result_version', (int) $target->current_result_version)
|
||||
->where('status', DrawResultBatchStatus::Published->value)
|
||||
->value('id');
|
||||
$resultItems = $this->cachedPublishedResultItems(
|
||||
(int) $target->id,
|
||||
(int) $target->current_result_version,
|
||||
);
|
||||
|
||||
if ($batchId !== null) {
|
||||
$payload['result_items'] = DrawResultItem::query()
|
||||
->where('result_batch_id', $batchId)
|
||||
->orderBy('prize_type')
|
||||
->orderBy('prize_index')
|
||||
->get([
|
||||
'prize_type', 'prize_index',
|
||||
'number_4d', 'suffix_3d', 'suffix_2d', 'head_digit', 'tail_digit',
|
||||
])
|
||||
->map(fn ($row) => [
|
||||
'prize_type' => $row->prize_type,
|
||||
'prize_index' => (int) $row->prize_index,
|
||||
'number_4d' => $row->number_4d,
|
||||
'suffix_3d' => $row->suffix_3d,
|
||||
'suffix_2d' => $row->suffix_2d,
|
||||
'head_digit' => $row->head_digit,
|
||||
'tail_digit' => $row->tail_digit,
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
if ($resultItems !== null) {
|
||||
$payload['result_items'] = $resultItems;
|
||||
}
|
||||
|
||||
$payload['result_version'] = (int) $target->current_result_version;
|
||||
@@ -327,4 +311,89 @@ final class DrawHallSnapshotBuilder
|
||||
|
||||
return LotterySettings::defaultCurrency();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function cachedJackpotSummary(string $currencyCode): array
|
||||
{
|
||||
$cacheKey = sprintf('hall_snapshot:jackpot:%s', strtoupper($currencyCode));
|
||||
|
||||
/** @var array<string, mixed> */
|
||||
return Cache::remember($cacheKey, self::JACKPOT_CACHE_TTL_SECONDS, fn (): array => $this->jackpotSummary->summary($currencyCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{normalized_number: string, status: string}>
|
||||
*/
|
||||
private function cachedRiskAlerts(int $drawId): array
|
||||
{
|
||||
$cacheKey = sprintf('hall_snapshot:risk_alerts:%d', $drawId);
|
||||
|
||||
/** @var list<array{normalized_number: string, status: string}> */
|
||||
return Cache::remember($cacheKey, self::RISK_ALERTS_CACHE_TTL_SECONDS, function () use ($drawId): array {
|
||||
return RiskPool::query()
|
||||
->where('draw_id', $drawId)
|
||||
->where(function ($q): void {
|
||||
$q->where('sold_out_status', 1)
|
||||
->orWhereRaw('(locked_amount * 1.0 / NULLIF(total_cap_amount, 0)) >= 0.8');
|
||||
})
|
||||
->orderByRaw('(locked_amount * 1.0 / NULLIF(total_cap_amount, 0)) DESC')
|
||||
->orderByDesc('locked_amount')
|
||||
->orderBy('normalized_number')
|
||||
->limit(500)
|
||||
->get(['normalized_number', 'sold_out_status'])
|
||||
->map(fn ($row) => [
|
||||
'normalized_number' => (string) $row->normalized_number,
|
||||
'status' => (int) $row->sold_out_status === 1 ? 'sold_out' : 'warning',
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<string, mixed>>|null
|
||||
*/
|
||||
private function cachedPublishedResultItems(int $drawId, int $resultVersion): ?array
|
||||
{
|
||||
if ($resultVersion <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = sprintf('hall_snapshot:result_items:%d:%d', $drawId, $resultVersion);
|
||||
|
||||
/** @var list<array<string, mixed>>|null */
|
||||
return Cache::remember($cacheKey, self::RESULT_ITEMS_CACHE_TTL_SECONDS, function () use ($drawId, $resultVersion): ?array {
|
||||
$batchId = DrawResultBatch::query()
|
||||
->where('draw_id', $drawId)
|
||||
->where('result_version', $resultVersion)
|
||||
->where('status', DrawResultBatchStatus::Published->value)
|
||||
->value('id');
|
||||
|
||||
if ($batchId === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DrawResultItem::query()
|
||||
->where('result_batch_id', $batchId)
|
||||
->orderBy('prize_type')
|
||||
->orderBy('prize_index')
|
||||
->get([
|
||||
'prize_type', 'prize_index',
|
||||
'number_4d', 'suffix_3d', 'suffix_2d', 'head_digit', 'tail_digit',
|
||||
])
|
||||
->map(fn ($row) => [
|
||||
'prize_type' => $row->prize_type,
|
||||
'prize_index' => (int) $row->prize_index,
|
||||
'number_4d' => $row->number_4d,
|
||||
'suffix_3d' => $row->suffix_3d,
|
||||
'suffix_2d' => $row->suffix_2d,
|
||||
'head_digit' => $row->head_digit,
|
||||
'tail_digit' => $row->tail_digit,
|
||||
])
|
||||
->values()
|
||||
->all();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user