From 4cbf6379baf34e03b657686b037df95fbafa563f Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Tue, 3 Mar 2026 13:35:44 -0400 Subject: [PATCH] support fast clean options --- src-tauri/src/cleaner.rs | 59 +++++++++++++--------------- src-tauri/src/lib.rs | 4 +- src/App.vue | 84 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 106 insertions(+), 41 deletions(-) diff --git a/src-tauri/src/cleaner.rs b/src-tauri/src/cleaner.rs index ed17a05..11c1e21 100644 --- a/src-tauri/src/cleaner.rs +++ b/src-tauri/src/cleaner.rs @@ -174,11 +174,12 @@ pub struct CleaningConfig { pub name: String, pub path: String, pub filter_days: Option, + pub default_enabled: bool, } impl CleaningConfig { - fn new(name: &str, path: &str, filter_days: Option) -> Self { - Self { name: name.into(), path: path.into(), filter_days } + fn new(name: &str, path: &str, filter_days: Option, default_enabled: bool) -> Self { + Self { name: name.into(), path: path.into(), filter_days, default_enabled } } } @@ -188,33 +189,32 @@ fn get_fast_cleaning_configs() -> Vec { // 1. 用户临时文件 if let Ok(t) = std::env::var("TEMP") { - configs.push(CleaningConfig::new("用户临时文件", &t, None)); + configs.push(CleaningConfig::new("用户临时文件", &t, None, true)); } // 2. 系统临时文件 - configs.push(CleaningConfig::new("系统临时文件", "C:\\Windows\\Temp", None)); + configs.push(CleaningConfig::new("系统临时文件", "C:\\Windows\\Temp", None, true)); // 3. Windows 更新残留 (通常建议清理 10 天前的) - configs.push(CleaningConfig::new("Windows 更新残留", "C:\\Windows\\SoftwareDistribution\\Download", Some(10))); + configs.push(CleaningConfig::new("Windows 更新残留", "C:\\Windows\\SoftwareDistribution\\Download", Some(10), true)); - // 4. 传递优化缓存 - // configs.push(CleaningConfig::new( - // "传递优化缓存", - // "C:\\Windows\\ServiceProfiles\\NetworkService\\AppData\\Local\\Microsoft\\Windows\\DeliveryOptimization", - // None - // )); - - // 以后要添加新目录,只需在此处追加一行: - // configs.push(CleaningConfig::new("新目录名称", "C:\\路径", None)); + // 4. 内核转储文件 + configs.push(CleaningConfig::new("内核转储文件", "C:\\Windows\\LiveKernelReports", None, false)); configs } #[derive(Serialize, Clone)] -pub struct ScanItem { pub name: String, pub path: String, pub size: u64, pub count: u32 } +pub struct ScanItem { + pub name: String, + pub path: String, + pub size: u64, + pub count: u32, + pub enabled: bool, +} #[derive(Serialize)] -pub struct FastScanResult { pub items: Vec, pub total_size: String, pub total_count: u32 } +pub struct FastScanResult { pub items: Vec, total_size: String, total_count: u32 } pub async fn run_fast_scan() -> FastScanResult { let configs = get_fast_cleaning_configs(); @@ -228,7 +228,8 @@ pub async fn run_fast_scan() -> FastScanResult { name: config.name, path: config.path, size, - count + count, + enabled: config.default_enabled, }); total_bytes += size; total_count += count; @@ -274,27 +275,21 @@ pub struct CleanResult { pub fail_count: u32, } -pub async fn run_fast_clean(is_simulation: bool) -> Result { - if is_simulation { - return Ok(CleanResult { - total_freed: "0 B".into(), - success_count: 0, - fail_count: 0, - }); - } - +pub async fn run_fast_clean(selected_paths: Vec) -> Result { let configs = get_fast_cleaning_configs(); let mut success_count = 0; let mut fail_count = 0; let mut total_freed: u64 = 0; for config in configs { - let path = Path::new(&config.path); - if path.exists() { - let (freed, s, f) = clean_directory_contents(path, config.filter_days); - total_freed += freed; - success_count += s; - fail_count += f; + if selected_paths.contains(&config.path) { + let path = Path::new(&config.path); + if path.exists() { + let (freed, s, f) = clean_directory_contents(path, config.filter_days); + total_freed += freed; + success_count += s; + fail_count += f; + } } } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index cd169ee..935ec56 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -9,8 +9,8 @@ async fn start_fast_scan() -> cleaner::FastScanResult { } #[tauri::command] -async fn start_fast_clean(is_simulation: bool) -> Result { - cleaner::run_fast_clean(is_simulation).await +async fn start_fast_clean(selected_paths: Vec) -> Result { + cleaner::run_fast_clean(selected_paths).await } #[tauri::command] diff --git a/src/App.vue b/src/App.vue index a04d0dc..5f13283 100644 --- a/src/App.vue +++ b/src/App.vue @@ -10,7 +10,7 @@ const activeTab = ref('clean-c-fast'); const isCMenuOpen = ref(true); // --- 数据结构 --- -interface ScanItem { name: string; path: string; size: number; count: number; } +interface ScanItem { name: string; path: string; size: number; count: number; enabled: boolean; } interface FastScanResult { items: ScanItem[]; total_size: string; total_count: number; } interface CleanResult { total_freed: string; success_count: number; fail_count: number; } interface FileNode { @@ -115,10 +115,19 @@ async function startFastScan() { } async function startFastClean() { - if (isCleaning.value) return; + if (isCleaning.value || !fastScanResult.value) return; + const selectedPaths = fastScanResult.value.items + .filter(item => item.enabled) + .map(item => item.path); + + if (selectedPaths.length === 0) { + showAlert("未选择任何项", "请至少勾选一个需要清理的项目。", 'info'); + return; + } + isCleaning.value = true; try { - const res = await invoke("start_fast_clean", { isSimulation: false }); + const res = await invoke("start_fast_clean", { selectedPaths }); cleanResult.value = res; isCleanDone.value = true; fastScanResult.value = null; @@ -353,8 +362,20 @@ function splitSize(sizeStr: string | number) {

清理项详情

-
- {{ item.name }} +
+
+ + {{ item.name }} +
{{ formatItemSize(item.size) }}
正在深度扫描文件系统...
@@ -972,14 +993,63 @@ body { .detail-item { display: flex; justify-content: space-between; + align-items: center; padding: 16px 0; border-bottom: 1px solid #F5F5F7; font-size: 14px; color: #424245; - transition: transform 0.2s ease; + transition: all 0.2s ease; + cursor: pointer; } -.detail-item:hover { transform: translateX(4px); } +.detail-item:hover { background-color: #FAFAFB; padding-left: 8px; padding-right: 8px; border-radius: 8px; } +.detail-item.disabled { opacity: 0.5; } .detail-item:last-child { border-bottom: none; } + +.item-info { display: flex; align-items: center; gap: 12px; } + +/* --- 自定义复选框 --- */ +.checkbox-container { + display: block; + position: relative; + width: 20px; + height: 20px; + cursor: pointer; + user-select: none; +} + +.checkbox-container input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; width: 0; +} + +.checkmark { + position: absolute; + top: 0; left: 0; + height: 20px; width: 20px; + background-color: #F2F2F7; + border-radius: 6px; + transition: all 0.2s; + border: 1px solid #E5E5E7; +} + +.checkbox-container:hover input ~ .checkmark { background-color: #E5E5E7; } +.checkbox-container input:checked ~ .checkmark { background-color: var(--primary-color); border-color: var(--primary-color); } + +.checkmark:after { + content: ""; + position: absolute; + display: none; + left: 6px; top: 1px; + width: 5px; height: 10px; + border: solid white; + border-width: 0 2px 2px 0; + transform: rotate(45deg); +} + +.checkbox-container input:checked ~ .checkmark:after { display: block; } + .item-size { font-weight: 600; color: var(--primary-color); } .placeholder-page { padding-top: 120px; text-align: center; color: var(--text-sec); }