VUE条件树查询

news2024/11/18 16:31:16

看如下图所示的功能,是不是可高级了?什么,你没看懂?拜托双击放大看!

 是的,我最近消失了一段时间就是在研究这个玩意的实现,通过不懈努力与钻研并参考其他人员实现并加以改造,很好,终于有点小成果,这不就迫不及待给大家分享出来!使用的第三组件为VANT-X6引擎!

自己看官方文档:->https://x6.antv.antgroup.com/tutorial/getting-started

通过上述流后,可以任意组装出查询SQL语句或者是结构交给后端进行查询显示!这远比给定的那些搜索框框来的更加有性价比!用户搜索功能那就是嗖的一下提升了好多个档次。

来吧,到了最重要的环节,代码展示:

一、依赖安装

在项目的依赖包中添加以下依赖:最好按照我使用的版本添加哦,避免出现不兼容API报错无法运行!

"@antv/x6": "1.34.6",
"@antv/hierarchy": "0.6.8",
"@antv/x6-vue-shape": "1.3.2",
"@vue/composition-api":"1.3.0"

完成后,进行npm install或yarn install,取决于你使用的是什么环境脚本!

二、页面代码:

 queryGraph.vue 页面代码

<template>
    <div id="container" style="height: 100%;width:100%"></div>
</template>
<script>
import { Graph } from '@antv/x6'
import Hierarchy from '@antv/hierarchy'
import '@antv/x6-vue-shape'
import condition from './queryCondition.vue' //这是我的vue组件,作为子节点展示在思维导图上
import { findItem, lastChild, setData, addChildNode, removeNode, randomId } from './fun'


