withCount('members')->latest(); if ($request->user()->role !== 'admin') { $query->where('owner_id', $request->user()->id); } return ApiResponse::page($query->paginate((int) $request->query('per_page', 20))); } #[Apidoc\Title('创建班级')] #[Apidoc\Url('/admin/classes')] #[Apidoc\Method('POST')] #[Apidoc\RouteMiddleware(['permission:classes'])] public function store(Request $request): JsonResponse { $data = $request->validate([ 'name' => ['required', 'string', 'max:100'], 'description' => ['nullable', 'string'], ]); $class = SchoolClass::create($data + [ 'owner_id' => $request->user()->id, 'join_code' => strtoupper(Str::random(8)), 'is_active' => true, ]); return ApiResponse::success($class, '班级已创建'); } #[Apidoc\Title('更新班级')] #[Apidoc\Url('/admin/classes/{class}')] #[Apidoc\Method('PUT')] #[Apidoc\RouteMiddleware(['permission:classes'])] public function update(Request $request, mixed $class): JsonResponse { $class = $this->resolveClass($class); abort_if($request->user()->role !== 'admin' && $class->owner_id !== $request->user()->id, 403, '权限不足'); $data = $request->validate([ 'name' => ['sometimes', 'required', 'string', 'max:100'], 'description' => ['nullable', 'string'], 'is_active' => ['sometimes', 'boolean'], ]); $class->update($data); return ApiResponse::success($class->fresh()->loadCount('members'), '班级已更新'); } #[Apidoc\Title('分配成员')] #[Apidoc\Url('/admin/classes/{class}/members')] #[Apidoc\Method('POST')] #[Apidoc\RouteMiddleware(['permission:classes'])] public function addMember(Request $request, mixed $class): JsonResponse { $class = $this->resolveClass($class); abort_if($request->user()->role !== 'admin' && $class->owner_id !== $request->user()->id, 403, '权限不足'); $data = $request->validate([ 'user_id' => ['required', 'exists:users,id'], 'role' => ['nullable', 'in:student,assistant'], ]); $class->members()->syncWithoutDetaching([ $data['user_id'] => ['role' => $data['role'] ?? 'student'], ]); return ApiResponse::success($class->load('members'), '成员已加入'); } #[Apidoc\Title('批量分配成员')] #[Apidoc\Url('/admin/classes/{class}/members/batch')] #[Apidoc\Method('POST')] #[Apidoc\RouteMiddleware(['permission:classes'])] public function addMembers(Request $request, mixed $class): JsonResponse { $class = $this->resolveClass($class); abort_if($request->user()->role !== 'admin' && $class->owner_id !== $request->user()->id, 403, '权限不足'); $data = $request->validate([ 'user_ids' => ['required', 'array', 'min:1'], 'user_ids.*' => ['integer', 'exists:users,id'], 'role' => ['nullable', 'in:student,assistant'], ]); $role = $data['role'] ?? 'student'; $members = collect($data['user_ids']) ->unique() ->mapWithKeys(fn (int $userId): array => [$userId => ['role' => $role]]) ->all(); $class->members()->syncWithoutDetaching($members); return ApiResponse::success($class->fresh()->loadCount('members'), '成员已加入'); } private function resolveClass(mixed $class): SchoolClass { if ($class instanceof SchoolClass && $class->exists) { return $class; } return SchoolClass::query()->findOrFail((int) $class); } }