From d77a3b244c44f81aa865d2d23d7229cbdf65d1b3 Mon Sep 17 00:00:00 2001 From: imeepos Date: Mon, 11 Aug 2025 13:26:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=A4=B9=E9=80=92=E5=BD=92=E6=89=AB=E6=8F=8F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 启用文件夹选择时的递归扫描,遍历所有子文件夹 - 添加递归扫描选项复选框,用户可以选择是否扫描子文件夹 - 动态更新按钮文本显示当前扫描模式 - 改进扫描状态反馈,显示扫描进度和结果统计 - 添加状态显示区域,实时显示扫描状态和结果 - 优化用户体验,提供清晰的视觉反馈 现在用户可以: - 选择文件夹时自动扫描所有子文件夹中的视频文件 - 通过复选框控制是否递归扫描 - 查看扫描进度和结果统计信息 --- .../src/pages/tools/FrameExtractorTool.tsx | 56 +++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/pages/tools/FrameExtractorTool.tsx b/apps/desktop/src/pages/tools/FrameExtractorTool.tsx index 9ee4fb1..0ccac1b 100644 --- a/apps/desktop/src/pages/tools/FrameExtractorTool.tsx +++ b/apps/desktop/src/pages/tools/FrameExtractorTool.tsx @@ -55,6 +55,7 @@ const FrameExtractorTool: React.FC = () => { const [ffmpegAvailable, setFfmpegAvailable] = useState(null); const [selectedVideoForPreview, setSelectedVideoForPreview] = useState(null); const [currentPlayTime, setCurrentPlayTime] = useState(0); + const [recursiveScan, setRecursiveScan] = useState(true); // 检查 FFmpeg 可用性 useEffect(() => { @@ -107,7 +108,7 @@ const FrameExtractorTool: React.FC = () => { if (selected && typeof selected === 'string') { setSelectedFolder(selected); - await scanVideoFiles(selected, false); + await scanVideoFiles(selected, recursiveScan); } } catch (error) { console.error('选择文件夹失败:', error); @@ -117,6 +118,8 @@ const FrameExtractorTool: React.FC = () => { // 扫描视频文件 const scanVideoFiles = useCallback(async (folderPath: string, recursive: boolean) => { setIsScanning(true); + setCurrentFile(`正在扫描文件夹: ${folderPath}${recursive ? ' (递归)' : ''}`); + try { const files = await invoke('scan_video_files', { request: { @@ -125,10 +128,29 @@ const FrameExtractorTool: React.FC = () => { supported_formats: SUPPORTED_VIDEO_FORMATS, } }); - - setSelectedVideos(files.filter(f => f.is_valid)); + + const validFiles = files.filter(f => f.is_valid); + setSelectedVideos(validFiles); + + // 显示扫描结果 + const totalFiles = files.length; + const validCount = validFiles.length; + const invalidCount = totalFiles - validCount; + + console.log(`扫描完成: 找到 ${totalFiles} 个文件,其中 ${validCount} 个有效,${invalidCount} 个无效`); + setCurrentFile(`扫描完成: 找到 ${validCount} 个有效视频文件`); + + // 2秒后清除状态信息 + setTimeout(() => { + setCurrentFile(''); + }, 2000); + } catch (error) { console.error('扫描视频文件失败:', error); + setCurrentFile('扫描失败,请重试'); + setTimeout(() => { + setCurrentFile(''); + }, 3000); } finally { setIsScanning(false); } @@ -266,9 +288,10 @@ const FrameExtractorTool: React.FC = () => { onClick={handleSelectFolder} disabled={isScanning || isExtracting} className="flex items-center gap-2 px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" + title={recursiveScan ? "选择文件夹并递归扫描所有子文件夹中的视频文件" : "选择文件夹并扫描其中的视频文件"} > - 选择文件夹 + 选择文件夹{recursiveScan ? ' (递归)' : ''} + + {/* 递归扫描选项 */} +
+ +
@@ -306,6 +342,18 @@ const FrameExtractorTool: React.FC = () => {
+ {/* 状态显示区域 */} + {(isScanning || currentFile) && ( +
+
+ {isScanning && } + + {currentFile || '正在处理...'} + +
+
+ )} + {/* 视图切换 */}