From b38c5d451d5358a1ad22e4c14c2f878601738631 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Sun, 26 Oct 2025 02:32:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E5=90=88=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=20json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/claude_config.rs | 38 +++- src-tauri/src/commands/relay_stations.rs | 16 +- src/components/RelayStationManager.tsx | 236 +++++++++++++++++++++-- src/locales/en/common.json | 5 +- src/locales/zh/common.json | 5 +- src/main.tsx | 18 ++ 6 files changed, 290 insertions(+), 28 deletions(-) diff --git a/src-tauri/src/claude_config.rs b/src-tauri/src/claude_config.rs index 5e13853..04aed96 100644 --- a/src-tauri/src/claude_config.rs +++ b/src-tauri/src/claude_config.rs @@ -189,7 +189,7 @@ pub fn apply_relay_station_to_config(station: &RelayStation) -> Result<(), Strin // 读取当前配置 let mut config = read_claude_config()?; - // 仅更新这三个关键字段,保留其他所有配置不变: + // 更新三个关键字段: // 1. ANTHROPIC_BASE_URL config.env.anthropic_base_url = Some(station.api_url.clone()); @@ -199,6 +199,29 @@ pub fn apply_relay_station_to_config(station: &RelayStation) -> Result<(), Strin // 3. apiKeyHelper - 设置为 echo 格式 config.api_key_helper = Some(format!("echo '{}'", station.system_token)); + // 处理 adapter_config 中的自定义字段 + if let Some(ref adapter_config) = station.adapter_config { + log::info!("[CLAUDE_CONFIG] Applying adapter_config: {:?}", adapter_config); + + // 遍历 adapter_config 中的所有字段 + for (key, value) in adapter_config { + match key.as_str() { + // 已知的字段直接写入对应位置 + "model" => { + if let Some(model_value) = value.as_str() { + config.model = Some(model_value.to_string()); + log::info!("[CLAUDE_CONFIG] Set model: {}", model_value); + } + } + // 其他字段写入到 extra_fields 中 + _ => { + config.extra_fields.insert(key.clone(), value.clone()); + log::info!("[CLAUDE_CONFIG] Set extra field {}: {:?}", key, value); + } + } + } + } + // 如果是特定适配器,可能需要特殊处理 URL 格式 match station.adapter.as_str() { "packycode" => { @@ -213,7 +236,7 @@ pub fn apply_relay_station_to_config(station: &RelayStation) -> Result<(), Strin // 写入更新后的配置 write_claude_config(&config)?; - log::info!("已将中转站 {} 的 API 配置(apiKeyHelper, ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN)应用到 Claude 配置文件", station.name); + log::info!("已将中转站 {} 的 API 配置(apiKeyHelper, ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN)及自定义配置应用到 Claude 配置文件", station.name); Ok(()) } @@ -241,13 +264,22 @@ pub fn clear_relay_station_from_config() -> Result<(), String> { // 恢复原始的 apiKeyHelper(如果有备份的话) if let Some(backup) = backup_config { config.api_key_helper = backup.api_key_helper; + config.model = backup.model.clone(); // 如果备份中有 ANTHROPIC_AUTH_TOKEN,也恢复它 if backup.env.anthropic_auth_token.is_some() { config.env.anthropic_auth_token = backup.env.anthropic_auth_token; } + // 恢复备份中的 extra_fields + config.extra_fields = backup.extra_fields.clone(); + log::info!("[CLAUDE_CONFIG] Restored model from backup: {:?}", backup.model); + log::info!("[CLAUDE_CONFIG] Restored {} extra fields from backup", config.extra_fields.len()); } else { - // 如果没有备份,清除 apiKeyHelper + // 如果没有备份,清除 apiKeyHelper 和 model config.api_key_helper = None; + config.model = None; + // 清除所有额外的自定义字段 + config.extra_fields.clear(); + log::info!("[CLAUDE_CONFIG] Cleared model and all extra fields (no backup found)"); } // 写入更新后的配置 diff --git a/src-tauri/src/commands/relay_stations.rs b/src-tauri/src/commands/relay_stations.rs index 8294007..ba3907a 100644 --- a/src-tauri/src/commands/relay_stations.rs +++ b/src-tauri/src/commands/relay_stations.rs @@ -351,6 +351,9 @@ pub async fn relay_station_create( .trim_matches('"') .to_string(); + // 记录adapter_config日志 + log::info!("[CREATE] Received adapter_config: {:?}", request.adapter_config); + let adapter_config_str = request .adapter_config .as_ref() @@ -358,6 +361,8 @@ pub async fn relay_station_create( .transpose() .map_err(|_| i18n::t("relay_station.invalid_config"))?; + log::info!("[CREATE] Serialized adapter_config_str: {:?}", adapter_config_str); + // 如果要启用这个新中转站,先禁用所有其他中转站 if request.enabled { conn.execute("UPDATE relay_stations SET enabled = 0", []) @@ -408,7 +413,8 @@ pub async fn relay_station_create( updated_at: now, }; - log::info!("Created relay station: {} ({})", station.name, id); + log::info!("[CREATE] Created relay station: {} ({})", station.name, id); + log::info!("[CREATE] Final station.adapter_config: {:?}", station.adapter_config); Ok(station) } @@ -438,6 +444,9 @@ pub async fn relay_station_update( .trim_matches('"') .to_string(); + // 记录adapter_config日志 + log::info!("[UPDATE] Received adapter_config: {:?}", request.adapter_config); + let adapter_config_str = request .adapter_config .as_ref() @@ -445,6 +454,8 @@ pub async fn relay_station_update( .transpose() .map_err(|_| i18n::t("relay_station.invalid_config"))?; + log::info!("[UPDATE] Serialized adapter_config_str: {:?}", adapter_config_str); + // 如果要启用这个中转站,先禁用所有其他中转站 if request.enabled { conn.execute( @@ -504,7 +515,8 @@ pub async fn relay_station_update( updated_at: now, }; - log::info!("Updated relay station: {} ({})", station.name, request.id); + log::info!("[UPDATE] Updated relay station: {} ({})", station.name, request.id); + log::info!("[UPDATE] Final station.adapter_config: {:?}", station.adapter_config); Ok(station) } diff --git a/src/components/RelayStationManager.tsx b/src/components/RelayStationManager.tsx index 8cf16ed..a1fe294 100644 --- a/src/components/RelayStationManager.tsx +++ b/src/components/RelayStationManager.tsx @@ -853,6 +853,8 @@ const CreateStationDialog: React.FC<{ const [packycodeService, setPackycodeService] = useState('bus'); // 默认公交车 const [packycodeNode, setPackycodeNode] = useState('https://api.packycode.com'); // 默认节点(公交车用) const [packycodeTaxiNode, setPackycodeTaxiNode] = useState('https://share-api.packycode.com'); // 滴滴车节点 + const [customJson, setCustomJson] = useState(''); // 自定义JSON配置 + const [originalCustomJson] = useState(''); // 原始JSON配置(用于比较是否修改) // 测速弹出框状态 const [showSpeedTestModal, setShowSpeedTestModal] = useState(false); @@ -1012,11 +1014,43 @@ const CreateStationDialog: React.FC<{ try { setSubmitting(true); - + + // 处理自定义JSON配置 + let adapterConfig: Record = {}; + let shouldUpdateConfig = false; + + console.log('[DEBUG] Custom JSON Input:', customJson); + console.log('[DEBUG] Original Custom JSON:', originalCustomJson); + + if (customJson.trim()) { + // 用户输入了JSON内容 + try { + const parsed = JSON.parse(customJson); + adapterConfig = parsed; + shouldUpdateConfig = true; + console.log('[DEBUG] Parsed JSON config:', adapterConfig); + } catch (error) { + setFormToast({ message: t('relayStation.invalidJson'), type: "error" }); + return; + } + } else if (customJson === '' && originalCustomJson !== '') { + // 用户清空了输入框(原不为空,现为空) + shouldUpdateConfig = true; + adapterConfig = {}; + console.log('[DEBUG] User cleared custom config'); + } else if (customJson === '' && originalCustomJson === '') { + // 一直为空(创建新中转站或未修改) + shouldUpdateConfig = false; + console.log('[DEBUG] No custom config update needed'); + } + + console.log('[DEBUG] Should update config:', shouldUpdateConfig); + console.log('[DEBUG] Adapter config to send:', shouldUpdateConfig ? adapterConfig : 'undefined'); + // PackyCode 保存时自动选择最佳节点 if (formData.adapter === 'packycode') { let finalApiUrl = formData.api_url; - + if (packycodeService === 'bus') { // 公交车自动选择 const busNodes = [ @@ -1026,7 +1060,7 @@ const CreateStationDialog: React.FC<{ { url: "https://api-cf-pro.packycode.com", name: "☁️ 公交车 CF-Pro" }, { url: "https://api-us-cn2.packycode.com", name: "🇺🇸 公交车 US-CN2" } ]; - + await performSpeedTest(busNodes, (bestNode) => { finalApiUrl = bestNode.url; setPackycodeNode(bestNode.url); @@ -1040,26 +1074,38 @@ const CreateStationDialog: React.FC<{ { url: "https://share-api-cf-pro.packycode.com", name: "☁️ 滴滴车 CF-Pro" }, { url: "https://share-api-us-cn2.packycode.com", name: "🇺🇸 滴滴车 US-CN2" } ]; - + await performSpeedTest(taxiNodes, (bestNode) => { finalApiUrl = bestNode.url; setPackycodeTaxiNode(bestNode.url); }); } - + + const finalConfig = shouldUpdateConfig ? { + service_type: packycodeService, + ...adapterConfig + } : undefined; + + console.log('[DEBUG] Final adapter_config for PackyCode:', finalConfig); + // 使用选择的最佳节点创建中转站 await api.relayStationCreate({ ...formData, api_url: finalApiUrl, - adapter_config: { - service_type: packycodeService - } + adapter_config: finalConfig }); } else { + const finalConfig = shouldUpdateConfig ? adapterConfig : undefined; + + console.log('[DEBUG] Final adapter_config for non-PackyCode:', finalConfig); + // 非 PackyCode 适配器直接创建 - await api.relayStationCreate(formData); + await api.relayStationCreate({ + ...formData, + adapter_config: finalConfig + }); } - + onSuccess(); } catch (error) { console.error('Failed to create station:', error); @@ -1467,6 +1513,25 @@ const CreateStationDialog: React.FC<{

{t('relayStation.packycodeTokenNote')}

+ + {/* 自定义JSON配置 */} +
+
+ + {t('relayStation.customJsonOptional')} +
+