|
|
@@ -1,11 +1,20 @@
|
|
|
"""运输计划管理 - 基础数据 API(承运商、车辆、人员)"""
|
|
|
from datetime import datetime
|
|
|
-from typing import Optional
|
|
|
+from typing import List, Optional
|
|
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
|
|
+from pydantic import BaseModel, Field
|
|
|
from sqlalchemy import case, func, or_
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
+from app.utils.excel_export import (
|
|
|
+ EXPORT_MAX_ROWS,
|
|
|
+ ExportColumn,
|
|
|
+ ExportValidationError,
|
|
|
+ export_rows_to_xlsx_response,
|
|
|
+ filter_export_columns,
|
|
|
+)
|
|
|
+
|
|
|
from app.core.database import get_db
|
|
|
from app.core.db_auth import DbUserContext, get_db_current_user
|
|
|
from app.core.delete_guard import assert_row_deletable_by_creator, user_info_from_context
|
|
|
@@ -114,6 +123,101 @@ def list_carriers(
|
|
|
)
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+CARRIER_EXPORT_COLUMNS = [
|
|
|
+ ExportColumn(title="承运商名称", field="carrierName"),
|
|
|
+ ExportColumn(title="联系人", field="contactName"),
|
|
|
+ ExportColumn(title="联系电话", field="contactPhone"),
|
|
|
+ ExportColumn(title="合作状态", field="statusLabel"),
|
|
|
+ ExportColumn(title="资质提示", field="qualificationHint"),
|
|
|
+ ExportColumn(title="协议有效期", field="transportAgreementExpireDate"),
|
|
|
+ ExportColumn(title="备注", field="remark"),
|
|
|
+]
|
|
|
+
|
|
|
+
|
|
|
+class CarrierExportBody(BaseModel):
|
|
|
+ q: Optional[str] = None
|
|
|
+ status: Optional[str] = None
|
|
|
+ audit_status: Optional[str] = Field(default=None, alias="auditStatus")
|
|
|
+ ids: Optional[List[str]] = None
|
|
|
+ columns: Optional[List[str]] = None
|
|
|
+
|
|
|
+ model_config = {"populate_by_name": True}
|
|
|
+
|
|
|
+
|
|
|
+@router.post("/carrier/export")
|
|
|
+def export_carriers(
|
|
|
+ body: CarrierExportBody,
|
|
|
+ db: Session = Depends(get_db),
|
|
|
+ user: DbUserContext = Depends(get_db_current_user),
|
|
|
+):
|
|
|
+ """导出承运商列表(当前筛选全量,或 ids 已选)。"""
|
|
|
+ try:
|
|
|
+ tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
|
+ query = db.query(PlCarrier).filter(
|
|
|
+ PlCarrier.tenant_no == tenant_no,
|
|
|
+ PlCarrier.del_flag == 0,
|
|
|
+ )
|
|
|
+ if body.status:
|
|
|
+ query = query.filter(PlCarrier.status == body.status)
|
|
|
+ if body.audit_status:
|
|
|
+ query = query.filter(PlCarrier.audit_status == body.audit_status)
|
|
|
+ if body.q:
|
|
|
+ query = query.filter(
|
|
|
+ or_(
|
|
|
+ func.lower(PlCarrier.carrier_name).contains(body.q.lower()),
|
|
|
+ func.lower(PlCarrier.contact_name).contains(body.q.lower()),
|
|
|
+ )
|
|
|
+ )
|
|
|
+ if body.ids:
|
|
|
+ query = query.filter(PlCarrier.id.in_(body.ids))
|
|
|
+ query = query.order_by(
|
|
|
+ case((PlCarrier.order_num.is_(None), 1), else_=0).asc(),
|
|
|
+ PlCarrier.create_time.desc(),
|
|
|
+ )
|
|
|
+ rows = query.limit(EXPORT_MAX_ROWS + 1).all()
|
|
|
+ items = []
|
|
|
+ for row in rows:
|
|
|
+ data = carrier_to_read(row).model_dump(by_alias=True)
|
|
|
+ data["statusLabel"] = "合作中" if str(data.get("status")) == "1" else "已终止"
|
|
|
+ if data.get("transportAgreementExpired"):
|
|
|
+ data["qualificationHint"] = "协议已过期"
|
|
|
+ elif data.get("qualificationComplete") is False:
|
|
|
+ data["qualificationHint"] = "资质不全"
|
|
|
+ else:
|
|
|
+ data["qualificationHint"] = "资质齐全"
|
|
|
+ items.append(data)
|
|
|
+ requested = None
|
|
|
+ if body.columns:
|
|
|
+ requested = []
|
|
|
+ for key in body.columns:
|
|
|
+ if key in (
|
|
|
+ "qualificationAttachments",
|
|
|
+ "qualificationAttachment",
|
|
|
+ "photoUrls",
|
|
|
+ ):
|
|
|
+ continue
|
|
|
+ if key == "status":
|
|
|
+ requested.append("statusLabel")
|
|
|
+ elif key == "qualificationHint":
|
|
|
+ requested.append("qualificationHint")
|
|
|
+ else:
|
|
|
+ requested.append(key)
|
|
|
+ cols = filter_export_columns(CARRIER_EXPORT_COLUMNS, requested)
|
|
|
+ date_str = datetime.now().strftime("%Y%m%d")
|
|
|
+ return export_rows_to_xlsx_response(
|
|
|
+ db,
|
|
|
+ tenant_no=tenant_no,
|
|
|
+ sheet_title="承运商列表",
|
|
|
+ columns=cols,
|
|
|
+ rows=items,
|
|
|
+ filename_stem=f"承运商列表_{date_str}",
|
|
|
+ )
|
|
|
+ except ExportValidationError as e:
|
|
|
+ raise HTTPException(status_code=400, detail=str(e)) from e
|
|
|
+
|
|
|
+
|
|
|
@router.post("/carrier", response_model=CarrierRead, status_code=status.HTTP_201_CREATED)
|
|
|
def create_carrier(
|
|
|
payload: CarrierCreate,
|