自己记录,一个简单的权限限制主要是记录数组比

文章展示了使用Vue3和ElementPlus组件库构建的权限管理页面,包括角色列表、筛选、添加、编辑和删除功能。重点在于如何处理权限配置,通过递归方法比对一维数组和树形结构数据,确保选中的权限在路由中有效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ps:这个功能做的很简单 后端只做数据存储不做其他操作,没什么好借鉴地,只是第二步数组进行比较那个我觉得还可以所以就发出来了。

1、勾选权限(整理麻烦 直接提的页面全部代码 vue3+elementplus)

<template>
    <div class="page-container">
        <!-- 如果页面有头部(page-header),需要添加with-header样式 -->
        <div class="page-layer with-header">
            <div class="page-header">
                <div class="left">
                    <crumbs></crumbs>
                </div>
                <!-- <div class="right">
                    申请企业总数: <span class="num">18</span>
                </div> -->
            </div>
            <div class="common-page page-table">
                <section class="common-list-operate">
                    <section class="query">
                        <el-form :inline="true" :label-width="0" @submit.native.prevent>
                            <el-form-item>
                                <el-input v-model="queryParams.name" style="width: 200px;" placeholder="角色名称">
                                    <template #append>
                                        <el-button icon="Search" @click="handleFilterSubmit()" />
                                    </template>
                                </el-input>
                            </el-form-item>
                        </el-form>
                        <div class="buttons">
                            <el-button class="reset" type="default" icon="RefreshLeft" @click="handleFilterReset()"></el-button>
                        </div>
                    </section>
                    <section class="action">
                        <el-button @click="handleAdd()" type="primary">
                            <el-icon>
                                <Plus />
                            </el-icon>&nbsp;添加角色
                        </el-button>
                        <!-- <el-button @click="showMessage()" :class="{'multi-delete':(selectRows && selectRows.length)}" :type="(selectRows && selectRows.length)?'danger':'info'" :disabled="!selectRows || !selectRows.length">批量删除<span class="count" v-if="selectRows && selectRows.length">{{selectRows.length}}</span></el-button> -->
                    </section>
                </section>

                <section class="table-outer">
                    <div class="table-contain">
                        <el-table ref="dataTable" :data="tableData.listData" stripe height="calc(100% - 45px)">
                            <el-table-column prop="index" label="序号" width="60" align="center">
                                <template #default="scope">
                                    <span>{{ pageSort(queryParams.page,queryParams.size,scope.$index)}}</span>
                                </template>
                            </el-table-column>
                            <el-table-column prop="name" label="角色名称" align="center"></el-table-column>
                            <el-table-column prop="personCount" label="关联人数" align="center"></el-table-column>
                            <el-table-column prop="status" label="状态" align="center">
                                <template #default="scope">
                                    <el-tag style="width: 80px;" :type="scope.row.status?'success':'info'">{{(scope.row.status?'启用':'禁用')}}</el-tag>
                                </template>
                            </el-table-column>
                            <el-table-column prop="remark" label="角色描述" align="center"></el-table-column>
                            <el-table-column prop="createdAt" label="创建时间" align="center"></el-table-column>
                            <el-table-column label="操作" width="200" align="center">
                                <template #default="scope">
                                    <a @click="handleDetail(scope.row)" class="operation detail">查看</a>
                                    <a @click="handleEdit(scope.row)" class="operation detail">编辑</a>
                                    <a @click="handleDel(scope.row)" class="operation delete">删除</a>
                                </template>
                            </el-table-column>
                        </el-table>
                        <div class="pages">
                            <el-pagination v-if="tableData.total>1" :page-sizes="[10, 20, 30, 50]" :small="small" :disabled="disabled" :background="background" layout="total, sizes, prev, pager, next, jumper" :total="tableData.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
                            <span v-else class="no-more">已无更多信息</span>
                        </div>
                    </div>
                </section>
            </div>
        </div>
        <el-dialog class="common-dialog" :title="state.operationType=='add'?'添加':'修改'" v-model="state.dialogVisible.add" width="600px" append-to-body align-center destroy-on-close :close-on-click-modal='false'>
            <div class="form-group">
                <div class="commom-form">
                    <el-form ref="FormDataref" @submit.native.prevent   :model="state.formData" label-width="100px" label-position="left">
                        <el-row :gutter="20">
                            <el-col :span="24">
                                <el-form-item prop="name" label="角色名称" :rules="state.rules.name" class="is-required">
                                    <el-input v-model="state.formData.name" clearable placeholder="请输入"></el-input>
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row :gutter="20">
                            <el-col :span="24">
                                <el-form-item prop="permission" label="菜单配置权限" :rules="state.rules.permission" class="is-required">
                                    <el-tree show-checkbox ref="routerTree" :data="mainRoutes" node-key="name" highlight-current :props="TreedefaultProps" />
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row :gutter="20">
                            <el-col :span="24">
                                <el-form-item label="角色描述">
                                    <el-input v-model="state.formData.remark" :rows="3" type="textarea" resize="none" placeholder="请输入" />
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-row :gutter="20">
                            <el-col :span="24">
                                <el-form-item prop="status" :rules="state.rules.status" class="is-required" label="状态">
                                    <el-radio-group v-model="state.formData.status">
                                        <el-radio :label="true">启用</el-radio>
                                        <el-radio :label="false">禁用</el-radio>
                                    </el-radio-group>
                                </el-form-item>
                            </el-col>
                        </el-row>
                    </el-form>
                    <section class="float-buttons" style="bottom:15px">
                        <el-button @click="handleFormSubmit()" type="primary">保存</el-button>
                        <el-button @click="handleFormReset()">返回</el-button>
                    </section>
                </div>
            </div>
        </el-dialog>
        <el-dialog class="common-dialog my-dialog" title="查看" v-model="state.dialogVisible.detail" width="600px" append-to-body align-center destroy-on-close>
            <div class="outer-detail">
                <section class="detail-group">
                    <el-descriptions class="margin-top" :column="1" border>
                        <el-descriptions-item label="角色名称" span="1">
                            {{state.info.name}}
                        </el-descriptions-item>
                        <el-descriptions-item label="角色描述" span="1">
                            {{state.info.remark}}
                        </el-descriptions-item>
                        <el-descriptions-item label="角色描述" span="1">
                            {{state.info.remark}}
                        </el-descriptions-item>
                        <el-descriptions-item label="角色权限" span="1">
                            <div class="content-box">
                                <el-tree show-checkbox ref="detailTree" :data="detailTree" :default-checked-keys="state.info.permission" node-key="name" highlight-current :props="TreedefaultProps" />
                            </div>
                        </el-descriptions-item>
                        <el-descriptions-item label="状态" span="1">
                            <el-tag style="width: 80px;" :type="state.info.status?'success':'info'">{{(state.info.status?'启用':'禁用')}}</el-tag>
                        </el-descriptions-item>
                    </el-descriptions>
                </section>
                <section class="float-buttons" style="bottom:15px;margin:15px 0;">
                    <el-button @click="handledetailDown()">返回</el-button>
                </section>
            </div>
        </el-dialog>
    </div>

