feat: 增强模型配置与创建表单功能
- 在 NodeLibraryFormItem 和 WorkflowItem 接口中添加了新的字段,如 value、options、expand 和 outputParams,以支持更复杂的表单配置。 - 新增 getOperatorList 函数以获取服务商列表,并在 editModule.vue 中集成了运营商选择功能。 - 更新了模型创建和编辑逻辑,支持 tokenConfig 的 JSON 格式配置,确保更灵活的模型设置。 - 优化了文件上传处理,增加了上传状态管理,提升用户体验。
This commit is contained in:
@@ -23,6 +23,13 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="运营商名称" prop="operatorName" required>
|
||||
<el-select v-model="state.ruleForm.operatorName" placeholder="请选择运营商" clearable style="width: 100%">
|
||||
<el-option v-for="item in operatorNameOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="模型服务地址" prop="baseUrl">
|
||||
<el-input v-model="state.ruleForm.baseUrl" placeholder="请输入模型服务地址" clearable></el-input>
|
||||
@@ -150,6 +157,17 @@
|
||||
<el-input v-model="state.ruleForm.tokenMapping" placeholder="请输入Token映射" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
|
||||
<el-form-item label="Token计算配置" prop="tokenConfig">
|
||||
<el-input
|
||||
v-model="state.ruleForm.tokenConfig"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入 JSON 对象,例如:{promptRate: 1, completionRate: 1}"
|
||||
clearable
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-collapse-transition>
|
||||
</el-form>
|
||||
@@ -243,11 +261,17 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemEditModule">
|
||||
import { reactive, ref, computed } from 'vue';
|
||||
import { reactive, ref, computed, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { ArrowUp, ArrowDown } from '@element-plus/icons-vue';
|
||||
import { addModelModule, updateModelModule, getModelModuleDetail, type ModelFormEntry } from '/@/api/settings/modelConfig/modelModule/index';
|
||||
import {
|
||||
addModelModule,
|
||||
updateModelModule,
|
||||
getModelModuleDetail,
|
||||
getOperatorList,
|
||||
type ModelFormEntry,
|
||||
} from '/@/api/settings/modelConfig/modelModule/index';
|
||||
|
||||
export type ModelTypeOption = { id: number | string; label: string };
|
||||
|
||||
@@ -264,6 +288,20 @@ const props = withDefaults(
|
||||
|
||||
const modelTypeOptions = computed(() => props.modelTypes);
|
||||
|
||||
const operatorNameOptions = ref<Array<{ label: string; value: string }>>([]);
|
||||
|
||||
const loadOperatorOptions = async () => {
|
||||
try {
|
||||
const res: any = await getOperatorList();
|
||||
const list = res?.data?.list;
|
||||
operatorNameOptions.value = Array.isArray(list)
|
||||
? list.filter((item: unknown) => typeof item === 'string' && item.trim() !== '').map((name: string) => ({ label: name, value: name }))
|
||||
: [];
|
||||
} catch {
|
||||
operatorNameOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
const typeOptionValue = (id: number | string): number | string => {
|
||||
const n = Number(id);
|
||||
return Number.isNaN(n) ? id : n;
|
||||
@@ -280,6 +318,7 @@ const state = reactive({
|
||||
id: '',
|
||||
modelName: '',
|
||||
modelType: null as number | string | null,
|
||||
operatorName: '',
|
||||
baseUrl: '',
|
||||
httpMethod: 'POST',
|
||||
headMsg: '',
|
||||
@@ -296,6 +335,7 @@ const state = reactive({
|
||||
autoCleanSeconds: 300,
|
||||
remark: '',
|
||||
tokenMapping: '',
|
||||
tokenConfig: '{}',
|
||||
},
|
||||
rules: {
|
||||
modelName: [{ required: true, message: '请输入模型名称', trigger: 'blur' }],
|
||||
@@ -313,6 +353,7 @@ const state = reactive({
|
||||
],
|
||||
baseUrl: [{ required: true, message: '请输入模型服务地址', trigger: 'blur' }],
|
||||
httpMethod: [{ required: true, message: '请选择请求方式', trigger: 'change' }],
|
||||
operatorName: [{ required: true, message: '请选择运营商名称', trigger: 'change' }],
|
||||
apiKey: [
|
||||
{
|
||||
validator: (_rule: unknown, value: unknown, callback: (e?: Error) => void) => {
|
||||
@@ -339,6 +380,27 @@ const state = reactive({
|
||||
queueLimit: [{ required: true, message: '请输入排队队列上限', trigger: 'blur' }],
|
||||
timeoutSeconds: [{ required: true, message: '请输入请求超时时间', trigger: 'blur' }],
|
||||
expectedSeconds: [{ required: true, message: '请输入预计执行时间', trigger: 'blur' }],
|
||||
tokenConfig: [
|
||||
{
|
||||
validator: (_rule: unknown, value: unknown, callback: (e?: Error) => void) => {
|
||||
if (value === undefined || value === null || String(value).trim() === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(String(value));
|
||||
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
callback(new Error('Token计算配置必须为 JSON 对象'));
|
||||
} catch {
|
||||
callback(new Error('Token计算配置 JSON 格式不正确'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
},
|
||||
dialog: {
|
||||
isShowDialog: false,
|
||||
@@ -402,12 +464,6 @@ const parseResponseMappingFields = (mapping: unknown) => {
|
||||
return Object.entries(mapping).map(([key, value]) => ({ key, value: String(value) }));
|
||||
};
|
||||
|
||||
const buildFormArray = (): ModelFormEntry[] => {
|
||||
return state.formFields
|
||||
.filter((field) => field.key?.trim() && field.value?.trim())
|
||||
.map((field) => ({ key: field.key.trim(), value: field.value.trim() }));
|
||||
};
|
||||
|
||||
const parseKeyValueString = (raw: string) => {
|
||||
if (!raw) return [];
|
||||
const headers: Array<{ key: string; value: string }> = [];
|
||||
@@ -551,6 +607,7 @@ const fillFormFromDetailRow = (row: Record<string, unknown>) => {
|
||||
id: row.id as string,
|
||||
modelName: String(row.modelName ?? ''),
|
||||
modelType: row.modelType !== undefined && row.modelType !== null ? typeOptionValue(row.modelType as number | string) : null,
|
||||
operatorName: String(row.operatorName ?? ''),
|
||||
baseUrl: String(row.baseUrl ?? ''),
|
||||
httpMethod: String(row.httpMethod || 'POST'),
|
||||
headMsg: String(row.headMsg || ''),
|
||||
@@ -567,6 +624,10 @@ const fillFormFromDetailRow = (row: Record<string, unknown>) => {
|
||||
autoCleanSeconds: Number(row.autoCleanSeconds ?? 300),
|
||||
remark: String(row.remark || ''),
|
||||
tokenMapping: String(row.tokenMapping || ''),
|
||||
tokenConfig:
|
||||
typeof row.tokenConfig === 'string'
|
||||
? row.tokenConfig
|
||||
: JSON.stringify((row.tokenConfig as Record<string, unknown>) || {}, null, 2),
|
||||
};
|
||||
state.headers = ensureKeyValueRows(parseHeaders(String(row.headMsg || '')));
|
||||
state.formFields = ensureKeyValueRows(parseFormFields(row.form));
|
||||
@@ -628,6 +689,7 @@ const openDialog = async (type: string, row?: Record<string, unknown>) => {
|
||||
id: '',
|
||||
modelName: '',
|
||||
modelType: null,
|
||||
operatorName: '',
|
||||
baseUrl: '',
|
||||
httpMethod: 'POST',
|
||||
headMsg: '',
|
||||
@@ -644,6 +706,7 @@ const openDialog = async (type: string, row?: Record<string, unknown>) => {
|
||||
autoCleanSeconds: 300,
|
||||
remark: '',
|
||||
tokenMapping: '',
|
||||
tokenConfig: '{}',
|
||||
};
|
||||
state.headers = [{ key: '', value: '' }];
|
||||
state.formFields = [{ key: '', value: '' }];
|
||||
@@ -682,6 +745,7 @@ const onSubmit = () => {
|
||||
const submitData = {
|
||||
modelName: state.ruleForm.modelName,
|
||||
modelType: state.ruleForm.modelType as number | string,
|
||||
operatorName: state.ruleForm.operatorName,
|
||||
baseUrl: state.ruleForm.baseUrl,
|
||||
httpMethod: state.ruleForm.httpMethod || 'POST',
|
||||
headMsg: state.ruleForm.headMsg,
|
||||
@@ -702,6 +766,7 @@ const onSubmit = () => {
|
||||
autoCleanSeconds: state.ruleForm.autoCleanSeconds,
|
||||
remark: state.ruleForm.remark || '',
|
||||
tokenMapping: state.ruleForm.tokenMapping || '',
|
||||
tokenConfig: parseJsonObjectField(state.ruleForm.tokenConfig || '{}', {}),
|
||||
};
|
||||
|
||||
if (state.dialog.type === 'edit') {
|
||||
@@ -725,6 +790,10 @@ const onSubmit = () => {
|
||||
defineExpose({
|
||||
openDialog,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
loadOperatorOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -773,7 +842,3 @@ defineExpose({
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user