瀏覽代碼

feat(pl): add JWT driver-plan routes for miniprogram

Expose history/detail/feedback/attachments under /transport/driver-plan
and exclude the path from API encryption middleware.

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 1 月之前
父節點
當前提交
57ca252f81
共有 3 個文件被更改,包括 156 次插入 和 1 次删除
  1. 16 1
      backend/app/api/pl/__init__.py
  2. 138 0
      backend/app/api/pl/driver_plan.py
  3. 2 0
      backend/app/core/config.py

+ 16 - 1
backend/app/api/pl/__init__.py

@@ -2,9 +2,18 @@
 from fastapi import APIRouter
 
 from app.api.pl import plan, transport, freight, inventory, menu_badges, ocr
-from app.api.pl import base_data, vehicle_recharge, vehicle_maintenance, vehicle_urea, transport_address
+from app.api.pl import (
+    base_data,
+    vehicle_fuel,
+    vehicle_recharge,
+    vehicle_maintenance,
+    vehicle_urea,
+    transport_address,
+)
 from app.api.pl import customer_stop_pref
 from app.api.pl import io_order
+from app.api.pl import site_plan
+from app.api.pl import driver_plan
 
 pl_router = APIRouter(prefix="/transport", tags=["运输计划管理"])
 
@@ -30,6 +39,10 @@ pl_router.include_router(io_order.outbound_router)
 # 运输管理
 pl_router.include_router(transport.router)
 
+# 现场计划单(登录态)
+pl_router.include_router(site_plan.router)
+pl_router.include_router(driver_plan.router)
+
 # 运费结算
 pl_router.include_router(freight.router)
 
@@ -43,6 +56,8 @@ pl_router.include_router(menu_badges.router)
 pl_router.include_router(vehicle_recharge.apply_router)
 pl_router.include_router(vehicle_recharge.record_router)
 
+pl_router.include_router(vehicle_fuel.router)
+
 # 车辆维保
 pl_router.include_router(vehicle_maintenance.apply_router)
 pl_router.include_router(vehicle_maintenance.process_router)

+ 138 - 0
backend/app/api/pl/driver_plan.py

@@ -0,0 +1,138 @@
+"""小程序/门户登录态 · 司机运输计划单"""
+from __future__ import annotations
+
+from typing import Optional
+
+from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, UploadFile
+from sqlalchemy.orm import Session
+
+from app.core.database import get_db
+from app.core.db_auth import DbUserContext, get_db_current_user
+from app.core.response import error_response, success_response
+from app.core.tenant_context import get_tenant_no
+from app.schemas.pl.transport import (
+    PublicTransportDriverStopFeedback,
+    PublicTransportFeedback,
+)
+from app.services import pl_driver_plan_service as drv_svc
+
+router = APIRouter(prefix="/driver-plan", tags=["运输计划-司机计划单"])
+
+
+def _resolve_personnel_or_empty(db: Session, user: DbUserContext, tenant_no: str):
+    return drv_svc.resolve_personnel_for_user(
+        db, tenant_no=tenant_no, user_id=user.id
+    )
+
+
+@router.get("/history")
+def get_driver_plan_history(
+    date: str = Query(..., description="筛选日 YYYY-MM-DD"),
+    db: Session = Depends(get_db),
+    user: DbUserContext = Depends(get_db_current_user),
+):
+    tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
+    page, err = drv_svc.build_driver_history_page(
+        db,
+        tenant_no=tenant_no,
+        user_id=user.id,
+        date_str=date,
+    )
+    if err:
+        return error_response(400, err)
+    return success_response(page.model_dump(by_alias=True))
+
+
+@router.get("/{plan_id}")
+def get_driver_plan_detail(
+    plan_id: str,
+    db: Session = Depends(get_db),
+    user: DbUserContext = Depends(get_db_current_user),
+):
+    tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
+    personnel = _resolve_personnel_or_empty(db, user, tenant_no)
+    if not personnel:
+        raise HTTPException(status_code=404, detail="未关联驾押人员,无法查看")
+    page, err = drv_svc.build_driver_page_for_plan(
+        db,
+        tenant_no=tenant_no,
+        plan_id=plan_id,
+        personnel_id=personnel.id,
+    )
+    if err or page is None:
+        raise HTTPException(status_code=404, detail=err or "计划不存在")
+    return success_response(page.model_dump(by_alias=True))
+
+
+@router.post("/{plan_id}/feedback")
+def save_driver_plan_feedback(
+    plan_id: str,
+    payload: PublicTransportFeedback,
+    db: Session = Depends(get_db),
+    user: DbUserContext = Depends(get_db_current_user),
+):
+    tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
+    personnel = _resolve_personnel_or_empty(db, user, tenant_no)
+    if not personnel:
+        return error_response(400, "未关联驾押人员,无法提交回执")
+    ok, msg = drv_svc.save_driver_feedback_for_plan(
+        db,
+        tenant_no=tenant_no,
+        plan_id=plan_id,
+        personnel_id=personnel.id,
+        payload=payload,
+    )
+    if not ok:
+        return error_response(400, msg or "保存失败")
+    db.commit()
+    return success_response({"success": True, "message": "保存成功"})
+
+
+@router.post("/{plan_id}/driver-feedback")
+def save_driver_plan_stop_feedback(
+    plan_id: str,
+    payload: PublicTransportDriverStopFeedback,
+    db: Session = Depends(get_db),
+    user: DbUserContext = Depends(get_db_current_user),
+):
+    tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
+    personnel = _resolve_personnel_or_empty(db, user, tenant_no)
+    if not personnel:
+        return error_response(400, "未关联驾押人员,无法提交回执")
+    ok, msg = drv_svc.save_driver_stop_feedback_for_plan(
+        db,
+        tenant_no=tenant_no,
+        plan_id=plan_id,
+        personnel_id=personnel.id,
+        payload=payload,
+    )
+    if not ok:
+        return error_response(400, msg or "保存失败")
+    db.commit()
+    return success_response({"success": True, "message": "保存成功"})
+
+
+@router.post("/{plan_id}/attachments")
+def upload_driver_plan_attachment(
+    plan_id: str,
+    file: UploadFile = File(...),
+    folder: Optional[str] = Form(""),
+    db: Session = Depends(get_db),
+    user: DbUserContext = Depends(get_db_current_user),
+):
+    tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
+    personnel = _resolve_personnel_or_empty(db, user, tenant_no)
+    if not personnel:
+        return error_response(400, "未关联驾押人员,无法上传附件")
+    data, err = drv_svc.upload_driver_attachment_for_plan(
+        db,
+        tenant_no=tenant_no,
+        plan_id=plan_id,
+        personnel_id=personnel.id,
+        file=file,
+        folder=folder or "",
+    )
+    if err:
+        code, msg = err
+        return error_response(code, msg)
+    return success_response(data)

+ 2 - 0
backend/app/core/config.py

@@ -178,6 +178,8 @@ class Settings(BaseSettings):
         "/api/public/pl/site,"
         "/api/public/pl/inbound,"
         "/api/public/pl/outbound,"
+        "/api/transport/site-plan,"
+        "/api/transport/driver-plan,"
         "/api/public/db/inventory,"
         "/api/public/db/vehicle-plates,"
         "/api/public/duty"