</template>
<script setup>
    import { ref, reactive, computed, getCurrentInstance, watch, onBeforeMount, onMounted, nextTick } from 'vue';
    import { useRouter } from 'vue-router';
    import crumbs from '@/components/crumbs/crumbs.vue'

    const { proxy } = getCurrentInstance();
    const router = useRouter();
    const validation = proxy.validation;
    //筛选器参数
    let queryParams = ref({
        page: 1,
        size: 10,
    })
    //列表数据
    let tableData = ref({
        listData: [],
    })
    const state = reactive({
        roleList: [],
        operationType: 'add',
        dialogVisible: {
            add: false,
            detail: false,
        },
        formData: {
            status: null,
        },
        rules: {
            name: [
                { required: true, message: '请输入', trigger: ['blur', 'change'] },
                { validator: validation, check: ['empty', 'blank'] }
            ],
            permission: [
                { required: true, message: '请输入', trigger: ['blur', 'change'] },
                { validator: validation, check: ['empty', 'blank', ] }
            ],
            status: [
                { required: true, message: '请选择', trigger: ['blur', 'change'] },
            ],
        }
    })
    const FormDataref = ref()
    // 权限----------------------
    const mainRoutes = ref([])
    const detailTree = ref([])
    const routerTree = ref({})
    const TreedefaultProps = {
        children: 'children',
        label: 'title',
        value: 'name'
    }

    //页面生命周期:挂载前
    onBeforeMount(async () => {
        await getRouteList()
        getListData()
    })

    const getRouteList = async () => {
        let data = router.options.routes.find(main => main.name == 'main-frame');
        let digui = (arr) => {
            let myData = [];
            for (let i of arr) {
                i.title = i.meta.title;
                if (i.meta.showOnNav) {
                    if (i.children) {
                        i.children = digui(i.children)
                    }
                    myData.push(i)

                }
            }
            return myData;
        }
        if (data && data.children) {
            mainRoutes.value = digui(data.children);
        }
    }

    //筛选器:重置
    function handleFilterReset() {
        queryParams.value = {
            page: 1,
            size: 10,
        }
        getListData()
    }

    //筛选器:提交
    function handleFilterSubmit() {
        queryParams.value.page = 1;
        getListData()
    }
    //获取列表数据
    function getListData() {
        let params = {
            name: queryParams.value.name,
            page: queryParams.value.page,
            size: queryParams.value.size
        }
        proxy.api.apiTenantSysRoleSelectPage(params).then((res) => {
            if (res.success) {
                tableData.value = {
                    page: queryParams.value.page,
                    total: res.pagination.total,
                    listData: res.list
                }
            }
        })
    }

    function handleEdit(val) {
        state.operationType = 'edit';
        state.dialogVisible.add = true;
        // 注意代码异步问题 弹框dom还没渲染 下面数据结构就组装完成了 递归就会报错
        nextTick(() => {
            state.formData = JSON.parse(JSON.stringify(val))
            let data = JSON.parse(JSON.stringify(val))
            data.permission = JSON.parse(data.permission);
            let digui = (arr, val) => {
                let result = [];
                for (let i of arr) {
                    if (i.children && i.children.length != 0) {
                        digui(i.children, val);
                    } else {
                        if (i.name == val) {
                            proxy.$refs.routerTree.setChecked(i, true, false)
                        }
                    }
                }
                return result
            }
            for (let i of data.permission) {
                digui(mainRoutes.value, i)
            }
        })
    }

    function handleAdd() {
        state.operationType = 'add';
        state.dialogVisible.add = true;
        state.formData = {
            status: null,
        };
    }

    function handleFormSubmit() {
        let son = routerTree.value.getCheckedNodes();
        let fa = routerTree.value.getHalfCheckedKeys();
        let digui = (arr) => {
            let result = [];
            for (let i of arr) {
                result.push(i.name);
                if (i.children) {
                    digui(i.children)
                }
            }
            return result
        }
        let data = digui(son)
        if (fa && fa.length != 0) {
            fa.map(i=>{
                data.push(i)
            })
        }
        state.formData.permission = JSON.stringify(data);
        FormDataref.value.validate((valid, fields) => {
            if (valid) {
                let params = JSON.parse(JSON.stringify(state.formData));
                if (state.operationType == 'add') {
                    proxy.api.apiTenantSysRoleSaveSysRole(params).then((res) => {
                        if (res.success) {
                            proxy.openNotify('success', '操作成功', `操作保存成功`);
                            state.dialogVisible.add = false;
                            state.formData = {};
                            getListData()
                        }
                    })
                } else {
                    proxy.api.apiTenantSysRoleUpdateSysRole(params).then((res) => {
                        if (res.success) {
                            proxy.openNotify('success', '操作成功', `操作保存成功`);
                            state.dialogVisible.add = false;
                            state.formData = {};
                            getListData()
                        }
                    })
                }
            } else {

            }
        })
    }

    function handleFormReset() {
        state.dialogVisible.add = false;
        state.formData = {};

    }

    function handleDetail(val) {
     
        state.info = JSON.parse(JSON.stringify(val))
        let data = JSON.parse(JSON.stringify(val));
        let copyTree = JSON.parse(JSON.stringify(mainRoutes.value))
        let digui = (arr) => {
            let copydata = [];
            for (let i of arr) {
                i.disabled = true;
                if (i.children) {
                    i.children = digui(i.children)
                }
                copydata.push(i);
            }
            return copydata
        }
        detailTree.value = digui(copyTree)
        state.info.permission = JSON.parse(data.permission);
        state.dialogVisible.detail = true;
    }

    function handledetailDown() {
        state.dialogVisible.detail = false;
        state.info = {};
    }

    function handleDel(val) {
        proxy.$confirm('', {
            dangerouslyUseHTMLString: true,
            customClass: 'flash',
            message: `<h2>操作确认</h2><span>该操作不可逆,是否确认删除?</span>`,
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            showClose: false,
            type: 'warning',
        }).then(() => {
            proxy.api.apiTenantSysRoleDelete({ ids: [val.id] }).then((res) => {
                if (res.success) {
                    proxy.openNotify('success', '操作成功', `数据删除成功`);
                    getListData()
                }
            })
        }).catch(() => {});
    }

    function handleSizeChange(val) {
        queryParams.value.size = val;
        queryParams.value.page = 1;
        getListData();
    }

    function handleCurrentChange(val) {
        queryParams.value.page = val;
        getListData();
    }
