vue-admin-template dynamic routing implementation example

vue-admin-template dynamic routing implementation example

Provide login and obtain user information data interface

In api/user.js

import request from '@/utils/request'
const Api = {
  TakeOut: '/student/students/takeOut/',
  LoginIn: '/student/students/loginIn/',
  StudentInfo:'/student/students/studentInfo/',
}
export function login(parameter) {
  return request({
    url: Api.LoginIn,
    method: 'get',
    params: parameter
  })
}

export function getInfo(token) {
  return request({
    url: Api.StudentInfo,
    method: 'get',
    params: {'token':token}
  })
}

export function logout() {
  return request({
    url: Api.TakeOut,
    method: 'get'
  })
}

Login interface data

{'code': 200, 'data': {'token': 'X-admin'}, 'message': "Operation successful"}

Exit interface data

{'code': 200, 'data': 'success', 'message': "Operation successful"}

Detailed interface data

{
    "code": 200,
    "data": {
        "avatar": "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
        "name": "Huang Xiaoguo",
        "roles": [
            "editor"
        ]
    }
}

Modify router/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'

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

  {
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: 'Home', icon: 'el-icon-menu' }
    }]
  },
]

/**
 * Dynamic routing */
export const asyncRoutes = [
  {
    path: '/studentinformation',
    component: Layout,
    children: [
      {
        path: 'index',
        component: () => import('@/views/studentinformation/index'),
        meta: { title: 'Student Information', icon: 'el-icon-s-check' }
      }
    ]
  },
  {
    path: '/lecturerinformation',
    component: Layout,
    children: [
      {
        path: 'index',
        component: () => import('@/views/lecturerinformation/index'),
        meta: { title: 'Lecturer Information', icon: 'el-icon-s-custom', roles: ['editor'] }
      }
    ]
  },
  {
    path: '/coursemanage',
    component: Layout,
    meta: { roles: ['admin'] },
    children: [
      {
        path: 'index',
        component: () => import('@/views/coursemanage/index'),
        meta: { title: 'Course Management', icon: 'el-icon-s-platform'}
      }
    ]
  },
  // The 404 page must be placed at the last page { path: '*', redirect: '/404', hidden: true }
]

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

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router

Write the dynamically displayed routes in asyncRoutes and add roles, for example, meta: { roles: ['admin'] },

Add permission.js in the store/modules directory

import { asyncRoutes, constantRoutes } from '@/router'

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles) {
  const res = []

  routes.forEach(route => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

const state = {
  routes: [],
  addRoutes: []
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
  }
}

const actions = {
  generateRoutes({ commit }, roles) {
    return new Promise(resolve => {
      const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

Modify store/modulds/user.js

import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { resetRouter } from '@/router'

const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: '',
    roles: []
  }
}

const state = getDefaultState()

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  }
}

const actions = {
  // user login
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response

        if (!data) {
          return reject('Verification failed, please log in again')
        }

        const { roles, name, avatar } = data
        commit('SET_ROLES', roles)
        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        removeToken() // must remove token first
        resetRouter()
        commit('RESET_STATE')
        commit('SET_ROLES', [])
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      removeToken() // must remove token first
      commit('RESET_STATE')
      commit('SET_ROLES', [])
      resolve()
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

Add roles: [] to save the permission list, add the following content

const getDefaultState = () => {
  return {
    ...
    roles: []
  }
}

const mutations = {
  ...
  SET_ROLES: (state, roles) => {
    state.roles = roles
  }
}

  // get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        ...
        const { roles, name, avatar } = data
        commit('SET_ROLES', roles)
        ...
      }).catch(error => {
        reject(error)
      })
    })
  },

  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        ...
        commit('SET_ROLES', [])
        ...
      }).catch(error => {
        reject(error)
      })
    })
  },

  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      ...
      commit('SET_ROLES', [])
      ...
    })
  }
}

Add roles in store/getters.js

const getters = {
  sidebar: state => state.app.sidebar,
  device: state => state.app.device,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,
  
  //Add roles
  roles: state => state.user.roles,
  //Dynamic routing permission_routes: state => state.permission.routes,
}
export default getters

