JinZHouXiYiJi_DaPin2/examples/router/index.ts

217 lines
5.4 KiB
TypeScript

import type {
NavigationGuardNext,
RouteLocationNormalized,
Router,
RouterHistory
} from 'vue-router'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import { LOGIN_URL, NoAuth, RouteMode } from '@/enum'
import { useUserStoreWithOut } from '@/store/modules/user'
import NProgress from '@/utils/progress'
import type { AppRouteRecordRaw, MenuType } from './types'
const userStore = useUserStoreWithOut()
class RouteView {
// 路由对象
private router: Router | undefined = undefined
constructor() {
this.router = this.createRouter()
this.beforeRouteChange()
this.afterRouteChange()
}
// 根据环境变量中的配置生成路由模式
private createHistory = (): RouterHistory => {
if (import.meta.env.VITE_ROUTER_MODE === RouteMode.HISTORY) {
return createWebHistory()
} else {
return createWebHashHistory()
}
}
// 动态获取 modules 目录下的所有 .ts 文件生成基础路由
private createBasicRoutes = (): AppRouteRecordRaw[] => {
const moduleFiles: Record<string, { [key: string]: any }> = import.meta.glob(
'./modules/**/*.ts',
{
eager: true
}
)
const routeModuleList: AppRouteRecordRaw[] = []
Object.keys(moduleFiles).forEach((key) => {
const mod: { [key: string]: any } = moduleFiles[key].default || {}
const modList: AppRouteRecordRaw[] = Array.isArray(mod) ? [...mod] : [mod]
routeModuleList.push(...modList)
})
return routeModuleList
}
// 创建路由对象
private createRouter(): Router {
return createRouter({
history: this.createHistory(),
routes: this.createBasicRoutes(),
strict: true,
scrollBehavior: () => ({ left: 0, top: 0 })
})
}
// 路由守卫
private beforeRouteChange(): void {
if (!this.router) {
return
}
const curRouter = this.router as Router
curRouter.beforeEach((to, _, next) => {
NProgress.start()
// 如果网站不需要登录认证,所有路由直接切换
if (to.meta.ignoreAuth) {
next()
return
}
if (import.meta.env.VITE_APP_NO_AUTH === NoAuth.NO_AUTH) {
next()
} else {
if (this.checkLogin(to)) {
if (this.checkPermission(to)) {
next()
} else {
this.to403(next)
}
} else {
this.toLogin(to, next)
}
}
})
}
/**
* 检查是否认证
* @param to 需要跳转的路由
* @returns 检查结果
*/
private checkLogin(to: RouteLocationNormalized): boolean {
if (to.meta.ignoreAuth) {
return true
} else {
return !!userStore.userToken
}
}
/**
* 检查用户是否有访问权限
* @param _to 需要跳转的路由
* @returns 检查结果
*/
private checkPermission(_to: RouteLocationNormalized): boolean {
return true
}
private toLogin(to: RouteLocationNormalized, next: NavigationGuardNext): void {
next({
path: LOGIN_URL,
query: {
redirect: to.fullPath
}
})
}
private to403(next: NavigationGuardNext): void {
next({
name: '403'
})
}
private afterRouteChange(): void {
if (!this.router) {
return
}
const myRouter = this.router as Router
myRouter.afterEach((to) => {
document.title = (to?.meta?.title as string) || import.meta.env.VITE_APP_TITLE
NProgress.done()
})
}
// 获取所有子路由
private getChildRoutes(route: AppRouteRecordRaw): string[] {
const childList: string[] = []
if (!route.children?.length) {
return childList
}
for (const item of route.children) {
childList.push(item.path)
childList.push(...this.getChildRoutes(item))
}
return childList
}
private getNormalRoutes(): AppRouteRecordRaw[] {
if (!this.router) {
return []
}
// 因为所有路由都是平铺结构,而且路由间的嵌套关系依然存在,因此我们要找到真正的顶层路由,根据嵌套关系显示在菜单中
const routes = this.router?.getRoutes()
const childRoutes: string[] = []
for (const route of routes) {
childRoutes.push(...this.getChildRoutes(route as unknown as AppRouteRecordRaw))
}
// 去重重复路径
const noDuplicatePaths = new Set([...childRoutes])
return routes.filter((route) => {
return !noDuplicatePaths.has(route.path)
}) as unknown as AppRouteRecordRaw[]
}
private formatRouteToMenu(routes: Optional<AppRouteRecordRaw[]>, menus: MenuType[]): void {
if (!routes) {
return
}
const menuRoutes = routes.filter((route) => {
return !route.meta.hideInMenu
})
for (const item of menuRoutes) {
const children: MenuType[] = []
item.children && this.formatRouteToMenu(item.children, children)
menus.push({
name: item.name,
title: item.meta.title,
icon: item.meta.icon ? item.meta.icon : '',
children: children.length ? children : undefined
})
}
}
// 生成路由菜单
public generatorMenu() {
const routes = this.getNormalRoutes()
const menus: MenuType[] = []
this.formatRouteToMenu(routes, menus)
return menus
}
// 获取路由对象
public getRouter(): Router {
return this.router as Router
}
}
const routeView = new RouteView()
export { MenuType, routeView }
export default routeView.getRouter()