最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 总结一下最近学习的后台管理系统的前端权限设计

    正文概述 掘金(十里青山)   2021-01-06   530

    基础工作

    首先还是后台管理系统的基础工作,登录,侧边栏,导航栏什么的,因为给的时间实在太紧,我就直接用的网上已经有的基础框架 vue-admin-template 的,这些东西也没必要重复写,直接用现成的就好,主要还是总结一下权限相关。

    菜单表设计

    因为 vue-admin-template 框架中,侧边栏是根据路由生成的,所以我们只要用一个菜单表维护路由就行了,不需要单独再搞一个侧边栏管理,为了满足渲染路由所必须的参数,我们需要告诉后端我们都需要什么参数,一般情况下,具有一定开发经验的后端都知道要返回什么参数,但如果对方碰巧没啥经验,我们就要主动提出来了。

    字段含义备注
    title标题用于侧边栏标题展示icon图标用于侧边栏图标展示type类型区分目录/菜单/按钮parentId父级id记录父子关系name路由name路由必备path地址地址栏的地址,用于跳转和展示url模块路径模块位于文件夹的路径identification授权标识用于权限判断,常见格式 crm:customer:listhidden是否渲染在侧边栏有一些路由我们需要可以访问,又不想让它出现在侧边栏parentId父级id记录父子关系

    *以上仅列出我们所必须的字段,像创建时间,创建人,排序等可以与后端协商按需求添加

    角色分配

    菜单表搞好之后,我们就可以开始开发角色列表,角色列表无非就是增删查改,这里仅记录自己碰到的几个小知识点。

    给角色分配菜单时,保存的参数和回显

    保存

    大部分后台管理系统都是用的element-ui,而菜单展示一般会用element的el-tree组件,因为渲染路由的时候,需要有父子结构,我这里保存的时候会把选中的节点this.$refs.menuListTree.getCheckedKeys()和半选中的节点this.$refs.menuListTree.getHalfCheckedKeys()都保存下来

    回显

    因为保存的时候半选中的节点也给保存了下来,回显的时候如果给半选中的节点选中,它的子节点也会全部选中,如果要解决这个问题,我们只需要判断该节点是否是子节点就可以了

    let menuId = res.data.menuId // 后端返回的id字符串 '1,3,4,5,8,9'
    let _arr = menuId.split(",").map(item => {
      return +item; // 用加号是因为字符串分割的数组每一项都是字符串,需要转成数字
    });
    _arr.map(item => {
      //获取该id对应的tree节点
      let node = this.$refs.menuListTree.getNode(item);
      //判断该节点是否是子节点(即该节点是否是末级节点),是的话就设置选中状态
      if (node.isLeaf) {
        this.$refs.menuListTree.setChecked(node, true);
      }
    });
    

    路由守卫判断

    前端做权限,主要靠的就是操作路由,这一块想了好久,事实证明,好记性不如赖笔头,想半天想不明白,写下来一会儿就搞明白了。总结一下最近学习的后台管理系统的前端权限设计

    获取用户权限列表及菜单信息

    这里贴上我的代码,里面注释了一些遇到的小难点

    router.beforeEach(async (to, from, next) => {
      // vue-admin-template自带的进度条
      NProgress.start();
    
      // 设置浏览器标签标题
      document.title = getPageTitle(to.meta.title);
    
      // 获取token
      const hasToken = getToken();
    
      if (hasToken) {
        if (to.path === "/login") {
          // 如果已经登录,重定向至首页
          next({ path: "/" });
          NProgress.done();
        } else {
          const hasGetUserInfo = store.getters.name;
          if (!hasGetUserInfo) {
            try {
              // 如果没有用户信息则获取用户信息
              await store.dispatch("user/getInfo");
            } catch (error) {
              // 获取用户信息失败则清除token并跳转至首页
              await store.dispatch("user/resetToken");
              Message.error(error || "获取用户信息失败");
              next(`/login?redirect=${to.path}`);
              NProgress.done();
            }
          }
    	  // 判断是否已经加载路由或者是否要访问白名单内的页面
          if (
            router.options.isAddDynamicMenuRoutes ||
            whiteList.indexOf(to.path) !== -1
          ) {
            next();
          } else {
            // 获取用户权限信息及菜单列表
            menuApi
              .getListById({ id: store.getters.userId })
              .then(res => {
                console.log(res);
                let menuList = res.data.menuList;
                let permissions = res.data.permission;
                // 我这里是后端返回所有的菜单,然后前端根据权限筛选出有权限的菜单
                // 筛选出有权限的路由或者是目录
                menuList = menuList.filter(item => {
                  return (
                    permissions.indexOf(item.identifying) > -1 ||
                    item.parentId === 0
                  );
                });
                // 将数据转化成路由结构
                menuList.map(item => {
                  if (item.parentId === 0) {
                    item.component = Layout;
                  } else {
                    item.component = _import(item.url);
                  }
                  item.meta = {
                    title: item.title,
                    icon: item.icon
                  };
                });
                // 将路由转换成父子结构
                menuList = treeDataTranslate(menuList);
                console.log(menuList);
                menuList = menuList.filter(item => {
                  return item.children;
                });
                // 在添加完动态路由之后再添加404路由,以防止页面在匹配动态路由之前先匹配404
                menuList.push({ path: "*", redirect: "/404", hidden: true });
                router.options.isAddDynamicMenuRoutes = true;
                router.addRoutes(menuList);
                // this.$router不是响应式的,所以手动将路由元注入路由对象
                router.options.routes.push(...menuList);
                // 下面这个我也不知道为什么要加,但是我知道不加刷新就会404?
                if (from.name == null) {
                  next(to);
                } else {
                  next();
                }
              })
              .catch(err => {
                console.log(err);
                next(`/login?redirect=${to.path}`);
              });
          }
        }
      } else {
        /* has no token*/
    
        if (whiteList.indexOf(to.path) !== -1) {
          // in the free login whitelist, go directly
          next();
        } else {
          // other pages that do not have permission to access are redirected to the login page.
          next(`/login?redirect=${to.path}`);
          NProgress.done();
        }
      }
    });
    

    才疏学浅,请各位大神多多指教,如果有哪里写的不好或者不详细的,请评论区留言


    起源地下载网 » 总结一下最近学习的后台管理系统的前端权限设计

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元