# dao/stu_score_dao.py # 学生成绩数据访问层:含成绩等级自动判定的业务规则 from decimal import Decimal from typing import List, Optional, Tuple from sqlalchemy.orm import Session from dao.exceptions import ConflictError, NotFoundError from dao.pagination import paginate from dao.stu_dao import assert_stu_alive from model.stu_score_model import StuScore def compute_score_level(score: Decimal) -> str: """根据分数自动判定等级:>=90 优秀、80-89 良好、60-79 普通、<60 不及格""" if score >= 90: return "优秀" if score >= 80: return "良好" if score >= 60: return "普通" return "不及格" def assert_score_alive(db: Session, score_id: int, detail: Optional[str] = None) -> StuScore: """确认成绩记录存在且未删除,否则抛 NotFoundError。""" score = ( db.query(StuScore) .filter(StuScore.id == score_id, StuScore.is_deleted == False) # noqa: E712 布尔列 .first() ) if not score: raise NotFoundError(detail or "成绩记录不存在或已删除") return score def list_scores( db: Session, page: int, size: int, stu_id: Optional[str] = None, score_level: Optional[str] = None, ) -> Tuple[int, List[StuScore]]: """分页查询未删除的成绩,支持按学生 / 等级过滤。""" query = db.query(StuScore).filter(StuScore.is_deleted == False) # noqa: E712 布尔列 if stu_id: query = query.filter(StuScore.stu_id == stu_id) if score_level: query = query.filter(StuScore.score_level == score_level) return paginate(query, page, size, order_by=StuScore.id) def list_scores_by_student(db: Session, stu_id: str) -> List[StuScore]: """查询某学生的全部有效成绩,按考试轮次升序。""" return ( db.query(StuScore) .filter(StuScore.stu_id == stu_id, StuScore.is_deleted == False) # noqa: E712 .order_by(StuScore.exam_attempt) .all() ) def create_score(db: Session, data: dict) -> StuScore: """新增成绩:校验学生存在、同轮次不重复,并在未指定等级时自动判定。""" assert_stu_alive(db, data["stu_id"]) exists = ( db.query(StuScore) .filter( StuScore.stu_id == data["stu_id"], StuScore.exam_attempt == data["exam_attempt"], StuScore.is_deleted == False, # noqa: E712 ) .first() ) if exists: raise ConflictError("该学生此轮次成绩已存在") # 未显式指定等级时,根据分数自动判定 if not data.get("score_level"): data["score_level"] = compute_score_level(data["exam_score"]) score = StuScore(**data) db.add(score) db.commit() db.refresh(score) return score def update_score(db: Session, score_id: int, data: dict) -> StuScore: """更新成绩:若更换学生需校验存在;只改分数没改等级时自动重判等级。""" score = assert_score_alive(db, score_id) if data.get("stu_id"): assert_stu_alive(db, data["stu_id"]) if "exam_score" in data and "score_level" not in data: data["score_level"] = compute_score_level(data["exam_score"]) for field, value in data.items(): setattr(score, field, value) db.commit() db.refresh(score) return score def soft_delete_score(db: Session, score_id: int) -> None: """软删除成绩记录。""" score = assert_score_alive(db, score_id) score.is_deleted = True db.commit()