/** * 工作流管理器组件 * 提供现代化的工作流管理界面 */ import React, { useState, useEffect } from 'react'; import { PlusIcon, MagnifyingGlassIcon, FunnelIcon, PlayIcon, PencilIcon, TrashIcon, TagIcon, CalendarIcon, EyeIcon, } from '@heroicons/react/24/outline'; import { useComfyUIV2Store, useFilteredWorkflows } from '../../store/comfyuiV2Store'; import type { WorkflowV2 } from '../../services/comfyuiV2Service'; import { WorkflowTemplateCreator } from './WorkflowTemplateCreator'; import { invoke } from '@tauri-apps/api/core'; interface WorkflowManagerProps { className?: string; } export const WorkflowManager: React.FC = ({ className = '' }) => { const { workflows, workflowsLoading, workflowsError, selectedWorkflowIds, workflowFilters, loadWorkflows, deleteWorkflow, executeWorkflow, selectWorkflow, deselectWorkflow, clearWorkflowSelection, setWorkflowFilters, setCurrentWorkflow, } = useComfyUIV2Store(); const filteredWorkflows = useFilteredWorkflows(); const [showCreateModal, setShowCreateModal] = useState(false); const [showFilters, setShowFilters] = useState(false); const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid'); // 加载工作流 useEffect(() => { loadWorkflows(); }, [loadWorkflows]); const handleSearch = (query: string) => { setWorkflowFilters({ searchQuery: query }); }; const handleCategoryFilter = (category: string) => { setWorkflowFilters({ category: category === workflowFilters.category ? undefined : category }); }; const handleExecuteWorkflow = async (workflow: WorkflowV2) => { try { await executeWorkflow({ workflow_id: workflow.id, parameters: {}, }); } catch (error) { console.error('执行工作流失败:', error); } }; const handleDeleteWorkflow = async (workflow: WorkflowV2) => { if (window.confirm(`确定要删除工作流 "${workflow.name}" 吗?`)) { try { await deleteWorkflow(workflow.id); } catch (error) { console.error('删除工作流失败:', error); } } }; const handleSelectWorkflow = (workflow: WorkflowV2, selected: boolean) => { if (selected) { selectWorkflow(workflow.id); } else { deselectWorkflow(workflow.id); } }; const getUniqueCategories = () => { const categories = workflows .map(w => w.category) .filter((category): category is string => Boolean(category)); return [...new Set(categories)]; }; const getUniqueTags = () => { const tags = workflows.flatMap(w => w.tags); return [...new Set(tags)]; }; if (workflowsError) { return (
加载工作流失败
{workflowsError}
); } return (
{/* 头部 */}

工作流管理

共 {filteredWorkflows.length} 个工作流 {selectedWorkflowIds.length > 0 && ( (已选择 {selectedWorkflowIds.length} 个) )}

{/* 搜索和筛选 */}
{/* 搜索框 */}
handleSearch(e.target.value)} className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
{/* 筛选器 */} {showFilters && (
{/* 分类筛选 */}
{getUniqueCategories().map(category => ( ))}
{/* 标签筛选 */}
{getUniqueTags().slice(0, 10).map(tag => ( ))}
)}
{/* 批量操作 */} {selectedWorkflowIds.length > 0 && (
已选择 {selectedWorkflowIds.length} 个工作流
)} {/* 工作流列表 */}
{workflowsLoading ? (
加载中...
) : filteredWorkflows.length === 0 ? (
{workflows.length === 0 ? '暂无工作流' : '没有符合条件的工作流'}
) : (
{filteredWorkflows.map(workflow => ( handleSelectWorkflow(workflow, selected)} onExecute={() => handleExecuteWorkflow(workflow)} onEdit={() => setCurrentWorkflow(workflow)} onDelete={() => handleDeleteWorkflow(workflow)} onView={() => setCurrentWorkflow(workflow)} /> ))}
)}
{/* 工作流模板创建模态框 */} setShowCreateModal(false)} onSave={async (templateData) => { try { // 调用ComfyUI V2模板创建接口 await invoke('comfyui_v2_create_template', { request: templateData }); setShowCreateModal(false); // 重新加载工作流列表 await loadWorkflows(); } catch (error) { console.error('创建工作流模板失败:', error); // 这里可以添加错误提示 } }} />
); }; // 工作流卡片组件 interface WorkflowCardProps { workflow: WorkflowV2; viewMode: 'grid' | 'list'; selected: boolean; onSelect: (selected: boolean) => void; onExecute: () => void; onEdit: () => void; onDelete: () => void; onView: () => void; } const WorkflowCard: React.FC = ({ workflow, viewMode, selected, onSelect, onExecute, onEdit, onDelete, onView, }) => { if (viewMode === 'list') { return (
onSelect(e.target.checked)} className="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" />

{workflow.name}

{workflow.description}

{workflow.category && ( {workflow.category} )}
); } return (
onSelect(e.target.checked)} className="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500 mt-1" />

{workflow.name}

{workflow.description}

{workflow.category && ( {workflow.category} )}
{new Date(workflow.updated_at).toLocaleDateString()}
v{workflow.version}
{workflow.tags.length > 0 && (
{workflow.tags.slice(0, 2).join(', ')} {workflow.tags.length > 2 && ...}
)}
); };