227 lines
7.8 KiB
TypeScript
227 lines
7.8 KiB
TypeScript
|
|
import type { Router, RouteRecordRaw } from 'vue-router'
|
|||
|
|
import { useNProgress } from '@vueuse/integrations/useNProgress'
|
|||
|
|
import { asyncRoutes, asyncRoutesByFilesystem } from './routes'
|
|||
|
|
import '@/assets/styles/nprogress.css'
|
|||
|
|
|
|||
|
|
function setupRoutes(router: Router) {
|
|||
|
|
router.beforeEach(async (to, _from, next) => {
|
|||
|
|
const settingsStore = useSettingsStore()
|
|||
|
|
const userStore = useUserStore()
|
|||
|
|
const routeStore = useRouteStore()
|
|||
|
|
const menuStore = useMenuStore()
|
|||
|
|
// 是否已登录
|
|||
|
|
if (userStore.isLogin) {
|
|||
|
|
// 是否已根据权限动态生成并注册路由
|
|||
|
|
if (routeStore.isGenerate) {
|
|||
|
|
// 导航栏如果不是 single 模式,则需要根据 path 定位主导航的选中状态
|
|||
|
|
settingsStore.settings.menu.mode !== 'single' && menuStore.setActived(to.path)
|
|||
|
|
// 如果已登录状态下,进入登录页会强制跳转到主页
|
|||
|
|
if (to.name === 'login') {
|
|||
|
|
next({
|
|||
|
|
path: settingsStore.settings.home.fullPath,
|
|||
|
|
replace: true,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
// 如果未开启主页,但进入的是主页,则会进入侧边栏导航第一个模块
|
|||
|
|
else if (!settingsStore.settings.home.enable && to.fullPath === settingsStore.settings.home.fullPath) {
|
|||
|
|
if (menuStore.sidebarMenus.length > 0) {
|
|||
|
|
next({
|
|||
|
|
path: menuStore.sidebarMenusFirstDeepestPath,
|
|||
|
|
replace: true,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
// 如果侧边栏导航第一个模块均无法命中,则还是进入主页
|
|||
|
|
else {
|
|||
|
|
next()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 正常访问页面
|
|||
|
|
else {
|
|||
|
|
next()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
try {
|
|||
|
|
// 获取用户权限
|
|||
|
|
settingsStore.settings.app.enablePermission && await userStore.getPermissions()
|
|||
|
|
// 生成动态路由
|
|||
|
|
switch (settingsStore.settings.app.routeBaseOn) {
|
|||
|
|
case 'frontend':
|
|||
|
|
routeStore.generateRoutesAtFront(asyncRoutes)
|
|||
|
|
break
|
|||
|
|
case 'backend':
|
|||
|
|
await routeStore.generateRoutesAtBack()
|
|||
|
|
break
|
|||
|
|
case 'filesystem':
|
|||
|
|
routeStore.generateRoutesAtFilesystem(asyncRoutesByFilesystem)
|
|||
|
|
// 文件系统生成的路由,需要手动生成导航数据
|
|||
|
|
switch (settingsStore.settings.menu.baseOn) {
|
|||
|
|
case 'frontend':
|
|||
|
|
menuStore.generateMenusAtFront()
|
|||
|
|
break
|
|||
|
|
case 'backend':
|
|||
|
|
await menuStore.generateMenusAtBack()
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
// 注册并记录路由数据
|
|||
|
|
// 记录的数据会在登出时会使用到,不使用 router.removeRoute 是考虑配置的路由可能不一定有设置 name ,则通过调用 router.addRoute() 返回的回调进行删除
|
|||
|
|
const removeRoutes: (() => void)[] = []
|
|||
|
|
routeStore.routes.forEach((route) => {
|
|||
|
|
if (!/^(?:https?:|mailto:|tel:)/.test(route.path)) {
|
|||
|
|
removeRoutes.push(router.addRoute(route as RouteRecordRaw))
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
if (settingsStore.settings.app.routeBaseOn !== 'filesystem') {
|
|||
|
|
routeStore.systemRoutes.forEach((route) => {
|
|||
|
|
removeRoutes.push(router.addRoute(route as RouteRecordRaw))
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
routeStore.setCurrentRemoveRoutes(removeRoutes)
|
|||
|
|
}
|
|||
|
|
catch {
|
|||
|
|
userStore.logout()
|
|||
|
|
}
|
|||
|
|
// 动态路由生成并注册后,重新进入当前路由
|
|||
|
|
next({
|
|||
|
|
path: to.path,
|
|||
|
|
query: to.query,
|
|||
|
|
replace: true,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
if (to.name !== 'login') {
|
|||
|
|
next({
|
|||
|
|
name: 'login',
|
|||
|
|
query: {
|
|||
|
|
redirect: to.fullPath !== settingsStore.settings.home.fullPath ? to.fullPath : undefined,
|
|||
|
|
},
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
next()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 当父级路由未配置重定向时,自动重定向到有访问权限的子路由
|
|||
|
|
function setupRedirectAuthChildrenRoute(router: Router) {
|
|||
|
|
router.beforeEach((to, _from, next) => {
|
|||
|
|
const { auth } = useAuth()
|
|||
|
|
const currentRoute = router.getRoutes().find(route => route.path === (to.matched.at(-1)?.path ?? ''))
|
|||
|
|
if (!currentRoute?.redirect) {
|
|||
|
|
const findAuthRoute = currentRoute?.children?.find(route => route.meta?.menu !== false && auth(route.meta?.auth ?? ''))
|
|||
|
|
if (findAuthRoute) {
|
|||
|
|
next(findAuthRoute)
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
next()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
next()
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 进度条
|
|||
|
|
function setupProgress(router: Router) {
|
|||
|
|
const { isLoading } = useNProgress()
|
|||
|
|
router.beforeEach((_to, _from, next) => {
|
|||
|
|
const settingsStore = useSettingsStore()
|
|||
|
|
if (settingsStore.settings.app.enableProgress) {
|
|||
|
|
isLoading.value = true
|
|||
|
|
}
|
|||
|
|
next()
|
|||
|
|
})
|
|||
|
|
router.afterEach(() => {
|
|||
|
|
const settingsStore = useSettingsStore()
|
|||
|
|
if (settingsStore.settings.app.enableProgress) {
|
|||
|
|
isLoading.value = false
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 标题
|
|||
|
|
function setupTitle(router: Router) {
|
|||
|
|
router.afterEach((to) => {
|
|||
|
|
const settingsStore = useSettingsStore()
|
|||
|
|
if (settingsStore.settings.app.routeBaseOn !== 'filesystem') {
|
|||
|
|
settingsStore.setTitle(to.matched?.at(-1)?.meta?.title ?? to.meta.title)
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
settingsStore.setTitle(to.meta.title)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 页面缓存
|
|||
|
|
function setupKeepAlive(router: Router) {
|
|||
|
|
router.afterEach(async (to, from) => {
|
|||
|
|
const keepAliveStore = useKeepAliveStore()
|
|||
|
|
if (to.fullPath !== from.fullPath) {
|
|||
|
|
if (to.meta.cache) {
|
|||
|
|
const componentName = to.matched.at(-1)?.components?.default.name
|
|||
|
|
if (componentName) {
|
|||
|
|
// 缓存当前页面前,先判断是否需要进行清除缓存,判断依据:
|
|||
|
|
// 1. 如果 to.meta.cache 为 boolean 类型,并且不为 true,则需要清除缓存
|
|||
|
|
// 2. 如果 to.meta.cache 为 string 类型,并且与 from.name 不一致,则需要清除缓存
|
|||
|
|
// 3. 如果 to.meta.cache 为 array 类型,并且不包含 from.name,则需要清除缓存
|
|||
|
|
// 4. 如果 to.meta.noCache 为 string 类型,并且与 from.name 一致,则需要清除缓存
|
|||
|
|
// 5. 如果 to.meta.noCache 为 array 类型,并且包含 from.name,则需要清除缓存
|
|||
|
|
// 6. 如果是刷新页面,则需要清除缓存
|
|||
|
|
let shouldClearCache = false
|
|||
|
|
if (typeof to.meta.cache === 'boolean') {
|
|||
|
|
shouldClearCache = !to.meta.cache
|
|||
|
|
}
|
|||
|
|
else if (typeof to.meta.cache === 'string') {
|
|||
|
|
shouldClearCache = to.meta.cache !== from.name
|
|||
|
|
}
|
|||
|
|
else if (Array.isArray(to.meta.cache)) {
|
|||
|
|
shouldClearCache = !to.meta.cache.includes(from.name as string)
|
|||
|
|
}
|
|||
|
|
if (to.meta.noCache) {
|
|||
|
|
if (typeof to.meta.noCache === 'string') {
|
|||
|
|
shouldClearCache = to.meta.noCache === from.name
|
|||
|
|
}
|
|||
|
|
else if (Array.isArray(to.meta.noCache)) {
|
|||
|
|
shouldClearCache = to.meta.noCache.includes(from.name as string)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (from.name === 'reload') {
|
|||
|
|
shouldClearCache = true
|
|||
|
|
}
|
|||
|
|
if (shouldClearCache) {
|
|||
|
|
keepAliveStore.remove(componentName)
|
|||
|
|
await nextTick()
|
|||
|
|
}
|
|||
|
|
keepAliveStore.add(componentName)
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
// turbo-console-disable-next-line
|
|||
|
|
console.warn('[Fantastic-admin] 该页面组件未设置组件名,会导致缓存失效,请检查')
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 其他
|
|||
|
|
function setupOther(router: Router) {
|
|||
|
|
router.afterEach(() => {
|
|||
|
|
document.documentElement.scrollTop = 0
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default function setupGuards(router: Router) {
|
|||
|
|
setupRoutes(router)
|
|||
|
|
setupRedirectAuthChildrenRoute(router)
|
|||
|
|
setupProgress(router)
|
|||
|
|
setupTitle(router)
|
|||
|
|
setupKeepAlive(router)
|
|||
|
|
setupOther(router)
|
|||
|
|
}
|