vue-动态路由+按钮级权限(二)之动态路由

首先,把整个系统的路由表分为静态路由和动态路由,

静态路由为不需要权限就加载的路由组,

动态路由为权限关联路由

import addRoutes from './routers/add'
import staticRoutes from './routers/static'
export const routes = [
   //...addRoutes,
    ...staticRoutes,
]

static.js

const routes =  [
    {
        path: "/",
        redirect: '/home',
    },
    {
        path: '/home',
        name: 'home',
        meta:{
            title:'首页',
            keepAlive: false, //此组件不需要被缓存
            name:'home'

        },
        component: () =>  import('@/views/home/main/index.vue'),
    },
    {
        path: '/login',
        name: 'login',
        meta:{
                keepAlive: false, 
        },
        component: () => import('@/views/login/main/index.vue')
    },
    {
        path: '/404',
        name: '404',
        component: () =>
            import('@/views/error/404.vue')
    },
//     {
//         path: '/:pathMatch(.*)',
//         redirect: '/404'
//     }
]

export default routes

add.js

[
    {
        "path": "/personal",
        "name": "personal",
        "meta": {
            "title": "个人中心",
            "keepAlive": false,
            "name": "personal"
        },
        "component": "personal"
    },
    {
        "path": "/system",
        "name": "system",
        "meta": {
            "title": "系统设置",
            "keepAlive": false,
            "name": "system"
        },
        "component": "system"
    },
    {
        "path": "/multi-prjs",
        "name": "multi-prjs",
        "meta": {
            "title": "项目集成管理智慧运营中心",
            "keepAlive": false,
            "name": "multiPrjs"
        },
        "component": "multiPrjs"
    },
    {
        "path": "/single-prj",
        "name": "single-prj",
        "meta": {
            "title": "研发管理看板",
            "keepAlive": false,
            "name": "singlePrj"
        },
        "component": "singlePrj"
    },
    {
        "path": "/single-design",
        "name": "single-design",
        "meta": {
            "title": "设计看板",
            "keepAlive": false,
            "name": "singleDesign"
        },
        "component": "singleDesign"
    },
    {
        "path": "/single-dev",
        "name": "single-dev",
        "meta": {
            "title": "开发看板",
            "keepAlive": false,
            "name": "singleDev"
        },
        "component": "singleDev"
    },
    {
        "path": "/single-test",
        "name": "single-test",
        "meta": {
            "title": "个人中心",
            "keepAlive": false,
            "name": "singleTest"
        },
        "component": "singleTest"
    },
    {
        "path": "/single-ci",
        "name": "single-ci",
        "meta": {
            "title": "个人中心",
            "keepAlive": false,
            "name": "singleCi"
        },
        "component": "singleCi"
    }
]

router/index

import Vue from 'vue'
import {
    Message
} from 'element-ui'
import store from "../store";
import VueRouter from 'vue-router'
import addRoutes from './routers/add'
import staticRoutes from './routers/static'
import db from '@/common/storage'
//解决vue路由重复的时候,点击报错问题
const originalReplace = VueRouter.prototype.replace
VueRouter.prototype.replace = function replace(location) {
    return originalReplace.call(this, location).catch(err => err)
}
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
    return originalPush.call(this, location).catch(err => err)
}
Vue.use(VueRouter)
export const routes = [
    //...addRoutes,
    ...staticRoutes,
]
const router = new VueRouter({
    //mode:'history',
    mode: 'hash',
    base: process.env.BASE_URL,
    routes
})
const whiteList = ['/login']
router.beforeEach(async(to, from, next) => {
    const hasLogin = window.sessionStorage.getItem('token') || false
        if (hasLogin) {
            if (to.path === '/login') {
                next({ path: '/' })
            }else{
                if (to.name === 'home') {
                    store.state.singlePrjStore.xname = '创新中心';
                    store.state.singlePrjStore.orgStoreId = null;
                    store.state.singlePrjStore.projectId = null;
                    store.state.singlePrjStore.projectNo = null;
                    store.state.singlePrjStore.iterationId = null;
                    store.state.singlePrjStore.iterationStartTime = null;
                    store.state.singlePrjStore.iterationEndTime = null;
                 }
                 const hasRoles = store.state.userStore.asyncRoutes.length > 0
                 if(hasRoles){
                    next()
                 }else{
                    try {
                        let params ={
                          userId:db.ss.get('userId')
                        } 
                        const accessRoutes = await store.dispatch('userStore/generateRoutes',params)
                        router.addRoutes(accessRoutes)
                        next({ ...to, replace: true })
                      } catch (error) {
                        db.ss.clear();
                        next(`/login?redirect=${to.path}`)
                      }
                 }
                 next()
            }
        } else {
            if (whiteList.indexOf(to.path) !== -1) {
                // 访问的路径处于白名单中
                next()
              } else {
                Message({
                    message: '您尚未登录,你先登录',
                    type: 'error',
                    duration: 5 * 1000
                })
                // 没有登录,跳转登录页
                next(`/login?redirect=${to.path}`)
              }
            
        }
    
})
export default router

