You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
flow-playform-react/src/hooks/useFlowCallbacks.ts

846 lines
26 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import React, { useCallback } from 'react';
import {
applyNodeChanges,
applyEdgeChanges,
addEdge,
reconnectEdge,
Node,
Edge
} from '@xyflow/react';
import { setMainFlow } from '@/api/appRes';
import { getUserToken } from '@/api/user';
import { Message } from '@arco-design/web-react';
import { nodeTypeMap, registerNodeType } from '@/components/FlowEditor/node';
import { convertFlowData, revertFlowData } from '@/utils/convertFlowData';
import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData';
import { defaultNodeTypes } from '@/components/FlowEditor/node/types/defaultType';
import useWebSocket from '@/hooks/useWebSocket';
import { useAlignmentGuidelines } from '@/hooks/useAlignmentGuidelines';
import LocalNode from '@/components/FlowEditor/node/localNode/LocalNode';
import LoopNode from '@/components/FlowEditor/node/loopNode/LoopNode';
import BasicNode from '@/components/FlowEditor/node/basicNode/BasicNode';
import { updateCanvasDataMap } from '@/store/ideContainer';
import { Dispatch } from 'redux';
export const useFlowCallbacks = (
nodes: Node[],
setNodes: React.Dispatch<React.SetStateAction<Node[]>>,
edges: Edge[],
setEdges: React.Dispatch<React.SetStateAction<Edge[]>>,
reactFlowInstance: any,
canvasDataMap: any,
dispatch: Dispatch<any>,
updateCanvasDataMapDebounced: (
dispatch: Dispatch<any>,
canvasDataMap: any,
id: string,
nodes: Node[],
edges: Edge[]
) => void,
initialData: any,
historyTimeoutRef: React.MutableRefObject<NodeJS.Timeout | null>,
setHistoryInitialized: React.Dispatch<React.SetStateAction<boolean>>,
editingNode: Node | null,
setEditingNode: React.Dispatch<React.SetStateAction<Node | null>>,
setIsEditModalOpen: React.Dispatch<React.SetStateAction<boolean>>,
edgeForNodeAdd: Edge | null,
setEdgeForNodeAdd: React.Dispatch<React.SetStateAction<Edge | null>>,
positionForNodeAdd: { x: number, y: number } | null,
setPositionForNodeAdd: React.Dispatch<React.SetStateAction<{ x: number, y: number } | null>>,
setIsDelete: React.Dispatch<React.SetStateAction<boolean>>,
setIsRunning: React.Dispatch<React.SetStateAction<boolean>>
) => {
const { getGuidelines, clearGuidelines } = useAlignmentGuidelines();
// 获取handle类型 (api或data)
const getHandleType = (handleId: string, nodeParams: any) => {
// 检查是否为api类型的handle
const apiOuts = nodeParams.apiOuts || [];
const apiIns = nodeParams.apiIns || [];
if (apiOuts.some((api: any) => (api.name || api.id) === handleId) ||
apiIns.some((api: any) => (api.name || api.id) === handleId) || (handleId.includes('loop'))) {
return 'api';
}
// 检查是否为data类型的handle
const dataOuts = nodeParams.dataOuts || [];
const dataIns = nodeParams.dataIns || [];
if (dataOuts.some((data: any) => (data.name || data.id) === handleId) ||
dataIns.some((data: any) => (data.name || data.id) === handleId)) {
return 'data';
}
// 默认为data类型
return 'data';
};
// 验证数据类型是否匹配
const validateDataType = (sourceNode: defaultNodeTypes, targetNode: defaultNodeTypes, sourceHandleId: string, targetHandleId: string) => {
const sourceParams = sourceNode.data?.parameters || {};
const targetParams = targetNode.data?.parameters || {};
// 获取源节点的输出参数
let sourceDataType = '';
const sourceApiOuts = sourceParams.apiOuts || [];
const sourceDataOuts = sourceParams.dataOuts || [];
// 查找源handle的数据类型
const sourceApi = sourceApiOuts.find((api: any) => api.name === sourceHandleId);
const sourceData = sourceDataOuts.find((data: any) => data.name === sourceHandleId);
if (sourceApi) {
sourceDataType = sourceApi.dataType || '';
}
else if (sourceData) {
sourceDataType = sourceData.dataType || '';
}
// 获取目标节点的输入参数
let targetDataType = '';
const targetApiIns = targetParams.apiIns || [];
const targetDataIns = targetParams.dataIns || [];
// 查找目标handle的数据类型
const targetApi = targetApiIns.find((api: any) => api.name === targetHandleId);
const targetData = targetDataIns.find((data: any) => data.name === targetHandleId);
if (targetApi) {
targetDataType = targetApi.dataType || '';
}
else if (targetData) {
targetDataType = targetData.dataType || '';
}
// 如果任一数据类型为空,则允许连接
if (!sourceDataType || !targetDataType) {
return true;
}
// 比较数据类型是否匹配
return sourceDataType === targetDataType;
};
// onNodesChange 函数,添加防抖机制
const onNodesChange = useCallback(
(changes: any) => {
// 深度克隆节点数组以避免修改冻结的对象
const clonedNodes = JSON.parse(JSON.stringify(nodes));
const newNodes = applyNodeChanges(changes, clonedNodes);
setNodes(newNodes);
// 如果需要在节点变化时执行某些操作,可以在这里添加
// 只有当变化是节点位置变化时才不立即记录历史
const isPositionChange = changes.some((change: any) =>
change.type === 'position' && change.dragging === false
);
// 如果是位置变化结束或者不是位置变化,则记录历史
if (isPositionChange || !changes.some((change: any) => change.type === 'position')) {
// 清除之前的定时器
if (historyTimeoutRef.current) {
clearTimeout(historyTimeoutRef.current);
}
// 设置新的定时器,延迟记录历史记录
historyTimeoutRef.current = setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: { nodes: [...newNodes], edges: [...edges] }
});
document.dispatchEvent(event);
}, 100);
}
},
[nodes, edges]
);
// onEdgesChange 函数
const onEdgesChange = useCallback(
(changes: any) => {
const newEdges = applyEdgeChanges(changes, edges);
setEdges(newEdges);
// 如果需要在边变化时执行某些操作,可以在这里添加
// 边的变化立即记录历史
const event = new CustomEvent('takeSnapshot', {
detail: { nodes: [...nodes], edges: [...newEdges] }
});
document.dispatchEvent(event);
},
[edges, nodes]
);
const onNodesDelete = useCallback((deletedNodes: any) => {
setIsDelete(true);
}, []);
// onConnect 函数
const onConnect = useCallback(
(params: any) => {
// 获取源节点和目标节点
const sourceNode = nodes.find(node => node.id === params.source);
const targetNode = nodes.find(node => node.id === params.target);
// 如果找不到节点,不创建连接
if (!sourceNode || !targetNode) {
return;
}
// 获取源节点和目标节点的参数信息
const sourceParams = sourceNode.data?.parameters || {};
const targetParams = targetNode.data?.parameters || {};
// 获取源handle和目标handle的类型 (api或data)
const sourceHandleType = getHandleType(params.sourceHandle, sourceParams);
const targetHandleType = getHandleType(params.targetHandle, targetParams);
// 验证连接类型是否匹配 (api只能连api, data只能连data)
if (sourceHandleType !== targetHandleType) {
console.warn('连接类型不匹配: ', sourceHandleType, targetHandleType);
return;
}
// 验证数据类型是否匹配
if (!validateDataType(sourceNode, targetNode, params.sourceHandle, params.targetHandle)) {
console.warn('数据类型不匹配');
return;
}
// 如果验证通过,创建连接
setEdges((edgesSnapshot: Edge[]) => {
const newEdges = addEdge({ ...params, type: 'custom' }, edgesSnapshot);
// 连接建立后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: { nodes: [...nodes], edges: [...newEdges] }
});
document.dispatchEvent(event);
}, 0);
return newEdges;
});
},
[nodes]
);
// 边重新连接处理
const onReconnect = useCallback(
(oldEdge: Edge, newConnection: any) => {
// 获取源节点和目标节点
const sourceNode = nodes.find(node => node.id === newConnection.source);
const targetNode = nodes.find(node => node.id === newConnection.target);
// 如果找不到节点,不创建连接
if (!sourceNode || !targetNode) {
return;
}
// 获取源节点和目标节点的参数信息
const sourceParams = sourceNode.data?.parameters || {};
const targetParams = targetNode.data?.parameters || {};
// 获取源handle和目标handle的类型 (api或data)
const sourceHandleType = getHandleType(newConnection.sourceHandle, sourceParams);
const targetHandleType = getHandleType(newConnection.targetHandle, targetParams);
// 验证连接类型是否匹配 (api只能连api, data只能连data)
if (sourceHandleType !== targetHandleType) {
console.warn('连接类型不匹配: ', sourceHandleType, targetHandleType);
return;
}
// 验证数据类型是否匹配
if (!validateDataType(sourceNode, targetNode, newConnection.sourceHandle, newConnection.targetHandle)) {
console.warn('数据类型不匹配');
return;
}
// 如果验证通过,重新连接
setEdges((els) => reconnectEdge(oldEdge, newConnection, els));
},
[nodes]
);
const onDragOver = useCallback((event: React.DragEvent) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
}, []);
// 侧边栏节点实例
const onDrop = useCallback(
(event: React.DragEvent) => {
event.preventDefault();
if (!reactFlowInstance) return;
const callBack = event.dataTransfer.getData('application/reactflow');
const nodeData = JSON.parse(callBack);
if (typeof nodeData.nodeType === 'undefined' || !nodeData.nodeType) {
return;
}
const position = reactFlowInstance.screenToFlowPosition({
x: event.clientX,
y: event.clientY
});
// 特殊处理循环节点,添加开始和结束节点
if (nodeData.nodeType === 'LOOP') {
addLoopNodeWithStartEnd(position, nodeData);
return;
}
const newNode = {
id: `${nodeData.nodeType}-${Date.now()}`,
type: nodeData.nodeType,
position,
data: { ...nodeData.data, title: nodeData.nodeName, type: nodeData.nodeType }
};
// 将未定义的节点动态追加进nodeTypes
const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
// 目前默认添加的都是系统组件/本地组件
if (!nodeMap.includes(nodeData.nodeType)) {
registerNodeType(nodeData.nodeType, LocalNode, nodeData.nodeName);
}
setNodes((nds: Node[]) => {
const newNodes = nds.concat(newNode);
// 添加节点后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: { nodes: [...newNodes], edges: [...edges] }
});
document.dispatchEvent(event);
}, 0);
return newNodes;
});
},
[reactFlowInstance, edges]
);
// 添加循环节点及其开始和结束节点
const addLoopNodeWithStartEnd = useCallback((position: { x: number, y: number }, nodeData: any) => {
// 创建循环开始节点
const loopStartNode = {
id: `LOOP_START-${Date.now()}`,
type: 'LOOP', // 使用本地节点类型
position: { x: position.x, y: position.y },
data: {
title: '循环开始',
type: 'LOOP_START',
parameters: {
apiIns: [{ name: 'start', desc: '', dataType: '', defaultValue: '' }],
apiOuts: [{ name: 'done', desc: '', dataType: '', defaultValue: '' }],
dataIns: [],
dataOuts: []
},
component: {}
}
};
// 创建循环结束节点
const loopEndNode = {
id: `LOOP_END-${Date.now()}`,
type: 'LOOP', // 使用本地节点类型
position: { x: position.x + 400, y: position.y },
data: {
title: '循环结束',
type: 'LOOP_END',
parameters: {
apiIns: [{ name: 'continue', desc: '', dataType: '', defaultValue: '' }],
apiOuts: [{ name: 'break', desc: '', dataType: '', defaultValue: '' }],
dataIns: [{
'arrayType': null,
'dataType': 'INTEGER',
'defaultValue': 10,
'desc': '最大循环次数',
'id': 'maxTime'
}],
dataOuts: []
},
component: {
type: 'LOOP_END',
customDef: JSON.stringify({
apiOutIds: ['continue', 'break'],
conditions: [],
loopStartNodeId: loopStartNode.id
}),
loopStartNodeId: loopStartNode.id // 这里的参数是为了提供在组件内部处理数据是使用最后这个字段要序列化后放进customDef
}
}
};
loopStartNode.data.component = {
type: 'LOOP_START',
customDef: JSON.stringify({ loopEndNodeId: loopEndNode.id })
};
// 创建连接边(连接循环开始和结束节点的顶部连接点)
const newEdges = [
{
id: `${loopStartNode.id}-${loopEndNode.id}-group`,
source: loopStartNode.id,
target: loopEndNode.id,
sourceHandle: `${loopStartNode.id}-group`,
targetHandle: `${loopEndNode.id}-group`,
type: 'custom'
}
];
// 将未定义的节点动态追加进nodeTypes
const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
if (!nodeMap.includes('LOOP')) {
registerNodeType('LOOP', LoopNode, '循环');
}
setNodes((nds: Node[]) => {
const newNodes = [...nds, loopStartNode, loopEndNode];
// 添加节点后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: { nodes: [...newNodes], edges: [...edges, ...newEdges] }
});
document.dispatchEvent(event);
}, 0);
return newNodes;
});
setEdges((eds: Edge[]) => {
const updatedEdges = [...eds, ...newEdges];
// 添加边后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: { nodes: [...nodes, loopStartNode, loopEndNode], edges: [...updatedEdges] }
});
document.dispatchEvent(event);
}, 0);
return updatedEdges;
});
}, [nodes, edges]);
const onNodeDrag = useCallback(
(_: any, node: Node) => {
// 获取对齐线
getGuidelines(node, nodes);
},
[nodes, getGuidelines]
);
// 节点拖拽结束处理
const onNodeDragStop = useCallback(() => {
// 清除对齐线
clearGuidelines();
}, [clearGuidelines]);
// 初始化画布数据
const initializeCanvasData = useCallback(() => {
if (canvasDataMap[initialData?.appId]) {
const { edges, nodes } = canvasDataMap[initialData?.appId];
setNodes(nodes);
setEdges(edges);
}
else {
// 首次进入
const { nodes: convertedNodes, edges: convertedEdges } = convertFlowData(initialData?.main.components, true);
// return;
// 为所有边添加类型
const initialEdges: Edge[] = convertedEdges.map(edge => ({
...edge,
type: 'custom'
}));
setNodes(convertedNodes);
setEdges(initialEdges);
if (initialData?.appId) {
dispatch(updateCanvasDataMap({
...canvasDataMap,
[initialData.appId]: { nodes: convertedNodes, edges: initialEdges }
}));
}
}
// 标记历史记录已初始化
setHistoryInitialized(true);
}, [initialData, canvasDataMap]);
// 实时更新 canvasDataMap
const updateCanvasDataMapEffect = useCallback(() => {
if (initialData?.appId) {
updateCanvasDataMapDebounced(dispatch, canvasDataMap, initialData.appId, nodes, edges);
}
// 清理函数,在组件卸载时取消防抖
return () => {
// 取消防抖函数
};
}, [nodes, edges, initialData?.appId, dispatch, canvasDataMap]);
// 关闭编辑弹窗
const closeEditModal = useCallback(() => {
setIsEditModalOpen(false);
setEditingNode(null);
}, []);
// 保存节点编辑
const saveNodeEdit = useCallback((updatedData: any) => {
console.log('updatedData:', updatedData);
const updatedNodes = nodes.map((node) => {
if (node.id === editingNode?.id) {
return {
...node,
data: { ...node.data, ...updatedData }
};
}
return node;
});
setNodes(updatedNodes);
closeEditModal();
// TODO 如果需要在节点编辑后立即保存到服务器,可以调用保存函数
// saveFlowDataToServer();
}, [nodes, editingNode, closeEditModal]);
// 删除节点函数
const deleteNode = useCallback((node: Node) => {
console.log('node:', node);
setNodes((nds: Node[]) => nds.filter((n) => n.id !== node.id));
setEdges((eds: Edge[]) => eds.filter((e) => e.source !== node.id && e.target !== node.id));
// 删除节点后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: {
nodes: [...nodes.filter((n) => n.id !== node.id)],
edges: [...edges.filter((e) => e.source !== node.id && e.target !== node.id)]
}
});
document.dispatchEvent(event);
}, 0);
}, [nodes, edges]);
// 删除边函数
const deleteEdge = useCallback((edge: Edge) => {
setEdges((eds: Edge[]) => eds.filter((e) => e.id !== edge.id));
// 删除边后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: {
nodes: [...nodes],
edges: [...edges.filter((e) => e.id !== edge.id)]
}
});
document.dispatchEvent(event);
}, 0);
}, [nodes, edges]);
// 编辑节点
const editNode = useCallback((node: Node) => {
setEditingNode(node);
setIsEditModalOpen(true);
}, []);
// 编辑边
const editEdge = useCallback((edge: Edge) => {
// 这里可以实现边编辑逻辑
console.log('编辑边:', edge);
}, []);
// 复制节点
const copyNode = useCallback((node: Node) => {
// 这里可以实现节点复制逻辑
console.log('复制节点:', node);
}, []);
// 在边上添加节点的具体实现
const addNodeOnEdge = useCallback((nodeType: string, node: any) => {
if (!edgeForNodeAdd || !reactFlowInstance) return;
// 查找节点定义
const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType) || node;
if (!nodeDefinition) return;
// 获取源节点和目标节点
const sourceNode = nodes.find(n => n.id === edgeForNodeAdd.source);
const targetNode = nodes.find(n => n.id === edgeForNodeAdd.target);
if (!sourceNode || !targetNode) return;
// 计算中点位置
const position = {
x: (sourceNode.position.x + targetNode.position.x) / 2,
y: (sourceNode.position.y + targetNode.position.y) / 2
};
// 创建新节点
const newNode = {
id: `${nodeType}-${Date.now()}`,
type: nodeType,
position,
data: {
...nodeDefinition.data,
title: nodeDefinition.nodeName,
type: nodeType,
compId: nodeDefinition.id
}
};
// 将未定义的节点动态追加进nodeTypes
const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
if (!nodeMap.includes(nodeType)) {
registerNodeType(nodeType, nodeType === 'BASIC' ? BasicNode : LocalNode, nodeDefinition.nodeName);
}
// 添加新节点
setNodes((nds: Node[]) => [...nds, newNode]);
// 删除旧边
setEdges((eds: Edge[]) => eds.filter(e => e.id !== edgeForNodeAdd.id));
// 确定新边的句柄
// 对于第一条边 (source -> new node): 使用原始边的 sourceHandle目标句柄根据节点类型确定
// 对于第二条边 (new node -> target): 源句柄根据节点类型确定,使用原始边的 targetHandle
// 获取新节点的默认句柄
let newNodeSourceHandle = 'done'; // 默认源句柄
let newNodeTargetHandle = 'start'; // 默认目标句柄
// 如果新节点有参数定义,尝试获取更准确的句柄信息
if (newNode.data?.parameters) {
const { apiOuts, apiIns } = newNode.data.parameters;
// 获取第一个api输出作为源句柄如果存在
if (apiOuts && apiOuts.length > 0) {
newNodeSourceHandle = apiOuts[0].name || apiOuts[0].id || newNodeSourceHandle;
}
// 获取第一个api输入作为目标句柄如果存在
if (apiIns && apiIns.length > 0) {
newNodeTargetHandle = apiIns[0].name || apiIns[0].id || newNodeTargetHandle;
}
}
// 创建新边: source -> new node, new node -> target
const newEdges = [
...edges.filter(e => e.id !== edgeForNodeAdd.id),
{
id: `e${edgeForNodeAdd.source}-${newNode.id}`,
source: edgeForNodeAdd.source,
target: newNode.id,
sourceHandle: edgeForNodeAdd.sourceHandle,
targetHandle: newNodeTargetHandle,
type: 'custom'
},
{
id: `e${newNode.id}-${edgeForNodeAdd.target}`,
source: newNode.id,
target: edgeForNodeAdd.target,
sourceHandle: newNodeSourceHandle,
targetHandle: edgeForNodeAdd.targetHandle,
type: 'custom'
}
];
setEdges(newEdges);
// 关闭菜单
setEdgeForNodeAdd(null);
setPositionForNodeAdd(null);
// 添加节点后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: {
nodes: [...nodes, newNode],
edges: [...newEdges]
}
});
document.dispatchEvent(event);
}, 0);
}, [edgeForNodeAdd, nodes, reactFlowInstance, edges]);
// 在画布上添加节点
const addNodeOnPane = useCallback((nodeType: string, position: { x: number; y: number }, node?: any) => {
if (!reactFlowInstance) return;
// 查找节点定义
const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType) || node;
if (!nodeDefinition) return;
// 特殊处理循环节点,添加开始和结束节点
if (nodeType === 'LOOP') {
addLoopNodeWithStartEnd(position, nodeDefinition);
return;
}
// 创建新节点
const newNode = {
id: `${nodeType}-${Date.now()}`,
type: nodeType,
position,
data: {
...nodeDefinition.data,
title: nodeDefinition.nodeName,
type: nodeType,
compId: nodeDefinition.id
}
};
// 将未定义的节点动态追加进nodeTypes
const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
// 目前默认添加的都是系统组件/本地组件
if (!nodeMap.includes(nodeType)) {
registerNodeType(nodeType, nodeType === 'BASIC' ? BasicNode : LocalNode, nodeDefinition.nodeName);
}
setNodes((nds: Node[]) => {
const newNodes = [...nds, newNode];
// 添加节点后记录历史
setTimeout(() => {
const event = new CustomEvent('takeSnapshot', {
detail: { nodes: [...newNodes], edges: [...edges] }
});
document.dispatchEvent(event);
}, 0);
return newNodes;
});
}, [reactFlowInstance, edges, addLoopNodeWithStartEnd]);
// 处理添加节点的统一方法
const handleAddNode = useCallback((nodeType: string, node: any) => {
// 如果是通过边添加节点
if (edgeForNodeAdd) {
addNodeOnEdge(nodeType, node);
}
// 如果是通过画布添加节点
else if (positionForNodeAdd) {
addNodeOnPane(nodeType, positionForNodeAdd, node);
}
// 清除状态
setEdgeForNodeAdd(null);
setPositionForNodeAdd(null);
}, [edgeForNodeAdd, positionForNodeAdd, addNodeOnEdge, addNodeOnPane]);
// 保存所有节点和边数据到服务器
const saveFlowDataToServer = useCallback(async () => {
try {
// 转换会原始数据类型
const revertedData = revertFlowData(nodes, edges);
console.log('revertedData:', revertedData);
// return;
const res: any = await setMainFlow(revertedData, initialData.appId);
if (res.code === 200) {
Message.success('保存成功');
}
else {
Message.error(res.message);
}
} catch (error) {
console.error('Error saving flow data:', error);
Message.error('保存失败');
}
}, [nodes, edges, initialData?.appId]);
// 初始化WebSocket hook
const ws = useWebSocket({
onOpen: () => {
console.log('WebSocket连接已建立');
Message.success('运行已启动');
},
onClose: () => {
console.log('WebSocket连接已关闭');
setIsRunning(false);
Message.info('运行已停止');
},
onError: (event) => {
console.error('WebSocket错误:', event);
setIsRunning(false);
Message.error('运行连接出错');
},
onMessage: (event) => {
console.log('收到WebSocket消息:', event.data);
// 这里可以处理从后端收到的消息,例如日志更新等
}
});
// 运行处理函数
const handleRun = useCallback(async (running: boolean) => {
if (running) {
// 启动运行
const res = await getUserToken();
const token = res.data;
const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
let wsApi = `${protocol}://${window.location.host}/ws/v1/bpms-runtime`;
if (window.location.host.includes('localhost')) {
wsApi = `ws://api.myserver.com:4121/ws/v1/bpms-runtime`;
}
const uri = `${wsApi}?x-auth0-token=${token}`;
ws.connect(uri);
setIsRunning(true);
}
else {
// 停止运行
ws.disconnect();
setIsRunning(false);
}
}, [initialData?.appId, ws]);
return {
// Event handlers
onNodesChange,
onEdgesChange,
onConnect,
onReconnect,
onDragOver,
onDrop,
onNodeDrag,
onNodeDragStop,
onNodesDelete,
// Menu handlers
closeEditModal,
saveNodeEdit,
deleteNode,
deleteEdge,
editNode,
editEdge,
copyNode,
// Node operations
addNodeOnEdge,
addNodeOnPane,
handleAddNode,
// Initialization
initializeCanvasData,
updateCanvasDataMapEffect,
// Actions
saveFlowDataToServer,
handleRun,
// Utilities
getHandleType,
validateDataType
};
};