From ada3eb94ede26d54bfe3c26c8d9ca1c3b4dd16d7 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 8 Aug 2025 21:41:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DComfyUI=20V2=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81TAB=E6=96=B0=E5=BB=BA=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=B5=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在WorkflowManager组件中添加了WorkflowV2Creator模态框的渲染 - 创建了新的WorkflowV2Creator组件,专门用于ComfyUI V2工作流创建 - 添加了createWorkflow方法到useComfyUIV2Store的解构中 - 实现了完整的工作流创建流程,包括基本信息、工作流配置和高级设置 - 支持JSON文件导入和手动编辑工作流数据 - 添加了表单验证和错误处理 - 修复了点击新建工作流按钮没有反应的问题 --- .../components/comfyui/WorkflowManager.tsx | 19 + .../components/comfyui/WorkflowV2Creator.tsx | 380 ++++++++++++++++++ 2 files changed, 399 insertions(+) create mode 100644 apps/desktop/src/components/comfyui/WorkflowV2Creator.tsx diff --git a/apps/desktop/src/components/comfyui/WorkflowManager.tsx b/apps/desktop/src/components/comfyui/WorkflowManager.tsx index 9b294e0..7fde353 100644 --- a/apps/desktop/src/components/comfyui/WorkflowManager.tsx +++ b/apps/desktop/src/components/comfyui/WorkflowManager.tsx @@ -18,6 +18,7 @@ import { } from '@heroicons/react/24/outline'; import { useComfyUIV2Store, useFilteredWorkflows } from '../../store/comfyuiV2Store'; import type { WorkflowV2 } from '../../services/comfyuiV2Service'; +import { WorkflowV2Creator } from './WorkflowV2Creator'; interface WorkflowManagerProps { className?: string; @@ -33,6 +34,7 @@ export const WorkflowManager: React.FC = ({ selectedWorkflowIds, workflowFilters, loadWorkflows, + createWorkflow, deleteWorkflow, executeWorkflow, selectWorkflow, @@ -329,6 +331,23 @@ export const WorkflowManager: React.FC = ({ )} + + {/* 工作流创建模态框 */} + setShowCreateModal(false)} + onSave={async (workflowData) => { + try { + await createWorkflow(workflowData); + setShowCreateModal(false); + // 重新加载工作流列表 + await loadWorkflows(); + } catch (error) { + console.error('创建工作流失败:', error); + // 这里可以添加错误提示 + } + }} + /> ); }; diff --git a/apps/desktop/src/components/comfyui/WorkflowV2Creator.tsx b/apps/desktop/src/components/comfyui/WorkflowV2Creator.tsx new file mode 100644 index 0000000..a989c9d --- /dev/null +++ b/apps/desktop/src/components/comfyui/WorkflowV2Creator.tsx @@ -0,0 +1,380 @@ +/** + * ComfyUI V2 工作流创建器组件 + * 专门用于创建ComfyUI V2工作流的模态框 + */ + +import React, { useState, useEffect } from 'react'; +import { + X, + Save, + Upload, + FileText, + Settings, + Info, + AlertCircle, + CheckCircle, +} from 'lucide-react'; +import type { CreateWorkflowRequest } from '../../services/comfyuiV2Service'; + +interface WorkflowV2CreatorProps { + /** 是否显示模态框 */ + isOpen: boolean; + /** 关闭回调 */ + onClose: () => void; + /** 保存回调 */ + onSave: (workflowData: CreateWorkflowRequest) => Promise; + /** 编辑的工作流(为空时表示创建新工作流) */ + editingWorkflow?: any; +} + +/** + * ComfyUI V2 工作流创建器组件 + */ +export const WorkflowV2Creator: React.FC = ({ + isOpen, + onClose, + onSave, + editingWorkflow +}) => { + const [activeTab, setActiveTab] = useState<'basic' | 'workflow' | 'advanced'>('basic'); + const [formData, setFormData] = useState({ + name: '', + description: '', + category: '', + workflow_data: {}, + tags: [], + }); + const [errors, setErrors] = useState>({}); + const [isSaving, setIsSaving] = useState(false); + const [workflowJsonText, setWorkflowJsonText] = useState('{}'); + + // 重置表单数据 + useEffect(() => { + if (isOpen) { + if (editingWorkflow) { + setFormData({ + name: editingWorkflow.name || '', + description: editingWorkflow.description || '', + category: editingWorkflow.category || '', + workflow_data: editingWorkflow.workflow_data || {}, + tags: editingWorkflow.tags || [], + }); + setWorkflowJsonText(JSON.stringify(editingWorkflow.workflow_data || {}, null, 2)); + } else { + // 重置为默认值 + setFormData({ + name: '', + description: '', + category: '', + workflow_data: {}, + tags: [], + }); + setWorkflowJsonText('{}'); + } + setErrors({}); + setActiveTab('basic'); + } + }, [editingWorkflow, isOpen]); + + // 更新表单字段 + const updateField = (field: keyof CreateWorkflowRequest, value: any) => { + setFormData(prev => ({ ...prev, [field]: value })); + // 清除该字段的错误 + if (errors[field]) { + setErrors(prev => { + const newErrors = { ...prev }; + delete newErrors[field]; + return newErrors; + }); + } + }; + + // 验证表单 + const validateForm = (): boolean => { + const newErrors: Record = {}; + + if (!formData.name.trim()) { + newErrors.name = '工作流名称不能为空'; + } + + if (!workflowJsonText.trim() || workflowJsonText.trim() === '{}') { + newErrors.workflow_data = '工作流数据不能为空'; + } else { + try { + const parsed = JSON.parse(workflowJsonText); + if (typeof parsed !== 'object' || parsed === null) { + newErrors.workflow_data = '工作流数据必须是有效的JSON对象'; + } + } catch (error) { + newErrors.workflow_data = 'JSON格式错误,请检查语法'; + } + } + + setErrors(newErrors); + return Object.keys(newErrors).length === 0; + }; + + // 处理保存 + const handleSave = async () => { + if (!validateForm()) { + return; + } + + setIsSaving(true); + try { + const workflowData = JSON.parse(workflowJsonText); + const requestData: CreateWorkflowRequest = { + ...formData, + workflow_data: workflowData, + }; + + await onSave(requestData); + } catch (error) { + console.error('保存工作流失败:', error); + setErrors({ general: `保存失败: ${error}` }); + } finally { + setIsSaving(false); + } + }; + + // 导入ComfyUI工作流 + const handleImportWorkflow = () => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.json'; + input.onchange = (e) => { + const file = (e.target as HTMLInputElement).files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (e) => { + try { + const workflow = JSON.parse(e.target?.result as string); + setWorkflowJsonText(JSON.stringify(workflow, null, 2)); + updateField('workflow_data', workflow); + } catch (error) { + console.error('解析ComfyUI工作流失败:', error); + setErrors({ workflow_data: '文件格式错误,请选择有效的JSON文件' }); + } + }; + reader.readAsText(file); + } + }; + input.click(); + }; + + // 处理标签输入 + const handleTagsChange = (tagsString: string) => { + const tags = tagsString + .split(',') + .map(tag => tag.trim()) + .filter(tag => tag.length > 0); + updateField('tags', tags); + }; + + if (!isOpen) return null; + + return ( +
+
+ {/* 头部 */} +
+
+ +

+ {editingWorkflow ? '编辑工作流' : '创建工作流'} +

+
+ + +
+ + {/* 错误提示 */} + {errors.general && ( +
+ + {errors.general} +
+ )} + + {/* 标签页导航 */} +
+ {[ + { id: 'basic', label: '基本信息', icon: FileText }, + { id: 'workflow', label: '工作流配置', icon: Settings }, + { id: 'advanced', label: '高级设置', icon: Info }, + ].map(tab => { + const Icon = tab.icon; + return ( + + ); + })} +
+ + {/* 内容区域 */} +
+ {/* 基本信息标签页 */} + {activeTab === 'basic' && ( +
+
+
+ + updateField('name', e.target.value)} + className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${ + errors.name ? 'border-red-300' : 'border-gray-300' + }`} + placeholder="例如:图像生成工作流" + /> + {errors.name && ( +

{errors.name}

+ )} +
+ +
+ + updateField('category', e.target.value)} + className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" + placeholder="例如:图像处理" + /> +
+
+ +
+ +