From 8a3133be43cdc5a8376fdc180ef17cc59174faaa Mon Sep 17 00:00:00 2001 From: farion1231 Date: Sat, 23 Aug 2025 20:15:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=20Tauri=20Commands?= =?UTF-8?q?=20-=20=E5=AE=8C=E6=88=90=E6=89=80=E6=9C=89=E4=BE=9B=E5=BA=94?= =?UTF-8?q?=E5=95=86=E5=92=8C=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86=E5=91=BD?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/commands.rs | 215 ++++++++++++++++++++++++++++++++++++++ src-tauri/src/lib.rs | 84 ++++++++++++--- 2 files changed, 285 insertions(+), 14 deletions(-) create mode 100644 src-tauri/src/commands.rs diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs new file mode 100644 index 0000000..dc818d4 --- /dev/null +++ b/src-tauri/src/commands.rs @@ -0,0 +1,215 @@ +use std::collections::HashMap; +use tauri::State; +use serde_json::Value; + +use crate::config::{ + get_claude_config_status, import_current_config_as_default, get_claude_settings_path, + ConfigStatus, +}; +use crate::provider::{Provider, ProviderManager}; +use crate::store::AppState; + +/// 获取所有供应商 +#[tauri::command] +pub async fn get_providers(state: State<'_, AppState>) -> Result, String> { + let manager = state.provider_manager.lock() + .map_err(|e| format!("获取锁失败: {}", e))?; + + Ok(manager.get_all_providers().clone()) +} + +/// 获取当前供应商ID +#[tauri::command] +pub async fn get_current_provider(state: State<'_, AppState>) -> Result { + let manager = state.provider_manager.lock() + .map_err(|e| format!("获取锁失败: {}", e))?; + + Ok(manager.current.clone()) +} + +/// 添加供应商 +#[tauri::command] +pub async fn add_provider( + state: State<'_, AppState>, + provider: Provider, +) -> Result { + let mut manager = state.provider_manager.lock() + .map_err(|e| format!("获取锁失败: {}", e))?; + + manager.add_provider(provider)?; + + // 保存配置 + drop(manager); // 释放锁 + state.save()?; + + Ok(true) +} + +/// 更新供应商 +#[tauri::command] +pub async fn update_provider( + state: State<'_, AppState>, + provider: Provider, +) -> Result { + let mut manager = state.provider_manager.lock() + .map_err(|e| format!("获取锁失败: {}", e))?; + + manager.update_provider(provider)?; + + // 保存配置 + drop(manager); // 释放锁 + state.save()?; + + Ok(true) +} + +/// 删除供应商 +#[tauri::command] +pub async fn delete_provider( + state: State<'_, AppState>, + id: String, +) -> Result { + let mut manager = state.provider_manager.lock() + .map_err(|e| format!("获取锁失败: {}", e))?; + + manager.delete_provider(&id)?; + + // 保存配置 + drop(manager); // 释放锁 + state.save()?; + + Ok(true) +} + +/// 切换供应商 +#[tauri::command] +pub async fn switch_provider( + state: State<'_, AppState>, + id: String, +) -> Result { + let mut manager = state.provider_manager.lock() + .map_err(|e| format!("获取锁失败: {}", e))?; + + manager.switch_provider(&id)?; + + // 保存配置 + drop(manager); // 释放锁 + state.save()?; + + Ok(true) +} + +/// 导入当前配置为默认供应商 +#[tauri::command] +pub async fn import_default_config( + state: State<'_, AppState>, +) -> Result { + // 导入配置 + let settings_config = import_current_config_as_default()?; + + // 创建默认供应商 + let provider = Provider::with_id( + "default".to_string(), + "default".to_string(), + settings_config, + None, + ); + + // 添加到管理器 + let mut manager = state.provider_manager.lock() + .map_err(|e| format!("获取锁失败: {}", e))?; + + manager.add_provider(provider)?; + + // 如果没有当前供应商,设置为 default + if manager.current.is_empty() { + manager.current = "default".to_string(); + } + + // 保存配置 + drop(manager); // 释放锁 + state.save()?; + + Ok(true) +} + +/// 获取 Claude Code 配置状态 +#[tauri::command] +pub async fn get_claude_config_status() -> Result { + Ok(get_claude_config_status()) +} + +/// 获取 Claude Code 配置文件路径 +#[tauri::command] +pub async fn get_claude_code_config_path() -> Result { + Ok(get_claude_settings_path().to_string_lossy().to_string()) +} + +/// 打开配置文件夹 +#[tauri::command] +pub async fn open_config_folder() -> Result { + let config_dir = crate::config::get_claude_config_dir(); + + // 确保目录存在 + if !config_dir.exists() { + std::fs::create_dir_all(&config_dir) + .map_err(|e| format!("创建目录失败: {}", e))?; + } + + // 在不同平台上打开文件夹 + #[cfg(target_os = "windows")] + { + std::process::Command::new("explorer") + .arg(&config_dir) + .spawn() + .map_err(|e| format!("打开文件夹失败: {}", e))?; + } + + #[cfg(target_os = "macos")] + { + std::process::Command::new("open") + .arg(&config_dir) + .spawn() + .map_err(|e| format!("打开文件夹失败: {}", e))?; + } + + #[cfg(target_os = "linux")] + { + std::process::Command::new("xdg-open") + .arg(&config_dir) + .spawn() + .map_err(|e| format!("打开文件夹失败: {}", e))?; + } + + Ok(true) +} + +/// 打开外部链接 +#[tauri::command] +pub async fn open_external(url: String) -> Result { + #[cfg(target_os = "windows")] + { + std::process::Command::new("cmd") + .args(&["/C", "start", "", &url]) + .spawn() + .map_err(|e| format!("打开链接失败: {}", e))?; + } + + #[cfg(target_os = "macos")] + { + std::process::Command::new("open") + .arg(&url) + .spawn() + .map_err(|e| format!("打开链接失败: {}", e))?; + } + + #[cfg(target_os = "linux")] + { + std::process::Command::new("xdg-open") + .arg(&url) + .spawn() + .map_err(|e| format!("打开链接失败: {}", e))?; + } + + Ok(true) +} \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 9c3118c..96f9a3d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,16 +1,72 @@ +mod config; +mod provider; +mod store; +mod commands; + +use store::AppState; + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { - tauri::Builder::default() - .setup(|app| { - if cfg!(debug_assertions) { - app.handle().plugin( - tauri_plugin_log::Builder::default() - .level(log::LevelFilter::Info) - .build(), - )?; - } - Ok(()) - }) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} + tauri::Builder::default() + .setup(|app| { + // 初始化日志 + if cfg!(debug_assertions) { + app.handle().plugin( + tauri_plugin_log::Builder::default() + .level(log::LevelFilter::Info) + .build(), + )?; + } + + // 初始化应用状态 + let app_state = AppState::new(); + + // 如果没有供应商且存在 Claude Code 配置,自动导入 + { + let manager = app_state.provider_manager.lock().unwrap(); + if manager.providers.is_empty() { + drop(manager); // 释放锁 + + let settings_path = config::get_claude_settings_path(); + if settings_path.exists() { + log::info!("检测到 Claude Code 配置,自动导入为默认供应商"); + + if let Ok(settings_config) = config::import_current_config_as_default() { + let mut manager = app_state.provider_manager.lock().unwrap(); + let provider = provider::Provider::with_id( + "default".to_string(), + "default".to_string(), + settings_config, + None, + ); + + if manager.add_provider(provider).is_ok() { + manager.current = "default".to_string(); + drop(manager); + let _ = app_state.save(); + log::info!("成功导入默认供应商"); + } + } + } + } + } + + Ok(()) + }) + .manage(AppState::new()) + .invoke_handler(tauri::generate_handler![ + commands::get_providers, + commands::get_current_provider, + commands::add_provider, + commands::update_provider, + commands::delete_provider, + commands::switch_provider, + commands::import_default_config, + commands::get_claude_config_status, + commands::get_claude_code_config_path, + commands::open_config_folder, + commands::open_external, + ]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} \ No newline at end of file