|
|
@@ -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,
|