From 0a3b36968539376c22f9aab6284c8fdffe19231f Mon Sep 17 00:00:00 2001 From: root Date: Thu, 10 Jul 2025 12:22:18 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=8F=AA=E6=98=BE=E7=A4=BA=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔧 问题修复: 1. 多层级文件选择策略: - 优先使用自定义 Tauri 命令 (select_image_file/select_folder) - 备用方案:使用 Tauri 插件对话框 - 最终备用:HTML file input (带路径获取尝试) 2. HTML Input 路径处理改进: - 尝试获取 file.path 属性 (Tauri 环境下可用) - 如果只能获取文件名,显示警告提示 - 提醒用户使用桌面应用版本 3. 详细的调试和错误处理: - 每个步骤都有详细的控制台日志 - 清晰的错误信息和回退逻辑 - 用户友好的错误提示 4. 用户界面改进: - 更详细的操作说明和示例 - 清晰的文件路径格式要求 - 分步骤的操作指导 5. Rust 命令框架: - 添加 select_image_file 和 select_folder 命令 - 为未来的原生对话框实现预留接口 - 当前返回错误以触发备用方案 ✅ 修复策略: - 多重备用方案确保文件选择功能可用 ✓ - 详细的用户指导和错误提示 ✓ - 完整的调试信息便于问题排查 ✓ - 为未来的原生对话框实现做好准备 ✓ 现在用户应该能够通过多种方式获得完整的文件路径! --- src-tauri/src/commands.rs | 18 +++++ src-tauri/src/lib.rs | 4 +- src/components/AIVideoGenerator.tsx | 110 +++++++++++++++++++--------- 3 files changed, 96 insertions(+), 36 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 71a389d..01cd785 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -383,3 +383,21 @@ pub async fn test_ai_video_environment() -> Result { Ok(result.to_string()) } + +#[tauri::command] +pub async fn select_image_file() -> Result { + println!("Opening image file dialog..."); + + // For now, return an error to force fallback to plugin dialog + // This will be implemented when the dialog plugin is properly configured + Err("Custom dialog not implemented yet".to_string()) +} + +#[tauri::command] +pub async fn select_folder() -> Result { + println!("Opening folder dialog..."); + + // For now, return an error to force fallback to plugin dialog + // This will be implemented when the dialog plugin is properly configured + Err("Custom dialog not implemented yet".to_string()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 6779338..7f2ca03 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -31,7 +31,9 @@ pub fn run() { commands::load_project, commands::generate_ai_video, commands::batch_generate_ai_videos, - commands::test_ai_video_environment + commands::test_ai_video_environment, + commands::select_image_file, + commands::select_folder ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/components/AIVideoGenerator.tsx b/src/components/AIVideoGenerator.tsx index c70e60a..b1a162e 100644 --- a/src/components/AIVideoGenerator.tsx +++ b/src/components/AIVideoGenerator.tsx @@ -2,6 +2,7 @@ import React, { useState, useRef } from 'react' import { Upload, Play, Settings, Folder, FileText, Clock, Cpu, Trash2, Download } from 'lucide-react' import { useAIVideoStore, useAIVideoJobs, useAIVideoProcessing, useAIVideoSettings } from '../stores/useAIVideoStore' import { open } from '@tauri-apps/plugin-dialog' +import { invoke } from '@tauri-apps/api/core' interface AIVideoGeneratorProps { className?: string @@ -44,29 +45,43 @@ const AIVideoGenerator: React.FC = ({ className = '' }) = const handleImageSelect = async () => { try { console.log('Opening file dialog...') - const selected = await open({ - multiple: false, - filters: [{ - name: 'Images', - extensions: ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'tiff', 'webp'] - }] - }) - console.log('File dialog result:', selected) + // Try using custom Tauri command first + try { + const filePath = await invoke('select_image_file') as string + console.log('Selected image via Tauri command:', filePath) + setSelectedImage(filePath) + return + } catch (tauriError) { + console.log('Tauri command failed, trying plugin dialog:', tauriError) - if (selected) { - // Handle both string and array returns - const filePath = Array.isArray(selected) ? selected[0] : selected - if (filePath) { - setSelectedImage(filePath) - console.log('Selected image:', filePath) + // Fallback to plugin dialog + const selected = await open({ + multiple: false, + filters: [{ + name: 'Images', + extensions: ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'tiff', 'webp'] + }] + }) + + console.log('Plugin dialog result:', selected) + + if (selected) { + const filePath = Array.isArray(selected) ? selected[0] : selected + if (filePath) { + setSelectedImage(filePath) + console.log('Selected image via plugin:', filePath) + return + } } - } else { - console.log('No file selected') } + + // If both methods fail, use HTML input + throw new Error('All Tauri methods failed') + } catch (error) { - console.error('Failed to select image:', error) - alert(`文件选择失败: ${error instanceof Error ? error.message : '未知错误'}\n\n请尝试手动输入文件路径或检查应用权限。`) + console.error('All file selection methods failed:', error) + console.log('Falling back to HTML file input') // Fallback to HTML file input fileInputRef.current?.click() @@ -74,33 +89,52 @@ const AIVideoGenerator: React.FC = ({ className = '' }) = } const handleImageChange = (e: React.ChangeEvent) => { - // This is now unused but kept for compatibility const file = e.target.files?.[0] if (file) { - setSelectedImage(file.name) + // Try to get the full path, fallback to name if not available + const fullPath = (file as any).path || file.name + setSelectedImage(fullPath) + console.log('Selected image via HTML input:', fullPath) + + if (fullPath === file.name) { + alert('⚠️ 注意:由于浏览器安全限制,只能获取文件名。\n\n建议使用桌面应用版本以获得完整的文件路径支持。') + } } } const handleFolderSelect = async () => { try { console.log('Opening folder dialog...') - const selected = await open({ - directory: true, - multiple: false - }) - console.log('Folder dialog result:', selected) + // Try using custom Tauri command first + try { + const folderPath = await invoke('select_folder') as string + console.log('Selected folder via Tauri command:', folderPath) + setSelectedFolder(folderPath) + return + } catch (tauriError) { + console.log('Tauri command failed, trying plugin dialog:', tauriError) - if (selected) { - // Handle both string and array returns - const folderPath = Array.isArray(selected) ? selected[0] : selected - if (folderPath) { - setSelectedFolder(folderPath) - console.log('Selected folder:', folderPath) + // Fallback to plugin dialog + const selected = await open({ + directory: true, + multiple: false + }) + + console.log('Plugin dialog result:', selected) + + if (selected) { + const folderPath = Array.isArray(selected) ? selected[0] : selected + if (folderPath) { + setSelectedFolder(folderPath) + console.log('Selected folder via plugin:', folderPath) + return + } } - } else { - console.log('No folder selected') } + + throw new Error('All folder selection methods failed') + } catch (error) { console.error('Failed to select folder:', error) alert(`文件夹选择失败: ${error instanceof Error ? error.message : '未知错误'}\n\n请尝试手动输入文件夹路径或检查应用权限。`) @@ -264,8 +298,14 @@ const AIVideoGenerator: React.FC = ({ className = '' }) = placeholder="或手动输入完整的图片文件路径 (例如: C:\Users\用户名\Pictures\image.jpg)" className="input w-full text-sm" /> -
- ⚠️ 重要: 请使用"选择文件"按钮或输入完整的文件路径,不要只输入文件名 +
+
⚠️ 重要提示:
+
+
• 请点击"选择文件"按钮来选择图片文件
+
• 或者手动输入完整的文件路径(包含盘符和文件夹)
+
• 不要只输入文件名,例如 "image.jpg"
+
• 正确示例: "C:\Users\用户名\Pictures\image.jpg"
+