export default {
    data() {
        return {
            graphData: {
                'id': '1',
                'type': 'original—add',
                'width': 80,
                'height': 30,
                "children": [
                    // {
                    //     "id": 0.28207584597793156,
                    //     "type": "relative", //关系节点
                    //     "width": 44,
                    //     "height": 44,
                    //     "data": {
                    //         "relative": "and" //and并且 or或者
                    //     },
                    //     "children": [
                    //         {
                    //             "id": 0.32858917851150116,
                    //             "type": "condition-text", //条件节点
                    //             "width": 90,
                    //             "height": 44,
                    //             "level": 1, //判断它是第几级的条件节点
                    //             "edgeText": "",
                    //             "data": {
                    //                 "complete": true,
                    //                 "form": {} //你的业务数据
                    //             }
                    //         },
                    //         {
                    //             "id": 0.30546487070416783,
                    //             "type": "vue-shape", //自定义组件 业务节点
                    //             "width": 744,
                    //             "height": 44,
                    //             "level": 1,
                    //             "edgeText": "",
                    //             "data": {
                    //                 "complete": false,
                    //                 "form": {} //你的业务数据
                    //             }
                    //         }
                    //     ]
                    // }
                ]
            } //默认只有一个根节点
        }
    },
    mounted() {
        this.init()
    },
    methods: {
        //初始化⽅法
        init() {
            let self = this
            Graph.registerNode(
                'original—add',
                {
                    inherit: 'rect',
                    width: 80,
                    height: 30,
                    label: '+纳入条件',
                    attrs: { //样式代码
                        body: {
                            rx: 4,
                            ry: 4,
                            stroke: '#037AFB',
                            fill: '#037AFB',
                            strokeWidth: 1,
                            event: 'add:original' //根节点点击事件
                        },
                        label: {
                            fontSize: 14,
                            fill: 'white',
                            event: 'add:original'//根节点点击事件
                        }
                    }
                },
                true,
            )

            //表示《并且 或者》的关系节点
            Graph.registerNode(
                'relative',
                {
                    inherit: 'rect',
                    markup: [
                        {
                            tagName: 'rect',
                            selector: 'body'
                        },
                        {
                            tagName: 'text',
                            selector: 'label_text'
                        },
                        {
                            tagName: 'image',
                            selector: 'switch'
                        }
                    ],
                    attrs: { //样式代码
                        body: {
                            rx: 4,
                            ry: 4,
                            stroke: 'orange',
                            fill: 'orange',
                            strokeWidth: 1,
                            event: 'change:relative'
                        },
                        label_text: {
                            fontSize: 14,
                            fill: 'white',
                            event: 'change:relative'
                        },
                        switch: {
                            event: 'change:relative' //关系节点 切换 关系事件
                        },
                        text: { text: '并且' }
                    },
                    data: { relative: 'and' } //and并且 or或者 默认为 并且
                }
            )

            //自定义vue 业务节点
            Graph.registerVueComponent('condition', condition, true)

            //显示条件语句
            Graph.registerNode('condition-text',
                {
                    inherit: 'rect',
                    markup: [
                        {
                            tagName: 'rect',
                            selector: 'body'
                        },
                        {
                            tagName: 'g',
                            attrs: { class: 'content' },
                            children: []
                        }
                    ],
                    attrs: {}//样式代码
                }
            )
            // 弯的边
            Graph.registerEdge(
                'mindmap-edge',
                {
                    inherit: 'edge',
                    router: {
                        name: 'manhattan',
                        args: {
                            startDirections: ['right'],
                            endDirections: ['left']
                        }
                    },
                    connector: {
                        name: 'rounded'
                    },
                    attrs: {
                        line: {
                            targetMarker: '',
                            stroke: '#A2B1C3',
                            strokeWidth: 2
                        }
                    }, //样式代码
                    zIndex: 0
                },
                true,
            )

            // 直的边
            Graph.registerEdge(
                'straight-edge',
                {
                    inherit: 'edge',
                    attrs: {}, //样式代码
                    zIndex: 0
                },
                true,
            )

            //编辑
            Graph.registerNodeTool('edit', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -96, y: -72 },
                onClick({ cell }) {
                    const dataItem = cell.getData()
                    setData(this.graphData, cell.id, { ...dataItem, complete: false, isEdit: true })
                    cell.setData({ ...dataItem, complete: false, isEdit: true })
                    //打开编辑时,子级元素偏移
                    const firstChild = cell.getChildAt(0)
                    if (firstChild) {
                        const cellWidth = dataItem.form.unit ? 844 : 744
                        const x = cellWidth - firstChild.position({ relative: true }).x + 80 //编辑框 - 第一个子级位置 - 连接线宽 = 子级偏移量
                        cell.getChildAt(0).translate(x)
                    }
                }
            })

            //删除
            Graph.registerNodeTool('del', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -64, y: -72 },
                onClick({ cell }) {
                    if (removeNode(cell.id, this.graphData)) {
                        render(graph, this.graphData)
                    }
                }
            })

            //新增限定条件
            Graph.registerNodeTool('add-condition', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -32, y: -72 },
                onClick({ cell }) {
                    debugger
                    const { id } = cell
                    const dataItem = findItem(this.graphData, id).node
                    const lastNode = lastChild(dataItem)//找到当前node的最后一级,添加
                    if (addChildNode(lastNode.id, '并且', graphData)) render(graph, this.graphData)
                }
            })

            //关系节点 点击增加条件事件
            Graph.registerNodeTool('relative:add-condition', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            width: 32,
                            height: 28
                        }
                    },
                    {
                        tagName: 'image',
                        selector: 'icon',
                        attrs: {
                            'xlink:href': 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SYCuQ6HHs5cAAAAAAAAAAAAAARQnAQ',
                            cursor: 'pointer',
                            width: 16,
                            height: 16,
                            x: 8,
                            y: 6
                        }
                    }
                ],
                x: '100%',
                y: '100%',
                offset: { x: -32, y: -72 },
                onClick({ cell }) {
                    debugger
                    const { id } = cell
                    if (addChildNode(id, '', this.graphData)) render(graph, this.graphData)
                }
            })

            //边增加条件
            Graph.registerEdgeTool('edge:add-condition', {
                inherit: 'button', // 基类名称,使用已经注册的工具名称。
                markup: [
                    {
                        tagName: 'rect',
                        selector: 'button',
                        attrs: {
                            fill: '#296FFF',
                            cursor: 'pointer',
                            fontSize: 16,
                            width: 20,
                            height: 20,
                            rx: 2,
                            ry: 2,
                            stroke: '#296FFF',
                            strokeWidth: 1
                        }
                    },
                    {
                        tagName: 'text',
                        selector: 'label',
                        textContent: '+',
                        attrs: {
                            x: 5,
                            y: 15,
                            fontSize: 16,
                            cursor: 'pointer',
                            fill: '#ffff'
                        }
                    }
                ],
                distance: '100%',
                offset: { y: -10, x: -10 },
                onClick({ cell }) {
                    const { node, parent } = findItem(self.graphData, cell.target.cell)
                    const newId = randomId()
                    const childP = {
                        children: [node],
                        id: newId,
                        type: 'relative',
                        width: 40,
                        height: 40,
                        level: 2,
                        data: { relative: 'and', type: 'document' }
                    }
                    const currentIndex = parent.children.findIndex(item => item.id === node.id)
                    parent.children[currentIndex] = childP
                    let anode = addChildNode(newId, '', self.graphData)
                    anode.width = 550
                    if (anode) {
                        render(graph, self.graphData)
                    }

                    // const { node, parent } = findItem(self.graphData, cell.target.cell)
                    // const newId = randomId()
                    // const childP = {
                    //     id: newId,
                    //     type: "vue-shape", //自定义组件 业务节点
                    //     width: 550,
                    //     height: 44,
                    //     level: 1,
                    //     edgeText: "",
                    //     data: {
                    //         complete: false,
                    //         form: {} //你的业务数据
                    //     }
                    // }
                    // parent.children.push(childP)
                    // render(graph, self.graphData)
                }
            })

            let graph = new Graph({
                background: { color: '#fff' },
                container: document.getElementById('container'),
                panning: { enabled: true },
                selecting: { enabled: true },
                keyboard: { enabled: true },
                grid: true,
                mousewheel: {
                    enabled: true,
                    modifiers: ['ctrl', 'meta']
                },
                interacting: { nodeMovable: false }
            })

            const render = (graph, graphData) => {
                const result = Hierarchy.mindmap(graphData, {
                    direction: 'H',
                    getHeight(d) {
                        return d.height
                    },
                    getWidth(d) {
                        return d.width
                    },
                    getHGap() {
                        return 40
                    },
                    getVGap() {
                        return 20
                    },
                    getSide: () => {
                        return 'right'
                    }
                })
                const cells = []
                const traverse = (hierarchyItem, parentId) => {
                    if (hierarchyItem) {
                        const { data, children } = hierarchyItem
                        const node = graph.createNode({
                            ...data,
                            shape: data.type,
                            x: hierarchyItem.x,
                            y: hierarchyItem.y,
                            component: 'condition'
                        })
                        if (parentId) {
                            //有父级则插入父级
                            const parent = graph.getCellById(parentId)
                            parent && parent.addChild(node)
                        }
                        if (data.type === 'condition-text') {
                            //条件文案节点 根据文字长度,计算宽度,这边粗糙了点,将数字也按中文字长度计算,可优化
                            //下面是我的根据我的业务数据结构计算长度,可参考
                            //const { key, opt, value = [], unit } = data.data.form
                            //const keyText = key.displayText
                            //const optText = opt.displayText
                            //const valueText = typeof value === 'string' ? value : value.join(',')
                            //const unitText = valueText.length ? (unit || '') : ''
                            //const width = (keyText.length + optText.length + valueText.length + unitText.length) * 16 + 10

                            //node.attr('key/text', `${keyText},`)
                            //node.attr('opt', { text: `${optText} `, x: keyText.length * 16 + 5 })
                            //node.attr('value', { text: valueText, x: (keyText.length + optText.length) * 16 + 5 })
                            //node.attr('unit', { text: unitText, x: (keyText.length + optText.length + valueText.length) * 16 + 5 })
                            //node.resize(width, 44)
                            //data.width = width
                        }
                        //关系节点,默认是并且为蓝色,是或者的话,需要切换颜色判断
                        if (data.type === 'relative' && data.data.relative === 'or') {
                            node.setAttrs({
                                body: { stroke: '#CEE8D9', fill: '#CEE8D9' },
                                label_text: { fill: '#008451' },
                                switch: { 'xlink:href': "" },
                                text: { text: '或者' }
                            })
                        }
                        cells.push(node)
                        //子节点边
                        if (children) {
                            children.forEach((item) => {
                                const { id, data: itemData } = item
                                cells.push(
                                    graph.createEdge({
                                        shape: itemData.edgeText ? 'straight-edge' : 'mindmap-edge',
                                        source: {
                                            cell: hierarchyItem.id,
                                            anchor: {
                                                name: itemData.type === 'topic-child' ? 'right' : 'center',
                                                args: {
                                                    dx: itemData.type === 'topic-child' ? -16 : '25%'
                                                }
                                            }
                                        },
                                        target: { cell: id, anchor: { name: 'left' } },
                                        labels: [{ attrs: { text: { text: itemData.edgeText || '' } } }]
                                    }),
                                )
                                traverse(item, node.id)
                            })
                        }
                    }
                }
                traverse(result)
                graph.resetCells(cells)
                // graph.scaleContentToFit({ maxScale: 1 })
                graph.centerContent()
            }
            //根结点添加
            graph.on('add:original', ({ node }) => {
                debugger
                if (this.graphData.children.length == 0) {
                    const { id } = node
                    let anode = addChildNode(id, '', this.graphData)
                    anode.id = randomId()
                    anode.type = "vue-shape" //自定义组件 业务节点
                    anode.width = 550
                    anode.height = 44
                    anode.level = 1
                    anode.edgeText = ""
                    anode.data = {
                        complete: false,
                        form: {} //你的业务数据
                    }
                    anode.children = []
                    if (anode) {
                        render(graph, this.graphData)
                    }
                }
                else if (this.graphData.children.lastObject().type != 'relative') {
                    const { id } = node
                    let tlist = this.graphData.children
                    this.graphData.children = []

                        let anode = addChildNode(id, '', this.graphData)
                        anode.type = "relative"
                        anode.width = 40;
                        anode.height = 40;
                        anode.level = 1;
                        anode.data = {
                            "relative": "and" //and并且 or或者
                        }

                        let xlist = []
                        tlist.forEach(element => {
                            xlist.push(element)
                        });
                        xlist.push({
                            "id": randomId(),
                            "type": "vue-shape", //自定义组件 业务节点
                            "width": 550,
                            "height": 44,
                            "level": 1,
                            "edgeText": "",
                            "data": {
                                "complete": false,
                                "form": {} //你的业务数据
                            }
                        })
                        anode.children = xlist
                        if (anode) {
                            render(graph, this.graphData)
                        }
                }
                else 
                {
                    const { id } = node
                    let tlist = this.graphData.children
                    this.graphData.children = []

                    let anode = addChildNode(id, '', this.graphData)
                    anode.type = "relative"
                    anode.width = 40;
                    anode.height = 40;
                    anode.level = 1;
                    anode.data = {
                        "relative": "and" //and并且 or或者
                    }

                    let xlist = []
                    tlist.forEach(x=>{
                        xlist.push(x)
                    })
                    xlist.push({
                        "id": randomId(),
                        "type": "vue-shape", //自定义组件 业务节点
                        "width": 550,
                        "height": 44,
                        "level": 1,
                        "edgeText": "",
                        "data": {
                            "complete": false,
                            "form": {} //你的业务数据
                        }
                    })
                    anode.children = xlist
                    // tlist.push(anode)
                    this.graphData.children = [anode]
                    if (anode) {
                        render(graph, this.graphData)
                    }
                }
            })
            //节点数据变化
            graph.on('node:change:data', (cell) => {
                debugger
            })
            //关系节点 切换《并且或者》
            graph.on('change:relative', (cell) => {
                let node = cell.node
                if (node.data.relative == "and") {
                    node.data.relative = "or"
                    node.setAttrs({
                        body: {
                            stroke: '#d4eade',
                            fill: '#d4eade'
                        },
                        label_text: {
                            fontSize: 14,
                            fill: '#3e845e',
                        },
                        text: { text: '或者' }
                    })
                }
                else {
                    node.data.relative = "and"
                    node.setAttrs({
                        body: {
                            stroke: 'orange',
                            fill: 'orange'
                        },
                        label_text: {
                            fontSize: 14,
                            fill: 'white',
                        },
                        text: { text: '并且' }
                    })
                }
                debugger
                const dataItem = node.getData()
                setData(self.graphData,node.id,dataItem)
                debugger
            })
            //节点聚焦 增加工具栏目
            graph.on('node:mouseenter', ({ node }) => {
                // if (['condition-text', 'relative'].includes(node.shape)) {
                //     if (!this.isExistUnComplete()) { //判断当前是否有未填写完成的vue组件节点
                //         if (node.shape === 'condition-text') {
                //             node.setAttrs({ body: { fill: '#E9F0FF', stroke: '#296FFF' } })
                //         }
                //         this.addTool(node)
                //     }
                // }
            })
            //节点失焦 移除工具栏
            graph.on('node:mouseleave', ({ node }) => {
                // if (['condition-text', 'relative'].includes(node.shape)) {
                //     if (node.shape === 'condition-text') {
                //         node.setAttrs({ body: { stroke: '#CCC', fill: '#fff' } })
                //     }
                //     this.removeTool(node)
                // }
            })
            //边 悬浮事件
            graph.on('edge:mouseenter', ({ edge }) => {
                //不是 根结点下第一个关系节点 并且 没有未完成的节点 可添加
                const targetNode = graph.getCellById(edge.target.cell)
                const targetNodeData = findItem(this.graphData, edge.target.cell).node
                const isChild = targetNodeData.level ? targetNodeData.level === 1 : true //不是限定节点 可添加
                if (!(edge.source.cell === '1' && targetNode.shape === 'relative') && isChild && !this.isExistUnComplete()) {
                    edge.addTools(['edge:add-condition'])
                }
            })
            //边 失焦
            graph.on('edge:mouseleave', ({ edge }) => {
                if (!this.isExistUnComplete()) {//判断当前是否有未填写完成的vue组件节点
                    edge.removeTools(['edge:add-condition'])
                }
            })
            render(graph, this.graphData)
        },
        isExistUnComplete() {
            return false
        }
    }
}
</script>
<style lang="scss">
.topic-image {
    visibility: hidden;
    cursor: pointer;
}

