Files
EasyFlow/easyflow-ui-admin/app/src/views/ai/documentCollection/KnowledgeShareConfigPanel.vue
陈子默 2689adfa40 feat: 重构知识库文档导入任务化流程
- 新增上传建单、异步解析、分块处理与异步向量化闭环

- 收口分享页权限、完成态检索过滤与 SSE 局部状态刷新
2026-04-15 19:27:22 +08:00

252 lines
5.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import { $t } from '@easyflow/locales';
import {
ElButton,
ElCard,
ElForm,
ElFormItem,
ElInputNumber,
ElMessage,
ElOption,
ElSelect,
ElSwitch,
} from 'element-plus';
import { api } from '#/api/request';
import { buildKnowledgePath } from '#/views/ai/documentCollection/share-path';
const props = defineProps({
knowledgeId: {
type: String,
required: true,
},
detailData: {
type: Object as any,
default: () => ({}),
},
requestClient: {
type: Object as any,
default: () => api,
},
endpointPrefix: {
type: String,
default: '',
},
manageable: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['reload']);
const form = ref<any>({
knowledgeId: '',
vectorEmbedModelId: '',
rerankModelId: '',
rerankEnable: false,
docRecallMaxNum: 5,
simThreshold: 0.6,
rebuildVectors: false,
});
const embeddingModels = ref<any[]>([]);
const rerankModels = ref<any[]>([]);
const saving = ref(false);
const syncForm = () => {
const options = props.detailData?.options || {};
form.value = {
knowledgeId: props.knowledgeId,
vectorEmbedModelId: props.detailData?.vectorEmbedModelId || '',
rerankModelId: props.detailData?.rerankModelId || '',
rerankEnable:
options?.rerankEnable === undefined
? !!props.detailData?.rerankModelId
: !!options.rerankEnable,
docRecallMaxNum: Number(options?.docRecallMaxNum || 5),
simThreshold: Number(options?.simThreshold || 0.6),
rebuildVectors: false,
};
};
watch(
() => [props.detailData, props.knowledgeId],
() => {
syncForm();
},
{ immediate: true, deep: true },
);
const loadModels = async () => {
const [embeddingRes, rerankRes] = await Promise.all([
props.requestClient.get(
buildKnowledgePath(
props.endpointPrefix,
'/api/v1/documentCollection/modelList',
),
{ params: { modelType: 'embeddingModel' } },
),
props.requestClient.get(
buildKnowledgePath(
props.endpointPrefix,
'/api/v1/documentCollection/modelList',
),
{ params: { modelType: 'rerankModel' } },
),
]);
embeddingModels.value = embeddingRes?.data || [];
rerankModels.value = rerankRes?.data || [];
};
const handleSave = async () => {
saving.value = true;
try {
const res = await props.requestClient.post(
buildKnowledgePath(
props.endpointPrefix,
'/api/v1/documentCollection/shareConfigUpdate',
),
form.value,
);
if (res.errorCode === 0) {
ElMessage.success($t('message.saveOkMessage'));
emit('reload');
}
} finally {
saving.value = false;
}
};
onMounted(() => {
loadModels();
});
</script>
<template>
<ElCard shadow="never" class="share-config-card">
<template #header>
<div class="share-config-card__header">
<div>
<div class="share-config-card__title">受限配置</div>
<div class="share-config-card__desc">
仅开放模型切换检索参数与向量重建
</div>
<div v-if="!props.manageable" class="share-config-card__tip">
当前分享仅支持查看不允许修改配置
</div>
</div>
<ElButton
v-if="props.manageable"
type="primary"
:loading="saving"
@click="handleSave"
>
{{ $t('button.save') }}
</ElButton>
</div>
</template>
<ElForm label-position="top" class="share-config-form">
<ElFormItem :label="$t('documentCollection.vectorEmbedLlmId')">
<ElSelect v-model="form.vectorEmbedModelId" :disabled="!props.manageable">
<ElOption
v-for="item in embeddingModels"
:key="item.id"
:label="item.title"
:value="item.id"
/>
</ElSelect>
</ElFormItem>
<ElFormItem :label="$t('documentCollection.rerankLlmId')">
<ElSelect v-model="form.rerankModelId" clearable :disabled="!props.manageable">
<ElOption
v-for="item in rerankModels"
:key="item.id"
:label="item.title"
:value="item.id"
/>
</ElSelect>
</ElFormItem>
<ElFormItem :label="$t('documentCollection.rerankEnable')">
<ElSwitch v-model="form.rerankEnable" :disabled="!props.manageable" />
</ElFormItem>
<ElFormItem :label="$t('documentCollectionSearch.docRecallMaxNum.label')">
<ElInputNumber
v-model="form.docRecallMaxNum"
:min="1"
:max="50"
:disabled="!props.manageable"
/>
</ElFormItem>
<ElFormItem :label="$t('documentCollectionSearch.simThreshold.label')">
<ElInputNumber
v-model="form.simThreshold"
:min="0"
:max="1"
:step="0.01"
:disabled="!props.manageable"
/>
</ElFormItem>
<ElFormItem label="保存后重建向量">
<ElSwitch v-model="form.rebuildVectors" :disabled="!props.manageable" />
</ElFormItem>
</ElForm>
</ElCard>
</template>
<style scoped>
.share-config-card {
border-radius: 16px;
}
.share-config-card__header {
display: flex;
gap: 16px;
align-items: center;
justify-content: space-between;
}
.share-config-card__title {
font-size: 16px;
font-weight: 600;
}
.share-config-card__desc {
margin-top: 4px;
font-size: 13px;
color: var(--el-text-color-secondary);
}
.share-config-card__tip {
margin-top: 6px;
font-size: 12px;
color: var(--el-text-color-secondary);
}
.share-config-form {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0 16px;
}
@media (max-width: 768px) {
.share-config-form {
grid-template-columns: 1fr;
}
.share-config-card__header {
flex-direction: column;
align-items: flex-start;
}
}
</style>