duty.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """值班排班 · 管理端 API"""
  2. from __future__ import annotations
  3. from datetime import datetime
  4. from typing import Optional
  5. from fastapi import APIRouter, Depends, Query
  6. from sqlalchemy.orm import Session
  7. from app.core.database import get_db
  8. from app.core.menu_guard import require_admin_or_super_admin
  9. from app.core.response import error_response, success_response
  10. from app.crud import user as user_crud
  11. from app.schemas.duty import DutyDaySaveBody, DutyLinkBody
  12. from app.services import duty_schedule as duty_svc
  13. from app.services.duty_schedule import DutyBizError
  14. router = APIRouter(prefix="/web/admin/duty", tags=["值班排班"])
  15. def _enrich_assign_names(db: Session, body: DutyDaySaveBody) -> DutyDaySaveBody:
  16. """指定用户时补全 personName(用 nick_name)。"""
  17. for slot in body.slots:
  18. for item in slot.assignments or []:
  19. if item.source != "assign":
  20. continue
  21. uid = (item.userId or "").strip()
  22. if not uid:
  23. continue
  24. if (item.personName or "").strip():
  25. continue
  26. u = user_crud.get_user(db, uid)
  27. if u:
  28. item.personName = (u.nick_name or "").strip() or uid
  29. return body
  30. @router.get("")
  31. def month_summary(
  32. year: int = Query(..., ge=2000, le=2100),
  33. month: int = Query(..., ge=1, le=12),
  34. _user: dict = Depends(require_admin_or_super_admin),
  35. db: Session = Depends(get_db),
  36. ):
  37. tenant_no = _user.get("tenant_no", "") or ""
  38. data = duty_svc.get_month_summary(db, tenant_no, year, month)
  39. return success_response(data)
  40. @router.get("/day")
  41. def day_detail(
  42. dutyDate: str = Query(..., description="YYYY-MM-DD"),
  43. _user: dict = Depends(require_admin_or_super_admin),
  44. db: Session = Depends(get_db),
  45. ):
  46. tenant_no = _user.get("tenant_no", "") or ""
  47. try:
  48. d = datetime.strptime(dutyDate.strip(), "%Y-%m-%d").date()
  49. except ValueError:
  50. return error_response(400, "日期格式无效")
  51. return success_response(duty_svc.get_day_detail(db, tenant_no, d))
  52. @router.post("/day")
  53. def save_day(
  54. body: DutyDaySaveBody,
  55. _user: dict = Depends(require_admin_or_super_admin),
  56. db: Session = Depends(get_db),
  57. ):
  58. tenant_no = _user.get("tenant_no", "") or ""
  59. try:
  60. body = _enrich_assign_names(db, body)
  61. data = duty_svc.save_day(db, tenant_no, _user, body)
  62. return success_response(data, message="保存成功")
  63. except DutyBizError as exc:
  64. return error_response(400, str(exc))
  65. @router.post("/day/{day_id}/link")
  66. def set_link(
  67. day_id: str,
  68. body: DutyLinkBody,
  69. _user: dict = Depends(require_admin_or_super_admin),
  70. db: Session = Depends(get_db),
  71. ):
  72. tenant_no = _user.get("tenant_no", "") or ""
  73. user_id = _user.get("user_id") or _user.get("id", "")
  74. try:
  75. data = duty_svc.set_link_status(db, tenant_no, day_id, body.linkStatus, operator_id=user_id)
  76. return success_response(data, message="已更新链接状态")
  77. except DutyBizError as exc:
  78. return error_response(400, str(exc))
  79. @router.delete("/assignments/{assignment_id}")
  80. def delete_assignment(
  81. assignment_id: str,
  82. _user: dict = Depends(require_admin_or_super_admin),
  83. db: Session = Depends(get_db),
  84. ):
  85. tenant_no = _user.get("tenant_no", "") or ""
  86. user_id = _user.get("user_id") or _user.get("id", "")
  87. try:
  88. duty_svc.soft_delete_assignment(db, tenant_no, assignment_id, operator_id=user_id)
  89. return success_response(None, message="已删除")
  90. except DutyBizError as exc:
  91. return error_response(400, str(exc))