21、springboot3 vue3开发平台-前端-自定义树形穿梭框,用于角色权限分配

news2024/11/28 2:03:43

文章目录

  • 1. 使用原因
  • 2. 实现
  • 3. 使用

1. 使用原因

elemenutplus 有穿梭框,但是不支持树状数据的操作,所以这里自定义树状穿梭框,用于菜单权限分配, 如下:
在这里插入图片描述

2. 实现

这里主要是将菜单列表树解构后添加修改组合再恢复
src\components\TransferTree\index.vue

<template>
    <el-dialog v-model="transferVisible" title="权限分配" width="800">
        <div class="transfer">
            <div class="contaner">
                <!---->
                <div class="item">
                    <div class="title">
                        已分配权限
                    </div>
                    <div class="tree">
                        <el-tree ref="treeRef" :data="transData" :props="transProps" show-checkbox />
                    </div>
                </div>
                <div class="transfercenter">
                    <!---->
                    <div class="transbutton">
                        <el-button type="primary" :icon="ArrowLeft" @click="leftButtonClick"></el-button>
                        <el-button type="primary"><el-icon class="el-icon--right" @click="rightButtonClick">
                                <ArrowRight />
                            </el-icon></el-button>
                    </div>
                </div>
                <!---->
                <div class="item">
                    <div class="title">
                        未分配权限
                    </div>
                    <div class="tree">
                        <el-tree ref="treeRef1" :data="transData1" :props="transProps" show-checkbox />
                    </div>
                </div>

            </div>
            <div>
                <div class="footer">
                    <el-button type="primary" @click="onDialogFormConfirmTransfer">确 定</el-button>
                    <el-button @click="onDialogFormCancelTransFer">取 消</el-button>
                </div>
            </div>
        </div>
    </el-dialog>
</template>

<script lang="ts" setup>
import {ref } from 'vue'
import {ArrowLeft, ArrowRight  } from '@element-plus/icons-vue'

const props = defineProps<{
    transDataAuth: Array<any>,
    transDataNoAuth:  Array<any>
}>()

// 传回的菜单ids
const emit = defineEmits(['returnIds', "close"])

const transferVisible = ref(true)
const transData = ref(props.transDataAuth)
const transData1 = ref(props.transDataNoAuth)
const treeRef = ref() 
const treeRef1= ref() 

const transProps = {
    id: "roleId",
    children: 'children',
    label: 'menuName',
}

// 提交对话框表单按钮事件
const onDialogFormConfirmTransfer = async () => {
    let authMenus = flattenMenuTree(props.transDataAuth)
    let ids = authMenus.map((item: any) => item.id)
    emit('returnIds', ids)
}


// 取消对话表单框按钮事件
const onDialogFormCancelTransFer = () => {
    emit('close')
}

// 授权按钮
const leftButtonClick = () => {
    let selctedMenus = treeRef1.value.getCheckedNodes(false, false)
    let ids = selctedMenus.map((item: any) => item.id)
    // 解构菜单树
    let authList = flattenMenuTree(transData.value)
    let notAuthList = flattenMenuTree(transData1.value)
    // 添加授权,删除未授权菜单
    authList.push(...selctedMenus)
    notAuthList = notAuthList.filter((item: any) => !ids.includes(item.id))
    // 重新构建菜单树
    transData.value = []
    transData1.value = []
    transData.value = buildMenuTree(filterRepetition(authList))
    transData1.value = buildMenuTree(filterRepetition(notAuthList))
}

// 取消授权按钮
const rightButtonClick = () => {
    let selctedMenus = treeRef.value.getCheckedNodes(false, false)
    let ids = selctedMenus.map((item: any) => item.id)
    // 解构菜单树
    let authList = flattenMenuTree(transData.value)
    let notAuthList = flattenMenuTree(transData1.value)
    // 添加授权,删除未授权菜单
    notAuthList.push(...selctedMenus)
    authList = authList.filter((item: any) => !ids.includes(item.id))
    // 重新构建菜单树
    transData.value = buildMenuTree(filterRepetition(authList))
    transData1.value = buildMenuTree(filterRepetition(notAuthList))
}

// 构建列表树
function buildMenuTree(menuList: any) {  
    // 创建一个映射,以便快速通过ID查找菜单项  
    const map = new Map(menuList.map((item: any) => [item.id, { ...item, children: [] }]));  
  
    // 遍历菜单列表,构建树结构  
    function attachChildren(parentId = 0) {  
        // 查找所有具有指定parentId的菜单项  
        return menuList.filter((item: any) => item.parentId === parentId).map((item: any) => {  
            const currentNode: any = map.get(item.id)
            // 递归地为当前节点附加子节点  
            currentNode.children = attachChildren(item.id)
            return currentNode;  
        });  
    }  
  
    // 注意:顶级菜单项(没有parentId或parentId为null/undefined)  
    const tree = attachChildren();  
    return tree;  
} 

