feat: 文件浏览页支持多选、批量下载/删除与分页

- 后端:
  - UploadService.delete_file 下沉删除逻辑(DB 行 + 磁盘文件),单删/批删复用。
  - POST /api/admin/files/batch-delete:批量硬删除,返回 deleted 数与 not_found 列表。
  - list 接口加 Query 约束(limit 1-10000、offset>=0),非法返回 422。
- 前端(file_browser):
  - 复选框列 + 全选/反选,选中行高亮,批量操作栏(已选计数/下载/删除/取消)。
  - 分页控件:每页 20/50/100/全部 切换,页码导航(首页/末页/当前±1/省略号)。
  - 批量下载逐个触发(间隔 150ms 防浏览器拦截);批量删除走 batch-delete 接口。
  - 删除后重载当前页,当前页空则回退一页。
This commit is contained in:
zikai
2026-07-21 14:37:13 +00:00
parent fffba79022
commit 41580a9025
5 changed files with 292 additions and 45 deletions

View File

@@ -92,6 +92,24 @@ class UploadService:
path = (self.upload_root / row.storage_path).resolve()
return out, path
def delete_file(self, file_id: int) -> bool:
"""硬删除:删磁盘文件 + 删 DB 行。磁盘缺失不阻断 DB 清理。返回是否命中。
供单删/批删复用,保证删除语义一致。
"""
_, path = self.get_out_with_disk_path(file_id)
row = self.dao.get_by_id(file_id)
if row is None:
return False
if path is not None:
try:
Path(path).unlink(missing_ok=True)
except Exception:
# 即使磁盘删除失败也继续清 DB 行,保证列表不再显示
pass
self.dao.delete(file_id)
return True
# ---------------- 共享 helper供本类与 ChunkUploadService 复用) ----------------
@staticmethod