mirror of https://gitee.com/xiaonuobase/snowy
237 lines
6.3 KiB
JavaScript
237 lines
6.3 KiB
JavaScript
/**
|
||
* Copyright [2022] [https://www.xiaonuo.vip]
|
||
* Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||
* 2.请不要删除和修改Snowy源码头部的版权声明。
|
||
* 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
|
||
* 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
|
||
* 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
|
||
* 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||
*/
|
||
import { createRouter, createWebHistory } from 'vue-router'
|
||
import { notification } from 'ant-design-vue'
|
||
import NProgress from 'nprogress'
|
||
import 'nprogress/nprogress.css'
|
||
import systemRouter from './systemRouter'
|
||
import { afterEach, beforeEach } from './scrollBehavior'
|
||
import whiteListRouters from './whiteList'
|
||
import userRoutes from '@/config/route'
|
||
import tool from '@/utils/tool'
|
||
import { cloneDeep } from 'lodash-es'
|
||
const modules = import.meta.glob('/src/views/**/**.vue')
|
||
import { globalStore, searchStore } from '@/store'
|
||
|
||
// 进度条配置
|
||
NProgress.configure({ showSpinner: false, speed: 500 })
|
||
|
||
// 系统特殊路由
|
||
const routes_404 = [
|
||
{
|
||
path: '/:pathMatch(.*)*',
|
||
hidden: true,
|
||
component: () => import('@/layout/other/404.vue')
|
||
}
|
||
]
|
||
// 系统路由
|
||
const routes = [...systemRouter, ...whiteListRouters, ...routes_404]
|
||
|
||
const router = createRouter({
|
||
history: createWebHistory(),
|
||
routes
|
||
})
|
||
|
||
// 设置标题
|
||
// document.title = sysBaseConfig.SNOWY_SYS_NAME
|
||
|
||
// 判断是否已加载过动态/静态路由
|
||
const isGetRouter = ref(false)
|
||
|
||
// 白名单校验
|
||
const exportWhiteListFromRouter = (router) => {
|
||
const res = []
|
||
for (const item of router) res.push(item.path)
|
||
return res
|
||
}
|
||
const whiteList = exportWhiteListFromRouter(whiteListRouters)
|
||
|
||
router.beforeEach(async (to, from, next) => {
|
||
NProgress.start()
|
||
const store = globalStore()
|
||
|
||
const sysBaseConfig = tool.data.get('SNOWY_SYS_BASE_CONFIG') || store.sysBaseConfig
|
||
// 动态标题
|
||
document.title = to.meta.title
|
||
? `${to.meta.title} - ${sysBaseConfig.SNOWY_SYS_NAME}`
|
||
: `${sysBaseConfig.SNOWY_SYS_NAME}`
|
||
|
||
// 过滤白名单
|
||
if (whiteList.includes(to.path)) {
|
||
next()
|
||
// NProgress.done()
|
||
return false
|
||
}
|
||
|
||
const token = tool.data.get('TOKEN')
|
||
if (to.path === '/login') {
|
||
// 当用户输入了login路由,将其跳转首页即可
|
||
if (token) {
|
||
next({
|
||
path: '/'
|
||
})
|
||
return false
|
||
}
|
||
// 删除路由(替换当前layout路由)
|
||
router.addRoute(routes[0])
|
||
isGetRouter.value = false
|
||
next()
|
||
return false
|
||
} else {
|
||
if (token) {
|
||
// 有token的时候才保存登录之前要访问的页面
|
||
tool.data.set('LAST_VIEWS_PATH', to.fullPath)
|
||
}
|
||
}
|
||
if (!token) {
|
||
next({
|
||
path: '/login'
|
||
})
|
||
return false
|
||
}
|
||
// 整页路由处理
|
||
if (to.meta.fullpage) {
|
||
to.matched = [to.matched[to.matched.length - 1]]
|
||
}
|
||
// 加载动态/静态路由
|
||
if (!isGetRouter.value) {
|
||
const apiMenu = tool.data.get('MENU') || []
|
||
if (apiMenu.length === 0) {
|
||
// 创建默认模块,显示默认菜单
|
||
apiMenu[0] = cloneDeep(userRoutes.module[0])
|
||
}
|
||
const childrenApiMenu = apiMenu[0].children
|
||
apiMenu[0].children = [...childrenApiMenu ? childrenApiMenu : [], ...userRoutes.menu]
|
||
let menuRouter = filterAsyncRouter(apiMenu)
|
||
menuRouter = flatAsyncRoutes(menuRouter)
|
||
menuRouter.forEach((item) => {
|
||
router.addRoute('layout', item)
|
||
})
|
||
|
||
const search_store = searchStore()
|
||
search_store.init(menuRouter)
|
||
isGetRouter.value = true
|
||
next({ ...to, replace: true })
|
||
return false
|
||
}
|
||
beforeEach(to, from)
|
||
next()
|
||
})
|
||
|
||
router.afterEach((to, from) => {
|
||
afterEach(to, from)
|
||
NProgress.done()
|
||
})
|
||
|
||
router.onError((error) => {
|
||
NProgress.done()
|
||
notification.error({
|
||
message: '路由错误',
|
||
description: error.message
|
||
})
|
||
})
|
||
|
||
// 入侵追加自定义方法、对象
|
||
router.getMenu = () => {
|
||
let apiMenu = tool.data.get('MENU') || []
|
||
// 增加固定路由
|
||
if (apiMenu.length === 0) {
|
||
// 创建默认模块,显示默认菜单
|
||
apiMenu[0] = cloneDeep(userRoutes.module[0])
|
||
}
|
||
const childrenApiMenu = apiMenu[0].children
|
||
apiMenu[0].children = [...childrenApiMenu ? childrenApiMenu : [], ...userRoutes.menu]
|
||
return filterUrl(apiMenu)
|
||
}
|
||
|
||
const filterUrl = (map) => {
|
||
const newMap = []
|
||
const traverse = (maps) => {
|
||
maps &&
|
||
maps.forEach((item) => {
|
||
item.meta = item.meta ? item.meta : {}
|
||
// 处理iframe
|
||
if (item.meta.type === 'iframe') {
|
||
item.path = `/${item.name}`
|
||
}
|
||
// 递归循环
|
||
if (item.children && item.children.length > 0) {
|
||
item.children = filterUrl(item.children)
|
||
}
|
||
newMap.push(item)
|
||
})
|
||
}
|
||
traverse(map)
|
||
return newMap
|
||
}
|
||
|
||
// 转换
|
||
const filterAsyncRouter = (routerMap) => {
|
||
const accessedRouters = []
|
||
routerMap.forEach((item) => {
|
||
item.meta = item.meta ? item.meta : {}
|
||
// 处理外部链接特殊路由
|
||
if (item.meta.type === 'iframe') {
|
||
item.meta.url = item.path
|
||
item.path = `/${item.name}`
|
||
}
|
||
// MAP转路由对象
|
||
const route = {
|
||
path: item.path,
|
||
name: item.name,
|
||
meta: item.meta,
|
||
redirect: item.redirect,
|
||
children: item.children ? filterAsyncRouter(item.children) : null,
|
||
component: loadComponent(item.component)
|
||
}
|
||
accessedRouters.push(route)
|
||
})
|
||
return accessedRouters
|
||
}
|
||
const loadComponent = (component) => {
|
||
if (component) {
|
||
if (component.includes('/')) {
|
||
return modules[`/src/views/${component}.vue`]
|
||
}
|
||
return modules[`/src/views/${component}/index.vue`]
|
||
} else {
|
||
return () => import(/* @vite-ignore */ `/src/layout/other/empty.vue`)
|
||
}
|
||
}
|
||
|
||
// 路由扁平化
|
||
const flatAsyncRoutes = (routes, breadcrumb = []) => {
|
||
const res = []
|
||
routes.forEach((route) => {
|
||
const tmp = { ...route }
|
||
if (tmp.children) {
|
||
const childrenBreadcrumb = [...breadcrumb]
|
||
childrenBreadcrumb.push(route)
|
||
const tmpRoute = { ...route }
|
||
tmpRoute.meta.breadcrumb = childrenBreadcrumb
|
||
delete tmpRoute.children
|
||
res.push(tmpRoute)
|
||
const childrenRoutes = flatAsyncRoutes(tmp.children, childrenBreadcrumb)
|
||
childrenRoutes.map((item) => {
|
||
res.push(item)
|
||
})
|
||
} else {
|
||
const tmpBreadcrumb = [...breadcrumb]
|
||
tmpBreadcrumb.push(tmp)
|
||
tmp.meta.breadcrumb = tmpBreadcrumb
|
||
res.push(tmp)
|
||
}
|
||
})
|
||
return res
|
||
}
|
||
|
||
export default router
|