import { create } from 'zustand'; import { invoke } from '@tauri-apps/api/core'; import { Material, MaterialStats, CreateMaterialRequest, MaterialImportResult, ProcessingStatus, MaterialProcessingConfig } from '../types/material'; /** * 素材状态管理 * 遵循 Tauri 开发规范的状态管理模式 */ interface MaterialState { // 状态 materials: Material[]; currentMaterial: Material | null; stats: MaterialStats | null; isLoading: boolean; isImporting: boolean; isProcessing: boolean; error: string | null; importProgress: { current_file: string; processed_count: number; total_count: number; current_status: string; errors: string[]; } | null; // 操作 loadMaterials: (projectId: string) => Promise; loadMaterialStats: (projectId: string) => Promise; importMaterials: (request: CreateMaterialRequest) => Promise; getMaterialById: (id: string) => Promise; deleteMaterial: (id: string) => Promise; processMaterials: (materialIds: string[]) => Promise; updateMaterialStatus: (id: string, status: ProcessingStatus, errorMessage?: string) => Promise; cleanupInvalidMaterials: (projectId: string) => Promise; setCurrentMaterial: (material: Material | null) => void; clearError: () => void; // 工具方法 selectMaterialFiles: () => Promise; validateMaterialFiles: (filePaths: string[]) => Promise; getFileInfo: (filePath: string) => Promise; checkFFmpegAvailable: () => Promise; getFFmpegVersion: () => Promise; getSupportedExtensions: () => Promise; } export const useMaterialStore = create((set, get) => ({ // 初始状态 materials: [], currentMaterial: null, stats: null, isLoading: false, isImporting: false, isProcessing: false, error: null, importProgress: null, // 加载项目素材 loadMaterials: async (projectId: string) => { set({ isLoading: true, error: null }); try { const materials = await invoke('get_project_materials', { projectId }); set({ materials, isLoading: false }); } catch (error) { set({ error: error as string, isLoading: false, materials: [] }); } }, // 加载素材统计 loadMaterialStats: async (projectId: string) => { try { const stats = await invoke('get_project_material_stats', { projectId }); set({ stats }); } catch (error) { console.error('加载素材统计失败:', error); } }, // 导入素材 importMaterials: async (request: CreateMaterialRequest) => { set({ isImporting: true, error: null, importProgress: { current_file: '', processed_count: 0, total_count: request.file_paths.length, current_status: '准备导入...', errors: [] }}); try { const result = await invoke('import_materials', { request }); // 更新素材列表 const { materials } = get(); set({ materials: [...materials, ...result.created_materials], isImporting: false, importProgress: null }); // 重新加载统计信息 get().loadMaterialStats(request.project_id); return result; } catch (error) { set({ error: error as string, isImporting: false, importProgress: null }); throw error; } }, // 获取素材详情 getMaterialById: async (id: string) => { try { const material = await invoke('get_material_by_id', { id }); return material; } catch (error) { set({ error: error as string }); return null; } }, // 删除素材 deleteMaterial: async (id: string) => { try { await invoke('delete_material', { id }); // 从状态中移除 const { materials } = get(); set({ materials: materials.filter(m => m.id !== id) }); // 如果删除的是当前素材,清空当前素材 const { currentMaterial } = get(); if (currentMaterial?.id === id) { set({ currentMaterial: null }); } } catch (error) { set({ error: error as string }); throw error; } }, // 批量处理素材 processMaterials: async (materialIds: string[]) => { set({ isProcessing: true, error: null }); try { const processedIds = await invoke('batch_process_materials', { materialIds }); // 更新处理状态 const { materials } = get(); const updatedMaterials = materials.map(material => { if (processedIds.includes(material.id)) { return { ...material, processing_status: 'Processing' as ProcessingStatus }; } return material; }); set({ materials: updatedMaterials, isProcessing: false }); } catch (error) { set({ error: error as string, isProcessing: false }); throw error; } }, // 更新素材状态 updateMaterialStatus: async (id: string, status: ProcessingStatus, errorMessage?: string) => { try { await invoke('update_material_status', { id, status, errorMessage }); // 更新本地状态 const { materials } = get(); const updatedMaterials = materials.map(material => { if (material.id === id) { return { ...material, processing_status: status, error_message: errorMessage, updated_at: new Date().toISOString() }; } return material; }); set({ materials: updatedMaterials }); } catch (error) { set({ error: error as string }); throw error; } }, // 清理失效素材 cleanupInvalidMaterials: async (projectId: string) => { try { const result = await invoke('cleanup_invalid_materials', { projectId }); // 重新加载素材列表 await get().loadMaterials(projectId); return result; } catch (error) { set({ error: error as string }); throw error; } }, // 设置当前素材 setCurrentMaterial: (material: Material | null) => { set({ currentMaterial: material }); }, // 清除错误 clearError: () => { set({ error: null }); }, // 选择素材文件 selectMaterialFiles: async () => { try { const filePaths = await invoke('select_material_files'); return filePaths; } catch (error) { set({ error: error as string }); return []; } }, // 验证素材文件 validateMaterialFiles: async (filePaths: string[]) => { try { const validFiles = await invoke('validate_material_files', { filePaths }); return validFiles; } catch (error) { set({ error: error as string }); return []; } }, // 获取文件信息 getFileInfo: async (filePath: string) => { try { const fileInfo = await invoke('get_file_info', { filePath }); return fileInfo; } catch (error) { set({ error: error as string }); return null; } }, // 检查 FFmpeg 是否可用 checkFFmpegAvailable: async () => { try { const isAvailable = await invoke('check_ffmpeg_available'); return isAvailable; } catch (error) { console.error('检查 FFmpeg 失败:', error); return false; } }, // 获取 FFmpeg 版本 getFFmpegVersion: async () => { try { const version = await invoke('get_ffmpeg_version'); return version; } catch (error) { console.error('获取 FFmpeg 版本失败:', error); return 'Unknown'; } }, // 获取支持的扩展名 getSupportedExtensions: async () => { try { const extensions = await invoke('get_supported_extensions'); return extensions; } catch (error) { console.error('获取支持的扩展名失败:', error); return []; } }, // 测试场景检测 testSceneDetection: async (filePath: string) => { try { const result = await invoke('test_scene_detection', { filePath }); return result; } catch (error) { console.error('测试场景检测失败:', error); return `测试失败: ${error}`; } }, // 获取FFmpeg状态 getFFmpegStatus: async () => { try { const status = await invoke('get_ffmpeg_status'); return status; } catch (error) { console.error('获取FFmpeg状态失败:', error); return `获取状态失败: ${error}`; } }, }));