Browse Source

feat(pl): add public driver transport history API

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 2 tháng trước cách đây
mục cha
commit
c51345eec5
1 tập tin đã thay đổi với 96 bổ sung và 1 xóa
  1. 96 1
      backend/app/api/pl/public_transport.py

+ 96 - 1
backend/app/api/pl/public_transport.py

@@ -6,7 +6,8 @@ import os
 from datetime import date, datetime
 from typing import Optional
 
-from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
+from fastapi import APIRouter, Depends, File, Form, HTTPException, Query, UploadFile
+from sqlalchemy import and_, func, or_
 from sqlalchemy.orm import Session
 
 from app.core.storage import storage
@@ -28,6 +29,8 @@ from app.schemas.pl.io_order import BrandOption, BrandQtyItem
 from app.schemas.pl.resource_snapshot import parse_resource_snapshot
 from app.schemas.pl.transport import (
     PublicTransportFeedback,
+    PublicTransportHistoryPageRead,
+    PublicTransportHistoryRecordRead,
     PublicTransportPageRead,
     PublicTransportPersonnelRead,
     PublicTransportPlanProductRead,
@@ -123,6 +126,11 @@ def _history_status_label(plan_voided: bool, plan_archived: bool) -> str:
     return "进行中"
 
 
+def _build_driver_url(token: str) -> str:
+    origin = (settings.PUBLIC_WEB_ORIGIN or "").rstrip("/")
+    return f"{origin}/#/public/pl/transport/{token}"
+
+
 def _resolve_driver_link_flags(
     plan: Optional[PlPlan], transport: PlTransport
 ) -> tuple[bool, bool]:
@@ -327,6 +335,93 @@ def get_public_transport(token: str, db: Session = Depends(get_db)):
     return success_response(page.model_dump(by_alias=True))
 
 
+@router.get("/{token}/history")
+def get_public_transport_history(
+    token: str,
+    date: str = Query(..., description="筛选日 YYYY-MM-DD"),
+    db: Session = Depends(get_db),
+):
+    transport = _get_transport_by_token(db, token)
+    day = _parse_history_date(date)
+    if day is None:
+        return error_response(400, "日期格式无效,请使用 YYYY-MM-DD")
+
+    plate = _normalize_main_plate(transport.license_plate)
+    if not plate:
+        page = PublicTransportHistoryPageRead(
+            license_plate=None, date=day.isoformat(), records=[]
+        )
+        return success_response(page.model_dump(by_alias=True))
+
+    rows = (
+        db.query(PlPlan, PlTransport)
+        .join(
+            PlPlanTransport,
+            and_(
+                PlPlanTransport.plan_id == PlPlan.id,
+                PlPlanTransport.del_flag == 0,
+            ),
+        )
+        .join(
+            PlTransport,
+            and_(
+                PlTransport.id == PlPlanTransport.transport_id,
+                PlTransport.del_flag == 0,
+            ),
+        )
+        .filter(
+            PlPlan.tenant_no == transport.tenant_no,
+            PlPlan.del_flag == 0,
+            PlPlan.transport_status == "arranged",
+            PlTransport.tenant_no == transport.tenant_no,
+            PlTransport.license_plate == plate,
+            or_(
+                and_(PlPlan.pickup_time.isnot(None), func.date(PlPlan.pickup_time) == day),
+                and_(PlPlan.delivery_time.isnot(None), func.date(PlPlan.delivery_time) == day),
+            ),
+        )
+        .order_by(
+            PlPlan.pickup_time.desc(),
+            PlPlan.plan_date.desc(),
+            PlPlan.create_time.desc(),
+        )
+        .all()
+    )
+
+    seen_plan: set[str] = set()
+    records: list[PublicTransportHistoryRecordRead] = []
+    for plan, tr in rows:
+        if plan.id in seen_plan:
+            continue
+        seen_plan.add(plan.id)
+        voided, archived = _resolve_driver_link_flags(plan, tr)
+        tok = (tr.driver_access_token or "").strip()
+        records.append(
+            PublicTransportHistoryRecordRead(
+                plan_id=plan.id,
+                plan_no=plan.plan_no or "",
+                transport_id=tr.id,
+                driver_access_token=tok or None,
+                driver_url=_build_driver_url(tok) if tok else None,
+                license_plate=tr.license_plate or plate,
+                pickup_time=plan.pickup_time,
+                delivery_time=plan.delivery_time,
+                pickup_address=plan.pickup_address,
+                destination_address=plan.destination_address or plan.destination_name,
+                plan_voided=voided,
+                plan_archived=archived,
+                status_label=_history_status_label(voided, archived),
+            )
+        )
+
+    page = PublicTransportHistoryPageRead(
+        license_plate=plate,
+        date=day.isoformat(),
+        records=records,
+    )
+    return success_response(page.model_dump(by_alias=True))
+
+
 @router.post("/{token}/feedback")
 def save_public_feedback(
     token: str,