vue路由权限(2)

路由权限

1、先登录后 将用户的 uid 传给 后端,请求后端api接口 得到路由权限的列表;
2、后端 给到用户对应的路由权限列表 返回给前端;
3、数据是 json 格式 ,树形结构化路由列表,id对应的pid值 放到对应的children中 ,如下:
4、树形结构化数据 —— vue路由结构;
5、将路由的结构动态 添加到 静态路由中;
6、树形结构化的数据 —— 菜单组件;

  let json = [
      {
        id: 2,
        pid: '',
        path: '',
        name: '',
        link: '',
        title: ''
      },
      {
        id: 3,
        pid: '',
        path: '',
        name: '',
        link: '',
        title: ''
      },
      {
        id: 1,
        pid: 3, // 代表是 parentId 说明这个路由是id 为3 子路由
        path: '',
        name: '',
        link: '',
        title: ''
      }
    ]

有一种写法:先把路由写好,然后放到路由表中作为变量,然后从后端请求回来数据,然后对比静态的表,删减合并到原本的路由中去。注意:实际这种做法不正确;

应该写法:从后端表里面取出来,然后在前端形成树形,然后转为路由,这种做法较正确;

koa搭建后端

以koa为后端开始编写路有权限需要的路由等数据

部分 koa 代码请看博客 使用koa-generator快速搭建 Koa项目
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
得到返回的如下路由数据

在这里插入图片描述
转为树形结构的数据如下:

// 格式化树形结构
function formateRouterTree(data) {
    let parents = data.filter(p => p.pid === 0),
        children = data.filter(c => c.pid !== 0);
        
    dataToTree(parents, children)

    function dataToTree(parents, children) {
        parents.map(p => {
            children.map((c, i) => {
                if (c.pid === p.id) {
                    let _c = JSON.parse(JSON.stringify(children))
                    _c.splice(i, 1);
                    dataToTree([c], _c)
                    if (p.children) {
                        p.children.push(c)
                    } else {
                        p.children = [c]
                    }
                }
            })
        })
    }
    return parents
}

// 转为vue 路由格式
function generateRouter(userRouters){
  let newRouters = userRouters.map(r => {
    let routes = {
      path:r.path,
      name:r.name,
      component:() => import(`@/views/${r.name}`)
    }
    if(r.children){
      routes.children = generateRouter(r.children)
    }
    return routes
  })
  return newRouters
}

export {
  formateRouterTree,
  generateRouter
} 


对数据的处理和路由的处理

数据的处理

在store中新建state.js、mutations.js、actions.js;

state.js

export default {
  // 注意 uid 是请求
  uid:3,
  hasAuth:false,
  userRouters:[],
}

mutations.js

export default {
  setAuth(state,auth){
    state.hasAuth = auth
  },
  setUserRouters(state,userRouters){
    state.userRouters = userRouters
  }
}

actions.js

import { getUserRouters } from '@/server4';
import {formateRouterTree,generateRouter} from '@/utils'

export default {
  async setUserRouters({commit,state}){
    const userRouters = await getUserRouters(state.uid),
    payload = formateRouterTree(userRouters);
    // console.log(userRouters);
    // console.log(payload);
    // console.log(generateRouter(payload));
    commit('setUserRouters',payload)
    commit('setAuth',true)
  }
}

路由处理

main.js 中添加路由拦截

import {generateRouter} from '@/utils';
router.beforeEach(async (to, form, next)=>{
  if(!store.state.hasAuth){
    await store.dispatch('setUserRouters')
    const newRouters = generateRouter(store.state.userRouters)
    router.addRoutes(newRouters)
    next({path:to.path})
  }else{
    next()
  }
})

router里面的index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'

Vue.use(VueRouter)

const router = new VueRouter({
  mode: 'hash',
  // base: process.env.BASE_URL,
  routes,
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition;
    } else {
      return {
        x: 0,
        y: 0
      };
    }
  }
})
router.beforeEach((to, from, next) => {
  next();
});

router.afterEach((to, from, next) => {
  window.scrollTo(0, 0);
});


const VueRouterPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(to) {
  return VueRouterPush.call(this, to).catch(err => err)
}

export default router

routes.js

// function load(component) {
//     return resolve => require([`../views/${component}/${component}`], resolve)
// }

const routes = [
    {
        path: '/',
        component: resolve => require(['@/views/myhome.vue'], resolve),
    },
    {
        path: '/home',
        name: 'home',
        component: resolve => require(['@/views/myhome.vue'], resolve),
        meta: {
            title: '首页'
        },
    {
        path: '*',
        name:'NotFound',
        component:()=>import ('@/views/NotFound.vue'),
    }
];
export default routes;

src中views文件里面的部分代码

MHeader.vue

<template>
  <div class="header-container">头部</div>
</template>
<script>
export default {
  name: "MHeader",
  data() {
    return {};
  },
  created() {},
  computed: {},
  methods: {},
};
</script>
<style lang="scss" scoped>
.header-container {
  width: 100%;
  height: 60px;
  position: fixed;
  top: 0;
  left: 0;
  background: #000;
  color: #fff;
  z-index: 2;
}
</style>

PageBoard.vue

<template>
  <div class="page-board">
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: "PageBoard",
  data() {
    return {};
  },
  created() {},
  computed: {},
  methods: {},
};
</script>
<style lang="scss" scoped>
.page-board {
  width: 100%;
  height: 100%;
  padding: 90px 30px 30px 230px;
  background: cadetblue;
}
</style>