.x6-node:hover .topic-image {
    visibility: visible;
}

.x6-node-selected rect {
    stroke-width: 2px;
}
</style>

三、自定义条件组件queryCondition.vue

<template>
    <div class="condition">
        <el-form ref="form" :model="form" label-width="0" inline>
            <el-row :gutter="10">
                <el-col :span=8>
                    <el-form-item class="w-100">
                        <el-input v-model="form.name" placeholder="搜索项目"></el-input>
                    </el-form-item>
                </el-col>
                <el-col :span=4>
                    <el-form-item class="w-100">
                        <el-select v-model="form.condition" placeholder="关系">
                            <el-option v-for="item in optionsList" :key="item.label" :label="item.label"
                                :value="item.value">
                            </el-option>
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span=7>
                    <el-form-item class="w-100">
                        <el-input v-model="form.text" placeholder="对比值"></el-input>
                    </el-form-item>
                </el-col>
                <el-col :span=5>
                    <el-from-item class="w-100">
                        <div class="flex-row w-100">
                            <el-button>取消</el-button>
                            <el-button type="primary" @click="onSubmit">确定</el-button>
                        </div>
                    </el-from-item>
                </el-col>
            </el-row>
        </el-form>
    </div>
</template>

<script>

// import { elForm, elFormItem, elInput, elSelect, elOption } from 'element-ui'//在这需要再次按需引入对应组件
export default {
    name: 'queryCondition',
    inject: ["getGraph", "getNode"],
    // components: { elForm, elFormItem, elInput, elSelect, elOption },
    data() {
        return {
            form: {
                name:null,
                condition:null,
                text:null
            },
            optionsList: [
                { label: '等于', value: '=' },
                { label: '不等于', value: '!=' },
                { label: '大于', value: '>' },
                { label: '大于等于', value: '>=' },
                { label: '小于', value: '<' },
                { label: '小于等于', value: '<=' }
            ]
        }
    },
    mounted() {
    },
    methods: {
        onSubmit(){}
    }
}
</script>

