前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >总结一下最近学习的后台管理系统的前端权限设计

总结一下最近学习的后台管理系统的前端权限设计

作者头像
十里青山
发布2022-08-07 10:58:28
6850
发布2022-08-07 10:58:28
举报
文章被收录于专栏:我的前端之路我的前端之路

刚到新公司,领导交代给了一个新项目,就是非常简易的后台管理系统,后端由于是刚毕业的,所以没有用什么已经搭建好的后台管理系统的框架,比如renren-fast啥的,后端都没有用,我自然只能陪他一点点的重新写,刚好我对这一块也不熟,正好用来练练手,学习一下,以下就是我本次开发总结的一点体会,记录一下。本文以思路为主,不会写出全部代码

基础工作

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

菜单表设计

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

字段

含义

备注

title

标题

用于侧边栏标题展示

icon

图标

用于侧边栏图标展示

type

类型

区分目录/菜单/按钮

parentId

父级id

记录父子关系

name

路由name

路由必备

path

地址

地址栏的地址,用于跳转和展示

url

模块路径

模块位于文件夹的路径

identification

授权标识

用于权限判断,常见格式 crm:customer:list

hidden

是否渲染在侧边栏

有一些路由我们需要可以访问,又不想让它出现在侧边栏

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

角色分配

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

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

保存

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

回显

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

代码语言:javascript
复制
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);
  }
});

路由守卫判断

前端做权限,主要靠的就是操作路由,这一块想了好久,事实证明,好记性不如赖笔头,想半天想不明白,写下来一会儿就搞明白了。

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

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

代码语言:javascript
复制
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();
    }
  }
});

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-01-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基础工作
  • 菜单表设计
  • 角色分配
    • 给角色分配菜单时,保存的参数和回显
      • 保存
      • 回显
  • 路由守卫判断
    • 获取用户权限列表及菜单信息
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档