feat: 支持知识库导入 PPTX 与 XLSX 文档

- 打通 Office 文档桥接解析、解析进度承接与图片引用改写

- 落地 PPTX 按页分块、XLSX 行窗口分块以及预览与检索渲染闭环
This commit is contained in:
2026-04-18 13:01:17 +08:00
parent ad67ba85ad
commit 4130381658
28 changed files with 2876 additions and 120 deletions

View File

@@ -40,6 +40,8 @@ interface DocumentStatusPayload {
failedChunks?: number;
knowledgeId?: number | string;
lastTaskError?: string;
parseCurrentStage?: string;
parseStatusMessage?: string;
processStatus?: string;
progressPercent?: number;
taskModifiedAt?: string;
@@ -154,11 +156,24 @@ const statusMetaMap: Record<
},
};
const defaultStatusMeta: {
icon: Component;
toneClass: string;
} = statusMetaMap.UPLOADED!;
const getStatusLabel = (status?: string) =>
$t(`documentCollection.taskStatus.${status || 'UPLOADED'}`);
const getStatusMeta = (status?: string) =>
statusMetaMap[status || 'UPLOADED'] || statusMetaMap.UPLOADED;
const getStatusMeta = (
status?: string,
): {
icon: Component;
toneClass: string;
} => statusMetaMap[status || 'UPLOADED'] ?? defaultStatusMeta;
const getStatusToneClass = (status?: string) => getStatusMeta(status).toneClass;
const getStatusIcon = (status?: string) => getStatusMeta(status).icon;
const getChunkCount = (row: any) => {
const totalChunks = Number(row.totalChunks || 0);
@@ -171,12 +186,28 @@ const getChunkCount = (row: any) => {
const getProgressText = (row: any) => {
const completed = Number(row.completedChunks || 0);
const total = Number(row.totalChunks || 0);
if (row.processStatus === 'PARSING') {
return `${Number(row.progressPercent || 0)}%`;
}
if (total <= 0) {
return `${Number(row.progressPercent || 0)}%`;
}
return `${Number(row.progressPercent || 0)}% · ${completed}/${total}`;
};
const parseStageLabels: Record<string, string> = {
assembling: '汇总中',
extracting: '提取中',
ocr: 'OCR 中',
preparing: '准备中',
queued: '排队中',
};
const getProcessingHint = (row: any) =>
row.parseStatusMessage ||
parseStageLabels[row.parseCurrentStage || ''] ||
'';
const clearReconnectTimer = () => {
if (!reconnectTimer) {
return;
@@ -211,6 +242,8 @@ const patchDocumentRow = (payload: DocumentStatusPayload) => {
completedChunks: payload.completedChunks,
failedChunks: payload.failedChunks,
lastTaskError: payload.lastTaskError,
parseCurrentStage: payload.parseCurrentStage,
parseStatusMessage: payload.parseStatusMessage,
processStatus: payload.processStatus,
progressPercent: payload.progressPercent,
taskModifiedAt: payload.taskModifiedAt,
@@ -529,7 +562,7 @@ watch(
<div class="status-cell">
<div
class="status-pill"
:class="getStatusMeta(row.processStatus).toneClass"
:class="getStatusToneClass(row.processStatus)"
>
<span class="status-pill__icon-shell">
<ElIcon
@@ -540,7 +573,7 @@ watch(
: ''
"
>
<component :is="getStatusMeta(row.processStatus).icon" />
<component :is="getStatusIcon(row.processStatus)" />
</ElIcon>
</span>
<span class="status-pill__label">
@@ -548,7 +581,10 @@ watch(
</span>
</div>
<div
v-if="row.processStatus === 'INDEXING'"
v-if="
row.processStatus === 'INDEXING' ||
row.processStatus === 'PARSING'
"
class="status-progress"
>
<ElProgress
@@ -558,6 +594,12 @@ watch(
<span class="status-progress__text">
{{ getProgressText(row) }}
</span>
<span
v-if="row.processStatus === 'PARSING' && getProcessingHint(row)"
class="status-progress__hint"
>
{{ getProcessingHint(row) }}
</span>
</div>
<div
v-else-if="row.lastTaskError"
@@ -663,6 +705,12 @@ watch(
text-align: left;
}
.status-progress__hint {
font-size: 12px;
color: var(--el-text-color-secondary);
text-align: left;
}
.status-error {
max-width: 176px;
font-size: 12px;