上传文件至「/」
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# ============================================================
|
||||
# api/advisor_api.py —— 顾问模块路由层(Controller)
|
||||
# 职责:定义顾问相关的所有 HTTP 接口,调用 dao 层完成业务处理
|
||||
# 统一前缀:/advisor(在 main.py 中挂载)
|
||||
# ============================================================
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
from dao import advisor_dao # 顾问数据访问层
|
||||
from database import get_db # 数据库会话依赖
|
||||
from scheme.advisor_scheme import (
|
||||
AdvisorCreate, # 新增顾问请求模型
|
||||
AdvisorResp, # 顾问响应模型
|
||||
AdvisorStudentResp, # 顾问名下学生响应模型
|
||||
AdvisorUpdate, # 更新顾问请求模型
|
||||
)
|
||||
|
||||
# router = APIRouter(prefix="/advisor", tags=["顾问管理模块"])
|
||||
router = APIRouter() # 前缀在 main.py 统一挂载为 /advisor
|
||||
|
||||
# 新增顾问(POST /advisor/)
|
||||
@router.post("/", response_model=AdvisorResp, summary="新增顾问")
|
||||
def add_advisor(advisor: AdvisorCreate, db: Session = Depends(get_db)):
|
||||
# 校验顾问编号唯一性:已存在则拒绝新增
|
||||
if advisor_dao.get_advisor_by_no(db, advisor.advisor_no):
|
||||
raise HTTPException(status_code=400, detail=f"顾问编号 {advisor.advisor_no} 已存在")
|
||||
return advisor_dao.create_advisor(db, advisor)
|
||||
|
||||
# 顾问列表/搜索(GET /advisor/):可按编号或姓名模糊搜索
|
||||
@router.get("/", response_model=list[AdvisorResp], summary="顾问列表/搜索")
|
||||
def get_advisor_list(
|
||||
search_keyword: str | None = Query(default=None, description="按顾问编号或姓名模糊搜索"),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
return advisor_dao.get_advisor_list(db, search_keyword)
|
||||
|
||||
# 按编号查询单个顾问(GET /advisor/{advisor_no})
|
||||
@router.get("/{advisor_no}", response_model=AdvisorResp, summary="按编号查询顾问")
|
||||
def get_advisor(advisor_no: str, db: Session = Depends(get_db)):
|
||||
advisor = advisor_dao.get_advisor_by_no(db, advisor_no)
|
||||
if not advisor:
|
||||
raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在")
|
||||
return advisor
|
||||
|
||||
# 查询该顾问名下所有学生(GET /advisor/{advisor_no}/students)
|
||||
@router.get("/{advisor_no}/students", response_model=list[AdvisorStudentResp], summary="查询顾问名下学生")
|
||||
def get_advisor_students(advisor_no: str, db: Session = Depends(get_db)):
|
||||
# 先确认顾问存在
|
||||
if not advisor_dao.get_advisor_by_no(db, advisor_no):
|
||||
raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在")
|
||||
return advisor_dao.get_students_by_advisor_no(db, advisor_no)
|
||||
|
||||
# 更新顾问信息(PUT /advisor/{advisor_no})
|
||||
@router.put("/{advisor_no}", response_model=AdvisorResp, summary="更新顾问")
|
||||
def update_advisor(advisor_no: str, update: AdvisorUpdate, db: Session = Depends(get_db)):
|
||||
# model_dump(exclude_unset=True):只传被修改的字段(没传的不覆盖)
|
||||
advisor = advisor_dao.update_advisor(db, advisor_no, update.model_dump(exclude_unset=True))
|
||||
if not advisor:
|
||||
raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在")
|
||||
return advisor
|
||||
|
||||
# 删除顾问(DELETE /advisor/{advisor_no},逻辑删除)
|
||||
@router.delete("/{advisor_no}", response_model=AdvisorResp, summary="删除顾问")
|
||||
def delete_advisor(advisor_no: str, db: Session = Depends(get_db)):
|
||||
advisor = advisor_dao.delete_advisor(db, advisor_no)
|
||||
if not advisor:
|
||||
raise HTTPException(status_code=404, detail=f"顾问 {advisor_no} 不存在")
|
||||
return advisor
|
||||
@@ -0,0 +1,99 @@
|
||||
# ============================================================
|
||||
# api/api_analysis.py —— 统计分析模块路由层(Controller)
|
||||
# 职责:定义各类统计查询接口,调用 dao 层的统计分析函数
|
||||
# 统一前缀:/analysis(在 main.py 中挂载)
|
||||
# ============================================================
|
||||
|
||||
from fastapi import APIRouter, Query, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# 导入 dao 层的统计分析函数
|
||||
from dao.age_analysis import (
|
||||
analysis_student_age, # 年龄区间统计
|
||||
analysis_class_gender, # 班级性别分布
|
||||
analysis_score_over, # 达标学生(每次考试都在分数线以上)
|
||||
analysis_score_not_qualified, # 不及格次数达阈值学生
|
||||
analysis_avg_score_order, # 每次考试班级平均分
|
||||
analysis_employment_salary_order, # 就业薪资 Top N
|
||||
analysis_student_employment_time, # 学生就业时长
|
||||
avg_employment_time, # 班级平均就业时长
|
||||
)
|
||||
from database import get_db # 数据库会话依赖
|
||||
# 导入统计接口的响应模型
|
||||
from scheme.schema_analysis import (
|
||||
StudentOut,
|
||||
StudentGenderOut,
|
||||
StudentRecordOut1,
|
||||
StudentRecordOut2,
|
||||
StudentRecordOut3,
|
||||
StudentRecordOut4,
|
||||
StudentRecordOut5,
|
||||
StudentRecordOut6,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# 动态年龄范围查询(GET /analysis/analysis_age):
|
||||
# 支持输入年龄阈值(大于等于/小于等于)动态查询学员信息
|
||||
@router.get("/analysis_age", response_model=list[StudentOut])
|
||||
async def analysis_age(
|
||||
db: Session = Depends(get_db),
|
||||
min_age: int | None = Query(None, ge=0, description="请输入查询年龄大于等于"),
|
||||
max_age: int | None = Query(None, ge=0, description="请输入查询年龄小于等于"),
|
||||
):
|
||||
return analysis_student_age(db, min_age, max_age)
|
||||
|
||||
|
||||
# 统计每个班级的总人数,以及按性别(男、女)细分的人数分布(GET /analysis/analysis_gender)
|
||||
@router.get("/analysis_gender", response_model=list[StudentGenderOut])
|
||||
async def analysis_gender(db: Session = Depends(get_db)):
|
||||
return analysis_class_gender(db)
|
||||
|
||||
|
||||
# 查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩(GET /analysis/analysis_scores)
|
||||
@router.get("/analysis_scores", response_model=list[StudentRecordOut1])
|
||||
async def analysis_scores(
|
||||
db: Session = Depends(get_db),
|
||||
score: float = Query(0, ge=0, le=100, description="请输入查询学生每次考试分数在多少以上"),
|
||||
):
|
||||
return analysis_score_over(db, score)
|
||||
|
||||
|
||||
# 查询有输入指定次数(如两次)以上不及格的学生的姓名、班级和不及格成绩明细(GET /analysis/analysis_not_qualified)
|
||||
@router.get("/analysis_not_qualified", response_model=list[StudentRecordOut2])
|
||||
async def analysis_not_qualified(
|
||||
db: Session = Depends(get_db),
|
||||
n: int = Query(1, ge=1, description="请输入不及格次数下限"),
|
||||
):
|
||||
return analysis_score_not_qualified(db, n)
|
||||
|
||||
|
||||
# 统计每次考试每个班级的平均分,支持按分数从高到低或从低到高动态排序(GET /analysis/analysis_avg_score)
|
||||
@router.get("/analysis_avg_score", response_model=list[StudentRecordOut3])
|
||||
async def analysis_avg_score(
|
||||
db: Session = Depends(get_db),
|
||||
sort: str = Query("asc", description="请输入排序类型 asc/desc"),
|
||||
):
|
||||
return analysis_avg_score_order(db, sort)
|
||||
|
||||
|
||||
# 统计就业薪资排名 Top N(动态输入 N)的学生的姓名、班级、就业时间和就业公司(GET /analysis/analysis_salary_top)
|
||||
@router.get("/analysis_salary_top", response_model=list[StudentRecordOut4])
|
||||
async def analysis_salary_top(
|
||||
db: Session = Depends(get_db),
|
||||
n: int = Query(1, ge=1, description="请输入取前几名薪资"),
|
||||
):
|
||||
return analysis_employment_salary_order(db, n)
|
||||
|
||||
|
||||
# 统计每个学生的就业时长(offer下发时间 - 就业开放时间,单位秒)(GET /analysis/analysis_employment_time)
|
||||
@router.get("/analysis_employment_time", response_model=list[StudentRecordOut5])
|
||||
async def analysis_employment_time(db: Session = Depends(get_db)):
|
||||
return analysis_student_employment_time(db)
|
||||
|
||||
|
||||
# 统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生)(GET /analysis/analysis_avg_employment_time)
|
||||
@router.get("/analysis_avg_employment_time", response_model=list[StudentRecordOut6])
|
||||
async def analysis_avg_employment_time(db: Session = Depends(get_db)):
|
||||
return avg_employment_time(db)
|
||||
@@ -0,0 +1,74 @@
|
||||
# ============================================================
|
||||
# api/classinfo_api.py —— 班级模块路由层(Controller)
|
||||
# 职责:定义班级相关的所有 HTTP 接口,调用 dao 层完成业务处理
|
||||
# 统一前缀:/classinfo(在 main.py 中挂载)
|
||||
# ============================================================
|
||||
|
||||
# 路由接口
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter,Depends,HTTPException
|
||||
from database import get_db # 数据库会话依赖
|
||||
from dao.classinfo_dao import create_class, get_class, get_all_class, update_class, delete_class, \
|
||||
get_class_all_teachers, get_class_all_students # 班级数据访问层函数
|
||||
from scheme.classinfo_scheme import ClassCreate,ClassUpdate,ClassIn # 班级请求/响应模型
|
||||
|
||||
|
||||
router=APIRouter()
|
||||
|
||||
# 新增班级(POST /classinfo/)
|
||||
@router.post("/",response_model=ClassIn)
|
||||
def add_class(class_data:ClassCreate,db=Depends(get_db)):
|
||||
return create_class(db=db,obj=class_data)
|
||||
|
||||
# 条件查询班级(GET /classinfo/search):可按 id 或名称筛选
|
||||
@router.get("/search",response_model=List[ClassIn])
|
||||
def get_cls(class_id:int=None,class_name:str=None,db=Depends(get_db)):
|
||||
res_list=get_class(db=db,class_id=class_id,class_name=class_name)
|
||||
# 如果指定class_id但是查不到,才抛出404
|
||||
if class_id is not None and len(res_list)==0:
|
||||
raise HTTPException(status_code=404, detail="班级不存在")
|
||||
return res_list
|
||||
|
||||
# 查询全部班级(GET /classinfo/)
|
||||
@router.get("/",response_model=List[ClassIn])
|
||||
def get_all(db=Depends(get_db)):
|
||||
return get_all_class(db=db)
|
||||
|
||||
# 修改班级(PUT /classinfo/{class_id})
|
||||
@router.put("/{class_id}",response_model=ClassIn)
|
||||
def up_class(class_id:int,class_data:ClassUpdate,db=Depends(get_db)):
|
||||
res=update_class(db=db,class_id=class_id, obj=class_data)
|
||||
if not res:
|
||||
raise HTTPException(status_code=404, detail="班级不存在")
|
||||
return res
|
||||
|
||||
# 逻辑删除班级(DELETE /classinfo/{class_id})
|
||||
@router.delete("/{class_id}")
|
||||
def del_class(class_id:int,db=Depends(get_db)):
|
||||
res=delete_class(db=db,class_id=class_id)
|
||||
if not res:
|
||||
raise HTTPException(status_code=404,detail="班级不存在")
|
||||
return {"msg": "逻辑删除成功"}
|
||||
|
||||
# 1. 查询班级下全部老师(GET /classinfo/{class_id}/teachers)
|
||||
@router.get("/{class_id}/teachers")
|
||||
def get_class_teacher_list(class_id:int, db=Depends(get_db)):
|
||||
teacher_list = get_class_all_teachers(db, class_id)
|
||||
if teacher_list is None:
|
||||
raise HTTPException(status_code=404, detail="班级不存在")
|
||||
return {
|
||||
"class_id": class_id,
|
||||
"teacher_list": teacher_list
|
||||
}
|
||||
|
||||
# 2. 查询班级下全部学生(GET /classinfo/{class_id}/students)
|
||||
@router.get("/{class_id}/students")
|
||||
def get_class_student_list(class_id:int, db=Depends(get_db)):
|
||||
student_list = get_class_all_students(db, class_id)
|
||||
if student_list is None:
|
||||
raise HTTPException(status_code=404, detail="班级不存在")
|
||||
return {
|
||||
"class_id": class_id,
|
||||
"student_list": student_list
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
from sqlalchemy import Column, Integer, String, ForeignKey,Date,DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from model import Base
|
||||
from model.teacher_class import teacher_class
|
||||
|
||||
|
||||
class Teacher(Base):
|
||||
__tablename__="teacher"
|
||||
id=Column(Integer,primary_key=True,autoincrement=True)
|
||||
teacher_no=Column(String(50),unique=True,nullable=False)
|
||||
name=Column(String(50),nullable=False)
|
||||
phone=Column(String(50),nullable=False)
|
||||
is_deleted=Column(Integer,default=0)
|
||||
created_at=Column(DateTime,server_default=func.now())
|
||||
updated_at=Column(DateTime,onupdate=func.now())
|
||||
classinfo = relationship("ClassInfo",secondary=teacher_class, back_populates="teachers")
|
||||
@@ -0,0 +1,12 @@
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, Table, Date
|
||||
from sqlalchemy.orm import relationship
|
||||
from model import Base
|
||||
|
||||
teacher_class = Table(
|
||||
"teacher_class", # 中间表的名字
|
||||
Base.metadata, # 绑定到 Base 的元数据
|
||||
Column("class_id", Integer, ForeignKey("classinfo.id"), primary_key=True),
|
||||
Column("teacher_id", Integer, ForeignKey("teacher.id"), primary_key=True) ,
|
||||
Column("role",String(50))
|
||||
|
||||
)
|
||||
Reference in New Issue
Block a user