import { nextTick } from 'vue'
|
import NProgress from 'nprogress'
|
import { useSettingStore } from '@/store/modules/setting'
|
import { useUserStore } from '@/store/modules/user'
|
import { useMenuStore } from '@/store/modules/menu'
|
import { setWorktab } from '@/utils/navigation'
|
import { setPageTitle } from '@/utils/router'
|
import { RoutesAlias } from '../routesAlias'
|
import { staticRoutes } from '../routes/staticRoutes'
|
import { loadingService } from '@/utils/ui'
|
import { useCommon } from '@/hooks/core/useCommon'
|
import { useWorktabStore } from '@/store/modules/worktab'
|
import { fetchGetUserInfo } from '@/api/auth'
|
import { ApiStatus } from '@/utils/http/status'
|
import { isHttpError } from '@/utils/http/error'
|
import { RouteRegistry, MenuProcessor, IframeRouteManager, RoutePermissionValidator } from '../core'
|
let routeRegistry = null
|
const menuProcessor = new MenuProcessor()
|
let pendingLoading = false
|
let routeInitFailed = false
|
let routeInitInProgress = false
|
function getPendingLoading() {
|
return pendingLoading
|
}
|
function resetPendingLoading() {
|
pendingLoading = false
|
}
|
function getRouteInitFailed() {
|
return routeInitFailed
|
}
|
function resetRouteInitState() {
|
routeInitFailed = false
|
routeInitInProgress = false
|
}
|
function setupBeforeEachGuard(router) {
|
routeRegistry = new RouteRegistry(router)
|
router.beforeEach(async (to, from, next) => {
|
try {
|
await handleRouteGuard(to, from, next, router)
|
} catch (error) {
|
console.error('[RouteGuard] 路由守卫处理失败:', error)
|
closeLoading()
|
next({ name: 'Exception500' })
|
}
|
})
|
}
|
function closeLoading() {
|
if (pendingLoading) {
|
nextTick(() => {
|
loadingService.hideLoading()
|
pendingLoading = false
|
})
|
}
|
}
|
async function handleRouteGuard(to, from, next, router) {
|
const settingStore = useSettingStore()
|
const userStore = useUserStore()
|
if (settingStore.showNprogress) {
|
NProgress.start()
|
}
|
if (!handleLoginStatus(to, userStore, next)) {
|
return
|
}
|
if (routeInitFailed) {
|
if (to.matched.length > 0) {
|
next()
|
} else {
|
next({ name: 'Exception500', replace: true })
|
}
|
return
|
}
|
if (!routeRegistry?.isRegistered() && userStore.isLogin) {
|
if (routeInitInProgress) {
|
next(false)
|
return
|
}
|
await handleDynamicRoutes(to, next, router)
|
return
|
}
|
if (handleRootPathRedirect(to, next)) {
|
return
|
}
|
if (to.matched.length > 0) {
|
setWorktab(to)
|
setPageTitle(to)
|
next()
|
return
|
}
|
next({ name: 'Exception404' })
|
}
|
function handleLoginStatus(to, userStore, next) {
|
if (userStore.isLogin || to.path === RoutesAlias.Login || isStaticRoute(to.path)) {
|
return true
|
}
|
userStore.logOut()
|
next({
|
name: 'Login',
|
query: { redirect: to.fullPath }
|
})
|
return false
|
}
|
function isStaticRoute(path) {
|
const checkRoute = (routes, targetPath) => {
|
return routes.some((route) => {
|
if (route.name === 'Exception404') {
|
return false
|
}
|
const routePath = route.path
|
const pattern = routePath.replace(/:[^/]+/g, '[^/]+').replace(/\*/g, '.*')
|
const regex = new RegExp(`^${pattern}$`)
|
if (regex.test(targetPath)) {
|
return true
|
}
|
if (route.children && route.children.length > 0) {
|
return checkRoute(route.children, targetPath)
|
}
|
return false
|
})
|
}
|
return checkRoute(staticRoutes, path)
|
}
|
async function handleDynamicRoutes(to, next, router) {
|
routeInitInProgress = true
|
pendingLoading = true
|
loadingService.showLoading()
|
try {
|
await fetchUserInfo()
|
const menuList = await menuProcessor.getMenuList()
|
if (!menuProcessor.validateMenuList(menuList)) {
|
throw new Error('获取菜单列表失败,请重新登录')
|
}
|
routeRegistry?.register(menuList)
|
const menuStore = useMenuStore()
|
menuStore.setMenuList(menuList)
|
menuStore.addRemoveRouteFns(routeRegistry?.getRemoveRouteFns() || [])
|
IframeRouteManager.getInstance().save()
|
useWorktabStore().validateWorktabs(router)
|
if (isStaticRoute(to.path)) {
|
routeInitInProgress = false
|
next({
|
path: to.path,
|
query: to.query,
|
hash: to.hash,
|
replace: true
|
})
|
return
|
}
|
const { homePath } = useCommon()
|
const { path: validatedPath, hasPermission } = RoutePermissionValidator.validatePath(
|
to.path,
|
menuList,
|
homePath.value || '/'
|
)
|
routeInitInProgress = false
|
if (!hasPermission) {
|
closeLoading()
|
console.warn(`[RouteGuard] 用户无权限访问路径: ${to.path},已跳转到首页`)
|
next({
|
path: validatedPath,
|
replace: true
|
})
|
} else {
|
next({
|
path: to.path,
|
query: to.query,
|
hash: to.hash,
|
replace: true
|
})
|
}
|
} catch (error) {
|
console.error('[RouteGuard] 动态路由注册失败:', error)
|
closeLoading()
|
if (isUnauthorizedError(error)) {
|
routeInitInProgress = false
|
next(false)
|
return
|
}
|
routeInitFailed = true
|
routeInitInProgress = false
|
if (isHttpError(error)) {
|
console.error(`[RouteGuard] 错误码: ${error.code}, 消息: ${error.message}`)
|
}
|
next({ name: 'Exception500', replace: true })
|
}
|
}
|
async function fetchUserInfo() {
|
const userStore = useUserStore()
|
const data = await fetchGetUserInfo()
|
userStore.setUserInfo(data)
|
userStore.checkAndClearWorktabs()
|
}
|
function resetRouterState(delay) {
|
setTimeout(() => {
|
routeRegistry?.unregister()
|
IframeRouteManager.getInstance().clear()
|
const menuStore = useMenuStore()
|
menuStore.removeAllDynamicRoutes()
|
menuStore.setMenuList([])
|
resetRouteInitState()
|
}, delay)
|
}
|
function handleRootPathRedirect(to, next) {
|
if (to.path !== '/') {
|
return false
|
}
|
const { homePath } = useCommon()
|
if (homePath.value && homePath.value !== '/') {
|
next({ path: homePath.value, replace: true })
|
return true
|
}
|
return false
|
}
|
function isUnauthorizedError(error) {
|
return isHttpError(error) && error.code === ApiStatus.unauthorized
|
}
|
export {
|
getPendingLoading,
|
getRouteInitFailed,
|
resetPendingLoading,
|
resetRouteInitState,
|
resetRouterState,
|
setupBeforeEachGuard
|
}
|