Files
max_code_test_gitea_2/api/statistics_api.py
T
2026-09-14 11:51:13 +08:00

134 lines
7.2 KiB
Python

# api/stats
# 本文件定义统计分析相关的所有 API 路由(Controller 层)
from itertools import count
from pydoc import describe
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from sqlalchemy import func
from starlette import status
from database import get_db
from dao.statistics_dao import StatisticsDao
from model.stu_model import StuInfo
from scheme.statistics_scheme import StatsResponse, StuInfoAllExamAboveScore, FailingStudentItem, ClassExamAvgScoreItem, \
TopSalaryStudentItem, StudentEmpDurationItem, ClassAvgEmpDurationItem, StudentAgeDetailItem
router = APIRouter()
#### 2.6.1 基本信息动态统计
# - **动态年龄范围查询**:支持用户输入年龄阈值及比较条件(如大于、小于、等于、区间等),动态查询符合条件的学员信息。
# - **多维度班级统计**:统计每个班级的总人数,以及按性别(男、女)细分的人数分布。
@router.get("/api/stats/students/age_filter",
response_model=List[StudentAgeDetailItem],
summary="动态年龄范围查询",
description="支持用户输入年龄阈值及比较条件(如大于、小于、等于、区间等),动态查询符合条件的学员信息。")
def get_students_by_age_condition(db: Session = Depends(get_db),
operator: str = Query(..., description="比较条件: gt/gte/lt/lte/eq/between"),
age: Optional[int] = Query(None, ge=0, description="单值比较时的年龄(gt/lt/eq等用)"),
min_age: Optional[int] = Query(None, ge=0,description="区间比较时的最小年龄(between用)"),
max_age: Optional[int] = Query(None, ge=0,description="区间比较时的最大年龄(between用)")
):
if operator == "between":
if min_age is None or max_age is None:
raise HTTPException(status_code=400, detail="最大/最小值 都得输入")
if min_age > max_age:
raise HTTPException(status_code=400, detail="最小值 要 小于 最大值!")
else:
if age is None:
raise HTTPException(status_code=400, detail="age 不能不写!")
data = StatisticsDao.find_students_by_age_condition(db = db,
operator = operator,
age = age,
min_age = min_age,
max_age = max_age)
return data
# **多维度班级统计**:统计每个班级的总人数,以及按性别(男、女)细分的人数分布。
@router.get("/class/stats/gender",
response_model=List[StatsResponse],
summary="班级性别统计",
description="统计每个班级的总人数,以及按性别(男、女)细分的人数分布。")
def get_class_stats(db: Session = Depends(get_db)):
data = StatisticsDao.get_cls_stats(db)
return data
#### 2.6.2 成绩综合统计
# 1- 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩。
# 2- 查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细。
# 3- 统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序。
@router.get("/api/stats/students/all_exams_above_score",
response_model = List[StuInfoAllExamAboveScore],
summary="查询成绩在xx分以上的学生信息",
description= "查询成绩在xx分以上的学生信息")
def get_students_all_exams_above_score(
db: Session = Depends(get_db),
score: float = Query(..., ge=0.0, le=100.0, description="输入最低成绩(包含)"),
):
data = StatisticsDao.get_stu_info_all_exams_above_score(db, score)
return data
# 查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细。
@router.get("/api/stats/failing_records",
response_model=List[FailingStudentItem],
summary="查询有输入指定次数不及格学生",
description="查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细。")
def get_frequent_failing_students(
db: Session = Depends(get_db),
fail_cnt: int = Query(..., ge = 0, le = 100, description="不及格次数")
):
data = StatisticsDao.find_students_fail_count(db, fail_cnt)
return data
# 统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序。
@router.get("/api/stats/class/exam_avg_scores",
response_model=List[ClassExamAvgScoreItem],
summary="统计每次考试每个班级的平均分",
description="统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序")
def get_class_exams_avg_scores(
db: Session = Depends(get_db),
order_choose: int = Query(..., ge = 1, le = 2, description="1: 升序, 2: 降序")
):
data = StatisticsDao.find_class_exam_averages(db, order_choose)
return data
#### 2.6.3 就业数据统计
# - 统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司。
# - 统计每个学生的就业时长(计算公式:offer下发时间 - 就业开放时间)。
# - 统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生)
@router.get("/api/stats/employment/top_salaries",
response_model=List[TopSalaryStudentItem],
summary="就业薪资top_N",
description="统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司")
def get_top_salary_students(
db: Session = Depends(get_db),
top_n: int = Query(default=5, ge=1, description="获取前N名")):
data = StatisticsDao.find_top_salary_students(db, top_n)
return data
# - 统计每个学生的就业时长(计算公式:offer下发时间 - 就业开放时间)。
@router.get("/api/stats/employment/job_seeking_duration",
response_model=List[StudentEmpDurationItem],
summary="统计就业时长",
description="统计每个学生的就业时长(计算公式:offer下发时间 - 就业开放时间)")
def get_students_job_seeking_duration(db: Session = Depends(get_db)):
data = StatisticsDao.find_students_employment_duration(db)
return data
# - 统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生)
@router.get("/api/stats/class/avg_employment_duration",
response_model=List[ClassAvgEmpDurationItem],
summary="班级平均就业时长",
description="统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生)")
def get_class_avg_employment_duration(db: Session = Depends(get_db)):
data = StatisticsDao.find_class_avg_employment_duration(db)
return data