luxiaotao1123
2024-03-02 0c009a44f7cd35489a56450d0aa2715b00b23c32
Merge branch 'master' of http://47.97.1.152:5880/r/zy-asrs-master
4个文件已修改
15个文件已添加
1245 ■■■■■ 已修改文件
zy-asrs-flow/package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/Flow/GraphComponent.jsx 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/Flow/GraphConfig.jsx 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/Flow/GraphTools.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/Flow/StencilComponent.jsx 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/config/setting.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/index.css 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/index.jsx 108 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/index.jsx2 363 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/index.jsx_old 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/index.less 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-edge/dege2.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-edge/edge1.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-edge/edge1.less 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-edge/edge2.less 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-node/node1.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-node/node1.less 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-node/node2.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/home/react-node/node2.less 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/package.json
@@ -49,6 +49,8 @@
    "@ant-design/icons": "^5.3.0",
    "@ant-design/pro-components": "^2.6.48",
    "@antv/g6": "^4.8.24",
    "@antv/x6": "^2.18.1",
    "@antv/x6-plugin-stencil": "^2.1.5",
    "@antv/xflow": "^2.0.4",
    "@umijs/route-utils": "^2.2.2",
    "antd": "^5.13.2",
zy-asrs-flow/src/components/Flow/GraphComponent.jsx
New file
@@ -0,0 +1,200 @@
import React, { useRef, useEffect } from "react";
import { Graph, Shape } from "@antv/x6";
import { Snapline } from '@antv/x6-plugin-snapline';
import { Selection } from '@antv/x6-plugin-selection';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Clipboard } from '@antv/x6-plugin-clipboard';
import { Stencil } from '@antv/x6-plugin-stencil';
import { History } from '@antv/x6-plugin-history'
import { commonGraphPorts, commonGraphAttrs } from "./GraphConfig";
export const GraphComponent = React.forwardRef((props, ref) => {
    const container = useRef(null);
    const stencilContainer = useRef(null);
    useEffect(() => {
        const graph = initGrap();
        initBind(graph);
        initStencil(graph);
        return () => graph.dispose();
    })
    function initGrap() {
        ref.current = new Graph({
            container: container.current,
            // width: document.documentElement.clientWidth,
            // height: document.documentElement.clientHeight,
            width: 200,
            height: 500,
            // grid: 1,
            connecting: {
                snap: true,
                createEdge() {
                    return new Shape.Edge({
                        attrs: {
                            line: {
                                stroke: '#a0a0a0',
                                strokeWidth: 1,
                                targetMarker: {
                                    name: 'classic',
                                    size: 8,
                                },
                            },
                        },
                    })
                },
                connector: 'smooth',
                allowMulti: true,
                allowPort: true,
            }
        });
        const graph = ref.current;
        const rect = graph.addNode({
            x: 60,
            y: 60,
            width: 120,
            height: 40,
            label: '订单管理',
            ports: commonGraphPorts,
            attrs: commonGraphAttrs,
        });
        const rect2 = graph.addNode({
            x: 240,
            y: 240,
            width: 120,
            height: 40,
            label: '库存管理',
            ports: commonGraphPorts,
            attrs: commonGraphAttrs,
        });
        graph.use(
            new Snapline({
                enabled: true,
            }),
        )
        graph.use(
            new Selection({
                enabled: true,
                multiple: true,
                rubberband: true,
                movable: true,
                showNodeSelectionBox: true,
            }),
        )
        graph.use(
            new History({
                enabled: true,
            }),
        )
        props.initHandle();//通知父组件初始化完成
        return graph;
    }
    function initStencil(graph) {
        const stencil = new Stencil({
            title: '全部',
            target: graph,
            search(cell, keyword) {
                return cell.label.indexOf(keyword) !== -1
            },
            placeholder: '搜索组件',
            notFoundText: '组件不存在',
            collapsable: true,
            stencilGraphHeight: 0,
            groups: [
                {
                    name: 'group1',
                    title: '常用组件',
                }
            ],
        })
        stencilContainer.current.appendChild(stencil.container)
        const n1 = graph.createNode({
            shape: "rect",
            width: 80,
            height: 40,
            label: "默认组件",
            attrs: commonGraphAttrs,
        })
        const n2 = graph.createNode({
            shape: "rect",
            width: 80,
            height: 40,
            label: "测试组件",
            attrs: commonGraphAttrs,
        })
        stencil.load([n1, n2], 'group1')
    }
    function initBind(graph) {
        graph.use(
            new Clipboard({
                enabled: true,
            }),
        )
        graph.use(
            new Keyboard({
                enabled: true,
                global: true,
            })
        )
        graph.bindKey('ctrl+c', () => {
            const cells = graph.getSelectedCells()
            if (cells.length) {
                graph.copy(cells)
            }
            return false
        })
        graph.bindKey('ctrl+v', () => {
            if (!graph.isClipboardEmpty()) {
                const cells = graph.paste({ offset: 32 })
                graph.cleanSelection()
                graph.select(cells)
            }
            return false
        })
        graph.bindKey('ctrl+z', () => {
            graph.undo()
            return false
        })
        graph.bindKey('ctrl+y', () => {
            graph.redo()
            return false
        })
        graph.bindKey('del', (e) => {
            let nodeSelected = graph.getSelectedCells();  // 获取选中的元素
            nodeSelected.forEach(cell => {
                graph.removeCell(cell)
            })
            return false
        })
    }
    return (
        <>
            <div className="app-stencil" ref={stencilContainer} />
            <div className="app-content" ref={container} />
        </>
    );
})
zy-asrs-flow/src/components/Flow/GraphConfig.jsx
New file
@@ -0,0 +1,74 @@
import React, { useRef, useEffect } from "react";
const commonGraphPorts = {
    groups: {
        top: {
            position: 'top',
            attrs: {
                circle: {
                    magnet: true,
                    stroke: '#8f8f8f',
                    r: 5,
                },
            },
        },
        bottom: {
            position: 'bottom',
            attrs: {
                circle: {
                    magnet: true,
                    stroke: '#8f8f8f',
                    r: 5,
                },
            },
        },
        left: {
            position: 'left',
            attrs: {
                circle: {
                    magnet: true,
                    stroke: '#8f8f8f',
                    r: 5,
                },
            },
        },
        right: {
            position: 'right',
            attrs: {
                circle: {
                    magnet: true,
                    stroke: '#8f8f8f',
                    r: 5,
                },
            },
        },
    },
    items: [
        {
            id: 'port1',
            group: 'top',
        },
        {
            id: 'port2',
            group: 'bottom',
        },
        {
            id: 'port3',
            group: 'left',
        },
        {
            id: 'port4',
            group: 'right',
        },
    ],
}
const commonGraphAttrs = {
    body: {
        fill: '#efefef',
        stroke: '#4d4d4d',
        strokeWidth: 2,
    },
}
export { commonGraphPorts, commonGraphAttrs }
zy-asrs-flow/src/components/Flow/GraphTools.jsx
New file
@@ -0,0 +1,15 @@
import React, { useRef, useEffect } from "react";
export const GraphTools = ({ graphRef,isReady }) => {
    const exportData = () => {
        const graph = graphRef.current;
        if (graph) {
            const data = graph.toJSON();
            console.log(data);
            // 这里你可以将数据发送到服务器或保存到本地
        }
    }
    return <button onClick={exportData}>导出数据</button>;
}
zy-asrs-flow/src/components/Flow/StencilComponent.jsx
New file
@@ -0,0 +1,92 @@
import React, { useRef, useEffect } from "react";
import { Stencil } from '@antv/x6-plugin-stencil';
export const StencilComponent = (({ graphRef, isReady, stencilContainer }) => {
    useEffect(() => {
        if (isReady) {
            const graph = graphRef.current;
            const stencil = new Stencil({
                title: 'Stencil',
                target: graphRef.current,
                search(cell, keyword) {
                    return cell.shape.indexOf(keyword) !== -1
                },
                placeholder: 'Search by shape name',
                notFoundText: 'Not Found',
                collapsable: true,
                stencilGraphHeight: 0,
                groups: [
                    {
                        name: 'group1',
                        title: 'Group(Collapsable)',
                    },
                    {
                        name: 'group2',
                        title: 'Group',
                        collapsable: false,
                    },
                ],
            })
            stencilContainer.current.appendChild(stencil.container)
            const commonAttrs = {
                body: {
                    fill: '#fff',
                    stroke: '#8f8f8f',
                    strokeWidth: 1,
                },
            }
            const n1 = graph.createNode({
                shape: 'rect',
                x: 40,
                y: 40,
                width: 80,
                height: 40,
                label: 'rect',
                attrs: commonAttrs,
            })
            const n2 = graph.createNode({
                shape: 'circle',
                x: 180,
                y: 40,
                width: 40,
                height: 40,
                label: 'circle',
                attrs: commonAttrs,
            })
            const n3 = graph.createNode({
                shape: 'ellipse',
                x: 280,
                y: 40,
                width: 80,
                height: 40,
                label: 'ellipse',
                attrs: commonAttrs,
            })
            const n4 = graph.createNode({
                shape: 'path',
                x: 420,
                y: 40,
                width: 40,
                height: 40,
                // https://www.svgrepo.com/svg/13653/like
                path: 'M24.85,10.126c2.018-4.783,6.628-8.125,11.99-8.125c7.223,0,12.425,6.179,13.079,13.543c0,0,0.353,1.828-0.424,5.119c-1.058,4.482-3.545,8.464-6.898,11.503L24.85,48L7.402,32.165c-3.353-3.038-5.84-7.021-6.898-11.503c-0.777-3.291-0.424-5.119-0.424-5.119C0.734,8.179,5.936,2,13.159,2C18.522,2,22.832,5.343,24.85,10.126z',
                attrs: commonAttrs,
                label: 'path123',
            })
            stencil.load([n1, n2], 'group1')
            stencil.load([n3, n4], 'group2')
        }
    })
    return <div className="app-stencil" ref={stencilContainer} />
})
zy-asrs-flow/src/config/setting.ts
@@ -1,5 +1,5 @@
// 接口地址
export const API_BASE_URL: string = 'http://172.16.0.219:9090/wcs';
export const API_BASE_URL: string = 'http://127.0.0.1:9090/wcs';
// 项目名称
export const PROJECT_NAME: string = 'admin';
zy-asrs-flow/src/pages/home/index.css
@@ -7,4 +7,9 @@
        background-color: rgba(255, 255, 255, 0.9);
        padding: 10px 8px;
        box-shadow: rgb(174, 174, 174) 0px 0px 10px;
      }
      .modalInput {
        margin-top: 30px;
        margin-bottom: 30px;
      }
