, * consolation: array * } */ /** 已发布批次的头奖 4D 号码;未发布或缺失时返回空字符串。 */ public function firstPrizeNumber4dForDraw(Draw $draw): string { $summary = $this->summarizeDraw($draw); if ($summary === null) { return ''; } return (string) ($summary['results']['1st'] ?? ''); } 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|null */ public function summarizeDraw(Draw $draw, ?string $currencyCode = null): ?array { $currencyCode = $this->normalizeCurrencyCode($currencyCode); $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, 'jackpot_currency_code' => $currencyCode, 'jackpot' => $this->jackpotSummary->summary($currencyCode), '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 $paginator */ public function decoratePaginator(LengthAwarePaginator $paginator, ?string $currencyCode = null): LengthAwarePaginator { $collection = $paginator->getCollection()->map(function (Draw $draw) use ($currencyCode): ?array { return $this->summarizeDraw($draw, $currencyCode); })->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, ]; } private function normalizeCurrencyCode(?string $currencyCode): string { $code = strtoupper(substr(trim((string) ($currencyCode ?? '')), 0, 16)); if ($code !== '') { return $code; } return LotterySettings::defaultCurrency(); } }