Merge remote-tracking branch 'origin/main' into zhutt

# Conflicts:
#	main.py
This commit is contained in:
2026-09-22 09:53:34 +08:00
23 changed files with 1461 additions and 65 deletions
+5 -7
View File
@@ -9,8 +9,7 @@ router = APIRouter()
@router.get(
path="/consultants",
tags=['顾问管理模块']
)
tags=['顾问管理模块'],summary='顾问模糊分页查询')
def read_consultants(
db: Session = Depends(get_db),
page:int=1,
@@ -22,7 +21,7 @@ def read_consultants(
@router.post("/consultants", response_model=ConsultantResponse,tags=['顾问管理模块'])
@router.post("/consultants", response_model=ConsultantResponse,tags=['顾问管理模块'],summary='顾问增加')
def create_consultant(
obj_in: ConsultantCreate,
db: Session = Depends(get_db)
@@ -30,7 +29,7 @@ def create_consultant(
return dao_consultant.create_consultant(db, obj_in)
@router.get("/consultants/{id}", response_model=ConsultantResponse,tags=['顾问管理模块'])
@router.get("/consultants/{id}", response_model=ConsultantResponse,tags=['顾问管理模块'],summary='顾问查询')
def read_consultant(id: int, db: Session = Depends(get_db)):
res = dao_consultant.get_consultant_by_id(db, cid=id)
if res is None:
@@ -41,8 +40,7 @@ def read_consultant(id: int, db: Session = Depends(get_db)):
@router.put(
path="/consultants/{id}",
response_model=ConsultantResponse,
tags=['顾问管理模块']
)
tags=['顾问管理模块'],summary='顾问更新')
def update_consultant(
id: int,
obj_in: ConsultantUpdate,
@@ -57,7 +55,7 @@ def update_consultant(
@router.delete("/consultants/{id}", response_model=ConsultantResponse,tags=['顾问管理模块'])
@router.delete("/consultants/{id}", response_model=ConsultantResponse,tags=['顾问管理模块'],summary='顾问删除')
def delete_consultant(id: int, db: Session = Depends(get_db)):
res = dao_consultant.delete_consultant(db, cid=id)
if res is None:
+82
View File
@@ -0,0 +1,82 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from core.database import get_db
from dao.employment import (
create_employment,
get_employment_by_id,
get_employment_by_student_id,
get_employment_list,
update_employment,
delete_employment_logic
)
from schemas.employment import (
EmploymentCreate,
EmploymentUpdate,
EmploymentResponse
)
employment_router = APIRouter(prefix="/employments", tags=["就业管理模块"])
@employment_router.post("/", response_model=EmploymentResponse, summary="新增就业信息")
def add_employment(body: EmploymentCreate, db: Session = Depends(get_db)):
"""
新增就业信息
- 一个学生只能保存一条就业记录
- student_id必须在学生表student_info_detail中真实存在
"""
res = create_employment(db, body)
if res is None:
raise HTTPException(status_code=500, detail="新增失败,学生id不存在或该学生已有就业记录")
return res
@employment_router.get("/students/{student_id}", response_model=EmploymentResponse, summary="查询指定学生的就业信息")
def query_student_employment(student_id: int, db: Session = Depends(get_db)):
"""根据学生id获取对应就业记录"""
record = get_employment_by_student_id(db, student_id)
if not record:
raise HTTPException(status_code=404, detail="未找到该学生的就业信息")
return record
@employment_router.get("/", summary="就业信息列表,支持筛选")
def query_employment_list(
company_name: str | None = Query(None, description="公司名称模糊查询"),
salary_min: float | None = Query(None, description="最低薪资"),
salary_max: float | None = Query(None, description="最高薪资"),
skip: int = Query(0, ge=0, description="偏移量"),
limit: int = Query(20, ge=1, le=100, description="每页条数"),
db: Session = Depends(get_db)
):
# 调用dao列表查询,拿到数据字典列表和总条数
data_list, total = get_employment_list(db, company_name, salary_min, salary_max, skip, limit)
return {"total": total, "data": data_list}
@employment_router.get("/{eid}", response_model=EmploymentResponse, summary="根据id查询就业详情")
def query_employment_detail(eid: int, db: Session = Depends(get_db)):
"""根据就业主键id查询单条就业记录"""
record = get_employment_by_id(db, eid)
if not record:
raise HTTPException(status_code=404, detail="就业记录不存在或已被逻辑删除")
return record
@employment_router.put("/{eid}", response_model=EmploymentResponse, summary="修改就业信息")
def edit_employment(eid: int, body: EmploymentUpdate, db: Session = Depends(get_db)):
"""修改就业记录,只传想要修改的字段即可"""
res = update_employment(db, eid, body)
if res is None:
raise HTTPException(status_code=404, detail="修改失败,记录不存在")
return res
@employment_router.delete("/{eid}", summary="逻辑删除就业记录")
def logic_delete_employment(eid: int, db: Session = Depends(get_db)):
"""执行逻辑删除,is_deleted置1,不会真正删除数据库行"""
ok = delete_employment_logic(db, eid)
if not ok:
raise HTTPException(status_code=404, detail="删除失败,记录不存在")
# 删除成功返回提示字典
return {"code": 200, "msg": "逻辑删除成功"}
+51
View File
@@ -0,0 +1,51 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from core.database import get_db
from dao.score import post_score_dao, update_score_dao, get_score_dao, delete_score_dao, exist_student_exam_dao
from schemas.score import ScoreCreate, ScoreUpdate, ScorePageResp
scores_router = APIRouter(prefix="/scores", tags=["成绩接口"])
@scores_router.post("", summary="新增成绩接口")
def create_score(req: ScoreCreate, db: Session = Depends(get_db)):
# 业务校验:联合唯一
if exist_student_exam_dao(req.student_id, req.exam_seq, db):
raise HTTPException(status_code=400, detail="该学生本次考试成绩已存在,不能重复录入")
ok = post_score_dao(req.model_dump(), db)
if not ok:
raise HTTPException(status_code=400, detail="新增成绩失败,请检查学生id是否存在")
return {"msg": "新增成功"}
@scores_router.get("", response_model=ScorePageResp, summary="查询成绩接口")
def list_score(
score_id: int|None=None,
student_id: int |None=None,
exam_seq: int|None=None,
page: int = Query(1, ge=1),
page_size: int = Query(10, ge=1, le=100),
db: Session = Depends(get_db)
):
total, data_list = get_score_dao(score_id, student_id, exam_seq, page, page_size, db)
return {"total": total, "data": data_list}
@scores_router.put("{score_id}", summary="更新成绩接口")
def modify_score(score_id: int, req: ScoreUpdate, db: Session = Depends(get_db)):
update_dict = req.model_dump(exclude_unset=True)
if not update_dict:
raise HTTPException(status_code=400, detail="没有传入任何修改字段")
ok = update_score_dao(score_id, db, update_dict)
if not ok:
raise HTTPException(status_code=400, detail="修改失败,记录不存在或已删除")
return {"msg": "修改成功"}
@scores_router.delete("{score_id}", summary="删除成绩接口")
def remove_score(score_id: int, db: Session = Depends(get_db)):
ok = delete_score_dao(score_id, db)
if not ok:
raise HTTPException(status_code=400, detail="删除失败,记录不存在或已删除")
return {"msg": "逻辑删除成功"}
+62 -7
View File
@@ -1,16 +1,17 @@
from fastapi import APIRouter,HTTPException,Depends
from DoubaoTeam.core.database import get_db
from DoubaoTeam.models.student import Student
from DoubaoTeam.models.score import Score
from DoubaoTeam.dao.statistics import *
from DoubaoTeam.schemas.common import SuccessResponse
from core.database import get_db
from models.employment import Employment
from models.student import Student
from models.score import Score
from dao.statistics import *
from schemas.common import SuccessResponse
from sqlalchemy.orm import Session
statistics_router=APIRouter()
statistics_router=APIRouter(tags=['statistics'])
@statistics_router.get("/scores/age-over-30",response_model=SuccessResponse)
@statistics_router.get("/students/age-over-30",response_model=SuccessResponse)
def api_age_over_thirty(db:Session=Depends(get_db)):
try:
age_over_thirty_list=age_over_thirty(Student,db)
@@ -26,3 +27,57 @@ def api_gender_count(db:Session=Depends(get_db)):
except NoExist as e:
raise HTTPException(status_code=404,detail=str(e))
@statistics_router.get("/scores/all-above-80",response_model=SuccessResponse)
def all_above_eighty(db:Session=Depends(get_db)):
try:
result = score_over_eighty(Score,Student,db)
return SuccessResponse(status_code=200,msg=result)
except NoExist as e:
raise HTTPException(status_code=404,detail=str(e))
@statistics_router.get("/scores/fail-more-than-two",response_model=SuccessResponse)
def fail_two(db:Session=Depends(get_db)):
try:
result = twice_error(Score,Student,db)
return SuccessResponse(status_code=200,msg=result)
except NoExist as e:
raise HTTPException(status_code=404,detail=str(e))
@statistics_router.get("/scores/class-average",response_model=SuccessResponse)
def class_average(db:Session=Depends(get_db)):
try:
result = avg_class(Score,Student,db)
return SuccessResponse(status_code=200,msg=result)
except NoExist as e:
raise HTTPException(status_code=404,detail=str(e))
@statistics_router.get("/employments/top5-salary",response_model=SuccessResponse)
def top_salary(db:Session=Depends(get_db)):
try:
result=max_salary(Student,Employment,db)
return SuccessResponse(status_code=200,msg=result)
except NoExist as e:
raise HTTPException(status_code=404,detail=str(e))
@statistics_router.get("/employments/student-duration",response_model=SuccessResponse)
def employ_time(db:Session=Depends(get_db)):
try:
result = student_market(Employment,db)
return SuccessResponse(status_code=200,msg=result)
except NoExist as e:
raise HTTPException(status_code=404,detail=str(e))
@statistics_router.get("/employments/class-average-duration",response_model=SuccessResponse)
def avg_employ_time(db:Session=Depends(get_db)):
try:
result = avg_emptime(Employment,Student,db)
return SuccessResponse(status_code=200,msg=result)
except NoExist as e:
raise HTTPException(status_code=404,detail=str(e))
+89 -7
View File
@@ -1,14 +1,96 @@
from fastapi import APIRouter,Depends,HTTPException
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from dao.student import *
from schemas.student import StudentCreate
from core.database import get_db
from schemas.student import StudentCreate, StudentUpdate
from dao import student as student_dao
student_router = APIRouter()
@student_router.post("/student")
def create_student(request:StudentCreate,db:Session,create = Depends(create_students)):
@student_router.post("",summary='添加学生')
def create_student(request:StudentCreate,db:Session = Depends(get_db)):
d = request.model_dump()
r = create_students(d,db)
r = student_dao.create_students(d,db)
if not r:
raise HTTPException(status_code=500,detail='服务器繁忙,请稍后添加!')
return {'code':200,'detail':"添加学生成功"}
return {'code':200,'detail':"添加学生成功"}
@student_router.put("/{id}", summary="修改学生")
def update_student(
id: int,
request: StudentUpdate,
db: Session = Depends(get_db),
):
# 只取前端真正传来的字段
# 例如只传 age,就只修改 age
data = request.model_dump(exclude_unset=True)
student = student_dao.update_student(id, data, db)
# None 表示学生不存在
if student is None:
raise HTTPException(status_code=404, detail="学生不存在")
# False 表示操作数据库失败
if student is False:
raise HTTPException(status_code=500, detail="修改学生失败")
return {
"code": 200,
"detail": "修改学生成功",
"data": student,
}
@student_router.get("", summary="查询学生列表")
def get_students(
# 三个查询条件都可以不传
student_no: str | None = None,
student_name: str | None = None,
class_id: int | None = None,
# 获取本次请求使用的数据库连接
db: Session = Depends(get_db),
):
# 调用 DAO 查询数据库
students = student_dao.get_students(
db=db,
student_no=student_no,
student_name=student_name,
class_id=class_id,
)
return {
"code": 200,
"detail": "查询成功",
"total": len(students),
"data": students,
}
@student_router.get("/{id}", summary="查询学生详情")
def get_student(id: int, db: Session = Depends(get_db)):
# 根据路径中的 ID 查询学生
student = student_dao.get_student_by_id(id, db)
if not student:
# 404 表示请求的数据不存在
raise HTTPException(status_code=404, detail="学生不存在")
return {
"code": 200,
"detail": "查询成功",
"data": student,
}
@student_router.delete("/{id}", summary="逻辑删除学生")
def delete_student(id: int, db: Session = Depends(get_db)):
student = student_dao.delete_student(id, db)
# None 表示不存在,或者以前已经删除
if student is None:
raise HTTPException(status_code=404, detail="学生不存在或已经删除")
if student is False:
raise HTTPException(status_code=500, detail="删除学生失败")
return {
"code": 200,
"detail": "删除学生成功",
}
+129
View File
@@ -0,0 +1,129 @@
from typing import List
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from core import database
from core.database import get_db
from schemas.teacher import TeacherOut, TeacherCreate, TeacherUpdate, ClassTeachersCreate, ClassTeacherOut
# 导入dao层所有函数
from models.teacher import Teacher
from models.class_teacher import ClassTeachers
from dao.teacher import (
get_teacher_list,
get_teacher_by_id,
create_teacher,
update_teacher,
delete_teacher,
get_class_teacher_by_class_id,
create_class_teacher,
update_class_teacher_full,
delete_class_teacher
)
router = APIRouter(prefix="/teacher", tags=["老师管理模块"])
#============================老师表===============================
@router.get("/list", response_model=List[TeacherOut])
def api_get_teacher_list(db: Session = Depends(get_db)):
"""
GET 查询全部有效老师列表
:param db: 数据库会话,Depends自动注入
:return: List[TeacherOut] 老师列表,使用TeacherOut做响应格式化
"""
return get_teacher_list(db)
@router.get("/{teacher_id}", response_model=TeacherOut)
def api_get_teacher_by_id(teacher_id: int,db: Session = Depends(get_db)):
"""
根据老师主键ID查询单个有效老师
:param teacher_id: int 老师表主键ID
:param db: Session 数据库会话对象,依赖注入自动获取
:return: TeacherOut 老师详情信息
"""
return get_teacher_by_id(db,teacher_id)
@router.post("", response_model=TeacherOut, summary="新增老师")
def api_create_teacher(obj: TeacherCreate, db: Session = Depends(get_db)):
"""
新增老师记录,自动校验姓名、编号唯一性,并自动生成老师业务编号
:param obj: TeacherCreate Pydantic模型,前端提交新增老师表单数据
:param db: Session 数据库会话对象,依赖注入自动获取
:return: TeacherOut 新增成功后的老师完整信息
"""
return create_teacher(db, obj)
@router.put("/{teacher_id}", response_model=TeacherOut, summary="修改老师信息(局部更新)")
def api_update_teacher(teacher_id: int, obj: TeacherUpdate, db: Session = Depends(get_db)):
"""
修改老师信息,支持局部更新,仅更新前端传入的字段
:param teacher_id: int 需要修改的老师主键ID
:param obj: TeacherUpdate Pydantic模型,前端提交待修改字段
:param db: Session 数据库会话对象,依赖注入自动获取
:return: TeacherOut 更新后的老师完整信息
"""
db_teacher = get_teacher_by_id(db, teacher_id)
if not db_teacher:
raise HTTPException(status_code=404, detail="老师不存在或已删除!")
result = update_teacher(db, teacher_id, obj)
return result
@router.delete("/{teacher_id}", summary="逻辑删除老师")
def api_delete_teacher(teacher_id: int, db: Session = Depends(get_db)):
"""
逻辑删除老师,存在有效班级带班关系时禁止删除
:param teacher_id: int 需要删除的老师主键ID
:param db: Session 数据库会话对象,依赖注入自动获取
:return: dict 操作成功提示
"""
result = delete_teacher(db, teacher_id)
if not result:
raise HTTPException(status_code=404, detail="老师不存在或已删除!")
return {"msg": "老师逻辑删除成功"}
# ===================== 班级老师关联路由组 =====================
class_teacher_router = APIRouter(prefix="/class-teacher", tags=["班级老师分配管理模块"])
@class_teacher_router.get("/class/{class_id}", response_model=List[ClassTeacherOut], summary="根据班级ID查询该班级所有带班老师")
def api_get_class_teacher_by_class_id(class_id: int, db: Session = Depends(get_db)):
"""
根据班级主键ID,查询该班级全部有效的班级-老师绑定记录
:param class_id: int 班级表主键ID
:param db: Session 数据库会话对象,依赖注入自动获取
:return: List[ClassTeachersOut] 班级老师关联记录列表
"""
return get_class_teacher_by_class_id(db, class_id)
@class_teacher_router.post("", response_model=ClassTeacherOut, summary="分配老师到班级,新增班级老师关联记录")
def api_create_class_teacher(obj: ClassTeachersCreate, db: Session = Depends(get_db)):
"""
新增班级与老师的绑定关系,做重复性校验与老师有效性校验
:param obj: ClassTeachersCreate Pydantic模型,前端提交class_id、teacher_id、role
:param db: Session 数据库会话对象,依赖注入自动获取
:return: ClassTeachersOut 新增成功后的班级老师关联记录
"""
return create_class_teacher(db, obj)
@class_teacher_router.put("/{rel_id}", response_model=ClassTeacherOut, summary="更新班级老师绑定关系")
def api_update_class_teacher_full(rel_id: int, obj: ClassTeachersCreate, db: Session = Depends(get_db)):
"""
修改班级老师中间表记录,支持修改class_id、teacher_id、role;自动校验老师有效性、三元组合唯一性
:param rel_id: int class_teachers中间表主键ID(待修改的关联记录id)
:param obj: ClassTeachersCreate Pydantic模型,前端提交新的class_id、teacher_id、role
:param db: Session 数据库会话对象,依赖注入自动获取
:return: ClassTeachersOut 更新后的班级老师关联记录
"""
result = update_class_teacher_full(db, rel_id, obj)
if not result:
raise HTTPException(status_code=404, detail="班级老师关联记录不存在!")
return result
@class_teacher_router.delete("/{rel_id}", summary="逻辑删除班级老师带班关联")
def api_delete_class_teacher(rel_id: int, db: Session = Depends(get_db)):
"""
逻辑删除班级老师绑定关系,修改is_deleted标记为1,非物理删除
:param rel_id: int class_teachers中间表主键ID
:param db: Session 数据库会话对象,依赖注入自动获取
:return: dict 操作成功提示
"""
result = delete_class_teacher(db, rel_id)
if not result:
raise HTTPException(status_code=404, detail="班级老师关联记录不存在!")
return {"msg": "解除班级带班关系成功"}