</script>

<style lang='less' scoped>
.float-buttons{
    width: 100%;
    text-align: center;
}
.content-box{
    height: 200px; .scrollbar();
}
</style> 

2、写完的时候后端还没出接口就自己先的弄的demo 根据选中的一维数组去和路由进行比较找到存在的路由,有子级就必有父级,有父级不一定会有所有子级。
我的错误思路:一直想的是循环a数组在循环里面去调递归方法进行比较每次都是循环多少数组里面就有几个值,没拿到想要的,卡了2天。
然后终于第三天想通了,直接递归数组b然后直接每一层对象去对比是否存在在数组a里面,然后5分钟就写出来了 哈哈!!!!!!!

let a=['boss','demo','test','data','k','lisi'];
let b =[{name:'boss',children:[{name:'demo',children:[{name:'测试'},{name:'k'}]}]},{name:'test',children:[{name:'lisi'},{name:'wusi',children:[{name:'crr'}]}]},{name:'data'}];
    let  c=[];
    let digui=function(arr){
    //存当前的值用来返给上级。
      let returnData=[];
      for(let i of arr){
        if(a.some(name=>i.name==name)){
          let current=i;
          if(i.children){
            current.children=digui(i.children)
          }
          returnData.push(current)
        }
      }
      return returnData
    } 
     c=digui(b)
     console.log(c)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值