fix: 修正自动导入完成提示

- 根据关联文档真实状态识别已完成的历史失败批次

- 完成后自动移除提示并低频复查失败或中断批次
This commit is contained in:
2026-08-26 18:58:42 +08:00
parent 1ccdafdb47
commit ec6e03587a
5 changed files with 248 additions and 18 deletions

View File

@@ -51,7 +51,7 @@ describe('documentImportBatchStatus', () => {
wrapper.unmount();
});
it('当前页面跟踪的批次完成后继续展示结果', async () => {
it('当前页面跟踪的批次完成后移除提示', async () => {
vi.useFakeTimers();
apiMocks.get
.mockResolvedValueOnce({
@@ -73,10 +73,62 @@ describe('documentImportBatchStatus', () => {
await vi.advanceTimersByTimeAsync(3000);
await flushPromises();
expect(wrapper.find('.batch-status').exists()).toBe(false);
wrapper.unmount();
});
it('失败批次关联任务实际完成后不再展示提示', async () => {
apiMocks.get.mockResolvedValue({
data: {
...createBatch('RUNNING', 0),
actualCompleted: true,
failedCount: 2,
pendingCount: 0,
status: 'PARTIAL_SUCCEEDED',
},
errorCode: 0,
});
const wrapper = mount(DocumentImportBatchStatus, {
props: { knowledgeId: 'knowledge-1' },
});
await flushPromises();
expect(wrapper.find('.batch-status').exists()).toBe(false);
wrapper.unmount();
});
it('失败批次低频复查后在关联任务完成时移除提示', async () => {
vi.useFakeTimers();
const failedBatch = {
...createBatch('RUNNING', 0),
actualCompleted: false,
failedCount: 2,
pendingCount: 0,
status: 'PARTIAL_SUCCEEDED',
};
apiMocks.get
.mockResolvedValueOnce({
data: failedBatch,
errorCode: 0,
})
.mockResolvedValueOnce({
data: { ...failedBatch, actualCompleted: true },
errorCode: 0,
});
const wrapper = mount(DocumentImportBatchStatus, {
props: { knowledgeId: 'knowledge-1' },
});
await flushPromises();
expect(wrapper.find('.batch-status').exists()).toBe(true);
expect(wrapper.text()).toContain(
'documentCollection.importDoc.batchCompleted',
);
await vi.advanceTimersByTimeAsync(15_000);
await flushPromises();
expect(apiMocks.get).toHaveBeenCalledTimes(2);
expect(wrapper.find('.batch-status').exists()).toBe(false);
wrapper.unmount();
});
@@ -239,9 +291,7 @@ describe('documentImportBatchStatus', () => {
expect(apiMocks.get).toHaveBeenCalledTimes(3);
expect(wrapper.find('.batch-status__load-error').exists()).toBe(false);
expect(wrapper.text()).toContain(
'documentCollection.importDoc.batchCompleted',
);
expect(wrapper.find('.batch-status').exists()).toBe(false);
wrapper.unmount();
});
});

View File

@@ -8,6 +8,7 @@ import { ElAlert, ElButton, ElProgress } from 'element-plus';
import { api } from '#/api/request';
interface BatchStatus {
actualCompleted?: boolean;
batchId: string;
cancelledCount?: number;
completedCount: number;
@@ -53,6 +54,7 @@ let pollTimer: null | ReturnType<typeof setTimeout> = null;
let disposed = false;
let refreshGeneration = 0;
let pollDelayMs = 3000;
const TERMINAL_RECHECK_DELAY_MS = 15_000;
const canContinue = computed(
() =>
@@ -122,7 +124,7 @@ const interruptMetadata = computed(() => {
return details.join(' · ');
});
async function refresh(hideCompletedOnRestore = false) {
async function refresh() {
if (!props.knowledgeId) return;
const currentGeneration = ++refreshGeneration;
refreshing.value = true;
@@ -142,10 +144,9 @@ async function refresh(hideCompletedOnRestore = false) {
loadError.value = '';
pollDelayMs = 3000;
const restoredBatch = response.data || undefined;
batch.value =
hideCompletedOnRestore && restoredBatch?.status === 'COMPLETED'
? undefined
: restoredBatch;
const completed =
restoredBatch?.status === 'COMPLETED' || restoredBatch?.actualCompleted;
batch.value = completed ? undefined : restoredBatch;
} catch {
if (!disposed && currentGeneration === refreshGeneration) {
loadError.value = $t(
@@ -175,13 +176,16 @@ function schedulePoll() {
if (
!batch.value ||
batch.value.status === 'COMPLETED' ||
batch.value.status === 'PARTIAL_SUCCEEDED' ||
batch.value.status === 'INTERRUPTED' ||
batch.value.status === 'CANCELLED'
) {
return;
}
pollTimer = setTimeout(refresh, 3000);
const delay =
batch.value.status === 'PARTIAL_SUCCEEDED' ||
batch.value.status === 'INTERRUPTED'
? TERMINAL_RECHECK_DELAY_MS
: 3000;
pollTimer = setTimeout(refresh, delay);
}
async function continueBatch() {
@@ -204,7 +208,7 @@ async function continueBatch() {
onMounted(() => {
disposed = false;
refresh(true);
refresh();
});
onBeforeUnmount(() => {
@@ -222,7 +226,7 @@ watch(
loadError.value = '';
pollDelayMs = 3000;
}
refresh(knowledgeChanged);
refresh();
},
);
</script>