feat: 优化创建分组字段填充

This commit is contained in:
tbphp
2025-07-23 18:39:17 +08:00
parent 529513f848
commit 2d41a1b45d
3 changed files with 107 additions and 15 deletions

View File

@@ -86,6 +86,12 @@ const configOptions = ref<GroupConfigOption[]>([]);
const channelTypesFetched = ref(false); const channelTypesFetched = ref(false);
const configOptionsFetched = ref(false); const configOptionsFetched = ref(false);
// 跟踪用户是否已手动修改过字段(仅在新增模式下使用)
const userModifiedFields = ref({
test_model: false,
upstream: false,
});
// 根据渠道类型动态生成占位符提示 // 根据渠道类型动态生成占位符提示
const testModelPlaceholder = computed(() => { const testModelPlaceholder = computed(() => {
switch (formData.channel_type) { switch (formData.channel_type) {
@@ -183,21 +189,95 @@ watch(
} }
); );
// 监听渠道类型变化,在新增模式下智能更新默认值
watch(
() => formData.channel_type,
(_newChannelType, oldChannelType) => {
if (!props.group && oldChannelType) {
// 仅在新增模式且不是初始设置时处理
// 检查测试模型是否应该更新(为空或是旧渠道类型的默认值)
if (
!userModifiedFields.value.test_model ||
formData.test_model === getOldDefaultTestModel(oldChannelType)
) {
formData.test_model = testModelPlaceholder.value;
userModifiedFields.value.test_model = false;
}
// 检查第一个上游地址是否应该更新
if (
formData.upstreams.length > 0 &&
(!userModifiedFields.value.upstream ||
formData.upstreams[0].url === getOldDefaultUpstream(oldChannelType))
) {
formData.upstreams[0].url = upstreamPlaceholder.value;
userModifiedFields.value.upstream = false;
}
}
}
);
// 获取旧渠道类型的默认值(用于比较)
function getOldDefaultTestModel(channelType: string): string {
switch (channelType) {
case "openai":
return "gpt-4.1-nano";
case "gemini":
return "gemini-2.0-flash-lite";
case "anthropic":
return "claude-3-haiku-20240307";
default:
return "";
}
}
function getOldDefaultUpstream(channelType: string): string {
switch (channelType) {
case "openai":
return "https://api.openai.com";
case "gemini":
return "https://generativelanguage.googleapis.com";
case "anthropic":
return "https://api.anthropic.com";
default:
return "";
}
}
// 重置表单 // 重置表单
function resetForm() { function resetForm() {
const isCreateMode = !props.group;
const defaultChannelType = "openai";
// 先设置渠道类型,这样 computed 属性能正确计算默认值
formData.channel_type = defaultChannelType;
Object.assign(formData, { Object.assign(formData, {
name: "", name: "",
display_name: "", display_name: "",
description: "", description: "",
upstreams: [{ url: "", weight: 1 }], upstreams: [
channel_type: "openai", {
url: isCreateMode ? upstreamPlaceholder.value : "",
weight: 1,
},
],
channel_type: defaultChannelType,
sort: 1, sort: 1,
test_model: "", test_model: isCreateMode ? testModelPlaceholder.value : "",
validation_endpoint: "", validation_endpoint: "",
param_overrides: "", param_overrides: "",
config: {}, config: {},
configItems: [], configItems: [],
}); });
// 重置用户修改状态追踪
if (isCreateMode) {
userModifiedFields.value = {
test_model: false,
upstream: false,
};
}
} }
// 加载分组数据(编辑模式) // 加载分组数据(编辑模式)
@@ -466,11 +546,15 @@ async function handleSubmit() {
<template #trigger> <template #trigger>
<n-icon :component="HelpCircleOutline" class="help-icon" /> <n-icon :component="HelpCircleOutline" class="help-icon" />
</template> </template>
用于验证API密钥有效性的模型名称系统会使用这个模型发送测试请求来检查密钥是否可用 用于验证API密钥有效性的模型名称系统会使用这个模型发送测试请求来检查密钥是否可用请尽量使用轻量快速的模型
</n-tooltip> </n-tooltip>
</div> </div>
</template> </template>
<n-input v-model:value="formData.test_model" :placeholder="testModelPlaceholder" /> <n-input
v-model:value="formData.test_model"
:placeholder="testModelPlaceholder"
@input="() => !props.group && (userModifiedFields.test_model = true)"
/>
</n-form-item> </n-form-item>
<n-form-item <n-form-item
@@ -559,7 +643,11 @@ async function handleSubmit() {
</template> </template>
<div class="upstream-row"> <div class="upstream-row">
<div class="upstream-url"> <div class="upstream-url">
<n-input v-model:value="upstream.url" :placeholder="upstreamPlaceholder" /> <n-input
v-model:value="upstream.url"
:placeholder="upstreamPlaceholder"
@input="() => !props.group && index === 0 && (userModifiedFields.upstream = true)"
/>
</div> </div>
<div class="upstream-weight"> <div class="upstream-weight">
<span class="weight-label">权重</span> <span class="weight-label">权重</span>

View File

@@ -15,6 +15,7 @@ interface Props {
interface Emits { interface Emits {
(e: "group-select", group: Group): void; (e: "group-select", group: Group): void;
(e: "refresh"): void; (e: "refresh"): void;
(e: "refresh-and-select", groupId: number): void;
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@@ -67,15 +68,8 @@ function handleGroupCreated(_group: Group) {
} }
function handleSwitchToGroup(groupId: number) { function handleSwitchToGroup(groupId: number) {
// 创建成功后,等待列表刷新完成,然后切换到新创建的分组 // 创建成功后,通知父组件刷新并切换到新创建的分组
emit("refresh"); emit("refresh-and-select", groupId);
// 延迟选择新分组,确保列表已更新
setTimeout(() => {
const newGroup = props.groups.find(g => g.id === groupId);
if (newGroup) {
emit("group-select", newGroup);
}
}, 100);
} }
</script> </script>

View File

@@ -51,6 +51,15 @@ async function handleGroupRefresh() {
} }
} }
async function handleGroupRefreshAndSelect(targetGroupId: number) {
await loadGroups();
// 刷新完成后,切换到指定的分组
const targetGroup = groups.value.find(g => g.id === targetGroupId);
if (targetGroup) {
handleGroupSelect(targetGroup);
}
}
function handleGroupDelete(deletedGroup: Group) { function handleGroupDelete(deletedGroup: Group) {
// 从分组列表中移除已删除的分组 // 从分组列表中移除已删除的分组
groups.value = groups.value.filter(g => g.id !== deletedGroup.id); groups.value = groups.value.filter(g => g.id !== deletedGroup.id);
@@ -71,6 +80,7 @@ function handleGroupDelete(deletedGroup: Group) {
:loading="loading" :loading="loading"
@group-select="handleGroupSelect" @group-select="handleGroupSelect"
@refresh="handleGroupRefresh" @refresh="handleGroupRefresh"
@refresh-and-select="handleGroupRefreshAndSelect"
/> />
</div> </div>