'boolean', 'pool_amount' => 'integer', 'carry_amount' => 'integer', 'payout_amount' => 'integer', 'total_tickets' => 'integer', 'sell_closes_at' => 'datetime', 'draw_at' => 'datetime', ]; } // ─── 关联 ────────────────────────────────────────────────────────── /** * 本期所有购票记录。 */ public function tickets(): HasMany { return $this->hasMany(LotteryTicket::class, 'issue_id'); } /** * 本期奖池流水。 */ public function poolLogs(): HasMany { return $this->hasMany(LotteryPoolLog::class, 'issue_id'); } // ─── 静态查询 ────────────────────────────────────────────────────── /** * 获取当前正在购票的期次(status=open)。 */ public static function currentIssue(): ?static { return static::query()->where('status', 'open')->latest()->first(); } /** * 获取最新一期(不论状态)。 */ public static function latestIssue(): ?static { return static::query()->latest()->first(); } /** * 生成下一期的期号(格式:年份 + 三位序号,如 2026001)。 */ public static function nextIssueNo(): string { $year = now()->year; $last = static::query() ->whereYear('created_at', $year) ->latest() ->first(); $seq = $last ? ((int) substr($last->issue_no, -3)) + 1 : 1; return $year.str_pad($seq, 3, '0', STR_PAD_LEFT); } // ─── 业务方法 ────────────────────────────────────────────────────── /** * 判断当前期次是否仍在售票中。 */ public function isOpen(): bool { return $this->status === 'open' && now()->lt($this->sell_closes_at); } /** * 距离开奖剩余秒数。 */ public function secondsUntilDraw(): int { if (! $this->draw_at) { return 0; } return max(0, (int) now()->diffInSeconds($this->draw_at, false)); } /** * 判断给定号码是否与开奖号码匹配并返回奖级(0=未中)。 * * @param int $r1 用户红球1(已排序) * @param int $r2 用户红球2 * @param int $r3 用户红球3 * @param int $b 用户蓝球 */ public function calcPrizeLevel(int $r1, int $r2, int $r3, int $b): int { $userReds = [$r1, $r2, $r3]; $drawReds = [$this->red1, $this->red2, $this->red3]; $redMatches = count(array_intersect($userReds, $drawReds)); $blueMatch = ($b === $this->blue); return match (true) { $redMatches === 3 && $blueMatch => 1, // 一等奖 $redMatches === 3 && ! $blueMatch => 2, // 二等奖 $redMatches === 2 && $blueMatch => 3, // 三等奖 $redMatches === 2 && ! $blueMatch => 4, // 四等奖 $redMatches === 1 && $blueMatch => 5, // 五等奖 default => 0, // 未中奖 }; } /** * 返回奖级的中文标签。 */ public static function prizeLevelLabel(int $level): string { return match ($level) { 1 => '一等奖', 2 => '二等奖', 3 => '三等奖', 4 => '四等奖', 5 => '五等奖', default => '未中奖', }; } }