diff --git a/backend/scan-manager.js b/backend/scan-manager.js index 6460668..6df0292 100644 --- a/backend/scan-manager.js +++ b/backend/scan-manager.js @@ -40,6 +40,7 @@ export const scanState = { startupScanning: false, pendingDailyScan: false, // 定时扫描被并发扫描挤掉时标记,扫描结束后自动补扫 _triggerSource: 'manual', // 'startup' | 'manual' | 'daily' | 'pending' | 'lazy' + dirty: false, // 缓存失效标记:invalidateScan 时置 true,扫描完成后清零 } /** 磁盘占用(跨平台):递归统计目录内所有文件字节和 @@ -93,9 +94,10 @@ export async function runScanAsync() { scanState.bytes = p.bytes // 目录内所有文件字节和 scanState.tgzBytes = p.tgzBytes || 0 // 仅 .tgz }) -rawCacheAt = new Date().toISOString() + rawCacheAt = new Date().toISOString() scanState.done = true scanState.error = null + scanState.dirty = false // 扫描完成,清除 dirty 标记 scanState.lastErrorAt = null // 成功后清除错误状态,解除冷却 scanState.finishedAt = rawCacheAt scanState.diskBytes = await diskBytesOf(storage) // 磁盘占用(跨平台字节和) @@ -205,10 +207,12 @@ rawCacheAt = new Date().toISOString() // 扫描失败后冷却期:避免持续异常(目录权限/挂载问题)时每次请求都触发扫描 const SCAN_RETRY_COOLDOWN_MS = 5 * 60_000 // 5 分钟 -// 确保扫描已启动(缓存缺失时懒触发,不阻塞当前请求) +// 确保扫描已启动(缓存缺失或 dirty 时懒触发,不阻塞当前请求) export function ensureScan() { if (isDemoMode()) return - if (rawCache || scanState.scanning) return + if (scanState.scanning) return + // rawCache 存在但 dirty 时,也需要触发扫描重建缓存 + if (rawCache && !scanState.dirty) return // 失败冷却期内不重试,手动 POST /api/scan 不受此限制 if (scanState.lastErrorAt) { const elapsed = Date.now() - new Date(scanState.lastErrorAt).getTime() @@ -228,8 +232,8 @@ export function hasScanCache() { } export function invalidateScan() { - rawCache = null - rawCacheAt = null + // 保留 rawCache 供扫描期间使用,只标记 dirty;扫描完成后自动替换 + scanState.dirty = true packagesCache = null // 清空包列表构建缓存 clearPkgCache() // storage 目录切换 / 清理动作后废弃增量缓存,避免旧目录条目残留 } diff --git a/frontend/src/store/actions.js b/frontend/src/store/actions.js index ae27799..0420ca2 100644 --- a/frontend/src/store/actions.js +++ b/frontend/src/store/actions.js @@ -34,8 +34,8 @@ export async function unignorePkg(name, versionCount) { export async function cleanPkg(name, keep) { const res = await api.clean(name, keep) if (res.ok) { - // 删除触发 invalidateScan,下一次拉包会懒扫描重建缓存 → 静默提示并等待完成 - await Promise.all([silentRefresh({ toast: true }), refreshLogs()]) + // 不等待扫描完成,立即返回让对话框关闭;后台扫描完成后自动刷新 + silentRefresh({ toast: true }).then(() => refreshLogs()) } return res } @@ -43,7 +43,8 @@ export async function cleanPkg(name, keep) { export async function deleteVersion(name, version) { const res = await api.deleteVersion(name, version) if (res.ok) { - await Promise.all([silentRefresh({ toast: true }), refreshLogs()]) + // 不等待扫描完成,立即返回让对话框关闭;后台扫描完成后自动刷新 + silentRefresh({ toast: true }).then(() => refreshLogs()) } return res } \ No newline at end of file