fix(wiki): fix progress display and reprocess feedback issues

Three root causes for broken progress:

1. JobStageBar was shown whenever a job record existed (even at queued
   stage), hiding the working SSE-driven progress bar. Fix: only show
   JobStageBar when job.stage !== queued.

2. SSE connection only opened when hasProcessing was true (status ===
   processing), but reprocess sets status to pending first. Fix:
   include pending in the hasProcessing check.

3. After reprocess, if processing finished before SSE connected, the
   status badge stayed on pending forever. Fix: immediately set local
   status to processing after reprocess API call, clear stale job
   entries, and add delayed re-fetches (5s/15s) as safety net.

Also: clear rawJobs entries on raw.completed/raw.failed SSE events to
prevent stale JobStageBar from lingering after processing ends.
This commit is contained in:
matevip 2026-04-19 19:35:30 +08:00
parent 6c15622b59
commit d9dfd602f9

View File

@ -91,9 +91,9 @@
</button>
</div>
</div>
<!-- RFC-033: Job stage bar (when job data available) -->
<!-- RFC-033: Job stage bar only show when job has progressed past 'queued' -->
<JobStageBar
v-if="rawJobs[raw.id]"
v-if="rawJobs[raw.id] && rawJobs[raw.id].stage !== 'queued'"
:stage="rawJobs[raw.id].stage"
:status="rawJobs[raw.id].status"
:current-model="rawJobs[raw.id].currentModelName ?? (rawJobs[raw.id].currentModelId ? `Model #${rawJobs[raw.id].currentModelId}` : undefined)"
@ -106,7 +106,7 @@
@reprocess="reprocess(raw.id)"
@repair="handleLocalRepair(raw.id)"
/>
<!-- Fallback: legacy progress bar when no job data -->
<!-- Original progress bar: shown during processing when job data is not active -->
<div v-else-if="raw.processingStatus === 'processing'" class="raw-progress">
<div class="raw-progress-track">
<div
@ -178,7 +178,7 @@ let fallbackTimer: number | null = null
let activeKbId: number | null = null
const hasProcessing = computed(() =>
store.rawMaterials.some(r => r.processingStatus === 'processing')
store.rawMaterials.some(r => r.processingStatus === 'processing' || r.processingStatus === 'pending')
)
function applyProgressEvent(payload: any) {
@ -224,7 +224,8 @@ function openSse(kbId: number) {
raw.progressTotal = data.totalPages
}
}
// list pageCount
// Clear stale job entry so JobStageBar hides
delete rawJobs[data.rawId]
if (store.currentKB) store.fetchRawMaterials(store.currentKB.id)
} catch { /* ignore */ }
})
@ -233,6 +234,8 @@ function openSse(kbId: number) {
const data = JSON.parse(ev.data)
const raw = store.rawMaterials.find(r => r.id === data.rawId)
if (raw) raw.processingStatus = 'failed'
// Clear stale job entry
delete rawJobs[data.rawId]
if (store.currentKB) store.fetchRawMaterials(store.currentKB.id)
} catch { /* ignore */ }
})
@ -350,8 +353,21 @@ async function handleAddText() {
async function reprocess(rawId: number) {
if (!store.currentKB) return
await wikiApi.reprocessRaw(store.currentKB.id, rawId)
await store.fetchRawMaterials(store.currentKB.id)
const kbId = store.currentKB.id
await wikiApi.reprocessRaw(kbId, rawId)
// Immediately mark local state as processing so SSE connects and progress bar shows
const raw = store.rawMaterials.find(r => r.id === rawId)
if (raw) {
raw.processingStatus = 'processing'
raw.progressDone = 0
raw.progressTotal = 0
}
// Clear stale job entry
delete rawJobs[rawId]
await store.fetchRawMaterials(kbId)
// Delayed re-fetch to catch final status if processing finishes before SSE connects
setTimeout(() => { store.fetchRawMaterials(kbId) }, 5000)
setTimeout(() => { store.fetchRawMaterials(kbId) }, 15000)
}
async function deleteRaw(rawId: number) {
@ -362,8 +378,14 @@ async function deleteRaw(rawId: number) {
async function processAll() {
if (!store.currentKB) return
await wikiApi.processKB(store.currentKB.id)
await store.fetchRawMaterials(store.currentKB.id)
const kbId = store.currentKB.id
await wikiApi.processKB(kbId)
// Mark all pending materials as processing so SSE connects
store.rawMaterials
.filter(r => r.processingStatus === 'pending')
.forEach(r => { r.processingStatus = 'processing'; r.progressDone = 0; r.progressTotal = 0 })
await store.fetchRawMaterials(kbId)
setTimeout(() => { store.fetchRawMaterials(kbId) }, 5000)
}
async function handleScanDir() {