fix: FilesView merge logic and computed property

Bug: When regFiles API fails, all files get 'unregistered' status even if
they are actually registered. Also, computed property was using reference
to files.value instead of a copy, which could cause mutation issues.

Fix:
- Fetch scan results FIRST (source of truth for files on disk)
- Use scan API's is_registered field as fallback status
- Only override with regFiles data if file exists in scan results
- Computed property now uses [...files.value] to create a copy
- Skip files from regFiles that don't exist on disk (deleted)
This commit is contained in:
Accusys
2026-07-04 23:42:42 +08:00
parent 53f28ac458
commit 5fcd5212d5
+36 -23
View File
@@ -220,7 +220,8 @@ function getMediaType(fileName: string): 'video' | 'photo' {
}
const displayFiles = computed(() => {
let result = files.value
// Start with a copy to avoid mutation issues
let result = [...files.value]
// Filter by media type
if (mediaType.value !== 'all') {
@@ -263,7 +264,20 @@ async function fetchFiles() {
try {
const config = getCurrentConfig()
// Get registered files with real processing status FIRST
// Get scan results FIRST (source of truth for files on disk)
const scanResp = await httpFetch<any>(`${config.api_base_url}/api/v1/files/scan`)
const scanFiles: any[] = (scanResp?.files || []).map((f: any) => {
const mediaType = getMediaType(f.file_name)
return {
...f,
media_type: mediaType,
is_indexed: false,
// Use scan API's is_registered field as default status
status: f.is_registered ? 'pending' : 'unregistered'
}
})
// Get registered files with real processing status
let regFiles: any[] = []
try {
const regResp = await httpFetch<any>(`${config.api_base_url}/api/v1/files?page=1&page_size=200`)
@@ -277,38 +291,37 @@ async function fetchFiles() {
}
})
} catch {
// Registered files API may not be available
// Registered files API may not be available; scan data will be used as fallback
console.warn('Failed to fetch registered files, using scan data as fallback')
}
// Get scan results
const scanResp = await httpFetch<any>(`${config.api_base_url}/api/v1/files/scan`)
const scanFiles: any[] = (scanResp?.files || []).map((f: any) => {
const mediaType = getMediaType(f.file_name)
return {
...f,
media_type: mediaType,
is_indexed: false
}
})
// Build a set of registered file paths for quick lookup
const registeredPaths = new Set(regFiles.map(f => f.file_path))
// Build a map of registered files by file_path for quick lookup
const regMap = new Map<string, any>()
for (const f of regFiles) {
regMap.set(f.file_path, f)
}
// Merge: start with scan results, override with registered data where available
const merged = new Map<string, any>()
// First pass: add all scan results
for (const f of scanFiles) {
const isRegistered = registeredPaths.has(f.file_path)
merged.set(f.file_path, {
...f,
status: isRegistered ? 'pending' : 'unregistered'
})
merged.set(f.file_path, { ...f })
}
// Second pass: override with real registered data
// Second pass: override with real registered data (only for files that exist in scan)
for (const f of regFiles) {
merged.set(f.file_path, f)
if (merged.has(f.file_path)) {
// File exists on disk, update with real status
const existing = merged.get(f.file_path)
merged.set(f.file_path, {
...existing,
...f,
media_type: f.media_type || existing.media_type,
is_indexed: f.is_indexed || existing.is_indexed
})
}
// If file not in scan, it might have been deleted from disk - skip it
}
files.value = Array.from(merged.values())