基於vue-element-admin的異步權限路由——動態路由(三)

    前面已經實現了用戶與角色關聯、角色與路由關聯,這篇文章主要介紹後端根據用戶角色返回角色綁定的路由後,前端如何實現動態生成路由。
    首先我們前端保存了一份全部的異步路由配置表:

export const asyncRoutes = [
    {
        path: '/privilegeManage',
        component: Layout,
        redirect: '/privilegeManage/menuList',
        name: 'privilegeManage',
        alwaysShow: true,
        meta: {
            title: '權限管理',
            icon: 'privilege-manage',
            roles: ['admin', 'seeAdmin']
        },
        children: [
            {
                path: 'menuList',
                component: () => import('@/views/privilegeManage/menuList'),
                name: 'menuList',
                meta: {
                    title: '菜單管理',
                    icon: 'menu',
                    noCache: true
                }
            },
            {
                path: 'createMenu',
                component: () => import('@/views/privilegeManage/createMenu'),
                name: 'createMenu',
                meta: {
                    title: '添加菜單',
                },
                hidden: true
            },
            {
                path: 'editMenu',
                component: () => import('@/views/privilegeManage/editMenu'),
                name: 'editMenu',
                meta: {
                    title: '修改菜單',
                },
                hidden: true
            },
            {
                path: 'roleList',
                component: () => import('@/views/privilegeManage/roleList'),
                name: 'roleList',
                meta: {
                    title: '角色管理',
                    icon: 'role-list',
                    noCache: true
                }
            },
        ]
    },
{
        path: '/accounts',
        component: Layout,
        redirect: '/accounts/list',
        name: 'accountManage',
        alwaysShow: true,
        meta: {
            title: '賬單管理',
            icon: 'accounts'
        },
        children: [
            {
                path: 'accountClassify',
                component: () => import('@/views/accounts/accountClassify'),
                name: 'accountClassify',
                meta: {
                    title: '分類管理',
                    icon: 'classify',
                    roles: ['admin', 'seeAdmin']
                }
            },
            {
                path: 'list',
                component: () => import('@/views/accounts/list'),
                name: 'accountsList',
                meta: {
                    title: '賬單列表',
                    icon: 'capitallist',
                    noCache: true
                }
            },
            {
                path: 'accountsEdit',
                component: () => import('@/views/accounts/accountsEdit'),
                name: 'accountsEdit',
                meta: {
                    title: '修改賬單',
                    activeMenu: '/accounts/list'
                },
                hidden: true
            },
            {
                path: 'accountsAdd',
                component: () => import('@/views/accounts/accountsAdd'),
                name: 'accountsAdd',
                meta: {
                    title: '添加賬單',
                    activeMenu: '/accounts/list'
                },
                hidden: true
            }
        ]
    },
 {path: '*', redirect: '/404', hidden: true}
]

    目前就以兩個一級菜單爲例,爲一個角色配置賬單管理的權限。後端返回的數據如下:

let userRouter = [
	{
		menuId: 'f95523b631cbb1f9bc7892147f2e441f',
		name: '賬單管理',
		pid: '',
		url: '/accounts'
		children: [
			{
				menuId: "8b0e14591bb0964817192401b3bfe934"
				name: "賬單列表"
				pid: "f95523b631cbb1f9bc7892147f2e441f"
				url: "list"
			},
			{
				menuId: "aadc11cddff3e18e09d3291c92e17ce8"
				name: "修改賬單"
				pid: "f95523b631cbb1f9bc7892147f2e441f"
				url: "accountsEdit"
			},
			{
				menuId: "f8548737bacd227bddbc7315a7f65fd0"
				name: "添加賬單"
				pid: "f95523b631cbb1f9bc7892147f2e441f"
				url: "accountsAdd"
			}
		]
	}
]

    一般都是在返回用戶信息的接口裏面同時返回用戶的路由信息,你也可以在獲取到用戶信息後再獲取路由信息也是可以的。
    src/permision.js文件:

