You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
6.0 KiB
179 lines
6.0 KiB
|
1 month ago
|
<?php
|
||
|
|
|
||
|
|
namespace App\Http\Controllers\Api;
|
||
|
|
|
||
|
|
use App\Http\Controllers\Controller;
|
||
|
|
use App\Models\AudienceRegistration;
|
||
|
|
use App\Models\AudienceSession;
|
||
|
|
use App\Models\Competition;
|
||
|
|
use App\Models\User;
|
||
|
|
use App\Services\AudienceRegistrationService;
|
||
|
|
use App\Support\BizDateTime;
|
||
|
|
use Illuminate\Http\JsonResponse;
|
||
|
|
use Illuminate\Http\Request;
|
||
|
|
use Illuminate\Validation\Rule;
|
||
|
|
use Illuminate\Validation\ValidationException;
|
||
|
|
|
||
|
|
class AudienceController extends Controller
|
||
|
|
{
|
||
|
|
public function me(Request $request): JsonResponse
|
||
|
|
{
|
||
|
|
/** @var User $user */
|
||
|
|
$user = $request->user();
|
||
|
|
|
||
|
|
return response()->json([
|
||
|
|
'id' => $user->id,
|
||
|
|
'mobile' => $user->mobile,
|
||
|
|
'name' => $user->name,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function sessions(Request $request): JsonResponse
|
||
|
|
{
|
||
|
|
$competition = $this->publishedCompetition($request);
|
||
|
|
/** @var User $user */
|
||
|
|
$user = $request->user();
|
||
|
|
|
||
|
|
$registeredSessionIds = AudienceRegistration::query()
|
||
|
|
->where('user_id', $user->id)
|
||
|
|
->where('competition_id', $competition->id)
|
||
|
|
->pluck('audience_session_id')
|
||
|
|
->map(fn ($id) => (int) $id)
|
||
|
|
->all();
|
||
|
|
|
||
|
|
$sessions = $competition->audienceSessions()
|
||
|
|
->withCount('registrations')
|
||
|
|
->where('enabled', true)
|
||
|
|
->get()
|
||
|
|
->map(fn (AudienceSession $session) => $this->sessionPayload(
|
||
|
|
$session,
|
||
|
|
in_array((int) $session->id, $registeredSessionIds, true)
|
||
|
|
));
|
||
|
|
|
||
|
|
return response()->json(['data' => $sessions]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function storeRegistration(Request $request, AudienceRegistrationService $service): JsonResponse
|
||
|
|
{
|
||
|
|
$competition = $this->publishedCompetition($request);
|
||
|
|
/** @var User $user */
|
||
|
|
$user = $request->user();
|
||
|
|
|
||
|
|
$data = $request->validate([
|
||
|
|
'audience_session_id' => ['required', 'integer', 'min:1'],
|
||
|
|
'name' => ['required', 'string', 'max:64'],
|
||
|
|
'company' => ['nullable', 'string', 'max:128'],
|
||
|
|
'job' => ['nullable', 'string', 'max:128'],
|
||
|
|
'purpose' => ['required', 'string', Rule::in(AudienceRegistration::PURPOSES)],
|
||
|
|
], [], [
|
||
|
|
'name' => '个人姓名',
|
||
|
|
'company' => '所属单位',
|
||
|
|
'job' => '个人职务',
|
||
|
|
'purpose' => '观赛目的',
|
||
|
|
'audience_session_id' => '赛事场次',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$mobile = trim((string) $user->mobile);
|
||
|
|
if (! preg_match('/^1[3-9]\d{9}$/', $mobile)) {
|
||
|
|
throw ValidationException::withMessages([
|
||
|
|
'phone' => ['登录手机号无效,请重新登录'],
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
$data['phone'] = $mobile;
|
||
|
|
|
||
|
|
$registration = $service->register($user, $competition, $data);
|
||
|
|
$registration->load('session');
|
||
|
|
|
||
|
|
return response()->json($this->registrationPayload($registration), 201);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function registrations(Request $request): JsonResponse
|
||
|
|
{
|
||
|
|
$competition = $this->publishedCompetition($request);
|
||
|
|
/** @var User $user */
|
||
|
|
$user = $request->user();
|
||
|
|
|
||
|
|
$rows = AudienceRegistration::query()
|
||
|
|
->with('session')
|
||
|
|
->where('user_id', $user->id)
|
||
|
|
->where('competition_id', $competition->id)
|
||
|
|
->orderByDesc('registered_at')
|
||
|
|
->orderByDesc('id')
|
||
|
|
->get()
|
||
|
|
->map(fn (AudienceRegistration $row) => $this->registrationPayload($row));
|
||
|
|
|
||
|
|
return response()->json(['data' => $rows]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @return array<string, mixed>
|
||
|
|
*/
|
||
|
|
private function sessionPayload(AudienceSession $session, bool $isRegistered): array
|
||
|
|
{
|
||
|
|
$status = $session->windowStatus();
|
||
|
|
$statusLabel = $isRegistered ? '已报名' : $session->statusLabel();
|
||
|
|
|
||
|
|
return [
|
||
|
|
'id' => $session->id,
|
||
|
|
'code' => $session->code,
|
||
|
|
'name' => $session->name,
|
||
|
|
'event_date_text' => $session->event_date_text,
|
||
|
|
'address' => $session->address,
|
||
|
|
'capacity' => (int) $session->capacity,
|
||
|
|
'registered_count' => $session->registeredCount(),
|
||
|
|
'remaining' => $session->remainingCount(),
|
||
|
|
'is_final' => (bool) $session->is_final,
|
||
|
|
'signup_start_at' => BizDateTime::toIso8601($session->signup_start_at),
|
||
|
|
'signup_end_at' => BizDateTime::toIso8601($session->signup_end_at),
|
||
|
|
'status' => $status,
|
||
|
|
'status_label' => $statusLabel,
|
||
|
|
'is_registered' => $isRegistered,
|
||
|
|
'is_available' => ! $isRegistered && $session->isAvailable(),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @return array<string, mixed>
|
||
|
|
*/
|
||
|
|
private function registrationPayload(AudienceRegistration $row): array
|
||
|
|
{
|
||
|
|
$session = $row->session;
|
||
|
|
|
||
|
|
return [
|
||
|
|
'id' => $row->id,
|
||
|
|
'audience_session_id' => $row->audience_session_id,
|
||
|
|
'session_name' => $session?->name,
|
||
|
|
'event_date_text' => $session?->event_date_text,
|
||
|
|
'address' => $session?->address,
|
||
|
|
'name' => $row->name,
|
||
|
|
'phone' => $row->phone,
|
||
|
|
'company' => $row->company,
|
||
|
|
'job' => $row->job,
|
||
|
|
'purpose' => $row->purpose,
|
||
|
|
'ticket_code' => $row->ticket_code,
|
||
|
|
'registered_at' => BizDateTime::toIso8601($row->registered_at),
|
||
|
|
'checked_in_at' => BizDateTime::toIso8601($row->checked_in_at),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
private function publishedCompetition(Request $request): Competition
|
||
|
|
{
|
||
|
|
$data = $request->validate([
|
||
|
|
'competition_slug' => ['required', 'string', 'max:64'],
|
||
|
|
]);
|
||
|
|
|
||
|
|
$competition = Competition::query()
|
||
|
|
->where('slug', $data['competition_slug'])
|
||
|
|
->where('published', true)
|
||
|
|
->first();
|
||
|
|
|
||
|
|
if ($competition === null) {
|
||
|
|
throw ValidationException::withMessages([
|
||
|
|
'competition_slug' => ['赛事不存在或未发布'],
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $competition;
|
||
|
|
}
|
||
|
|
}
|