feat: 支持知识库 CSV 大文件导入
- 增加 CSV 流式解析、表格语义分块和分页预览 - 增加快照两阶段清理、失败重试和格式校验 - 补充批量入口、管理端交互和回归测试
This commit is contained in:
@@ -49,6 +49,8 @@ interface PreviewItem {
|
||||
chunks?: ChunkItem[];
|
||||
fileName: string;
|
||||
normalizedContent?: string;
|
||||
pageNo?: number;
|
||||
pageSize?: number;
|
||||
previewSessionId: string;
|
||||
strategyCode?: string;
|
||||
strategyLabel?: string;
|
||||
@@ -97,6 +99,7 @@ const activeDocumentId = ref(props.documentId || '');
|
||||
const previewError = ref('');
|
||||
const previewLoading = ref(false);
|
||||
const startLoading = ref(false);
|
||||
const previewPageSize = 20;
|
||||
let previewDebounceTimer: null | ReturnType<typeof setTimeout> = null;
|
||||
let previewSequence = 0;
|
||||
|
||||
@@ -137,7 +140,9 @@ const fileExt = computed(
|
||||
|
||||
const isPptx = computed(() => fileExt.value === 'pptx');
|
||||
const isXlsx = computed(() => fileExt.value === 'xlsx');
|
||||
const showStrategySelector = computed(() => !isPptx.value && !isXlsx.value);
|
||||
const isCsv = computed(() => fileExt.value === 'csv');
|
||||
const isTabular = computed(() => isXlsx.value || isCsv.value);
|
||||
const showStrategySelector = computed(() => !isPptx.value && !isTabular.value);
|
||||
|
||||
const mdLevels = [1, 2, 3, 4, 5, 6];
|
||||
|
||||
@@ -169,10 +174,10 @@ const buildStrategyConfig = () => {
|
||||
strategyCode: 'OFFICE_PPTX_PAGE',
|
||||
};
|
||||
}
|
||||
if (isXlsx.value) {
|
||||
if (isTabular.value) {
|
||||
return {
|
||||
rowsPerChunk: formState.rowsPerChunk,
|
||||
strategyCode: 'OFFICE_XLSX_ROW_WINDOW',
|
||||
strategyCode: isCsv.value ? 'TABLE_ROW' : 'OFFICE_XLSX_ROW_WINDOW',
|
||||
};
|
||||
}
|
||||
return {
|
||||
@@ -233,6 +238,8 @@ const generatePreview = async () => {
|
||||
},
|
||||
],
|
||||
knowledgeId: props.knowledgeId,
|
||||
pageNo: 1,
|
||||
pageSize: previewPageSize,
|
||||
},
|
||||
);
|
||||
if (requestSequence !== previewSequence) {
|
||||
@@ -261,6 +268,52 @@ const generatePreview = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const loadPreviewPage = async (pageNo: number) => {
|
||||
if (
|
||||
!activeDocumentId.value ||
|
||||
!currentPreviewSessionId.value ||
|
||||
previewLoading.value
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const requestSequence = ++previewSequence;
|
||||
previewLoading.value = true;
|
||||
previewError.value = '';
|
||||
try {
|
||||
const res = await props.requestClient.post(
|
||||
buildKnowledgePath(
|
||||
props.endpointPrefix,
|
||||
'/api/v1/document/import/task/preview',
|
||||
),
|
||||
{
|
||||
documentId: activeDocumentId.value,
|
||||
knowledgeId: props.knowledgeId,
|
||||
pageNo,
|
||||
pageSize: previewPageSize,
|
||||
previewSessionId: currentPreviewSessionId.value,
|
||||
},
|
||||
);
|
||||
if (requestSequence !== previewSequence) {
|
||||
return;
|
||||
}
|
||||
previewItems.value = normalizePreviewItems(
|
||||
(res.data?.items || []) as PreviewItem[],
|
||||
);
|
||||
} catch (error: any) {
|
||||
if (requestSequence !== previewSequence) {
|
||||
return;
|
||||
}
|
||||
const message =
|
||||
error?.message || $t('documentCollection.importDoc.previewRequestFailed');
|
||||
previewError.value = message;
|
||||
ElMessage.error(message);
|
||||
} finally {
|
||||
if (requestSequence === previewSequence) {
|
||||
previewLoading.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const schedulePreviewGeneration = () => {
|
||||
if (!activeDocumentId.value) {
|
||||
return;
|
||||
@@ -321,8 +374,10 @@ watch(
|
||||
if (isPptx.value) {
|
||||
formState.strategyCode = 'OFFICE_PPTX_PAGE';
|
||||
}
|
||||
if (isXlsx.value) {
|
||||
formState.strategyCode = 'OFFICE_XLSX_ROW_WINDOW';
|
||||
if (isTabular.value) {
|
||||
formState.strategyCode = isCsv.value
|
||||
? 'TABLE_ROW'
|
||||
: 'OFFICE_XLSX_ROW_WINDOW';
|
||||
formState.rowsPerChunk = 10;
|
||||
}
|
||||
resetPreviewState();
|
||||
@@ -365,7 +420,7 @@ watch(
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem
|
||||
v-if="isXlsx"
|
||||
v-if="isTabular"
|
||||
label="每多少行分一块"
|
||||
class="workbench__form-full"
|
||||
>
|
||||
@@ -450,6 +505,7 @@ watch(
|
||||
<SplitterDocPreview
|
||||
:loading="previewLoading"
|
||||
:preview-items="previewItems"
|
||||
@page-change="loadPreviewPage"
|
||||
@preview-session-change="handlePreviewSessionChange"
|
||||
/>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user