feat(duty): register admin and public duty APIs with encrypt exclude
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
49cad98c84
commit
36fc7f286c
4 files changed
+151
-1
No files matched your search
@@ -0,0 +1,107 @@
|
||||
"""值班排班 · 管理端 API"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.menu_guard import require_admin_or_super_admin
|
||||
from app.core.response import error_response, success_response
|
||||
from app.crud import user as user_crud
|
||||
from app.schemas.duty import DutyDaySaveBody, DutyLinkBody
|
||||
from app.services import duty_schedule as duty_svc
|
||||
from app.services.duty_schedule import DutyBizError
|
||||
|
||||
router = APIRouter(prefix="/web/admin/duty", tags=["值班排班"])
|
||||
|
||||
|
||||
def _enrich_assign_names(db: Session, body: DutyDaySaveBody) -> DutyDaySaveBody:
|
||||
"""指定用户时补全 personName(用 nick_name)。"""
|
||||
for slot in body.slots:
|
||||
for item in slot.assignments or []:
|
||||
if item.source != "assign":
|
||||
continue
|
||||
uid = (item.userId or "").strip()
|
||||
if not uid:
|
||||
continue
|
||||
if (item.personName or "").strip():
|
||||
continue
|
||||
u = user_crud.get_user(db, uid)
|
||||
if u:
|
||||
item.personName = (u.nick_name or "").strip() or uid
|
||||
return body
|
||||
|
||||
|
||||
@router.get("")
|
||||
def month_summary(
|
||||
year: int = Query(..., ge=2000, le=2100),
|
||||
month: int = Query(..., ge=1, le=12),
|
||||
_user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _user.get("tenant_no", "") or ""
|
||||
data = duty_svc.get_month_summary(db, tenant_no, year, month)
|
||||
return success_response(data)
|
||||
|
||||
|
||||
@router.get("/day")
|
||||
def day_detail(
|
||||
dutyDate: str = Query(..., description="YYYY-MM-DD"),
|
||||
_user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _user.get("tenant_no", "") or ""
|
||||
try:
|
||||
d = datetime.strptime(dutyDate.strip(), "%Y-%m-%d").date()
|
||||
except ValueError:
|
||||
return error_response(400, "日期格式无效")
|
||||
return success_response(duty_svc.get_day_detail(db, tenant_no, d))
|
||||
|
||||
|
||||
@router.post("/day")
|
||||
def save_day(
|
||||
body: DutyDaySaveBody,
|
||||
_user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _user.get("tenant_no", "") or ""
|
||||
try:
|
||||
body = _enrich_assign_names(db, body)
|
||||
data = duty_svc.save_day(db, tenant_no, _user, body)
|
||||
return success_response(data, message="保存成功")
|
||||
except DutyBizError as exc:
|
||||
return error_response(400, str(exc))
|
||||
|
||||
|
||||
@router.post("/day/{day_id}/link")
|
||||
def set_link(
|
||||
day_id: str,
|
||||
body: DutyLinkBody,
|
||||
_user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _user.get("tenant_no", "") or ""
|
||||
user_id = _user.get("user_id") or _user.get("id", "")
|
||||
try:
|
||||
data = duty_svc.set_link_status(db, tenant_no, day_id, body.linkStatus, operator_id=user_id)
|
||||
return success_response(data, message="已更新链接状态")
|
||||
except DutyBizError as exc:
|
||||
return error_response(400, str(exc))
|
||||
|
||||
|
||||
@router.delete("/assignments/{assignment_id}")
|
||||
def delete_assignment(
|
||||
assignment_id: str,
|
||||
_user: dict = Depends(require_admin_or_super_admin),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
tenant_no = _user.get("tenant_no", "") or ""
|
||||
user_id = _user.get("user_id") or _user.get("id", "")
|
||||
try:
|
||||
duty_svc.soft_delete_assignment(db, tenant_no, assignment_id, operator_id=user_id)
|
||||
return success_response(None, message="已删除")
|
||||
except DutyBizError as exc:
|
||||
return error_response(400, str(exc))
|
||||
@@ -0,0 +1,37 @@
|
||||
"""值班排班 · 公开抢班 API(免登录)"""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.response import error_response, success_response
|
||||
from app.schemas.duty import DutyGrabBody
|
||||
from app.services import duty_schedule as duty_svc
|
||||
from app.services.duty_schedule import DutyBizError
|
||||
|
||||
router = APIRouter(prefix="/public/duty", tags=["值班排班-公开"])
|
||||
|
||||
|
||||
@router.get("/{token}")
|
||||
def public_page(token: str, db: Session = Depends(get_db)):
|
||||
try:
|
||||
data = duty_svc.get_public_page(db, token)
|
||||
return success_response(data)
|
||||
except DutyBizError as exc:
|
||||
msg = str(exc)
|
||||
if "无效" in msg:
|
||||
raise HTTPException(status_code=404, detail=msg)
|
||||
return error_response(400, msg)
|
||||
|
||||
|
||||
@router.post("/{token}/grab")
|
||||
def public_grab(token: str, body: DutyGrabBody, db: Session = Depends(get_db)):
|
||||
try:
|
||||
data = duty_svc.grab(db, token, body.shiftType, body.personName)
|
||||
return success_response(data, message="报名成功")
|
||||
except DutyBizError as exc:
|
||||
msg = str(exc)
|
||||
if "无效" in msg:
|
||||
raise HTTPException(status_code=404, detail=msg)
|
||||
return error_response(400, msg)
|
||||
@@ -178,7 +178,8 @@ class Settings(BaseSettings):
|
||||
"/api/public/pl/inbound,"
|
||||
"/api/public/pl/outbound,"
|
||||
"/api/public/db/inventory,"
|
||||
"/api/public/db/vehicle-plates"
|
||||
"/api/public/db/vehicle-plates,"
|
||||
"/api/public/duty"
|
||||
)
|
||||
|
||||
class Config:
|
||||
|
||||
@@ -18,6 +18,7 @@ from app.models import models # noqa: F401
|
||||
import app.models.bx_models # noqa: F401
|
||||
import app.models.db_models # noqa: F401
|
||||
import app.models.pl_models # noqa: F401
|
||||
import app.models.duty_models # noqa: F401
|
||||
from app.api import (
|
||||
public_router,
|
||||
menu_router,
|
||||
@@ -38,6 +39,8 @@ from app.api.pl.public_io_order import (
|
||||
)
|
||||
from app.api.db.public_inventory import router as public_db_inventory_router
|
||||
from app.api.db.public_vehicles import router as public_db_vehicles_router
|
||||
from app.api.duty import router as duty_router
|
||||
from app.api.public_duty import router as public_duty_router
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
@@ -161,6 +164,7 @@ app.include_router(public_pl_inbound_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(public_pl_outbound_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(public_db_inventory_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(public_db_vehicles_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(public_duty_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(menu_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(admin_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(workflow_router, prefix=settings.API_V1_PREFIX)
|
||||
@@ -169,6 +173,7 @@ app.include_router(crm_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(bx_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(db_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(pl_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(duty_router, prefix=settings.API_V1_PREFIX)
|
||||
app.include_router(monitor_router, prefix=settings.API_V1_PREFIX)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user