|
|
@@ -2,10 +2,10 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
import styles from './index.module.scss'
|
|
|
import { infoPageIDGet } from '@/utils/locStore'
|
|
|
import history from '@/utils/history'
|
|
|
-
|
|
|
import { baseOssUrl } from '@/utils/http'
|
|
|
import { urlCanRes } from '@/utils/urlCan'
|
|
|
import classNames from 'classnames'
|
|
|
+import dagre from 'dagre'
|
|
|
|
|
|
import {
|
|
|
ReactFlow,
|
|
|
@@ -18,9 +18,10 @@ import {
|
|
|
} from '@xyflow/react'
|
|
|
import '@xyflow/react/dist/style.css'
|
|
|
|
|
|
+const layoutDirection = 'TB'
|
|
|
+
|
|
|
function FlowChart() {
|
|
|
const { fitView } = useReactFlow() // 获取 fitView 方法
|
|
|
-
|
|
|
// 每个组件
|
|
|
const Row = useCallback((item: any) => {
|
|
|
return (
|
|
|
@@ -33,10 +34,11 @@ function FlowChart() {
|
|
|
)
|
|
|
}, [])
|
|
|
|
|
|
- const initnode: any[] = useMemo(() => {
|
|
|
+ // 创建不带位置的初始节点
|
|
|
+ const initialNodesWithoutPosition: any[] = useMemo(() => {
|
|
|
return cardNames.map(v => ({
|
|
|
id: v.id + '',
|
|
|
- position: v.position,
|
|
|
+ // position: v.position,
|
|
|
data: { label: Row(v) },
|
|
|
draggable: true
|
|
|
}))
|
|
|
@@ -69,19 +71,87 @@ function FlowChart() {
|
|
|
}, [])
|
|
|
|
|
|
// 使用状态管理节点和边
|
|
|
- const [nodes, setNodes, onNodesChange] = useNodesState(initnode)
|
|
|
- const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges)
|
|
|
-
|
|
|
- // 重置功能
|
|
|
- const handleReset = useCallback(() => {
|
|
|
- // 重置节点和边
|
|
|
- setNodes(initnode)
|
|
|
- setEdges(initialEdges)
|
|
|
- // 重置视图到初始大小和位置
|
|
|
- setTimeout(() => {
|
|
|
- fitView({ duration: 300 }) // 添加动画效果,300ms
|
|
|
- }, 0)
|
|
|
- }, [setNodes, initnode, setEdges, initialEdges, fitView])
|
|
|
+ const [nodes, setNodes, onNodesChange] = useNodesState([] as any[])
|
|
|
+ const [edges, setEdges, onEdgesChange] = useEdgesState([] as any[])
|
|
|
+
|
|
|
+ // 自动布局函数
|
|
|
+ const applyAutoLayout = useCallback((nodes: any[], edges: any[], direction: string = 'TB') => {
|
|
|
+ // 创建 dagre 图
|
|
|
+ const dagreGraph = new dagre.graphlib.Graph()
|
|
|
+ dagreGraph.setDefaultEdgeLabel(() => ({}))
|
|
|
+
|
|
|
+ // 设置布局选项
|
|
|
+ const nodeWidth = 250
|
|
|
+ const nodeHeight = 295
|
|
|
+
|
|
|
+ // 根据方向设置布局参数
|
|
|
+ const isHorizontal = direction === 'LR' || direction === 'RL'
|
|
|
+ dagreGraph.setGraph({
|
|
|
+ rankdir: direction,
|
|
|
+ nodesep: 100, // 节点间距
|
|
|
+ ranksep: 100, // 层级间距
|
|
|
+ marginx: 20,
|
|
|
+ marginy: 20
|
|
|
+ })
|
|
|
+
|
|
|
+ // 添加节点到 dagre 图
|
|
|
+ nodes.forEach(node => {
|
|
|
+ dagreGraph.setNode(node.id, {
|
|
|
+ width: nodeWidth,
|
|
|
+ height: nodeHeight
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ // 添加边到 dagre 图
|
|
|
+ edges.forEach(edge => {
|
|
|
+ if (edge.source && edge.target) {
|
|
|
+ dagreGraph.setEdge(edge.source, edge.target)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 计算布局
|
|
|
+ dagre.layout(dagreGraph)
|
|
|
+
|
|
|
+ // 转换节点位置
|
|
|
+ const layoutedNodes = nodes.map(node => {
|
|
|
+ const nodeWithPosition = dagreGraph.node(node.id)
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...node,
|
|
|
+ targetPosition: isHorizontal ? 'left' : 'top',
|
|
|
+ sourcePosition: isHorizontal ? 'right' : 'bottom',
|
|
|
+ position: {
|
|
|
+ x: nodeWithPosition.x - nodeWidth / 2 + Math.random() * 10,
|
|
|
+ y: nodeWithPosition.y - nodeHeight / 2 + Math.random() * 10
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ return layoutedNodes
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ // 初始化布局
|
|
|
+
|
|
|
+ const initFu = useCallback(() => {
|
|
|
+ if (initialNodesWithoutPosition.length > 0) {
|
|
|
+ const layoutedNodes = applyAutoLayout(
|
|
|
+ initialNodesWithoutPosition,
|
|
|
+ initialEdges,
|
|
|
+ layoutDirection
|
|
|
+ )
|
|
|
+ setNodes(layoutedNodes)
|
|
|
+ setEdges(initialEdges)
|
|
|
+
|
|
|
+ // 自适应视图
|
|
|
+ setTimeout(() => {
|
|
|
+ fitView({ duration: 300, padding: 0.1 })
|
|
|
+ }, 100)
|
|
|
+ }
|
|
|
+ }, [applyAutoLayout, fitView, initialEdges, initialNodesWithoutPosition, setEdges, setNodes])
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ initFu()
|
|
|
+ }, [initFu])
|
|
|
|
|
|
// 处理节点点击
|
|
|
const onNodeClick = useCallback((event: React.MouseEvent, node: any) => {}, [])
|
|
|
@@ -101,7 +171,7 @@ function FlowChart() {
|
|
|
</div>
|
|
|
|
|
|
{/* 手动重置按钮 */}
|
|
|
- <div className='A5Aback A5Aloding' onClick={handleReset}>
|
|
|
+ <div className='A5Aback A5Aloding' onClick={initFu}>
|
|
|
<img src={require('@/assets/three/Reset.png')} alt='' />
|
|
|
<div>重置</div>
|
|
|
</div>
|