zy-asrs-flow/src/pages/home/index.jsx
@@ -1,91 +1,29 @@
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import { data } from './data';
import G6 from '@antv/g6';
import "./index.css"
import React, { useEffect, useRef, useState } from "react";
import { Graph, Shape } from "@antv/x6";
import { GraphComponent } from "../../components/Flow/GraphComponent";
import { GraphTools } from "../../components/Flow/GraphTools";
import './index.less';
export default function() {
  const ref = React.useRef(null);
  let graph = null;
export default function () {
    const graphRef = useRef(null);
    const [ready, setReady] = useState(false);
  useEffect(() => {
    if (!graph) {
      graph = new G6.Graph({
        container: ReactDOM.findDOMNode(ref.current),
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight,
        modes: {
          default: [
            'drag-canvas',
            'zoom-canvas',
            'drag-node',
          ],
          edit: ['click-select']
        },
        layout: {
          type: 'dagre',
          direction: 'LR',
        },
        defaultNode: {
          shape: 'node',
          type: 'rect',
          labelCfg: {
            style: {
              fill: '#000000A6',
              fontSize: 14,
            },
          },
          style: {
            // 仅在 keyShape 上生效
            fill: 'lightblue',
            stroke: '#888',
            lineWidth: 1,
            radius: 7,
          },
          linkPoints: {
            top: true,
            bottom: true,
            left: true,
            right: true,
            // ... 四个圆的样式可以在这里指定
          },
        },
        defaultEdge: {
          shape: 'polyline',
        },
        nodeStateStyles: {
          // 各状态下的样式,平铺的配置项仅在 keyShape 上生效。需要在其他 shape 样式上响应状态变化则写法不同,参见上文提到的 配置状态样式 链接
          hover: {
            fillOpacity: 0.1,
            lineWidth: 1,
          },
        },
      });
    const initHandle = () => {
        setReady(true);
    }
    graph.data(data);
    graph.render();
    // 监听鼠标进入节点事件
    graph.on('node:mouseenter', (evt) => {
      const node = evt.item;
      // 激活该节点的 hover 状态
      graph.setItemState(node, 'hover', true);
    });
    // 监听鼠标离开节点事件
    graph.on('node:mouseleave', (evt) => {
      const node = evt.item;
      // 关闭该节点的 hover 状态
      graph.setItemState(node, 'hover', false);
    });
    useEffect(() => {
        if (ready) {
            // 你需要在loading状态改变后执行的代码
            console.log('graphRef is ready:', graphRef.current);
        }
    }, [ready]);
    graph.on('node:click', (evt) => {
      const node = evt.item;
      const model = node.getModel();
      // 在这里打开模态框或者编辑表格,传入model以便用于初始化编辑内容
      showModal(model);
    });
  }, []);
  return <div ref={ref}></div>;
    return (
        <div className="stencil-app">
            <GraphTools isReady={ready} graphRef={graphRef} />
            <GraphComponent ref={graphRef} initHandle={initHandle} />
        </div>
    );
}
zy-asrs-flow/src/pages/home/index.jsx2
New file
@@ -0,0 +1,363 @@
import React, { useRef, useEffect } from "react";
import { Graph, Shape } from "@antv/x6";
import { Snapline } from '@antv/x6-plugin-snapline';
import { Selection } from '@antv/x6-plugin-selection';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Clipboard } from '@antv/x6-plugin-clipboard';
import { Stencil } from '@antv/x6-plugin-stencil';
import './index.less';
export default function () {
    const container = useRef(null);
    const stencilContainer = useRef(null);
    const graphRef = useRef(null);
    useEffect(() => {
        graphRef.current = new Graph({
            container: container.current,
            // width: document.documentElement.clientWidth,
            // height: document.documentElement.clientHeight,
            // width: 200,
            // height: 300,
            // grid: 1,
            connecting: {
                snap: true,
                createEdge() {
                    return new Shape.Edge({
                        attrs: {
                            line: {
                                stroke: '#a0a0a0',
                                strokeWidth: 1,
                                targetMarker: {
                                    name: 'classic',
                                    size: 8,
                                },
                            },
                        },
                    })
                },
                connector: 'smooth',
                allowMulti: true,
                allowPort: true,
            },
        });
        const graph = graphRef.current;
        // // 开启节点可以被拖动交互
        // graph.on('cell:mouseenter', ({ cell }) => {
        //     if (cell.isNode()) {
        //         cell.addTools([
        //             {
        //                 name: 'boundary',
        //             },
        //         ])
        //     }
        // })
        // graph.on('node:mouseleave', ({ cell }) => {
        //     cell.removeTools()
        // })
        const rect = graph.addNode({
            x: 60,
            y: 60,
            width: 120,
            height: 40,
            label: '订单管理',
            ports: {
                groups: {
                    top: {
                        position: 'top',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                    bottom: {
                        position: 'bottom',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                    left: {
                        position: 'left',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                    right: {
                        position: 'right',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                },
                items: [
                    {
                        id: 'port1',
                        group: 'top',
                    },
                    {
                        id: 'port2',
                        group: 'bottom',
                    },
                    {
                        id: 'port3',
                        group: 'left',
                    },
                    {
                        id: 'port4',
                        group: 'right',
                    },
                ],
            },
            attrs: {
                body: {
                    fill: '#efefef',
                    stroke: '#4d4d4d',
                    strokeWidth: 2,
                },
            },
        });
        const rect2 = graph.addNode({
            x: 240,
            y: 240,
            width: 120,
            height: 40,
            label: '库存管理',
            ports: {
                groups: {
                    top: {
                        position: 'top',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                    bottom: {
                        position: 'bottom',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                    left: {
                        position: 'left',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                    right: {
                        position: 'right',
                        attrs: {
                            circle: {
                                magnet: true,
                                stroke: '#8f8f8f',
                                r: 5,
                            },
                        },
                    },
                },
                items: [
                    {
                        id: 'port1',
                        group: 'top',
                    },
                    {
                        id: 'port2',
                        group: 'bottom',
                    },
                    {
                        id: 'port3',
                        group: 'left',
                    },
                    {
                        id: 'port4',
                        group: 'right',
                    },
                ],
            },
            attrs: {
                body: {
                    fill: '#efefef',
                    stroke: '#4d4d4d',
                    strokeWidth: 2,
                },
            },
        });
        // graph.addEdge({
        //     source: { cell: rect.id },
        //     target: { cell: rect2.id },
        // });
        graph.use(
            new Snapline({
                enabled: true,
            }),
        )
        graph.use(
            new Selection({
                enabled: true,
                multiple: true,
                rubberband: true,
                movable: true,
                showNodeSelectionBox: true,
            }),
        )
        graph.use(
            new Clipboard({
                enabled: true,
            }),
        )
        graph.use(
            new Keyboard({
                enabled: true,
                global: true,
            })
        )
        graph.bindKey('ctrl+c', () => {
            const cells = graph.getSelectedCells()
            if (cells.length) {
                graph.copy(cells)
            }
            return false
        })
        graph.bindKey('ctrl+v', () => {
            if (!graph.isClipboardEmpty()) {
                const cells = graph.paste({ offset: 32 })
                graph.cleanSelection()
                graph.select(cells)
            }
            return false
        })
        const stencil = new Stencil({
            title: 'Stencil',
            target: graph,
            search(cell, keyword) {
                return cell.shape.indexOf(keyword) !== -1
            },
            placeholder: 'Search by shape name',
            notFoundText: 'Not Found',
            collapsable: true,
            stencilGraphHeight: 0,
            groups: [
                {
                    name: 'group1',
                    title: 'Group(Collapsable)',
                },
                {
                    name: 'group2',
                    title: 'Group',
                    collapsable: false,
                },
            ],
        })
        stencilContainer.current.appendChild(stencil.container)
        const commonAttrs = {
            body: {
                fill: '#fff',
                stroke: '#8f8f8f',
                strokeWidth: 1,
            },
        }
        const n1 = graph.createNode({
            shape: 'rect',
            x: 40,
            y: 40,
            width: 80,
            height: 40,
            label: 'rect',
            attrs: commonAttrs,
        })
        const n2 = graph.createNode({
            shape: 'circle',
            x: 180,
            y: 40,
            width: 40,
            height: 40,
            label: 'circle',
            attrs: commonAttrs,
        })
        const n3 = graph.createNode({
            shape: 'ellipse',
            x: 280,
            y: 40,
            width: 80,
            height: 40,
            label: 'ellipse',
            attrs: commonAttrs,
        })
        const n4 = graph.createNode({
            shape: 'path',
            x: 420,
            y: 40,
            width: 40,
            height: 40,
            // https://www.svgrepo.com/svg/13653/like
            path: 'M24.85,10.126c2.018-4.783,6.628-8.125,11.99-8.125c7.223,0,12.425,6.179,13.079,13.543c0,0,0.353,1.828-0.424,5.119c-1.058,4.482-3.545,8.464-6.898,11.503L24.85,48L7.402,32.165c-3.353-3.038-5.84-7.021-6.898-11.503c-0.777-3.291-0.424-5.119-0.424-5.119C0.734,8.179,5.936,2,13.159,2C18.522,2,22.832,5.343,24.85,10.126z',
            attrs: commonAttrs,
            label: 'path',
        })
        stencil.load([n1, n2], 'group1')
        stencil.load([n3, n4], 'group2')
        return () => graph.dispose();
    }, []);
    const exportData = () => {
        if (graphRef.current) {
            const data = graphRef.current.toJSON();
            console.log(data);
        }
    }
    return (
        <div className="stencil-app">
            <button onClick={exportData}>导出数据</button>
            <div className="app-stencil" ref={stencilContainer} />
            <div className="app-content" ref={container} />
        </div>
    );
}
zy-asrs-flow/src/pages/home/index.jsx_old
New file
@@ -0,0 +1,256 @@
import React, { useEffect, useState,useRef } from 'react';
import ReactDOM from 'react-dom';
import { data } from './data';
import G6 from '@antv/g6';
import "./index.css"
import { Modal, Input } from 'antd';
export default function() {
  const ref = useRef(null);
  const graphRef = useRef(null);
  useEffect(() => {
    if (!graphRef.current) {
      // // 注册自定义行为
      // G6.registerBehavior('drag-line', {
      //   getEvents() {
      //     return {
      //       'edge:mousedown': 'onDragStart',
      //       'canvas:mousemove': 'onDrag',
      //       'canvas:mouseup': 'onDragEnd',
      //     }
      //   },
      //   onDragStart(ev) {
      //     const edge = ev.item;
      //     this.edge = edge;
      //     this.dragging = true;
      //     console.log(ev)
      //   },
      //   onDrag(ev) {
      //     if (!this.dragging) {
      //       return;
      //     }
      //     const { x, y } = ev;
      //     // 更新边的 target(终点)
      //     this.edge.update({
      //       target: { x, y },
      //     });
      //   },
      //   onDragEnd() {
      //     this.edge = null;
      //     this.dragging = false;
      //   }
      // });
      G6.registerBehavior('click-add-edge', {
        getEvents() {
          return {
            'node:click': 'onClick',
            mousemove: 'onMousemove',
            'edge:click': 'onEdgeClick' // 点击空白处,取消边
          };
        },
        onClick(ev) {
          const node = ev.item;
          const graph = this.graph;
          const point = {
            x: ev.x,
            y: ev.y
          };
          const model = node.getModel();
          if (this.addingEdge && this.edge) {
            graph.updateItem(this.edge, {
              target: model.id
            });
            // graph.setItemState(this.edge, 'selected', true);
            this.edge = null;
            this.addingEdge = false;
          } else {
            this.edge = graph.addItem('edge', {
              source: model.id,
              target: point
            });
            this.addingEdge = true;
          }
        },
        onMousemove(ev) {
          const point = {
            x: ev.x,
            y: ev.y
          };
          if (this.addingEdge && this.edge) {
            this.graph.updateItem(this.edge, {
              target: point
            });
          }
        },
        onEdgeClick(ev) {
          const currentEdge = ev.item;
          // 拖拽过程中,点击会点击到新增的边上
          if (this.addingEdge && this.edge == currentEdge) {
            graph.removeItem(this.edge);
            this.edge = null;
            this.addingEdge = false;
          }
        }
      });
      graphRef.current = new G6.Graph({
        container: ReactDOM.findDOMNode(ref.current),
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight,
        modes: {
          default: [
            'drag-canvas',
            'zoom-canvas',
            'drag-node',
            'drag-line',
            'click-add-edge'
          ],
          addEdge: ['click-add-edge', 'click-select']
        },
        layout: {
          type: 'dagre',
          direction: 'LR',
        },
        defaultNode: {
          shape: 'node',
          type: 'rect',
          labelCfg: {
            style: {
              fill: '#000000A6',
              fontSize: 14,
            },
          },
          style: {
            // 仅在 keyShape 上生效
            fill: 'lightblue',
            stroke: '#888',
            lineWidth: 1,
            radius: 7,
          },
          // linkPoints: {
          //   top: true,
          //   bottom: true,
          //   left: true,
          //   right: true,
          //   // ... 四个圆的样式可以在这里指定
          // },
        },
        defaultEdge: {
          shape: 'polyline',
        },
        nodeStateStyles: {
          // 各状态下的样式,平铺的配置项仅在 keyShape 上生效。需要在其他 shape 样式上响应状态变化则写法不同,参见上文提到的 配置状态样式 链接
          hover: {
            fillOpacity: 0.1,
            lineWidth: 1,
          },
        },
      });
    }
    const graph = graphRef.current;
    graph.data(data);
    graph.render();
    graph.setMode("edit")
    // 监听鼠标进入节点事件
    graph.on('node:mouseenter', (evt) => {
      const node = evt.item;
      // 激活该节点的 hover 状态
      graph.setItemState(node, 'hover', true);
    });
    // 监听鼠标离开节点事件
    graph.on('node:mouseleave', (evt) => {
      const node = evt.item;
      // 关闭该节点的 hover 状态
      graph.setItemState(node, 'hover', false);
    });
    graph.on('node:dblclick', (evt) => {
      const node = evt.item;
      const model = node.getModel();
      // 在此处执行显示一个模态框或输入框的操作,将model.id传入用来确定哪个节点,model.label传入用来显示当前节点文字
      showModal(model.id, model.label);
    });
    // 添加行为
    graph.on('edge:click', (evt) => {
      const { item } = evt;
      // 获取边的模型数据
      const model = item.getModel();
      // 切换选中状态
      if (model.style?.stroke === '#f00') {
        // 如果边处于选中状态,则取消选中
        graph.updateItem(item, {
          style: {
            ...model.style,
            stroke: '#000',
          },
        });
      } else {
        // 如果边未被选中,则选中当前边
        graph.updateItem(item, {
          style: {
            ...model.style,
            stroke: '#f00',
          },
        });
      }
    });
  }, []);
  const [modalVisible, setModalVisible] = useState(false);
  const [currentNode, setCurrentNode] = useState(null);
  const [currentLabel, setCurrentLabel] = useState('');
  const showModal = (id, label) => {
    setCurrentNode(id);        // 设置当前节点
    setCurrentLabel(label);    // 设置当前节点文字
    setModalVisible(true);     // 打开模态框
  };
  const updateLabel = (nodeId, newLabel) => {
    if(graphRef.current){
      const node = graphRef.current.findById(nodeId);
      graphRef.current.update(node, {
        label: newLabel,
      });
      graphRef.current.refresh();
    }
  };
  const handleOk = () => {
    // 点击确定后更新节点
    updateLabel(currentNode, currentLabel);
    setModalVisible(false);
  };
  const handleCancel = () => {
    // 关闭模态框
    setModalVisible(false);
  };
  return (
    <>
      <div ref={ref} />  {/* g6图表的容器 */}
      <Modal
        open={modalVisible}
        onOk={handleOk}
        onCancel={handleCancel}
      >
        <div className='modalInput'>
        <Input value={currentLabel} onChange={e => setCurrentLabel(e.target.value)} />
        </div>
      </Modal>
    </>
  );
}
zy-asrs-flow/src/pages/home/index.less
New file
@@ -0,0 +1,20 @@
.stencil-app {
    display: flex;
    padding: 0;
    font-family: sans-serif;
    .app-stencil {
      position: relative;
      width: 300px;
      border: 1px solid #f0f0f0;
    }
    .app-content {
      flex: 1;
      height: 380px;
      margin-right: 8px;
      margin-left: 8px;
      box-shadow: 0 0 10px 1px #e9e9e9;
    }
  }
zy-asrs-flow/src/pages/home/react-edge/dege2.jsx
New file
@@ -0,0 +1,9 @@
import React from 'react'
import { NsGraph } from '@antv/xflow'
import { useAppContext } from '@antv/xflow'
import './edge2.less'
const Edge2 = props => {
  return <div className="edge2-container">React2</div>
}
export default Edge2
zy-asrs-flow/src/pages/home/react-edge/edge1.jsx
New file
@@ -0,0 +1,22 @@
import React from 'react'
import { NsGraph } from '@antv/xflow'
import { useAppContext } from '@antv/xflow'
import { Tooltip } from 'antd'
import './edge1.less'
const Edge1 = props => {
  const ctx = useAppContext()
  // console.log('edge useAppContext', ctx);
  // console.log('edge props:', props);
  return (
    <div className="edge1-container">
      <Tooltip
        title="这是连线上渲染的React内容"
        // defaultVisible={true}
      >
        <div>hover我</div>
      </Tooltip>
    </div>
  )
}
export default Edge1
zy-asrs-flow/src/pages/home/react-edge/edge1.less
New file
@@ -0,0 +1,12 @@
.edge1-container {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-size: 14px;
    background-color: #fff;
    border: 1px solid #690;
    border-radius: 4px;
    cursor: pointer;
  }
zy-asrs-flow/src/pages/home/react-edge/edge2.less
New file
@@ -0,0 +1,12 @@
.edge2-container {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-size: 14px;
    background-color: #fff;
    border: 1px solid #690;
    border-radius: 4px;
    cursor: pointer;
  }
zy-asrs-flow/src/pages/home/react-node/node1.jsx
New file
@@ -0,0 +1,16 @@
import { NsGraph } from '@antv/xflow'
import React from 'react'
import './node1.less'
const Node1 = props => {
  /**
   * 1. 节点的数据、位置信息通过props取
   * 2. 当节点被触发更新时, props返回的数据也会动态更新, 触发节点重新渲染
   */
  return (
    <div className="node1-container">
      <div>{'React节点1'}</div>
    </div>
  )
}
export default Node1
zy-asrs-flow/src/pages/home/react-node/node1.less
New file
@@ -0,0 +1,11 @@
.node1-container {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-weight: 600;
    background-color: #fff;
    border: 1px solid #873bf4;
    border-radius: 4px;
  }
zy-asrs-flow/src/pages/home/react-node/node2.jsx
New file
@@ -0,0 +1,15 @@
import { NsGraph } from '@antv/xflow'
import React from 'react'
import { useAppContext } from '@antv/xflow'
import './node2.less'
const Node2 = props => {
  const ctx = useAppContext()
  return (
    <div className="node2-container">
      <div>{'React节点2'}</div>
    </div>
  )
}
export default Node2
zy-asrs-flow/src/pages/home/react-node/node2.less
New file
@@ -0,0 +1,11 @@
.node2-container {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-weight: 600;
    background-color: #fff;
    border: 1px solid #dd4a68;
    border-radius: 4px;
  }