""" 学生管理模块 - API 层(路由) """ from typing import List from fastapi import APIRouter, Depends, HTTPException, Path from sqlalchemy.orm import Session from dao import student_dao from dao.student_dao import search_student, BusinessException, DuplicateStudentNo, get_student, student_dict, create_student, update_student, delete_student from database import get_db from schema.student_schema import StudentQuery, StudentCreate, StudentUpdate, AgeQuery, workTimeResponse, \ failMoreResponse, countAvgOrderResponse, higherScoreResponse, ClassGenderFlatItem router = APIRouter() # 按性别统计人数 @router.get("/count_gender",summary="按性别统计人数",response_model=List[ClassGenderFlatItem]) def count_gender(db:Session =Depends(get_db)): res=student_dao.get_class_gender(db) return res # 统计分数高于分数线的 @router.get("/count_score_higherScores/{score}",summary="统计高于分数线的人数",response_model=List[higherScoreResponse]) def higher_score(score: int,db:Session =Depends(get_db)): res = student_dao.get_higher_score(db, score) return res # 统计每个学生就业时长 @router.get("/search_workTime",summary="统计每个学生就业时长",response_model=List[workTimeResponse]) def work_time(db:Session =Depends(get_db)): res = student_dao.work_time(db) return res # 统计不及格次数大于指定次数 @router.get("/fail_more",summary="统计不及格次数大于指定次数",response_model=List[failMoreResponse]) def fail_more_api(fail_times:int,db:Session =Depends(get_db)): res = student_dao.get_fail_more_than(db,fail_times) return res # 统计平均分,可以切换排序方式 @router.get("/count_avg",summary="统计平均分,可以切换排序方式",response_model=List[countAvgOrderResponse]) def count_avg_api(order_type:str,db:Session =Depends(get_db)): res = student_dao.count_avg(db,order_type) return res # 按年龄区间自定义比较 @router.post("/order_age",summary="按年龄区间自定义比较") def get_students_by_age(query:AgeQuery,db:Session =Depends(get_db)): res = student_dao.get_students_by_age(db,query) return res # 按就业信息排名查询学生 @router.get("get_top_salary",summary="按就业信息排名查询学生") def get_top_n_salary(rank:int,db:Session =Depends(get_db)): res = student_dao.get_top_n_salary(db,rank) return res # 统计每个班级的平均就业时长 @router.get("avg_work_time_by_class",summary="统计每个班级的平均就业时长") def avg_work_time_by_class(db:Session =Depends(get_db)): res = student_dao.avg_work_time_by_class(db) return res # ====================查询学生===================== @router.get("/api/get/student",summary="模糊查询学生") def list_student_api( student_query: StudentQuery = Depends(), db: Session = Depends(get_db), ): """ 支持按学号、姓名(模糊)、班级筛选,分页返回。 请求示例:GET /api/student/?student_name=张&page=1&size=10 """ try: return search_student( db, student_no=student_query.student_no, student_name=student_query.student_name, class_id=student_query.class_id, page=student_query.page, size=student_query.size, ) except BusinessException as e: raise HTTPException(status_code=500, detail=str(e)) # ====================查询学生详情==================== @router.get("/get/student/{sid}", summary="查询学生详情") def get_student_api( sid: int = Path(..., ge=1, description="学生ID"), db: Session = Depends(get_db), ): try: student = get_student(db, sid) if student is None: raise HTTPException(status_code=404, detail=f"学生 {sid} 不存在") return student_dict(student) except BusinessException as e: raise HTTPException(status_code=500, detail=str(e)) # ==================== 2. 创建学生 ==================== @router.post("/api/create/student") def create_student_api( student_create:StudentCreate, # 不加 Depends -> 走 JSON 请求体 db: Session = Depends(get_db), ): """ 请求体:测试数据 { "student_no": "S2023011", "student_name": "李四", "class_id": 1, "flag": 1, "advisor_id": 1, "native_place": "江苏南京", "school": "东南大学", "major": "软件工程", "enrollment_time": "2023-09-01", "graduation_time": "2026-06-30", "education": "本科", "age": 20, "gender": "男", "state": "在读" } """ try: student = create_student( db, student_no=student_create.student_no, student_name=student_create.student_name, class_id=student_create.class_id, flag=student_create.flag, advisor_id=student_create.advisor_id, native_place=student_create.native_place, school=student_create.school, major=student_create.major, enrollment_time=student_create.enrollment_time, graduation_time=student_create.graduation_time, education=student_create.education, age=student_create.age, gender=student_create.gender, state=student_create.state, ) return {"message": "创建成功", "data": student_dict(student)} except DuplicateStudentNo as e: raise HTTPException(status_code=409, detail=str(e)) except BusinessException as e: raise HTTPException(status_code=500, detail=str(e)) # ==================== 3. 更新学生 ==================== @router.put("/api/update/student/{sid}", summary="更新学生") def update_student_api( params: StudentUpdate, sid: int = Path(..., ge=1, description="学生ID"), db: Session = Depends(get_db), ): """ 学号不在更新范围内(业务主键不可改)。 """ try: student = update_student( db, sid=sid, student_name=params.student_name, class_id=params.class_id, flag=params.flag, advisor_id=params.advisor_id, native_place=params.native_place, school=params.school, major=params.major, enrollment_time=params.enrollment_time, graduation_time=params.graduation_time, education=params.education, age=params.age, gender=params.gender, state=params.state, ) if student is None: raise HTTPException(status_code=404, detail=f"学生 {sid} 不存在") return {"message": "更新成功", "data": student_dict(student)} except BusinessException as e: raise HTTPException(status_code=500, detail=str(e)) # ==================== 4. 删除学生(逻辑删除) ==================== @router.delete("/api/delete/student/{sid}", summary="删除学生(逻辑删除)") def delete_student_api( sid: int = Path(..., ge=1, description="学生ID"), db: Session = Depends(get_db), ): """逻辑删除:把 flag 置 0,数据行仍然保留。""" try: student = delete_student(db, sid) if student is None: raise HTTPException(status_code=404, detail=f"学生 {sid} 不存在或已删除") return {"message": f"学生 {student.student_name} 删除成功"} except BusinessException as e: raise HTTPException(status_code=500, detail=str(e))