feat(知识库): 添加模型配置管理功能并修复向量状态显示

添加模型配置管理相关功能,包括模型配置列表展示、创建和编辑功能。同时修复文档详情中向量状态显示问题,将数字类型转换为布尔类型以正确绑定到el-switch组件。

- 新增模型配置相关API接口和类型定义
- 添加模型配置列表弹窗及创建/编辑表单
- 修复向量状态显示问题,确保与el-switch组件正确绑定
- 优化深拷贝逻辑,自动转换status字段类型
This commit is contained in:
2026-04-16 14:49:33 +08:00
parent 6bf571c681
commit 4f547b5bff
3 changed files with 413 additions and 9 deletions

View File

@@ -0,0 +1,83 @@
import request from '/@/utils/request';
// 模型配置查询参数
export interface ModelConfigQueryParams {
pageNum: number;
pageSize: number;
modelType?: string;
modelName?: string;
}
// 模型配置信息
export interface ModelConfigInfo {
id: number;
modelType: string;
modelName: string;
modelDesc: string;
configType: string;
configContent: number[];
createTime: string;
updateTime: string;
}
// 获取模型配置列表
export function listModelConfigs(params?: ModelConfigQueryParams) {
return request({
url: '/rag/model/list',
method: 'get',
params,
});
}
// 创建模型配置
export function createModelConfig(data: any) {
return request({
url: '/rag/model/create',
method: 'post',
data,
});
}
// 更新模型配置
export function updateModelConfig(data: any) {
return request({
url: '/rag/model/update',
method: 'put',
data,
});
}
// 删除模型配置
export function deleteModelConfig(id: string | number) {
return request({
url: '/rag/model/delete',
method: 'post',
data: { id },
});
}
// 获取模型配置详情
export function getModelConfig(id: string | number, modelType: string) {
return request({
url: '/rag/model/get',
method: 'get',
params: { id, modelType },
});
}
// 获取模型类型和配置类型枚举
export function getAllModelEnums() {
return request({
url: '/rag/model/getAllEnums',
method: 'get',
});
}
// 获取模型表单字段
export function getModelFormField(modelType: string, configType: string) {
return request({
url: '/rag/model/getModelFormField',
method: 'get',
params: { modelType, configType },
});
}

View File

