架构实现V1.0
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import func
|
||||
from typing import List, Optional
|
||||
|
||||
from database import get_db
|
||||
from models import Student, Class, Score, Employment
|
||||
|
||||
router = APIRouter(prefix="/api/stats", tags=["stats"])
|
||||
|
||||
|
||||
@router.get("/classes")
|
||||
def class_stats(db: Session = Depends(get_db)):
|
||||
"""按班级统计学生人数和性别分布"""
|
||||
results = (
|
||||
db.query(
|
||||
Student.class_id,
|
||||
Class.name.label("class_name"),
|
||||
func.count(Student.id).label("total"),
|
||||
func.sum(func.if_(Student.sex == 1, 1, 0)).label("male"),
|
||||
func.sum(func.if_(Student.sex == 2, 1, 0)).label("female"),
|
||||
)
|
||||
.join(Class, Student.class_id == Class.id)
|
||||
.filter(Student.is_deleted == False, Class.is_deleted == False)
|
||||
.group_by(Student.class_id, Class.name)
|
||||
.all()
|
||||
)
|
||||
return [
|
||||
{
|
||||
"class_id": r.class_id,
|
||||
"class_name": r.class_name,
|
||||
"total_students": r.total,
|
||||
"male_count": r.male,
|
||||
"female_count": r.female,
|
||||
}
|
||||
for r in results
|
||||
]
|
||||
|
||||
|
||||
@router.get("/scores")
|
||||
def score_stats(class_id: Optional[int] = None, score_num: Optional[str] = None, db: Session = Depends(get_db)):
|
||||
"""成绩统计:平均分、最高分、最低分、人数"""
|
||||
query = (
|
||||
db.query(
|
||||
Score.num.label("score_num"),
|
||||
Student.class_id,
|
||||
func.avg(Score.score).label("avg_score"),
|
||||
func.max(Score.score).label("max_score"),
|
||||
func.min(Score.score).label("min_score"),
|
||||
func.count(Score.id).label("count"),
|
||||
)
|
||||
.join(Student, Score.sid == Student.id)
|
||||
.filter(Student.is_deleted == False, Score.is_deleted == False)
|
||||
.group_by(Score.num, Student.class_id)
|
||||
)
|
||||
if class_id:
|
||||
query = query.filter(Student.class_id == class_id)
|
||||
if score_num:
|
||||
query = query.filter(Score.num == score_num)
|
||||
results = query.all()
|
||||
return [
|
||||
{
|
||||
"score_num": r.score_num,
|
||||
"class_id": r.class_id,
|
||||
"avg_score": float(r.avg_score),
|
||||
"max_score": float(r.max_score),
|
||||
"min_score": float(r.min_score),
|
||||
"count": r.count,
|
||||
}
|
||||
for r in results
|
||||
]
|
||||
|
||||
|
||||
@router.get("/employment")
|
||||
def employment_stats(class_id: Optional[int] = None, db: Session = Depends(get_db)):
|
||||
"""就业统计:已就业人数、总人数、平均薪资、平均签约周期"""
|
||||
from sqlalchemy import cast, Integer
|
||||
|
||||
query = (
|
||||
db.query(
|
||||
Employment.class_id,
|
||||
Class.name.label("class_name"),
|
||||
func.count(Employment.id).label("employed_count"),
|
||||
func.count(Student.id).label("total_count"),
|
||||
func.avg(Employment.employment_salary).label("avg_salary"),
|
||||
)
|
||||
.join(Class, Employment.class_id == Class.id)
|
||||
.join(Student, Employment.sid == Student.id)
|
||||
.filter(Employment.is_deleted == False, Student.is_deleted == False, Class.is_deleted == False)
|
||||
.group_by(Employment.class_id, Class.name)
|
||||
)
|
||||
if class_id:
|
||||
query = query.filter(Employment.class_id == class_id)
|
||||
results = query.all()
|
||||
|
||||
output = []
|
||||
for r in results:
|
||||
# 计算平均签约周期(天数)
|
||||
durations = (
|
||||
db.query(
|
||||
func.ceil(
|
||||
func.cast(func.julianday(Employment.offer_recived_time) - func.julianday(Employment.employment_open_time), Integer)
|
||||
)
|
||||
)
|
||||
.filter(
|
||||
Employment.class_id == r.class_id,
|
||||
Employment.is_deleted == False,
|
||||
Employment.employment_open_time.isnot(None),
|
||||
Employment.offer_recived_time.isnot(None),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
avg_days = sum(d[0] for d in durations if d[0] is not None) / len(durations) if durations else None
|
||||
output.append({
|
||||
"class_id": r.class_id,
|
||||
"class_name": r.class_name,
|
||||
"employed_count": r.employed_count,
|
||||
"total_count": r.total_count,
|
||||
"avg_salary": float(r.avg_salary) if r.avg_salary else None,
|
||||
"avg_duration_days": round(avg_days, 1) if avg_days is not None else None,
|
||||
})
|
||||
return output
|
||||
Reference in New Issue
Block a user