router.beforeEach(async (to, from, next) => {
	// 根據token判斷用戶登錄狀態(有的項目不是根據token判斷登錄的,可根據實際情況進行改變)
	const hasToken = getToken();
	if(hasToken) {
		if(to.path === '/login') {
			next({path: '/'})
		} else {
			// 判斷用戶是否獲取到路由信息
			const hasUserRouter = store.state.permission.hasUserRouter;
			if (hasUserRouter) {
				next();
			} else {
				try {
					// 重新獲取用戶信息並接收信息中的路由信息
					const {routerList} = await stroe.dispatch('user/getInfo');
					// 動態生成可訪問的路由
					const recursiveRouter = await store.dispatch('permission/recursiveRouter', routerList);
					router.addRoutes(recursiveRouter);
					next({...to, replace: true})
				} catch (error) {
					Message.error(error || error.message);
                    // 刪除token並跳轉到登錄頁重新登錄
                    await store.dispatch('user/resetToken')
                    // Message.error(error || '出現一個未知錯誤')
                    next(`/login?redirect=${to.path}`)
				}
			}
		}
	} else {
		// 沒有token
        if (whiteList.indexOf(to.path) !== -1) {
            // 在白名單中,直接進入
            next()
        } else {
            // 其他沒有訪問權限的頁面將重定向到登錄頁面
            next(`/login?redirect=${to.path}`)
        }
	}
})

    store/modules/permission.js文件:

/**
 * 權限生成路由模塊
 */
import {asyncRoutes, constantRoutes} from "@/router/index";

/**
 * 判斷路由路徑是否相等
 * @param asyncRouterItem
 * @param userRouteItem
 */
function hasPath(asyncRouterItem, userRouteItem) {
    return asyncRouterItem.path === userRouteItem.path;
}

/**
 * 通過循環遞歸出符合用戶權限的路由表
 * @param asyncRouterList
 * @param userRouterList
 * @returns {*[]}
 */
export function recursiveAsyncRoutes(asyncRouterList, userRouterList) {
    let res = [];
    asyncRouterList.forEach(route => {
        const tmp = {...route};
        if (tmp.path === '*' && !tmp.hasOwnProperty('children')) {
        	// 這一步主要是爲了添加404路由
            res.push(tmp)
        } else {
            userRouterList.forEach(uRoute => {
                if (hasPath(tmp, uRoute)) {
                    if (tmp.children && uRoute.children) {
                        tmp.children = recursiveAsyncRoutes(tmp.children, uRoute.children)
                    }
                    res.push(tmp)
                }
            })
        }
    })
    return res;
}
/**
 * 數據
 * @type {{routes: Array, addRoutes: Array}}
 */
const state = {
	hasUserRouter: false,
    routes: [],
    addRoutes: []
}
const mutations = {
    /**
     * 設置路由表
     * @param state 數據
     * @param routes 路由
     * @constructor
     */
    SET_ROUTES: (state, routes) => {
        state.addRoutes = routes
        state.routes = constantRoutes.concat(routes)
    },
    /**
     * 設置路由狀態
     * @param state
     * @param states
     * @constructor
     */
    SET_ROUTER_STATE: (state, states) => {
        state.hasUserRouter = states;
    }
}
const actions = {
    /**
     * 根據用戶路由權限遞歸路由表
     * @param commit
     * @param userRouterList 用戶路由權限表
     * @returns {Promise<any>}
     */
    recursiveRouter({commit}, userRouterList) {
        return new Promise(resolve => {
            let accessedRoutes = recursiveAsyncRoutes(asyncRoutes, userRouterList);
            commit('SET_ROUTES', accessedRoutes)
            commit('SET_ROUTER_STATE', true)
            resolve(accessedRoutes)
        })
    },
    removeRouterState({commit}) {
        commit('SET_ROUTER_STATE', false);
    }
}

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

    這個js文件的主要作用就是把後端返回的路由和前端配置的完整路由進行比較,取相同部分的路由。只擁有賬單管理的用戶如下圖:
在這裏插入圖片描述    擁有權限管理和賬單管理的用戶如下圖:
在這裏插入圖片描述
    至此,完成了不同角色用戶不同菜單(路由)的功能,我們只需要在後臺管理系統給角色分配路由的權限就能實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章