优化筛选

This commit is contained in:
liquid committed 2025-11-23 00:02:38 +08:00
1 parent 10daff4128
commit 5dc2bae00d
4 files changed
+79 -43

No files matched your search

@@ -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<TaskQueuePanelProps> = ({
} = useTaskQueue();
const { board } = useDrawnix();
const [activeTab, setActiveTab] = useState<string>('all');
const [activeTab, setActiveTab] = useState<string>('active');
const [showClearConfirm, setShowClearConfirm] = useState(false);
const [clearType, setClearType] = useState<'completed' | 'failed'>('completed');
const [searchText, setSearchText] = useState<string>('');
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<TaskQueuePanelProps> = ({
return (
<>
<div className={`task-queue-panel ${expanded ? 'task-queue-panel--expanded' : ''}`}>
{/* Header with title and close button */}
{/* Header with title and tabs */}
<div className="task-queue-panel__header">
<div>
<h3>任务队列</h3>
<Tabs value={activeTab} onChange={(value) => setActiveTab(value as string)}>
<TabPanel value="all" label={`全部 (${tasks.length})`} />
<TabPanel value="active" label={`活动 (${activeTasks.length})`} />
<TabPanel value="completed" label={`已完成 (${completedTasks.length})`} />
<TabPanel value="failed" label={`失败 (${failedTasks.length})`} />
<TabPanel value="completed" label={`已完成 (${completedTasks.length})`} />
<TabPanel value="all" label={`全部 (${tasks.length})`} />
</Tabs>
</div>
</div>
{/* Filters and Actions */}
<div className="task-queue-panel__filters">
<Input
value={searchText}
onChange={(value) => setSearchText(value)}
placeholder="搜索 Prompt..."
clearable
prefixIcon={<SearchIcon />}
size="small"
style={{ flex: 1, marginRight: '8px' }}
/>
<RadioGroup
value={typeFilter}
onChange={(value) => setTypeFilter(value as 'all' | 'image' | 'video')}
size="small"
variant="default-filled"
style={{ marginRight: '8px' }}
>
<Radio.Button value="all">全部</Radio.Button>
<Radio.Button value="image">图片</Radio.Button>
<Radio.Button value="video">视频</Radio.Button>
</RadioGroup>
<div className="task-queue-panel__actions">
{completedTasks.length > 0 && (
@@ -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 {
@@ -252,18 +252,8 @@ const AIImageGeneration = ({ initialPrompt = '', initialImages = [], selectedEle
// 保存提示词到历史记录
savePromptToHistory(prompt);
// 重置表单(500ms 延迟以提供更好的用户体验)
setTimeout(() => {
handleReset();
}, 100);
// 关闭对话框
setTimeout(() => {
setAppState({
...appState,
openDialogType: null,
});
}, 300);
// 清空表单,允许用户继续生成
handleReset();
} else {
// 任务创建失败(可能是重复提交)
setError(
@@ -252,18 +252,8 @@ const AIVideoGeneration = ({ initialPrompt = '', initialImage }: AIVideoGenerati
// 保存提示词到历史记录
savePromptToHistory(prompt);
// 重置表单
setTimeout(() => {
handleReset();
}, 100);
// 关闭对话框
setTimeout(() => {
setAppState({
...appState,
openDialogType: null,
});
}, 300);
// 清空表单,允许用户继续生成
handleReset();
} else {
// 任务创建失败
setError(