<style lang="scss" scoped>
.condition {
    padding: 0px 10px;
    height: 100%;
    background: #EFF4FF;
    border: 1px solid #5F95FF;
    border-radius: 6px;

    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
}


.flex-row{
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
}

::v-deep {
    .el-form-item--small {
        margin: 0px;
        vertical-align: middle !important;
    }

    .el-button--small{
        padding-left:10px;
        padding-right: 10px;
    }
}
</style>

四、公共方法 fun.js

import {snowFlakeId} from '@/utils/snowFlake'

//查找节点的父节点 当前节点,顶级节点的数据
export const findItem = (obj, id, levelTop) => {
    const topNode = levelTop
        ? levelTop
        : obj.level && obj.level === 1
        ? obj
        : null;
    if (obj.id === id) {
        return {
            parent: null,
            node: obj,
            topNode,
        };
    }
    const { children } = obj;
    if (children) {
        for (let i = 0, len = children.length; i < len; i++) {
            const res = findItem(children[i], id, topNode);
            if (res) {
                return {
                    parent: res.parent || obj,
                    node: res.node,
                    topNode: res.topNode,
                };
            }
        }
    }
    return null;
};
//查找最末级
export const lastChild = (obj) => {
    if (obj.children && obj.children.length) {
        return lastChild(obj.children[0]);
    } else {
        return obj;
    }
};
//设置某个节点的data
export const setData = (obj, id, dataItem) => {
    if (obj.id === id) {
        obj.data = dataItem;
        if (["vue-shape", "condition-text"].includes(obj.type)) {
            obj.type = dataItem.complete ? "condition-text" : "vue-shape";
        }
        return;
    }
    if (obj.children) {
        obj.children.forEach((child) => {
            setData(child, id, dataItem);
        });
    }
};

