From 5dc2bae00dd193402b1dc8d58cfd19a8f8dee52f Mon Sep 17 00:00:00 2001 From: liquid Date: Sun, 23 Nov 2025 00:02:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/task-queue/TaskQueuePanel.tsx | 85 +++++++++++++++---- .../src/components/task-queue/task-queue.scss | 9 +- .../ttd-dialog/ai-image-generation.tsx | 14 +-- .../ttd-dialog/ai-video-generation.tsx | 14 +-- 4 files changed, 79 insertions(+), 43 deletions(-) diff --git a/packages/drawnix/src/components/task-queue/TaskQueuePanel.tsx b/packages/drawnix/src/components/task-queue/TaskQueuePanel.tsx index 7852dd6b..a6ef2e66 100644 --- a/packages/drawnix/src/components/task-queue/TaskQueuePanel.tsx +++ b/packages/drawnix/src/components/task-queue/TaskQueuePanel.tsx @@ -5,9 +5,9 @@ * Supports filtering by status and provides batch operations. */ -import React, { useState } from 'react'; -import { Button, Tabs, Dialog, MessagePlugin } from 'tdesign-react'; -import { DeleteIcon } from 'tdesign-icons-react'; +import React, { useState, useMemo } from 'react'; +import { Button, Tabs, Dialog, MessagePlugin, Input, Radio } from 'tdesign-react'; +import { DeleteIcon, SearchIcon } from 'tdesign-icons-react'; import { TaskItem } from './TaskItem'; import { useTaskQueue } from '../../hooks/useTaskQueue'; import { Task, TaskType } from '../../types/task.types'; @@ -17,6 +17,7 @@ import { insertVideoFromUrl } from '../../data/video'; import './task-queue.scss'; const { TabPanel } = Tabs; +const RadioGroup = Radio.Group; export interface TaskQueuePanelProps { /** Whether the panel is expanded */ @@ -49,29 +50,54 @@ export const TaskQueuePanel: React.FC = ({ } = useTaskQueue(); const { board } = useDrawnix(); - const [activeTab, setActiveTab] = useState('all'); + const [activeTab, setActiveTab] = useState('active'); const [showClearConfirm, setShowClearConfirm] = useState(false); const [clearType, setClearType] = useState<'completed' | 'failed'>('completed'); + const [searchText, setSearchText] = useState(''); + const [typeFilter, setTypeFilter] = useState<'all' | 'image' | 'video'>('all'); - // Filter tasks based on active tab - const getFilteredTasks = (): Task[] => { + // Filter and sort tasks + const filteredTasks = useMemo(() => { + // Get tasks based on active tab + let tasksToFilter: Task[]; switch (activeTab) { case 'all': - return tasks; + tasksToFilter = tasks; + break; case 'active': - return activeTasks; + tasksToFilter = activeTasks; + break; case 'completed': - return completedTasks; + tasksToFilter = completedTasks; + break; case 'failed': - return failedTasks; + tasksToFilter = failedTasks; + break; case 'cancelled': - return cancelledTasks; + tasksToFilter = cancelledTasks; + break; default: - return tasks; + tasksToFilter = tasks; } - }; - const filteredTasks = getFilteredTasks(); + // Apply type filter + if (typeFilter !== 'all') { + tasksToFilter = tasksToFilter.filter(task => + task.type === (typeFilter === 'image' ? TaskType.IMAGE : TaskType.VIDEO) + ); + } + + // Apply search filter + if (searchText.trim()) { + const searchLower = searchText.toLowerCase().trim(); + tasksToFilter = tasksToFilter.filter(task => + task.params.prompt.toLowerCase().includes(searchLower) + ); + } + + // Sort by time - newest first (reverse chronological) + return [...tasksToFilter].sort((a, b) => b.createdAt - a.createdAt); + }, [activeTab, tasks, activeTasks, completedTasks, failedTasks, cancelledTasks, typeFilter, searchText]); // Handle clear action const handleClear = (type: 'completed' | 'failed') => { @@ -176,17 +202,42 @@ export const TaskQueuePanel: React.FC = ({ return ( <>
- {/* Header with title and close button */} + {/* Header with title and tabs */}

任务队列

setActiveTab(value as string)}> - - + +
+
+ + {/* Filters and Actions */} +
+ setSearchText(value)} + placeholder="搜索 Prompt..." + clearable + prefixIcon={} + size="small" + style={{ flex: 1, marginRight: '8px' }} + /> + + setTypeFilter(value as 'all' | 'image' | 'video')} + size="small" + variant="default-filled" + style={{ marginRight: '8px' }} + > + 全部 + 图片 + 视频 +
{completedTasks.length > 0 && ( diff --git a/packages/drawnix/src/components/task-queue/task-queue.scss b/packages/drawnix/src/components/task-queue/task-queue.scss index d24f079e..3adb9577 100644 --- a/packages/drawnix/src/components/task-queue/task-queue.scss +++ b/packages/drawnix/src/components/task-queue/task-queue.scss @@ -119,14 +119,18 @@ } &__filters { + padding: 12px 24px; + border-bottom: 1px solid var(--td-component-border, #e7e7e7); display: flex; + align-items: center; gap: 8px; + flex-wrap: wrap; } &__actions { display: flex; gap: 8px; - margin-top: 12px; + flex-shrink: 0; } &__content { @@ -154,7 +158,8 @@ } &__list { - // Task items will be rendered here + display: flex; + flex-direction: column; } &__empty { diff --git a/packages/drawnix/src/components/ttd-dialog/ai-image-generation.tsx b/packages/drawnix/src/components/ttd-dialog/ai-image-generation.tsx index 78f24dc4..e943df9d 100644 --- a/packages/drawnix/src/components/ttd-dialog/ai-image-generation.tsx +++ b/packages/drawnix/src/components/ttd-dialog/ai-image-generation.tsx @@ -252,18 +252,8 @@ const AIImageGeneration = ({ initialPrompt = '', initialImages = [], selectedEle // 保存提示词到历史记录 savePromptToHistory(prompt); - // 重置表单(500ms 延迟以提供更好的用户体验) - setTimeout(() => { - handleReset(); - }, 100); - - // 关闭对话框 - setTimeout(() => { - setAppState({ - ...appState, - openDialogType: null, - }); - }, 300); + // 清空表单,允许用户继续生成 + handleReset(); } else { // 任务创建失败(可能是重复提交) setError( diff --git a/packages/drawnix/src/components/ttd-dialog/ai-video-generation.tsx b/packages/drawnix/src/components/ttd-dialog/ai-video-generation.tsx index 998c657a..7e7fad45 100644 --- a/packages/drawnix/src/components/ttd-dialog/ai-video-generation.tsx +++ b/packages/drawnix/src/components/ttd-dialog/ai-video-generation.tsx @@ -252,18 +252,8 @@ const AIVideoGeneration = ({ initialPrompt = '', initialImage }: AIVideoGenerati // 保存提示词到历史记录 savePromptToHistory(prompt); - // 重置表单 - setTimeout(() => { - handleReset(); - }, 100); - - // 关闭对话框 - setTimeout(() => { - setAppState({ - ...appState, - openDialogType: null, - }); - }, 300); + // 清空表单,允许用户继续生成 + handleReset(); } else { // 任务创建失败 setError(