user(); $bankScope = QuestionBank::query()->whereNull('deleted_at'); if ($user->role !== 'admin') { $bankScope->where('owner_id', $user->id); } $bankIds = (clone $bankScope)->pluck('id'); $questionScope = Question::query()->whereIn('question_bank_id', $bankIds); $todayAnswered = DB::table('quiz_attempt_questions') ->join('quiz_attempts', 'quiz_attempts.id', '=', 'quiz_attempt_questions.quiz_attempt_id') ->join('questions', 'questions.id', '=', 'quiz_attempt_questions.question_id') ->whereIn('questions.question_bank_id', $bankIds) ->whereDate('quiz_attempt_questions.answered_at', today()) ->whereNotNull('quiz_attempt_questions.answered_at'); $answered = (clone $todayAnswered)->count(); $correct = (clone $todayAnswered)->where('quiz_attempt_questions.is_correct', true)->count(); $trend = DB::table('quiz_attempt_questions') ->join('questions', 'questions.id', '=', 'quiz_attempt_questions.question_id') ->whereIn('questions.question_bank_id', $bankIds) ->where('quiz_attempt_questions.answered_at', '>=', now()->subDays(6)->startOfDay()) ->whereNotNull('quiz_attempt_questions.answered_at') ->selectRaw('date(quiz_attempt_questions.answered_at) as day, count(*) as answered_count') ->groupBy('day') ->orderBy('day') ->get(); $classRanking = DB::table('classes') ->leftJoin('class_members', 'class_members.class_id', '=', 'classes.id') ->leftJoin('quiz_attempts', 'quiz_attempts.user_id', '=', 'class_members.user_id') ->whereNull('classes.deleted_at') ->when($user->role !== 'admin', fn ($query) => $query->where('classes.owner_id', $user->id)) ->selectRaw('classes.id, classes.name, count(distinct class_members.user_id) as members_count, count(distinct quiz_attempts.id) as attempts') ->groupBy('classes.id', 'classes.name') ->orderByDesc('attempts') ->limit(5) ->get(); $recentAttempts = QuizAttempt::query() ->join('users', 'users.id', '=', 'quiz_attempts.user_id') ->leftJoin('question_banks', 'question_banks.id', '=', 'quiz_attempts.question_bank_id') ->when($user->role !== 'admin', fn ($query) => $query->whereIn('quiz_attempts.question_bank_id', $bankIds)) ->selectRaw('quiz_attempts.id, users.name as user_name, coalesce(question_banks.name, "固定试卷") as bank_name, quiz_attempts.mode, quiz_attempts.total_questions, quiz_attempts.correct_count, quiz_attempts.started_at') ->latest('quiz_attempts.started_at') ->limit(8) ->get(); return ApiResponse::success([ 'stats' => [ 'banks' => (clone $bankScope)->count(), 'questions' => (clone $questionScope)->count(), 'today_answered' => $answered, 'accuracy' => $answered > 0 ? round($correct / $answered * 100, 2) : 0, 'users' => $user->role === 'admin' ? User::query()->count() : null, 'wrong_questions' => WrongQuestion::query() ->join('questions', 'questions.id', '=', 'wrong_questions.question_id') ->whereIn('questions.question_bank_id', $bankIds) ->whereNull('wrong_questions.mastered_at') ->count(), ], 'trend' => $trend, 'class_ranking' => $classRanking, 'recent_attempts' => $recentAttempts, ]); } }