import React, { useState, useEffect } from 'react'; import { FileVideo, FileAudio, FileImage, File, Loader2, Play, Pause, Volume2 } from 'lucide-react'; import { Material } from '../types/material'; import { invoke } from '@tauri-apps/api/core'; import { useLazyLoad } from '../hooks/useLazyLoad'; interface MaterialThumbnailProps { material: Material; size?: 'small' | 'medium' | 'large'; className?: string; thumbnailCache?: Map; setThumbnailCache?: (cache: Map) => void; } /** * Material缩略图组件 * 遵循Tauri开发规范的组件设计模式 * 支持懒加载、缓存机制、错误处理 */ export const MaterialThumbnail: React.FC = ({ material, size = 'medium', className = '', thumbnailCache = new Map(), setThumbnailCache = () => {}, }) => { const [loading, setLoading] = useState(false); const [thumbnailUrl, setThumbnailUrl] = useState(null); const [error, setError] = useState(false); const [isPlaying, setIsPlaying] = useState(false); const [audioElement, setAudioElement] = useState(null); // 使用懒加载Hook,当缩略图容器可见时才开始加载 const { isVisible, elementRef } = useLazyLoad(0.1, '100px'); // 根据size确定尺寸 const getSizeClasses = () => { switch (size) { case 'small': return 'w-12 h-12'; case 'medium': return 'w-16 h-16'; case 'large': return 'w-24 h-24'; default: return 'w-16 h-16'; } }; // 获取文件类型图标 const getTypeIcon = () => { const iconSize = size === 'small' ? 'w-6 h-6' : size === 'large' ? 'w-12 h-12' : 'w-8 h-8'; switch (material.material_type) { case 'Video': return ; case 'Audio': return ; case 'Image': return ; default: return ; } }; // 音频播放控制 const toggleAudioPlay = async () => { if (material.material_type !== 'Audio') return; if (!audioElement) { try { // 通过后端API获取音频数据 console.log('获取音频数据:', material.id); const audioDataUrl = await invoke('get_audio_file_base64', { materialId: material.id }); console.log('获取音频数据成功'); // 创建音频元素 const audio = new Audio(); audio.src = audioDataUrl; audio.onended = () => setIsPlaying(false); audio.onerror = () => { console.error('音频播放失败'); setIsPlaying(false); }; setAudioElement(audio); await audio.play(); setIsPlaying(true); } catch (error) { console.error('音频播放失败:', error); setIsPlaying(false); } } else { if (isPlaying) { audioElement.pause(); setIsPlaying(false); } else { try { await audioElement.play(); setIsPlaying(true); } catch (error) { console.error('音频播放失败:', error); setIsPlaying(false); } } } }; // 清理音频元素 useEffect(() => { return () => { if (audioElement) { audioElement.pause(); audioElement.src = ''; } }; }, [audioElement]); useEffect(() => { // 只有当元素可见时才加载内容 if (!isVisible) return; const loadContent = async () => { const materialId = material.id; // 检查缓存 if (thumbnailCache.has(materialId)) { const cachedUrl = thumbnailCache.get(materialId); setThumbnailUrl(cachedUrl || null); return; } // 根据素材类型加载不同内容 if (material.material_type === 'Video') { // 视频:生成缩略图 setLoading(true); setError(false); try { console.log('获取视频缩略图:', materialId); const dataUrl = await invoke('get_material_thumbnail_base64', { materialId: materialId }); console.log('获取缩略图成功'); setThumbnailUrl(dataUrl); // 更新缓存 const newCache = new Map(thumbnailCache); newCache.set(materialId, dataUrl); setThumbnailCache(newCache); } catch (error) { console.error('获取缩略图失败:', error); setError(true); } finally { setLoading(false); } } else if (material.material_type === 'Image') { // 图片:通过后端API获取base64数据 setLoading(true); setError(false); try { console.log('获取图片数据:', materialId); const dataUrl = await invoke('get_material_thumbnail_base64', { materialId: materialId }); console.log('获取图片数据成功'); setThumbnailUrl(dataUrl); // 更新缓存 const newCache = new Map(thumbnailCache); newCache.set(materialId, dataUrl); setThumbnailCache(newCache); } catch (error) { console.error('获取图片数据失败:', error); setError(true); } finally { setLoading(false); } } // 音频类型不需要加载缩略图,直接显示播放控件 }; loadContent(); }, [isVisible, material.id, material.material_type, material.original_path, thumbnailCache, setThumbnailCache]); // 渲染音频播放控件 const renderAudioPlayer = () => { const iconSize = size === 'small' ? 'w-4 h-4' : size === 'large' ? 'w-8 h-8' : 'w-6 h-6'; return (
{isPlaying ? ( ) : ( )}
{size !== 'small' && (
{isPlaying ? '播放中' : '点击播放'}
)}
); }; return (
{loading ? ( ) : material.material_type === 'Audio' ? ( // 音频:显示播放控件 renderAudioPlayer() ) : thumbnailUrl && !error ? ( // 图片和视频:显示图片/缩略图 {`${material.name} { setError(true); setThumbnailUrl(null); }} /> ) : isVisible ? ( // 加载失败或其他类型:显示类型图标 getTypeIcon() ) : ( // 未加载时显示占位符
)}
); };