{
label: node.nodeName,
nodeType: node.nodeType as any,
category: getNodeCategory(node.nodeType) as any,
- icon: nodeDefinition?.uiConfig.style.icon || getNodeIcon(node.nodeType),
- color: nodeDefinition?.uiConfig.style.fill || getNodeColor(node.nodeType),
+ icon: nodeDefinition?.renderConfig.icon.content || getNodeIcon(node.nodeType),
+ color: nodeDefinition?.renderConfig.theme.primary || getNodeColor(node.nodeType),
configs: node.configs || {},
inputMapping: node.inputMapping || {},
outputMapping: node.outputMapping || {},
diff --git a/frontend/src/pages/Workflow/Design/index.tsx b/frontend/src/pages/Workflow/Design/index.tsx
index c9b9e7ac..6ac6c87b 100644
--- a/frontend/src/pages/Workflow/Design/index.tsx
+++ b/frontend/src/pages/Workflow/Design/index.tsx
@@ -358,8 +358,8 @@ const WorkflowDesignInner: React.FC = () => {
label: nodeDefinition.nodeName,
nodeType: nodeDefinition.nodeType,
category: nodeDefinition.category,
- icon: nodeDefinition.uiConfig.style.icon,
- color: nodeDefinition.uiConfig.style.fill,
+ icon: nodeDefinition.renderConfig.icon.content,
+ color: nodeDefinition.renderConfig.theme.primary,
// 保存原始节点定义引用,用于配置
nodeDefinition,
// 初始化配置数据
diff --git a/frontend/src/pages/Workflow/Design/nodes/EndEventNode.tsx b/frontend/src/pages/Workflow/Design/nodes/EndEventNode.tsx
index c71c404f..0cc60827 100644
--- a/frontend/src/pages/Workflow/Design/nodes/EndEventNode.tsx
+++ b/frontend/src/pages/Workflow/Design/nodes/EndEventNode.tsx
@@ -1,10 +1,8 @@
-import React, { memo } from 'react';
-import { Handle, Position, NodeProps } from '@xyflow/react';
import { BaseNodeDefinition, NodeType, NodeCategory } from './types';
-import type { FlowNodeData } from '../types';
/**
- * 结束事件节点定义(元数据)
+ * 结束事件节点定义(纯配置)
+ * 使用 BaseNode 组件渲染,无需自定义渲染代码
*/
export const EndEventNodeDefinition: BaseNodeDefinition = {
nodeCode: "END_EVENT",
@@ -13,14 +11,29 @@ export const EndEventNodeDefinition: BaseNodeDefinition = {
category: NodeCategory.EVENT,
description: "工作流的结束节点",
- uiConfig: {
- size: { width: 80, height: 50 },
- style: {
- fill: '#ff4d4f',
- stroke: '#cf1322',
- strokeWidth: 2,
- icon: 'stop-circle',
- iconColor: '#fff'
+ // 渲染配置(配置驱动)
+ renderConfig: {
+ shape: 'circle',
+ size: { width: 100, height: 60 },
+ icon: {
+ type: 'emoji',
+ content: '⏹️',
+ size: 40
+ },
+ theme: {
+ primary: '#ef4444',
+ secondary: '#f87171',
+ selectedBorder: '#3b82f6',
+ hoverBorder: '#ef4444',
+ gradient: ['#fef2f2', '#fee2e2']
+ },
+ handles: {
+ input: true, // 结束节点有输入
+ output: false // 无输出
+ },
+ features: {
+ showBadge: false, // 结束节点不显示徽章
+ showHoverMenu: false // 结束节点不显示菜单
}
},
@@ -52,89 +65,4 @@ export const EndEventNodeDefinition: BaseNodeDefinition = {
}
};
-/**
- * 结束事件节点渲染组件
- */
-const EndEventNode: React.FC
= ({ data, selected }) => {
- const nodeData = data as FlowNodeData;
- const [isHovered, setIsHovered] = React.useState(false);
-
- return (
- setIsHovered(true)}
- onMouseLeave={() => setIsHovered(false)}
- style={{
- padding: '12px',
- borderRadius: '50%',
- border: `3px solid ${selected ? '#3b82f6' : '#ef4444'}`,
- background: selected
- ? 'linear-gradient(135deg, #fee2e2 0%, #fecaca 100%)'
- : 'linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%)',
- minWidth: '70px',
- minHeight: '70px',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- position: 'relative',
- boxShadow: selected
- ? '0 8px 16px rgba(59, 130, 246, 0.25), 0 2px 4px rgba(59, 130, 246, 0.15)'
- : isHovered
- ? '0 6px 12px rgba(239, 68, 68, 0.2), 0 2px 4px rgba(239, 68, 68, 0.1)'
- : '0 2px 8px rgba(0,0,0,0.08)',
- cursor: 'pointer',
- transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
- transform: isHovered ? 'scale(1.05)' : 'scale(1)',
- }}
- >
- {/* 图标 */}
-
- ⏹️
-
-
- {/* 输入连接点 */}
-
-
- {/* 节点标签 */}
-
- {nodeData.label || '结束'}
-
-
- );
-};
-
-export default memo(EndEventNode);
-
+// ✅ 不再需要单独的渲染组件,使用 BaseNode 即可
diff --git a/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx b/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx
index 7a3edcfd..342738ef 100644
--- a/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx
+++ b/frontend/src/pages/Workflow/Design/nodes/JenkinsBuildNode.tsx
@@ -1,10 +1,8 @@
-import React, { memo } from 'react';
-import { Handle, Position, NodeProps } from '@xyflow/react';
import { ConfigurableNodeDefinition, NodeType, NodeCategory } from './types';
-import type { FlowNodeData } from '../types';
/**
- * Jenkins构建节点定义(元数据)
+ * Jenkins构建节点定义(纯配置)
+ * 使用 BaseNode 组件渲染,无需自定义渲染代码
*/
export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = {
nodeCode: "JENKINS_BUILD",
@@ -13,14 +11,29 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = {
category: NodeCategory.TASK,
description: "通过Jenkins执行构建任务",
- uiConfig: {
+ // 渲染配置(配置驱动)
+ renderConfig: {
+ shape: 'rounded-rect',
size: { width: 160, height: 80 },
- style: {
- fill: '#52c41a',
- stroke: '#389e08',
- strokeWidth: 2,
- icon: 'jenkins',
- iconColor: '#fff'
+ icon: {
+ type: 'emoji',
+ content: '🔨',
+ size: 40
+ },
+ theme: {
+ primary: '#52c41a',
+ secondary: '#73d13d',
+ selectedBorder: '#3b82f6',
+ hoverBorder: '#73d13d',
+ gradient: ['#ffffff', '#f6ffed']
+ },
+ handles: {
+ input: true,
+ output: true
+ },
+ features: {
+ showBadge: true,
+ showHoverMenu: true
}
},
@@ -122,16 +135,12 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = {
type: "object",
title: "构建参数",
description: "传递给Jenkins Job的构建参数",
- properties: {},
- additionalProperties: true,
default: {}
},
environmentVariables: {
type: "object",
title: "环境变量",
description: "构建时的环境变量",
- properties: {},
- additionalProperties: true,
default: {}
},
commitId: {
@@ -203,12 +212,6 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = {
type: "object",
title: "测试结果",
description: "构建中的测试结果统计",
- properties: {
- totalCount: { type: "number", title: "总测试数", default: 0 },
- passCount: { type: "number", title: "通过数", default: 0 },
- failCount: { type: "number", title: "失败数", default: 0 },
- skipCount: { type: "number", title: "跳过数", default: 0 }
- },
default: {
totalCount: 0,
passCount: 0,
@@ -221,167 +224,4 @@ export const JenkinsBuildNodeDefinition: ConfigurableNodeDefinition = {
}
};
-/**
- * Jenkins构建节点渲染组件
- */
-const JenkinsBuildNode: React.FC = ({ data, selected }) => {
- const nodeData = data as FlowNodeData;
- const [isHovered, setIsHovered] = React.useState(false);
-
- return (
- setIsHovered(true)}
- onMouseLeave={() => setIsHovered(false)}
- style={{
- padding: '16px 20px',
- borderRadius: '12px',
- border: `2px solid ${selected ? '#3b82f6' : isHovered ? '#73d13d' : '#e5e7eb'}`,
- background: selected
- ? 'linear-gradient(135deg, #ffffff 0%, #f0f9ff 100%)'
- : 'linear-gradient(135deg, #ffffff 0%, #f6ffed 100%)',
- minWidth: '160px',
- minHeight: '80px',
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'center',
- position: 'relative',
- boxShadow: selected
- ? '0 8px 16px rgba(59, 130, 246, 0.2), 0 2px 8px rgba(59, 130, 246, 0.1)'
- : isHovered
- ? '0 6px 16px rgba(82, 196, 26, 0.15), 0 2px 6px rgba(82, 196, 26, 0.08)'
- : '0 2px 8px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)',
- cursor: 'pointer',
- transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
- transform: isHovered ? 'translateY(-2px)' : 'translateY(0)',
- }}
- >
- {/* 输入连接点 */}
-
-
- {/* 节点内容 */}
-
- {/* 图标背景 */}
-
- 🔨
-
-
- {/* 标签 */}
-
- {nodeData.label || 'Jenkins构建'}
-
-
-
- {/* 输出连接点 */}
-
-
- {/* 配置指示器 */}
- {nodeData.configs && Object.keys(nodeData.configs).length > 3 && (
-
- ✓
-
- )}
-
- {/* Hover操作菜单 */}
- {isHovered && !selected && (
-
- )}
-
- );
-};
-
-export default memo(JenkinsBuildNode);
-
+// ✅ 不再需要单独的渲染组件,使用 BaseNode 即可
diff --git a/frontend/src/pages/Workflow/Design/nodes/StartEventNode.tsx b/frontend/src/pages/Workflow/Design/nodes/StartEventNode.tsx
index a892cac5..e1529839 100644
--- a/frontend/src/pages/Workflow/Design/nodes/StartEventNode.tsx
+++ b/frontend/src/pages/Workflow/Design/nodes/StartEventNode.tsx
@@ -1,10 +1,8 @@
-import React, { memo } from 'react';
-import { Handle, Position, NodeProps } from '@xyflow/react';
import { BaseNodeDefinition, NodeType, NodeCategory } from './types';
-import type { FlowNodeData } from '../types';
/**
- * 开始事件节点定义(元数据)
+ * 开始事件节点定义(纯配置)
+ * 使用 BaseNode 组件渲染,无需自定义渲染代码
*/
export const StartEventNodeDefinition: BaseNodeDefinition = {
nodeCode: "START_EVENT",
@@ -13,14 +11,29 @@ export const StartEventNodeDefinition: BaseNodeDefinition = {
category: NodeCategory.EVENT,
description: "工作流的起始节点",
- uiConfig: {
- size: { width: 80, height: 50 },
- style: {
- fill: '#52c41a',
- stroke: '#389e08',
- strokeWidth: 2,
- icon: 'play-circle',
- iconColor: '#fff'
+ // 渲染配置(配置驱动)
+ renderConfig: {
+ shape: 'circle',
+ size: { width: 100, height: 60 },
+ icon: {
+ type: 'emoji',
+ content: '▶️',
+ size: 40
+ },
+ theme: {
+ primary: '#10b981',
+ secondary: '#34d399',
+ selectedBorder: '#3b82f6',
+ hoverBorder: '#10b981',
+ gradient: ['#ecfdf5', '#d1fae5']
+ },
+ handles: {
+ input: false, // 开始节点无输入
+ output: true // 有输出
+ },
+ features: {
+ showBadge: false, // 开始节点不显示徽章
+ showHoverMenu: false // 开始节点不显示菜单
}
},
@@ -52,89 +65,4 @@ export const StartEventNodeDefinition: BaseNodeDefinition = {
}
};
-/**
- * 开始事件节点渲染组件
- */
-const StartEventNode: React.FC = ({ data, selected }) => {
- const nodeData = data as FlowNodeData;
- const [isHovered, setIsHovered] = React.useState(false);
-
- return (
- setIsHovered(true)}
- onMouseLeave={() => setIsHovered(false)}
- style={{
- padding: '12px',
- borderRadius: '50%',
- border: `3px solid ${selected ? '#3b82f6' : '#10b981'}`,
- background: selected
- ? 'linear-gradient(135deg, #d0fce8 0%, #a7f3d0 100%)'
- : 'linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%)',
- minWidth: '70px',
- minHeight: '70px',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- position: 'relative',
- boxShadow: selected
- ? '0 8px 16px rgba(59, 130, 246, 0.25), 0 2px 4px rgba(59, 130, 246, 0.15)'
- : isHovered
- ? '0 6px 12px rgba(16, 185, 129, 0.2), 0 2px 4px rgba(16, 185, 129, 0.1)'
- : '0 2px 8px rgba(0,0,0,0.08)',
- cursor: 'pointer',
- transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
- transform: isHovered ? 'scale(1.05)' : 'scale(1)',
- }}
- >
- {/* 图标 */}
-
- ▶️
-
-
- {/* 输出连接点 */}
-
-
- {/* 节点标签 */}
-
- {nodeData.label || '开始'}
-
-
- );
-};
-
-export default memo(StartEventNode);
-
+// ✅ 不再需要单独的渲染组件,使用 BaseNode 即可
diff --git a/frontend/src/pages/Workflow/Design/nodes/components/BaseNode.tsx b/frontend/src/pages/Workflow/Design/nodes/components/BaseNode.tsx
new file mode 100644
index 00000000..dee08638
--- /dev/null
+++ b/frontend/src/pages/Workflow/Design/nodes/components/BaseNode.tsx
@@ -0,0 +1,244 @@
+import React, { useState, CSSProperties } from 'react';
+import { Handle, Position, NodeProps } from '@xyflow/react';
+import type { FlowNodeData } from '../../types';
+
+/**
+ * 通用节点组件 - 配置驱动渲染
+ * 所有节点共用这一个组件,通过 renderConfig 配置不同样式
+ */
+const BaseNode: React.FC = ({ data, selected }) => {
+ const nodeData = data as FlowNodeData;
+ const definition = nodeData?.nodeDefinition;
+
+ // 如果没有 definition,显示错误提示
+ if (!definition) {
+ return 节点未配置定义
;
+ }
+
+ const config = definition.renderConfig;
+ const [isHovered, setIsHovered] = useState(false);
+
+ // 🎨 计算容器样式
+ const getContainerStyle = (): CSSProperties => {
+ const { shape, size, theme } = config;
+
+ const baseStyle: CSSProperties = {
+ minWidth: `${size.width}px`,
+ minHeight: `${size.height}px`,
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ position: 'relative',
+ cursor: 'pointer',
+ transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
+ };
+
+ // 根据形状设置样式
+ switch (shape) {
+ case 'circle':
+ baseStyle.borderRadius = '50%';
+ baseStyle.padding = '12px';
+ break;
+ case 'rounded-rect':
+ baseStyle.borderRadius = '12px';
+ baseStyle.padding = '16px 20px';
+ break;
+ case 'rect':
+ baseStyle.borderRadius = '4px';
+ baseStyle.padding = '16px 20px';
+ break;
+ case 'diamond':
+ baseStyle.transform = 'rotate(45deg)';
+ baseStyle.padding = '16px';
+ break;
+ }
+
+ // 边框和背景
+ const borderColor = selected
+ ? theme.selectedBorder
+ : isHovered
+ ? theme.hoverBorder
+ : '#e5e7eb';
+
+ baseStyle.border = `${selected ? '3px' : '2px'} solid ${borderColor}`;
+ baseStyle.background = selected
+ ? `linear-gradient(135deg, ${theme.gradient[0]} 0%, #f0f9ff 100%)`
+ : `linear-gradient(135deg, ${theme.gradient[0]} 0%, ${theme.gradient[1]} 100%)`;
+
+ // 阴影
+ baseStyle.boxShadow = selected
+ ? `0 8px 16px ${theme.selectedBorder}33, 0 2px 8px ${theme.selectedBorder}22`
+ : isHovered
+ ? `0 6px 16px ${theme.hoverBorder}26, 0 2px 6px ${theme.hoverBorder}14`
+ : '0 2px 8px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)';
+
+ // Hover 效果
+ if (isHovered) {
+ baseStyle.transform = 'translateY(-2px)';
+ }
+
+ return baseStyle;
+ };
+
+ // 🔌 计算连接点样式
+ const getHandleStyle = (): CSSProperties => {
+ return {
+ background: config.theme.primary,
+ border: '3px solid white',
+ width: '14px',
+ height: '14px',
+ boxShadow: '0 2px 4px rgba(0,0,0,0.15)',
+ transition: 'all 0.2s ease',
+ transform: isHovered ? 'scale(1.2)' : 'scale(1)',
+ };
+ };
+
+ // 🎭 渲染图标
+ const renderIcon = () => {
+ const { icon, theme } = config;
+
+ if (icon.type === 'emoji') {
+ return (
+
+
+ {icon.content}
+
+
+ );
+ }
+
+ // TODO: 支持自定义组件图标
+ return {icon.content};
+ };
+
+ // 🎖️ 渲染配置徽章
+ const renderBadge = () => {
+ if (!config.features.showBadge) return null;
+ if (!nodeData.configs || Object.keys(nodeData.configs).length <= 3) return null;
+
+ return (
+
+ ✓
+
+ );
+ };
+
+ // 📋 渲染 Hover 菜单
+ const renderHoverMenu = () => {
+ if (!config.features.showHoverMenu) return null;
+ if (!isHovered || selected) return null;
+
+ return (
+
+ );
+ };
+
+ return (
+ setIsHovered(true)}
+ onMouseLeave={() => setIsHovered(false)}
+ style={getContainerStyle()}
+ >
+ {/* 🔌 输入连接点 */}
+ {config.handles.input && (
+
+ )}
+
+ {/* 📦 节点内容 */}
+
+ {/* 🎭 图标 */}
+ {renderIcon()}
+
+ {/* 🏷️ 标签 */}
+
+ {nodeData.label || definition.nodeName}
+
+
+
+ {/* 🔌 输出连接点 */}
+ {config.handles.output && (
+
+ )}
+
+ {/* 🎖️ 配置徽章 */}
+ {renderBadge()}
+
+ {/* 📋 Hover 菜单 */}
+ {renderHoverMenu()}
+
+ );
+};
+
+export default React.memo(BaseNode);
+
diff --git a/frontend/src/pages/Workflow/Design/nodes/index.ts b/frontend/src/pages/Workflow/Design/nodes/index.ts
index cafc6725..62c39120 100644
--- a/frontend/src/pages/Workflow/Design/nodes/index.ts
+++ b/frontend/src/pages/Workflow/Design/nodes/index.ts
@@ -1,13 +1,13 @@
/**
* 节点定义统一导出
- * 每个节点文件同时导出:
- * 1. xxxDefinition - 节点元数据配置(给配置表单用)
- * 2. default export - 节点渲染组件(给画布用)
+ * 所有节点使用统一的 BaseNode 组件渲染
+ * 通过 renderConfig 配置不同的样式和行为
*/
-import StartEventNode, { StartEventNodeDefinition } from './StartEventNode';
-import EndEventNode, { EndEventNodeDefinition } from './EndEventNode';
-import JenkinsBuildNode, { JenkinsBuildNodeDefinition } from './JenkinsBuildNode';
+import BaseNode from './components/BaseNode';
+import { StartEventNodeDefinition } from './StartEventNode';
+import { EndEventNodeDefinition } from './EndEventNode';
+import { JenkinsBuildNodeDefinition } from './JenkinsBuildNode';
import type { WorkflowNodeDefinition } from './types';
/**
@@ -21,21 +21,20 @@ export const NODE_DEFINITIONS: WorkflowNodeDefinition[] = [
/**
* React Flow 节点类型映射(给 FlowCanvas 使用)
+ * ✨ 所有节点都使用 BaseNode 组件,通过 renderConfig 配置渲染
*/
export const nodeTypes = {
- START_EVENT: StartEventNode,
- END_EVENT: EndEventNode,
- JENKINS_BUILD: JenkinsBuildNode,
+ START_EVENT: BaseNode,
+ END_EVENT: BaseNode,
+ JENKINS_BUILD: BaseNode,
};
/**
* 单独导出(按需导入)
*/
export {
- // 组件
- StartEventNode,
- EndEventNode,
- JenkinsBuildNode,
+ // 通用组件
+ BaseNode,
// 定义
StartEventNodeDefinition,
diff --git a/frontend/src/pages/Workflow/Design/nodes/types.ts b/frontend/src/pages/Workflow/Design/nodes/types.ts
index ae702bc5..f20b8010 100644
--- a/frontend/src/pages/Workflow/Design/nodes/types.ts
+++ b/frontend/src/pages/Workflow/Design/nodes/types.ts
@@ -47,30 +47,53 @@ export const getNodeCategory = (nodeType: NodeType | string): NodeCategory => {
import type { ISchema } from '@formily/react';
export type JSONSchema = ISchema;
-// UI 配置
+// ========== 渲染配置(配置驱动节点渲染) ==========
+
+// 节点尺寸
export interface NodeSize {
width: number;
height: number;
}
-export interface NodeStyle {
- fill: string;
- icon: string;
- stroke: string;
- iconColor: string;
- strokeWidth: number;
- iconSize?: number;
- borderRadius?: string;
- boxShadow?: string;
- transition?: string;
- fontSize?: string;
- fontWeight?: string;
- fontFamily?: string;
+// 节点形状
+export type NodeShape = 'circle' | 'rounded-rect' | 'rect' | 'diamond';
+
+// 图标配置
+export interface IconConfig {
+ type: 'emoji' | 'component'; // emoji 或 React 组件
+ content: string; // emoji: "🔨", component: "JenkinsIcon"
+ size?: number; // 图标大小(默认 24)
}
-export interface UIConfig {
- size: NodeSize;
- style: NodeStyle;
+// 颜色主题配置
+export interface ThemeConfig {
+ primary: string; // 主色
+ secondary: string; // 次要色
+ selectedBorder: string; // 选中边框色
+ hoverBorder: string; // Hover 边框色
+ gradient: [string, string]; // 背景渐变 [起始, 结束]
+}
+
+// 连接点配置
+export interface HandlesConfig {
+ input: boolean; // 是否显示输入连接点
+ output: boolean; // 是否显示输出连接点
+}
+
+// 功能开关配置
+export interface FeaturesConfig {
+ showBadge: boolean; // 是否显示配置徽章
+ showHoverMenu: boolean; // 是否显示 Hover 菜单
+}
+
+// 完整的渲染配置
+export interface RenderConfig {
+ shape: NodeShape; // 节点形状
+ size: NodeSize; // 节点尺寸
+ icon: IconConfig; // 图标配置
+ theme: ThemeConfig; // 颜色主题
+ handles: HandlesConfig; // 连接点配置
+ features: FeaturesConfig; // 功能开关
}
// 基础节点定义(只有基本配置)
@@ -80,8 +103,8 @@ export interface BaseNodeDefinition {
nodeType: NodeType;
category: NodeCategory;
description: string;
- uiConfig: UIConfig;
- configSchema: JSONSchema; // 基本配置Schema(包含基本信息+节点配置)
+ renderConfig: RenderConfig; // ✨ 渲染配置(配置驱动)
+ configSchema: JSONSchema; // 基本配置Schema(包含基本信息+节点配置)
}
// 可配置节点定义(有3个TAB:基本配置、输入、输出)
@@ -108,7 +131,6 @@ export interface NodeInstanceData {
// UI位置信息
position: { x: number; y: number };
- uiConfig: UIConfig;
}
// 判断是否为可配置节点