Merge branch 'main' into example

This commit is contained in:
Soybean
2024-11-17 22:34:18 +08:00
20 changed files with 863 additions and 796 deletions

View File

@@ -10,26 +10,33 @@ export function setupAppErrorHandle(app: App) {
};
}
// Update check interval in milliseconds
const UPDATE_CHECK_INTERVAL = 3 * 60 * 1000;
export function setupAppVersionNotification() {
const canAutoUpdateApp = import.meta.env.VITE_AUTOMATICALLY_DETECT_UPDATE === 'Y';
if (!canAutoUpdateApp) return;
let isShow = false;
let updateInterval: ReturnType<typeof setInterval> | undefined;
document.addEventListener('visibilitychange', async () => {
const preConditions = [!isShow, document.visibilityState === 'visible', !import.meta.env.DEV];
// Check if updates should be checked
const shouldCheckForUpdates = [!isShow, document.visibilityState === 'visible', !import.meta.env.DEV].every(Boolean);
if (!preConditions.every(Boolean)) return;
const checkForUpdates = async () => {
if (!shouldCheckForUpdates) return;
const buildTime = await getHtmlBuildTime();
// If build time hasn't changed, no update is needed
if (buildTime === BUILD_TIME) {
return;
}
isShow = true;
// Show update notification
const n = window.$notification?.create({
title: $t('system.updateTitle'),
content: $t('system.updateContent'),
@@ -60,11 +67,34 @@ export function setupAppVersionNotification() {
isShow = false;
}
});
});
};
const startUpdateInterval = () => {
if (updateInterval) {
clearInterval(updateInterval);
}
updateInterval = setInterval(checkForUpdates, UPDATE_CHECK_INTERVAL);
};
// If updates should be checked, set up the visibility change listener and start the update interval
if (shouldCheckForUpdates) {
// Check for updates when the document is visible
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
checkForUpdates();
startUpdateInterval();
}
});
// Start the update interval
startUpdateInterval();
}
}
async function getHtmlBuildTime() {
const res = await fetch(`/index.html?time=${Date.now()}`);
const baseUrl = import.meta.env.VITE_BASE_URL || '/';
const res = await fetch(`${baseUrl}index.html?time=${Date.now()}`);
const html = await res.text();

View File

@@ -36,54 +36,34 @@ export function createRouteGuard(router: Router) {
const routeRoles = to.meta.roles || [];
const hasRole = authStore.userInfo.roles.some(role => routeRoles.includes(role));
const hasAuth = authStore.isStaticSuper || !routeRoles.length || hasRole;
const routeSwitches: CommonType.StrategicPattern[] = [
// if it is login route when logged in, then switch to the root page
{
condition: isLogin && to.name === loginRoute,
callback: () => {
next({ name: rootRoute });
}
},
// if it is constant route, then it is allowed to access directly
{
condition: !needLogin,
callback: () => {
handleRouteSwitch(to, from, next);
}
},
// if the route need login but the user is not logged in, then switch to the login page
{
condition: !isLogin && needLogin,
callback: () => {
next({ name: loginRoute, query: { redirect: to.fullPath } });
}
},
// if the user is logged in and has authorization, then it is allowed to access
{
condition: isLogin && needLogin && hasAuth,
callback: () => {
handleRouteSwitch(to, from, next);
}
},
// if the user is logged in but does not have authorization, then switch to the 403 page
{
condition: isLogin && needLogin && !hasAuth,
callback: () => {
next({ name: noAuthorizationRoute });
}
}
];
// if it is login route when logged in, then switch to the root page
if (to.name === loginRoute && isLogin) {
next({ name: rootRoute });
return;
}
routeSwitches.some(({ condition, callback }) => {
if (condition) {
callback();
}
// if the route does not need login, then it is allowed to access directly
if (!needLogin) {
handleRouteSwitch(to, from, next);
return;
}
return condition;
});
// the route need login but the user is not logged in, then switch to the login page
if (!isLogin) {
next({ name: loginRoute, query: { redirect: to.fullPath } });
return;
}
// if the user is logged in but does not have authorization, then switch to the 403 page
if (!hasAuth) {
next({ name: noAuthorizationRoute });
return;
}
// switch route normally
handleRouteSwitch(to, from, next);
});
}
@@ -93,7 +73,6 @@ export function createRouteGuard(router: Router) {
* @param to to route
*/
async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw | null> {
const authStore = useAuthStore();
const routeStore = useRouteStore();
const notFoundRoute: RouteKey = 'not-found';
@@ -105,8 +84,48 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
// the route is captured by the "not-found" route because the constant route is not initialized
// after the constant route is initialized, redirect to the original route
const path = to.fullPath;
const location: RouteLocationRaw = {
path,
replace: true,
query: to.query,
hash: to.hash
};
return location;
}
const isLogin = Boolean(localStg.get('token'));
if (!isLogin) {
// if the user is not logged in and the route is a constant route but not the "not-found" route, then it is allowed to access.
if (to.meta.constant && !isNotFoundRoute) {
routeStore.onRouteSwitchWhenNotLoggedIn();
return null;
}
// if the user is not logged in, then switch to the login page
const loginRoute: RouteKey = 'login';
const query = getRouteQueryOfLoginRoute(to, routeStore.routeHome);
const location: RouteLocationRaw = {
name: loginRoute,
query
};
return location;
}
if (!routeStore.isInitAuthRoute) {
// initialize the auth route
await routeStore.initAuthRoute();
// the route is captured by the "not-found" route because the auth route is not initialized
// after the auth route is initialized, redirect to the original route
if (isNotFoundRoute) {
const path = to.fullPath;
const rootRoute: RouteKey = 'root';
const path = to.redirectedFrom?.name === rootRoute ? '/' : to.fullPath;
const location: RouteLocationRaw = {
path,
@@ -119,63 +138,21 @@ async function initRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
}
}
// if the route is the constant route but is not the "not-found" route, then it is allowed to access.
if (to.meta.constant && !isNotFoundRoute) {
return null;
}
// the auth route is initialized
// it is not the "not-found" route, then it is allowed to access
if (routeStore.isInitAuthRoute && !isNotFoundRoute) {
if (!isNotFoundRoute) {
routeStore.onRouteSwitchWhenLoggedIn();
return null;
}
// it is captured by the "not-found" route, then check whether the route exists
if (routeStore.isInitAuthRoute && isNotFoundRoute) {
const exist = await routeStore.getIsAuthRouteExist(to.path as RoutePath);
const noPermissionRoute: RouteKey = '403';
if (exist) {
const location: RouteLocationRaw = {
name: noPermissionRoute
};
return location;
}
return null;
}
// if the auth route is not initialized, then initialize the auth route
const isLogin = Boolean(localStg.get('token'));
// initialize the auth route requires the user to be logged in, if not, redirect to the login page
if (!isLogin) {
const loginRoute: RouteKey = 'login';
const query = getRouteQueryOfLoginRoute(to, routeStore.routeHome);
const exist = await routeStore.getIsAuthRouteExist(to.path as RoutePath);
const noPermissionRoute: RouteKey = '403';
if (exist) {
const location: RouteLocationRaw = {
name: loginRoute,
query
};
return location;
}
await authStore.initUserInfo();
// initialize the auth route
await routeStore.initAuthRoute();
// the route is captured by the "not-found" route because the auth route is not initialized
// after the auth route is initialized, redirect to the original route
if (isNotFoundRoute) {
const rootRoute: RouteKey = 'root';
const path = to.redirectedFrom?.name === rootRoute ? '/' : to.fullPath;
const location: RouteLocationRaw = {
path,
replace: true,
query: to.query,
hash: to.hash
name: noPermissionRoute
};
return location;

View File

@@ -310,6 +310,14 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
return getSelectedMenuKeyPathByKey(selectedKey, menus.value);
}
async function onRouteSwitchWhenLoggedIn() {
authStore.initUserInfo();
}
async function onRouteSwitchWhenNotLoggedIn() {
// some global init logic if it does not need to be logged in
}
return {
resetStore,
routeHome,
@@ -326,6 +334,8 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
isInitAuthRoute,
setIsInitAuthRoute,
getIsAuthRouteExist,
getSelectedMenuKeyPath
getSelectedMenuKeyPath,
onRouteSwitchWhenLoggedIn,
onRouteSwitchWhenNotLoggedIn
};
});