113 lines
3.5 KiB
Python
113 lines
3.5 KiB
Python
# 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() |