diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index cc0f3c1..879a95d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -17,7 +17,7 @@ pub struct LogPayload { pub timestamp: String, pub command: String, pub output: String, - pub status: String, // "info", "success", "error" + pub status: String, } pub fn emit_log(handle: &AppHandle, command: &str, output: &str, status: &str) { @@ -30,6 +30,14 @@ pub fn emit_log(handle: &AppHandle, command: &str, output: &str, status: &str) { }); } +#[tauri::command] +async fn initialize_app(app: AppHandle) -> Result { + // 执行耗时的环境配置 + tokio::task::spawn_blocking(move || { + ensure_winget_dependencies(&app).map(|_| true) + }).await.unwrap_or(Err("Initialization Task Panicked".to_string())) +} + #[tauri::command] fn get_essentials(app: AppHandle) -> Vec { let app_data_dir = app.path().app_data_dir().unwrap_or_default(); @@ -86,7 +94,6 @@ async fn install_software(id: String, state: State<'_, AppState>) -> Result<(), #[tauri::command] fn get_logs_history() -> Vec { - // 暂时返回空,后续可以考虑存储 vec![] } @@ -105,15 +112,8 @@ pub fn run() { let (tx, mut rx) = mpsc::channel::(100); app.manage(AppState { install_tx: tx }); - // 环境初始化逻辑 - let init_handle = handle.clone(); - tauri::async_runtime::spawn(async move { - let _ = tokio::task::spawn_blocking(move || { - let _ = ensure_winget_dependencies(&init_handle); - }).await; - }); + // 移除了在 setup 中直接执行异步 init 的逻辑,改为由前端指令触发 - // 安装队列 tauri::async_runtime::spawn(async move { while let Some(id) = rx.recv().await { let _ = handle.emit("install-status", InstallProgress { @@ -161,6 +161,7 @@ pub fn run() { Ok(()) }) .invoke_handler(tauri::generate_handler![ + initialize_app, get_essentials, get_all_software, get_updates, diff --git a/src-tauri/src/winget.rs b/src-tauri/src/winget.rs index afcafcd..222a384 100644 --- a/src-tauri/src/winget.rs +++ b/src-tauri/src/winget.rs @@ -26,10 +26,9 @@ struct WingetPackage { } pub fn ensure_winget_dependencies(handle: &AppHandle) -> Result<(), String> { - emit_log(handle, "Check Environment", "Initializing system components...", "info"); + emit_log(handle, "Check Environment", "Initializing system components and updating sources...", "info"); let setup_script = r#" - # 设置容错 $ErrorActionPreference = 'SilentlyContinue' Write-Output "Step 1: Enabling TLS 1.2" @@ -42,23 +41,24 @@ pub fn ensure_winget_dependencies(handle: &AppHandle) -> Result<(), String> { Write-Output "Step 3: Checking NuGet provider" $provider = Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue if ($null -eq $provider) { - Write-Output "Installing NuGet provider..." - Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false -ErrorAction SilentlyContinue + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false } Write-Output "Step 4: Configuring Repository Trust" - Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted -ErrorAction SilentlyContinue + Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted Write-Output "Step 5: Setting Execution Policy" - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force -ErrorAction SilentlyContinue + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force Write-Output "Step 6: Checking Microsoft.WinGet.Client" if (-not (Get-Module -ListAvailable Microsoft.WinGet.Client)) { - Write-Output "Installing Winget Client module (this may take 1-2 minutes)..." + Write-Output "Installing Winget Client module..." Install-Module -Name Microsoft.WinGet.Client -Force -AllowClobber -Scope CurrentUser -Confirm:$false - } else { - Write-Output "Winget Client module is already present." } + + Write-Output "Step 7: Updating Winget Sources (apt-get update style)" + # 这一步非常关键,确保 winget 的本地数据库是最新的 + winget source update --accept-source-agreements "#; let output = Command::new("powershell") @@ -70,7 +70,7 @@ pub fn ensure_winget_dependencies(handle: &AppHandle) -> Result<(), String> { Ok(out) => { let msg = String::from_utf8_lossy(&out.stdout).to_string(); let err = String::from_utf8_lossy(&out.stderr).to_string(); - // 只要最终模块存在,就认为成功,忽略过程中的次要警告 + let check_final = Command::new("powershell") .args(["-NoProfile", "-Command", "Get-Module -ListAvailable Microsoft.WinGet.Client"]) .creation_flags(0x08000000) @@ -79,7 +79,7 @@ pub fn ensure_winget_dependencies(handle: &AppHandle) -> Result<(), String> { let is_success = check_final.map(|o| !o.stdout.is_empty()).unwrap_or(false); if is_success { - emit_log(handle, "Environment Setup", "Winget module is ready.", "success"); + emit_log(handle, "Environment Setup", "Winget module and sources are ready.", "success"); Ok(()) } else { emit_log(handle, "Environment Setup Error", &format!("OUT: {}\nERR: {}", msg, err), "error"); diff --git a/src/App.vue b/src/App.vue index a1e1d4f..1f00308 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,18 +1,34 @@ diff --git a/src/components/SplashScreen.vue b/src/components/SplashScreen.vue new file mode 100644 index 0000000..549383d --- /dev/null +++ b/src/components/SplashScreen.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/src/store/software.ts b/src/store/software.ts index 95beb7a..3121190 100644 --- a/src/store/software.ts +++ b/src/store/software.ts @@ -20,6 +20,8 @@ export const useSoftwareStore = defineStore('software', { selectedUpdateIds: [] as string[], logs: [] as LogEntry[], loading: false, + isInitialized: false, + initStatus: '正在检查系统环境...', lastFetched: 0 }), getters: { @@ -47,6 +49,20 @@ export const useSoftwareStore = defineStore('software', { sortedAllSoftware: (state) => [...state.allSoftware].sort(sortByName) }, actions: { + async initializeApp() { + if (this.isInitialized) return; + + this.initStatus = '正在同步 Winget 模块...'; + try { + await invoke('initialize_app'); + this.isInitialized = true; + } catch (err) { + this.initStatus = '环境配置失败,请检查运行日志'; + console.error('Init failed:', err); + // 即使失败也允许进入,让用户看日志 + setTimeout(() => { this.isInitialized = true; }, 2000); + } + }, toggleSelection(id: string, type: 'essential' | 'update') { const list = type === 'essential' ? this.selectedEssentialIds : this.selectedUpdateIds; const index = list.indexOf(id); @@ -151,10 +167,8 @@ export const useSoftwareStore = defineStore('software', { } }) - // 监听日志事件 listen('log-event', (event: any) => { this.logs.unshift(event.payload as LogEntry); - // 限制日志条数,防止内存溢出 if (this.logs.length > 200) this.logs.pop(); }) }