//插入节点
export const addChildNode = (id, edgeText, data) => {
    const res = findItem(data, id);
    const dataItem = res.node;
    if (dataItem) {
        const item = {
            id: randomId(),
            type: "vue-shape",
            width: 744,
            height: 44, //内容宽高 + padding20 + 边框4
            level: dataItem.level === 1 ? dataItem.level + 1 : 1,
            edgeText,
        };
        if (dataItem.children) {
            dataItem.children.push(item);
        } else {
            dataItem.children = [item];
        }
        return item;
    }
    return null;
};
//移除节点
export const removeNode = (id, data) => {
    const res = findItem(data, id);
    const dataItem = res.parent;
    if (dataItem && dataItem.children) {
        const { children } = dataItem;
        const index = children.findIndex((item) => item.id === id);
        children.splice(index, 1); //删除当前
        if (children.length && children.length < 2) {
            //并且或者 只有一个子级时 删除并且或者节点
            const p2 = findItem(data, dataItem.id).parent; //父级的父级
            const p2OtherChildren = p2.children.filter(
                (item) => item.id !== dataItem.id
            );
            p2.children = [...p2OtherChildren, ...children];
        }
        return true;
    }
    return null;
};

export const randomId = ()=> {
    return snowFlakeId()
};

目前只实现初步的效果,后期实现相关功能后再视具体是否可开放源码进行共享!

