161 lines
6.7 KiB
Python
161 lines
6.7 KiB
Python
# api/employment.py
|
|
# 就业模块接口:就业开放登记、offer登记(状态联动)、多条件查询、修改、删除
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy.orm import Session
|
|
|
|
from core.deps import get_current_user, require_roles, get_teacher_class_ids
|
|
from dao.employment_dao import EmploymentDAO
|
|
from dao.students_dao import StudentDAO
|
|
from database import get_db
|
|
from model.user import User
|
|
from scheme.employment import (
|
|
EmploymentOpen,
|
|
OfferAdd,
|
|
EmploymentUpdate,
|
|
OfferResponse,
|
|
EmploymentResponse,
|
|
EmploymentListResponse,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
def _can_manage_student_employment(db: Session, user: User, student) -> bool:
|
|
if user.role == "admin":
|
|
return True
|
|
if user.role == "teacher":
|
|
return student.class_id in get_teacher_class_ids(db, user.teacher_id)
|
|
return False
|
|
|
|
|
|
def _check_student_manage(db: Session, user: User, stu_id: int):
|
|
"""公共校验:学生存在 + 操作者有权管理该学生就业信息"""
|
|
student = StudentDAO.get_active(db, stu_id)
|
|
if student is None:
|
|
raise HTTPException(status_code=404, detail="学生不存在,或已被软删除")
|
|
if not _can_manage_student_employment(db, user, student):
|
|
raise HTTPException(status_code=403, detail="教师只能管理自己所带班级学生的就业信息")
|
|
return student
|
|
|
|
|
|
def _to_response(db_base) -> EmploymentResponse:
|
|
resp = EmploymentResponse.model_validate(db_base)
|
|
resp.offers = [OfferResponse.model_validate(o) for o in (db_base.offers or [])]
|
|
return resp
|
|
|
|
|
|
# ---------- 登记就业开放 ----------
|
|
@router.post("/open", response_model=EmploymentResponse, summary="登记就业开放(学生状态联动→进入就业)")
|
|
async def open_employment(
|
|
body: EmploymentOpen,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_roles("admin", "teacher")),
|
|
):
|
|
_check_student_manage(db, current_user, body.stu_id)
|
|
existing = EmploymentDAO.get_base(db, body.stu_id)
|
|
if existing:
|
|
raise HTTPException(status_code=409, detail="该学生已登记就业开放,请勿重复登记")
|
|
db_base = EmploymentDAO.open_employment(db, body.stu_id, body.employment_open_time)
|
|
return _to_response(db_base)
|
|
|
|
|
|
# ---------- 登记 offer ----------
|
|
@router.post("/offer", response_model=EmploymentResponse, summary="登记offer(学生状态联动→已就业)")
|
|
async def add_offer(
|
|
body: OfferAdd,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_roles("admin", "teacher")),
|
|
):
|
|
_check_student_manage(db, current_user, body.stu_id)
|
|
db_base = EmploymentDAO.get_base(db, body.stu_id)
|
|
if db_base is None:
|
|
raise HTTPException(status_code=404, detail="该学生尚未登记就业开放,请先调用 /employment/open")
|
|
if body.offer_time < db_base.employment_open_time:
|
|
raise HTTPException(status_code=400, detail="offer下发时间不能早于就业开放时间")
|
|
EmploymentDAO.add_offer(db, body.stu_id, body.offer_time, body.company_name, body.salary)
|
|
return _to_response(EmploymentDAO.get_base(db, body.stu_id))
|
|
|
|
|
|
# ---------- 查询学生就业信息 ----------
|
|
@router.get("/students/{stu_id}", response_model=EmploymentResponse, summary="查询学生就业信息")
|
|
async def get_student_employment(
|
|
stu_id: int,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user),
|
|
):
|
|
if current_user.role == "student" and current_user.stu_id != stu_id:
|
|
raise HTTPException(status_code=403, detail="学生角色只能查看自己的就业信息")
|
|
db_base = EmploymentDAO.get_by_student(db, stu_id)
|
|
if db_base is None:
|
|
raise HTTPException(status_code=404, detail="该学生暂无就业信息")
|
|
return _to_response(db_base)
|
|
|
|
|
|
# ---------- 查询班级就业信息 ----------
|
|
@router.get("/class/{class_id}", response_model=EmploymentListResponse, summary="查询班级学生就业信息")
|
|
async def get_class_employment(
|
|
class_id: int,
|
|
skip: int = Query(0, ge=0),
|
|
limit: int = Query(100, ge=1, le=200),
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_roles("admin", "teacher")),
|
|
):
|
|
total, items = EmploymentDAO.get_by_class(db, class_id, skip=skip, limit=limit)
|
|
return EmploymentListResponse(total=total, items=[_to_response(b) for b in items])
|
|
|
|
|
|
# ---------- 多条件查询就业信息 ----------
|
|
@router.get("/total_query", response_model=EmploymentListResponse, summary="多条件查询就业信息(学号/公司/薪资范围)")
|
|
async def query_employment(
|
|
skip: int = Query(0, ge=0),
|
|
limit: int = Query(100, ge=1, le=200),
|
|
stu_id: int = Query(None, ge=1, description="按学号精确查询"),
|
|
company_name: str = Query(None, description="按公司名称模糊查询"),
|
|
salary_min: float = Query(None, ge=0, description="薪资下限"),
|
|
salary_max: float = Query(None, ge=0, description="薪资上限"),
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_roles("admin", "teacher")),
|
|
):
|
|
total, items = EmploymentDAO.get_all(
|
|
db,
|
|
skip=skip,
|
|
limit=limit,
|
|
stu_id=stu_id,
|
|
company_name=company_name,
|
|
salary_min=salary_min,
|
|
salary_max=salary_max,
|
|
)
|
|
return EmploymentListResponse(total=total, items=[_to_response(b) for b in items])
|
|
|
|
|
|
# ---------- 修改就业基础信息 ----------
|
|
@router.put("/update", response_model=EmploymentResponse, summary="修改学生就业基础信息")
|
|
async def update_employment(
|
|
body: EmploymentUpdate,
|
|
stu_id: int = Query(..., ge=1, description="学生编号"),
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_roles("admin", "teacher")),
|
|
):
|
|
_check_student_manage(db, current_user, stu_id)
|
|
update_data = body.model_dump(exclude_unset=True, exclude_none=True)
|
|
if not update_data:
|
|
raise HTTPException(status_code=400, detail="至少提供一个要修改的字段")
|
|
db_base = EmploymentDAO.update_base(db, stu_id, update_data)
|
|
if db_base is None:
|
|
raise HTTPException(status_code=404, detail="该学生暂无就业信息")
|
|
return _to_response(db_base)
|
|
|
|
|
|
# ---------- 删除就业信息 ----------
|
|
@router.delete("/delete", status_code=204, summary="删除学生就业信息(逻辑删除,状态回退为在读)")
|
|
async def delete_employment(
|
|
stu_id: int = Query(..., ge=1, description="学生编号"),
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_roles("admin", "teacher")),
|
|
):
|
|
_check_student_manage(db, current_user, stu_id)
|
|
success = EmploymentDAO.delete_light(db, stu_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="该学生暂无就业信息")
|
|
return None
|