feat: SFTP 上传的文件经磁盘扫描补录后可在文件浏览页展示

SFTP 上传的文件直接落盘到 upload_root(chroot 根),不经 HTTP 路径,无 DB 记录,
文件浏览页(读 uploaded_file 表)看不到。新增磁盘扫描机制:

- UploadService.scan_sftp_files(force=False):遍历 uploads/ 下所有文件(排除 .work/
  与 .part 残品),与 DB 已有 storage_path 比对,磁盘有 DB 无的补录(source="sftp",
  流式算 size + sha256)。
- 频率限制:模块级 _last_scan_time,两次扫描间隔 < 3s 则跳过返回 0(只读 DB 缓存),
  force=True 强制扫。
- file_admin_controller 的 list 接口返回前触发 scan_sftp_files(),文件浏览页打开/
  刷新即自动同步 SFTP 文件(受 3s 频率限制,不会每次翻页都扫磁盘)。
- UploadedFileDAO 加 list_storage_paths() 批量查已记录路径集合供比对。

SFTP 文件补录后可正常下载/删除(与 HTTP 上传文件一致)。
This commit is contained in:
zikai
2026-07-22 01:25:41 +00:00
parent 30a263ed50
commit 09705a8843
3 changed files with 79 additions and 1 deletions

View File

@@ -29,6 +29,11 @@ class UploadedFileDAO:
"""返回数据库中文件总条数。"""
return self.db.scalar(select(func.count()).select_from(UploadedFile)) or 0
def list_storage_paths(self) -> set[str]:
"""返回所有已记录的 storage_path 集合(供磁盘扫描比对,识别未入库文件)。"""
stmt = select(UploadedFile.storage_path)
return {row for row in self.db.scalars(stmt).all()}
def list(self, limit: int = 100, offset: int = 0) -> list[UploadedFile]:
stmt = (
select(UploadedFile)