from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import func, select from sqlalchemy.orm import Session from app.auth import get_current_user from app.database import get_db from app.grader_scope import allowed_subjects_for_user, apply_subject_scope from app.models import ( ExamPaperMap, ExaminationExamExaminee, ExaminationExaminee, ExaminationPaperSource, ImportBatch, User, ) from app.schemas import ScoreRow, ScoresResponse router = APIRouter(prefix="/api", tags=["scores"]) @router.get("/subjects") def list_subjects(db: Session = Depends(get_db), user: User = Depends(get_current_user)): q = select(ImportBatch.subject_name).distinct().order_by(ImportBatch.subject_name) allowed = allowed_subjects_for_user(db, user) if allowed is not None: if not allowed: return {"items": []} q = q.where(ImportBatch.subject_name.in_(allowed)) rows = db.scalars(q) return {"items": list(rows)} @router.get("/scores", response_model=ScoresResponse) def list_scores( page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100), name: str | None = None, id_card: str | None = None, subject: str | None = None, db: Session = Depends(get_db), user: User = Depends(get_current_user), ): allowed = allowed_subjects_for_user(db, user) if subject and allowed is not None and subject not in allowed: raise HTTPException(403, detail="无权查看该科目") q = ( select( ExaminationExamExaminee, ExaminationExaminee, ImportBatch.subject_name, ExaminationPaperSource.paper_name, ) .join(ExaminationExaminee, ExaminationExaminee.id == ExaminationExamExaminee.examinee_id) .join(ImportBatch, ImportBatch.id == ExaminationExamExaminee.import_batch_id) .outerjoin(ExamPaperMap, ExamPaperMap.exam_id == ExaminationExamExaminee.exam_id) .outerjoin( ExaminationPaperSource, ExaminationPaperSource.id == ExamPaperMap.paper_source_id, ) ) if name: q = q.where(ExaminationExaminee.nickname.contains(name)) if id_card: q = q.where(ExaminationExaminee.id_card.contains(id_card)) if subject: q = q.where(ImportBatch.subject_name == subject) q = apply_subject_scope(q, ImportBatch.subject_name, allowed) count_q = select(func.count()).select_from(q.subquery()) total = db.scalar(count_q) or 0 rows = db.execute( q.order_by(ExaminationExamExaminee.id.desc()) .offset((page - 1) * page_size) .limit(page_size) ).all() items = [ ScoreRow( examinee_id=str(ex.examinee_id), name=ee.nickname, id_card=ee.id_card, subject_name=sn, score=ex.score, attempt_id=str(ex.id), room_id=ex.room_id, paper_name=pn, start_time=ex.start_time, end_time=ex.end_time, ) for ex, ee, sn, pn in rows ] return ScoresResponse(total=total, page=page, page_size=page_size, items=items)