function flattenMenuTree(tree: any) {  
    let result: any = [] 
    // 递归函数来遍历树并收集节点  
    function traverse(nodes: any) { 
        if (nodes) {
            nodes.forEach((node: any) => {  
            // 将当前节点添加到结果数组中  
            result.push({ ...node});
            if (node.children && node.children.length > 0) {  
                traverse(node.children);
            }  
            })
        }
    }    
    // 开始遍历树  
    traverse(tree);  
  
    // 如果不需要层级信息,直接返回结果数组  
    return result;  
}  

// 过滤重复的菜单
const filterRepetition = (menulist: any) => {
    // console.log("menulist: " + menulist)
    let seenIds = new Set();  
    // 过滤菜单项  
    let menus = menulist.filter((item: any) => {  
        // 如果当前项的id在Set中不存在,则添加到Set中,并返回true(保留该项)  
        // 否则,返回false(移除该项)  
        if (!seenIds.has(item.id)) {  
            seenIds.add(item.id);  
            return true;  
        }  
        return false;  
    })
    //console.log("menulist: " + menulist)
    return menus
}


</script>


<style lang="scss">
.transfer {
    display: flex;
    flex-direction: column;

    .contaner {
        display: flex;
        flex-direction: row;
        justify-content: space-between;
        height: 500px;

        .item {
            display: flex;
            flex-direction: column;
            width: 40%;
            height: 100%;

            .title {
                text-align: center;
                background-color: #F5F7FA;
                height: 6%;
                font-size: 16px;

            }

            .tree {
                overflow-y: scroll;
                height: 94%;
            }
        }

        .transfercenter {
            display: flex;

            padding-top: 30px;
            box-sizing: border-box;
            width: 20%;
            height: 100%;

            // border: 10px solid black; /* 边框宽度、样式、颜色 */
            // background-color: #FF0000;
            .transbutton {
                margin-top: 200px;
            }

        }


    }

    .footer {
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
    }
}
</style>

3. 使用

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

STM32H7双路CAN踩坑记录

STM32H7双路CAN踩坑记录 目录 STM32H7双路CAN踩坑记录1 问题描述2 原因分析3 解决办法4 CAN配置参考代码 1 问题描述 STM32的CAN1和CAN2无法同时使用。 注&#xff1a;MCU使用的是STM32H743&#xff0c;其他型号不确定是否一样&#xff0c;本文只以STM32H743举例说明。 2 原因…

odoo17 网站内容存在哪了

odoo17 网站内容存在哪了 查数据库内容&#xff0c;却没找到 没理解这些内容到底存在了哪里呢

图文详解ThreadLocal:原理、结构与内存泄漏解析

目录 一.什么是ThreadLocal 二.ThreadLocal的内部结构 三.ThreadLocal带来的内存泄露问题 ▐ key强引用 ▐ key弱引用 总结 一.什么是ThreadLocal 在Java中&#xff0c;ThreadLocal 类提供了一种方式&#xff0c;使得每个线程可以独立地持有自己的变量副本&#xff0c;而…

「黑神话:悟空」狂销 15 亿!高清游戏录制神器助你称霸

短短一天时间 《黑神话&#xff1a;悟空》在Steam上已售出超过300万份 加上wegame、epic和ps平台 目前总销量超过450万份&#xff0c;总销售额超过15亿元。 根据Steam平台实时数据 8月20日晚间20点30分 该平台《黑神话&#xff1a;悟空》同时在线玩家人数突破200万 达到2…

手机怎么把百度网盘里的文件打印出来?

在日常生活中&#xff0c;我们常常需要打印各种文档&#xff0c;比如合同、报告或是学习资料。有时这些文件存储在网盘中&#xff0c;比如百度网盘&#xff0c;这时候如果能够直接从网盘中打印出来&#xff0c;将会极大地提高效率。今天&#xff0c;就让我们来了解一下如何使用…

PL3366C 用0.1+的芯片做过认证5V1A电源

PL3366C是一款原边反激式5W开关电源芯片恒流/恒压电源。PL3366C高度集成了功率开关&#xff0c;无需光耦以及次级控制电路&#xff0c;PL3366C的复合模式的应用使芯片能够实现低静态功耗、低音频噪音、高效率。满载时PL3366C工作在PFM模式&#xff0c;随着负载降低&#xff0c;…

I2C学习:上拉电阻选取

一&#xff0e;I2C简介 I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。I2C总线在使用时&#xff0c;需要接上拉电阻&#xff0c;这是因为I2C接口是开漏输出&#xff0c;如图1所示。 图1 I2C开漏输出 I2C有5种速度模式&#xff1a;标准&#xff08;100KHz&am…

日志文件的理解

前言 说实在话我一直对于日志不太理解&#xff0c;感觉这词说的这么高大上&#xff0c;不好理解&#xff0c;甚至还有点畏惧这个东西&#xff0c;所以专门去研究了下&#xff0c;最后发现这家伙不就是输出信息嘛&#xff0c;就像C语言中printf输出的信息&#xff0c;C中cout输…

