From 0cfd65cb909ba975a406e4aab704edfbe589ed26 Mon Sep 17 00:00:00 2001 From: farion1231 Date: Thu, 7 Aug 2025 21:28:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A6=96=E6=AC=A1=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E4=BD=93=E9=AA=8C=EF=BC=9A=E8=87=AA=E5=8A=A8=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E9=BB=98=E8=AE=A4=E4=BE=9B=E5=BA=94=E5=95=86=E4=B8=94?= =?UTF-8?q?=E8=AE=BE=E4=B8=BA=E9=80=89=E4=B8=AD=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 importCurrentConfigAsDefault 函数,创建 ID 为 'default' 的特殊供应商 - 默认供应商不生成独立配置文件,直接使用现有 settings.json - 首次启动时自动导入现有配置为默认供应商,并设为选中状态 - 切换到默认供应商时无需文件操作,直接使用原配置 - 删除默认供应商时保护原配置文件不被误删 - 简化 ImportConfigModal 组件,移除 isEmpty 相关逻辑 - 提升用户体验:无需手动操作,开箱即用 --- src/main/index.ts | 24 +++++++ src/main/preload.ts | 1 + src/main/services.ts | 63 ++++++++++++++++--- src/renderer/App.tsx | 21 ++++++- src/renderer/components/ImportConfigModal.tsx | 28 +++------ 5 files changed, 108 insertions(+), 29 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index 059fdf0..37660e8 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -9,6 +9,7 @@ import { deleteProviderConfig, sanitizeProviderName, importCurrentConfig, + importCurrentConfigAsDefault, getProviderConfigPath, fileExists, } from "./services"; @@ -234,6 +235,29 @@ ipcMain.handle("importCurrentConfig", async (_, name: string) => { } }); +ipcMain.handle("importCurrentConfigAsDefault", async () => { + try { + const result = await importCurrentConfigAsDefault(); + + if (result.success && result.provider) { + // 将默认供应商添加到store中 + const providers = store.get("providers", {} as Record); + providers[result.provider.id] = result.provider; + await store.set("providers", providers); + + // 设置为当前选中的供应商 + await store.set("current", result.provider.id); + + return { success: true, providerId: result.provider.id }; + } + + return result; + } catch (error: any) { + console.error("导入默认配置失败:", error); + return { success: false }; + } +}); + ipcMain.handle("getClaudeCodeConfigPath", () => { return getClaudeCodeConfig().path; }); diff --git a/src/main/preload.ts b/src/main/preload.ts index cf8cc27..aa17ef0 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -9,6 +9,7 @@ contextBridge.exposeInMainWorld('electronAPI', { updateProvider: (provider: Provider) => ipcRenderer.invoke('updateProvider', provider), switchProvider: (providerId: string) => ipcRenderer.invoke('switchProvider', providerId), importCurrentConfig: (name: string) => ipcRenderer.invoke('importCurrentConfig', name), + importCurrentConfigAsDefault: () => ipcRenderer.invoke('importCurrentConfigAsDefault'), getClaudeCodeConfigPath: () => ipcRenderer.invoke('getClaudeCodeConfigPath'), selectConfigFile: () => ipcRenderer.invoke('selectConfigFile'), openExternal: (url: string) => ipcRenderer.invoke('openExternal', url) diff --git a/src/main/services.ts b/src/main/services.ts index 1ec23f4..9b39baf 100644 --- a/src/main/services.ts +++ b/src/main/services.ts @@ -84,11 +84,18 @@ export async function switchProvider( ): Promise { try { const { path: settingsPath, dir: configDir } = getClaudeCodeConfig(); - const newSettingsPath = getProviderConfigPath(provider.id, provider.name); // 确保目录存在 await fs.mkdir(configDir, { recursive: true }); + // 特殊处理:如果切换到默认供应商(id="default"),直接使用现有的 settings.json + if (provider.id === "default") { + console.log(`切换到默认供应商,使用现有配置文件`); + return true; + } + + const newSettingsPath = getProviderConfigPath(provider.id, provider.name); + // 检查目标配置文件是否存在 if (!(await fileExists(newSettingsPath))) { console.error(`供应商配置文件不存在: ${newSettingsPath}`); @@ -98,12 +105,15 @@ export async function switchProvider( // 1. 如果当前存在settings.json,先备份到当前供应商的配置文件 if (await fileExists(settingsPath)) { if (currentProviderId && providers && providers[currentProviderId]) { - const currentProvider = providers[currentProviderId]; - const currentProviderPath = getProviderConfigPath( - currentProviderId, - currentProvider.name - ); - await fs.rename(settingsPath, currentProviderPath); + // 如果当前是默认供应商,不需要备份(因为 settings.json 就是它的配置) + if (currentProviderId !== "default") { + const currentProvider = providers[currentProviderId]; + const currentProviderPath = getProviderConfigPath( + currentProviderId, + currentProvider.name + ); + await fs.rename(settingsPath, currentProviderPath); + } } else { // 如果没有当前供应商ID,创建临时备份 const backupPath = path.join( @@ -180,6 +190,39 @@ export async function importCurrentConfig( } } +/** + * 导入当前配置为默认供应商(不生成独立配置文件) + */ +export async function importCurrentConfigAsDefault(): Promise<{ success: boolean; provider?: Provider }> { + try { + const { path: settingsPath } = getClaudeCodeConfig(); + + // 检查当前配置是否存在 + if (!(await fileExists(settingsPath))) { + return { success: false }; + } + + // 读取当前配置 + const configContent = await fs.readFile(settingsPath, "utf-8"); + const settingsConfig = JSON.parse(configContent); + + // 创建默认供应商对象 + const provider: Provider = { + id: "default", + name: "默认", + settingsConfig: settingsConfig, + createdAt: Date.now(), + updatedAt: Date.now(), + }; + + console.log(`已导入当前配置为默认供应商(不生成独立文件)`); + return { success: true, provider }; + } catch (error: any) { + console.error("导入默认配置失败:", error); + return { success: false }; + } +} + /** * 删除供应商配置文件 */ @@ -188,6 +231,12 @@ export async function deleteProviderConfig( providerName?: string ): Promise { try { + // 特殊处理:默认供应商不删除配置文件 + if (providerId === "default") { + console.log("默认供应商不删除配置文件"); + return true; + } + const providerConfigPath = getProviderConfigPath(providerId, providerName); if (await fileExists(providerConfigPath)) { diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index ac8766c..bc82747 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -76,9 +76,9 @@ function App() { setProviders(loadedProviders); setCurrentProviderId(currentId); - // 如果供应商列表为空,自动弹出导入配置对话框 + // 如果供应商列表为空,尝试自动导入现有配置为"默认"供应商 if (Object.keys(loadedProviders).length === 0) { - setIsImportModalOpen(true); + await handleAutoImportDefault(); } }; @@ -163,6 +163,22 @@ function App() { } } + // 自动导入现有配置为"默认"供应商 + const handleAutoImportDefault = async () => { + try { + const result = await window.electronAPI.importCurrentConfigAsDefault() + + if (result.success) { + await loadProviders() + showNotification("已自动导入现有配置为默认供应商", "success", 3000) + } + // 如果导入失败(比如没有现有配置),静默处理,不显示错误 + } catch (error) { + console.error('自动导入默认配置失败:', error) + // 静默处理,不影响用户体验 + } + } + const handleSelectConfigFile = async () => { const selectedPath = await window.electronAPI.selectConfigFile(); if (selectedPath) { @@ -233,7 +249,6 @@ function App() { setIsImportModalOpen(false)} - isEmpty={Object.keys(providers).length === 0} /> )} diff --git a/src/renderer/components/ImportConfigModal.tsx b/src/renderer/components/ImportConfigModal.tsx index c7af647..2659690 100644 --- a/src/renderer/components/ImportConfigModal.tsx +++ b/src/renderer/components/ImportConfigModal.tsx @@ -4,10 +4,9 @@ import './AddProviderModal.css' interface ImportConfigModalProps { onImport: (name: string) => void onClose: () => void - isEmpty?: boolean // 供应商列表是否为空 } -const ImportConfigModal: React.FC = ({ onImport, onClose, isEmpty = false }) => { +const ImportConfigModal: React.FC = ({ onImport, onClose }) => { const [name, setName] = useState('') const [error, setError] = useState('') @@ -26,22 +25,13 @@ const ImportConfigModal: React.FC = ({ onImport, onClose return (
-

{isEmpty ? '供应商列表为空' : '导入当前配置'}

+

导入当前配置

- {isEmpty ? ( -

- 当前还没有任何供应商配置。您可以将当前的 Claude Code 配置 - ~/.claude/settings.json 导入为一个供应商配置。 -
- 注意:这不会修改您当前的配置文件。 -

- ) : ( -

- 将当前的 ~/.claude/settings.json 配置文件导入为一个新的供应商。 -
- 注意:这不会修改您当前的配置文件。 -

- )} +

+ 将当前的 ~/.claude/settings.json 配置文件导入为一个新的供应商。 +
+ 注意:这不会修改您当前的配置文件。 +

{error &&
{error}
} @@ -54,7 +44,7 @@ const ImportConfigModal: React.FC = ({ onImport, onClose name="name" value={name} onChange={(e) => setName(e.target.value)} - placeholder={isEmpty ? "例如:我的默认配置" : "例如:我的当前配置"} + placeholder="例如:我的当前配置" required autoFocus /> @@ -62,7 +52,7 @@ const ImportConfigModal: React.FC = ({ onImport, onClose