创作不易,谢谢你的点赞和关注收藏!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2166677.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能时代的网络空间战略稳定及其挑战

文章目录 前言一、人工智能时代的网络空间战略稳定及其挑战(一)国内政治与官僚主义二、大国竞争与溯源政治三、国际法规与治理限制总结前言 人工智能的武器化应用在短期内将同时强化网络空间中进攻方和防御方的能力,但从长期看将有利于防御方。这种态势将令传统威慑逻辑重新…

[数据库实验三]安全性

目录 一、实验目的与要求&#xff1a; 二、实验内容&#xff1a; 三、实验小结 一、实验目的与要求&#xff1a; 1、设计用户子模式 2、根据实际需要创建用户角色及用户&#xff0c;并授权 3、针对不同级别的用户定义不同的视图&#xff0c;以保证系统的安全性 二、实验内…

Springboot jPA+thymeleaf实现增删改查

项目结构 pom文件 配置相关依赖&#xff1a; 2.thymeleaf有点类似于jstlel th:href"{url}表示这是一个链接 th:each"user : ${users}"相当于foreach&#xff0c;对user进行循环遍历 th:if进行if条件判断 {变量} 与 ${变量}的区别: 4.配置好application.ym…

【SemeDrive】【X9H】如何修改 SAFETY_FAULT 输出 PWM 频率

