findOrFail($course); $checkinDate = $request->query('checkin_date'); $checkinStatus = $request->query('checkin_status'); $query = CourseSignup::query()->where('course_id', $course)->orderByDesc('id'); if ($kw = $request->query('keyword')) { $query->where(function ($q) use ($kw) { $q->where('name', 'like', "%{$kw}%") ->orWhere('mobile', 'like', "%{$kw}%") ->orWhere('company', 'like', "%{$kw}%"); }); } if ($checkinDate) { if ((string) $checkinStatus === '1') { $query->whereHas('checkins', function ($q) use ($checkinDate) { $q->whereDate('checkin_date', $checkinDate)->whereNotNull('checked_in_at'); }); } elseif ((string) $checkinStatus === '0') { $query->whereDoesntHave('checkins', function ($q) use ($checkinDate) { $q->whereDate('checkin_date', $checkinDate)->whereNotNull('checked_in_at'); }); } } $paginator = $query ->with(['checkins' => function ($q) use ($checkinDate) { if ($checkinDate) { $q->whereDate('checkin_date', $checkinDate); } }]) ->paginate((int) $request->query('page_size', 20)) ->withQueryString(); $paginator->getCollection()->transform( fn (CourseSignup $r) => $this->serialize($r, is_string($checkinDate) ? $checkinDate : null) ); return $this->paginated($paginator); } public function store(Request $request, int $course): JsonResponse { $courseModel = Course::query()->findOrFail($course); $data = $request->validate([ 'name' => ['required', 'string', 'max:64'], 'mobile' => ['required', 'string', 'max:32'], 'company' => ['nullable', 'string', 'max:128'], 'form_answers' => ['nullable', 'array'], ]); $formAnswers = null; if (isset($data['form_answers']) && is_array($data['form_answers'])) { $formAnswers = SignupFormAnswers::normalize( $data['form_answers'], is_array($courseModel->signup_form_schema) ? $courseModel->signup_form_schema : null ); } $signup = CourseSignup::query()->create([ 'course_id' => $course, 'name' => $data['name'], 'mobile' => $data['mobile'], 'company' => $data['company'] ?? null, 'form_answers' => $formAnswers, 'signed_up_at' => now(), 'status' => 1, ]); return $this->ok(['id' => $signup->id], '报名已登记'); } public function destroy(int $course, int $signup): JsonResponse { $model = CourseSignup::query()->where('course_id', $course)->findOrFail($signup); $model->delete(); return $this->ok(null, '已删除'); } public function checkin(Request $request, int $course, int $signup): JsonResponse { $courseModel = Course::query()->findOrFail($course); $model = CourseSignup::query()->where('course_id', $course)->findOrFail($signup); $data = $request->validate([ 'checkin_date' => ['required', 'date'], ]); $checkinDate = $data['checkin_date']; if (! CourseCheckinDaySync::isTeachDate($courseModel, $checkinDate)) { return $this->fail('该日期不在课程开课范围内', 422); } CourseSignupCheckin::query()->updateOrCreate( [ 'course_signup_id' => $model->id, 'checkin_date' => $checkinDate, ], ['checked_in_at' => now()] ); return $this->ok(null, '签到成功'); } /** * @return array */ protected function serialize(CourseSignup $r, ?string $checkinDate = null): array { $dayCheckedInAt = null; if ($checkinDate) { $checkin = $r->relationLoaded('checkins') ? $r->checkins->first() : $r->checkins()->whereDate('checkin_date', $checkinDate)->first(); $dayCheckedInAt = $checkin?->checked_in_at; } return [ 'id' => $r->id, 'course_id' => $r->course_id, 'name' => $r->name, 'mobile' => $r->mobile, 'company' => $r->company, 'form_answers' => $r->form_answers, 'signed_up_at' => $r->signed_up_at?->toIso8601String(), 'status' => (int) $r->status, 'checkin_date' => $checkinDate, 'day_checked_in_at' => $dayCheckedInAt?->toIso8601String(), ]; } }