Add permission to store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import app from './modules/app'
import settings from './modules/settings'
import user from './modules/user'

//Add permission
import permission from './modules/permission'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules:
    app,
    settings,
    user,
    
 //Add permission
    permission
  },
  getters
})

export default store

Finally modify the permission.js in the root directory

import router, { constantRoutes } from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'

NProgress.configure({ showSpinner: false }) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

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 {
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          // get user info
          // note: roles must be an object array! such as: ['admin'] or ,['developer','editor']
          const { roles } = await store.dispatch('user/getInfo')
          console.log(roles)
          // generate accessible routes map based on roles
          const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
          // dynamically add accessible routes
          router.options.routes = constantRoutes.concat(accessRoutes)
          router.addRoutes(accessRoutes)
          
          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
          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.afterEach(() => {
  // finish progress bar
  NProgress.done()
})

Bind data to the nav navigation bar

In layout/components/sidebar/index.vue

...mapGetters([
      // Dynamic routing adds permission_routes
      'permission_routes',
      'sidebar'
    ]),

 <!-- Dynamic Routing -->
 <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />

The full code is as follows:

<template>
  <div :class="{ 'has-logo': showLogo }">
    <logo v-if="showLogo" :collapse="isCollapse" />
    <el-scrollbar wrap-class="scrollbar-wrapper">
      <el-menu
        :default-active="activeMenu"
        :collapse="isCollapse"
        :background-color="variables.menuBg"
        :text-color="variables.menuText"
        :unique-opened="false"
        :active-text-color="variables.menuActiveText"
        :collapse-transition="false"
        mode="vertical"
      >
        <!-- <sidebar-item
          v-for="route in routes"
          :key="route.path"
          :item="route"
          :base-path="route.path"
        /> -->
        <sidebar-item
          v-for="route in permission_routes"
          :key="route.path"
          :item="route"
          :base-path="route.path"
        />
      </el-menu>
    </el-scrollbar>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'

export default {
  components: { SidebarItem, Logo },
  computed: {
    ...mapGetters([
      // Dynamic routing adds permission_routes
      'permission_routes',
      'sidebar',
    ]),
    routes() {
      return this.$router.options.routes
    },
    activeMenu() {
      const route = this.$route
      const { meta, path } = route
      // If you set path, the sidebar will highlight the path you set
      if (meta.activeMenu) {
        return meta.activeMenu
      }
      return path
    },
    showLogo() {
      return this.$store.state.settings.sidebarLogo
    },
    variables() {
      return variables
    },
    isCollapse() {
      return !this.sidebar.opened
    },
  },
}
</script>

This is the end of this article about the implementation of vue-admin-template dynamic routing. For more information about the implementation of vue-admin-template dynamic routing, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • vue-admin-template configures quick navigation code (tab navigation bar)
  • Detailed explanation of the optimization process using vue-admin-template
  • Implementation of adding tagsview to vue-admin-template template

<<:  How to make a div height adaptive to the browser height

>>:  15 Best Practices for HTML Beginners

Recommend

Detailed examples of Docker-compose networks

Today I experimented with the network settings un...

Elementui exports data to xlsx and excel tables

Recently, I learned about the Vue project and cam...

Nginx merges request connections and speeds up website access examples

Preface As one of the best web servers in the wor...

VMware Workstation 14 Pro installation Ubuntu 16.04 tutorial

This article records the specific method of insta...

Use of Linux crontab command

1. Command Introduction The contab (cron table) c...

js uses the reduce method to make your code more elegant

Preface In actual projects, the most common proce...

Detailed explanation of Vue's custom event content distribution

1. This is a bit complicated to understand, I hop...

Use JS to zoom in and out when you put the mouse on the image

Use JS to zoom in and out when the mouse is on th...

Summary of Several Methods for Implementing Vertical Centering with CSS

In the front-end layout process, it is relatively...

Steps for docker container exit error code

Sometimes some docker containers exit after a per...

Using docker command does not require sudo

Because the docker daemon needs to bind to the ho...

Detailed explanation of MySQL redo log (redo log) and rollback log (undo logo)

Preface: The previous article described several c...

The difference between html block-level tags and inline tags

1. Block-level element: refers to the ability to e...