"""export_records.py — 导出记录管理路由及管理端存储查询。""" import math from fastapi import APIRouter from fastapi.responses import FileResponse from app.core.database import AsyncSessionLocal from app.core.exceptions import RecordNotFoundError from app.services.export_record_service import ExportRecordService from app.services.storage_monitor import get_storage_info router = APIRouter(tags=["Export Records"]) def _ok(data: dict) -> dict: return {"code": 0, "data": data} # ------------------------------------------------------------------ # # GET /export/records — 分页查询导出记录 # ------------------------------------------------------------------ # @router.get("/export/records", summary="获取导出记录列表") async def list_export_records( userId: str, page: int = 1, pageSize: int = 20, sortOrder: str = "desc", ) -> dict: page = max(1, page) page_size = min(max(1, pageSize), 100) async with AsyncSessionLocal() as db: svc = ExportRecordService(db) records, total = await svc.list_records( user_id=userId, page=page, page_size=page_size, sort_order=sortOrder, ) total_pages = math.ceil(total / page_size) if total > 0 else 1 return _ok( { "records": [ { "recordId": r.id, "userId": r.user_id, "fileName": r.file_name, "fileSize": r.file_size, "downloadUrl": r.download_url, "documentId": r.document_id, "styleId": r.style_id, "createdAt": int(r.created_at.timestamp() * 1000), } for r in records ], "pagination": { "page": page, "pageSize": page_size, "total": total, "totalPages": total_pages, }, } ) # ------------------------------------------------------------------ # # GET /export/records/{recordId}/download — 重新下载文件 # ------------------------------------------------------------------ # @router.get("/export/records/{recordId}/download", summary="重新下载导出文件") async def download_export_record(recordId: str, userId: str) -> FileResponse: from pathlib import Path async with AsyncSessionLocal() as db: svc = ExportRecordService(db) record = await svc.get_record(recordId, userId) file_path = Path(record.file_path) if not file_path.exists(): raise RecordNotFoundError(recordId) return FileResponse( path=str(file_path), filename=record.file_name, media_type="application/msword", ) # ------------------------------------------------------------------ # # DELETE /export/records/{recordId} — 删除记录(同步删文件) # ------------------------------------------------------------------ # @router.delete("/export/records/{recordId}", summary="删除导出记录") async def delete_export_record(recordId: str, userId: str) -> dict: async with AsyncSessionLocal() as db: svc = ExportRecordService(db) await svc.delete_record(recordId, userId) return {"code": 0, "message": "Record deleted successfully"} # ------------------------------------------------------------------ # # GET /admin/storage — 管理端存储查询 # ------------------------------------------------------------------ # @router.get("/admin/storage", summary="管理端:存储使用情况") async def admin_storage() -> dict: info = get_storage_info() return _ok( { "diskTotalBytes": info["disk_total_bytes"], "diskUsedBytes": info["disk_used_bytes"], "tmpTotalBytes": info["tmp_total_bytes"], "quotaBytes": info["quota_bytes"], "quotaExceeded": info["quota_exceeded"], "activeUsers": info["active_users"], "perUserQuotaBytes": info["per_user_quota_bytes"], "users": [ { "userId": u["user_id"], "usedBytes": u["used_bytes"], "quotaExceeded": u["quota_exceeded"], } for u in info["users"] ], } )