From 0e4a1dddb514a1e6715b38995cb62c57bbe54549 Mon Sep 17 00:00:00 2001 From: fawney19 Date: Thu, 8 Jan 2026 10:50:25 +0800 Subject: [PATCH] =?UTF-8?q?refactor(ui):=20=E4=BC=98=E5=8C=96=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E7=AB=AF=E7=82=B9=E5=88=9B=E5=BB=BA=E7=9A=84=20UI=20?= =?UTF-8?q?=E5=92=8C=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整布局: API URL 移至顶部, API 格式选择移至下方 - 优化 checkbox 样式: 使用自定义勾选框替代原生样式 - API 格式按列排序: 基础格式和对应 CLI 格式上下对齐 - 请求配置改为 4 列布局, 更紧凑 - 使用 Promise.allSettled 并发创建端点, 提升性能 - 改进错误提示: 失败时直接展示具体错误信息给用户 - 清理未使用的 Select 组件导入和 selectOpen 变量 --- .../components/EndpointFormDialog.vue | 161 ++++++++++-------- 1 file changed, 94 insertions(+), 67 deletions(-) diff --git a/frontend/src/features/providers/components/EndpointFormDialog.vue b/frontend/src/features/providers/components/EndpointFormDialog.vue index 162af87..6cfc5c0 100644 --- a/frontend/src/features/providers/components/EndpointFormDialog.vue +++ b/frontend/src/features/providers/components/EndpointFormDialog.vue @@ -20,43 +20,6 @@ API 配置 - -
- - - -
-
@@ -76,11 +39,63 @@ v-model="form.custom_path" :placeholder="isEditMode ? defaultPathPlaceholder : '留空使用各格式的默认路径'" /> -

- 将为所有选中的格式使用相同的 URL 和路径配置 -

+ + +
+ + + +
@@ -89,7 +104,7 @@ 请求配置 -
+
-
-
- + ([]) // API 格式列表 const apiFormats = ref>([]) +// 排序后的 API 格式:按列排列,每列是基础格式+CLI格式 +const sortedApiFormats = computed(() => { + const baseFormats = apiFormats.value.filter(f => !f.value.endsWith('_cli')) + const cliFormats = apiFormats.value.filter(f => f.value.endsWith('_cli')) + // 交错排列:base1, cli1, base2, cli2, base3, cli3 + const result: typeof apiFormats.value = [] + for (let i = 0; i < baseFormats.length; i++) { + result.push(baseFormats[i]) + const cliFormat = cliFormats.find(f => f.value === baseFormats[i].value + '_cli') + if (cliFormat) { + result.push(cliFormat) + } + } + return result +}) + // 加载API格式列表 const loadApiFormats = async () => { try { @@ -336,7 +359,7 @@ const defaultPath = computed(() => { // 动态 placeholder const defaultPathPlaceholder = computed(() => { - return `留空使用默认路径:${defaultPath.value}` + return defaultPath.value }) // 检查是否有已保存的密码(后端返回 *** 表示有密码) @@ -508,14 +531,11 @@ const handleSubmit = async (skipCredentialCheck = false) => { emit('endpointUpdated') emit('update:modelValue', false) } else if (props.provider) { - // 批量创建端点 - let failCount = 0 - const errors: string[] = [] - - for (const apiFormat of selectedFormats.value) { - try { - await createEndpoint(props.provider.id, { - provider_id: props.provider.id, + // 批量创建端点 - 使用并发请求提升性能 + const results = await Promise.allSettled( + selectedFormats.value.map(apiFormat => + createEndpoint(props.provider!.id, { + provider_id: props.provider!.id, api_format: apiFormat, base_url: form.value.base_url, custom_path: form.value.custom_path || undefined, @@ -526,22 +546,29 @@ const handleSubmit = async (skipCredentialCheck = false) => { is_active: form.value.is_active, proxy: proxyConfig, }) + ) + ) + + // 统计结果 + const errors: string[] = [] + results.forEach((result, index) => { + if (result.status === 'fulfilled') { successCount++ - } catch (error: any) { - failCount++ + } else { + const apiFormat = selectedFormats.value[index] const formatLabel = apiFormats.value.find((f: any) => f.value === apiFormat)?.label || apiFormat - errors.push(`${formatLabel}: ${error.response?.data?.detail || '创建失败'}`) + const errorMsg = result.reason?.response?.data?.detail || '创建失败' + errors.push(`${formatLabel}: ${errorMsg}`) } - } + }) + + const failCount = errors.length // 显示结果 if (successCount > 0 && failCount === 0) { success(`成功创建 ${successCount} 个端点`, '创建成功') } else if (successCount > 0 && failCount > 0) { - success(`成功创建 ${successCount} 个端点,${failCount} 个失败`, '部分成功') - if (errors.length > 0) { - log.error('创建端点失败:', errors) - } + showError(`${failCount} 个端点创建失败:\n${errors.join('\n')}`, `${successCount} 个成功,${failCount} 个失败`) } else { showError(errors.join('\n') || '创建端点失败', '创建失败') }