Dirección de demostración de GitHub
vista previa en línea
prefacio
1. El proyecto en la demostración ha agregado
TagsView
funciones y control de permisos local.
Acerca deTagsView
la adición de funciones, puede ver: Vue - transformación de proyecto de plantilla de vue-admin-template: agregando la función TagsView
. Acerca rama de control de permisosvue-admin-template
del control de permisos local referencia de código relacionado
2. Y el proyecto en la demostración tiene funciones basadas en 1.
增加TopHeader(顶栏)
Muestra el título del proyecto y la información del usuario en la barra superior, que puede admitir la pantalla original, y también puede mostrar la barra superior a través de la configuración de
configuración增加TopHeader(顶栏)
. puede ver: Vue - Transformación de proyecto de plantilla de Vue-admin-template: agregue TopHeader (barra superior)
Por lo tanto, el código del proyecto puede ser un poco diferente de la versión original
vue-admin-template
, dirección del código vue-admin-template
Control de permisos locales, específicamente, obtenga roles de usuario consultando la información del usuario, filtre rutas configuradas localmente a través de roles en la protección de rutas y genere una matriz de rutas para rutas que cumplan con los permisos de roles
La idea de obtener dinámicamente el enrutamiento del menú es en realidad la misma, excepto que la matriz de enrutamiento se obtiene del servidor, consultando la lista de menú de un rol y luego convirtiendo la matriz de menú obtenida en una matriz de enrutamiento en la protección de enrutamiento.
La implementación del enrutamiento dinámico se escribe con referencia a los problemas de vue-element-admin , problemas relacionados:
vue-element-admin/issues/167
vue-element-admin/issues/293
vue-element-admin/issues/3326# problemacomentario-832852647
punto clave
Principalmente en la lista del menú de la interfaz, cambie el padre
component
aLayout
la cadena 'Layout',
children
el componente: () => import('@/views/table/index'), cambie a la cadena 'table/index', y luego obtenga transferir de nuevo a los datos
!!!!!!!!!!!! 接口格式可以根据项目需要自定义,不一定非得按照这里的来
Formato de enrutamiento local:
{
path: '/example',
component: Layout,
redirect: '/example/table',
name: 'Example',
meta: {
title: 'Example', icon: 'el-icon-s-help', roles: ['admin'] },
children: [
{
path: 'table',
name: 'Table',
component: () => import('@/views/table/index'),
meta: {
title: 'Table', icon: 'table' }
},
{
path: 'tree',
name: 'Tree',
component: () => import('@/views/tree/index'),
meta: {
title: 'Tree', icon: 'tree' }
}
]
},
Formato de enrutamiento de interfaz:
{
path: '/example',
component: 'Layout',
redirect: '/example/table',
name: 'Example',
meta: {
title: '动态Example', icon: 'el-icon-s-help', roles: ['admin'] },
children: [
{
path: 'table',
name: 'Table',
component: 'table/index',
meta: {
title: '动态Table', icon: 'table' }
},
{
path: 'tree',
name: 'Tree',
component: 'tree/index',
meta: {
title: '动态Tree', icon: 'tree' }
}
]
},
Implementación
1. Interfaz
Debido a que es una solicitud de red simulada por simulacro, es necesario agregar una interfaz para obtener la lista del menú de usuario (puede copiar directamente la carpeta de roles debajo de la carpeta simulada en vue-element-admin al proyecto y luego modificarla)
Cree una carpeta de roles y un archivo index.js en el directorio simulado
const Mock = require('mockjs')
const {
asyncRoutes } = require('./routes.js')
const routes = asyncRoutes
module.exports = [
// mock get all routes form server
{
url: '/vue-element-admin/routes',
type: 'get',
response: _ => {
return {
code: 20000,
data: routes
}
}
}
Cree una carpeta de roles y un archivo route.js en el directorio simulado,
principalmente usando asyncRoutes
// Just a mock data
const constantRoutes = [
{
path: '/redirect',
component: 'Layout',
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: 'redirect/index'
}
]
},
{
path: '/login',
component: 'login/index',
hidden: true
},
{
path: '/404',
component: '404',
hidden: true
},
{
path: '/',
component: 'Layout',
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: 'dashboard/index',
meta: {
title: 'Dashboard', icon: 'dashboard', affix: true }
}]
}
]
/**
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
const asyncRoutes = [
{
path: '/example',
component: 'Layout',
redirect: '/example/table',
name: 'Example',
meta: {
title: '动态Example', icon: 'el-icon-s-help', roles: ['admin'] },
children: [
{
path: 'table',
name: 'Table',
component: 'table/index',
meta: {
title: '动态Table', icon: 'table' }
},
{
path: 'tree',
name: 'Tree',
component: 'tree/index',
meta: {
title: '动态Tree', icon: 'tree' }
}
]
},
{
path: '/form',
component: 'Layout',
meta: {
roles: ['admin'] },
children: [
{
path: 'index',
name: 'Form',
component: 'form/index',
meta: {
title: '动态Form', icon: 'form' }
}
]
},
{
path: '/nested',
component: 'Layout',
redirect: '/nested/menu1',
name: 'Nested',
meta: {
title: '动态Nested', icon: 'nested', roles: ['admin'] },
children: [
{
path: 'menu1',
component: 'nested/menu1/index', // Parent router-view
name: 'Menu1',
meta: {
title: '动态Menu1' },
children: [
{
path: 'menu1-1',
component: 'nested/menu1/menu1-1',
name: 'Menu1-1',
meta: {
title: '动态Menu1-1' }
},
{
path: 'menu1-2',
component: 'nested/menu1/menu1-2',
name: 'Menu1-2',
meta: {
title: '动态Menu1-2' },
children: [
{
path: 'menu1-2-1',
component: 'nested/menu1/menu1-2/menu1-2-1',
name: 'Menu1-2-1',
meta: {
title: '动态Menu1-2-1' }
},
{
path: 'menu1-2-2',
component: 'nested/menu1/menu1-2/menu1-2-2',
name: 'Menu1-2-2',
meta: {
title: '动态Menu1-2-2' }
}
]
},
{
path: 'menu1-3',
component: 'nested/menu1/menu1-3',
name: 'Menu1-3',
meta: {
title: '动态Menu1-3' }
}
]
},
{
path: 'menu2',
component: 'nested/menu2/index',
meta: {
title: '动态menu2' }
}
]
},
{
path: 'external-link',
component: 'Layout',
children: [
{
path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
meta: {
title: '动态External Link', icon: 'link' }
}
]
},
/** when your routing map is too long, you can split it into small modules **/
// componentsRouter,
// chartsRouter,
// 404 page must be placed at the end !!!
{
path: '*', redirect: '/404', hidden: true }
]
module.exports = {
constantRoutes,
asyncRoutes
}
Luego, en mock/index.js, cite el rol recién agregado
const user = require('./user')
const role = require('./role/index') // 新加的
const table = require('./table')
const dict = require('./demos/dict')
const tables = require('./demos/tables')
const mocks = [
...user,
...role, // 新加的
...table,
...dict,
...tables
]
2. El front-end llama a la interfaz del menú y genera una matriz de enrutamiento
Primero implemente la interfaz simulada en src/api/roles.js (cree nuevos roles.j o colóquelo en el usuario)
import request from '@/utils/request'
export function getUserMenus() {
return request({
url: '/vue-element-admin/routes',
method: 'get'
})
}
Luego modifique src/store/modules/permission.js para implementar el método de convertir la matriz del menú de procesamiento en una matriz de enrutamiento
const {
deepClone } = require('@/utils')
// 加载路由
export const loadView = (view) => {
// 路由懒加载
return (resolve) => require([`@/views/${
view}`], resolve)
// return (resolve) => require([`@${view}`], resolve)
}
/**
* 通过递归格式化菜单路由 (配置项规则:https://panjiachen.github.io/vue-element-admin-site/zh/guide/essentials/router-and-nav.html#配置项)
* @param routes
* @param roles
*/
export function filterAsyncRoutes2(routes) {
const res = []
routes.forEach((route) => {
const tmp = deepClone(route)
if (route.component === 'Layout') {
tmp.component = Layout
} else if (route.component) {
tmp.component = loadView(route.component)
}
if (route.children && route.children.length > 0) {
tmp.children = filterAsyncRoutes2(route.children)
}
res.push(tmp)
})
return res
}
Agregar una nueva función en acciones
generateDynamicRoutes({
commit }, menus) {
return new Promise(resolve => {
const accessedRoutes = filterAsyncRoutes2(menus)
commit('SET_ROUTES', accessedRoutes) // Todo: 内部拼接constantRoutes,所以查出来的菜单不用包含constantRoutes
resolve(accessedRoutes)
})
}
Luego modifique src\store\modules\user.js
para agregar el método para obtener el menú de usuario
const state = {
// ```
menus: [] //这个是我新增的
}
const mutations = {
// ```
SET_MENUS: (state, menus) => {
//这里是新增的
state.menus = menus
}
}
getUserMenus({
commit, state }) {
return new Promise((resolve, reject) => {
getUserMenus(state.token).then(response => {
const {
data } = response
if (!data) {
reject('Verification failed, please Login again.')
}
const menus = data
// roles must be a non-empty array
if (!menus || menus.length <= 0) {
reject('getMenus: menus must be a non-null array!')
}
commit('SET_MENUS', menus)
resolve(menus)
}).catch(error => {
reject(error)
})
})
},
Luego modifique la protección de ruta de src\permission.js
para que se cambie cerca del código store.dispatch('permission/generateRoutes').La ruta del usuario se obtuvo originalmente de la configuración local + roles, y ahora se obtiene del servidor anterior agregandoRutas
He agregado un rol al simulacro aquí
editor2
. Aleditor2
iniciar sesión, la ruta dinámica se obtiene del servidor y otros roles obtienen la ruta del local.
const {
roles } = await store.dispatch('user/getInfo')
// console.log('roles', JSON.stringify(roles))
var accessRoutes = []
if (roles.includes('editor2')) {
// 根据服务器获取的用户菜单生成路由
const menus = await store.dispatch('user/getUserMenus')
const asyncRoutes = await store.dispatch('permission/generateDynamicRoutes', menus)
accessRoutes = asyncRoutes
} else {
// generate accessible routes map based on roles
accessRoutes = await store.dispatch('permission/generateRoutes', roles)
}
// dynamically add accessible routes
router.addRoutes(accessRoutes)
Eso es todo.