前言&#xff1a; SAFETY_FAULT 也是 SEM_FAULT&#xff0c;在原理图上会有不同的标注&#xff0c;但意义一样。 默认的 SAFETY_FAULT 正常时输出 PWM 频率为 100 MHz&#xff0c;过高的频率有时会导致无法通过 EMI 测试&#xff0c;需要降低频率。以下描述如何将正常时的 S…

ssh 命令详解

一、命令简介 ​ssh ​命令用于安全登录远程主机&#xff0c;以便在远程机上执行命令或传输数据。 ‍ 例如登录远程主机 169.10.222.23 ​上的 soulio ​用户&#xff1a; ssh soulio169.10.222.23更多示例参考第三章。 ‍ 了解背景知识&#xff1a;ssh 加密 1. 加密类型…

C++之Person类中调用Date类

main.cpp #include <iostream> #include "Person.h" using namespace std;int main() {Person myPerson;// Person myPerson("S.M.Wang", 070145, "莲花路200号");cout << "请输入姓名:" ;string name;cin >> name…

【文档智能 RAG】浅看开源的同质化的文档解析框架-Docling

前言 RAG的兴起&#xff0c;越来越多的人开始关注文档结构化解析的效果&#xff0c;这个赛道变得非常的同质化。 关于文档智能解析过程中的每个技术环节的技术点&#xff0c;前期文章详细介绍了很多内容&#xff1a; 下面我们简单的看看Docling这个PDF文档解析框架里面都有什…

尚品汇-自动化部署-Jenkins的安装与环境配置(五十六)

目录&#xff1a; 自动化持续集成 &#xff08;1&#xff09;环境准备 &#xff08;2&#xff09;初始化 Jenkins 插件和管理员用户 &#xff08;3&#xff09;工作流程 &#xff08;4&#xff09;配置 Jenkins 构建工具 自动化持续集成 互联网软件的开发和发布&#xf…

AI:颠覆式创新 vs. 持续性创新

随着有关生成式人工智能 (GenAI) 的新闻不断出现在社交媒体上&#xff0c;包括 ChatGPT 4o 如何帮助你与朋友玩石头、剪刀、布&#xff0c;关于 GenAI 的“颠覆性”影响的惊人声明并不难找到。 事实证明&#xff0c;将 GenAI 本身称为“颠覆性”并没有多大意义。 它能成为颠覆…

libvirt中的qemu与kvm

