Vue添加动态路由

2019-11-20  本文已影响0人  领带衬有黄金

需求

后台管理需要根据登陆的用户权限做菜单控制

思路

后台返回用户权限,保存到vuex中,判断权限是否有惨淡导航,如果有使用addRoutes添加到路由中。
路由声明处,需要声明动态路由和公共路由。
由权限去判断是否应该加入动态路由

store代码:

-->user.js
function isAddRoute(pers, route) {
  return pers.some(per => per.code.split('_').pop() === route.path.split('/').pop())
}

function removeArrayData(arr) {
  let i = arr.length - 1;
  while (i >= 0) {
    if (arr[i].path !== '/login' && arr[i].path !== '/' && arr[i].path !== '/404' && arr[i].path !== '*') {
      arr.splice(i, 1)
    }
    i--
  }
}


export function filterAsyncRoutes(pers, routes) {
  const res = []
  routes.forEach(route => {
    const tmp = {...route}
    if (isAddRoute(pers, tmp)) {
      // 目前仅控制一级路由,子路由以后控制
      // if (tmp.children) {
      //   tmp.children = filterAsyncRoutes(tmp.children, roles)
      // }
      res.push(tmp)
    }
  });
  return res
}

const state = {
  addRoutes: []
}

const mutations = {
  // 移除用户
  REMOVE: (state) => {
    state.name = ''
    state.addRoutes = []
    //退出后,改变还原静态路由
    removeArrayData(constantRoutes)
  },
  ADD_ROUTES: (state, routes) => {
    state.addRoutes = routes
    routes.forEach((i, index) => {
      // 从第3+index个位置插入
      constantRoutes.splice(3 + index, 0, i)
    })
  }
}

const actions = {
  // get user info
  getInfo({commit, state}) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(res => {
        const {data} = res
        let pers = []
        let admin_pers = []
        if (!data) {
          reject('Verification failed, please Login again.')
        }
        // const {name, phone, active, create_time, avatar} = data
        commit('SET_INFO', data)
        admin_pers = data.roles.map(item => item.pers)
        for (let i in admin_pers) {
          for (let j in admin_pers[i]) {
            let target = pers.filter(item => item.code === admin_pers[i][j].code)
            if (target.length === 0) {
              // 判断如果角色中有相同的
              pers.push(admin_pers[i][j])
            }
          }
        }
        const accessedRoutes = filterAsyncRoutes(pers, asyncRoutes)
        // 将角色权限保存到vuex
        commit('ADD_ROUTES', accessedRoutes)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout
  logout({commit, state}) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        commit('SET_TOKEN', '')
        commit('REMOVE')
        removeToken()
        resetRouter()
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  }
}


-->main.js

router.beforeEach(async (to, from, next) => {
  // start progress bar
  NProgress.start()
  // set page title
  document.title = getPageTitle(to.meta.title)
  // determine whether the user has logged in
  const hasToken = getToken()
  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page,如果已经登陆,还要访问登陆页面,则重定向到首页
      next({
        path: '/'
      })
      NProgress.done()
    } else {
      // 在vuex中保存有用户信息的,直接通过
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        // 判断路由是否在 database,在该路由下,即发送数据请求,保存到vuex
        if (/database/.test(to.path)) {
          ajax_get_db_types()
          // await store.dispatch('db/action_get_types')
        }
        const hasAddRoutes = store.getters.addRoutes && store.getters.addRoutes.length > 0
        if (hasAddRoutes) {
          next()
        }
      } else {
        /*没有用户信息*/
        const hasAddRoutes = store.getters.addRoutes && store.getters.addRoutes.length > 0
        if (hasAddRoutes) {
          next()
        } else {
          // 判断用户角色
          try {
            if (/database/.test(to.path)) {
              // 当路由来到database时,发送获取数据库分类请求,保存到vuex中
              ajax_get_db_types()
            }
            // 首次保存用户信息 // 第一次请求保存用户信息到vuex中,并进入index页面,此时不做进入database的判断
            await store.dispatch('user/getInfo');
            // // constantRoutes.options.routes = newRoutes
            router.addRoutes(store.getters.addRoutes)
            // 解决路由刷新404界面
            router.addRoutes([{path: '*', redirect: '/404', hidden: true}])
            next({...to, replace: true})
          } catch (error) {
            // remove token and go to login page to re-login
            await store.dispatch('user/resetToken')
            Message.error(error || 'Has Error')
            next(`/login?redirect=${to.path}`)
            NProgress.done()
          }
        }
      }
    }
  } 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()
    }
  }
})


-->router.js

import Layout from '@/layout'

export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    name: '404',
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true, meta: {title: '404'}
  },
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: '/dashboard',
      name: '首页',
      component: () => import('@/views/dashboard/index'),
      meta: {title: '首页', icon: 'dashboard', noCache: true, affix: true}
    }]
  },
  // 匹配所有路由,如果匹配了上面的路由,就会直接跳转,否则跳转到404路由
  // {path: '*', redirect: '/404', hidden: true}
]

