diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 10453ff..80e76d2 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -110,6 +110,7 @@ struct ZcaResult { #[derive(serde::Deserialize)] struct ExportImageTask { path: String, + output_filename: Option, manual_position: Option, scale: Option, opacity: Option, @@ -251,7 +252,12 @@ async fn export_batch(images: Vec, watermark: WatermarkSettings } // END IF MODE == ADD // Save - let file_name = input_path.file_name().unwrap_or_default(); + // Prioritize explicitly provided output filename (from original path), fall back to input filename + let file_name = match &task.output_filename { + Some(name) => std::ffi::OsStr::new(name), + None => input_path.file_name().unwrap_or_default() + }; + let output_path = Path::new(&output_dir).join(file_name); let output_path = Path::new(&output_dir).join(file_name); // Handle format specific saving diff --git a/src/App.vue b/src/App.vue index 1837287..e449dde 100644 --- a/src/App.vue +++ b/src/App.vue @@ -50,13 +50,20 @@ async function exportBatch() { isExporting.value = true; // Map images to include manual settings - const exportTasks = store.images.map(img => ({ - path: img.path, - manual_position: img.manualPosition || null, - scale: img.scale || null, - opacity: img.opacity || null, - color: img.color || null - })); + const exportTasks = store.images.map(img => { + // Extract filename from originalPath to ensure export uses original name + // Handles both Windows (\) and Unix (/) separators + const originalName = img.originalPath.split(/[/\\]/).pop() || "image.png"; + + return { + path: img.path, + output_filename: originalName, + manual_position: img.manualPosition || null, + scale: img.scale || null, + opacity: img.opacity || null, + color: img.color || null + }; + }); // Pass dummy globals for rust struct compatibility // The backend struct fields are named _manual_override and _manual_position diff --git a/src/components/SettingsPanel.vue b/src/components/SettingsPanel.vue index 89ccbe1..4055854 100644 --- a/src/components/SettingsPanel.vue +++ b/src/components/SettingsPanel.vue @@ -232,7 +232,12 @@ const applyAll = () => {
AI 修复功能已就绪。 - 正在处理中,请稍候... + + 正在处理: {{ store.progress.current }} / {{ store.progress.total }} + + + 正在检测: {{ store.progress.current }} / {{ store.progress.total }} +
diff --git a/src/stores/gallery.ts b/src/stores/gallery.ts index 7a94385..d112b3d 100644 --- a/src/stores/gallery.ts +++ b/src/stores/gallery.ts @@ -54,6 +54,7 @@ export const useGalleryStore = defineStore("gallery", () => { const isDetecting = ref(false); const isProcessing = ref(false); + const progress = ref({ current: 0, total: 0 }); const selectedImage = computed(() => { if (selectedIndex.value >= 0 && selectedIndex.value < images.value.length) { @@ -136,8 +137,10 @@ export const useGalleryStore = defineStore("gallery", () => { async function detectCurrentWatermark() { if (selectedIndex.value < 0 || !images.value[selectedIndex.value]) return; isDetecting.value = true; + progress.value = { current: 0, total: 1 }; try { await detectWatermarkForImage(images.value[selectedIndex.value]); + progress.value.current = 1; } finally { isDetecting.value = false; } @@ -146,11 +149,15 @@ export const useGalleryStore = defineStore("gallery", () => { async function detectAllWatermarks() { if (images.value.length === 0) return; isDetecting.value = true; + progress.value = { current: 0, total: images.value.length }; try { const batchSize = 5; for (let i = 0; i < images.value.length; i += batchSize) { - const batch = images.value.slice(i, i + batchSize).map(img => detectWatermarkForImage(img)); + const batch = images.value.slice(i, i + batchSize).map(async (img) => { + await detectWatermarkForImage(img); + progress.value.current++; + }); await Promise.all(batch); } } finally { @@ -211,8 +218,10 @@ export const useGalleryStore = defineStore("gallery", () => { if (!img) return; isProcessing.value = true; + progress.value = { current: 0, total: 1 }; try { await runInpaintingForImage(img); + progress.value.current = 1; } catch (e) { alert("处理失败: " + e); } finally { @@ -225,10 +234,12 @@ export const useGalleryStore = defineStore("gallery", () => { if (candidates.length === 0) return; isProcessing.value = true; + progress.value = { current: 0, total: candidates.length }; try { // Sequential processing to avoid freezing UI or overloading backend for (const img of candidates) { await runInpaintingForImage(img); + progress.value.current++; } alert("批量处理完成!"); } catch (e) { @@ -285,6 +296,7 @@ export const useGalleryStore = defineStore("gallery", () => { brushSettings, isDetecting, isProcessing, + progress, setImages, selectImage, updateWatermarkSettings,