373 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { computed, nextTick, ref, shallowRef } from 'vue';
import type { RouteRecordRaw } from 'vue-router';
import { defineStore } from 'pinia';
import { useBoolean } from '@sa/hooks';
import type { CustomRoute, ElegantConstRoute, LastLevelRouteKey, RouteKey, RouteMap } from '@elegant-router/types';
import { router } from '@/router';
import { fetchGetConstantRoutes, fetchGetUserRoutes } from '@/service/api';
import { SetupStoreId } from '@/enum';
import { createStaticRoutes, getAuthVueRoutes } from '@/router/routes';
import { ROOT_ROUTE } from '@/router/routes/builtin';
import { getRouteName, getRoutePath } from '@/router/elegant/transform';
import { useAuthStore } from '../auth';
import { useTabStore } from '../tab';
import {
filterAuthRoutesByRoles,
getBreadcrumbsByRoute,
getCacheRouteNames,
getGlobalMenusByAuthRoutes,
getSelectedMenuKeyPathByKey,
isRouteExistByRouteName,
sortRoutesByOrder,
transformMenuToSearchMenus,
updateLocaleOfGlobalMenus
} from './shared';
import { log } from 'console';
export const useRouteStore = defineStore(SetupStoreId.Route, () => {
const authStore = useAuthStore();
const tabStore = useTabStore();
const { bool: isInitConstantRoute, setBool: setIsInitConstantRoute } = useBoolean();
const { bool: isInitAuthRoute, setBool: setIsInitAuthRoute } = useBoolean();
/**
* Auth route mode
*
* It recommends to use static mode in the development environment, and use dynamic mode in the production
* environment, if use static mode in development environment, the auth routes will be auto generated by plugin
* "@elegant-router/vue"
*/
const authRouteMode = ref(import.meta.env.VITE_AUTH_ROUTE_MODE);
/** Home route key */
const routeHome = ref(import.meta.env.VITE_ROUTE_HOME);
/**
* Set route home
*
* @param routeKey Route key
*/
function setRouteHome(routeKey: LastLevelRouteKey) {
routeHome.value = routeKey;
}
/** constant routes */
const constantRoutes = shallowRef<ElegantConstRoute[]>([]);
function addConstantRoutes(routes: ElegantConstRoute[]) {
const constantRoutesMap = new Map<string, ElegantConstRoute>([]);
routes.forEach(route => {
constantRoutesMap.set(route.name, route);
});
constantRoutes.value = Array.from(constantRoutesMap.values());
}
/** auth routes */
const authRoutes = shallowRef<ElegantConstRoute[]>([]);
function addAuthRoutes(routes: ElegantConstRoute[]) {
const authRoutesMap = new Map<string, ElegantConstRoute>([]);
routes.forEach(route => {
authRoutesMap.set(route.name, route);
});
authRoutes.value = Array.from(authRoutesMap.values());
}
const removeRouteFns: (() => void)[] = [];
/** Global menus */
const menus = ref<App.Global.Menu[]>([]);
const searchMenus = computed(() => transformMenuToSearchMenus(menus.value));
/** Get global menus */
function getGlobalMenus(routes: ElegantConstRoute[]) {
menus.value = getGlobalMenusByAuthRoutes(routes);
}
/** Update global menus by locale */
function updateGlobalMenusByLocale() {
menus.value = updateLocaleOfGlobalMenus(menus.value);
}
/** Cache routes */
const cacheRoutes = ref<RouteKey[]>([]);
/**
* Exclude cache routes
*
* for reset route cache
*/
const excludeCacheRoutes = ref<RouteKey[]>([]);
/**
* Get cache routes
*
* @param routes Vue routes
*/
function getCacheRoutes(routes: RouteRecordRaw[]) {
cacheRoutes.value = getCacheRouteNames(routes);
}
/**
* Reset route cache
*
* @default router.currentRoute.value.name current route name
* @param routeKey
*/
async function resetRouteCache(routeKey?: RouteKey) {
const routeName = routeKey || (router.currentRoute.value.name as RouteKey);
excludeCacheRoutes.value.push(routeName);
await nextTick();
excludeCacheRoutes.value = [];
}
/** Global breadcrumbs */
const breadcrumbs = computed(() => getBreadcrumbsByRoute(router.currentRoute.value, menus.value));
/** Reset store */
async function resetStore() {
const routeStore = useRouteStore();
routeStore.$reset();
resetVueRoutes();
// after reset store, need to re-init constant route
await initConstantRoute();
}
/** Reset vue routes */
function resetVueRoutes() {
removeRouteFns.forEach(fn => fn());
removeRouteFns.length = 0;
}
/** init constant route */
async function initConstantRoute() {
if (isInitConstantRoute.value) return;
const staticRoute = createStaticRoutes();
if (authRouteMode.value === 'static') {
addConstantRoutes(staticRoute.constantRoutes);
} else {
console.log('cccccccccccc');
addConstantRoutes(staticRoute.constantRoutes);
}
handleConstantAndAuthRoutes();
setIsInitConstantRoute(true);
tabStore.initHomeTab();
}
/** Init auth route */
async function initAuthRoute() {
// check if user info is initialized
if (!authStore.userInfo.userId) {
await authStore.initUserInfo();
}
if (authRouteMode.value === 'static') {
initStaticAuthRoute();
} else {
await initDynamicAuthRoute();
}
tabStore.initHomeTab();
}
/** Init static auth route */
function initStaticAuthRoute() {
const { authRoutes: staticAuthRoutes } = createStaticRoutes();
if (authStore.isStaticSuper) {
addAuthRoutes(staticAuthRoutes);
} else {
const filteredAuthRoutes = filterAuthRoutesByRoles(staticAuthRoutes, authStore.userInfo.roles);
addAuthRoutes(filteredAuthRoutes);
}
handleConstantAndAuthRoutes();
setIsInitAuthRoute(true);
}
/** Init dynamic auth route */
async function initDynamicAuthRoute() {
const { response } = await fetchGetUserRoutes();
// 递归转换路由数据的函数
function transformRoutesData(routes: any[]): ElegantConstRoute[] {
if (!Array.isArray(routes)) return [];
return routes.map(item => {
// 创建新对象,只保留需要的字段
const route: ElegantConstRoute = {
name: item.name,
path: item.url,
component: item.condition,
meta: {
title: item.title,
icon: item.icon,
order: item.weigh,
}
};
// 如果有子路由,递归处理
if (Array.isArray(item.children) && item.children.length > 0) {
route.children = transformRoutesData(item.children);
}
return route;
});
}
// 确保类型兼容的比较
if (response.data.code === '1' || response.data.code === 1) {
// 转换路由数据并舍弃其他字段
const routes = transformRoutesData(Array.isArray(response.data.data) ? response.data.data : []);
console.log('用户菜单',routes);
addAuthRoutes(routes);
handleConstantAndAuthRoutes();
// 获取首页路由如果response中有home属性则使用否则使用第一个路由
//使用数组中name=home那个
const homeRoute = routes.find(item => item.name === 'home')?.name as LastLevelRouteKey;
console.log('homeRoute',homeRoute);
setRouteHome(homeRoute);
handleUpdateRootRouteRedirect(homeRoute);
setIsInitAuthRoute(true);
} else {
// if fetch user routes failed, reset store
authStore.resetStore();
}
}
/** handle constant and auth routes */
function handleConstantAndAuthRoutes() {
const allRoutes = [...constantRoutes.value, ...authRoutes.value];
const sortRoutes = sortRoutesByOrder(allRoutes);
const vueRoutes = getAuthVueRoutes(sortRoutes);
console.log('sortRoutes',vueRoutes);
resetVueRoutes();
addRoutesToVueRouter(vueRoutes);
getGlobalMenus(sortRoutes);
getCacheRoutes(vueRoutes);
}
/**
* Add routes to vue router
*
* @param routes Vue routes
*/
function addRoutesToVueRouter(routes: RouteRecordRaw[]) {
routes.forEach(route => {
const removeFn = router.addRoute(route);
addRemoveRouteFn(removeFn);
});
}
/**
* Add remove route fn
*
* @param fn
*/
function addRemoveRouteFn(fn: () => void) {
removeRouteFns.push(fn);
}
/**
* Update root route redirect when auth route mode is dynamic
*
* @param redirectKey Redirect route key
*/
function handleUpdateRootRouteRedirect(redirectKey: LastLevelRouteKey) {
const redirect = getRoutePath(redirectKey);
if (redirect) {
const rootRoute: CustomRoute = { ...ROOT_ROUTE, redirect };
router.removeRoute(rootRoute.name);
const [rootVueRoute] = getAuthVueRoutes([rootRoute]);
router.addRoute(rootVueRoute);
}
}
/**
* Get is auth route exist
*
* @param routePath Route path
*/
async function getIsAuthRouteExist(routePath: RouteMap[RouteKey]) {
const routeName = getRouteName(routePath);
if (!routeName) {
return false;
}
if (authRouteMode.value === 'static') {
const { authRoutes: staticAuthRoutes } = createStaticRoutes();
return isRouteExistByRouteName(routeName, staticAuthRoutes);
}
//const { data } = await fetchIsRouteExist(routeName);
return false;
}
/**
* Get selected menu key path
*
* @param selectedKey Selected menu key
*/
function getSelectedMenuKeyPath(selectedKey: string) {
return getSelectedMenuKeyPathByKey(selectedKey, menus.value);
}
async function onRouteSwitchWhenLoggedIn() {
await authStore.initUserInfo();
}
async function onRouteSwitchWhenNotLoggedIn() {
// some global init logic if it does not need to be logged in
}
return {
resetStore,
routeHome,
menus,
searchMenus,
updateGlobalMenusByLocale,
cacheRoutes,
excludeCacheRoutes,
resetRouteCache,
breadcrumbs,
initConstantRoute,
isInitConstantRoute,
initAuthRoute,
isInitAuthRoute,
setIsInitAuthRoute,
getIsAuthRouteExist,
getSelectedMenuKeyPath,
onRouteSwitchWhenLoggedIn,
onRouteSwitchWhenNotLoggedIn
};
});