1
This commit is contained in:
parent
978a24790a
commit
fa506b4d96
@ -1,7 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import { Modal, Form, Input, InputNumber, Radio } from 'antd';
|
||||
import { Edge } from '@antv/x6';
|
||||
import { ConditionType, EdgeCondition } from '../types';
|
||||
import { EdgeCondition } from '../nodes/types';
|
||||
|
||||
interface ExpressionModalProps {
|
||||
visible: boolean;
|
||||
|
||||
@ -45,8 +45,17 @@ const NodeConfigModal: React.FC<NodeConfigModalProps> = ({
|
||||
if (nodeDefinition && node) {
|
||||
// 从节点数据中获取现有配置
|
||||
const nodeData = node.getData() || {};
|
||||
|
||||
// 准备默认的基本信息配置
|
||||
const defaultConfig = {
|
||||
nodeName: nodeDefinition.nodeName, // 默认节点名称
|
||||
nodeCode: nodeDefinition.nodeCode, // 默认节点编码
|
||||
description: nodeDefinition.description // 默认节点描述
|
||||
};
|
||||
|
||||
// 合并默认值和已保存的配置
|
||||
setFormData({
|
||||
config: nodeData.config || {},
|
||||
config: { ...defaultConfig, ...(nodeData.config || {}) },
|
||||
inputMapping: nodeData.inputMapping || {},
|
||||
outputMapping: nodeData.outputMapping || {},
|
||||
});
|
||||
@ -92,6 +101,7 @@ const NodeConfigModal: React.FC<NodeConfigModalProps> = ({
|
||||
children: (
|
||||
<div style={{ padding: '16px 0' }}>
|
||||
<BetaSchemaForm
|
||||
key={`config-${node?.id}-${JSON.stringify(formData.config)}`}
|
||||
layoutType="Form"
|
||||
columns={convertJsonSchemaToColumns(nodeDefinition.configSchema as any)}
|
||||
initialValues={formData.config}
|
||||
@ -112,6 +122,7 @@ const NodeConfigModal: React.FC<NodeConfigModalProps> = ({
|
||||
children: (
|
||||
<div style={{ padding: '16px 0' }}>
|
||||
<BetaSchemaForm
|
||||
key={`input-${node?.id}-${JSON.stringify(formData.inputMapping)}`}
|
||||
layoutType="Form"
|
||||
columns={convertJsonSchemaToColumns(nodeDefinition.inputMappingSchema as any)}
|
||||
initialValues={formData.inputMapping}
|
||||
@ -130,6 +141,7 @@ const NodeConfigModal: React.FC<NodeConfigModalProps> = ({
|
||||
children: (
|
||||
<div style={{ padding: '16px 0' }}>
|
||||
<BetaSchemaForm
|
||||
key={`output-${node?.id}-${JSON.stringify(formData.outputMapping)}`}
|
||||
layoutType="Form"
|
||||
columns={convertJsonSchemaToColumns(nodeDefinition.outputMappingSchema as any)}
|
||||
initialValues={formData.outputMapping}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import {Card, Collapse, Tooltip, message} from 'antd';
|
||||
import type {NodeCategory} from '../types';
|
||||
import type {NodeCategory} from '../nodes/types';
|
||||
import {
|
||||
PlayCircleOutlined,
|
||||
StopOutlined,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import NodePanel from './NodePanel';
|
||||
import type { NodeDefinitionResponse } from "../nodes/nodeService";
|
||||
import type { WorkflowNodeDefinition } from "../nodes/nodeService";
|
||||
|
||||
interface WorkflowCanvasProps {
|
||||
graphContainerRef: React.RefObject<HTMLDivElement>;
|
||||
|
||||
@ -1,150 +0,0 @@
|
||||
// 节点端口配置
|
||||
export const PORT_GROUPS = ['top', 'right', 'bottom', 'left'] as const;
|
||||
|
||||
// 转换后端端口配置为X6格式
|
||||
export const convertPortConfig = (ports: any = {}) => {
|
||||
const { groups = {} } = ports;
|
||||
|
||||
// 转换groups配置
|
||||
const processedGroups: any = {};
|
||||
Object.entries(groups).forEach(([key, group]: [string, any]) => {
|
||||
processedGroups[key] = {
|
||||
...group,
|
||||
attrs: {
|
||||
circle: {
|
||||
...group.attrs?.circle,
|
||||
magnet: true,
|
||||
}
|
||||
},
|
||||
position: group.position
|
||||
};
|
||||
});
|
||||
|
||||
// 如果没有types,就用groups的key作为默认的items
|
||||
const items = Object.keys(groups).map(group => ({
|
||||
group: group
|
||||
}));
|
||||
|
||||
return {
|
||||
groups: processedGroups,
|
||||
items
|
||||
};
|
||||
};
|
||||
|
||||
// 默认样式配置
|
||||
export const DEFAULT_STYLES = {
|
||||
node: {
|
||||
stroke: '#5F95FF',
|
||||
strokeWidth: 2,
|
||||
fill: '#FFF',
|
||||
},
|
||||
label: {
|
||||
fontSize: 12,
|
||||
fill: '#000000',
|
||||
},
|
||||
edge: {
|
||||
stroke: '#1890ff',
|
||||
strokeWidth: 2,
|
||||
targetMarker: {
|
||||
name: 'classic',
|
||||
size: 8,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
// 默认节点大小
|
||||
export const NODE_SIZES = {
|
||||
circle: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
},
|
||||
rectangle: {
|
||||
width: 100,
|
||||
height: 50,
|
||||
},
|
||||
diamond: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
},
|
||||
} as const;
|
||||
|
||||
// 网格配置
|
||||
export const GRID_CONFIG = {
|
||||
size: 10,
|
||||
visible: true,
|
||||
type: 'dot',
|
||||
args: {
|
||||
color: '#a0a0a0',
|
||||
thickness: 1,
|
||||
},
|
||||
} as const;
|
||||
|
||||
// 连接配置
|
||||
export const CONNECTING_CONFIG = {
|
||||
snap: true,
|
||||
allowBlank: false,
|
||||
allowLoop: false,
|
||||
highlight: true,
|
||||
connector: 'rounded',
|
||||
connectionPoint: 'boundary',
|
||||
router: {
|
||||
name: 'manhattan'
|
||||
},
|
||||
validateConnection({
|
||||
sourceMagnet,
|
||||
targetMagnet
|
||||
}: any) {
|
||||
if (!sourceMagnet || !targetMagnet) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} as const;
|
||||
|
||||
// 高亮配置
|
||||
export const HIGHLIGHTING_CONFIG = {
|
||||
magnetAvailable: {
|
||||
name: 'stroke',
|
||||
args: {
|
||||
padding: 4,
|
||||
attrs: {
|
||||
strokeWidth: 4,
|
||||
stroke: '#52c41a',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
// 节点注册配置
|
||||
export const NODE_REGISTRY_CONFIG = {
|
||||
circle: {
|
||||
inherit: 'circle',
|
||||
width: NODE_SIZES.circle.width,
|
||||
height: NODE_SIZES.circle.height,
|
||||
attrs: {
|
||||
body: DEFAULT_STYLES.node,
|
||||
label: DEFAULT_STYLES.label,
|
||||
},
|
||||
},
|
||||
rectangle: {
|
||||
inherit: 'rect',
|
||||
width: NODE_SIZES.rectangle.width,
|
||||
height: NODE_SIZES.rectangle.height,
|
||||
attrs: {
|
||||
body: DEFAULT_STYLES.node,
|
||||
label: DEFAULT_STYLES.label,
|
||||
},
|
||||
},
|
||||
diamond: {
|
||||
inherit: 'polygon',
|
||||
width: NODE_SIZES.diamond.width,
|
||||
height: NODE_SIZES.diamond.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...DEFAULT_STYLES.node,
|
||||
refPoints: '0,10 10,0 20,10 10,20',
|
||||
},
|
||||
label: DEFAULT_STYLES.label,
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
@ -34,7 +34,9 @@ export const useWorkflowData = () => {
|
||||
// 加载工作流定义详情
|
||||
const loadDefinitionDetail = useCallback(async (graphInstance: Graph, definitionId: string) => {
|
||||
try {
|
||||
console.log('正在加载工作流定义详情, ID:', definitionId);
|
||||
const response = await getDefinitionDetail(Number(definitionId));
|
||||
console.log('工作流定义详情加载成功:', response);
|
||||
setTitle(`工作流设计 - ${response.name}`);
|
||||
setDefinitionData(response);
|
||||
|
||||
@ -142,52 +144,18 @@ export const useWorkflowData = () => {
|
||||
}
|
||||
}, [nodeDefinitions]);
|
||||
|
||||
// 合并 LocalVariables Schemas
|
||||
const mergeLocalVariablesSchemas = (schemas: any[]) => {
|
||||
const mergedSchema = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
required: []
|
||||
};
|
||||
|
||||
schemas.forEach(schema => {
|
||||
if (!schema) return;
|
||||
|
||||
// 合并 properties
|
||||
if (schema.properties) {
|
||||
Object.entries(schema.properties).forEach(([key, property]) => {
|
||||
if ((mergedSchema.properties as any)[key]) {
|
||||
if (JSON.stringify((mergedSchema.properties as any)[key]) !== JSON.stringify(property)) {
|
||||
console.warn(`属性 ${key} 在不同节点中定义不一致,使用第一个定义`);
|
||||
}
|
||||
} else {
|
||||
(mergedSchema.properties as any)[key] = property;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 合并 required 字段
|
||||
if (schema.required) {
|
||||
schema.required.forEach((field: string) => {
|
||||
if (!(mergedSchema.required as any).includes(field)) {
|
||||
(mergedSchema.required as any).push(field);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return mergedSchema;
|
||||
};
|
||||
|
||||
// 保存工作流
|
||||
const saveWorkflow = useCallback(async (graph: Graph) => {
|
||||
if (!graph) {
|
||||
console.error('Graph 实例为空');
|
||||
message.error('图形实例不存在,无法保存');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!definitionData) {
|
||||
console.error('definitionData 为空');
|
||||
console.error('definitionData 为空 - 工作流定义数据未加载');
|
||||
message.error('工作流定义数据未加载,请刷新页面重试');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -199,10 +167,9 @@ export const useWorkflowData = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有节点和边的数据
|
||||
// 获取所有节点和边的数据 - 只保存业务数据,不保存UI配置
|
||||
const nodes = graph.getNodes().map(node => {
|
||||
const nodeData = node.getData();
|
||||
const nodeDefinition = nodeDefinitions.find(def => def.nodeType === nodeData.nodeType);
|
||||
const position = node.getPosition();
|
||||
|
||||
return {
|
||||
@ -210,14 +177,10 @@ export const useWorkflowData = () => {
|
||||
nodeCode: nodeData.nodeCode,
|
||||
nodeType: nodeData.nodeType,
|
||||
nodeName: nodeData.nodeName,
|
||||
position,
|
||||
uiConfig: {
|
||||
...(nodeDefinition?.uiConfig || {}),
|
||||
position
|
||||
},
|
||||
config: nodeData.config || {},
|
||||
inputMapping: nodeData.inputMapping || {},
|
||||
outputMapping: nodeData.outputMapping || {}
|
||||
position, // 只保存位置信息
|
||||
config: nodeData.config || {}, // 节点配置数据
|
||||
inputMapping: nodeData.inputMapping || {}, // 输入映射数据
|
||||
outputMapping: nodeData.outputMapping || {} // 输出映射数据
|
||||
};
|
||||
});
|
||||
|
||||
@ -238,24 +201,13 @@ export const useWorkflowData = () => {
|
||||
};
|
||||
});
|
||||
|
||||
// 收集并合并所有节点的输入映射Schema (用于全局变量)
|
||||
const allInputSchemas = nodes
|
||||
.map(node => {
|
||||
const nodeDefinition = nodeDefinitions.find(def => def.nodeType === node.nodeType);
|
||||
// 检查是否为可配置节点并有输入映射Schema
|
||||
return 'inputMappingSchema' in nodeDefinition! ? nodeDefinition.inputMappingSchema : null;
|
||||
})
|
||||
.filter(schema => schema); // 过滤掉空值
|
||||
const mergedLocalSchema = mergeLocalVariablesSchemas(allInputSchemas);
|
||||
|
||||
// 构建保存数据
|
||||
// 构建保存数据 - 只保存图形结构,不保存Schema配置
|
||||
const saveData = {
|
||||
...definitionData,
|
||||
graph: {
|
||||
nodes,
|
||||
edges
|
||||
},
|
||||
localVariablesSchema: mergedLocalSchema
|
||||
}
|
||||
};
|
||||
|
||||
// 调用保存接口
|
||||
|
||||
@ -2,7 +2,7 @@ import { useState, useCallback } from 'react';
|
||||
import { Cell, Edge } from '@antv/x6';
|
||||
import { message } from 'antd';
|
||||
import type { WorkflowNodeDefinition } from '../nodes/types';
|
||||
import type { EdgeCondition } from '../types';
|
||||
import type { EdgeCondition } from '../nodes/types';
|
||||
|
||||
/**
|
||||
* 工作流弹窗管理 Hook
|
||||
|
||||
@ -1,17 +1,20 @@
|
||||
.workflow-design {
|
||||
position: relative;
|
||||
height: calc(100vh - 184px); // 120px + 24px * 2 + 16px
|
||||
height: calc(100vh - 184px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
background: #f8fafc;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
.header {
|
||||
padding: 16px;
|
||||
padding: 16px 24px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.back-button {
|
||||
margin-right: 16px;
|
||||
@ -35,11 +38,13 @@
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden; // 防止sidebar本身出现滚动条
|
||||
overflow: hidden;
|
||||
|
||||
:global {
|
||||
.ant-collapse {
|
||||
@ -69,6 +74,7 @@
|
||||
border-radius: 4px;
|
||||
cursor: move;
|
||||
transition: all 0.3s;
|
||||
background: #ffffff;
|
||||
|
||||
&:hover {
|
||||
background: #f5f5f5;
|
||||
@ -88,7 +94,7 @@
|
||||
position: relative;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
background: #f5f5f5;
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
|
||||
.workflow-canvas {
|
||||
|
||||
@ -64,7 +64,20 @@ const WorkflowDesign: React.FC = () => {
|
||||
|
||||
// 加载工作流数据
|
||||
useEffect(() => {
|
||||
console.log('工作流数据加载检查:', {
|
||||
hasGraph: !!graph,
|
||||
hasId: !!id,
|
||||
id,
|
||||
isNodeDefinitionsLoaded
|
||||
});
|
||||
|
||||
if (!id) {
|
||||
console.error('工作流ID缺失,无法加载定义数据');
|
||||
return;
|
||||
}
|
||||
|
||||
if (graph && id && isNodeDefinitionsLoaded) {
|
||||
console.log('开始加载工作流定义详情:', id);
|
||||
loadDefinitionDetail(graph, id);
|
||||
}
|
||||
}, [graph, id, isNodeDefinitionsLoaded, loadDefinitionDetail]);
|
||||
|
||||
@ -1,76 +0,0 @@
|
||||
/**
|
||||
* 节点数据转换器
|
||||
* 负责在设计时Schema格式和运行时key/value格式之间转换
|
||||
*/
|
||||
|
||||
import {
|
||||
ConfigurableNodeDefinition,
|
||||
NodeInstanceData,
|
||||
NodeFormData,
|
||||
WorkflowNodeDefinition,
|
||||
UIConfig
|
||||
} from './types';
|
||||
|
||||
export class NodeDataConverter {
|
||||
/**
|
||||
* 判断节点是否为可配置节点
|
||||
*/
|
||||
static isConfigurableNode(node: WorkflowNodeDefinition): node is ConfigurableNodeDefinition {
|
||||
return 'inputMappingSchema' in node || 'outputMappingSchema' in node;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存时:将用户表单数据转换为后端存储格式
|
||||
*/
|
||||
static convertToSaveFormat(
|
||||
nodeDefinition: WorkflowNodeDefinition,
|
||||
formData: NodeFormData,
|
||||
position: { x: number; y: number },
|
||||
uiConfig: UIConfig
|
||||
): NodeInstanceData {
|
||||
const baseData = {
|
||||
nodeCode: nodeDefinition.nodeCode,
|
||||
nodeName: nodeDefinition.nodeName,
|
||||
nodeType: nodeDefinition.nodeType,
|
||||
category: nodeDefinition.category,
|
||||
description: nodeDefinition.description,
|
||||
position,
|
||||
uiConfig,
|
||||
config: formData.config || {},
|
||||
};
|
||||
|
||||
// 如果是可配置节点,添加输入输出映射
|
||||
if (this.isConfigurableNode(nodeDefinition)) {
|
||||
return {
|
||||
...baseData,
|
||||
inputMapping: formData.inputMapping || {},
|
||||
outputMapping: formData.outputMapping || {}
|
||||
};
|
||||
}
|
||||
|
||||
return baseData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载时:将后端数据转换为表单格式
|
||||
*/
|
||||
static convertToFormFormat(
|
||||
nodeDefinition: WorkflowNodeDefinition,
|
||||
savedData: NodeInstanceData
|
||||
): NodeFormData {
|
||||
const formData: NodeFormData = {
|
||||
config: savedData.config || {}
|
||||
};
|
||||
|
||||
// 如果是可配置节点,添加输入输出映射
|
||||
if (this.isConfigurableNode(nodeDefinition)) {
|
||||
return {
|
||||
...formData,
|
||||
inputMapping: savedData.inputMapping || {},
|
||||
outputMapping: savedData.outputMapping || {}
|
||||
};
|
||||
}
|
||||
|
||||
return formData;
|
||||
}
|
||||
}
|
||||
@ -11,12 +11,12 @@ export const DeployNode: ConfigurableNodeDefinition = {
|
||||
category: NodeCategory.TASK,
|
||||
description: "执行应用构建和部署任务",
|
||||
|
||||
// UI 配置 - 节点在画布上的显示样式
|
||||
// UI 配置 - 节点在画布上的显示样式(现代化设计)
|
||||
uiConfig: {
|
||||
shape: 'rect',
|
||||
size: {
|
||||
width: 120,
|
||||
height: 60
|
||||
size: {
|
||||
width: 160,
|
||||
height: 80
|
||||
},
|
||||
style: {
|
||||
fill: '#1890ff',
|
||||
@ -27,24 +27,44 @@ export const DeployNode: ConfigurableNodeDefinition = {
|
||||
},
|
||||
ports: {
|
||||
groups: {
|
||||
// 输入端口 - 现代化样式
|
||||
in: {
|
||||
position: 'left',
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 4,
|
||||
fill: '#fff',
|
||||
stroke: '#1890ff'
|
||||
}
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 7,
|
||||
fill: '#ffffff',
|
||||
stroke: '#3b82f6',
|
||||
strokeWidth: 2.5,
|
||||
// 现代化端口样式
|
||||
filter: 'drop-shadow(0 2px 4px rgba(59, 130, 246, 0.3))',
|
||||
// 端口悬浮效果
|
||||
':hover': {
|
||||
r: 8,
|
||||
fill: '#dbeafe',
|
||||
stroke: '#2563eb'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// 输出端口 - 现代化样式
|
||||
out: {
|
||||
position: 'right',
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 4,
|
||||
fill: '#fff',
|
||||
stroke: '#1890ff'
|
||||
}
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 7,
|
||||
fill: '#ffffff',
|
||||
stroke: '#3b82f6',
|
||||
strokeWidth: 2.5,
|
||||
// 现代化端口样式
|
||||
filter: 'drop-shadow(0 2px 4px rgba(59, 130, 246, 0.3))',
|
||||
// 端口悬浮效果
|
||||
':hover': {
|
||||
r: 8,
|
||||
fill: '#dbeafe',
|
||||
stroke: '#2563eb'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -61,17 +81,20 @@ export const DeployNode: ConfigurableNodeDefinition = {
|
||||
nodeName: {
|
||||
type: "string",
|
||||
title: "节点名称",
|
||||
description: "节点在流程图中显示的名称"
|
||||
description: "节点在流程图中显示的名称",
|
||||
default: "构建任务"
|
||||
},
|
||||
nodeCode: {
|
||||
type: "string",
|
||||
title: "节点编码",
|
||||
description: "节点的唯一标识符"
|
||||
description: "节点的唯一标识符",
|
||||
default: "DEPLOY_NODE"
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
title: "节点描述",
|
||||
description: "节点的详细说明"
|
||||
description: "节点的详细说明",
|
||||
default: "执行应用构建和部署任务"
|
||||
},
|
||||
// 节点配置
|
||||
buildCommand: {
|
||||
|
||||
@ -11,30 +11,30 @@ export const EndEventNode: BaseNodeDefinition = {
|
||||
category: NodeCategory.EVENT,
|
||||
description: "工作流的结束节点",
|
||||
|
||||
// UI 配置 - 节点在画布上的显示样式
|
||||
// UI 配置 - 节点在画布上的显示样式(现代化设计)
|
||||
uiConfig: {
|
||||
shape: 'circle',
|
||||
size: {
|
||||
width: 40,
|
||||
height: 40
|
||||
width: 60,
|
||||
height: 60
|
||||
},
|
||||
style: {
|
||||
fill: '#f5222d',
|
||||
stroke: '#cf1322',
|
||||
strokeWidth: 1,
|
||||
strokeWidth: 2,
|
||||
icon: 'stop',
|
||||
iconColor: '#fff'
|
||||
},
|
||||
ports: {
|
||||
groups: {
|
||||
// 结束节点只有输入端口
|
||||
// 结束节点只有输入端口 - 现代化样式
|
||||
in: {
|
||||
position: 'left',
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 4,
|
||||
fill: '#fff',
|
||||
stroke: '#f5222d'
|
||||
stroke: '#f5222d'
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,17 +51,20 @@ export const EndEventNode: BaseNodeDefinition = {
|
||||
nodeName: {
|
||||
type: "string",
|
||||
title: "节点名称",
|
||||
description: "节点在流程图中显示的名称"
|
||||
description: "节点在流程图中显示的名称",
|
||||
default: "结束"
|
||||
},
|
||||
nodeCode: {
|
||||
type: "string",
|
||||
title: "节点编码",
|
||||
description: "节点的唯一标识符"
|
||||
description: "节点的唯一标识符",
|
||||
default: "END_EVENT"
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
title: "节点描述",
|
||||
description: "节点的详细说明"
|
||||
description: "节点的详细说明",
|
||||
default: "工作流的结束节点"
|
||||
}
|
||||
},
|
||||
required: ["nodeName", "nodeCode"]
|
||||
|
||||
@ -1,69 +1,72 @@
|
||||
import { BaseNodeDefinition, NodeType, NodeCategory } from '../types';
|
||||
import {BaseNodeDefinition, NodeType, NodeCategory} from '../types';
|
||||
|
||||
/**
|
||||
* 开始事件节点定义
|
||||
* 简单节点,无需额外配置
|
||||
*/
|
||||
export const StartEventNode: BaseNodeDefinition = {
|
||||
nodeCode: "START_EVENT",
|
||||
nodeName: "开始",
|
||||
nodeType: NodeType.START_EVENT,
|
||||
category: NodeCategory.EVENT,
|
||||
description: "工作流的起始节点",
|
||||
|
||||
// UI 配置 - 节点在画布上的显示样式
|
||||
nodeCode: "START_EVENT",
|
||||
nodeName: "开始",
|
||||
nodeType: NodeType.START_EVENT,
|
||||
category: NodeCategory.EVENT,
|
||||
description: "工作流的起始节点",
|
||||
|
||||
// UI 配置 - 节点在画布上的显示样式(现代化设计)
|
||||
uiConfig: {
|
||||
shape: 'circle',
|
||||
size: {
|
||||
width: 40,
|
||||
height: 40
|
||||
width: 60,
|
||||
height: 60
|
||||
},
|
||||
style: {
|
||||
fill: '#52c41a',
|
||||
stroke: '#389e08',
|
||||
strokeWidth: 1,
|
||||
strokeWidth: 2,
|
||||
icon: 'play-circle',
|
||||
iconColor: '#fff'
|
||||
},
|
||||
ports: {
|
||||
groups: {
|
||||
// 开始节点只有输出端口
|
||||
// 开始节点只有输出端口 - 现代化样式
|
||||
out: {
|
||||
position: 'right',
|
||||
attrs: {
|
||||
circle: {
|
||||
r: 4,
|
||||
fill: '#fff',
|
||||
stroke: '#52c41a'
|
||||
stroke: '#52c41a'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 基本配置Schema - 用于生成"基本配置"TAB(包含基本信息)
|
||||
configSchema: {
|
||||
type: "object",
|
||||
title: "基本配置",
|
||||
description: "节点的基本配置信息",
|
||||
properties: {
|
||||
nodeName: {
|
||||
type: "string",
|
||||
title: "节点名称",
|
||||
description: "节点在流程图中显示的名称"
|
||||
},
|
||||
nodeCode: {
|
||||
type: "string",
|
||||
title: "节点编码",
|
||||
description: "节点的唯一标识符"
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
title: "节点描述",
|
||||
description: "节点的详细说明"
|
||||
}
|
||||
},
|
||||
required: ["nodeName", "nodeCode"]
|
||||
}
|
||||
|
||||
// 基本配置Schema - 用于生成"基本配置"TAB(包含基本信息)
|
||||
configSchema: {
|
||||
type: "object",
|
||||
title: "基本配置",
|
||||
description: "节点的基本配置信息",
|
||||
properties: {
|
||||
nodeName: {
|
||||
type: "string",
|
||||
title: "节点名称",
|
||||
description: "节点在流程图中显示的名称",
|
||||
default: "开始"
|
||||
},
|
||||
nodeCode: {
|
||||
type: "string",
|
||||
title: "节点编码",
|
||||
description: "节点的唯一标识符",
|
||||
default: "START_EVENT"
|
||||
},
|
||||
description: {
|
||||
type: "string",
|
||||
title: "节点描述",
|
||||
description: "节点的详细说明",
|
||||
default: "工作流的起始节点"
|
||||
}
|
||||
},
|
||||
required: ["nodeName", "nodeCode"]
|
||||
}
|
||||
};
|
||||
@ -1,76 +1,23 @@
|
||||
import { WorkflowNodeDefinition, NodeCategory, NodeType } from '../types';
|
||||
import { NodeDataConverter } from '../NodeDataConverter';
|
||||
import { DeployNode } from './DeployNode';
|
||||
import { StartEventNode } from './StartEventNode';
|
||||
import { EndEventNode } from './EndEventNode';
|
||||
import {WorkflowNodeDefinition, ConfigurableNodeDefinition, NodeCategory, NodeType} from '../types';
|
||||
import {DeployNode} from './DeployNode';
|
||||
import {StartEventNode} from './StartEventNode';
|
||||
import {EndEventNode} from './EndEventNode';
|
||||
|
||||
/**
|
||||
* 所有节点定义的注册表
|
||||
*/
|
||||
export const NODE_DEFINITIONS: WorkflowNodeDefinition[] = [
|
||||
StartEventNode,
|
||||
EndEventNode,
|
||||
DeployNode,
|
||||
// 在这里添加更多节点定义
|
||||
StartEventNode,
|
||||
EndEventNode,
|
||||
DeployNode,
|
||||
// 在这里添加更多节点定义
|
||||
];
|
||||
|
||||
/**
|
||||
* 根据节点类型获取节点定义
|
||||
*/
|
||||
export const getNodeDefinition = (nodeType: NodeType): WorkflowNodeDefinition | undefined => {
|
||||
return NODE_DEFINITIONS.find(node => node.nodeType === nodeType);
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据节点代码获取节点定义
|
||||
*/
|
||||
export const getNodeDefinitionByCode = (nodeCode: string): WorkflowNodeDefinition | undefined => {
|
||||
return NODE_DEFINITIONS.find(node => node.nodeCode === nodeCode);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取指定分类的所有节点
|
||||
*/
|
||||
export const getNodesByCategory = (category: NodeCategory): WorkflowNodeDefinition[] => {
|
||||
return NODE_DEFINITIONS.filter(node => node.category === category);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取按分类分组的节点定义
|
||||
*/
|
||||
export const getNodesByCategories = (): Record<NodeCategory, WorkflowNodeDefinition[]> => {
|
||||
return NODE_DEFINITIONS.reduce((acc, node) => {
|
||||
if (!acc[node.category]) {
|
||||
acc[node.category] = [];
|
||||
}
|
||||
acc[node.category].push(node);
|
||||
return acc;
|
||||
}, {} as Record<NodeCategory, WorkflowNodeDefinition[]>);
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取所有已启用的节点定义
|
||||
*/
|
||||
export const getEnabledNodes = (): WorkflowNodeDefinition[] => {
|
||||
// 目前所有节点都是启用的,后续可以添加enabled字段
|
||||
return NODE_DEFINITIONS;
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查节点是否为可配置节点
|
||||
*/
|
||||
export const isConfigurableNode = NodeDataConverter.isConfigurableNode;
|
||||
|
||||
/**
|
||||
* 导出节点定义
|
||||
*/
|
||||
export {
|
||||
StartEventNode,
|
||||
EndEventNode,
|
||||
DeployNode
|
||||
StartEventNode,
|
||||
EndEventNode,
|
||||
DeployNode
|
||||
};
|
||||
|
||||
/**
|
||||
* 导出数据转换器
|
||||
*/
|
||||
export { NodeDataConverter };
|
||||
@ -2,58 +2,16 @@
|
||||
* 节点服务 - 提供节点定义的访问接口
|
||||
*/
|
||||
|
||||
import {
|
||||
NODE_DEFINITIONS,
|
||||
getNodeDefinition,
|
||||
getNodesByCategory,
|
||||
getNodesByCategories
|
||||
} from './definitions';
|
||||
import {
|
||||
WorkflowNodeDefinition,
|
||||
NodeType,
|
||||
NodeCategory
|
||||
} from './types';
|
||||
import {NODE_DEFINITIONS} from './definitions';
|
||||
import {WorkflowNodeDefinition} from './types';
|
||||
|
||||
/**
|
||||
* 获取所有节点定义列表
|
||||
*/
|
||||
export const getNodeDefinitionList = async (): Promise<WorkflowNodeDefinition[]> => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(NODE_DEFINITIONS);
|
||||
}, 10);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取节点定义列表,按分类分组
|
||||
*/
|
||||
export const getNodeDefinitionsGroupedByCategory = async (): Promise<Record<NodeCategory, WorkflowNodeDefinition[]>> => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(getNodesByCategories());
|
||||
}, 10);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据节点类型获取节点定义
|
||||
*/
|
||||
export const getNodeDefinitionByType = async (nodeType: NodeType): Promise<WorkflowNodeDefinition | undefined> => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(getNodeDefinition(nodeType));
|
||||
}, 10);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据分类获取节点定义
|
||||
*/
|
||||
export const getNodeDefinitionsByCategory = async (category: NodeCategory): Promise<WorkflowNodeDefinition[]> => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(getNodesByCategory(category));
|
||||
}, 10);
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(NODE_DEFINITIONS);
|
||||
}, 10);
|
||||
});
|
||||
};
|
||||
@ -1,4 +1,22 @@
|
||||
import { BaseResponse } from "@/types/base";
|
||||
|
||||
// 节点分类 (从 ../types.ts 合并)
|
||||
export enum NodeCategory {
|
||||
EVENT = 'EVENT',
|
||||
TASK = 'TASK',
|
||||
GATEWAY = 'GATEWAY',
|
||||
CONTAINER = 'CONTAINER'
|
||||
}
|
||||
|
||||
// 条件类型
|
||||
export type ConditionType = 'EXPRESSION' | 'SCRIPT' | 'DEFAULT';
|
||||
|
||||
// 边的条件配置
|
||||
export interface EdgeCondition {
|
||||
type: ConditionType;
|
||||
expression?: string;
|
||||
script?: string;
|
||||
priority: number;
|
||||
}
|
||||
|
||||
// JSON Schema 定义
|
||||
export interface JSONSchema {
|
||||
@ -19,6 +37,13 @@ export interface PortStyle {
|
||||
r: number;
|
||||
fill: string;
|
||||
stroke: string;
|
||||
strokeWidth?: number; // 新增:端口描边宽度
|
||||
filter?: string; // 新增:端口滤镜效果
|
||||
':hover'?: { // 新增:端口悬浮状态
|
||||
r?: number;
|
||||
fill?: string;
|
||||
stroke?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PortAttributes {
|
||||
@ -45,6 +70,24 @@ export interface NodeStyle {
|
||||
stroke: string;
|
||||
iconColor: string;
|
||||
strokeWidth: number;
|
||||
// 现代化样式属性
|
||||
iconSize?: number; // 新增:图标大小
|
||||
borderRadius?: string; // 新增:圆角
|
||||
boxShadow?: string; // 新增:阴影
|
||||
transition?: string; // 新增:过渡效果
|
||||
fontSize?: string; // 新增:字体大小
|
||||
fontWeight?: string; // 新增:字体粗细
|
||||
fontFamily?: string; // 新增:字体族
|
||||
':hover'?: { // 新增:悬浮状态
|
||||
fill?: string;
|
||||
stroke?: string;
|
||||
boxShadow?: string;
|
||||
transform?: string;
|
||||
};
|
||||
':active'?: { // 新增:激活状态
|
||||
transform?: string;
|
||||
boxShadow?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface UIConfig {
|
||||
@ -59,23 +102,17 @@ export interface UIConfig {
|
||||
|
||||
// 节点类型和分类(保持原有的枚举格式)
|
||||
export enum NodeType {
|
||||
START_EVENT = 'START_EVENT',
|
||||
END_EVENT = 'END_EVENT',
|
||||
USER_TASK = 'USER_TASK',
|
||||
SERVICE_TASK = 'SERVICE_TASK',
|
||||
SCRIPT_TASK = 'SCRIPT_TASK',
|
||||
DEPLOY_NODE = 'DEPLOY_NODE',
|
||||
GATEWAY_NODE = 'GATEWAY_NODE',
|
||||
SUB_PROCESS = 'SUB_PROCESS',
|
||||
CALL_ACTIVITY = 'CALL_ACTIVITY'
|
||||
START_EVENT = 'START_EVENT',
|
||||
END_EVENT = 'END_EVENT',
|
||||
USER_TASK = 'USER_TASK',
|
||||
SERVICE_TASK = 'SERVICE_TASK',
|
||||
SCRIPT_TASK = 'SCRIPT_TASK',
|
||||
DEPLOY_NODE = 'DEPLOY_NODE',
|
||||
GATEWAY_NODE = 'GATEWAY_NODE',
|
||||
SUB_PROCESS = 'SUB_PROCESS',
|
||||
CALL_ACTIVITY = 'CALL_ACTIVITY'
|
||||
}
|
||||
|
||||
export enum NodeCategory {
|
||||
EVENT = 'EVENT',
|
||||
TASK = 'TASK',
|
||||
GATEWAY = 'GATEWAY',
|
||||
CONTAINER = 'CONTAINER'
|
||||
}
|
||||
|
||||
// 基础节点定义(只有基本配置)
|
||||
export interface BaseNodeDefinition {
|
||||
@ -104,37 +141,13 @@ export interface NodeInstanceData {
|
||||
nodeType: NodeType;
|
||||
category: NodeCategory;
|
||||
description?: string;
|
||||
|
||||
|
||||
// 运行时数据(key/value格式)
|
||||
config?: Record<string, any>; // 基本配置数据(包含基本信息+节点配置)
|
||||
configs?: Record<string, any>; // 基本配置数据(包含基本信息+节点配置)
|
||||
inputMapping?: Record<string, any>;
|
||||
outputMapping?: Record<string, any>;
|
||||
|
||||
|
||||
// UI位置信息
|
||||
position: { x: number; y: number };
|
||||
uiConfig: UIConfig; // 包含运行时可能更新的UI配置,如位置
|
||||
}
|
||||
|
||||
// 兼容现有API的响应格式
|
||||
export interface NodeDefinitionResponse extends BaseResponse {
|
||||
nodeCode: string;
|
||||
nodeName: string;
|
||||
nodeType: NodeType;
|
||||
category: NodeCategory;
|
||||
description: string;
|
||||
uiConfig: UIConfig | null;
|
||||
configSchema?: JSONSchema | null; // 基本配置Schema
|
||||
|
||||
// 兼容字段(保持现有组件正常工作)
|
||||
panelVariablesSchema?: JSONSchema | null;
|
||||
localVariablesSchema?: JSONSchema | null;
|
||||
panelVariables?: Record<string, any>;
|
||||
localVariables?: Record<string, any>;
|
||||
}
|
||||
|
||||
// 数据转换器工具类型
|
||||
export interface NodeFormData {
|
||||
config?: Record<string, any>; // 基本配置表单数据(包含基本信息+节点配置)
|
||||
inputMapping?: Record<string, any>;
|
||||
outputMapping?: Record<string, any>;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
// 节点分类
|
||||
export type NodeCategory = 'EVENT' | 'TASK' | 'GATEWAY' | 'CONTAINER';
|
||||
|
||||
// 条件类型
|
||||
export type ConditionType = 'EXPRESSION' | 'SCRIPT' | 'DEFAULT';
|
||||
|
||||
// 边的条件配置
|
||||
export interface EdgeCondition {
|
||||
type: ConditionType;
|
||||
expression?: string;
|
||||
script?: string;
|
||||
priority: number;
|
||||
}
|
||||
@ -44,7 +44,7 @@ export class EventRegistrar {
|
||||
PortManager.showPorts(node.id);
|
||||
});
|
||||
|
||||
this.graph.on('node:mouseleave', ({node}: any) => {
|
||||
this.graph.on('node:mouseleave', ({node}) => {
|
||||
NodeStyleManager.resetNodeStyle(node);
|
||||
PortManager.hidePorts(node.id);
|
||||
});
|
||||
|
||||
@ -1,135 +1,136 @@
|
||||
import { Graph } from '@antv/x6';
|
||||
import { WorkflowNodeDefinition, NodeInstanceData } from '../nodes/types';
|
||||
import {Graph} from '@antv/x6';
|
||||
import {WorkflowNodeDefinition, NodeInstanceData} from '../nodes/types';
|
||||
|
||||
/**
|
||||
* 从节点定义创建新节点
|
||||
*/
|
||||
export const createNodeFromDefinition = (
|
||||
graph: Graph,
|
||||
nodeDefinition: WorkflowNodeDefinition,
|
||||
position: { x: number; y: number }
|
||||
graph: Graph,
|
||||
nodeDefinition: WorkflowNodeDefinition,
|
||||
position: { x: number; y: number }
|
||||
) => {
|
||||
const { uiConfig } = nodeDefinition;
|
||||
|
||||
// 根据形状类型设置正确的 shape
|
||||
let shape = 'rect';
|
||||
if (uiConfig.shape === 'circle') {
|
||||
shape = 'circle';
|
||||
} else if (uiConfig.shape === 'diamond') {
|
||||
shape = 'polygon';
|
||||
}
|
||||
const {uiConfig} = nodeDefinition;
|
||||
|
||||
// 创建节点配置
|
||||
const nodeConfig = {
|
||||
shape,
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
width: uiConfig.size.width,
|
||||
height: uiConfig.size.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...uiConfig.style,
|
||||
...(uiConfig.shape === 'diamond' ? {
|
||||
refPoints: '0,10 10,0 20,10 10,20',
|
||||
} : {})
|
||||
},
|
||||
label: {
|
||||
text: nodeDefinition.nodeName,
|
||||
fontSize: 12,
|
||||
fill: '#000'
|
||||
},
|
||||
},
|
||||
ports: convertPortConfig(uiConfig.ports),
|
||||
// 同时设置为props和data,方便访问
|
||||
nodeType: nodeDefinition.nodeType,
|
||||
nodeCode: nodeDefinition.nodeCode,
|
||||
data: {
|
||||
nodeType: nodeDefinition.nodeType,
|
||||
nodeCode: nodeDefinition.nodeCode,
|
||||
nodeName: nodeDefinition.nodeName
|
||||
// 根据形状类型设置正确的 shape
|
||||
let shape = 'rect';
|
||||
if (uiConfig.shape === 'circle') {
|
||||
shape = 'circle';
|
||||
} else if (uiConfig.shape === 'diamond') {
|
||||
shape = 'polygon';
|
||||
}
|
||||
};
|
||||
|
||||
return graph.addNode(nodeConfig);
|
||||
// 创建节点配置
|
||||
const nodeConfig = {
|
||||
shape,
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
width: uiConfig.size.width,
|
||||
height: uiConfig.size.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...uiConfig.style,
|
||||
...(uiConfig.shape === 'diamond' ? {
|
||||
refPoints: '0,10 10,0 20,10 10,20',
|
||||
} : {})
|
||||
},
|
||||
label: {
|
||||
text: nodeDefinition.nodeName,
|
||||
fontSize: 12,
|
||||
fill: '#000'
|
||||
},
|
||||
},
|
||||
ports: convertPortConfig(uiConfig.ports),
|
||||
// 同时设置为props和data,方便访问
|
||||
nodeType: nodeDefinition.nodeType,
|
||||
nodeCode: nodeDefinition.nodeCode,
|
||||
data: {
|
||||
nodeType: nodeDefinition.nodeType,
|
||||
nodeCode: nodeDefinition.nodeCode,
|
||||
nodeName: nodeDefinition.nodeName
|
||||
}
|
||||
};
|
||||
|
||||
return graph.addNode(nodeConfig);
|
||||
};
|
||||
|
||||
/**
|
||||
* 从保存的数据恢复节点
|
||||
*/
|
||||
export const restoreNodeFromData = (
|
||||
graph: Graph,
|
||||
nodeData: NodeInstanceData,
|
||||
_nodeDefinition: WorkflowNodeDefinition
|
||||
graph: Graph,
|
||||
nodeData: NodeInstanceData,
|
||||
nodeDefinition: WorkflowNodeDefinition
|
||||
) => {
|
||||
const { uiConfig } = nodeData;
|
||||
|
||||
// 根据形状类型设置正确的 shape
|
||||
let shape = 'rect';
|
||||
if (uiConfig.shape === 'circle') {
|
||||
shape = 'circle';
|
||||
} else if (uiConfig.shape === 'diamond') {
|
||||
shape = 'polygon';
|
||||
}
|
||||
// 从节点定义中获取UI配置,兼容旧数据中的uiConfig
|
||||
const uiConfig = nodeData.uiConfig || nodeDefinition.uiConfig;
|
||||
|
||||
// 创建节点配置
|
||||
const nodeConfig = {
|
||||
id: nodeData.nodeCode, // 使用保存的ID
|
||||
shape,
|
||||
x: nodeData.position.x,
|
||||
y: nodeData.position.y,
|
||||
width: uiConfig.size.width,
|
||||
height: uiConfig.size.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...uiConfig.style,
|
||||
...(uiConfig.shape === 'diamond' ? {
|
||||
refPoints: '0,10 10,0 20,10 10,20',
|
||||
} : {})
|
||||
},
|
||||
label: {
|
||||
text: nodeData.nodeName,
|
||||
fontSize: 12,
|
||||
fill: '#000'
|
||||
},
|
||||
},
|
||||
ports: convertPortConfig(uiConfig.ports),
|
||||
// 同时设置为props和data,方便访问
|
||||
nodeType: nodeData.nodeType,
|
||||
nodeCode: nodeData.nodeCode,
|
||||
data: {
|
||||
nodeType: nodeData.nodeType,
|
||||
nodeCode: nodeData.nodeCode,
|
||||
nodeName: nodeData.nodeName,
|
||||
config: nodeData.config,
|
||||
inputMapping: nodeData.inputMapping,
|
||||
outputMapping: nodeData.outputMapping
|
||||
// 根据形状类型设置正确的 shape
|
||||
let shape = 'rect';
|
||||
if (uiConfig.shape === 'circle') {
|
||||
shape = 'circle';
|
||||
} else if (uiConfig.shape === 'diamond') {
|
||||
shape = 'polygon';
|
||||
}
|
||||
};
|
||||
|
||||
return graph.addNode(nodeConfig);
|
||||
// 创建节点配置
|
||||
const nodeConfig = {
|
||||
id: nodeData.nodeCode, // 使用保存的ID
|
||||
shape,
|
||||
x: nodeData.position.x,
|
||||
y: nodeData.position.y,
|
||||
width: uiConfig.size.width,
|
||||
height: uiConfig.size.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...uiConfig.style,
|
||||
...(uiConfig.shape === 'diamond' ? {
|
||||
refPoints: '0,10 10,0 20,10 10,20',
|
||||
} : {})
|
||||
},
|
||||
label: {
|
||||
text: nodeData.nodeName,
|
||||
fontSize: 12,
|
||||
fill: '#000'
|
||||
},
|
||||
},
|
||||
ports: convertPortConfig(uiConfig.ports),
|
||||
// 同时设置为props和data,方便访问
|
||||
nodeType: nodeData.nodeType,
|
||||
nodeCode: nodeData.nodeCode,
|
||||
data: {
|
||||
nodeType: nodeData.nodeType,
|
||||
nodeCode: nodeData.nodeCode,
|
||||
nodeName: nodeData.nodeName,
|
||||
configs: nodeData.configs,
|
||||
inputMapping: nodeData.inputMapping,
|
||||
outputMapping: nodeData.outputMapping
|
||||
}
|
||||
};
|
||||
|
||||
return graph.addNode(nodeConfig);
|
||||
};
|
||||
|
||||
/**
|
||||
* 转换端口配置为X6格式
|
||||
*/
|
||||
const convertPortConfig = (ports: any) => {
|
||||
if (!ports?.groups) return { items: [] };
|
||||
|
||||
const groups: any = {};
|
||||
const items: any[] = [];
|
||||
if (!ports?.groups) return {items: []};
|
||||
|
||||
Object.entries(ports.groups).forEach(([key, group]: [string, any]) => {
|
||||
groups[key] = {
|
||||
position: group.position,
|
||||
attrs: {
|
||||
circle: {
|
||||
...group.attrs.circle,
|
||||
magnet: true,
|
||||
}
|
||||
}
|
||||
};
|
||||
items.push({ group: key });
|
||||
});
|
||||
const groups: any = {};
|
||||
const items: any[] = [];
|
||||
|
||||
return { groups, items };
|
||||
Object.entries(ports.groups).forEach(([key, group]: [string, any]) => {
|
||||
groups[key] = {
|
||||
position: group.position,
|
||||
attrs: {
|
||||
circle: {
|
||||
...group.attrs.circle,
|
||||
magnet: true,
|
||||
}
|
||||
}
|
||||
};
|
||||
items.push({group: key});
|
||||
});
|
||||
|
||||
return {groups, items};
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user