|
|
|
|
@ -18,6 +18,9 @@ import {
|
|
|
|
|
ConnectionLineType
|
|
|
|
|
} from '@xyflow/react';
|
|
|
|
|
import '@xyflow/react/dist/style.css';
|
|
|
|
|
import { useSelector, useDispatch } from 'react-redux';
|
|
|
|
|
import { updateCanvasDataMap } from '@/store/ideContainer';
|
|
|
|
|
import { debounce } from 'lodash';
|
|
|
|
|
import { nodeTypeMap, nodeTypes, registerNodeType } from '@/components/FlowEditor/node';
|
|
|
|
|
import SideBar from './sideBar/sideBar';
|
|
|
|
|
import { convertFlowData, revertFlowData } from '@/utils/convertFlowData';
|
|
|
|
|
@ -55,6 +58,7 @@ const FlowEditorWithProvider: React.FC<{ initialData?: any }> = ({ initialData }
|
|
|
|
|
const FlowEditor: React.FC<{ initialData?: any }> = ({ initialData }) => {
|
|
|
|
|
const [nodes, setNodes] = useState<Node[]>([]);
|
|
|
|
|
const [edges, setEdges] = useState<Edge[]>([]);
|
|
|
|
|
const { canvasDataMap } = useSelector(state => state.ideContainer);
|
|
|
|
|
const reactFlowInstance = useReactFlow();
|
|
|
|
|
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
|
|
|
|
const [menu, setMenu] = useState<{
|
|
|
|
|
@ -65,6 +69,7 @@ const FlowEditor: React.FC<{ initialData?: any }> = ({ initialData }) => {
|
|
|
|
|
position?: { x: number; y: number };
|
|
|
|
|
} | null>(null);
|
|
|
|
|
const store = useStoreApi();
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
|
|
|
|
|
// 添加编辑弹窗相关状态
|
|
|
|
|
const [editingNode, setEditingNode] = useState<Node | null>(null);
|
|
|
|
|
@ -77,6 +82,15 @@ const FlowEditor: React.FC<{ initialData?: any }> = ({ initialData }) => {
|
|
|
|
|
|
|
|
|
|
const { getGuidelines, clearGuidelines, AlignmentGuides } = useAlignmentGuidelines();
|
|
|
|
|
|
|
|
|
|
const updateCanvasDataMapDebounced = useRef(
|
|
|
|
|
debounce((dispatch, canvasDataMap, id, nodes, edges) => {
|
|
|
|
|
dispatch(updateCanvasDataMap({
|
|
|
|
|
...canvasDataMap,
|
|
|
|
|
[id]: { nodes, edges }
|
|
|
|
|
}));
|
|
|
|
|
}, 500)
|
|
|
|
|
).current;
|
|
|
|
|
|
|
|
|
|
// 获取handle类型 (api或data)
|
|
|
|
|
const getHandleType = (handleId: string, nodeParams: any) => {
|
|
|
|
|
// 检查是否为api类型的handle
|
|
|
|
|
@ -310,17 +324,44 @@ const FlowEditor: React.FC<{ initialData?: any }> = ({ initialData }) => {
|
|
|
|
|
}, [clearGuidelines]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const { nodes: convertedNodes, edges: convertedEdges } = convertFlowData(initialData);
|
|
|
|
|
// 为所有边添加类型-
|
|
|
|
|
const initialEdges: Edge[] = convertedEdges.map(edge => ({
|
|
|
|
|
...edge,
|
|
|
|
|
type: 'custom'
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
setNodes(convertedNodes);
|
|
|
|
|
setEdges(initialEdges);
|
|
|
|
|
if (canvasDataMap[initialData?.id]) {
|
|
|
|
|
const { edges, nodes } = canvasDataMap[initialData?.id];
|
|
|
|
|
setNodes(nodes);
|
|
|
|
|
setEdges(edges);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 首次进入
|
|
|
|
|
const { nodes: convertedNodes, edges: convertedEdges } = convertFlowData(initialData);
|
|
|
|
|
// 为所有边添加类型-
|
|
|
|
|
const initialEdges: Edge[] = convertedEdges.map(edge => ({
|
|
|
|
|
...edge,
|
|
|
|
|
type: 'custom'
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
setNodes(convertedNodes);
|
|
|
|
|
setEdges(initialEdges);
|
|
|
|
|
|
|
|
|
|
if (initialData?.id) {
|
|
|
|
|
dispatch(updateCanvasDataMap({
|
|
|
|
|
...canvasDataMap,
|
|
|
|
|
[initialData.id]: { convertedNodes, initialEdges }
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, [initialData]);
|
|
|
|
|
|
|
|
|
|
// 实时更新 canvasDataMap
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (initialData?.id) {
|
|
|
|
|
updateCanvasDataMapDebounced(dispatch, canvasDataMap, initialData.id, nodes, edges);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清理函数,在组件卸载时取消防抖
|
|
|
|
|
return () => {
|
|
|
|
|
updateCanvasDataMapDebounced.cancel();
|
|
|
|
|
};
|
|
|
|
|
}, [nodes, edges, initialData?.id, dispatch, canvasDataMap]);
|
|
|
|
|
|
|
|
|
|
// 监听边的变化,处理添加节点的触发
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const edgeToAddNode = edges.find(edge => edge.data?.addNodeTrigger);
|
|
|
|
|
|