使用的的是vue-admin-template,这是一个极简的 vue admin 管理后台,它只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。需要根据自己的需求二次开发。
线上地址:vue-admin-template
国内访问:vue-admin-template
- 开发了一个公司内部的后台管理系统
- 路由信息是登录成功后台返回,然后动态添加的
- 遇到的问题:动态添加路由死活不显示
解决思路:
1. 所有的页面必须有index.vue
比如一个模块“日志和统计”, 它包含两个自己,‘操作日志’和‘数据列表’
- LogsAndStatistics
- OperationLog
- index.vue
- DataStatistics
- index.vue
- index.vue
- OperationLog
对!必须有index.vue!必须有index.vue!!必须有index.vue!重要的事情3遍,不写就是不显示!!!
name也必须是一 一对应的唯一值!!!
2. 修改配置条件
- 先登录成功后后台会返回该账号匹配的路由信息,格式如下:
[
{
"title": "消息管理",
"name": "message",
"id": 2,
"pid": 0,
"icon": "el-icon-tickets",
"component": "#",
"path": "/message-management",
"redirect": "/list",
"alwaysShow": 1,
"children": [
{
"title": "消息列表",
"name": "MessageManagement",
"id": 3,
"pid": 2,
"component": "MessageManagement",
"path": "list"
}
]
},
{
"title": "客户管理",
"name": "Customer:List",
"id": 25,
"pid": 0,
"icon": "el-icon-user-solid",
"component": "#",
"path": "/customer",
"redirect": "Customer",
"alwaysShow": 1,
"children": [
{
"title": "客户列表",
"name": "CustomerManagement",
"id": 26,
"pid": 25,
"component": "CustomerManagement",
"path": "list"
}
]
},
{
"title": "用户和权限",
"name": "",
"id": 31,
"pid": 0,
"icon": "el-icon-user-solid",
"component": "#",
"path": "/user-permissions",
"redirect": "/user-list",
"alwaysShow": 1,
"children": [
{
"title": "组织架构",
"name": "OrganizationalStructure",
"id": 37,
"pid": 31,
"component": "UsersAndPermissions/OrganizationalStructure",
"path": "organizational-list"
},
{
"title": "用户列表",
"name": "UserList",
"id": 32,
"pid": 31,
"component": "UsersAndPermissions/UserList",
"path": "user-list"
},
{
"title": "权限列表",
"name": "PermissionList",
"id": 41,
"pid": 31,
"component": "UsersAndPermissions/PermissionList",
"path": "permission-list"
},
{
"title": "角色列表",
"name": "RoleList",
"id": 44,
"pid": 31,
"component": "UsersAndPermissions/RoleList",
"path": "role-list"
}
]
},
{
"title": "日志和统计",
"name": "LogManagement",
"id": 46,
"pid": 0,
"icon": "el-icon-error",
"component": "#",
"path": "/logs-statistics",
"redirect": "/logs",
"alwaysShow": 1,
"children": [
{
"title": "操作日志",
"name": "LogsAndStatistic",
"id": 47,
"pid": 46,
"component": "LogsAndStatistics/OperationLog",
"path": "logs"
},
{
"title": "数据列表",
"name": "DataStatistics",
"id": 48,
"pid": 46,
"component": "LogsAndStatistics/DataStatistics",
"path": "statistics"
}
]
}
]
- 先保存到本地:我们是登录成功后直接返回的如下图:
// utils/auth.js
export function setPermission(permission){
const permissionData = {permission}
return localStorage.setItem(PERMISSION, JSON.stringify(permissionData))
}
export function getPermission(){
const val = JSON.parse(localStorage.getItem(PERMISSION)|| '{}')
return val.permission
}
- 我的permission配置文件直接copy的 vue-element-admin 的二次修改的。
首先是router下的index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/Login/index.vue'),
hidden: true
},
{
path: '/retrieve-password',
component: () => import('@/views/RetrievePassword/index.vue'),
hidden: true
},
{
path: '/404',
name:'Page404',
component: () => import('@/views/404'),
hidden: true
}
]
const createRouter = () => new Router({
isAddDynamicMenuRoutes: false, // 是否已经添加动态(菜单)路由
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
const router = createRouter()
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
然后修改src 目录下的permission.js
import router 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,getPermission} from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login','/retrieve-password'] // 不需要重定向白名单:登录和找回密码页面不需要重定向
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// 确定用户是否已登录
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
// 是否添加动态路由
if (router.options.isAddDynamicMenuRoutes) {
next()
} else {
try {
// 获取本地存储的路由信息(后台返回的)
const Permission = getPermission()
if(Permission.length<1){ return Promise.reject('菜单数据加载异常')}
const accessRoutes = await store.dispatch('permission/generateRoutes', Permission)
router.addRoutes(accessRoutes)
router.options.isAddDynamicMenuRoutes = true
next({ ...to, replace: true })
} catch (error) {
console.log(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 {
/* 未登录*/
if (whiteList.indexOf(to.path) !== -1) {
//在免费登录白名单中,直接进入
next()
} else {
//没有访问权限的其他页面将重定向到登录页面。
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})
store文件夹下添加permission.js (需要在store的index.js下引入:import permission from ‘./modules/permission’)
- 解析返回的路由信息时import(‘@/views/XXX/index.vue’) 会报错,找不到。
- 开始把整个路由信息’@/views/XXX/index.vue’全部返回,直接使用require([
/${component}
], resolve)) ,还是报错; - 搜索尝试后解决component只要中间部分:
eg:`@/views/RetrievePassword/index.vue' => 'RetrievePasswod'
解析时:require([`@/views/${component}/index.vue`], resolve))
import Vue from 'vue'
import {constantRoutes} from '@/router'
import Layout from '@/layout'
/**
* 后台查询的菜单数据拼装成路由格式的数据
* @param list 处理的路由列表
*/
export function AddMenuRoutes(list = []) {
const newRoutes = []
list.map((v, i) => {
const {path,id,name,component,alwaysShow,redirect,title,icon,children} = v
const route = {
id,
path: component=='#' && i==0?'/':path
}
if(component=='#'){
Vue.set(route,'component',Layout)
}else{
Vue.set(route,'component',(resolve) => require([`@/views/${component}/index.vue`], resolve))
}
if(name){
Vue.set(route,'name',name)
}
if(title){
Vue.set(route,'meta',{title})
if(icon){
Object.assign(route.meta,{icon})
}
}
if(alwaysShow==1){Vue.set(route,'alwaysShow',true)}
if(redirect){Vue.set(route,'redirect',redirect)}
if (children && children.length) {
Vue.set(route,'children',[])
route.children = AddMenuRoutes(v.children)
}
newRoutes.push(route)
})
return newRoutes
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
/**
* @param {*} permissionList 后台传回来的路由数据
*/
async generateRoutes({ commit }, permissionList) {
const MenuList = []
const permissions = permissionList || []
Object.assign(MenuList, permissions)
const newRoutes = await AddMenuRoutes(MenuList)
commit('SET_ROUTES', newRoutes)
return newRoutes
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
就可以看到效果了:
完整的authentic.js:
const TokenKey = 'access_token'
const PERMISSION ='Permission'
const USERINFO = 'UserInfo'
const BUTTONS = 'Buttons'
export function getUserInfo() {
const val = JSON.parse(localStorage.getItem(USERINFO)||'{}')
return val.name
}
export function setUserInfo(name) {
const userInfo={name}
return localStorage.setItem(USERINFO, JSON.stringify(userInfo))
}
export function removeUserInfo() {
return localStorage.removeItem(USERINFO)
}
export function getToken() {
const val = JSON.parse(localStorage.getItem(TokenKey)|| '{}')
return val.token
}
export function setToken(token) {
const tokeData = {token}
return localStorage.setItem(TokenKey, JSON.stringify(tokeData))
}
export function removeToken() {
return localStorage.removeItem(TokenKey)
}
export function setPermission(permission){
const permissionData = {permission}
return localStorage.setItem(PERMISSION, JSON.stringify(permissionData))
}
export function getPermission(){
const val = JSON.parse(localStorage.getItem(PERMISSION)|| '{}')
return val.permission
}
export function removePermission() {
return localStorage.removeItem(PERMISSION)
}
export function setButtons(buttons){
const buttonsData = {buttons}
return localStorage.setItem(BUTTONS, JSON.stringify(buttonsData))
}
export function getButtons(){
const val = JSON.parse(localStorage.getItem(BUTTONS)|| '{}')
return val.buttons
}
export function removeButtons() {
return localStorage.removeItem(BUTTONS)
}
export function removeAllInfo() {
removeButtons()
removePermission()
removeToken()
removeUserInfo()
}