This commit is contained in:
吴红兵
2025-12-02 10:37:49 +08:00
commit 1f645dad3e
1183 changed files with 147673 additions and 0 deletions

View File

@@ -0,0 +1,317 @@
<template>
<el-dialog width="40%" :title="form.storeId ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
<el-row :gutter="24">
<el-col :span="24" class="mb20">
<el-form-item label="类型" prop="storeType">
<el-select v-model="form.storeType" placeholder="请选择类型">
<el-option :label="item.label" :value="item.value" v-for="(item, index) in embed_store_type" :key="index"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20" v-if="form.storeType !== 'qdrant' && form.storeType !== 'redis' && form.storeType !== 'pgvector'">
<el-form-item label="URI" prop="uri">
<el-input v-model="form.uri" placeholder="请输入链接地址" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20" v-if="form.storeType === 'qdrant' || form.storeType === 'redis' || form.storeType === 'pgvector'">
<el-form-item label="Host" prop="host">
<el-input v-model="form.host" placeholder="请输入Host" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20" v-if="form.storeType === 'qdrant' || form.storeType === 'redis' || form.storeType === 'pgvector'">
<el-form-item label="端口" prop="port">
<el-input-number v-model="form.port" placeholder="请输入端口" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20" v-if="form.storeType !== 'pgvector'">
<el-form-item label="密钥" prop="apiKey">
<el-input v-model="form.apiKey" placeholder="请输入密钥" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20" v-if="form.storeType === 'milvus'">
<el-form-item label="数据库" prop="extData">
<el-input v-model="form.extData" placeholder="请输入数据库" />
</el-form-item>
</el-col>
<!-- PgVector 特有配置 -->
<template v-if="form.storeType === 'pgvector'">
<el-col :span="24" class="mb20">
<el-form-item label="用户名" prop="pgUsername">
<el-input v-model="form.pgUsername" placeholder="请输入用户名" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="密码" prop="pgPassword">
<el-input v-model="form.pgPassword" type="password" placeholder="请输入密码" show-password />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="数据库" prop="pgDatabase">
<el-input v-model="form.pgDatabase" placeholder="请输入数据库名" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="维度" prop="pgDimension">
<el-input-number v-model="form.pgDimension" :min="1" :max="4096" placeholder="请输入向量维度" />
</el-form-item>
</el-col>
</template>
<el-col :span="24" class="mb20">
<el-form-item prop="useTls" v-if="form.storeType === 'qdrant'">
<template #label> TLS<tip content="HTTPS安全认证" /> </template>
<el-radio-group v-model="form.useTls">
<el-radio :key="index" :label="item.value" border v-for="(item, index) in yes_no_type">{{ item.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="AiEmbedStoreDialog">
import { useDict } from '/@/hooks/dict';
import { useMessage } from '/@/hooks/message';
import { getObj, addObj, putObj, validateExist } from '/@/api/knowledge/aiEmbedStore';
const emit = defineEmits(['refresh']);
// 定义变量内容
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
// 定义字典
const { embed_store_type, yes_no_type } = useDict('embed_store_type', 'yes_no_type');
// 提交表单数据
const form = reactive({
storeId: '',
name: '',
storeType: 'milvus',
host: '127.0.0.1',
port: 6334,
uri: 'http://127.0.0.1:19530',
apiKey: '',
extData: 'default',
useTls: '0',
// PgVector 特有字段
pgUsername: 'postgres',
pgPassword: 'postgres',
pgDatabase: 'database',
pgDimension: 4096,
});
// 监听 storeType 变化,设置默认端口
watch(
() => form.storeType,
(newType) => {
if (newType === 'pgvector') {
form.port = 5432;
} else if (newType === 'qdrant') {
form.port = 6334;
} else if (newType === 'redis') {
form.port = 6379;
}
}
);
// 定义校验规则
const dataRules = ref({
name: [
{ required: true, message: '名称不能为空', trigger: 'blur' },
{ max: 64, message: '长度不能超过64个字符', trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
validateExist(rule, value, callback, form.storeId !== '');
},
trigger: 'blur',
},
],
storeType: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
host: [
{ required: true, message: 'Host不能为空', trigger: 'blur' },
{ max: 255, message: '长度不能超过255个字符', trigger: 'blur' },
],
port: [
{ required: true, message: '端口不能为空', trigger: 'blur' },
{ type: 'number', max: 65535, message: '端口不能超过65535', trigger: 'blur' },
],
uri: [
{ required: true, message: '地址不能为空', trigger: 'blur' },
{ max: 255, message: '长度不能超过255个字符', trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
// URI变化时重新验证数据库字段
nextTick(() => {
if (dataFormRef.value) {
dataFormRef.value.validateField('extData');
}
});
callback();
},
trigger: 'blur',
},
],
extData: [
{ max: 255, message: '长度不能超过255个字符', trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
// 检查URI是否包含.zilliz.com.cn在线服务
if (form.uri && form.uri.includes('.zilliz.com.cn')) {
if (!value) {
callback(new Error('使用Zilliz在线服务时数据库字段不能为空'));
return;
}
// 检查数据库字段格式是否为 db_xxxx
const dbPattern = /^db_\w+$/;
if (!dbPattern.test(value)) {
callback(new Error('使用Zilliz在线服务时数据库字段必须是 db_id 的形式'));
return;
}
}
callback();
},
trigger: 'blur',
},
],
// PgVector 校验规则
pgUsername: [
{ required: true, message: '用户名不能为空', trigger: 'blur' },
{ max: 64, message: '长度不能超过64个字符', trigger: 'blur' },
],
pgPassword: [
{ required: true, message: '密码不能为空', trigger: 'blur' },
{ max: 255, message: '长度不能超过255个字符', trigger: 'blur' },
],
pgDatabase: [
{ required: true, message: '数据库名不能为空', trigger: 'blur' },
{ max: 64, message: '长度不能超过64个字符', trigger: 'blur' },
],
pgDimension: [
{ required: true, message: '维度不能为空', trigger: 'blur' },
{ type: 'number', min: 1, max: 4096, message: '维度必须在1-4096之间', trigger: 'blur' },
],
});
// 打开弹窗
const openDialog = (id: string) => {
visible.value = true;
form.storeId = '';
form.extData = '';
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
});
// 获取aiEmbedStore信息
if (id) {
form.storeId = id;
getaiEmbedStoreData(id);
}
};
// 提交
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
try {
loading.value = true;
// 修复TypeScript错误正确处理apiKey的类型
const submitForm = { ...form };
// 处理 pgvector 类型的特殊逻辑
if (form.storeType === 'pgvector') {
// 将 pgvector 的配置信息存储到 extData 中
const pgConfig = {
username: form.pgUsername,
password: form.pgPassword,
database: form.pgDatabase,
dimension: form.pgDimension,
};
submitForm.extData = JSON.stringify(pgConfig);
// 清空不需要的字段
submitForm.apiKey = '';
} else {
// 处理其他类型的 apiKey
if (submitForm.apiKey?.includes('***')) {
submitForm.apiKey = '';
}
}
// 移除 pgvector 特有的临时字段
delete (submitForm as any).pgUsername;
delete (submitForm as any).pgPassword;
delete (submitForm as any).pgDatabase;
delete (submitForm as any).pgDimension;
form.storeId ? await putObj(submitForm) : await addObj(submitForm);
useMessage().success(form.storeId ? '修改成功' : '添加成功');
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
// 初始化表单数据
const getaiEmbedStoreData = (id: string) => {
// 获取数据
loading.value = true;
getObj({ storeId: id })
.then((res: any) => {
Object.assign(form, res.data);
// 如果是 pgvector 类型,解析 extData 中的配置
if (form.storeType === 'pgvector' && form.extData) {
try {
const pgConfig = JSON.parse(form.extData);
form.pgUsername = pgConfig.username || 'postgres';
form.pgPassword = pgConfig.password || 'postgres';
form.pgDatabase = pgConfig.database || 'database';
form.pgDimension = pgConfig.dimension || 4096;
} catch (e) {
// 解析失败时使用默认值
form.pgUsername = 'postgres';
form.pgPassword = 'postgres';
form.pgDatabase = 'database';
form.pgDimension = 4096;
}
}
})
.finally(() => {
loading.value = false;
});
};
// 暴露变量
defineExpose({
openDialog,
});
</script>