Refactor processing logic and enhance error handling
- Cleaned up code in processing.py by removing inline semicolons and improving readability. - Updated upsert_file_relation calls to ensure consistent handling of file relations. - Enhanced query_file_relations in db_schema.py to support filtering by file existence. - Improved API error handling in index.ts with user-friendly messages for 401 and 403 errors. - Added online/offline status tracking in Layout.vue. - Implemented debounced search functionality across multiple views to optimize performance. - Introduced loading skeletons in Dashboard.vue for better user experience during data fetching. - Enhanced file preview cleanup logic in Images.vue, Orders.vue, and Tables.vue to prevent memory leaks. - Updated global styles to include new loading and notification animations.
This commit is contained in:
@@ -3,6 +3,19 @@
|
||||
<!-- Top stats row -->
|
||||
<div class="stats-row animate-in">
|
||||
<div
|
||||
v-if="statsLoading"
|
||||
v-for="n in 4"
|
||||
:key="'sk'+n"
|
||||
class="stat-card"
|
||||
>
|
||||
<div class="skeleton skeleton-circle" style="width:44px;height:44px;border-radius:12px"></div>
|
||||
<div class="stat-info" style="gap:4px">
|
||||
<div class="skeleton skeleton-text" style="width:48px;height:24px"></div>
|
||||
<div class="skeleton skeleton-text short" style="width:64px;height:14px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!statsLoading"
|
||||
class="stat-card"
|
||||
v-for="stat in stats"
|
||||
:key="stat.label"
|
||||
@@ -183,6 +196,7 @@ const uploadingName = ref('')
|
||||
const processing = ref(false)
|
||||
const fileInput = ref<HTMLInputElement>()
|
||||
const logBox = ref<HTMLElement>()
|
||||
const statsLoading = ref(true)
|
||||
|
||||
const detailedStats = ref({
|
||||
input_images: 0,
|
||||
@@ -260,12 +274,6 @@ const stats = computed(() => [
|
||||
},
|
||||
])
|
||||
|
||||
function fmtSize(b: number): string {
|
||||
if (b < 1024) return b + ' B'
|
||||
if (b < 1048576) return (b / 1024).toFixed(1) + ' KB'
|
||||
return (b / 1048576).toFixed(1) + ' MB'
|
||||
}
|
||||
|
||||
function fmtTime(i: number): string {
|
||||
const d = new Date()
|
||||
d.setSeconds(d.getSeconds() - (logs.value.length - i))
|
||||
@@ -283,11 +291,14 @@ function clearLogs(): void {
|
||||
}
|
||||
|
||||
async function refreshStats(): Promise<void> {
|
||||
statsLoading.value = true
|
||||
try {
|
||||
const res = await api.get('/files/stats/detailed')
|
||||
detailedStats.value = res.data
|
||||
} catch {
|
||||
// silent
|
||||
} finally {
|
||||
statsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +339,7 @@ async function upload(files: File[]): Promise<void> {
|
||||
uploading.value = true
|
||||
uploadPct.value = 0
|
||||
const uploadedFiles: { name: string; type: string }[] = []
|
||||
const failedFiles: string[] = []
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i]
|
||||
uploadingName.value = file.name
|
||||
@@ -344,9 +356,8 @@ async function upload(files: File[]): Promise<void> {
|
||||
})
|
||||
const typeLabel = getFileTypeLabel(file.name)
|
||||
uploadedFiles.push({ name: file.name, type: typeLabel })
|
||||
ElMessage.success(`${file.name} → ${typeLabel === 'OCR' ? '全流程处理队列' : 'Excel处理队列'}`)
|
||||
} catch (err: any) {
|
||||
ElMessage.error(`上传失败: ${file.name}`)
|
||||
failedFiles.push(file.name)
|
||||
}
|
||||
}
|
||||
uploading.value = false
|
||||
@@ -354,15 +365,21 @@ async function upload(files: File[]): Promise<void> {
|
||||
uploadPct.value = 0
|
||||
refreshStats()
|
||||
|
||||
// Show upload results
|
||||
if (uploadedFiles.length > 0) {
|
||||
ElMessage.success(`${uploadedFiles.length} 个文件上传成功`)
|
||||
}
|
||||
if (failedFiles.length > 0) {
|
||||
ElMessage.error(`${failedFiles.length} 个文件上传失败: ${failedFiles.join(', ')}`)
|
||||
}
|
||||
|
||||
// Auto-process: pipeline for images, excel for Excel files
|
||||
if (uploadedFiles.length > 0) {
|
||||
const hasImages = uploadedFiles.some(f => f.type === 'OCR')
|
||||
const hasExcel = uploadedFiles.some(f => f.type === 'Excel')
|
||||
if (hasImages) {
|
||||
ElMessage.info('自动启动一键全流程...')
|
||||
await doAction('/processing/pipeline')
|
||||
} else if (hasExcel) {
|
||||
ElMessage.info('自动启动Excel处理...')
|
||||
await doAction('/processing/excel')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user