1
This commit is contained in:
parent
2df3cb3074
commit
0893ea614a
@ -3,13 +3,13 @@ import { useParams, useNavigate } from 'react-router-dom';
|
|||||||
import { Button, Space, Card, Row, Col, message } from 'antd';
|
import { Button, Space, Card, Row, Col, message } from 'antd';
|
||||||
import { ArrowLeftOutlined, SaveOutlined, PlayCircleOutlined } from '@ant-design/icons';
|
import { ArrowLeftOutlined, SaveOutlined, PlayCircleOutlined } from '@ant-design/icons';
|
||||||
import { Graph, Cell } from '@antv/x6';
|
import { Graph, Cell } from '@antv/x6';
|
||||||
|
import { DagreLayout } from '@antv/layout';
|
||||||
import { getDefinitionDetail, saveDefinition } from '../service';
|
import { getDefinitionDetail, saveDefinition } from '../service';
|
||||||
import NodePanel from './components/NodePanel';
|
import NodePanel from './components/NodePanel';
|
||||||
import NodeConfigDrawer from './components/NodeConfigModal';
|
import NodeConfigDrawer from './components/NodeConfigModal';
|
||||||
import { NodeDefinition } from './types';
|
import { NodeDefinition } from './types';
|
||||||
import { validateWorkflow } from './utils/validator';
|
import { validateWorkflow } from './utils/validator';
|
||||||
import {
|
import {
|
||||||
NODE_REGISTRY_CONFIG,
|
|
||||||
GRID_CONFIG,
|
GRID_CONFIG,
|
||||||
CONNECTING_CONFIG,
|
CONNECTING_CONFIG,
|
||||||
HIGHLIGHTING_CONFIG,
|
HIGHLIGHTING_CONFIG,
|
||||||
@ -27,59 +27,13 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const [configModalVisible, setConfigModalVisible] = useState(false);
|
const [configModalVisible, setConfigModalVisible] = useState(false);
|
||||||
const [definitionData, setDefinitionData] = useState<any>(null);
|
const [definitionData, setDefinitionData] = useState<any>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (id) {
|
|
||||||
loadDefinitionDetail();
|
|
||||||
}
|
|
||||||
}, [id]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (graphContainerRef.current) {
|
if (graphContainerRef.current) {
|
||||||
// 注册自定义节点
|
|
||||||
Object.entries(NODE_REGISTRY_CONFIG).forEach(([name, config]) => {
|
|
||||||
Graph.registerNode(name, config, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
const graph = new Graph({
|
const graph = new Graph({
|
||||||
container: graphContainerRef.current,
|
container: graphContainerRef.current,
|
||||||
grid: GRID_CONFIG,
|
grid: GRID_CONFIG,
|
||||||
connecting: {
|
connecting: CONNECTING_CONFIG,
|
||||||
...CONNECTING_CONFIG,
|
highlighting: HIGHLIGHTING_CONFIG,
|
||||||
validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
|
|
||||||
if (!sourceMagnet || !targetMagnet) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (sourceView === targetView) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
validateMagnet({ magnet }) {
|
|
||||||
const portGroup = magnet?.getAttribute('port-group');
|
|
||||||
return !!portGroup;
|
|
||||||
},
|
|
||||||
createEdge() {
|
|
||||||
return this.createEdge({
|
|
||||||
attrs: {
|
|
||||||
line: DEFAULT_STYLES.edge,
|
|
||||||
},
|
|
||||||
zIndex: -1,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
highlighting: {
|
|
||||||
...HIGHLIGHTING_CONFIG,
|
|
||||||
magnetAdsorbed: {
|
|
||||||
name: 'stroke',
|
|
||||||
args: {
|
|
||||||
attrs: {
|
|
||||||
fill: '#fff',
|
|
||||||
stroke: '#31d0c6',
|
|
||||||
strokeWidth: 4,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
snapline: true,
|
snapline: true,
|
||||||
history: true,
|
history: true,
|
||||||
clipboard: true,
|
clipboard: true,
|
||||||
@ -115,19 +69,110 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
|
|
||||||
setGraph(graph);
|
setGraph(graph);
|
||||||
|
|
||||||
|
// 在 graph 初始化完成后加载数据
|
||||||
|
if (id) {
|
||||||
|
loadDefinitionDetail(graph, id);
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
graph.dispose();
|
graph.dispose();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [graphContainerRef]);
|
}, [graphContainerRef, id]);
|
||||||
|
|
||||||
const loadDefinitionDetail = async () => {
|
const loadDefinitionDetail = async (graphInstance: Graph, definitionId: number) => {
|
||||||
try {
|
try {
|
||||||
const response = await getDefinitionDetail(id);
|
const response = await getDefinitionDetail(definitionId);
|
||||||
|
console.log('加载到的工作流数据:', response);
|
||||||
setTitle(`工作流设计 - ${response.name}`);
|
setTitle(`工作流设计 - ${response.name}`);
|
||||||
setDefinitionData(response);
|
setDefinitionData(response);
|
||||||
|
|
||||||
|
// 清空画布
|
||||||
|
graphInstance.clearCells();
|
||||||
|
|
||||||
|
const nodeMap = new Map();
|
||||||
|
|
||||||
|
// 动态注册节点类型
|
||||||
|
response.graph.nodes.forEach((nodeData: any) => {
|
||||||
|
// 根据节点类型动态注册
|
||||||
|
const nodeConfig = {
|
||||||
|
inherit: 'rect', // 使用基础的矩形节点作为默认继承
|
||||||
|
width: nodeData.graph.size.width,
|
||||||
|
height: nodeData.graph.size.height,
|
||||||
|
attrs: {
|
||||||
|
body: nodeData.graph.style,
|
||||||
|
},
|
||||||
|
ports: nodeData.graph.ports
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据形状选择不同的基础节点类型
|
||||||
|
if (nodeData.graph.shape === 'circle') {
|
||||||
|
nodeConfig.inherit = 'circle';
|
||||||
|
} else if (nodeData.graph.shape === 'polygon') {
|
||||||
|
nodeConfig.inherit = 'polygon';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册节点类型
|
||||||
|
Graph.registerNode(nodeData.code, nodeConfig, true);
|
||||||
|
|
||||||
|
// 创建节点
|
||||||
|
const node = graphInstance.addNode({
|
||||||
|
id: nodeData.id,
|
||||||
|
shape: nodeData.code,
|
||||||
|
position: nodeData.graph.position || { x: 100, y: 100 },
|
||||||
|
attrs: {
|
||||||
|
body: nodeData.graph.style,
|
||||||
|
label: {
|
||||||
|
text: nodeData.name,
|
||||||
|
fill: '#000000',
|
||||||
|
fontSize: 12,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nodeDefinition: nodeData,
|
||||||
|
});
|
||||||
|
nodeMap.set(nodeData.id, node);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建边
|
||||||
|
response.graph.edges.forEach((edge: any) => {
|
||||||
|
const sourceNode = nodeMap.get(edge.from);
|
||||||
|
const targetNode = nodeMap.get(edge.to);
|
||||||
|
if (sourceNode && targetNode) {
|
||||||
|
graphInstance.addEdge({
|
||||||
|
source: { cell: sourceNode.id },
|
||||||
|
target: { cell: targetNode.id },
|
||||||
|
attrs: {
|
||||||
|
line: DEFAULT_STYLES.edge
|
||||||
|
},
|
||||||
|
labels: [
|
||||||
|
{
|
||||||
|
attrs: {
|
||||||
|
label: {
|
||||||
|
text: edge.name || '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 自动布局
|
||||||
|
const layout = new DagreLayout({
|
||||||
|
type: 'dagre',
|
||||||
|
rankdir: 'LR',
|
||||||
|
align: 'UL',
|
||||||
|
ranksep: 80,
|
||||||
|
nodesep: 50,
|
||||||
|
});
|
||||||
|
|
||||||
|
const cells = graphInstance.getCells();
|
||||||
|
layout.layout(cells);
|
||||||
|
graphInstance.resetCells(cells);
|
||||||
|
graphInstance.centerContent();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load workflow definition:', error);
|
console.error('加载工作流定义失败:', error);
|
||||||
|
message.error('加载工作流定义失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -143,7 +188,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const node = JSON.parse(nodeData);
|
const node = JSON.parse(nodeData);
|
||||||
const { clientX, clientY } = e;
|
const { clientX, clientY } = e;
|
||||||
const point = graph.clientToLocal({ x: clientX, y: clientY });
|
const point = graph.clientToLocal({ x: clientX, y: clientY });
|
||||||
|
|
||||||
const nodeConfig = {
|
const nodeConfig = {
|
||||||
shape: node.graphConfig.uiSchema.shape,
|
shape: node.graphConfig.uiSchema.shape,
|
||||||
width: node.graphConfig.uiSchema.size.width,
|
width: node.graphConfig.uiSchema.size.width,
|
||||||
@ -193,21 +238,21 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
|
|
||||||
const handleNodeConfigUpdate = (values: any) => {
|
const handleNodeConfigUpdate = (values: any) => {
|
||||||
if (!selectedNode) return;
|
if (!selectedNode) return;
|
||||||
|
|
||||||
// 更新节点配置
|
// 更新节点配置
|
||||||
selectedNode.setProp('config', values);
|
selectedNode.setProp('config', values);
|
||||||
// 更新节点显示名称
|
// 更新节点显示名称
|
||||||
if (values.name) {
|
if (values.name) {
|
||||||
selectedNode.attr('label/text', values.name);
|
selectedNode.attr('label/text', values.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
setConfigModalVisible(false);
|
setConfigModalVisible(false);
|
||||||
message.success('节点配置已更新');
|
message.success('节点配置已更新');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveWorkflow = async () => {
|
const handleSaveWorkflow = async () => {
|
||||||
if (!graph || !definitionData) return;
|
if (!graph || !definitionData) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 校验流程图
|
// 校验流程图
|
||||||
const validationResult = validateWorkflow(graph);
|
const validationResult = validateWorkflow(graph);
|
||||||
@ -220,7 +265,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const nodes = graph.getNodes().map(node => {
|
const nodes = graph.getNodes().map(node => {
|
||||||
const nodeDefinition = node.getProp('nodeDefinition');
|
const nodeDefinition = node.getProp('nodeDefinition');
|
||||||
const nodeType = node.getProp('type');
|
const nodeType = node.getProp('type');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: node.id,
|
id: node.id,
|
||||||
code: nodeType,
|
code: nodeType,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user