export_records.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. """export_records.py — 导出记录管理路由及管理端存储查询。"""
  2. import math
  3. from pathlib import Path
  4. from fastapi import APIRouter
  5. from fastapi.responses import FileResponse
  6. from app.api.v1 import ok
  7. from app.core.database import AsyncSessionLocal
  8. from app.core.exceptions import RecordNotFoundError
  9. from app.schemas.export import ExportRecordSchema
  10. from app.services.export_record_service import ExportRecordService
  11. from app.services.storage_monitor import get_storage_info
  12. router = APIRouter(tags=["Export Records"])
  13. # ------------------------------------------------------------------ #
  14. # GET /export/records — 分页查询导出记录
  15. # ------------------------------------------------------------------ #
  16. @router.get("/export/records", summary="获取导出记录列表")
  17. async def list_export_records(
  18. userId: str,
  19. page: int = 1,
  20. pageSize: int = 20,
  21. sortOrder: str = "desc",
  22. ) -> dict:
  23. page = max(1, page)
  24. page_size = min(max(1, pageSize), 100)
  25. async with AsyncSessionLocal() as db:
  26. svc = ExportRecordService(db)
  27. records, total = await svc.list_records(
  28. user_id=userId,
  29. page=page,
  30. page_size=page_size,
  31. sort_order=sortOrder,
  32. )
  33. total_pages = math.ceil(total / page_size) if total > 0 else 1
  34. return ok(
  35. {
  36. "records": [
  37. ExportRecordSchema.from_record(r).model_dump(by_alias=True)
  38. for r in records
  39. ],
  40. "pagination": {
  41. "page": page,
  42. "pageSize": page_size,
  43. "total": total,
  44. "totalPages": total_pages,
  45. },
  46. }
  47. )
  48. # ------------------------------------------------------------------ #
  49. # GET /export/records/{recordId}/download — 重新下载文件
  50. # ------------------------------------------------------------------ #
  51. @router.get("/export/records/{recordId}/download", summary="重新下载导出文件")
  52. async def download_export_record(recordId: str, userId: str) -> FileResponse:
  53. async with AsyncSessionLocal() as db:
  54. svc = ExportRecordService(db)
  55. record = await svc.get_record(recordId, userId)
  56. file_path = Path(record.file_path)
  57. if not file_path.exists():
  58. raise RecordNotFoundError(recordId)
  59. return FileResponse(
  60. path=str(file_path),
  61. filename=record.file_name,
  62. media_type="application/msword",
  63. )
  64. # ------------------------------------------------------------------ #
  65. # DELETE /export/records/{recordId} — 删除记录(同步删文件)
  66. # ------------------------------------------------------------------ #
  67. @router.delete("/export/records/{recordId}", summary="删除导出记录")
  68. async def delete_export_record(recordId: str, userId: str) -> dict:
  69. async with AsyncSessionLocal() as db:
  70. svc = ExportRecordService(db)
  71. await svc.delete_record(recordId, userId)
  72. return {"code": 0, "message": "Record deleted successfully"}
  73. # ------------------------------------------------------------------ #
  74. # GET /admin/storage — 管理端存储查询
  75. # ------------------------------------------------------------------ #
  76. @router.get("/admin/storage", summary="管理端:存储使用情况")
  77. async def admin_storage() -> dict:
  78. info = get_storage_info()
  79. return ok(
  80. {
  81. "diskTotalBytes": info["disk_total_bytes"],
  82. "diskUsedBytes": info["disk_used_bytes"],
  83. "tmpTotalBytes": info["tmp_total_bytes"],
  84. "quotaBytes": info["quota_bytes"],
  85. "quotaExceeded": info["quota_exceeded"],
  86. "activeUsers": info["active_users"],
  87. "perUserQuotaBytes": info["per_user_quota_bytes"],
  88. "users": [
  89. {
  90. "userId": u["user_id"],
  91. "usedBytes": u["used_bytes"],
  92. "quotaExceeded": u["quota_exceeded"],
  93. }
  94. for u in info["users"]
  95. ],
  96. }
  97. )