From 37b2837baad7a03f09dd3a5dedd0d121a0670c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=A4=E5=AD=A6=E4=BC=9A?= Date: Fri, 10 Jul 2026 10:12:03 +0800 Subject: [PATCH] fix qrcode zip downloads --- app/routers/devices.py | 21 +++++++++++++++++++++ app/services/qrcode_batch_tasks.py | 21 ++++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/app/routers/devices.py b/app/routers/devices.py index 3799ec1..ac6e12a 100644 --- a/app/routers/devices.py +++ b/app/routers/devices.py @@ -7,6 +7,7 @@ from pathlib import Path from urllib.parse import quote, unquote, urlparse from fastapi import APIRouter, Depends, HTTPException, Query, Request +from fastapi.responses import FileResponse from sqlalchemy import select from sqlalchemy.orm import Session @@ -28,6 +29,7 @@ from app.services.qrcode_batch_tasks import ( QRCODE_TASK_STATUS_RUNNING, create_qrcode_batch_task, qrcode_batch_task_out, + qrcode_batch_zip_path, ) from app.services.wechat import WechatConfigError, create_device_qrcode @@ -373,6 +375,25 @@ def _get_own_batch_task(db: Session, user: Personnel, task_id: int) -> DeviceQrB return task +@router.get("/molds/qrcode/batch/tasks/{task_id}/download") +def download_mold_process_qrcode_batch_task( + task_id: int, + user: Personnel = Depends(require_roles(Role.admin)), + db: Session = Depends(get_db), +) -> FileResponse: + task = _get_own_batch_task(db, user, task_id) + if task.status != QRCODE_TASK_STATUS_COMPLETED: + raise HTTPException(status_code=409, detail="二维码ZIP任务还未完成") + file_path = qrcode_batch_zip_path(task) + if not file_path.is_file(): + raise HTTPException(status_code=404, detail="ZIP文件不存在或已过期,请重新生成") + return FileResponse( + path=file_path, + media_type="application/zip", + filename=task.file_name, + ) + + @router.post("/molds/qrcode/batch/tasks/{task_id}/stop", response_model=DeviceQrBatchTaskOut) def stop_mold_process_qrcode_batch_task( task_id: int, diff --git a/app/services/qrcode_batch_tasks.py b/app/services/qrcode_batch_tasks.py index 4709ace..eee4e3f 100644 --- a/app/services/qrcode_batch_tasks.py +++ b/app/services/qrcode_batch_tasks.py @@ -87,6 +87,21 @@ def _public_base_url() -> str: return settings.public_base_url.rstrip("/") or "http://127.0.0.1:8000" +def qrcode_batch_zip_path(task: DeviceQrBatchTask) -> Path: + return settings.upload_path / "qrcode_zips" / task.file_name + + +def qrcode_batch_zip_exists(task: DeviceQrBatchTask) -> bool: + return bool(task.file_name and qrcode_batch_zip_path(task).is_file()) + + +def _task_download_url(task: DeviceQrBatchTask, public_base_url: str) -> str: + return ( + f"{public_base_url.rstrip('/')}/api/devices/molds/qrcode/batch/tasks/" + f"{task.id}/download" + ) + + def _task_file_name(items: list[dict]) -> str: fingerprint = hashlib.sha1( "|".join( @@ -153,9 +168,9 @@ def qrcode_batch_task_out(task: DeviceQrBatchTask, public_base_url: str | None = progress_percent = 0.0 else: progress_percent = round(min(100, completed_count / item_count * 100), 1) - zip_url = task.zip_url - if public_base_url and task.file_name: - zip_url = f"{public_base_url.rstrip('/')}/uploads/qrcode_zips/{quote(task.file_name, safe='')}" + zip_url = None + if task.status == QRCODE_TASK_STATUS_COMPLETED and qrcode_batch_zip_exists(task): + zip_url = _task_download_url(task, public_base_url) if public_base_url else task.zip_url return DeviceQrBatchTaskOut( id=task.id, file_name=task.file_name,