第一次提交

This commit is contained in:
AQUAFIN
2026-09-21 17:39:16 +08:00
parent ea9a6644b1
commit 34783833e5
80 changed files with 3151 additions and 0 deletions
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+51
View File
@@ -0,0 +1,51 @@
from fastapi import FastAPI,APIRouter,Depends
from schemas.analysis import (AnalysisStudentInfoAge,AnalysisStudent_score,AnalysisStudent_score60
,AnalysisStudent_score_class,AnalysisStudent_employments_salary)
from dao.analysis import (student_info_age,student_info_class,student_score,student_score_class,student_employments_salary
,student_employments_time,student_employments_class_time,student_score60)
from database import get_db
from sqlalchemy.orm import Session
router = APIRouter(prefix="/analysis", tags=["统计分析"])
#动态年龄范围查询:支持用户输入年龄阈值及比较条件(如大于、小于、等于、区间等),动态查询符合条件的学员信息
@router.get("/studnet_info/age",summary="动态年龄范围查询")
async def student_info_age1(student:AnalysisStudentInfoAge = Depends(),db: Session = Depends(get_db)):
return student_info_age(db, student.min_age, student.max_age, student.operator)
#多维度班级统计:统计每个班级的总人数,以及按性别(男、女)细分的人数分布
@router.get("/studnet_info/class",summary="多维度班级统计")
async def student_info_class1(db: Session = Depends(get_db)):
return student_info_class(db)
#查询每次考试成绩都在输入分数线(如80分)以上的学生的编号、姓名和成绩。
@router.get("/studnet_score",summary="查询每次考试成绩都在输入分数线以上的学生")
async def student_score1(s_n:AnalysisStudent_score = Depends(),db: Session = Depends(get_db)):
return student_score(db,s_n.s_n)
#查询有输入指定次数(如两次(包含两次))以上不及格的学生的姓名、班级和不及格成绩明细。
@router.get("/studnet_score60",summary="查询有输入指定次数(如两次(包含两次))以上不及格的学生")
async def student_score60_1(n:AnalysisStudent_score60 = Depends(),db: Session = Depends(get_db)):
return student_score60(db,n.n)
#统计每次考试每个班级的平均分,并支持按分数从高到低或从低到高动态排序。
@router.get("/studnet_score_class",summary="统计每次考试每个班级的平均分")
async def student_score_class1(order:AnalysisStudent_score_class = Depends(),db: Session = Depends(get_db)):
return student_score_class(db,order.order)
#查询查询就业薪资排名前n的学生
@router.get("/studnet_employments_salary",summary="查询查询就业薪资排名前n的学生")
async def student_employments_salary1(n:AnalysisStudent_employments_salary = Depends(),db: Session = Depends(get_db)):
return student_employments_salary(db,n.n)
#统计每个学生的就业时长
@router.get("/studnet_employments_time",summary="每个学生的就业时长(天)")
async def student_employments_time1(db: Session = Depends(get_db)):
return student_employments_time(db)
#统计每个班级的平均就业时长(仅统计进入就业阶段,即有就业开放时间的学生)
@router.get("/studnet_employments_class_time",summary="每个班级的平均就业时长(天)")
async def student_employments_class_time1(db: Session = Depends(get_db)):
return student_employments_class_time(db)
+115
View File
@@ -0,0 +1,115 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import Optional
from database import get_db # 按你项目实际路径改
from dao.class_dao import ClassDAO
from schemas.class_scheme import (
ClassCreate,
ClassUpdateBase,
ClassHeadTeacherUpdate,
ClassTeachersUpdate,
ClassDelete,
ClassDetail,
ClassPageResult,
BatchDeleteResult,
)
router = APIRouter(prefix="/api/classes", tags=["班级管理"])
@router.post("", response_model=ClassDetail, summary="新增班级")
def create_class(req: ClassCreate, db: Session = Depends(get_db)):
try:
return ClassDAO.create(db, req)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("", response_model=ClassPageResult, summary="分页查询班级列表")
def list_classes(
page_num: int = Query(1, ge=1),
page_size: int = Query(10, ge=1, le=100),
class_name: Optional[str] = None,
head_teacher_id: Optional[int] = None,
db: Session = Depends(get_db),
):
total, rows = ClassDAO.list_page(
db, page_num, page_size, class_name, head_teacher_id
)
return ClassPageResult(total=total, items=rows)
@router.put(
"/batch-delete",
response_model=BatchDeleteResult,
summary="批量逻辑删除/恢复班级",
)
def batch_delete(req: ClassDelete, db: Session = Depends(get_db)):
count = ClassDAO.batch_toggle_delete(db, req)
return BatchDeleteResult(affected_count=count)
@router.get("/{class_id}", response_model=ClassDetail, summary="查询班级详情")
def get_class(class_id: int, db: Session = Depends(get_db)):
data = ClassDAO.get_by_id(db, class_id)
if not data:
raise HTTPException(status_code=404, detail="班级不存在或已删除")
return data
@router.put(
"/{class_id}/base",
response_model=ClassDetail,
summary="更新班级基础信息",
)
def update_class_base(
class_id: int, req: ClassUpdateBase, db: Session = Depends(get_db)
):
try:
data = ClassDAO.update_base(db, class_id, req)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
if not data:
raise HTTPException(status_code=404, detail="班级不存在或已删除")
return data
@router.put(
"/{class_id}/head-teacher",
response_model=ClassDetail,
summary="调整班主任",
)
def update_head_teacher(
class_id: int, req: ClassHeadTeacherUpdate, db: Session = Depends(get_db)
):
try:
data = ClassDAO.update_head_teacher(db, class_id, req)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
if not data:
raise HTTPException(status_code=404, detail="班级不存在或已删除")
return data
@router.put(
"/{class_id}/teachers",
response_model=ClassDetail,
summary="更新授课老师",
)
def update_teachers(
class_id: int, req: ClassTeachersUpdate, db: Session = Depends(get_db)
):
try:
data = ClassDAO.update_teachers(db, class_id, req)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
if not data:
raise HTTPException(status_code=404, detail="班级不存在或已删除")
return data
+68
View File
@@ -0,0 +1,68 @@
from datetime import datetime
from fastapi import HTTPException, APIRouter, Depends
from sqlalchemy.orm import Session
from dao.counselor_dao import add_counselor, query_counselor,\
update_counselor, delete_counselor_id
from database import get_db
from schemas.counselor_scheme import CounselorCreate, DeleteCounselor, UpdateCounselor
router = APIRouter(
prefix="/counselor",
tags=["顾问管理"]
)
@router.post("/counselors/")
def counselor_create(cou: CounselorCreate,
db:Session=Depends(get_db)):
date_obj=(datetime.strptime(cou.c_time,"%Y-%m-%d"))
data= {
"id":cou.id,
"name":cou.name,
"c_time":date_obj.date()
}
add_counselor(db,data["id"], data["name"],data["c_time"])
return {"message":"新增成功"}
@router.get("/{id}")
def get_counselor(id:int, db:Session=Depends(get_db)):
cou = query_counselor(db, id)
if not cou:
raise HTTPException(404,detail="顾问不存在")
return {"data":cou}
# @router.get("/counselors/{name}")
# async def counselor_get_name(name,db:Session=Depends(get_db)):
# res=query_counselor_name(db,name)
# return {"message":"根据名字查询成功","data":res}
@router.delete("/{id}")
async def counselor_del_id(dele:DeleteCounselor,
db:Session=Depends(get_db)):
delete_counselor_id(db,dele.id)
return {"message":"根据id删除成功"}
# @router.delete("/counselors/{name}")
# async def counselor_del_name(name:str,
# db:Session=Depends(get_db)):
# delete_counselor_name(db,name)
# return {"message":"根据姓名删除成功"}
@router.put("/{id}")
async def update_tea(id:int,update:UpdateCounselor,db:Session=Depends(get_db)):
date_obj = datetime.strptime(update.c_time, "%Y-%m-%d")
res=update_counselor(db,id=id,
new_name=update.name,
new_c_time=date_obj
)
if res.get("msg")=="没找到顾问信息":
raise HTTPException(404,detail="顾问不存在")
return {"msg":"修改成功","data":res}
# @router.put("/counselors/{name}")
# async def counselor_update_name(id:int,name:str,c_time:datetime,db:Session=Depends(get_db)):
# res=query_counselor_name(db,id,name,c_time)
# return res
+113
View File
@@ -0,0 +1,113 @@
from fastapi import APIRouter,Depends, HTTPException,Query
from sqlalchemy.orm import Session
from database import get_db
from dao.employments import get_student_id,get_class_id,add_update_employment,get_student_multi_condition
from dao.student import get_student_by_id
from schemas.employments import Emp_Class,Emp_add_update,Emp_multi_Conditions
from typing import List,Optional
from dao.employments import delete_employment
router = APIRouter(
prefix="/employment", tags=["学生就业管理"] # 该路由下所有路径的前缀
)
# 1. GET /employment/students/{student_id} 获取单个学生就业信息
@router.get("/students/{student_id}", response_model=Emp_Class, summary="获取单个学生就业信息")
def get_student_employment(student_id: str, db: Session = Depends(get_db)):
stu = get_student_by_id(db, student_id)
if not stu:
raise HTTPException(status_code=404, detail="学生不存在")
isbool = get_student_id(db, student_id)
if not isbool:
raise HTTPException(status_code=404, detail="学生不存在")
return Emp_Class(
id=stu.id,
name=stu.name,
class_name=stu.class_name,
offer_open=isbool.offer_open if isbool else None,
offer_review=isbool.offer_review if isbool else None,
emp=isbool.emp if isbool else None,
sal=isbool.sal if isbool else None,
is_deleted=isbool.is_deleted
)
# 2. GET /employment/class/{class_id} 获取班级全部学生就业信息
@router.get("/class/{class_id}", response_model=List[Emp_Class], summary="获取班级下所有学生就业信息")
def get_class_employment(class_id: str, db: Session = Depends(get_db)):
rows =get_class_id(db, class_id)
result_list = []
for stu, isbool in rows:
if not stu:
raise HTTPException(status_code=404, detail="学生不存在")
if not isbool:
raise HTTPException(status_code=404, detail="学生不存在")
result_list.append(Emp_Class(
id=stu.id,
name=stu.name,
class_name=stu.class_name,
offer_open=isbool.offer_open if isbool else None,
offer_review=isbool.offer_review if isbool else None,
emp=isbool.emp if isbool else None,
sal=isbool.sal if isbool else None,
is_deleted=isbool.is_deleted
))
return result_list
# 3. POST /employment/students/{student_id} 添加/更新就业信息
@router.post("/students/{student_id}", response_model=Emp_Class, summary="新增或更新学生就业信息")
def upsert_student_employment(
student_id: str,
emp_data: Emp_add_update,
db: Session = Depends(get_db)
):
stu = get_student_by_id(db, student_id)
if not stu:
raise HTTPException(status_code=404, detail="学生不存在,请先创建学生基础信息")
emp = add_update_employment(db, student_id, emp_data, stu)
return Emp_Class(
id=stu.id,
name=stu.name,
class_name=stu.class_name,
offer_open=emp.offer_open,
offer_review=emp.offer_review,
emp=emp.emp,
sal=emp.sal,
is_deleted=emp.is_deleted
)
#多条件查询
@router.get("/query", response_model=List[Emp_Class], summary="多条件查询就业信息")
def multi_query_employment(
mid: Optional[str] = Query(default=None, title="学生id", description="主键"),#title是前端可以看到的输入框内容
name: Optional[str] = Query(default=None, title="学生姓名"),
min_sal: Optional[float] = Query(default=None, ge=0, title="最低薪资"),
max_sal: Optional[float] = Query(default=None, ge=0, title="最高薪资"),
db: Session = Depends(get_db)
):
rows = get_student_multi_condition(db, mid, name, min_sal, max_sal)
result_list = []
for stu, isbool in rows:
result_list.append(Emp_Class(
id=stu.id,
name=stu.name,
class_name=stu.class_name,
offer_open=isbool.offer_open if isbool else None,
offer_review=isbool.offer_review if isbool else None,
emp=isbool.emp if isbool else None,
sal=isbool.sal if isbool else None,
is_deleted=isbool.is_deleted if isbool else False # ← 修复了 NoneType 报错
))
return result_list
@router.post('/deleted',summary="逻辑删除学生就业信息")
def delete_emp( student_id:str,db: Session = Depends(get_db)):
delete_employment(db,student_id)
if delete_employment(db,student_id):
return f"学生id:{student_id}删除成功"
else:
raise HTTPException(status_code=404, detail="学生不存在,请先创建学生基础信息")
+40
View File
@@ -0,0 +1,40 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from database import get_db
from dao.scores import add_score,query_id,query_er,query_sc,update_sc,delete_sc
router = APIRouter(prefix="/scores", tags=["考核成绩管理"])
@router.post("/add", summary="按考核序次录入考核成绩") #1.录入成绩的路由
def add_score_api(id: str = Query(..., description="学生ID"), #用于校验学生ID是否存在
exam_round: int = Query(..., description="考核序次"), #用于校验同一学生同一考核序次是否重复录入
score: int = Query(..., ge=0, le=100, description="成绩(0-100)"), #录入的成绩
db: Session = Depends(get_db)):
return add_score(db=db, id=id, exam_round=exam_round, score=score)
@router.get("/query/id", summary="按学生ID查询成绩") #2. 按学生ID查询的路由
def query_id_api(id: str = Query(..., description="学生ID"),
db: Session = Depends(get_db)):
return query_id(db=db, id=id)
@router.get("/query/round", summary="按考核序次查询成绩") #3. 按考核序次查询的路由
def query_er_api(exam_round: int = Query(..., description="考核序次"),
db: Session = Depends(get_db)):
return query_er(db=db, exam_round=exam_round)
@router.get("/query/score", summary="按成绩查询记录") #4. 按成绩查询的路由
def query_sc_api(score: int = Query(..., ge=0, le=100, description="成绩"),
db: Session = Depends(get_db)):
return query_sc(db=db, score=score)
@router.put("/update", summary="根据学生ID和考核序次修改成绩") #5. 修改成绩的路由
def update_sc_api(id: str = Query(..., description="学生ID"), #根据学生ID
exam_round: int = Query(..., description="考核序次"), #根据考核序次
score: int = Query(..., ge=0, le=100, description="新的成绩"), #修改的成绩值
db: Session = Depends(get_db)):
return update_sc(db=db, id=id, exam_round=exam_round, score=score)
@router.delete("/delete", summary="根据学生ID和考核序次删除成绩") #6. 删除成绩(软删除)
def delete_sc_api(id: str = Query(..., description="学生ID"), #根据学生ID
exam_round: int = Query(..., description="考核序次"), #根据考核序次
db: Session = Depends(get_db)):
return delete_sc(db=db, id=id, exam_round=exam_round)
+113
View File
@@ -0,0 +1,113 @@
from fastapi import APIRouter, Depends, HTTPException
from pymysql import IntegrityError
from sqlalchemy.orm import Session
from typing import List
from model.classes_model import Classes
from dao.student_dao import update_student
from database import get_db
from model.student_info import Student
from schemas.student_info import StudentCreate, StudentUpdate, StudentResponse,student_date
router = APIRouter(prefix="/students", tags=["学生基本信息"])
# 1. 查询
@router.get("", response_model=List[StudentResponse], summary="查询学生")
def list_students(
id: str = None,
name: str = None,
class_name: str = None,
db: Session = Depends(get_db)
):
query = db.query(Student).filter(Student.is_deleted == False)
if id:
query = query.filter(Student.id == id)
if name:
query = query.filter(Student.name.like(f"%{name}%"))
if class_name:
query = query.filter(Student.class_name == class_name)
return query.all()
# 2. 创建
@router.post("", response_model=StudentResponse, summary="创建新学生")
def create_student(student: StudentCreate, db: Session = Depends(get_db)):
# 调用校验函数 如果入学日期存在,就把它变成字符串;如果不存在,就赋值为空
enroll_str = student.enrollment_date.strftime("%Y-%m-%d") if student.enrollment_date else None
grad_str = student.graduation_date.strftime("%Y-%m-%d") if student.graduation_date else None
date_check_result = student_date(enroll_str, grad_str)
#如果不存在,直接抛出异常中断请求
if date_check_result != "时间校验通过":
raise HTTPException(status_code=400, detail=date_check_result)
# 检查学号是否已存在
exist = db.query(Student).filter(Student.id == student.id).first()
if exist:
raise HTTPException(status_code=400, detail=f"学号 {student.id} 已存在")
# 不存在的班级导致外键约束报错
class_exists = db.query(Classes).filter(
Classes.class_name == student.class_name,
).first()
if not class_exists:
raise HTTPException(status_code=400,detail=f"班级 '{student.class_name}' 不存在,请检查输入是否正确!")
# 3. 构建数据库模型对象 一个个赋值
db_student = Student(
id=student.id,
name=student.name,
gender=student.gender,
class_name=student.class_name,
age=student.age,
hometown=student.hometown,
graduate_school=student.graduate_school,
major=student.major,
education=student.education,
enrollment_date=student.enrollment_date,
graduation_date=student.graduation_date,
status=student.status,
is_deleted=False
)
db.add(db_student)
db.commit()
db.refresh(db_student)
return db_student #返回响应
# 3. 详情
@router.get("/{id}", response_model=StudentResponse, summary="获取特定学生信息")
def get_student(id: str, db: Session = Depends(get_db)):
student = db.query(Student).filter(
Student.id == id,
Student.is_deleted == False
).first()
if student is None:
raise HTTPException(status_code=404, detail="学生不存在或已删除")
return student
# 4. 更新
@router.put("/{id}", response_model=StudentResponse, summary="更新学生信息")
def api_update_student(id: str, payload: StudentUpdate, db: Session = Depends(get_db)):
try:
student = update_student(db, id, payload)
if student is None:
raise HTTPException(status_code=404, detail="学生不存在或已删除")
return student
except IntegrityError:
db.rollback()
raise HTTPException(status_code=400, detail="更新失败:指定的班级不存在,请先创建对应班级!")
# 5. 逻辑删除
@router.delete("/{id}", summary="逻辑删除学生")
def delete_student(id: str, db: Session = Depends(get_db)):
student = db.query(Student).filter(
Student.id == id,
Student.is_deleted == False
).first()
if student is None:
raise HTTPException(status_code=404, detail="学生不存在或已删除")
student.is_deleted = True
db.commit()
return {"message": f"学生 {id} 已逻辑删除,数据仍保留在库中"}
+66
View File
@@ -0,0 +1,66 @@
from datetime import datetime
from fastapi import APIRouter, HTTPException
from fastapi.params import Depends
from sqlalchemy.orm import Session
from dao.teachers_dao import add_teachers, del_teachers, update_teachers, search_teachers, \
search_teachers_by_id, get_teacher_classes
from database import get_db
from schemas.req import AddTeacher, DeleteTeacher, UpdateTeacher
router=APIRouter(prefix="/teacher",tags=["老师管理"])
@router.post("/teachers")
async def create_teacher(tea:AddTeacher,db:Session=Depends(get_db)):
date_obj=datetime.strptime(tea.t_created,"%Y-%m-%d") # 将字符串转时间
data={
"t_name":tea.t_name,
"t_gender":tea.t_gender,
"t_phone":tea.t_phone,
"t_subject":tea.t_subject,
"t_created":date_obj
}
res=add_teachers(db, data["t_name"],data["t_gender"],data["t_phone"],data["t_subject"],data["t_created"])
return {"msg":"新增成功","data":res}
@router.delete("/{t_id}")
def delete_teacher(dele:DeleteTeacher,db:Session=Depends(get_db)):
res=del_teachers(db,t_id=dele.t_id,t_name=dele.t_name)
if res.get("msg") == "没找到老师信息":
raise HTTPException(404, detail="老师不存在")
return {"msg": "删除成功"}
@router.put("/{t_id}")
async def update_tea(t_id:int,update:UpdateTeacher,db:Session=Depends(get_db)):
date_obj = datetime.strptime(update.t_created, "%Y-%m-%d")
res=update_teachers(db,t_id=t_id,
new_name=update.t_name,
new_gender=update.t_gender,
new_phone=update.t_phone,
new_subject=update.t_subject,
new_created=date_obj
)
if res.get("msg")=="没找到老师信息":
raise HTTPException(404,detail="老师不存在")
return {"msg":"修改成功","data":res}
@router.get("/list")
def list_teachers(db:Session=Depends(get_db),page:int=1,size:int=3):
res=search_teachers(db,page,size)
return res
@router.get("/{t_id}")
def get_one(t_id:int, db:Session=Depends(get_db)):
tea = search_teachers_by_id(db, t_id)
if not tea:
raise HTTPException(404,detail="老师不存在")
return {"data":tea}
@router.get("/{t_id}/classes")
async def get_classes(t_id:int, db:Session=Depends(get_db)):
data=get_teacher_classes(db, t_id)
if not data:
raise HTTPException(404,detail="老师不存在")
return {"data":data}