• vue+element后台菜单权限动态配置


    1、说明

    后台权限列表用的是element的table组件(https://element.eleme.cn/#/zh-CN/component/table
    在这里插入图片描述

    2、后端返回的菜单权限数据

    let data = [
        {
            "id": "1580804966837141505",
            "parentId": "0",
            "seq": 0,
            "children": [
                {
                    "id": "1580805570087108610",
                    "parentId": "1580804966837141505",
                    "seq": 0,
                    "name": "用户管理",
                    "spread": false,
                    "path": "index",
                    "keepAlive": "0",
                    "menuType": "0",
                    "label": "用户管理",
                    "createdAt": "2022-10-14 14:19:50",
                    "updatedAt": "2022-11-07 14:22:34"
                },
                {
                    "id": "1580805641843261441",
                    "parentId": "1580804966837141505",
                    "seq": 1,
                    "name": "积分记录",
                    "spread": false,
                    "path": "points",
                    "keepAlive": "0",
                    "menuType": "0",
                    "label": "积分记录",
                    "createdAt": "2022-10-14 14:20:07",
                    "updatedAt": "2022-11-07 14:22:39"
                }
            ],
            "name": "用户管理",
            "spread": false,
            "path": "user",
            "keepAlive": "0",
            "menuType": "0",
            "label": "用户管理",
            "createdAt": "2022-10-14 14:17:27",
            "updatedAt": "2022-10-14 14:17:27"
        },
        {
            "id": "1580805083585593346",
            "parentId": "0",
            "seq": 1,
            "children": [
                {
                    "id": "1580805723388919810",
                    "parentId": "1580805083585593346",
                    "seq": 1,
                    "name": "供应商管理",
                    "spread": false,
                    "path": "supplier",
                    "keepAlive": "0",
                    "menuType": "0",
                    "label": "供应商管理",
                    "createdAt": "2022-10-14 14:20:27",
                    "updatedAt": "2022-11-07 14:22:45"
                },
                {
                    "id": "1580805784856444930",
                    "parentId": "1580805083585593346",
                    "seq": 2,
                    "name": "商品分类管理",
                    "spread": false,
                    "path": "category",
                    "keepAlive": "0",
                    "menuType": "0",
                    "label": "商品分类管理",
                    "createdAt": "2022-10-14 14:20:42",
                    "updatedAt": "2022-11-07 14:22:54"
                },
                {
                    "id": "1580805854662246401",
                    "parentId": "1580805083585593346",
                    "seq": 3,
                    "name": "商品管理",
                    "spread": false,
                    "path": "goods",
                    "keepAlive": "0",
                    "menuType": "0",
                    "label": "商品管理",
                    "createdAt": "2022-10-14 14:20:58",
                    "updatedAt": "2022-11-07 14:23:01"
                }
            ],
            "name": "供应商管理",
            "spread": false,
            "path": "supplier",
            "keepAlive": "0",
            "menuType": "0",
            "label": "供应商管理",
            "createdAt": "2022-10-14 14:17:54",
            "updatedAt": "2022-10-14 14:17:54"
        },
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    3、router/index.js

    router / index.js
    静态配置页面路由是在这个js里配置的,首页是没有权限的也可以访问

    import Vue from "vue";
    import Router from "vue-router";
    Vue.use(Router);
    
    import Layout from "@/layout";
    
    export const constantRoutes = [
      {
        path: "/login",
        component: () => import("@/views/login/index"),
        hidden: true,
      },
      {
        path: "/404",
        component: () => import("@/views/404"),
        hidden: true,
      },
      {
        path: "/",
        component: Layout,
        redirect: "/",
        meta: { title: "首页", icon: "el-icon-s-home" },
        children: [
          {
            path: "/",
            name: "/",
            component: () => import("@/views/index/index"),
            meta: { title: "首页", icon: "el-icon-s-home" },
          },
        ],
      },
    ];
    const createRouter = () =>
      new Router({
        mode: "history", // require service support
        scrollBehavior: () => ({ y: 0 }),
        routes: constantRoutes,
      });
    
    const router = createRouter();
    
    export function resetRouter() {
      const newRouter = createRouter();
      router.matcher = newRouter.matcher; // reset router
    }
    
    export default router;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    4、store/getters.js

    store/getters.js

    const getters = {
    	...//其他内容
    	addRouters_: state => state.permission.addRouters,
    	permissionList: state => state.user.permissionList
    };
    export default getters;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5、store/modules/user.js

    store/modules/user.js

    import { constantRoutes } from "@/router";
    import { getUserMenu } from "@/api/auth";//获取登录账号的菜单权限
    import Layout from "@/layout";
    import router from "@/router";
    
    const getDefaultState = () => {
      return {
        //当前用户能够访问的路由对象
        routes: [],
    	permissionList:[]
      };
    };
    
    const state = getDefaultState();
    
    function lazyComponent(item,i){
    	let url = `@/views/${item.path}/${i.path}`
    	let obj = {
    		path: i.path,
    		name: `${item.path}/${i.path}`,
    		component: (resolve) => require([`@/views/${item.path}/${i.path}`], resolve),
    		meta: { title: i.name, icon: "el-icon-s-grid" },
    	}
    	return obj
    }
    
    const mutations = {
    	RESET_STATE: (state) => {
    	  Object.assign(state, getDefaultState());
    	},
    	//过滤之后的路由对象
    	SET_ROUTES: (state, routes) => {
    	  state.routes = routes;
    	},
    	SET_PERMISSIONLIST: (state, permissionList) => {
    	  state.permissionList = constantRoutes.concat(permissionList)
    	},
    };
    
    const actions = {
      	...
    	// 获取用户菜单信息
    	GetPermissionList({ commit }){
    		return new Promise((resolve, reject)=>{
    			getUserMenu().then(response=>{
    				let menuData = response.data
    				let arr = []
    				menuData.forEach((item,index)=>{
    					if(item.children){
    						let obj = {
    							path: '/' + item.path,
    							component: Layout,
    							redirect: '/' + item.path,
    							name:item.path,
    							meta: { title: item.name, icon: "el-icon-s-grid" },
    							children:[]
    						}
    						item.children.forEach((i,k)=>{
    							let a = lazyComponent(item,i)
    							obj.children.push(a)
    						})
    						commit('SET_PERMISSIONLIST', arr)
    						commit("SET_ROUTES", arr);
    						arr.push(obj)
    					}
    				})
    				resolve(arr)
    			}).catch(error => {
    				reject(error)
    			})
    		})
    	},
    };
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions,
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    6、src/permission.js

    src/permission.js

    // 最外层
    import router from "./router";
    import store from "./store";
    import { Message } from "element-ui";
    import NProgress from "nprogress"; // progress bar
    import "nprogress/nprogress.css"; // progress bar style
    import { getToken } from "@/utils/auth"; // get token from cookie
    import getPageTitle from "@/utils/get-page-title";
    import { getUserMenu } from "@/api/auth.js";
    import { generateIndexRouter } from '@/utils/util'
    NProgress.configure({ showSpinner: false }); // NProgress Configuration
    
    const whiteList = ["/login"]; // no redirect whitelist
    
    router.beforeEach(async (to, from, next) => {
      NProgress.start();
      document.title = getPageTitle(to.meta.title);
      const hasToken = getToken();
    
      if (hasToken) {
        if (to.path === "/login") {
          next({ path: "/" });
          NProgress.done();
        } else {
        	//重点代码 重点代码 重点代码
          if(store.getters.permissionList.length === 0){
    				store.dispatch('user/GetPermissionList').then(res=>{
    					router.addRoutes(store.getters.permissionList)
    					const redirect = decodeURIComponent(from.query.redirect || to.path)
    					if (to.path === redirect) {
    					  next({ ...to, replace: true })
    					} else {
    					  // 跳转到目的路由
    					  next({ path: redirect })
    					}
    				})
    			}else{
    				next()
    			}
    			//重点代码 重点代码 重点代码 到此结束
        }
      } else {
        if (whiteList.indexOf(to.path) !== -1) {
          next();
        } else {
          next(`/login`);
          NProgress.done();
        }
      }
    });
    
    router.afterEach(() => {
      // finish progress bar
      NProgress.done();
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    7、layout/components/Sidebar/index.vue

    layout/components/Sidebar/index.vue

    <template>
      <div :class="{ 'has-logo': showLogo }">
        <logo v-if="showLogo" :collapse="isCollapse" />
        <el-scrollbar wrap-class="scrollbar-wrapper">
          <el-menu
            :default-active="activeMenu"
            :collapse="isCollapse"
            :background-color="variables.menuBg"
            :text-color="variables.menuText"
            :unique-opened="false"
            :active-text-color="variables.menuActiveText"
            :collapse-transition="false"
            mode="vertical"
          >
            <sidebar-item
              v-for="route in routes"
              :key="route.path"
              :item="route"
              :base-path="route.path"
            />
          </el-menu>
        </el-scrollbar>
      </div>
    </template>
    
    <script>
    import { mapGetters, mapState } from "vuex";
    import Logo from "./Logo";
    import SidebarItem from "./SidebarItem";
    import variables from "@/styles/variables.scss";
    
    export default {
      components: { SidebarItem, Logo },
      computed: {
        ...mapGetters([
          "sidebar",
          // 'routes'
        ]),
        // 获取筛选过后的路由对象
        routes() {
    		return this.$store.state.user.permissionList;//重点这个,获取处理好的路由,展示在左侧菜单里
        },
        activeMenu() {
          const route = this.$route;
          const { meta, path } = route;
          // if set path, the sidebar will highlight the path you set
          if (meta.activeMenu) {
            return meta.activeMenu;
          }
          return path;
        },
        showLogo() {
          return this.$store.state.settings.sidebarLogo;
        },
        variables() {
          return variables;
        },
        isCollapse() {
          return !this.sidebar.opened;
        },
      },
      mounted() {
        // console.log(this.routes);
      },
    };
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    8、在过程中出现的一些问题

    1、src/permission.js不加store.getters.permissionList.length === 0判断的话,会一直死循环下面的操作(就是一直请求接口),加判断第二次执行就会到else里
    2、store/modules/user.js里,因为我后端有可能返回只有一级菜单,没添加二级菜单即item没有children这个字段,不加item.children判断,就会一直提示
    下面的问题在这里插入图片描述
    3、store/modules/user.js里,之前用的是component: () => import(url),虽然没报错,但是点击左侧菜单一直没反应,后面查了下,说是不能用import,后来改成component: (resolve) => require([@/views/${item.path}/${i.path}], resolve)

    ps:layout/components/Sidebar/index.vue左侧菜单组件,这个看每个人项目用的组件吧

  • 相关阅读:
    C 长度为0 的数组
    目标检测论文解读复现之九:基于改进YOLOv5的复杂场景下SAR图像船舶检测方法
    10月份stable diffusion animatediff等插件使用指南,又来更新了
    华为 2022_09_07 笔试题复盘
    Java中@Data注解的作用
    Waline评论服务docker自部署手册 + 无需备案域名配置
    【基础IO⑨】:重定向实现原理 &&“Linux下一切皆文件“
    Lazada店铺如何产号高效补单?(测评自养号技术详解篇)
    【电力系统】含电热联合系统的微电网运行优化附matlab代码和复现论文
    Jenkins :添加node权限获取凭据、执行命令
  • 原文地址:https://blog.csdn.net/qq_32707555/article/details/127733245