Просмотр исходного кода

feat(pl): wire archive_zip export format on plan export API.

Reuse archive row building and attach document plus hazard-cert files into a zip response.

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 1 месяц назад
Родитель
Сommit
d5c2e1f1a4
1 измененных файлов с 44 добавлено и 3 удалено
  1. 44 3
      backend/app/api/pl/plan.py

+ 44 - 3
backend/app/api/pl/plan.py

@@ -727,7 +727,11 @@ class PlanExportBody(BaseModel):
     hazard_cert_ready: Optional[int] = Field(default=None, alias="hazardCertReady")
     ids: Optional[List[str]] = None
     columns: Optional[List[str]] = None
-    export_format: Optional[str] = Field(default=None, alias="exportFormat", description="archive=运输计划归档专用导出")
+    export_format: Optional[str] = Field(
+        default=None,
+        alias="exportFormat",
+        description="archive=运输计划归档 Excel;archive_zip=归档数据及附件 ZIP",
+    )
 
     model_config = {"populate_by_name": True, "extra": "allow"}
 
@@ -779,8 +783,14 @@ def export_plans(
             .all()
         )
         date_str = datetime.now().strftime("%Y%m%d")
-        is_archive_export = (body.export_format or "").strip().lower() == "archive"
-        if is_archive_export:
+        export_format = (body.export_format or "").strip().lower()
+        is_archive_export = export_format == "archive"
+        is_archive_zip = export_format == "archive_zip"
+        if len(plans) > EXPORT_MAX_ROWS:
+            raise ExportValidationError(f"导出超过 {EXPORT_MAX_ROWS} 条,请缩小筛选范围")
+        if is_archive_export or is_archive_zip:
+            if not plans:
+                raise ExportValidationError("没有可导出的数据")
             transport_ids = [plan.transport_id for plan in plans if plan.transport_id]
             transports_by_id = _load_transports_by_id(db, tenant_no, transport_ids)
             items = build_plan_archive_export_rows(
@@ -799,6 +809,37 @@ def export_plans(
             cols = filter_export_columns(PLAN_ARCHIVE_EXPORT_COLUMNS, body.columns)
             if not user_can_view_archive_prices(db, user):
                 cols = [c for c in cols if c.field not in ARCHIVE_PRICE_EXPORT_FIELDS]
+            if is_archive_zip:
+                from app.services.pl_plan_archive_zip_export import (
+                    build_archive_zip_streaming_response,
+                    collect_hazard_cert_items,
+                    load_plan_products_by_plan_ids,
+                    merge_plan_attachment_items,
+                )
+
+                plan_ids = [p.id for p in plans]
+                docs = load_plan_document_attachments_by_plan_ids(
+                    db, tenant_no=tenant_no, plan_ids=plan_ids
+                )
+                products_by_plan = load_plan_products_by_plan_ids(
+                    db, tenant_no=tenant_no, plan_ids=plan_ids
+                )
+                attachments_by_plan = {
+                    pid: merge_plan_attachment_items(
+                        docs.get(pid, []),
+                        collect_hazard_cert_items(products_by_plan.get(pid, [])),
+                    )
+                    for pid in plan_ids
+                }
+                stamp = datetime.now().strftime("%Y%m%d%H%M")
+                return build_archive_zip_streaming_response(
+                    db=db,
+                    tenant_no=tenant_no,
+                    columns=cols,
+                    rows=items,
+                    attachments_by_plan=attachments_by_plan,
+                    stamp=stamp,
+                )
             sheet_title = "计划归档"
             filename_stem = f"计划归档_{date_str}"
         else: