duty.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. from typing import Optional
  2. from datetime import date
  3. from uuid import UUID
  4. from fastapi import APIRouter, Depends, HTTPException, Query
  5. from sqlalchemy import func, select
  6. from sqlalchemy.ext.asyncio import AsyncSession
  7. from backend.app.core.dependencies import require_permissions, get_current_user
  8. from backend.app.db.session import get_db
  9. from backend.app.models import DutyItem, User
  10. from backend.app.schemas.pagination import PaginatedResponse
  11. from backend.app.schemas.duty import DutyCreate, DutyResponse, DutyUpdate
  12. router = APIRouter(prefix="/duty", tags=["duty"])
  13. def is_limited_scope(user: User) -> bool:
  14. return user.role and user.role.name not in {"管理员", "排班员"}
  15. @router.get(
  16. "",
  17. response_model=list[DutyResponse] | PaginatedResponse[DutyResponse],
  18. dependencies=[Depends(require_permissions(["duty.view"]))],
  19. )
  20. async def list_duty(
  21. db: AsyncSession = Depends(get_db),
  22. current_user: User = Depends(get_current_user),
  23. start: Optional[str] = Query(default=None),
  24. end: Optional[str] = Query(default=None),
  25. page: Optional[int] = Query(default=None, ge=1),
  26. page_size: Optional[int] = Query(default=None, ge=1, le=200, alias="pageSize"),
  27. size: Optional[int] = Query(default=None, ge=1, le=200),
  28. ):
  29. query = select(DutyItem)
  30. if is_limited_scope(current_user) and current_user.dept_id:
  31. query = query.where(DutyItem.staff_id == current_user.id)
  32. if start:
  33. query = query.where(DutyItem.date >= date.fromisoformat(start))
  34. if end:
  35. query = query.where(DutyItem.date <= date.fromisoformat(end))
  36. if page is None and page_size is None and size is None:
  37. result = await db.execute(query.order_by(DutyItem.date))
  38. return result.scalars().all()
  39. page_value = page or 1
  40. size_value = page_size or size or 10
  41. total = await db.scalar(select(func.count()).select_from(query.subquery()))
  42. result = await db.execute(
  43. query.order_by(DutyItem.date)
  44. .offset((page_value - 1) * size_value)
  45. .limit(size_value)
  46. )
  47. return {
  48. "items": result.scalars().all(),
  49. "total": total or 0,
  50. "page": page_value,
  51. "pageSize": size_value,
  52. }
  53. @router.post("", response_model=DutyResponse, dependencies=[Depends(require_permissions(["duty.create"]))])
  54. async def create_duty(
  55. payload: DutyCreate,
  56. db: AsyncSession = Depends(get_db),
  57. ):
  58. item = DutyItem(
  59. date=date.fromisoformat(payload.date),
  60. staff_id=payload.staff_id,
  61. duty_type=payload.duty_type,
  62. contact=payload.contact,
  63. note=payload.note
  64. )
  65. db.add(item)
  66. await db.commit()
  67. await db.refresh(item)
  68. return item
  69. @router.put("/{item_id}", response_model=DutyResponse, dependencies=[Depends(require_permissions(["duty.edit"]))])
  70. async def update_duty(item_id: UUID, payload: DutyUpdate, db: AsyncSession = Depends(get_db)):
  71. result = await db.execute(select(DutyItem).where(DutyItem.id == item_id))
  72. item = result.scalar_one_or_none()
  73. if not item:
  74. raise HTTPException(status_code=404, detail="值班不存在")
  75. update_data = payload.model_dump(exclude_unset=True)
  76. if "date" in update_data and update_data["date"]:
  77. update_data["date"] = date.fromisoformat(update_data["date"])
  78. for key, value in update_data.items():
  79. setattr(item, key, value)
  80. await db.commit()
  81. await db.refresh(item)
  82. return item
  83. @router.delete("/{item_id}", dependencies=[Depends(require_permissions(["duty.delete"]))])
  84. async def delete_duty(item_id: UUID, db: AsyncSession = Depends(get_db)):
  85. result = await db.execute(select(DutyItem).where(DutyItem.id == item_id))
  86. item = result.scalar_one_or_none()
  87. if not item:
  88. raise HTTPException(status_code=404, detail="值班不存在")
  89. await db.delete(item)
  90. await db.commit()
  91. return {"success": True}