4848 <a-space >
4949 <a href =" javascript:" @click =" edit(record)" >编辑</a >
5050 <!-- 添加设为默认按钮,但在TTS中不显示 -->
51- <a v-if =" configType !== 'tts' && record.isDefault != 1" href =" javascript:" :disabled = " record.isDefault == 1 "
52- @click =" setAsDefault(record)" >设为默认</a >
51+ <a v-if =" configType !== 'tts' && record.isDefault != 1" href =" javascript:"
52+ :disabled = " record.isDefault == 1 " @click =" setAsDefault(record)" >设为默认</a >
5353 <a-popconfirm :title =" `确定要删除这个${configTypeInfo.label}配置吗?`"
5454 @confirm =" deleteConfig(record.configId)" >
5555 <a v-if =" record.isDefault != 1" href =" javascript:" style =" color : #ff4d4f " >删除</a >
7676 </a-col >
7777 <a-col :xl =" 16" :lg =" 12" :xs =" 24" >
7878 <a-form-item :label =" `${configTypeInfo.label}名称`" >
79- <!-- 修改这里,添加模型名称提示 -->
80- <a-tooltip v-if =" configType === 'llm' && currentType && getModelNameTip(currentType)"
81- :title =" getModelNameTip(currentType)" placement =" top" >
82- <a-input v-decorator =" [
79+ <!-- 如果是 llm 且有 currentType,变为可输入的下拉框 -->
80+ <a-select v-if =" configType === 'llm' && currentType"
81+ v-decorator =" [
8382 'configName',
8483 { rules: [{ required: true, message: `请输入${configTypeInfo.label}名称` }] }
85- ]" autocomplete =" off" :placeholder =" `请输入${configTypeInfo.label}名称`" />
86- </a-tooltip >
87- <a-input v-else v-decorator =" [
88- 'configName',
89- { rules: [{ required: true, message: `请输入${configTypeInfo.label}名称` }] }
90- ]" autocomplete =" off" :placeholder =" `请输入${configTypeInfo.label}名称`" />
84+ ]"
85+ showSearch
86+ allowClear
87+ :placeholder =" `请输入${configTypeInfo.label}名称`"
88+ :options =" modelOptions"
89+ :filterOption =" modelFilterOption"
90+ @search =" handleModelInputChange"
91+ @change =" handleModelChange"
92+ @blur =" handleModelBlur" >
93+ </a-select >
94+ <!-- 如果不是 llm 或没有 currentType,保留原来的输入框 -->
95+ <a-input v-else
96+ v-decorator =" [
97+ 'configName',
98+ { rules: [{ required: true, message: `请输入${configTypeInfo.label}名称` }] }
99+ ]"
100+ autocomplete =" off"
101+ :placeholder =" `请输入${configTypeInfo.label}名称`" />
91102 </a-form-item >
92103 </a-col >
93104 </a-row >
116127 <a-input v-decorator =" [
117128 field.name,
118129 { rules: [{ required: field.required, message: `请输入${field.label}` }] }
119- ]" :placeholder =" `请输入${field.label}`" :type =" field.inputType || 'text'" >
130+ ]" :placeholder =" `请输入${field.label}`" :type =" field.inputType || 'text'"
131+ @change =" getModelList()" >
120132 <template v-if =" field .suffix " slot="suffix">
121133 <span style =" color : #999 " >{{ field.suffix }}</span >
122134 </template >
@@ -185,13 +197,7 @@ export default {
185197 currentType: ' ' ,
186198 loading: false ,
187199
188- // 模型名称提示信息
189- // TODO 需要扩展每项模型提示,或者为每项增加默认模型名称
190- modelNameTips: {
191- openai: " 请输入要调用的模型名称,如:gpt-3.5-turbo, gpt-4, qwen-max, deepseek-chat等" ,
192- ollama: " 请输入要调用的Ollama模型名称,如:deepseek-r1, qwen2.5:7b, gemma3:12b等" ,
193- spark: " 请输入星火大模型官方模型名称,如:Lite, Pro, Max等"
194- },
200+ modelOptions: [], // 存储模型下拉框选项
195201
196202 columns: [
197203 {
@@ -286,9 +292,77 @@ export default {
286292 this .getData ()
287293 },
288294 methods: {
289- // 获取模型名称提示
290- getModelNameTip (providerType ) {
291- return this .configType === ' llm' ? this .modelNameTips [providerType] : null ;
295+ getModelList () {
296+
297+ const formValues = this .configForm .getFieldsValue ();
298+ const apiKey = formValues .apiKey ;
299+ const apiUrl = formValues .apiUrl ;
300+
301+ // 检查是否输入了必要的参数
302+ if (! apiKey || ! apiUrl) {
303+ return ;
304+ }
305+ axios
306+ .post ({
307+ url: api .config .getModels ,
308+ data: {
309+ ... formValues
310+ }
311+ })
312+ .then (res => {
313+ if (res .code === 200 ) {
314+ this .modelOptions = res .data .map ((item ) => ({
315+ value: item .id ,
316+ label: item .id ,
317+ }));
318+ }
319+ })
320+ .catch (() => {
321+ this .showError ();
322+ })
323+ },
324+
325+ filterOption (input , option ) {
326+ return option .label .toLowerCase ().includes (input .toLowerCase ());
327+ },
328+
329+ // 处理输入变化
330+ handleModelInputChange (value ) {
331+ this .$nextTick (() => {
332+ // 手动绑定输入的值到表单字段
333+ setTimeout (() => {
334+ this .configForm .setFieldsValue ({
335+ configName: value
336+ });
337+ }, 0 );
338+ });
339+ },
340+
341+ // 处理选项变化
342+ handleModelChange (value ) {
343+ // 如果用户选择了一个选项,直接更新表单字段
344+ this .$nextTick (() => {
345+ // 手动绑定输入的值到表单字段
346+ setTimeout (() => {
347+ this .configForm .setFieldsValue ({
348+ configName: value
349+ });
350+ }, 0 );
351+ });
352+ },
353+
354+ // 处理失去焦点时的逻辑
355+ handleModelBlur () {
356+ const value = this .configForm .getFieldValue (' configName' );
357+ // 如果输入的值不在选项列表中,保留用户输入的值
358+ this .$nextTick (() => {
359+ // 手动绑定输入的值到表单字段
360+ setTimeout (() => {
361+ this .configForm .setFieldsValue ({
362+ configName: value
363+ });
364+ }, 0 );
365+ });
292366 },
293367
294368 // 处理标签页切换
@@ -313,7 +387,7 @@ export default {
313387 configName: formValues .configName ,
314388 configDesc: formValues .configDesc
315389 };
316-
390+
317391 // 如果不是TTS,添加isDefault字段
318392 if (this .configType !== ' tts' ) {
319393 newValues .isDefault = formValues .isDefault ;
@@ -376,21 +450,28 @@ export default {
376450 e .preventDefault ()
377451 this .configForm .validateFields ((err , values ) => {
378452 if (! err) {
379- this .loading = true
380453
454+ if (this .configType === ' llm' ) {
455+ // 校验 configName 是否为英文、数字或者它们的组合
456+ const configName = values .configName ;
457+ const containsChineseRegex = / [\u4e00 -\u9fa5 ] / ; // 检测是否包含中文字符
458+ if (containsChineseRegex .test (configName)) {
459+ this .$message .error (' 模型名称不能随意输入,请输入正确的模型名称,例如:deepseek-chat、qwen-plus官方名称' );
460+ return ;
461+ }
462+ }
463+
381464 // 处理可能的URL后缀重复问题
382- if (values .apiUrl ) {
383- const currentType = values .provider ;
384- const typeFields = this .configTypeInfo .typeFields || {};
385- const apiUrlField = (typeFields[currentType] || []).find (field => field .name === ' apiUrl' );
386-
387- if (apiUrlField && apiUrlField .suffix ) {
388- const suffix = apiUrlField .suffix ;
389- // 检查URL是否已经以后缀结尾,如果是则不再添加
390- if (values .apiUrl .endsWith (suffix)) {
391- // 移除URL末尾的后缀部分
392- values .apiUrl = values .apiUrl .substring (0 , values .apiUrl .length - suffix .length );
393- }
465+ const currentType = values .provider ;
466+ const typeFields = this .configTypeInfo .typeFields || {};
467+ const apiUrlField = (typeFields[currentType] || []).find (field => field .name === ' apiUrl' );
468+
469+ if (apiUrlField && apiUrlField .suffix ) {
470+ const suffix = apiUrlField .suffix ;
471+ // 检查URL是否已经以后缀结尾,如果是则不再添加
472+ if (values .apiUrl .endsWith (suffix)) {
473+ // 移除URL末尾的后缀部分
474+ values .apiUrl = values .apiUrl .substring (0 , values .apiUrl .length - suffix .length );
394475 }
395476 }
396477
@@ -405,6 +486,7 @@ export default {
405486 if (this .configType !== ' tts' ) {
406487 formData .isDefault = values .isDefault ? 1 : 0 ;
407488 }
489+ this .loading = true
408490
409491 const url = this .editingConfigId
410492 ? api .config .update
@@ -451,14 +533,15 @@ export default {
451533
452534 // 设置表单值,使用setTimeout确保表单已渲染
453535 setTimeout (() => {
454- const formValues = {... record};
455-
536+ const formValues = { ... record };
537+
456538 // 只有非TTS类型才设置isDefault
457539 if (this .configType !== ' tts' ) {
458540 formValues .isDefault = record .isDefault == 1 ;
459541 }
460-
542+
461543 configForm .setFieldsValue (formValues);
544+ this .getModelList ();
462545 }, 0 );
463546 })
464547 },
@@ -467,7 +550,7 @@ export default {
467550 setAsDefault (record ) {
468551 // TTS不应该有这个功能,但为了安全起见,再次检查
469552 if (this .configType === ' tts' ) return ;
470-
553+
471554 this .$confirm ({
472555 title: ` 确定要将此${ this .configTypeInfo .label } 设为默认吗?` ,
473556 content: ` 设为默认后,系统将优先使用此${ this .configTypeInfo .label } 配置,原默认${ this .configTypeInfo .label } 将被取消默认状态。` ,
@@ -534,6 +617,7 @@ export default {
534617 resetForm () {
535618 this .configForm .resetFields ()
536619 this .currentType = ' '
620+ this .modelOptions = []
537621 this .editingConfigId = null
538622 }
539623 }
0 commit comments