【电子通识】开关上的“|”和“0”到底哪个是开?哪个是关?

有的电器、灯具和插座上带有电源开关&#xff0c;开关上会出现“|”和“O”两个符号。如下所示船型开关上就有“|”和“0”。 也有开关用ON/OFF代表开闭。 如果只看符号判断“|”和“O”到底代表什么含义呢&#xff1f;你又能分清哪个是电路连通&#xff0c;哪个是电路断开…

05.震动控制继电器开关

首先先知道控制器的原理 通过继电器来控制电路&#xff0c;比如智能插座&#xff0c;比如 220V 的灯&#xff0c;比如我们项目不带开关的傻瓜式报警器 当设置继电器为低电平触发时&#xff0c; STC89C52RC 的 IO 输出 低电平&#xff0c;就会导致 COM口和NO口闭合 &#xff0c…

LearnOpenGL——点光源阴影笔记

LearnOpenGL——点光源阴影笔记 点光源阴影一、生成深度立方体贴图1. 创建立方体贴图2. 光空间的变换3. 深度着色器 二、万向阴影贴图三、PCF 点光源阴影 点光阴影&#xff08;也叫万向阴影贴图&#xff08;Omnidirectional Shadow Maps&#xff0c;OSM&#xff09;&#xff0…

【乐吾乐大屏可视化组态编辑器】动画按顺序播放

动画按顺序播放 在线使用&#xff1a;https://v.le5le.com/ 如案例所示&#xff0c;通过连线去串联一组动画图元&#xff0c;动画按照顺序向后执行。 ① 首先给每个图元都配置动画&#xff0c;注意这里的动画播放次数一定要配置有限个&#xff08;这里配置都是1次&#xff0…

AI在医学领域:FEDMEKI平台实现在隐私约束下将医学知识整合到基础模型

基础模型已在众多领域掀起了一场革命性的变革&#xff0c;它们在处理多样化模态和复杂任务方面展现出了卓越的能力。以GPT-3和LLaMA为例&#xff0c;这些模型在众多应用场景中均表现出色。其成功的核心在于接触并学习海量的训练数据&#xff0c;从而深入洞察不同领域。借助这些…

【python与java的区别-04(文件流)】

一、文件和目录的操作 1、IO流&#xff08;Stream&#xff09; 通过“流”的形式允许计算机程序使用相同的方式来访问不同的流入/流出源。Stream是从起源&#xff08;source&#xff09;到接收(sink)的有序数据。我们把输入/输出源对比成“水桶”&#xff0c;那么流就是“管道…

企业给排水乙级资质续期:人才储备与补充计划

企业给排水乙级资质续期过程中&#xff0c;人才储备与补充计划是至关重要的环节。以下是一个详细的人才储备与补充计划&#xff0c;旨在帮助企业顺利应对资质续期挑战&#xff1a; 一、人才储备计划 1. 提前规划与预测 政策分析&#xff1a;密切关注住建部门或相关权威机构发…

VirtualBox和VMware的虚拟机ip配置为同一网段不使用wlan的网卡(vulnhub打靶前期准备)

打靶前期准备工作&#xff0c;virtualbox和VMware之间的网络互通&#xff08;即同一个网段下非wlan网卡的设置&#xff09; 首先在打靶的时候因为vulnhub的靶机都是使用的virtualbox的虚拟机&#xff0c;但是我的kali已经用了很久了一直使用的是VMware&#xff0c;突然转换使用…

面试必刷——二叉树习题/面试题详解

&#xff08;1&#xff09;检查两棵树是否相同 题目链接&#xff1a; . - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems…

品质更进阶 长安马自达MAZDA EZ-6通关中国“热极”

继在中国规格最高的重庆垫江测试场完成驾控试炼后&#xff0c;8月20日-22日&#xff0c;长安马自达MAZDA EZ-6“众测先享官—品质更进阶”在中国“热极”吐鲁番再次拉开帷幕。针对电动车用户最关心的酷暑天气用车痛点场景&#xff0c;由长安马自达工程师团队携手用户代表、权威…

云微客短视频矩阵获客有多容易?低成本获客备受好评

数字化时代&#xff0c;短视频矩阵已经成为企业获客的重要渠道之一&#xff0c;云微客短视频矩阵系统为企业解决在短视频营销中的账号搭建、内容生产、账号运营、低成本引流等难题。 短视频矩阵是一种基于抖音、快手、小红书、视频号等短视频平台&#xff0c;通过批量剪辑、批量…

Linux shell编程学习笔记72:tr命令——集合转换工具

0 前言 在大数据时代&#xff0c;我们要面对大量数据&#xff0c;有时需要对数据进行整理和转换。 在Linux中&#xff0c;我们可以使用 tr命令来整理和转换数据&#xff0c;也可以进行简单的加解密。 1 tr命令 的帮助信息&#xff0c;功能&#xff0c;格式&#xff0c;选项和…