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.

163 lines
6.0 KiB

1 month ago
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\StoreReviewerScopeRequest;
use App\Models\Competition;
use App\Models\CompetitionTrack;
use App\Models\ReviewerScope;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class ReviewerScopeController extends Controller
{
/**
* 各赛道已配置评审员人数(与原型「赛道 tab 角标」对齐)。
*/
public function countsByTrack(Competition $competition): JsonResponse
{
/** @var array<string, int|string> $pairs */
$pairs = ReviewerScope::query()
->where('competition_id', $competition->id)
->selectRaw('track_code, COUNT(*) as c')
->groupBy('track_code')
->pluck('c', 'track_code')
->all();
$out = [];
foreach ($pairs as $code => $n) {
$out[$code] = (int) $n;
}
return response()->json(['data' => $out]);
}
public function index(Request $request): JsonResponse
{
$validated = $request->validate([
'competition_id' => ['required', 'integer', 'exists:competitions,id'],
'reviewer_id' => ['sometimes', 'nullable', 'integer', 'exists:reviewers,id'],
'track_code' => ['sometimes', 'nullable', 'string', 'max:64'],
'per_page' => ['sometimes', 'integer', 'min:1', 'max:500'],
'page' => ['sometimes', 'integer', 'min:1'],
]);
$perPage = min((int) ($validated['per_page'] ?? 15), 500);
$competitionId = (int) $validated['competition_id'];
$q = ReviewerScope::query()
->with([
'reviewer:id,mobile,username,name,status,password_hash',
'competition:id,slug,name',
])
->where('competition_id', $competitionId)
->orderByDesc('id');
if (! empty($validated['reviewer_id'])) {
$q->where('reviewer_id', (int) $validated['reviewer_id']);
}
if (! empty($validated['track_code'])) {
$q->where('track_code', $validated['track_code']);
}
$paginator = $q->paginate($perPage);
$codes = $paginator->getCollection()->pluck('track_code')->unique()->filter()->values()->all();
$tracksByCode = CompetitionTrack::query()
->where('competition_id', $competitionId)
->whereIn('track_code', $codes)
->get()
->keyBy('track_code');
$paginator->getCollection()->transform(function (ReviewerScope $s) use ($tracksByCode): array {
$track = $tracksByCode->get($s->track_code);
return [
'id' => $s->id,
'reviewer_id' => $s->reviewer_id,
'competition_id' => $s->competition_id,
'track_code' => $s->track_code,
'track_title' => $track?->title,
'created_at' => $s->created_at?->toIso8601String(),
'reviewer' => $s->reviewer !== null ? [
'id' => $s->reviewer->id,
'mobile' => $s->reviewer->mobile,
'username' => $s->reviewer->username,
'name' => $s->reviewer->name,
'status' => $s->reviewer->status,
'password_display' => ($s->reviewer->password_hash !== null && $s->reviewer->password_hash !== '')
? '········'
: '—',
] : null,
'competition' => $s->competition !== null ? [
'id' => $s->competition->id,
'slug' => $s->competition->slug,
'name' => $s->competition->name,
] : null,
];
});
return response()->json($paginator);
}
public function store(StoreReviewerScopeRequest $request): JsonResponse
{
/** @var array{reviewer_id: int|string, competition_id: int|string, track_code: string} $validated */
$validated = $request->validated();
$scope = ReviewerScope::query()->create([
'reviewer_id' => (int) $validated['reviewer_id'],
'competition_id' => (int) $validated['competition_id'],
'track_code' => $validated['track_code'],
]);
$scope->load(['reviewer:id,mobile,username,name,status,password_hash', 'competition:id,slug,name']);
$track = CompetitionTrack::query()
->where('competition_id', $scope->competition_id)
->where('track_code', $scope->track_code)
->first();
return response()->json($this->singleRowPayload($scope, $track?->title), Response::HTTP_CREATED);
}
public function destroy(ReviewerScope $reviewer_scope): Response
{
$reviewer_scope->delete();
return response()->noContent();
}
/**
* @return array<string, mixed>
*/
private function singleRowPayload(ReviewerScope $s, ?string $trackTitle): array
{
return [
'id' => $s->id,
'reviewer_id' => $s->reviewer_id,
'competition_id' => $s->competition_id,
'track_code' => $s->track_code,
'track_title' => $trackTitle,
'created_at' => $s->created_at?->toIso8601String(),
'reviewer' => $s->reviewer !== null ? [
'id' => $s->reviewer->id,
'mobile' => $s->reviewer->mobile,
'username' => $s->reviewer->username,
'name' => $s->reviewer->name,
'status' => $s->reviewer->status,
'password_display' => ($s->reviewer->password_hash !== null && $s->reviewer->password_hash !== '')
? '········'
: '—',
] : null,
'competition' => $s->competition !== null ? [
'id' => $s->competition->id,
'slug' => $s->competition->slug,
'name' => $s->competition->name,
] : null,
];
}
}