第五版_完整
This commit is contained in:
+30
-5
@@ -3,6 +3,7 @@
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from model import Teacher
|
||||
from model.cls_mgmt_model import ClsMgmt
|
||||
from scheme.cls_mgmt_scheme import ClsMgmtResponse, ClsMgmtCreate
|
||||
from typing import Optional, List
|
||||
@@ -36,7 +37,9 @@ class ClsMgmtDAO:
|
||||
根据主键 ID 获取单个班级
|
||||
:return: 班级对象或 None
|
||||
"""
|
||||
return db.query(ClsMgmt).filter(ClsMgmt.id == class_id,ClsMgmt.is_deleted == 0).first()
|
||||
return (db.query(ClsMgmt)
|
||||
.filter(ClsMgmt.id == class_id,ClsMgmt.is_deleted == 0)
|
||||
.first())
|
||||
|
||||
|
||||
|
||||
@@ -68,6 +71,18 @@ class ClsMgmtDAO:
|
||||
id 根据开课时间自动生成,不再自增
|
||||
"""
|
||||
class_id = ClsMgmtDAO.generate_class_id(cls_data.cls_start_date)
|
||||
head_tea = db.query(Teacher).filter(
|
||||
Teacher.type == "班主任",
|
||||
Teacher.id == cls_data.head_tea_id
|
||||
).first()
|
||||
lecturer = db.query(Teacher).filter(
|
||||
Teacher.type == "授课老师",
|
||||
Teacher.id == cls_data.lecturer_id
|
||||
).first()
|
||||
if not head_tea:
|
||||
raise HTTPException(status_code=404, detail=f"班主任id{cls_data.head_tea_id}不存在")
|
||||
elif not lecturer:
|
||||
raise HTTPException(status_code=404, detail=f"授课老师id{cls_data.lecturer_id}不存在")
|
||||
new_cls = ClsMgmt(
|
||||
id=class_id, # 手动赋值班级id
|
||||
cls_start_date=cls_data.cls_start_date,
|
||||
@@ -109,13 +124,23 @@ class ClsMgmtDAO:
|
||||
ClsMgmt.id == class_id,
|
||||
ClsMgmt.is_deleted == 0 # 只查未删除的
|
||||
).first()
|
||||
|
||||
head_tea = db.query(Teacher).filter(
|
||||
Teacher.type == "班主任",
|
||||
Teacher.id == cls_data.head_tea_id
|
||||
).first()
|
||||
lecturer = db.query(Teacher).filter(
|
||||
Teacher.type == "授课老师",
|
||||
Teacher.id == cls_data.lecturer_id
|
||||
).first()
|
||||
if update_cls:
|
||||
update_cls.head_tea_id=cls_data.head_tea_id
|
||||
update_cls.lecturer_id=cls_data.lecturer_id
|
||||
if not head_tea:
|
||||
raise HTTPException(status_code=404, detail=f"班主任id{cls_data.head_tea_id}不存在")
|
||||
elif not lecturer:
|
||||
raise HTTPException(status_code=404, detail=f"授课老师id{cls_data.lecturer_id}不存在")
|
||||
update_cls.head_tea_id = cls_data.head_tea_id
|
||||
update_cls.lecturer_id = cls_data.lecturer_id
|
||||
db.commit()
|
||||
return update_cls
|
||||
|
||||
raise HTTPException(status_code=404, detail=f"班级{class_id}不存在")
|
||||
|
||||
|
||||
|
||||
+49
-19
@@ -20,7 +20,9 @@ class StatisticsDao:
|
||||
|
||||
@staticmethod
|
||||
def get_class_gender_distribution(db: Session) -> List[ClassGenderDistributionItem]:
|
||||
|
||||
"""
|
||||
**多维度班级统计**:统计每个班级的总人数,以及按性别(男、女)细分的人数分布。
|
||||
"""
|
||||
all_cls_gender_stats = (
|
||||
db.query(
|
||||
StuInfo.cls_id.label("cls_id"),
|
||||
@@ -38,12 +40,16 @@ class StatisticsDao:
|
||||
total_cnt=i.total_cnt,
|
||||
man_cnt=i.man_cnt,
|
||||
female_cnt=i.female_cnt,
|
||||
) for i in all_cls_gender_stats
|
||||
)
|
||||
for i in all_cls_gender_stats
|
||||
]
|
||||
|
||||
# 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩。
|
||||
@staticmethod
|
||||
def get_stu_info_all_exams_above_score(db: Session, score: float) -> List[StuInfoAllExamAboveScore]:
|
||||
"""
|
||||
# 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩 -- 参数: 分数
|
||||
"""
|
||||
stu_id_list_query = (
|
||||
db.query(StuScore.stu_id)
|
||||
.filter(StuScore.is_deleted == 0)
|
||||
@@ -87,7 +93,11 @@ class StatisticsDao:
|
||||
|
||||
@staticmethod
|
||||
def get_stu_dict_who_fail(db: Session) -> Dict[str, List[StuScore]]:
|
||||
"""
|
||||
获取不及格的学生信息 {stu_id, [StuScore]}
|
||||
"""
|
||||
stu_fail_dict = defaultdict(list)
|
||||
|
||||
data = (db.query(StuScore)
|
||||
.options(joinedload(StuScore.student)) # 预加载模式: 让 SQLAlchemy 在第一次查成绩表时,通过 JOIN 语句一次性把学生信息查出来。
|
||||
.filter(and_(StuScore.is_deleted == 0, StuScore.exam_score <= 60))
|
||||
@@ -98,7 +108,14 @@ class StatisticsDao:
|
||||
|
||||
@staticmethod
|
||||
def find_students_fail_count(db: Session, fail_cnt: int) -> List[FailingStudentItem]:
|
||||
test_max_cnt = len(db.query(StuScore.exam_attempt).group_by(StuScore.exam_attempt).all())
|
||||
"""
|
||||
# 2、查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细 -- 参数: 不及格次数
|
||||
"""
|
||||
test_max_cnt = len(db.query(StuScore.exam_attempt)
|
||||
.filter(StuScore.is_deleted == 0)
|
||||
.group_by(StuScore.exam_attempt)
|
||||
.all()
|
||||
)
|
||||
if fail_cnt > test_max_cnt:
|
||||
raise HTTPException(status_code = 400, detail = f'最大次数为{test_max_cnt}')
|
||||
|
||||
@@ -131,9 +148,12 @@ class StatisticsDao:
|
||||
# 统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序。
|
||||
@staticmethod
|
||||
def find_class_exam_averages(db: Session, order_choose: int) -> List[ClassExamAvgScoreItem]:
|
||||
"""
|
||||
# 统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序 -- 参数: 1:低到高, 2:高到低
|
||||
"""
|
||||
avg_score = func.avg(StuScore.exam_score)
|
||||
order_score = asc(avg_score) if order_choose == 1 else desc(avg_score)
|
||||
aaa = (db.query(
|
||||
finally_data = (db.query(
|
||||
StuInfo.cls_id,
|
||||
StuScore.exam_attempt,
|
||||
func.avg(StuScore.exam_score).label("avg_score"),
|
||||
@@ -146,7 +166,7 @@ class StatisticsDao:
|
||||
|
||||
# 班级 - 考试场次 - 平均分
|
||||
ans = []
|
||||
for row in aaa:
|
||||
for row in finally_data:
|
||||
ans.append(
|
||||
ClassExamAvgScoreItem(
|
||||
exam_attempt=row.exam_attempt,
|
||||
@@ -160,17 +180,20 @@ class StatisticsDao:
|
||||
|
||||
@staticmethod
|
||||
def find_top_salary_students(db: Session, top_n: int) -> List[TopSalaryStudentItem]:
|
||||
aaa = (db.query(
|
||||
"""
|
||||
# 1、统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司。 -- 参数: top_N
|
||||
"""
|
||||
finally_data = (db.query(
|
||||
StudentEmployManage.send_offer_time,
|
||||
StudentEmployManage.emp_company,
|
||||
StudentEmployManage.salary,
|
||||
StuInfo.name,
|
||||
StuInfo.cls_id
|
||||
).join(StuInfo, StuInfo.id == StudentEmployManage.stu_id)
|
||||
.filter(StudentEmployManage.is_deleted == 0, StudentEmployManage.is_deleted == 0)
|
||||
.order_by(StudentEmployManage.salary.desc())
|
||||
.limit(top_n)
|
||||
)
|
||||
.filter(StudentEmployManage.is_deleted == 0, StudentEmployManage.is_deleted == 0)
|
||||
.order_by(StudentEmployManage.salary.desc())
|
||||
.limit(top_n)
|
||||
)
|
||||
|
||||
ans = [
|
||||
TopSalaryStudentItem(
|
||||
@@ -180,26 +203,30 @@ class StatisticsDao:
|
||||
emp_company_name=row.emp_company,
|
||||
salary=row.salary
|
||||
)
|
||||
for row in aaa
|
||||
for row in finally_data
|
||||
]
|
||||
|
||||
return ans
|
||||
|
||||
@staticmethod
|
||||
def find_students_employment_duration(db: Session) -> List[StudentEmpDurationItem]:
|
||||
"""
|
||||
# 2、统计每个学生的就业时长(计算公式:offer下发时间 - 就业开放时间) -- 参数: 无
|
||||
"""
|
||||
time = func.datediff(StudentEmployManage.send_offer_time, StudentEmployManage.emp_open_time)
|
||||
aaa = (db.query(
|
||||
|
||||
finally_data = (db.query(
|
||||
StuInfo.id,
|
||||
StuInfo.cls_id,
|
||||
StuInfo.name,
|
||||
time.label("time")
|
||||
).join(StudentEmployManage, StuInfo.id == StudentEmployManage.stu_id)
|
||||
.filter(StuInfo.is_deleted == 0,
|
||||
StuInfo.is_deleted == 0,
|
||||
StudentEmployManage.send_offer_time.isnot(None),
|
||||
StudentEmployManage.emp_open_time.isnot(None))
|
||||
.order_by(time).all()
|
||||
)
|
||||
.filter(StuInfo.is_deleted == 0,
|
||||
StudentEmployManage.is_deleted == 0,
|
||||
StudentEmployManage.send_offer_time.isnot(None),
|
||||
StudentEmployManage.emp_open_time.isnot(None))
|
||||
.order_by(time).all()
|
||||
)
|
||||
|
||||
ans = [
|
||||
StudentEmpDurationItem(
|
||||
@@ -208,13 +235,16 @@ class StatisticsDao:
|
||||
cls_id=row.cls_id,
|
||||
offer_time=row.time
|
||||
)
|
||||
for row in aaa
|
||||
for row in finally_data
|
||||
]
|
||||
|
||||
return ans
|
||||
|
||||
@staticmethod
|
||||
def find_class_avg_employment_duration(db: Session) -> List[ClassAvgEmpDurationItem]:
|
||||
"""
|
||||
# 3、统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生) -- 参数: 无<br>
|
||||
"""
|
||||
duration_time = func.datediff(StudentEmployManage.send_offer_time, StudentEmployManage.emp_open_time)
|
||||
class_avg_query = (db.query(
|
||||
StuInfo.cls_id,
|
||||
|
||||
Reference in New Issue
Block a user