oa_front/src/router/router-guards.ts

110 lines
3.8 KiB
TypeScript
Raw Normal View History

2024-02-27 17:22:27 +08:00
import { NavigationFailureType, isNavigationFailure } from 'vue-router';
import NProgress from 'nprogress'; // progress bar
import { LOGIN_NAME, PAGE_NOT_FOUND_NAME, REDIRECT_NAME } from './constant';
import type { WhiteNameList } from './constant';
import type { Router, RouteLocationNormalized } from 'vue-router';
import { useUserStore } from '@/store/modules/user';
import { useKeepAliveStore } from '@/store/modules/keepAlive';
import { ACCESS_TOKEN_KEY } from '@/enums/cacheEnum';
import { Storage } from '@/utils/Storage';
import { to as _to } from '@/utils/awaitTo';
NProgress.configure({ showSpinner: false }); // NProgress Configuration
const defaultRoutePath = '/dashboard/welcome';
export function createRouterGuards(router: Router, whiteNameList: WhiteNameList) {
router.beforeEach(async (to, _, next) => {
NProgress.start(); // start progress bar
const userStore = useUserStore();
const token = Storage.get(ACCESS_TOKEN_KEY, null);
if (token) {
if (to.name === LOGIN_NAME) {
next({ path: defaultRoutePath });
} else {
const hasRoute = router.hasRoute(to.name!);
if (userStore.menus.length === 0) {
// 从后台获取菜单
const [err] = await _to(userStore.afterLogin());
if (err) {
userStore.resetToken();
return next({ name: LOGIN_NAME });
}
// 解决警告No match found for location with path "XXXXXXX"
if (to.name === PAGE_NOT_FOUND_NAME) {
next({ path: to.fullPath, replace: true });
}
// 如果该路由不存在,可能是动态注册的路由,它还没准备好,需要再重定向一次到该路由
else if (!hasRoute) {
next({ ...to, replace: true });
} else {
next();
}
} else {
next();
}
}
} else {
// not login
if (whiteNameList.some((n) => n === to.name)) {
// 在免登录名单,直接进入
next();
} else {
next({ name: LOGIN_NAME, query: { redirect: to.fullPath }, replace: true });
}
}
});
/** 获取路由对应的组件名称 */
const getComponentName = (route: RouteLocationNormalized) => {
const comp = route.matched.at(-1)?.components?.default;
return comp?.name ?? (comp as any)?.type?.name;
};
router.afterEach((to, from, failure) => {
// 跳过自己手动取消路由导航时的错误
if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
NProgress.done();
// console.error('failed navigation', failure);
return;
}
const keepAliveStore = useKeepAliveStore();
const token = Storage.get(ACCESS_TOKEN_KEY, null);
// 在这里设置需要缓存的组件名称
const toCompName = getComponentName(to);
// 判断当前页面是否开启缓存,如果开启,则将当前页面的 componentName 信息存入 keep-alive 全局状态
if (to.meta?.keepAlive) {
// 需要缓存的组件
if (toCompName) {
keepAliveStore.add(toCompName);
} else {
console.warn(
`${to.fullPath}页面组件的keepAlive为true但未设置组件名会导致缓存失效请检查`,
);
}
} else {
// 不需要缓存的组件
if (toCompName) {
keepAliveStore.remove(toCompName);
}
}
// 如果进入的是 Redirect 页面,则也将离开页面的缓存清空(刷新页面的操作)
if (to.name === REDIRECT_NAME) {
const fromCompName = getComponentName(from);
fromCompName && keepAliveStore.remove(fromCompName);
}
// 如果用户已登出,则清空所有缓存的组件
if (!token) {
keepAliveStore.clear();
}
NProgress.done(); // finish progress bar
});
router.onError((error) => {
console.error('路由错误', error);
});
}