import type { ComponentRecordType, GenerateMenuAndRoutesOptions, RouteRecordStringComponent, } from '@vben/types'; import { generateAccessible } from '@vben/access'; import { preferences } from '@vben/preferences'; import { message } from 'ant-design-vue'; import { getAllMenusApi } from '#/api'; import { BasicLayout, IFrameView } from '#/layouts'; import { $t } from '#/locales'; const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue'); const PRODUCT_PATH = '/product'; const PRODUCT_DETAIL_PATH = '/product/detail'; const PRODUCT_DETAIL_NAME = 'ProductDetail'; const PRODUCT_LIST_PATH = '/product/list'; async function generateAccess(options: GenerateMenuAndRoutesOptions) { const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue'); const layoutMap: ComponentRecordType = { BasicLayout, IFrameView, }; return await generateAccessible(preferences.app.accessMode, { ...options, fetchMenuListAsync: async () => { message.loading({ content: `${$t('common.loadingMenu')}...`, duration: 1.5, }); const menuList = await getAllMenusApi(); return ensureProductDetailRoute(menuList); }, // 可以指定没有权限跳转403页面 forbiddenComponent, // 如果 route.meta.menuVisibleWithForbidden = true layoutMap, pageMap, }); } function ensureProductDetailRoute( routes: RouteRecordStringComponent[], ): RouteRecordStringComponent[] { const clonedRoutes = cloneMenuRoutes(routes); if (containsRoute(clonedRoutes, PRODUCT_DETAIL_PATH, PRODUCT_DETAIL_NAME)) { return clonedRoutes; } const productRoute = findProductRoute(clonedRoutes); if (!productRoute) { return clonedRoutes; } const productChildren = [...(productRoute.children ?? [])]; const listMeta = productChildren.find( (item) => String(item.path || '').trim() === PRODUCT_LIST_PATH, )?.meta; productChildren.push({ name: PRODUCT_DETAIL_NAME, path: PRODUCT_DETAIL_PATH, component: '/views/product/detail/index.vue', meta: { ...listMeta, title: '商品详情', hideInMenu: true, }, }); productRoute.children = productChildren; return clonedRoutes; } function cloneMenuRoutes( routes: RouteRecordStringComponent[], ): RouteRecordStringComponent[] { return routes.map((route) => ({ ...route, meta: route.meta ? { ...route.meta } : route.meta, children: route.children ? cloneMenuRoutes(route.children) : undefined, })); } function containsRoute( routes: RouteRecordStringComponent[], path: string, name: string, ): boolean { for (const route of routes) { const routePath = String(route.path || '').trim(); const routeName = String(route.name || '').trim(); if (routePath === path || routeName === name) { return true; } if (route.children && containsRoute(route.children, path, name)) { return true; } } return false; } function findProductRoute( routes: RouteRecordStringComponent[], ): null | RouteRecordStringComponent { for (const route of routes) { const routePath = String(route.path || '').trim(); const routeName = String(route.name || '').trim(); const hasProductListChild = (route.children ?? []).some( (item) => String(item.path || '').trim() === PRODUCT_LIST_PATH, ); if ( routePath === PRODUCT_PATH || routeName === 'Product' || hasProductListChild ) { return route; } if (route.children) { const nestedMatch = findProductRoute(route.children); if (nestedMatch) { return nestedMatch; } } } return null; } export { generateAccess };