import React, { useCallback, useEffect } from 'react'; import { ReactFlow, Background, Controls, MiniMap, useNodesState, useEdgesState, addEdge, Connection, Edge, BackgroundVariant, Panel, reconnectEdge } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; import type { FlowNode, FlowEdge } from '../types'; import { nodeTypes } from '../nodes'; import SmartEdge from './SmartEdge'; import { generateEdgeId } from '../utils/idGenerator'; interface FlowCanvasProps { initialNodes?: FlowNode[]; initialEdges?: FlowEdge[]; onNodesChange?: (nodes: FlowNode[]) => void; onEdgesChange?: (edges: FlowEdge[]) => void; onNodeClick?: (event: React.MouseEvent, node: any) => void; onEdgeClick?: (event: React.MouseEvent, edge: any) => void; onDrop?: (event: React.DragEvent) => void; onDragOver?: (event: React.DragEvent) => void; onViewportChange?: () => void; className?: string; } const FlowCanvas: React.FC = ({ initialNodes = [], initialEdges = [], onNodesChange, onEdgesChange, onNodeClick, onEdgeClick, onDrop, onDragOver, onViewportChange, className = '' }) => { const [nodes, , onNodesStateChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesStateChange] = useEdgesState(initialEdges); // 处理边重连 const onReconnect = useCallback((oldEdge: Edge, newConnection: Connection) => { setEdges((els) => reconnectEdge(oldEdge, newConnection, els)); }, [setEdges]); // 处理连接 const onConnect = useCallback( (params: Connection | Edge) => { const newEdge: FlowEdge = { id: generateEdgeId(), // ✅ 生成格式: eid_xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx source: params.source!, target: params.target!, type: 'smoothstep', animated: false, style: { stroke: '#94a3b8', strokeWidth: 2, }, markerEnd: { type: 'arrowclosed' as const, color: '#94a3b8', }, data: { label: '', condition: { type: 'DEFAULT' as const, priority: 10 } } }; setEdges((eds) => addEdge(newEdge, eds)); }, [setEdges] ); // 节点变化处理 const handleNodesChange = useCallback((changes: any) => { onNodesStateChange(changes); }, [onNodesStateChange]); // 边变化处理 const handleEdgesChange = useCallback((changes: any) => { onEdgesStateChange(changes); }, [onEdgesStateChange]); // 使用 useEffect 监听 nodes 变化并通知父组件 useEffect(() => { if (onNodesChange && nodes.length > 0) { onNodesChange(nodes as FlowNode[]); } }, [nodes, onNodesChange]); // 使用 useEffect 监听 edges 变化并通知父组件 useEffect(() => { if (onEdgesChange) { onEdgesChange(edges as FlowEdge[]); } }, [edges, onEdgesChange]); // 连接验证 - 利用 React Flow 的实时验证功能 const isValidConnection = useCallback((connection: Connection | Edge) => { // 1. 防止自连接 if (connection.source === connection.target) { return false; } // 2. 检查是否已存在连接(防止重复) const isDuplicate = edges.some( (edge) => edge.source === connection.source && edge.target === connection.target ); if (isDuplicate) { return false; } // 3. 获取源节点和目标节点 const sourceNode = nodes.find(n => n.id === connection.source); const targetNode = nodes.find(n => n.id === connection.target); if (!sourceNode || !targetNode) { return false; } // 4. 开始节点不能作为连接目标 if (targetNode.type === 'START_EVENT') { return false; } // 5. 结束节点不能作为连接源 if (sourceNode.type === 'END_EVENT') { return false; } return true; }, [edges, nodes]); // 处理拖拽放置 const handleDrop = useCallback((event: React.DragEvent) => { event.preventDefault(); if (onDrop) { onDrop(event); } }, [onDrop]); // 处理拖拽悬停 const handleDragOver = useCallback((event: React.DragEvent) => { event.preventDefault(); event.dataTransfer.dropEffect = 'move'; if (onDragOver) { onDragOver(event); } }, [onDragOver]); return (
{/* 状态面板 */}
节点: {nodes.length}, 连接: {edges.length}
); }; export default FlowCanvas;