feat: 添加 Laravel Reverb 支持,更新 .env.example 文件以配置 WebSocket,增强彩票调度功能,更新 API 路由以支持期号管理与结果发布
This commit is contained in:
169
app/Services/Draw/DrawResultViewService.php
Normal file
169
app/Services/Draw/DrawResultViewService.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Draw;
|
||||
|
||||
use App\Lottery\DrawResultBatchStatus;
|
||||
use App\Lottery\DrawStatus;
|
||||
use App\Models\Draw;
|
||||
use App\Models\DrawResultBatch;
|
||||
use App\Models\DrawResultItem;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* 将已发布的 {@see DrawResultItem} 聚合成前端/文档约定结构。
|
||||
*/
|
||||
final class DrawResultViewService
|
||||
{
|
||||
/**
|
||||
* 与 `docs/01-产品文档` GET /api/v1/results 示例键名对齐(1st/2nd/3rd/starter/consolation)。
|
||||
*
|
||||
* @return array{
|
||||
* 1st: string,
|
||||
* 2nd: string,
|
||||
* 3rd: string,
|
||||
* starter: array<int, string>,
|
||||
* consolation: array<int, string>
|
||||
* }
|
||||
*/
|
||||
public function numbersFromItems(Collection $items): array
|
||||
{
|
||||
$byType = [
|
||||
'first' => [],
|
||||
'second' => [],
|
||||
'third' => [],
|
||||
'starter' => [],
|
||||
'consolation' => [],
|
||||
];
|
||||
|
||||
foreach ($items->sortBy(['prize_type', 'prize_index']) as $row) {
|
||||
/** @var DrawResultItem $row */
|
||||
$t = (string) $row->prize_type;
|
||||
if (! isset($byType[$t])) {
|
||||
continue;
|
||||
}
|
||||
$byType[$t][] = (string) $row->number_4d;
|
||||
}
|
||||
|
||||
return [
|
||||
'1st' => $byType['first'][0] ?? '',
|
||||
'2nd' => $byType['second'][0] ?? '',
|
||||
'3rd' => $byType['third'][0] ?? '',
|
||||
'starter' => array_values($byType['starter']),
|
||||
'consolation' => array_values($byType['consolation']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 null 若该期尚未有可展示的开奖采纳版本。
|
||||
*
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public function summarizeDraw(Draw $draw): ?array
|
||||
{
|
||||
$version = (int) $draw->current_result_version;
|
||||
if ($version < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$batch = DrawResultBatch::query()
|
||||
->where('draw_id', $draw->id)
|
||||
->where('result_version', $version)
|
||||
->where('status', DrawResultBatchStatus::Published->value)
|
||||
->first();
|
||||
|
||||
if ($batch === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$items = DrawResultItem::query()
|
||||
->where('result_batch_id', $batch->id)
|
||||
->orderBy('prize_type')
|
||||
->orderBy('prize_index')
|
||||
->get([
|
||||
'prize_type', 'prize_index', 'number_4d',
|
||||
'suffix_3d', 'suffix_2d', 'head_digit', 'tail_digit',
|
||||
]);
|
||||
|
||||
if ($items->isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$numbers = $this->numbersFromItems($items);
|
||||
|
||||
return [
|
||||
'draw_id' => $draw->draw_no,
|
||||
'draw_no' => $draw->draw_no,
|
||||
'business_date' => $draw->business_date?->format('Y-m-d') ?? (string) $draw->business_date,
|
||||
'draw_time' => $draw->draw_time?->format('Y-m-d H:i:s'),
|
||||
'draw_time_iso' => $draw->draw_time?->toIso8601String(),
|
||||
'result_version' => $version,
|
||||
'result_source' => $draw->result_source,
|
||||
'results' => $numbers,
|
||||
'result_items' => $items->map(fn (DrawResultItem $r) => [
|
||||
'prize_type' => $r->prize_type,
|
||||
'prize_index' => (int) $r->prize_index,
|
||||
'number_4d' => $r->number_4d,
|
||||
'suffix_3d' => $r->suffix_3d,
|
||||
'suffix_2d' => $r->suffix_2d,
|
||||
'head_digit' => $r->head_digit !== null ? (int) $r->head_digit : null,
|
||||
'tail_digit' => $r->tail_digit !== null ? (int) $r->tail_digit : null,
|
||||
])->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LengthAwarePaginator<int, Draw> $paginator
|
||||
*/
|
||||
public function decoratePaginator(LengthAwarePaginator $paginator): LengthAwarePaginator
|
||||
{
|
||||
$collection = $paginator->getCollection()->map(function (Draw $draw): ?array {
|
||||
return $this->summarizeDraw($draw);
|
||||
})->filter();
|
||||
|
||||
$paginator->setCollection($collection->values());
|
||||
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
/** 已发布开奖结果的可查询状态(对外展示往期)。 */
|
||||
public static function publishedDrawStatuses(): array
|
||||
{
|
||||
return [
|
||||
DrawStatus::Cooldown->value,
|
||||
DrawStatus::Settling->value,
|
||||
DrawStatus::Settled->value,
|
||||
];
|
||||
}
|
||||
|
||||
public function neighborsIsoTime(Draw $draw): array
|
||||
{
|
||||
$statuses = self::publishedDrawStatuses();
|
||||
$t = $draw->draw_time;
|
||||
$prevNo = null;
|
||||
$nextNo = null;
|
||||
|
||||
if ($t !== null) {
|
||||
$prevNo = Draw::query()
|
||||
->whereIn('status', $statuses)
|
||||
->where('current_result_version', '>', 0)
|
||||
->whereNotNull('draw_time')
|
||||
->where('draw_time', '<', $t)
|
||||
->orderByDesc('draw_time')
|
||||
->value('draw_no');
|
||||
|
||||
$nextNo = Draw::query()
|
||||
->whereIn('status', $statuses)
|
||||
->where('current_result_version', '>', 0)
|
||||
->whereNotNull('draw_time')
|
||||
->where('draw_time', '>', $t)
|
||||
->orderBy('draw_time')
|
||||
->value('draw_no');
|
||||
}
|
||||
|
||||
return [
|
||||
'previous_draw_no' => $prevNo,
|
||||
'next_draw_no' => $nextNo,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user