diff --git a/api/employment.py b/api/employment.py index e69de29..b0f6dcd 100644 --- a/api/employment.py +++ b/api/employment.py @@ -0,0 +1,59 @@ +from fastapi import APIRouter, Depends, HTTPException, Query # 导入fastapi组件 +from core.database import get_db # 导入获取数据库会话的工具函数 +from dao.employment import * # 导入dao层函数 +from schemas.employment import * # 导入schema模型 +from typing import List, Optional # 导入类型提示 + +employments_router = APIRouter() + +@employments_router.post("/employments", response_model=EmploymentResponse, summary="新增就业信息") +def create_employment(body: EmploymentCreate # 请求体入参 + ,db= Depends(get_db)): # 注入数据库会话 + """新增一条学生就业信息,一个学生只能有一条就业记录""" + x=body.model_dump() + y=create_employment(x,db) + if not y: + raise HTTPException(status_code=500, detail='服务器繁忙,请稍后添加!') + return {"code":200,"detail":"新增信息成功"} + +@employments_router.get("/employments", response_model=List[EmploymentResponse], summary="就业列表查询") +def get_employment_list(company_name: Optional[str] = Query(None, description="公司名称模糊搜索") + ,salary_min: Optional[float] = Query(None, description="薪资下限") + ,salary_max: Optional[float] = Query(None, description="薪资上限") + ,db: Session = Depends(get_db)): + """获取就业列表,支持按公司名称、薪资范围过滤""" + return get_employment_list(db=db + ,company_name=company_name + ,salary_min=salary_min + ,salary_max=salary_max) + + +@employments_router.get("/employments/students/{student_id}", response_model=EmploymentResponse, summary="查询某个学生的就业信息") +def get_student_employment(student_id: int + ,db: Session = Depends(get_db)): + """根据学生ID获取该学生对应的就业信息""" + res = get_employment_by_student_id(db=db, stu_id=student_id) + if not res: + raise HTTPException(status_code=404, detail="该学生暂无就业信息") + return res + + +@employments_router.put("/employments/{emp_id}", response_model=EmploymentResponse, summary="修改就业信息") +def update_employment(emp_id: int + ,body: EmploymentUpdate + ,db: Session = Depends(get_db)): + """根据id修改就业记录信息""" + res = update_employment(db=db, emp_id=emp_id, E=body) + if not res: + raise HTTPException(status_code=404, detail="就业记录不存在或已删除") + return res + + +@employments_router.delete("/employments/{emp_id}", summary="逻辑删除就业记录") +def delete_employment(emp_id: int + ,db: Session = Depends(get_db)): + """逻辑删除,设置is_deleted=1,不会物理删除数据库数据,删除后普通接口查询不到""" + ok = delete_employment_logic(db=db, emp_id=emp_id) + if not ok: + raise HTTPException(status_code=404, detail="就业记录不存在或已删除") + return {"msg": "逻辑删除成功", "id": emp_id} diff --git a/dao/employment.py b/dao/employment.py index e69de29..fe03065 100644 --- a/dao/employment.py +++ b/dao/employment.py @@ -0,0 +1,87 @@ +from sqlalchemy.orm import Session # 导入sqlalchemy会话对象 +from models.employment import Employment # 导入就业ORM模型 +from schemas.employment import EmploymentCreate, EmploymentUpdate # 导入pydantic新增、修改schema +from typing import Optional # 导入类型提示 + +def create_employment(db: Session, E: EmploymentCreate): #新增就业记录 + try: + db_obj = Employment(**E.model_dump()) + db.add(db_obj) + except: + db.rollback() + return False + else: + db.commit() + return db_obj + + +def get_employment_by_id(db: Session, emp_id: int): #根据主键id查询单条就业记录 + return db.query(Employment).filter(Employment.id == emp_id # 匹配id + ,Employment.is_deleted == 0).first() # 过滤逻辑删除,只查正常数据 + + + +def get_employment_by_student_id(db: Session, stu_id: int): #根据学生id查询该学生的就业信息 + return db.query(Employment).filter(Employment.student_id == stu_id + ,Employment.is_deleted == 0).first() + + +def get_employment_list(db: Session + ,company_name: Optional[str] = None # 按公司名称模糊查询 + ,salary_min: Optional[float] = None # 薪资下限 + ,salary_max: Optional[float] = None): # 薪资上限 + q = db.query(Employment).filter(Employment.is_deleted == 0) # 基础查询,只查询未删除数据 + + + if company_name: # 如果传入公司名称,做模糊匹配 + q = q.filter(Employment.company_name.like(f"%{company_name}%")) + + if salary_min is not None: # 如果传入薪资下限 + q = q.filter(Employment.salary >= salary_min) + + if salary_max is not None: # 如果传入薪资上限 + q = q.filter(Employment.salary <= salary_max) + + return q.all() # 执行查询返回列表 + + + +def update_employment(db: Session, emp_id: int, E: EmploymentUpdate): #修改就业记录 + """ + :param db: 数据库会话 + :param emp_id: 需要修改的就业记录id + :param obj_in: 修改入参 EmploymentUpdate + :return: 修改完成的对象 / None(数据不存在) + """ + # 先查询这条记录是否存在且未删除 + db_obj = get_employment_by_id(db, emp_id) + # 判断记录不存在直接返回None + if not db_obj: + return None + # 获取传入的非空字段字典 + update_data = E.model_dump(exclude_unset=True) + # 循环遍历需要更新的字段,赋值给ORM对象 + for k, v in update_data.items(): + setattr(db_obj, k, v) + db.commit() + # 刷新对象获取最新数据 + db.refresh(db_obj) + return db_obj + + +def delete_employment_logic(db: Session, emp_id: int): + """ + 逻辑删除就业记录:不物理删除,设置is_deleted=1 + :param db: 数据库会话 + :param emp_id: 就业记录主键id + :return: True成功;False记录不存在 + """ + # 查询目标记录 + db_obj = get_employment_by_id(db, emp_id) + if not db_obj: + return False + # 设置逻辑删除标记为1 + db_obj.is_deleted = 1 + # 提交事务 + db.commit() + return True diff --git a/models/employment.py b/models/employment.py index 69e2706..8c065f6 100644 --- a/models/employment.py +++ b/models/employment.py @@ -6,26 +6,26 @@ from core.database import Base, engine # 为了符合三范式,就业表只保存 student_id,不保存学生姓名和班级名称。查询返回时通过关联 students 和 classes 带出学生姓名、班级名称。 class Employment(Base): - __tablename__ = "employments" # 实际数据库的表名字 - id = Column(BigInteger, primary_key=True # 主键 - , autoincrement=True # 声明是自增主键 - ,comment="就业信息主键id") - student_id = Column(BigInteger, ForeignKey("students.id") # 外键 -> students.id - , nullable=False # 不允许为null - ,comment="关联学生id") + __tablename__ = "employments_info_detail" # 实际数据库的表名字 + id = Column(BigInteger, primary_key=True # 主键 + , autoincrement=True # 声明是自增主键 + , comment="就业信息主键id") + student_id = Column(BigInteger, ForeignKey("student_info_detail.id") # 外键 + , nullable=False # 不允许为null + , comment="关联学生id") employment_status = Column(String(50) , default="not_started" - ,comment="就业状态:not_started/job_hunting/offered/employed") + , comment="就业状态:not_started/job_hunting/offered/employed") employment_open_date = Column(Date - ,comment="就业开放时间") + , comment="就业开放时间") offer_date = Column(Date - ,comment="offer下发时间") + , comment="offer下发时间") company_name = Column(String(100) , comment="就业公司名称") salary = Column(DECIMAL(10, 2) # 高精度浮点数薪资,最多 10 位数字,小数占 2 位 , comment="就业薪资") remark = Column(String(255) - ,default=None + , default=None , comment="备注信息") created_at = Column(DateTime , default=datetime.now @@ -33,8 +33,8 @@ class Employment(Base): updated_at = Column(DateTime , default=datetime.now , onupdate=datetime.now - ,comment="更新时间") + , comment="更新时间") is_deleted = Column(SmallInteger - ,default=0 - ,comment="逻辑删除:0正常,1删除") + , default=0 + , comment="逻辑删除:0正常,1删除") diff --git a/schemas/employment.py b/schemas/employment.py index e69de29..ef95ed4 100644 --- a/schemas/employment.py +++ b/schemas/employment.py @@ -0,0 +1,43 @@ +from pydantic import BaseModel, Field +from typing import Optional +from datetime import date +from decimal import Decimal + + +class EmploymentCreate(BaseModel): + """新增就业信息 请求体 Schema""" + # 学生ID 必填,一个学生只能有一条就业记录 + student_id: int = Field(..., description="关联学生ID,必填") + # 就业状态必填,限定可选值业务枚举 + employment_status: str = Field(..., description="就业状态:not_started/job_hunting/offered/employed") + employment_open_date: Optional[date] = Field(None, description="就业开放时间,选填") + offer_date: Optional[date] = Field(None, description="offer下发时间,选填") + company_name: Optional[str] = Field(None, max_length=100, description="就业公司名称,选填") + salary: Optional[Decimal] = Field(None, ge=0, description="就业薪资,不能负数,选填") + remark: Optional[str] = Field(None, max_length=255, description="备注,选填") + + +class EmploymentUpdate(BaseModel): + """修改就业信息 请求体 Schema:全部字段可选,只传要修改的字段""" + employment_status: Optional[str] = Field(None, description="就业状态") + employment_open_date: Optional[date] = Field(None, description="就业开放时间") + offer_date: Optional[date] = Field(None, description="offer下发时间") + company_name: Optional[str] = Field(None, max_length=100, description="就业公司名称") + salary: Optional[Decimal] = Field(None, ge=0, description="就业薪资") + remark: Optional[str] = Field(None, max_length=255, description="备注") + + +class EmploymentResponse(BaseModel): + """就业信息返回响应体Schema,接口返回给前端的数据结构""" + id: int + student_id: int + employment_status: str + employment_open_date: Optional[date] + offer_date: Optional[date] + company_name: Optional[str] + salary: Optional[Decimal] + remark: Optional[str] + created_at: date + updated_at: date + +