import { AxiosWrapper } from '@/utils/axios-wrapper' import { UserStore } from '@/store/user' import { cloneDeep, isArray, omit } from 'lodash-es' import NProgress from 'nprogress' import 'nprogress/nprogress.css' import { ElMessageBox } from 'element-plus' import i18n from '@/lang' const whiteList = ['/redirect', '/login', '/401', '/404'] NProgress.configure({ showSpinner: false }) // 进度条 // 检查路由是否存在 const hasNecessaryRoute = (to, router) => { // 将默认注册的路由平铺成一维数组 const routesOneDimensional = toOneDimensional(router.getRoutes()) return routesOneDimensional.find((f) => f.path === to.path) } // 获取用户信息,返回菜单 const getUserMeta = async (token) => { const userStore = UserStore() const axios = new AxiosWrapper() const result = await axios.$get(`/token/tokenView`, null, { headers: { token: token } }) if (result.errcode === 0) { userStore.setUser(result.data) const resetMenusResult = resetMenus(result.data.menus) const storeMenus = toRaw(userStore.menus) if (storeMenus.length <= 0) { userStore.setMenus(resetMenusResult) } return { menus: result.data.menus, errcode: 0 } } return { errmsg: result.errmsg, errcode: result.errcode } } /** * 将路由数组一维化 * @param {Array} routes 路由数组 * @returns 一维路由数组 */ const toOneDimensional = (routes) => { const result = [] for (const r of routes) { const { children = [], ...others } = r result.push(others) if (children.length > 0) result.push(...toOneDimensional(children)) } return result } // 添加路由 const addUserRoutes = async (menus, router) => { return new Promise((resolve, reject) => { // 将用户菜单转换成普通对象 const menuArr = toRaw(menus) // 将用户菜单平铺成一维数组,并将目录过滤出去.目录不需要注册,不是组件 const menuOneDimensional = toOneDimensional(menuArr) // 将默认注册的路由平铺成一维数组 const routesOneDimensional = toOneDimensional(router.getRoutes()) routesRegister(menuOneDimensional, routesOneDimensional, router) resolve() }) } /** * 注册路由 * @param {Array} menus 一维数组菜单 * @param {Array} defaultRoutes 默认路由一维数组 * @param {*} router 路由实例 */ const routesRegister = (menus, defaultRoutes, router) => { // 默认注册位置 const __def = 'Layout' const loadComponent = import.meta.glob('../views/**/*.vue') for (const route of menus) { const { type, route_name, path, component, parent_id } = route if (!path) { console.log(route) } // 检查路由是否已存在,存在跳过 const hasRoute = defaultRoutes.find((f) => f.path === path) if (hasRoute) continue if (type === '0') { // 目录, 默认使用 `/${路由名称}` const route = { path: `/${route_name}`, name: route_name, meta: { title: route_name, type } } router.addRoute(__def, route) } else if (type === '1' || type === '2') { // 菜单 或 子菜单 const route = { path: path, name: route_name, meta: { title: route_name, type }, component: loadComponent[`../views${component}.vue`] } if (parent_id) { const parent = menus.find((f) => f._id === parent_id) if (!parent) continue const pos = parent.route_name router.addRoute(pos, route) // try { // } catch (error) { // console.log(pos, route) // console.error(error) // } } else { router.addRoute(__def, route) } } } } const resetMenus = (menus) => { if (!isArray(menus) || menus.length <= 0) return [] const cMenus = cloneDeep(menus) const result = [] for (const m of cMenus) { const mid = omit(m, ['is_use', 'order_num', 'in_admin_frame']) const { children } = mid if (children) mid.children = resetMenus(children) result.push(mid) } return result } // 注册前置守卫 export const registerBeforeRouter = async (router) => { router.beforeEach(async (to, from, next) => { NProgress.start() //开启进度条 const token = localStorage.getItem('token') NProgress.inc() if (whiteList.includes(to.path)) { next() return } if (token) { NProgress.inc() if (to.path === '/login') next() NProgress.inc() const { menus, errcode, errmsg } = await getUserMeta(token) // 登录信息有问题 if (errcode !== 0) { if (errcode.includes('FRAMEERROR_401')) { await ElMessageBox.alert(errmsg, i18n.global.t('common.user_confirm'), { confirmButtonText: i18n.global.t('common.re_login'), type: 'error' }) next('/login') return } else { await ElMessageBox.alert(errmsg, i18n.global.t('common.user_confirm'), { confirmButtonText: i18n.global.t('common.re_login'), type: 'error' }) location.reload() } } // 菜单格式不正确 if (!menus) { next('/401') return } // 检查目的地路由是否注册 const hasRoute = hasNecessaryRoute(to, router) NProgress.inc() if (hasRoute || to.meta.hidden) { // 注册了直接进入 next() } else { // 没注册就先注册再重定向进入直到进入为止 await addUserRoutes(menus, router) NProgress.inc() next({ ...to, replace: true }) } } else { next('/login') } }) } // 注册路由后置守卫 export const registerAfterRouter = async (router) => { router.afterEach(async (to, form) => { NProgress.done() //完成进度条 if (to.path === '/login') { return } // 请求该页面的权限 }) }