Files
EasyFlow/easyflow-ui-admin/app/src/views/ai/documentCollection/ImportKnowledgeDocFile.vue
陈子默 7e7c236c2a fix: 修复管理端前端 lint 与构建问题
- 收敛 easyflow-ui-admin 的 lint、格式和类型问题

- 修正 demo 页面与管理端前端构建失败点

- 验证 pnpm lint 与 pnpm build 均已通过
2026-04-05 21:39:13 +08:00

261 lines
6.3 KiB
Vue

<script setup lang="ts">
import { computed, ref } from 'vue';
import { useRoute } from 'vue-router';
import { $t } from '@easyflow/locales';
import { Back } from '@element-plus/icons-vue';
import { ElButton, ElMessage, ElStep, ElSteps } from 'element-plus';
import { api } from '#/api/request';
import ComfirmImportDocument from '#/views/ai/documentCollection/ComfirmImportDocument.vue';
import ImportKnowledgeFileContainer from '#/views/ai/documentCollection/ImportKnowledgeFileContainer.vue';
import SegmenterDoc from '#/views/ai/documentCollection/SegmenterDoc.vue';
import SplitterDocPreview from '#/views/ai/documentCollection/SplitterDocPreview.vue';
interface UploadFileItem {
fileName: string;
filePath: string;
}
interface AnalyzeItem {
fileName: string;
filePath: string;
strategyConfig: Record<string, any>;
}
interface PreviewItem {
fileName: string;
previewSessionId: string;
totalChunks?: number;
}
const emits = defineEmits(['importBack']);
const route = useRoute();
const knowledgeId = computed(() => (route.query.id as string) || '');
const fileUploadRef = ref<InstanceType<typeof ImportKnowledgeFileContainer>>();
const segmenterDocRef = ref<InstanceType<typeof SegmenterDoc>>();
const activeStep = ref(0);
const files = ref<UploadFileItem[]>([]);
const analysisItems = ref<AnalyzeItem[]>([]);
const previewItems = ref<PreviewItem[]>([]);
const commitResults = ref<any[]>([]);
const analyzing = ref(false);
const previewing = ref(false);
const committing = ref(false);
const canGoPrevious = computed(() => activeStep.value > 0 && !committing.value);
function back() {
emits('importBack');
}
function getUploadedFiles() {
return fileUploadRef.value?.getFilesData?.() || [];
}
async function goToNextStep() {
if (activeStep.value === 0) {
const currentFiles = getUploadedFiles();
if (currentFiles.length === 0) {
ElMessage.error($t('message.uploadFileFirst'));
return;
}
files.value = currentFiles;
await runAnalyze();
activeStep.value = 1;
return;
}
if (activeStep.value === 1) {
await runPreview();
activeStep.value = 2;
return;
}
if (activeStep.value === 2) {
activeStep.value = 3;
}
}
function goToPreviousStep() {
if (!canGoPrevious.value) {
return;
}
activeStep.value -= 1;
}
async function runAnalyze() {
analyzing.value = true;
try {
const res = await api.post('/api/v1/document/import/analyze', {
files: files.value.map((item) => ({
fileName: item.fileName,
filePath: item.filePath,
})),
knowledgeId: knowledgeId.value,
});
analysisItems.value = res.data?.items || [];
} finally {
analyzing.value = false;
}
}
async function runPreview() {
const previewRequestItems =
segmenterDocRef.value?.getPreviewRequestItems?.() || [];
if (previewRequestItems.length === 0) {
ElMessage.error($t('documentCollection.importDoc.previewEmpty'));
return;
}
previewing.value = true;
try {
const res = await api.post('/api/v1/document/import/preview', {
files: previewRequestItems,
knowledgeId: knowledgeId.value,
});
previewItems.value = res.data?.items || [];
commitResults.value = [];
} finally {
previewing.value = false;
}
}
async function confirmImport() {
if (previewItems.value.length === 0) {
ElMessage.error($t('documentCollection.importDoc.previewEmpty'));
return;
}
committing.value = true;
try {
const res = await api.post('/api/v1/document/import/commit', {
knowledgeId: knowledgeId.value,
previewSessionIds: previewItems.value.map(
(item) => item.previewSessionId,
),
});
commitResults.value = res.data?.results || [];
if ((res.data?.errorCount || 0) === 0) {
ElMessage.success($t('documentCollection.splitterDoc.importSuccess'));
}
} finally {
committing.value = false;
}
}
</script>
<template>
<div class="imp-doc-kno-container">
<div class="imp-doc-header">
<ElButton :icon="Back" @click="back">
{{ $t('button.back') }}
</ElButton>
</div>
<div class="imp-doc-kno-content">
<div class="step-card">
<ElSteps :active="activeStep" align-center>
<ElStep :title="$t('documentCollection.importDoc.fileUpload')" />
<ElStep
:title="$t('documentCollection.importDoc.strategyAnalysis')"
/>
<ElStep
:title="$t('documentCollection.importDoc.segmentedPreview')"
/>
<ElStep :title="$t('documentCollection.importDoc.confirmImport')" />
</ElSteps>
</div>
<div class="step-body">
<ImportKnowledgeFileContainer
v-if="activeStep === 0"
ref="fileUploadRef"
/>
<SegmenterDoc
v-else-if="activeStep === 1"
ref="segmenterDocRef"
:analysis-items="analysisItems"
/>
<SplitterDocPreview
v-else-if="activeStep === 2"
:preview-items="previewItems"
/>
<ComfirmImportDocument
v-else
:preview-items="previewItems"
:commit-results="commitResults"
:loading="committing"
/>
</div>
</div>
<div class="imp-doc-footer">
<ElButton v-if="canGoPrevious" @click="goToPreviousStep">
{{ $t('button.previousStep') }}
</ElButton>
<ElButton
v-if="activeStep < 3"
type="primary"
:loading="analyzing || previewing"
@click="goToNextStep"
>
{{ $t('button.nextStep') }}
</ElButton>
<ElButton
v-else
type="primary"
:loading="committing"
:disabled="committing"
@click="confirmImport"
>
{{ $t('button.startImport') }}
</ElButton>
</div>
</div>
</template>
<style scoped>
.imp-doc-kno-container {
position: relative;
display: flex;
flex-direction: column;
height: 100%;
padding: 24px;
background: var(--el-bg-color);
border-radius: 16px;
}
.imp-doc-kno-content {
display: flex;
flex: 1;
flex-direction: column;
gap: 20px;
padding-top: 16px;
overflow: auto;
}
.step-card {
padding: 20px 24px;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-light);
border-radius: 16px;
}
.step-body {
flex: 1;
padding-bottom: 72px;
}
.imp-doc-footer {
position: absolute;
right: 24px;
bottom: 24px;
display: flex;
gap: 12px;
align-items: center;
}
</style>