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

Teach you the detailed process of installing DOClever with Docker Compose

Table of contents 1. What is Docker Compose and h...

Full analysis of Vue diff algorithm

Table of contents Preface Vue update view patch s...

A brief talk about calculated properties and property listening in Vue

Table of contents 1. Computed properties Syntax: ...

A Brief Discussion on the Navigation Window in Iframe Web Pages

A Brief Discussion on the Navigation Window in If...

An example of implementing a simple finger click animation with CSS3 Animation

This article mainly introduces an example of impl...

TypeScript Enumeration Type

Table of contents 1. Overview 2. Digital Enumerat...

MySQL transaction details

Table of contents Introduction Four characteristi...

Solution to slow response of Tomcat server

1. Analytical thinking 1. Eliminate the machine&#...

How to prevent website content from being included in search engines

Usually the goal of building a website is to have...

How to completely delete and uninstall MySQL in Windows 10

Preface This article introduces a tutorial on how...

IIS7 IIS8 reverse proxy rule writing, installation and configuration method

Purpose: Treat Station A as the secondary directo...

Vue uses OSS to upload pictures or attachments

Use OSS to upload pictures or attachments in vue ...