diff --git a/src/pages/flowEditor/index.tsx b/src/pages/flowEditor/index.tsx
index a1dfe02..be985b3 100644
--- a/src/pages/flowEditor/index.tsx
+++ b/src/pages/flowEditor/index.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useCallback } from 'react';
+import React, { useState, useCallback, useRef } from 'react';
import {
ReactFlow,
applyNodeChanges,
@@ -7,58 +7,78 @@ import {
Background,
Controls,
Node,
- Edge
+ Edge,
+ ReactFlowProvider,
+ useReactFlow,
+ NodeTypes,
+ Panel
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import TextUpdaterNode from './node/textUpdateNode/TextUpdaterNode';
+import StartNode from './node/startNode/StartNode';
+import EndNode from './node/endNode/EndNode';
+import DraggableNode from './node/draggableNode/DraggableNode';
+import SideBar from './sideBar/sideBar';
-const nodeTypes = {
- textUpdater: TextUpdaterNode
+const nodeTypes: NodeTypes = {
+ textUpdater: TextUpdaterNode,
+ start: StartNode,
+ end: EndNode,
+ draggable: DraggableNode
};
const initialNodes: Node[] = [
{
- id: 'n1',
+ id: 'start-node',
position: { x: 0, y: 0 },
- data: { label: 'Node 1' },
- type: 'input'
+ data: { label: '开始' },
+ type: 'start'
+ },
+ {
+ id: 'end-node',
+ position: { x: 300, y: 200 },
+ data: { label: '结束' },
+ type: 'end'
},
{
id: 'node-1',
type: 'textUpdater',
position: { x: 150, y: 0 },
data: { value: 123 }
- },
- {
- id: 'n2',
- position: { x: 100, y: 100 },
- data: { label: 'Custom Node' }
}
];
const initialEdges: Edge[] = [
{
- id: 'n1-n2',
- source: 'n1',
- target: 'n2'
- },
- {
- id: 'n1-node-1',
- source: 'n1',
+ id: 'start-node-1',
+ source: 'start-node',
target: 'node-1',
- targetHandle: 'a'
+ sourceHandle: 'start-source'
},
{
- id: 'n2-node-1',
- source: 'n2',
- target: 'node-1',
- targetHandle: 'a1'
+ id: 'node-1-end',
+ source: 'node-1',
+ target: 'end-node',
+ targetHandle: 'end-target'
}
];
+const FlowEditorWithProvider: React.FC = () => {
+ return (
+
+
+
+
+
+
+ );
+};
+
const FlowEditor: React.FC = () => {
const [nodes, setNodes] = useState(initialNodes);
const [edges, setEdges] = useState(initialEdges);
+ const reactFlowInstance = useReactFlow();
+ const reactFlowWrapper = useRef(null);
const onNodesChange = useCallback(
(changes: any) => setNodes((nodesSnapshot) => applyNodeChanges(changes, nodesSnapshot)),
@@ -73,8 +93,41 @@ const FlowEditor: React.FC = () => {
[]
);
+ const onDragOver = useCallback((event: React.DragEvent) => {
+ event.preventDefault();
+ event.dataTransfer.dropEffect = 'move';
+ }, []);
+
+ const onDrop = useCallback(
+ (event: React.DragEvent) => {
+ event.preventDefault();
+
+ if (!reactFlowInstance) return;
+
+ const type = event.dataTransfer.getData('application/reactflow');
+ if (typeof type === 'undefined' || !type) {
+ return;
+ }
+
+ const position = reactFlowInstance.screenToFlowPosition({
+ x: event.clientX,
+ y: event.clientY,
+ });
+
+ const newNode = {
+ id: `${type}-${Date.now()}`,
+ type,
+ position,
+ data: { label: `${type} node` },
+ };
+
+ setNodes((nds) => nds.concat(newNode));
+ },
+ [reactFlowInstance]
+ );
+
return (
-
+
{
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
+ onDrop={onDrop}
+ onDragOver={onDragOver}
fitView
>
+ {/**/}
+ {/* 从左侧拖拽节点到画布中
*/}
+ {/**/}
);
};
-export default React.memo(FlowEditor);
\ No newline at end of file
+export default FlowEditorWithProvider;
\ No newline at end of file
diff --git a/src/pages/flowEditor/node/draggableNode/DraggableNode.tsx b/src/pages/flowEditor/node/draggableNode/DraggableNode.tsx
new file mode 100644
index 0000000..d1a2a8e
--- /dev/null
+++ b/src/pages/flowEditor/node/draggableNode/DraggableNode.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { Handle, Position } from '@xyflow/react';
+
+const DraggableNode = ({ data }: { data: any }) => {
+ return (
+
+
{data.label || '任务节点'}
+
+
+
+ );
+};
+
+export default DraggableNode;
\ No newline at end of file
diff --git a/src/pages/flowEditor/node/endNode/EndNode.tsx b/src/pages/flowEditor/node/endNode/EndNode.tsx
new file mode 100644
index 0000000..4f21b88
--- /dev/null
+++ b/src/pages/flowEditor/node/endNode/EndNode.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { Handle, Position } from '@xyflow/react';
+
+const EndNode = ({ data }: { data: any }) => {
+ return (
+
+ );
+};
+
+export default EndNode;
\ No newline at end of file
diff --git a/src/pages/flowEditor/node/startNode/StartNode.tsx b/src/pages/flowEditor/node/startNode/StartNode.tsx
new file mode 100644
index 0000000..8e55995
--- /dev/null
+++ b/src/pages/flowEditor/node/startNode/StartNode.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { Handle, Position } from '@xyflow/react';
+
+const StartNode = ({ data }: { data: any }) => {
+ return (
+
+ );
+};
+
+export default StartNode;
\ No newline at end of file
diff --git a/src/pages/flowEditor/sideBar/sideBar.tsx b/src/pages/flowEditor/sideBar/sideBar.tsx
new file mode 100644
index 0000000..0669a75
--- /dev/null
+++ b/src/pages/flowEditor/sideBar/sideBar.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { Card } from '@arco-design/web-react';
+
+const onDragStart = (event: React.DragEvent, nodeType: string) => {
+ event.dataTransfer.setData('application/reactflow', nodeType);
+ event.dataTransfer.effectAllowed = 'move';
+};
+
+const SideBar: React.FC = () => {
+ return (
+
+
+
+
onDragStart(event, 'draggable')}
+ >
+ 任务节点 1
+
+
+
onDragStart(event, 'textUpdater')}
+ >
+ 文本节点
+
+
+ );
+};
+
+export default SideBar;
\ No newline at end of file