diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 879470a..7f6afb9 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -75,11 +75,10 @@ export const en: Record = { 'easyMode.api.testing': 'Testing connection...', 'easyMode.api.fetchModels': 'Fetch model list', 'easyMode.api.fetchingModels': 'Fetching model list...', - 'easyMode.api.customModelId': 'Custom Model ID', - 'easyMode.api.customModelPlaceholder': 'For example: gpt-5.6-sol or deepseek-v4-pro', - 'easyMode.api.addModelId': 'Add Model ID', + 'easyMode.api.modelListTitle': 'Select models', + 'easyMode.api.modelListHint': 'Select the models to connect', 'easyMode.api.credentialsRequired': 'Enter an API URL and API key first', - 'easyMode.api.modelRequired': 'Fetch and select a model, or add a Model ID manually', + 'easyMode.api.modelRequired': 'Fetch and select a model', 'easyMode.api.testSuccess': 'Connection successful! Found {count} models', 'easyMode.api.testFailed': 'Connection test failed', 'easyMode.api.platform': 'Platform', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 8bed820..e469520 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -73,11 +73,10 @@ export const zhCN = { 'easyMode.api.testing': '正在测试连接...', 'easyMode.api.fetchModels': '获取模型列表', 'easyMode.api.fetchingModels': '正在获取模型列表...', - 'easyMode.api.customModelId': '自定义 Model ID', - 'easyMode.api.customModelPlaceholder': '例如:gpt-5.6-sol 或 deepseek-v4-pro', - 'easyMode.api.addModelId': '添加 Model ID', + 'easyMode.api.modelListTitle': '选择模型', + 'easyMode.api.modelListHint': '勾选需要接入的模型', 'easyMode.api.credentialsRequired': '请先填写 API URL 和 API 密钥', - 'easyMode.api.modelRequired': '请先获取模型列表并选择模型,或手动添加 Model ID', + 'easyMode.api.modelRequired': '请先获取模型列表并选择模型', 'easyMode.api.testSuccess': '连接成功!发现 {count} 个模型', 'easyMode.api.testFailed': '连接测试失败', 'easyMode.api.platform': '平台类型', diff --git a/src/pages/EasyModePage.tsx b/src/pages/EasyModePage.tsx index 2b0f908..12a30e0 100644 --- a/src/pages/EasyModePage.tsx +++ b/src/pages/EasyModePage.tsx @@ -1,7 +1,6 @@ import { useCallback, useEffect, - useMemo, useRef, useState, } from "react"; @@ -13,8 +12,6 @@ import { Check, CheckCircle2, LoaderCircle, - Plus, - RefreshCw, } from "lucide-react"; import { useI18n } from "../i18n"; import { @@ -122,7 +119,6 @@ export function EasyModePage({ const [apiTesting, setApiTesting] = useState(false); const [apiTestedModels, setApiTestedModels] = useState([]); const [apiSelectedModels, setApiSelectedModels] = useState([]); - const [apiCustomModelId, setApiCustomModelId] = useState(""); const [apiTestError, setApiTestError] = useState(""); const [apiSaving, setApiSaving] = useState(false); const [apiSaveNotice, setApiSaveNotice] = useState(null); @@ -195,6 +191,14 @@ export function EasyModePage({ return () => window.clearTimeout(timer); }, [oauthNotice]); + useEffect(() => { + if (!apiSaveNotice) return undefined; + const timer = window.setTimeout(() => { + setApiSaveNotice(null); + }, 4500); + return () => window.clearTimeout(timer); + }, [apiSaveNotice]); + const handleStartOAuth = async (provider: OAuthProviderId) => { if (oauthPollTimer.current) window.clearInterval(oauthPollTimer.current); setOauthLoggingIn(provider); @@ -260,7 +264,6 @@ export function EasyModePage({ if (opt) setApiBaseUrl(opt.defaultBaseUrl); setApiTestedModels([]); setApiSelectedModels([]); - setApiCustomModelId(""); setApiTestError(""); setApiSaveNotice(null); }; @@ -288,11 +291,7 @@ export function EasyModePage({ ); if (models.length > 0) { setApiTestedModels(models); - setApiSelectedModels((current) => { - const fetchedKeys = new Set(models.map((model) => model.name.trim().toLowerCase())); - const customModels = current.filter((model) => !fetchedKeys.has(model.name.trim().toLowerCase())); - return [...models, ...customModels]; - }); + setApiSelectedModels(models); } else { setApiTestError("未获取到任何模型,请检查 API URL 和 API 密钥"); } @@ -314,19 +313,6 @@ export function EasyModePage({ }); }; - const handleAddCustomModel = () => { - const name = apiCustomModelId.trim(); - if (!name) return; - const key = name.toLowerCase(); - setApiSelectedModels((current) => { - if (current.some((model) => model.name.trim().toLowerCase() === key)) return current; - const fetchedModel = apiTestedModels.find((model) => model.name.trim().toLowerCase() === key); - return [...current, fetchedModel ?? { name }]; - }); - setApiCustomModelId(""); - setApiTestError(""); - }; - const handleSaveApi = async () => { if (!apiBaseUrl.trim()) { setApiTestError("请先填写 API URL"); @@ -382,14 +368,6 @@ export function EasyModePage({ const totalLoggedInOAuth = oauthProviders.filter((p) => isOAuthLoggedIn(p.id)).length; const totalApiProviders = Object.values(apiCounts).reduce((a, b) => a + b, 0); const hasConnectedSource = totalLoggedInOAuth > 0 || totalApiProviders > 0; - const displayedApiModels = useMemo(() => { - const fetchedKeys = new Set(apiTestedModels.map((model) => model.name.trim().toLowerCase())); - return [ - ...apiTestedModels, - ...apiSelectedModels.filter((model) => !fetchedKeys.has(model.name.trim().toLowerCase())), - ]; - }, [apiSelectedModels, apiTestedModels]); - const setupStepStatus = t("easyMode.steps.current", { current: activeStep, total: 2, @@ -554,10 +532,7 @@ export function EasyModePage({ {authMethod === "api" ? (
{apiSaveNotice ? ( -
+
{apiSaveNotice}
@@ -629,77 +604,62 @@ export function EasyModePage({
-
- setApiCustomModelId(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault(); - handleAddCustomModel(); - } - }} - placeholder={t("easyMode.api.customModelPlaceholder")} - aria-label={t("easyMode.api.customModelId")} - /> - - -
- - {displayedApiModels.length > 0 ? ( -
- {displayedApiModels.map((model) => { - const key = model.name.trim().toLowerCase(); - const selected = apiSelectedModels.some( - (item) => item.name.trim().toLowerCase() === key, - ); - return ( - - ); - })} + {apiTestedModels.length === 0 ? ( +
+
- ) : null} + ) : ( + <> +
+ {t("easyMode.api.modelListTitle")} +
-
+
+
+ {t("easyMode.api.modelListHint")} +
+
+ {apiTestedModels.map((model) => { + const key = model.name.trim().toLowerCase(); + const selected = apiSelectedModels.some( + (item) => item.name.trim().toLowerCase() === key, + ); + return ( + + ); + })} +
+
-
- +
+ +
+ + )}
diff --git a/src/styles.css b/src/styles.css index d80a9c8..06db982 100644 --- a/src/styles.css +++ b/src/styles.css @@ -10870,39 +10870,60 @@ body.table-col-resizing * { padding-top: 2px; } -.simple-mode-api-model-toolbar { - display: grid; - grid-template-columns: minmax(0, 1fr) auto auto; - align-items: center; - gap: 7px; +.simple-mode-api-model-fetch { + display: flex; + justify-content: flex-start; } -.simple-mode-api-model-toolbar .text-input { - box-sizing: border-box; - width: 100%; - min-height: 40px; - padding: 0 12px; - border: 1px solid var(--theme-d5d2cb); - border-radius: 8px; - background: var(--theme-faf9f5); - color: var(--theme-2d2a26); - font-size: var(--font-size-body); -} - -.simple-mode-api-model-toolbar .text-input:focus { - outline: none; - border-color: var(--ui-accent); - background: var(--theme-fffdf8); - box-shadow: 0 0 0 3px var(--ui-accent-shadow); -} - -.simple-mode-api-model-toolbar .secondary-button { - min-height: 40px; - gap: 7px; - padding-inline: 12px; +.simple-mode-api-fetch-button { + min-height: 36px; + padding-inline: 14px; white-space: nowrap; } +.simple-mode-api-model-heading { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + min-width: 0; +} + +.simple-mode-api-model-heading strong { + color: var(--theme-2d2a26); + font-size: var(--font-size-label); + font-weight: 700; +} + +.simple-mode-api-model-heading .secondary-button { + min-height: 36px; + flex: none; + padding-inline: 11px; + white-space: nowrap; +} + +.simple-mode-api-model-selection { + display: grid; + gap: 8px; +} + +.simple-mode-api-model-selection-heading { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 10px; +} + +.simple-mode-api-model-selection-heading strong { + color: var(--theme-2d2a26); + font-size: var(--font-size-label); +} + +.simple-mode-api-model-selection-heading span { + color: var(--theme-7a746c); + font-size: var(--font-size-caption); +} + .simple-mode-api-model-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); @@ -11659,11 +11680,11 @@ body.table-col-resizing * { } @media (max-width: 680px) { - .simple-mode-api-model-toolbar { - grid-template-columns: 1fr; + .simple-mode-api-model-heading { + align-items: flex-start; } - .simple-mode-api-model-toolbar .secondary-button { + .simple-mode-api-model-heading .secondary-button { width: 100%; }