Files
TakeoutSaaS.TenantUI/apps/web-antd/src/router/access.ts

139 lines
3.6 KiB
TypeScript

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 };