fix: 直接修复 Tauri 对话框插件,移除回退机制
🎯 核心修复: 1. 正确实现 Tauri 对话框命令: - 使用 tauri_plugin_dialog::DialogExt 正确的 API - 实现 select_image_file 和 select_folder 命令 - 使用 blocking_pick_file 和 blocking_pick_folder 方法 - 修复路径转换问题 (FilePath.to_string()) 2. 简化前端文件选择逻辑: - 移除复杂的多重备用方案 - 直接调用 Tauri 命令 invoke('select_image_file') - 清晰的错误处理,不再回退到 HTML input - 统一的文件和文件夹选择逻辑 3. 清理代码: - 移除不需要的 HTML input 元素 - 移除 useRef 和相关的备用代码 - 移除 @tauri-apps/plugin-dialog 直接导入 - 清理未使用的导入和函数 4. 配置优化: - 确保 Tauri 对话框插件正确注册 - 移除不必要的配置复杂性 - 专注于核心功能实现 ✅ 修复效果: - 文件选择:直接使用原生 Tauri 对话框 ✓ - 路径获取:确保返回完整的文件路径 ✓ - 代码简洁:移除复杂的回退逻辑 ✓ - 错误处理:清晰的错误信息 ✓ 现在文件选择功能应该直接工作,返回完整的文件路径!
This commit is contained in:
parent
0a3b369685
commit
a6dbd37526
|
|
@ -385,19 +385,48 @@ pub async fn test_ai_video_environment() -> Result<String, String> {
|
|||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn select_image_file() -> Result<String, String> {
|
||||
pub async fn select_image_file(app: tauri::AppHandle) -> Result<String, String> {
|
||||
use tauri_plugin_dialog::DialogExt;
|
||||
|
||||
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())
|
||||
let file_path = app.dialog()
|
||||
.file()
|
||||
.add_filter("Images", &["jpg", "jpeg", "png", "bmp", "gif", "tiff", "webp"])
|
||||
.blocking_pick_file();
|
||||
|
||||
match file_path {
|
||||
Some(path) => {
|
||||
let path_str = path.to_string();
|
||||
println!("Selected image file: {}", path_str);
|
||||
Ok(path_str)
|
||||
}
|
||||
None => {
|
||||
println!("No file selected");
|
||||
Err("No file selected".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn select_folder() -> Result<String, String> {
|
||||
pub async fn select_folder(app: tauri::AppHandle) -> Result<String, String> {
|
||||
use tauri_plugin_dialog::{DialogExt};
|
||||
|
||||
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())
|
||||
let folder_path = app.dialog()
|
||||
.file()
|
||||
.blocking_pick_folder();
|
||||
|
||||
match folder_path {
|
||||
Some(path) => {
|
||||
let path_str = path.to_string();
|
||||
println!("Selected folder: {}", path_str);
|
||||
Ok(path_str)
|
||||
}
|
||||
None => {
|
||||
println!("No folder selected");
|
||||
Err("No folder selected".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useState, useRef } from 'react'
|
||||
import { Upload, Play, Settings, Folder, FileText, Clock, Cpu, Trash2, Download } from 'lucide-react'
|
||||
import React, { useState } from 'react'
|
||||
import { Upload, Play, 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 {
|
||||
|
|
@ -9,8 +8,6 @@ interface AIVideoGeneratorProps {
|
|||
}
|
||||
|
||||
const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) => {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
const folderInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
// State
|
||||
const [mode, setMode] = useState<'single' | 'batch'>('single')
|
||||
|
|
@ -45,115 +42,30 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
|||
const handleImageSelect = async () => {
|
||||
try {
|
||||
console.log('Opening file dialog...')
|
||||
|
||||
// Try using custom Tauri command first
|
||||
try {
|
||||
const filePath = await invoke('select_image_file') as string
|
||||
console.log('Selected image via Tauri command:', filePath)
|
||||
console.log('Selected image:', filePath)
|
||||
setSelectedImage(filePath)
|
||||
return
|
||||
} catch (tauriError) {
|
||||
console.log('Tauri command failed, trying plugin dialog:', tauriError)
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If both methods fail, use HTML input
|
||||
throw new Error('All Tauri methods failed')
|
||||
|
||||
} catch (error) {
|
||||
console.error('All file selection methods failed:', error)
|
||||
console.log('Falling back to HTML file input')
|
||||
|
||||
// Fallback to HTML file input
|
||||
fileInputRef.current?.click()
|
||||
console.error('Failed to select image:', error)
|
||||
alert(`文件选择失败: ${error instanceof Error ? error.message : '未知错误'}`)
|
||||
}
|
||||
}
|
||||
|
||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0]
|
||||
if (file) {
|
||||
// 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...')
|
||||
|
||||
// Try using custom Tauri command first
|
||||
try {
|
||||
const folderPath = await invoke('select_folder') as string
|
||||
console.log('Selected folder via Tauri command:', folderPath)
|
||||
console.log('Selected folder:', folderPath)
|
||||
setSelectedFolder(folderPath)
|
||||
return
|
||||
} catch (tauriError) {
|
||||
console.log('Tauri command failed, trying plugin dialog:', tauriError)
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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请尝试手动输入文件夹路径或检查应用权限。`)
|
||||
|
||||
// Fallback to HTML folder input
|
||||
folderInputRef.current?.click()
|
||||
alert(`文件夹选择失败: ${error instanceof Error ? error.message : '未知错误'}`)
|
||||
}
|
||||
}
|
||||
|
||||
const handleFolderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// This is now unused but kept for compatibility
|
||||
const files = e.target.files
|
||||
if (files && files.length > 0) {
|
||||
const firstFile = files[0]
|
||||
const path = (firstFile as any).webkitRelativePath || firstFile.name
|
||||
const folderPath = path.split('/')[0]
|
||||
setSelectedFolder(folderPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handle generation
|
||||
const handleGenerate = async () => {
|
||||
|
|
@ -308,13 +220,7 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleImageChange}
|
||||
className="hidden"
|
||||
/>
|
||||
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
|
@ -334,14 +240,7 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
|||
{selectedFolder || '未选择文件夹'}
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
ref={folderInputRef}
|
||||
type="file"
|
||||
{...({ webkitdirectory: "" } as any)}
|
||||
multiple
|
||||
onChange={handleFolderChange}
|
||||
className="hidden"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -361,19 +260,9 @@ const AIVideoGenerator: React.FC<AIVideoGeneratorProps> = ({ className = '' }) =
|
|||
onClick={async () => {
|
||||
try {
|
||||
console.log('Opening output folder dialog...')
|
||||
const selected = await open({
|
||||
directory: true,
|
||||
multiple: false
|
||||
})
|
||||
console.log('Output folder dialog result:', selected)
|
||||
|
||||
if (selected) {
|
||||
const folderPath = Array.isArray(selected) ? selected[0] : selected
|
||||
if (folderPath) {
|
||||
setOutputFolder(folderPath)
|
||||
const folderPath = await invoke('select_folder') as string
|
||||
console.log('Selected output folder:', folderPath)
|
||||
}
|
||||
}
|
||||
setOutputFolder(folderPath)
|
||||
} catch (error) {
|
||||
console.error('Failed to select output folder:', error)
|
||||
alert(`输出文件夹选择失败: ${error instanceof Error ? error.message : '未知错误'}`)
|
||||
|
|
|
|||
Loading…
Reference in New Issue