export const asyncRoutes = [
  {
    path: '/database',
    component: Layout,
    redirect: '/database/databaselist',
    name: '数据库管理',
    meta: {title: '数据库管理', icon: 'nested'},
    children: [
      {
        path: 'databaselist',
        name: 'DatabaseList',
        component: () => import('@/views/database/DatabaseList'),
        meta: {title: '数据库分类', icon: '列表'}
      },
      {
        path: 'databaserset',
        name: 'DatabaseSet',
        component: () => import('@/views/database/DatabaseSet'),
        meta: {title: '数据库设置', icon: '设置'}
      }
    ]
  },
  {
    path: '/news',
    component: Layout,
    redirect: '/news/newslist',
    name: '资讯快报管理',
    meta: {title: '资讯快报管理', icon: '资讯'},
    children: [
      {
        path: 'newslist',
        name: 'NewsList',
        component: () => import('@/views/news/NewsList'),
        meta: {title: '资讯快报列表', icon: '列表'}
      },
      {
        path: 'newsset',
        name: 'NewsSet',
        component: () => import('@/views/news/NewsSet'),
        meta: {title: '资讯快报设置', icon: '设置'}
      },
    ]
  },

  {
    path: '/intelligence',
    component: Layout,
    redirect: '/intelligence/intelclass',
    name: '情报智库管理',
    meta: {title: '情报智库管理', icon: '数据情报'},
    children: [
      {
        path: 'intellist',
        name: 'Tree',
        component: () => import('@/views/intelligence/IntelList'),
        meta: {title: '情报列表', icon: '列表'}
      },
      {
        path: 'intelclass',
        name: 'IntelClass',
        component: () => import('@/views/intelligence/IntelClass'),
        meta: {title: '情报分类', icon: 'link'}
      }
    ]
  },

  {
    path: '/permission',
    component: Layout,
    redirect: '/permission/admins',
    name: '管理员管理',
    meta: {title: '管理员管理', icon: '用户,管理员_jurassic'},
    children: [
      {
        path: 'admins',
        name: 'Admins',
        component: () => import('@/views/permission/Admins'),
        meta: {title: '管理员列表', icon: '列表'}
      },
      {
        path: 'roles',
        name: 'Roles',
        component: () => import('@/views/permission/Roles'),
        meta: {title: '角色列表', icon: '会员'}
      },
      {
        path: 'rules',
        name: 'Rules',
        component: () => import('@/views/permission/Rules'),
        meta: {title: '权限列表', icon: '权限'}
      }
    ]
  },

  {
    path: '/vip',
    component: Layout,
    redirect: '/vip/viplist',
    name: '会员管理',
    meta: {title: '会员管理', icon: '会员中心'},
    children: [
      {
        path: 'viplist',
        name: 'VipList',
        component: () => import('@/views/vip/VipList'),
        meta: {title: '会员列表', icon: '列表'}
      },
      {
        path: 'vippower',
        name: 'VipPower',
        component: () => import('@/views/vip/VipPower'),
        meta: {title: '会员权限', icon: '权限'}
      },
      {
        path: 'viporders',
        name: 'VipOrders',
        component: () => import('@/views/vip/VipOrders'),
        meta: {title: '用户订单', icon: '订单'}
      }
    ]
  },

  {
    path: '/swiper',
    component: Layout,
    redirect: '/swiper/homeswiper',
    name: '轮播图管理',
    meta: {title: '轮播图管理', icon: 'eye-open'},
    children: [
      {
        path: 'homeswiper',
        name: 'HomeSwiper',
        component: () => import('@/views/swiper/HomeSwiper'),
        meta: {title: '前台首页轮播图', icon: '首页轮播图'}
      },
      {
        path: 'newsswiper',
        name: 'NewsSwiper',
        component: () => import('@/views/swiper/NewsSwiper'),
        meta: {title: '资讯首页轮播文章', icon: '首页轮播图'}
      }
    ]
  },

  {
    path: '/tools',
    component: Layout,
    redirect: '/tools/pricecontrol',
    name: '工具管理',
    meta: {title: '工具管理', icon: 'example'},
    children: [
      {
        path: 'pricecontrol',
        name: 'PriceControl',
        component: () => import('@/views/tools/PriceControl'),
        meta: {title: '价格上浮管理', icon: '数据情报'}
      },
      {
        path: 'viewlog',
        name: 'Viewlog',
        component: () => import('@/views/tools/Viewlog'),
        meta: {title: '日志查看', icon: 'eye'}
      }
    ]
  },
  {
    path: '/gallery',
    component: Layout,
    redirect: '/gallery/database',
    name: '图库管理',
    meta: {title: '图库管理', icon: 'example'},
    children: [
      {
        path: 'database',
        name: 'database',
        component: () => import('@/views/gallery/Database'),
        meta: {title: '数据图库', icon: '数据情报'}
      },
      {
        path: 'intelligence',
        name: 'intelligence',
        component: () => import('@/views/gallery/Intelligence'),
        meta: {title: '情报图库', icon: 'eye'}
      }
    ]
  },

]

const createRouter = () => new Router({
  mode: 'history',
  scrollBehavior: () => ({y: 0}),
  routes: constantRoutes
})

const router = createRouter()

问题:

一:刷新404,不能在静态路由中添加 * 拦截没有的路由,需要手动传入router.addRoutes([{path: '*', redirect: '/404', hidden: true}])
二:访问动态路由404,需要将 * 拦截的路由放在最后。

上一篇 下一篇

猜你喜欢

热点阅读