store/userStore

import {getSysUserInfo,getSysUserPermissions} from '@/server/user/user'
import formatRoutes from '@/plugins/analysisRoute'
import db from '@/common/storage'
const userStore = {
    namespaced:true,
    state: {
      asyncRoutes:[],
      userInfo:{
        roles:[]
      },
    },
    actions: {
      async  getUserInfo({ commit },params) {
        const { code, data } = await getSysUserInfo(params);
        if (code == 0) {
         commit('setUserInfo', data)
        }
      },
      async generateRoutes({ commit },params) {
        return new Promise((resolve) => {
          getSysUserPermissions(params).then(res=>{
            let  accessedRoutes = formatRoutes(res.data.menuList);
            commit('setAsyncRoutes', accessedRoutes);
            db.ss.set('permissionList',res.data.buttonLit)
            resolve(accessedRoutes)
          });
        })
      }
    },
    mutations: {
      setAsyncRoutes(state, data) {
        state.asyncRoutes = data;
      },
      setUserInfo(state, data) {
        db.ss.set('userInfo',data)
        state.userInfo = data;
      }
    }
  };

  export default userStore;
  

db.js

/**
 * localStorage and sessionStorage basic operation
 */
const ls = localStorage;
const ss = sessionStorage;
const db = {
  ls: {
    get(key) {
      try {
        return JSON.parse(ls.getItem(key));
      } catch (err) {
        return ls.getItem(key);
      }
    },
    set(key, value) {
      ls.setItem(key, JSON.stringify(value));
    },
    remove(key) {
      ls.removeItem(key);
    },
    clear() {
      ls.clear();
    }
  },
  ss: {
    get(key) {
      try {
        return JSON.parse(ss.getItem(key));
      } catch (err) {
        return ss.getItem(key);
      }
    },
    set(key, value) {
      ss.setItem(key, JSON.stringify(value));
    },
    remove(key) {
      ss.removeItem(key);
    },
    clear() {
      ss.clear();
    }
  }
};
export default db;
formatRoutes.js
function loadView(component) {
  return (resolve) => require([`@/views/${component}/main/index`], resolve)
}
export default function formatRoutes(routes, Layout) {
    const formatRoutesArr = []
    routes.forEach(route => {
      const router = {
        meta: {}
      }
      const {
        pid,
        path,
        redirect,
        component,
        icon,
        name,
        meta,
        children
      } = route
      if (component === 'Layout') {
        router['component'] = Layout
      } else {
        router['component'] = loadView(component)
      }
      if (redirect !== null) {
        router['redirect'] = redirect
      }
      if (icon !== null) {
        router['meta']['icon'] = icon
      }
      if (children && children instanceof Array && children.length > 0) {
        router['children'] = formatRoutes(children)
      }
      if (name !== null) {
        router['name'] = name
      }
      // router['meta']['title'] = meta.title
      // router['meta']['name'] = meta.name
      //router['meta']['keepAlive'] = meta.keepAlive
      router['path'] = path
      if (pid === 0) {
        router['alwaysShow'] = true
      }
      formatRoutesArr.push(router)
    })
    // 将404页面添加到最后面
    formatRoutesArr.push({ path: '*', redirect: '/404', hidden: true })
    return formatRoutesArr
  }
  

后台返回的权限列表接口数据结构为

 

 总结:登录过后通过上面接口存到vuex里的asyncRoutes数组有没有值决定路由拦截器的逻辑,需要注意的是

加入动态路由会出现404的问题

原因在于,我们在addRoutes加动态路由前,就配置了通配符404路由;

所以上图静态路由表里面的注释那边就是重点

2>需要在退出登录,以及token失效过期清除asyncRoutes

退出登录


...mapMutations("userStore", ["setAsyncRoutes"]),
loginOut() {
      this.$message({
        message: "退出登录成功,跳转至登录页...",
        type: "success",
      });
      this.$db.ss.clear();
      this.setAsyncRoutes([]);
      setTimeout(() => {
        this.$router.push("/login");
      }, 1000);
    },

响应拦截器里面的

import store from "@/store";
store.state.userStore.asyncRoutes = [];

 

 
posted @ 2021-11-24 11:21  影思密达ing  阅读(759)  评论(0编辑  收藏  举报