在 libvirt 虚拟机管理中&#xff0c;domain_type 的设置决定了虚拟机使用的虚拟化技术。在 domain_type 中&#xff0c;qemu 和 kvm 是两种不同的虚拟化模式&#xff0c;它们的区别主要在于是否使用硬件虚拟化加速。 qemu 模式 定义&#xff1a;qemu 是一种完全软件模拟的虚…

Recorder录音插件使用日记

目录 一、安装插件 二、导入文件 1.app-xxx-support.js支持文件 2.RecordApp 三 功能的使用 3.1 请求录音权限 3.2 开始录音 3.3 停止录音 3.4 其他接口 四 、使用 4.1 开始录音实例 4.2 请求录音权限 4.3 停止录音——文件的下载与上传 一、安装插件 npm install…

c++ day06

类的栈 实现 #include <iostream>using namespace std;class Stack { private:static const size_t MAX 100; // 定义固定容量int data[MAX]; // 存储栈元素的数组size_t len; // 当前栈的大小public:// 构造函数Stack() : len…

排序(交换排序:冒泡,快排)

冒泡排序&#xff1a;定义两个指针&#xff0c;指向第一个和第二个位置&#xff0c;前一个比后一个大就交换&#xff0c;然后同时向后挪接着比较&#xff0c;把最大的放到最后一个位置。最坏的情况&#xff1a;O(N^2)&#xff0c;最好的情况&#xff1a;O(N)。冒泡和插入的时间…

【深度学习】03-神经网络 5 (完结篇) 一文讲解 pytroch手机价格神经网络分类与准确率优化案例

手机价格分类数据集已经上传&#xff0c;用户可以自行下载进行训练。 构建数据集 数据共有 2000 条, 其中 1600 条数据作为训练集, 400 条数据用作测试集。 我们使用 sklearn 的数据集划分工作来完成 。并使用 PyTorch 的 TensorDataset 来将数据集构建为 Dataset 对象&#x…

一款好用的远程连接工具:MobaXterm

在日常工作中&#xff0c;作为开发者或运维人员&#xff0c;你是否经常需要远程连接服务器进行调试和管理&#xff1f;传统的SSH工具常常不够灵活&#xff0c;操作繁琐&#xff0c;无法满足日益复杂的工作需求。而MobaXterm的出现&#xff0c;带来了远程连接工具的全新体验。它…

付费计量系统的标准化框架(上)

Generic processes 通用过程Specific system processes 专用系统过程Generic functions 通用功能Specific system functions 专用系统功能Data Elements 数据单元Specific system data elements 专用数据单元Customer_Information_System 用户信息系统CIS_to_POS_Interface Typ…

MySql中索引失效的情况及原因

1.索引失效的情况 这是正常查询情况&#xff0c;满足最左前缀&#xff0c;先查有先度高的索引。 1. 注意这里最后一种情况&#xff0c;这里和上面只查询 name 小米科技 的命中情况一样。说明索引部分丢失&#xff01; 2. 这里第二条sql中的&#xff0c;status > 1 就是范围…

鸿蒙小技巧

1.子调用父的方法 子组件 父组件 2.使用emitter实现孙子传爷 孙子组件 import emitter from ohos.events.emitter;let event: emitter.InnerEvent {eventId: 1,priority: emitter.EventPriority.HIGH};let eventData: emitter.EventData {data: {"state": true,…

QProgressDialog运行初始不显示的问题

我用的是qt手册上的示例代码&#xff0c;结果运行时却出现如下问题&#xff1a; 如图程序运行时&#xff0c;开始一段时间是不显示进度条、百分比之类的。 运行一段时间之后&#xff0c;到50%才显示。当时数字是2&#xff0c;总数是4。 我用了网上的方案&#xff0c;增加了一条…

mysql中的float vs double

mysql中的float vs double 1、精度2、存储空间3、适用场景 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在数据存储和计算领域&#xff0c;float和double是两种常见的浮点数类型&#xff0c;它们的主要区别如下&#xff1a; 1、精度 fl…