SildBar.vue

<template>
  <div class="side-bar">
    <ul>
      <li>
        <router-link to="/">首页</router-link>
      </li>
    </ul>
    <template v-for="(item, index) in $store.state.userRouters">
      <MenuItem :key="index" :item="item" />
    </template>
  </div>
</template>
<script>
import MenuItem from "@/components/MenuItem";
export default {
  name: "SildBar",
  components: {
    MenuItem,
  },
  data() {
    return {};
  },
  created() {},
  computed: {},
  methods: {},
};
</script>
<style lang="scss" scoped>
.side-bar {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1;
  width: 200px;
  height: 100%;
  padding-top: 60px;
  box-sizing: border-box;
  background: #ccc;
}
</style>

MenuItem.vue

<template>
  <div>
    <ul v-if="item.children && item.children.length > 0">
      <li>
        <router-link :to="item.link || item.path">{{ item.title }}</router-link>
        <template v-for="(c, i) in item.children">
          <MenuItem :key="i" :item="c" />
        </template>
      </li>
    </ul>
    <ul v-else>
      <li>
        <router-link :to="item.link || item.path">{{ item.title }}</router-link>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "MenuItem",
  props: {
    item: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  data() {
    return {};
  },
  created() {},
  computed: {},
  methods: {},
};
</script>

<style lang="scss" scoped>
</style>

后端的权限列表和前端的路由表匹配的另一中写法

注意:前端路由表不是一开始就加到路由中的,而是与后端返回的数据匹配到最后有权限的才加到路由中;

	/**
     * 参数解析:
     * route: 前端写好的路由表中的每一项
     * menuList:权限列表 后端根据用户角色生成的权限列表 
     * 其中menuLis中的code是后端固定写死数据,而route中的name是是路由表中的,要与后端的code匹配是否有权限展示当前路由信息
    */
    function hasPermission(route, menuList) {
      const seq = menuList.findIndex(menu => menu.code === route.name)
      if (seq >= 0) {
        route.seq = seq
        return true
      }
      return false
    }

    /**
     * 参数解析:
     * asyncRoutes:动态路由 前端写好的路由表
     * menuList:权限列表 后端根据用户角色生成的权限列表
    */
    function filterAsyncRoutes(asyncRoutes, menuList) {
      let res = []
      asyncRoutes.forEach((route) => {
        if (route.name && hasPermission(route, menuList)) {
          let curRoute = {
            ...route,
            children: []
          }
          if (route.children && route.children.length) {
            curRoute.children = filterAsyncRoutes(route.children, menuList)
          } else {
            delete curRoute.children
          }
          res.push(curRoute)
        }
      })
      return res.sort((a, b) => a.seq - b.seq)
    }


// 参数如下
let menuList = [{
        "id": "1414409930173083706",
        "code": "PAGE_EXECUTE",
        "name": "EXECUTE",
        "parentId": "254069752945840128",
        "url": ""
      },
      {
        "id": "1425351825283924055",
        "code": "PAGE_LOOK",
        "name": "LOOK",
        "parentId": "254069802262466560",
        "url": ""
      },
      {
        "id": "1428620149098856496",
        "code": "PAGE_NEWTASK",
        "name": "NEWTASK",
        "parentId": "1428567167967739913",
        "url": ""
      },
      {
        "id": "254069654174175232",
        "code": "MENU_INFO",
        "name": "INFO",
        "parentId": "",
        "url": ""
    },
    ...
 ]
  
  const asyncRoutes = [{
        name: 'MENU_INFO',
        path: '/taskInfo',
        // component: Layout,
        redirect: '/taskInfo/list',
        meta: {
          icon: 'icon-task-system',
          title: "信息"
        },
        children: [{
            name: 'MENU_LOGGING',
            path: 'Logging',
            // component: () => import('@/views/taskInfo/executiveLogging'),
            meta: {
              title: '记录'
            }
          },
          {
            name: 'MENU_TASK',
            path: 'list',
            // component: () => import('@/views/taskInfo/list'),
            meta: {
              title: '任务',
            }
          },
          {
            name: 'MENU_APPROVAL',
            path: 'Approval',
            // component: () => import('@/views/taskInfo/pendingApproval'),
            meta: {
              title: '审批',
            }
          }
        ]
      },
      ...
   ]    

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值