*/ public function checkInByTicket( Competition $competition, string $ticketCode, AdminUser|CompetitionAdmin $admin, ?int $expectedSessionId = null, ): array { $normalized = $this->normalizeTicketCode($ticketCode); if ($normalized === '') { throw ValidationException::withMessages([ 'ticket_code' => ['无效入场码'], ]); } return DB::transaction(function () use ($competition, $normalized, $admin, $expectedSessionId) { /** @var AudienceRegistration|null $row */ $row = AudienceRegistration::query() ->where('competition_id', $competition->id) ->where('ticket_code', $normalized) ->lockForUpdate() ->first(); if ($row === null) { throw ValidationException::withMessages([ 'ticket_code' => ['无效入场码'], ]); } return $this->applyCheckIn($row, $admin, $expectedSessionId); }); } /** * @return array */ public function checkInByRegistration( Competition $competition, int $registrationId, AdminUser|CompetitionAdmin $admin, ): array { return DB::transaction(function () use ($competition, $registrationId, $admin) { /** @var AudienceRegistration|null $row */ $row = AudienceRegistration::query() ->where('competition_id', $competition->id) ->whereKey($registrationId) ->lockForUpdate() ->first(); if ($row === null) { throw ValidationException::withMessages([ 'id' => ['报名记录不存在'], ]); } return $this->applyCheckIn($row, $admin, null); }); } public function normalizeTicketCode(string $raw): string { $raw = trim($raw); if ($raw === '') { return ''; } if (preg_match('#/t/([A-Za-z0-9_-]+)#', $raw, $matches) === 1) { return $matches[1]; } return preg_replace('/\s+/', '', $raw) ?? ''; } /** * @return array */ private function applyCheckIn(AudienceRegistration $row, AdminUser|CompetitionAdmin $admin, ?int $expectedSessionId): array { $row->load('session'); $session = $row->session; if ($session === null) { throw ValidationException::withMessages([ 'ticket_code' => ['无效入场码'], ]); } if ($expectedSessionId !== null && (int) $row->audience_session_id !== $expectedSessionId) { throw ValidationException::withMessages([ 'ticket_code' => ['非本场次入场码'], ]); } if (! $session->enabled) { throw ValidationException::withMessages([ 'ticket_code' => ['该场次已停用,暂不可核销'], ]); } $already = $row->checked_in_at !== null; if (! $already) { $row->checked_in_at = now(); if ($admin instanceof CompetitionAdmin) { $row->checked_in_by_competition_admin_id = $admin->id; $row->checked_in_by_admin_id = null; } else { $row->checked_in_by_admin_id = $admin->id; $row->checked_in_by_competition_admin_id = null; } $row->save(); } return [ 'already_checked_in' => $already, 'id' => $row->id, 'name' => $row->name, 'phone' => $row->phone, 'company' => $row->company, 'job' => $row->job, 'purpose' => $row->purpose, 'audience_session_id' => (int) $row->audience_session_id, 'session_name' => $session->name, 'event_date_text' => $session->event_date_text, 'checked_in_at' => BizDateTime::toIso8601($row->checked_in_at), ]; } }