driver_plan.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. """小程序/门户登录态 · 司机运输计划单"""
  2. from __future__ import annotations
  3. from typing import Optional
  4. from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, UploadFile
  5. from sqlalchemy.orm import Session
  6. from app.core.database import get_db
  7. from app.core.db_auth import DbUserContext, get_db_current_user
  8. from app.core.response import error_response, success_response
  9. from app.core.tenant_context import get_tenant_no
  10. from app.schemas.pl.transport import (
  11. PublicTransportDriverStopFeedback,
  12. PublicTransportFeedback,
  13. )
  14. from app.services import pl_driver_plan_service as drv_svc
  15. router = APIRouter(prefix="/driver-plan", tags=["运输计划-司机计划单"])
  16. def _resolve_personnel_or_empty(db: Session, user: DbUserContext, tenant_no: str):
  17. return drv_svc.resolve_personnel_for_user(
  18. db, tenant_no=tenant_no, user_id=user.id
  19. )
  20. @router.get("/history")
  21. def get_driver_plan_history(
  22. date: str = Query(..., description="筛选日 YYYY-MM-DD"),
  23. db: Session = Depends(get_db),
  24. user: DbUserContext = Depends(get_db_current_user),
  25. ):
  26. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  27. page, err = drv_svc.build_driver_history_page(
  28. db,
  29. tenant_no=tenant_no,
  30. user_id=user.id,
  31. date_str=date,
  32. )
  33. if err:
  34. return error_response(400, err)
  35. return success_response(page.model_dump(by_alias=True))
  36. @router.get("/calendar-counts")
  37. def get_driver_plan_calendar_counts(
  38. month: str = Query(..., description="月份 YYYY-MM"),
  39. db: Session = Depends(get_db),
  40. user: DbUserContext = Depends(get_db_current_user),
  41. ):
  42. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  43. counts, err = drv_svc.build_driver_calendar_counts(
  44. db,
  45. tenant_no=tenant_no,
  46. user_id=user.id,
  47. month_str=month,
  48. )
  49. if err:
  50. return error_response(400, err)
  51. return success_response({"month": month, "counts": counts or {}})
  52. @router.get("/{plan_id}")
  53. def get_driver_plan_detail(
  54. plan_id: str,
  55. db: Session = Depends(get_db),
  56. user: DbUserContext = Depends(get_db_current_user),
  57. ):
  58. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  59. personnel = _resolve_personnel_or_empty(db, user, tenant_no)
  60. if not personnel:
  61. raise HTTPException(status_code=404, detail="未关联驾押人员,无法查看")
  62. page, err = drv_svc.build_driver_page_for_plan(
  63. db,
  64. tenant_no=tenant_no,
  65. plan_id=plan_id,
  66. personnel_id=personnel.id,
  67. )
  68. if err or page is None:
  69. raise HTTPException(status_code=404, detail=err or "计划不存在")
  70. return success_response(page.model_dump(by_alias=True))
  71. @router.post("/{plan_id}/ensure-copy-seq")
  72. def ensure_driver_plan_copy_seq(
  73. plan_id: str,
  74. db: Session = Depends(get_db),
  75. user: DbUserContext = Depends(get_db_current_user),
  76. ):
  77. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  78. personnel = _resolve_personnel_or_empty(db, user, tenant_no)
  79. if not personnel:
  80. raise HTTPException(status_code=404, detail="未关联驾押人员,无法查看")
  81. seq, err = drv_svc.ensure_copy_seq_for_driver(
  82. db,
  83. tenant_no=tenant_no,
  84. plan_id=plan_id,
  85. personnel_id=personnel.id,
  86. )
  87. if err or seq is None:
  88. raise HTTPException(status_code=404, detail=err or "计划不存在")
  89. db.commit()
  90. return success_response({"copySeqNo": seq})
  91. @router.post("/{plan_id}/feedback")
  92. def save_driver_plan_feedback(
  93. plan_id: str,
  94. payload: PublicTransportFeedback,
  95. db: Session = Depends(get_db),
  96. user: DbUserContext = Depends(get_db_current_user),
  97. ):
  98. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  99. personnel = _resolve_personnel_or_empty(db, user, tenant_no)
  100. if not personnel:
  101. return error_response(400, "未关联驾押人员,无法提交回执")
  102. ok, msg = drv_svc.save_driver_feedback_for_plan(
  103. db,
  104. tenant_no=tenant_no,
  105. plan_id=plan_id,
  106. personnel_id=personnel.id,
  107. payload=payload,
  108. )
  109. if not ok:
  110. return error_response(400, msg or "保存失败")
  111. db.commit()
  112. return success_response({"success": True, "message": "保存成功"})
  113. @router.post("/{plan_id}/driver-feedback")
  114. def save_driver_plan_stop_feedback(
  115. plan_id: str,
  116. payload: PublicTransportDriverStopFeedback,
  117. db: Session = Depends(get_db),
  118. user: DbUserContext = Depends(get_db_current_user),
  119. ):
  120. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  121. personnel = _resolve_personnel_or_empty(db, user, tenant_no)
  122. if not personnel:
  123. return error_response(400, "未关联驾押人员,无法提交回执")
  124. ok, msg = drv_svc.save_driver_stop_feedback_for_plan(
  125. db,
  126. tenant_no=tenant_no,
  127. plan_id=plan_id,
  128. personnel_id=personnel.id,
  129. payload=payload,
  130. )
  131. if not ok:
  132. return error_response(400, msg or "保存失败")
  133. db.commit()
  134. return success_response({"success": True, "message": "保存成功"})
  135. @router.post("/{plan_id}/attachments")
  136. def upload_driver_plan_attachment(
  137. plan_id: str,
  138. file: UploadFile = File(...),
  139. folder: Optional[str] = Form(""),
  140. db: Session = Depends(get_db),
  141. user: DbUserContext = Depends(get_db_current_user),
  142. ):
  143. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  144. personnel = _resolve_personnel_or_empty(db, user, tenant_no)
  145. if not personnel:
  146. return error_response(400, "未关联驾押人员,无法上传附件")
  147. data, err = drv_svc.upload_driver_attachment_for_plan(
  148. db,
  149. tenant_no=tenant_no,
  150. plan_id=plan_id,
  151. personnel_id=personnel.id,
  152. file=file,
  153. folder=folder or "",
  154. )
  155. if err:
  156. code, msg = err
  157. return error_response(code, msg)
  158. return success_response(data)