@@ -77,7 +77,7 @@
<div class="vector-item" v-for="vector in vectorList" :key="vector.id">
<div class="vector-header">
<span class="vector-index"> {{ vector.chunkIndex }}</span>
<span class="vector-status">状态: {{ vector.status === 1 ? '启用' : '禁用' }}</span>
<span class="vector-status">状态: {{ vector.status ? '启用' : '禁用' }}</span>
<span class="vector-vector-status">向量状态: {{ vector.vectorStatus === 1 ? '已生成' : '未生成' }}</span>
<el-switch v-model="vector.status" size="small" @change="(value: boolean) => onVectorStatusChange(vector, !value)" />
</div>
@@ -233,8 +233,13 @@ const getVectorList = async () => {
pageNum: vectorPage.value,
pageSize: vectorPageSize.value,
});
// 深拷贝数据避免v-model触发不必要的更新
vectorList.value = (response.data?.list || []).map((item: any) => JSON.parse(JSON.stringify(item)));
// 深拷贝数据避免v-model触发不必要的更新并将status从数字转换为布尔类型
vectorList.value = (response.data?.list || []).map((item: any) => {
const clonedItem = JSON.parse(JSON.stringify(item));
// 将数字类型的status转换为布尔类型以便正确绑定到el-switch
clonedItem.status = clonedItem.status === 1;
return clonedItem;
});
vectorTotal.value = response.data?.total || 0;
} catch (_error) {
ElMessage.error('获取向量列表失败');

View File

@@ -7,10 +7,16 @@
<el-icon class="header-icon"><ele-Folder /></el-icon>
<span class="header-title">知识库</span>
</div>
<el-button type="primary" @click="onAddknowledge">
<el-icon><ele-Plus /></el-icon>
新建知识库
</el-button>
<div class="header-actions">
<el-button type="primary" @click="onAddknowledge">
<el-icon><ele-Plus /></el-icon>
新建知识库
</el-button>
<el-button type="success" @click="onOpenModelConfig">
<el-icon><ele-Setting /></el-icon>
模型配置
</el-button>
</div>
</div>
<div class="knowledge-cards" v-loading="knowledgeLoading">
@@ -268,6 +274,91 @@
:knowledgeName="currentknowledge?.name || ''"
:document="currentDocument"
/>
<!-- 模型配置弹窗 -->
<el-dialog title="模型配置" v-model="showModelConfigDialog" width="1000px" :close-on-click-modal="false">
<div class="model-config-list" v-loading="modelConfigLoading">
<el-button type="primary" style="margin-bottom: 16px" @click="onCreateModelConfig">
<el-icon><ele-Plus /></el-icon>
创建模型配置
</el-button>
<el-table :data="modelConfigList" style="width: 100%" border>
<el-table-column prop="modelName" label="模型名称" min-width="120" />
<el-table-column prop="modelType" label="模型类型" min-width="100" />
<el-table-column prop="modelDesc" label="模型描述" min-width="150" />
<el-table-column prop="configType" label="配置类型" min-width="100" />
<el-table-column prop="createTime" label="创建时间" min-width="150">
<template #default="{ row }">
{{ formatDateTime(row.createTime) }}
</template>
</el-table-column>
<el-table-column prop="updateTime" label="修改时间" min-width="150">
<template #default="{ row }">
{{ formatDateTime(row.updateTime) }}
</template>
</el-table-column>
<el-table-column label="操作" width="80" align="center">
<template #default="{ row }">
<el-button text size="small" type="primary" @click="onEditModelConfig(row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
<el-empty v-if="modelConfigList.length === 0 && !modelConfigLoading" description="暂无模型配置" :image-size="60" />
</div>
<template #footer>
<el-button @click="showModelConfigDialog = false">关闭</el-button>
</template>
</el-dialog>
<!-- 创建/编辑模型配置弹窗 -->
<el-dialog :title="isEditMode ? '编辑模型配置' : '创建模型配置'" v-model="showCreateModelDialog" width="600px" :close-on-click-modal="false">
<div v-loading="modelEnumsLoading || modelFormLoading">
<el-form :model="modelFormData" label-width="100px">
<!-- 模型类型选择 -->
<el-form-item label="模型类型" required>
<el-select v-model="selectedModelType" style="width: 100%" @change="onModelTypeChange">
<el-option v-for="item in modelEnums" :key="item.key" :label="item.value" :value="item.key" />
</el-select>
</el-form-item>
<!-- 配置类型选择 -->
<el-form-item label="配置类型" required>
<el-select v-model="selectedConfigType" style="width: 100%" @change="onConfigTypeChange" :disabled="!selectedModelType">
<el-option v-for="item in getConfigTypes()" :key="item.key" :label="item.value" :value="item.key" />
</el-select>
</el-form-item>
<!-- 动态表单字段 -->
<template v-if="modelFormFields.length > 0">
<el-form-item v-for="(field, index) in modelFormFields" :key="field.name || index" :label="field.label" :required="field.required">
<template v-if="field.type === 'textarea'">
<el-input
v-model="modelFormData[field.name]"
type="textarea"
:rows="3"
:placeholder="field.placeholder"
:disabled="field.disabled"
style="width: 100%"
/>
</template>
<template v-else-if="field.type === 'switch'">
<el-switch v-model="modelFormData[field.name]" :disabled="field.disabled" />
</template>
<template v-else>
<el-input v-model="modelFormData[field.name]" :placeholder="field.placeholder" :disabled="field.disabled" style="width: 100%" />
</template>
</el-form-item>
</template>
<!-- 无表单字段提示 -->
<el-empty v-else description="暂无表单字段" :image-size="60" />
</el-form>
</div>
<template #footer>
<el-button @click="showCreateModelDialog = false">取消</el-button>
<el-button type="primary" @click="onSaveModelConfig()" :disabled="!selectedModelType || !selectedConfigType"> 保存 </el-button>
</template>
</el-dialog>
</div>
</template>
@@ -284,6 +375,7 @@ import type { FormInstance, FormRules, UploadFile } from 'element-plus';
import DocumentDetailDialog from './component/documentDetailDialog.vue';
import { listknowledges, createknowledge, updateknowledge, deleteknowledge } from '/@/api/knowledge/dataset';
import { listDocuments, uploadFile, createDocument, deleteDocument, updateDocument, generateVector, getDocument } from '/@/api/knowledge/document';
import { listModelConfigs, createModelConfig, updateModelConfig, getModelConfig, getAllModelEnums, getModelFormField } from '/@/api/knowledge/model';
// 数据集相关
const knowledgeLoading = ref(false);
@@ -291,6 +383,23 @@ const knowledgeList = ref<any[]>([]);
const currentknowledge = ref<any>(null);
const showknowledgeDialog = ref(false);
const knowledgeSaving = ref(false);
// 模型配置相关
const showModelConfigDialog = ref(false);
const modelConfigList = ref<any[]>([]);
const modelConfigLoading = ref(false);
// 创建模型配置相关
const showCreateModelDialog = ref(false);
const modelEnums = ref<any[]>([]);
const selectedModelType = ref('');
const selectedConfigType = ref('');
const modelFormFields = ref<any[]>([]);
const modelFormData = ref<any>({});
const modelFormLoading = ref(false);
const modelEnumsLoading = ref(false);
const isEditMode = ref(false);
const currentModelId = ref<number | null>(null);
const knowledgeFormRef = ref<FormInstance>();
const knowledgeForm = reactive({
id: '',
@@ -675,8 +784,215 @@ const getLogList = () => {
};
// 保存配置
const onSaveSettings = () => {
ElMessage.success('配置保存成功');
const onSaveSettings = async () => {
ElMessage.success('保存成功');
};
// 打开模型配置弹窗
const onOpenModelConfig = async () => {
await getModelConfigList();
showModelConfigDialog.value = true;
};
// 打开创建模型配置弹窗
const onCreateModelConfig = async () => {
// 重置状态
selectedModelType.value = '';
selectedConfigType.value = '';
modelFormFields.value = [];
modelFormData.value = {};
isEditMode.value = false;
currentModelId.value = null;
// 获取模型类型和配置类型枚举
await getModelEnums();
// 打开创建弹窗
showCreateModelDialog.value = true;
};
// 编辑模型配置
const onEditModelConfig = async (row: any) => {
try {
// 重置状态
selectedModelType.value = '';
selectedConfigType.value = '';
modelFormFields.value = [];
modelFormData.value = {};
isEditMode.value = true;
currentModelId.value = row.id;
// 获取模型类型和配置类型枚举
await getModelEnums();
// 调用获取详情接口
const response = await getModelConfig(row.id, row.modelType);
const modelData = response.data;
// 设置模型类型和配置类型
selectedModelType.value = modelData.modelType;
selectedConfigType.value = modelData.configType;
// 填充表单数据
modelFormData.value = {
modelName: modelData.modelName,
modelDesc: modelData.modelDesc,
};
// 将configContent中的数据添加到表单数据中
if (modelData.configContent) {
Object.keys(modelData.configContent).forEach((key) => {
modelFormData.value[key] = modelData.configContent[key];
});
}
// 获取动态表单字段
await getModelFormFields();
// 打开弹窗
showCreateModelDialog.value = true;
} catch (error) {
ElMessage.error('获取模型配置详情失败');
}
};
// 获取模型类型和配置类型枚举
const getModelEnums = async () => {
modelEnumsLoading.value = true;
try {
const response = await getAllModelEnums();
modelEnums.value = response.data?.options || [];
} catch (error) {
ElMessage.error('获取模型类型枚举失败');
modelEnums.value = [];
} finally {
modelEnumsLoading.value = false;
}
};
// 模型类型选择变化
const onModelTypeChange = async () => {
selectedConfigType.value = '';
modelFormFields.value = [];
// 在编辑模式下,只保留模型名称和描述,清空其他字段
if (isEditMode.value) {
const { modelName, modelDesc } = modelFormData.value;
modelFormData.value = {
modelName,
modelDesc,
};
} else {
// 创建模式下清空所有字段
modelFormData.value = {};
}
};
// 配置类型选择变化
const onConfigTypeChange = async () => {
if (selectedModelType.value && selectedConfigType.value) {
await getModelFormFields();
}
};
// 获取模型表单字段
const getModelFormFields = async () => {
modelFormLoading.value = true;
try {
const response = await getModelFormField(selectedModelType.value, selectedConfigType.value);
// 过滤掉模型类型和配置类型字段,避免重复显示
modelFormFields.value = (response.data?.fields || []).filter((field: any) => {
return field.name !== 'modelType' && field.name !== 'configType';
});
// 设置字段的默认值,但保留已有的表单数据
modelFormFields.value.forEach((field: any) => {
if (field.value !== undefined && modelFormData.value[field.name] === undefined) {
modelFormData.value[field.name] = field.value;
}
});
} catch (error) {
ElMessage.error('获取模型表单字段失败');
modelFormFields.value = [];
} finally {
modelFormLoading.value = false;
}
};
// 保存模型配置
const onSaveModelConfig = async () => {
try {
// 构建请求数据,只传递接口需要的字段
const data = {
modelType: selectedModelType.value,
configType: selectedConfigType.value,
modelName: modelFormData.value.modelName,
modelDesc: modelFormData.value.modelDesc,
configContent: {} as Record<string, any>,
};
// 将动态表单字段除了modelType、configType、modelName、modelDesc添加到configContent中以key-value形式
Object.keys(modelFormData.value).forEach((key) => {
if (!['modelType', 'configType', 'modelName', 'modelDesc'].includes(key)) {
data.configContent[key] = modelFormData.value[key];
}
});
// 根据模式调用不同的接口
if (isEditMode.value && currentModelId.value) {
// 编辑模式,调用更新接口
await updateModelConfig({ ...data, id: currentModelId.value });
ElMessage.success('更新模型配置成功');
} else {
// 创建模式,调用创建接口
await createModelConfig(data);
ElMessage.success('创建模型配置成功');
}
// 关闭弹窗并刷新列表
showCreateModelDialog.value = false;
getModelConfigList();
} catch (error) {
ElMessage.error(isEditMode.value ? '更新模型配置失败' : '创建模型配置失败');
}
};
// 根据选中的模型类型获取配置类型列表
const getConfigTypes = () => {
if (!selectedModelType.value) {
return [];
}
const selectedModel = modelEnums.value.find((item: any) => item.key === selectedModelType.value);
return selectedModel?.configTypes || [];
};
// 获取模型配置列表
const getModelConfigList = async () => {
modelConfigLoading.value = true;
try {
const response = await listModelConfigs({
pageNum: 1,
pageSize: 100,
});
modelConfigList.value = response.data?.list || [];
} catch (error) {
ElMessage.error('获取模型配置列表失败');
modelConfigList.value = [];
} finally {
modelConfigLoading.value = false;
}
};
// 格式化时间
const formatDateTime = (dateTime: string) => {
if (!dateTime) return '-';
const date = new Date(dateTime);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
// 页面加载