增加工具栏提示。
This commit is contained in:
parent
989abcae89
commit
9e35ac490e
@ -3,18 +3,18 @@ import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Button, Space, Card, Row, Col, message } from 'antd';
|
||||
import { ArrowLeftOutlined, SaveOutlined, PlayCircleOutlined } from '@ant-design/icons';
|
||||
import { Graph, Cell } from '@antv/x6';
|
||||
import dagre from 'dagre';
|
||||
import { getDefinitionDetail, saveDefinition } from '../service';
|
||||
import NodePanel from './components/NodePanel';
|
||||
import NodeConfigDrawer from './components/NodeConfigModal';
|
||||
import { NodeDefinition } from './types';
|
||||
import { validateWorkflow } from './utils/validator';
|
||||
import { addNodeToGraph } from './utils/nodeUtils';
|
||||
import { applyAutoLayout } from './utils/layoutUtils';
|
||||
import {
|
||||
GRID_CONFIG,
|
||||
CONNECTING_CONFIG,
|
||||
HIGHLIGHTING_CONFIG,
|
||||
DEFAULT_STYLES,
|
||||
convertPortConfig
|
||||
} from './constants';
|
||||
|
||||
const WorkflowDesign: React.FC = () => {
|
||||
@ -96,60 +96,16 @@ const WorkflowDesign: React.FC = () => {
|
||||
const loadDefinitionDetail = async (graphInstance: Graph, definitionId: number) => {
|
||||
try {
|
||||
const response = await getDefinitionDetail(definitionId);
|
||||
console.log('加载到的工作流数据:', response);
|
||||
setTitle(`工作流设计 - ${response.name}`);
|
||||
setDefinitionData(response);
|
||||
|
||||
// 清空画布
|
||||
graphInstance.clearCells();
|
||||
|
||||
const nodeMap = new Map();
|
||||
|
||||
// 动态注册节点类型
|
||||
response.graph.nodes.forEach((nodeData: any) => {
|
||||
// 根据节点类型动态注册
|
||||
const nodeConfig = {
|
||||
inherit: nodeData.graph.shape === 'circle' ? 'circle' :
|
||||
nodeData.graph.shape === 'polygon' ? 'polygon' :
|
||||
nodeData.graph.shape === 'diamond' ? 'polygon' : 'rect',
|
||||
width: nodeData.graph.size.width,
|
||||
height: nodeData.graph.size.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...nodeData.graph.style,
|
||||
// 如果是菱形,添加 refPoints
|
||||
...(nodeData.graph.shape === 'diamond' ? {
|
||||
refPoints: '50,0 100,50 50,100 0,50'
|
||||
} : {})
|
||||
},
|
||||
label: {
|
||||
text: nodeData.name,
|
||||
fill: '#000000',
|
||||
fontSize: 12,
|
||||
}
|
||||
},
|
||||
ports: convertPortConfig(nodeData.graph.ports)
|
||||
};
|
||||
|
||||
// 注册节点类型
|
||||
Graph.registerNode(nodeData.id, nodeConfig, true);
|
||||
|
||||
// 创建节点
|
||||
const node = graphInstance.addNode({
|
||||
id: nodeData.id,
|
||||
shape: nodeData.id,
|
||||
position: nodeData.graph.position || { x: 100, y: 100 },
|
||||
attrs: {
|
||||
body: nodeData.graph.style,
|
||||
label: {
|
||||
text: nodeData.name,
|
||||
fill: '#000000',
|
||||
fontSize: 12,
|
||||
}
|
||||
},
|
||||
// 保存完整的节点信息用于后续操作
|
||||
nodeDefinition: nodeData,
|
||||
});
|
||||
response.graph.nodes.forEach((nodeData: any) => {
|
||||
const node = addNodeToGraph(graphInstance, nodeData);
|
||||
nodeMap.set(nodeData.id, node);
|
||||
});
|
||||
|
||||
@ -161,62 +117,16 @@ const WorkflowDesign: React.FC = () => {
|
||||
graphInstance.addEdge({
|
||||
source: { cell: sourceNode.id },
|
||||
target: { cell: targetNode.id },
|
||||
attrs: {
|
||||
line: DEFAULT_STYLES.edge
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
attrs: {
|
||||
label: {
|
||||
text: edge.name || '',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
attrs: { line: DEFAULT_STYLES.edge },
|
||||
labels: [{
|
||||
attrs: { label: { text: edge.name || '' } }
|
||||
}]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 自动布局
|
||||
const g = new dagre.graphlib.Graph();
|
||||
g.setGraph({
|
||||
rankdir: 'LR',
|
||||
align: 'UL',
|
||||
ranksep: 80,
|
||||
nodesep: 50,
|
||||
marginx: 20,
|
||||
marginy: 20,
|
||||
});
|
||||
g.setDefaultEdgeLabel(() => ({}));
|
||||
|
||||
// 添加节点
|
||||
const nodes = graphInstance.getNodes();
|
||||
nodes.forEach(node => {
|
||||
g.setNode(node.id, {
|
||||
width: node.getSize().width,
|
||||
height: node.getSize().height,
|
||||
});
|
||||
});
|
||||
|
||||
// 添加边
|
||||
const edges = graphInstance.getEdges();
|
||||
edges.forEach(edge => {
|
||||
g.setEdge(edge.getSourceCellId(), edge.getTargetCellId());
|
||||
});
|
||||
|
||||
// 执行布局
|
||||
dagre.layout(g);
|
||||
|
||||
// 应用布局结果
|
||||
nodes.forEach(node => {
|
||||
const nodeWithPosition = g.node(node.id);
|
||||
node.position(
|
||||
nodeWithPosition.x - nodeWithPosition.width / 2,
|
||||
nodeWithPosition.y - nodeWithPosition.height / 2
|
||||
);
|
||||
});
|
||||
|
||||
graphInstance.centerContent();
|
||||
// 应用自动布局
|
||||
applyAutoLayout(graphInstance);
|
||||
} catch (error) {
|
||||
console.error('加载工作流定义失败:', error);
|
||||
message.error('加载工作流定义失败');
|
||||
@ -229,55 +139,20 @@ const WorkflowDesign: React.FC = () => {
|
||||
|
||||
const handleDrop = (e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
if (graph) {
|
||||
if (!graph) return;
|
||||
|
||||
try {
|
||||
const nodeData = e.dataTransfer.getData('node');
|
||||
if (nodeData) {
|
||||
if (!nodeData) return;
|
||||
|
||||
const node = JSON.parse(nodeData);
|
||||
const { clientX, clientY } = e;
|
||||
const point = graph.clientToLocal({ x: clientX, y: clientY });
|
||||
console.log('Node Config:', node);
|
||||
console.log('Ports Config:', node.graphConfig.uiSchema.ports);
|
||||
console.log('Converted Ports:', convertPortConfig(node.graphConfig.uiSchema.ports));
|
||||
const nodeConfig = {
|
||||
inherit: node.graphConfig.uiSchema.shape === 'circle' ? 'circle' :
|
||||
node.graphConfig.uiSchema.shape === 'polygon' ? 'polygon' :
|
||||
node.graphConfig.uiSchema.shape === 'diamond' ? 'polygon' : 'rect',
|
||||
width: node.graphConfig.uiSchema.size.width,
|
||||
height: node.graphConfig.uiSchema.size.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...node.graphConfig.uiSchema.style,
|
||||
// 如果是菱形,添加 refPoints
|
||||
...(node.graphConfig.uiSchema.shape === 'diamond' ? {
|
||||
refPoints: '50,0 100,50 50,100 0,50'
|
||||
} : {})
|
||||
},
|
||||
label: {
|
||||
text: node.name,
|
||||
fill: '#000000',
|
||||
fontSize: 12,
|
||||
}
|
||||
},
|
||||
// ports: convertPortConfig(node.graphConfig.uiSchema.ports)
|
||||
};
|
||||
// 注册节点类型
|
||||
Graph.registerNode(node.code, nodeConfig, true);
|
||||
|
||||
// 创建节点时设置完整的属性
|
||||
graph.addNode({
|
||||
...nodeConfig,
|
||||
shape: node.graphConfig.uiSchema.shape,
|
||||
x: point.x,
|
||||
y: point.y,
|
||||
// 保存完整的节点信息
|
||||
type: node.type,
|
||||
code: node.code,
|
||||
// ports: nodeConfig.ports,
|
||||
ports: convertPortConfig(node.graphConfig.uiSchema.ports),
|
||||
// 保存节点定义,用于后续编辑
|
||||
nodeDefinition: node,
|
||||
});
|
||||
}
|
||||
addNodeToGraph(graph, node, point);
|
||||
} catch (error) {
|
||||
console.error('创建节点失败:', error);
|
||||
message.error('创建节点失败');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
import { Graph } from '@antv/x6';
|
||||
import dagre from 'dagre';
|
||||
|
||||
/**
|
||||
* 应用自动布局
|
||||
* @param graph 图形实例
|
||||
*/
|
||||
export const applyAutoLayout = (graph: Graph) => {
|
||||
const g = new dagre.graphlib.Graph();
|
||||
g.setGraph({
|
||||
rankdir: 'LR',
|
||||
align: 'UL',
|
||||
ranksep: 80,
|
||||
nodesep: 50,
|
||||
marginx: 20,
|
||||
marginy: 20,
|
||||
});
|
||||
g.setDefaultEdgeLabel(() => ({}));
|
||||
|
||||
// 添加节点
|
||||
const nodes = graph.getNodes();
|
||||
nodes.forEach(node => {
|
||||
g.setNode(node.id, {
|
||||
width: node.getSize().width,
|
||||
height: node.getSize().height,
|
||||
});
|
||||
});
|
||||
|
||||
// 添加边
|
||||
const edges = graph.getEdges();
|
||||
edges.forEach(edge => {
|
||||
g.setEdge(edge.getSourceCellId(), edge.getTargetCellId());
|
||||
});
|
||||
|
||||
// 执行布局
|
||||
dagre.layout(g);
|
||||
|
||||
// 应用布局结果
|
||||
nodes.forEach(node => {
|
||||
const nodeWithPosition = g.node(node.id);
|
||||
node.position(
|
||||
nodeWithPosition.x - nodeWithPosition.width / 2,
|
||||
nodeWithPosition.y - nodeWithPosition.height / 2
|
||||
);
|
||||
});
|
||||
|
||||
graph.centerContent();
|
||||
};
|
||||
103
frontend/src/pages/Workflow/Definition/Design/utils/nodeUtils.ts
Normal file
103
frontend/src/pages/Workflow/Definition/Design/utils/nodeUtils.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { Graph } from '@antv/x6';
|
||||
import { convertPortConfig } from '../constants';
|
||||
|
||||
interface NodeStyle {
|
||||
shape: string;
|
||||
style: any;
|
||||
size: {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
ports: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一获取节点样式配置
|
||||
* @param node 节点数据
|
||||
* @returns 统一的节点样式配置
|
||||
*/
|
||||
const getNodeStyle = (node: any): NodeStyle => {
|
||||
// 如果是从已保存的定义加载的节点
|
||||
if (node.graph) {
|
||||
return {
|
||||
shape: node.graph.shape,
|
||||
style: node.graph.style,
|
||||
size: node.graph.size,
|
||||
ports: node.graph.ports
|
||||
};
|
||||
}
|
||||
// 如果是从面板拖拽创建的新节点
|
||||
return {
|
||||
shape: node.graphConfig.uiSchema.shape,
|
||||
style: node.graphConfig.uiSchema.style,
|
||||
size: node.graphConfig.uiSchema.size,
|
||||
ports: node.graphConfig.uiSchema.ports
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建节点配置
|
||||
*/
|
||||
const createNodeConfig = (node: any) => {
|
||||
const style = getNodeStyle(node);
|
||||
|
||||
return {
|
||||
inherit: 'rect', // 默认使用矩形
|
||||
width: style.size.width,
|
||||
height: style.size.height,
|
||||
attrs: {
|
||||
body: {
|
||||
...style.style,
|
||||
// 如果是菱形,添加多边形的点
|
||||
...(style.shape === 'diamond' ? {
|
||||
refPoints: '0,10 10,0 20,10 10,20',
|
||||
} : {})
|
||||
},
|
||||
label: {
|
||||
text: node.name,
|
||||
fill: '#000000',
|
||||
fontSize: 12,
|
||||
}
|
||||
},
|
||||
ports: convertPortConfig(style.ports)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 添加节点到图形
|
||||
* @param graph X6 Graph实例
|
||||
* @param node 节点数据
|
||||
* @param position 节点位置(可选)
|
||||
* @returns 创建的节点实例
|
||||
*/
|
||||
export const addNodeToGraph = (
|
||||
graph: Graph,
|
||||
node: any,
|
||||
position?: { x: number, y: number }
|
||||
) => {
|
||||
const style = getNodeStyle(node);
|
||||
const nodeConfig = createNodeConfig(node);
|
||||
|
||||
// 根据形状类型设置正确的 shape
|
||||
let shape = 'rect'; // 默认使用矩形
|
||||
if (style.shape === 'circle') {
|
||||
shape = 'circle';
|
||||
} else if (style.shape === 'diamond') {
|
||||
shape = 'polygon';
|
||||
}
|
||||
|
||||
// 创建节点
|
||||
const newNode = graph.addNode({
|
||||
...nodeConfig,
|
||||
shape, // 使用映射后的形状
|
||||
...(position && { x: position.x, y: position.y }),
|
||||
// 如果是已保存的节点,使用其ID和位置
|
||||
...(node.id && { id: node.id }),
|
||||
...(node.graph?.position && { position: node.graph.position }),
|
||||
type: node.type,
|
||||
code: node.code,
|
||||
nodeDefinition: node,
|
||||
});
|
||||
|
||||
return newNode;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user