fix: 清理数据表导出临时文件
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
|
from contextlib import suppress
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from fastapi import APIRouter, Body, HTTPException
|
from fastapi import APIRouter, Body, HTTPException
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
|
from starlette.background import BackgroundTask
|
||||||
|
|
||||||
from app import state
|
from app import state
|
||||||
from app.config import CACHE_DIR
|
from app.config import CACHE_DIR
|
||||||
@@ -13,6 +16,11 @@ from app.database import DatabaseManager
|
|||||||
router = APIRouter(tags=["database"])
|
router = APIRouter(tags=["database"])
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_file(path: Path) -> None:
|
||||||
|
with suppress(OSError):
|
||||||
|
path.unlink()
|
||||||
|
|
||||||
|
|
||||||
@router.post("/api/database/test")
|
@router.post("/api/database/test")
|
||||||
async def test_database():
|
async def test_database():
|
||||||
db = DatabaseManager(state.config)
|
db = DatabaseManager(state.config)
|
||||||
@@ -161,6 +169,9 @@ async def download_table(
|
|||||||
table_name: str = Body(..., embed=True),
|
table_name: str = Body(..., embed=True),
|
||||||
file_format: str = Body("csv", alias="format"),
|
file_format: str = Body("csv", alias="format"),
|
||||||
):
|
):
|
||||||
|
if file_format not in {"csv", "xlsx"}:
|
||||||
|
raise HTTPException(status_code=400, detail="不支持的导出格式")
|
||||||
|
|
||||||
db = DatabaseManager(state.config)
|
db = DatabaseManager(state.config)
|
||||||
try:
|
try:
|
||||||
result = db.query_table(table_name, page=1, page_size=1000000)
|
result = db.query_table(table_name, page=1, page_size=1000000)
|
||||||
@@ -173,13 +184,22 @@ async def download_table(
|
|||||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
filename = f"{table_name}_{timestamp}.{file_format}"
|
filename = f"{table_name}_{timestamp}.{file_format}"
|
||||||
filepath = CACHE_DIR / filename
|
filepath = CACHE_DIR / filename
|
||||||
|
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
if file_format == "csv":
|
try:
|
||||||
df.to_csv(filepath, index=False, encoding="utf-8-sig")
|
if file_format == "csv":
|
||||||
media_type = "text/csv"
|
df.to_csv(filepath, index=False, encoding="utf-8-sig")
|
||||||
else:
|
media_type = "text/csv"
|
||||||
df.to_excel(filepath, index=False)
|
else:
|
||||||
media_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
df.to_excel(filepath, index=False)
|
||||||
|
media_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
return FileResponse(path=str(filepath), filename=filename, media_type=media_type)
|
except Exception:
|
||||||
|
_remove_file(filepath)
|
||||||
|
raise
|
||||||
|
|
||||||
|
return FileResponse(
|
||||||
|
path=str(filepath),
|
||||||
|
filename=filename,
|
||||||
|
media_type=media_type,
|
||||||
|
background=BackgroundTask(_remove_file, filepath),
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
# 项目上下文记录
|
# 项目上下文记录
|
||||||
|
|
||||||
|
## 2026-05-19:优化数据表导出临时文件清理
|
||||||
|
|
||||||
|
- `app/api/routers/database.py` 的 `/api/download` 导出接口增加格式校验,只允许 `csv` 和 `xlsx`。
|
||||||
|
- 导出文件仍临时写入 `cache/`,但 `FileResponse` 发送完成后会通过 `BackgroundTask` 自动删除;写入失败时也会清理半成品文件,避免导出残留占用服务器磁盘。
|
||||||
|
- 已清理 `cache/` 中旧的导出缓存文件 2 个,仅保留处理历史目录和 `history.json`。
|
||||||
|
- 已执行 `.venv\Scripts\python.exe -m compileall app`,编译检查通过。
|
||||||
|
|
||||||
## 2026-05-19:调整上传框操作按钮为换行显示
|
## 2026-05-19:调整上传框操作按钮为换行显示
|
||||||
|
|
||||||
- `frontend/src/components/FileWorkflow.vue` 移除上传框操作区里无效的 `<br>`,避免在 flex 布局中形成异常间距。
|
- `frontend/src/components/FileWorkflow.vue` 移除上传框操作区里无效的 `<br>`,避免在 flex 布局中形成异常间距。
|
||||||
|
|||||||
Reference in New Issue
Block a user