chore: code format

This commit is contained in:
xiaojunnuo
2025-06-29 14:09:09 +08:00
parent 04422a4637
commit 4fcfd089d8
644 changed files with 10845 additions and 13184 deletions
@@ -1,86 +1,77 @@
import { describe, expect, it } from 'vitest';
import { describe, expect, it } from "vitest";
import { findMenuByPath, findRootMenuByPath } from '../find-menu-by-path';
import { findMenuByPath, findRootMenuByPath } from "../find-menu-by-path";
// 示例菜单数据
const menus: any[] = [
{ path: '/', children: [] },
{ path: '/about', children: [] },
{ path: "/", children: [] },
{ path: "/about", children: [] },
{
path: '/contact',
path: "/contact",
children: [
{ path: '/contact/email', children: [] },
{ path: '/contact/phone', children: [] },
{ path: "/contact/email", children: [] },
{ path: "/contact/phone", children: [] },
],
},
{
path: '/services',
path: "/services",
children: [
{ path: '/services/design', children: [] },
{ path: "/services/design", children: [] },
{
path: '/services/development',
children: [{ path: '/services/development/web', children: [] }],
path: "/services/development",
children: [{ path: "/services/development/web", children: [] }],
},
],
},
];
describe('menu Finder Tests', () => {
it('finds a top-level menu', () => {
const menu = findMenuByPath(menus, '/about');
describe("menu Finder Tests", () => {
it("finds a top-level menu", () => {
const menu = findMenuByPath(menus, "/about");
expect(menu).toBeDefined();
expect(menu?.path).toBe('/about');
expect(menu?.path).toBe("/about");
});
it('finds a nested menu', () => {
const menu = findMenuByPath(menus, '/services/development/web');
it("finds a nested menu", () => {
const menu = findMenuByPath(menus, "/services/development/web");
expect(menu).toBeDefined();
expect(menu?.path).toBe('/services/development/web');
expect(menu?.path).toBe("/services/development/web");
});
it('returns null for a non-existent path', () => {
const menu = findMenuByPath(menus, '/non-existent');
it("returns null for a non-existent path", () => {
const menu = findMenuByPath(menus, "/non-existent");
expect(menu).toBeNull();
});
it('handles empty menus list', () => {
const menu = findMenuByPath([], '/about');
it("handles empty menus list", () => {
const menu = findMenuByPath([], "/about");
expect(menu).toBeNull();
});
it('handles menu items without children', () => {
const menu = findMenuByPath(
[{ path: '/only', children: undefined }] as any[],
'/only',
);
it("handles menu items without children", () => {
const menu = findMenuByPath([{ path: "/only", children: undefined }] as any[], "/only");
expect(menu).toBeDefined();
expect(menu?.path).toBe('/only');
expect(menu?.path).toBe("/only");
});
it('finds root menu by path', () => {
const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(
menus,
'/services/development/web',
);
it("finds root menu by path", () => {
const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(menus, "/services/development/web");
expect(findMenu).toBeDefined();
expect(rootMenu).toBeUndefined();
expect(rootMenuPath).toBeUndefined();
expect(findMenu?.path).toBe('/services/development/web');
expect(findMenu?.path).toBe("/services/development/web");
});
it('returns null for undefined or empty path', () => {
it("returns null for undefined or empty path", () => {
const menuUndefinedPath = findMenuByPath(menus);
const menuEmptyPath = findMenuByPath(menus, '');
const menuEmptyPath = findMenuByPath(menus, "");
expect(menuUndefinedPath).toBeNull();
expect(menuEmptyPath).toBeNull();
});
it('checks for root menu when path does not exist', () => {
const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(
menus,
'/non-existent',
);
it("checks for root menu when path does not exist", () => {
const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath(menus, "/non-existent");
expect(findMenu).toBeNull();
expect(rootMenu).toBeUndefined();
expect(rootMenuPath).toBeUndefined();
@@ -1,30 +1,30 @@
import type { Router, RouteRecordRaw } from 'vue-router';
import type { Router, RouteRecordRaw } from "vue-router";
import { createRouter, createWebHistory } from 'vue-router';
import { createRouter, createWebHistory } from "vue-router";
import { describe, expect, it, vi } from 'vitest';
import { describe, expect, it, vi } from "vitest";
import { generateMenus } from '../generate-menus';
import { generateMenus } from "../generate-menus";
// Nested route setup to test child inclusion and hideChildrenInMenu functionality
describe('generateMenus', () => {
describe("generateMenus", () => {
// 模拟路由数据
const mockRoutes = [
{
meta: { icon: 'home-icon', title: '首页' },
name: 'home',
path: '/home',
meta: { icon: "home-icon", title: "首页" },
name: "home",
path: "/home",
},
{
meta: { hideChildrenInMenu: true, icon: 'about-icon', title: '关于' },
name: 'about',
path: '/about',
meta: { hideChildrenInMenu: true, icon: "about-icon", title: "关于" },
name: "about",
path: "/about",
children: [
{
path: 'team',
name: 'team',
meta: { icon: 'team-icon', title: '团队' },
path: "team",
name: "team",
meta: { icon: "team-icon", title: "团队" },
},
],
},
@@ -33,24 +33,24 @@ describe('generateMenus', () => {
// 模拟 Vue 路由器实例
const mockRouter = {
getRoutes: vi.fn(() => [
{ name: 'home', path: '/home' },
{ name: 'about', path: '/about' },
{ name: 'team', path: '/about/team' },
{ name: "home", path: "/home" },
{ name: "about", path: "/about" },
{ name: "team", path: "/about/team" },
]),
};
it('the correct menu list should be generated according to the route', async () => {
it("the correct menu list should be generated according to the route", async () => {
const expectedMenus = [
{
badge: undefined,
badgeType: undefined,
badgeVariants: undefined,
icon: 'home-icon',
name: '首页',
icon: "home-icon",
name: "首页",
order: undefined,
parent: undefined,
parents: undefined,
path: '/home',
path: "/home",
show: true,
children: [],
},
@@ -58,12 +58,12 @@ describe('generateMenus', () => {
badge: undefined,
badgeType: undefined,
badgeVariants: undefined,
icon: 'about-icon',
name: '关于',
icon: "about-icon",
name: "关于",
order: undefined,
parent: undefined,
parents: undefined,
path: '/about',
path: "/about",
show: true,
children: [],
},
@@ -73,12 +73,12 @@ describe('generateMenus', () => {
expect(menus).toEqual(expectedMenus);
});
it('includes additional meta properties in menu items', async () => {
it("includes additional meta properties in menu items", async () => {
const mockRoutesWithMeta = [
{
meta: { icon: 'user-icon', order: 1, title: 'Profile' },
name: 'profile',
path: '/profile',
meta: { icon: "user-icon", order: 1, title: "Profile" },
name: "profile",
path: "/profile",
},
] as RouteRecordRaw[];
@@ -88,24 +88,24 @@ describe('generateMenus', () => {
badge: undefined,
badgeType: undefined,
badgeVariants: undefined,
icon: 'user-icon',
name: 'Profile',
icon: "user-icon",
name: "Profile",
order: 1,
parent: undefined,
parents: undefined,
path: '/profile',
path: "/profile",
show: true,
children: [],
},
]);
});
it('handles dynamic route parameters correctly', async () => {
it("handles dynamic route parameters correctly", async () => {
const mockRoutesWithParams = [
{
meta: { icon: 'details-icon', title: 'User Details' },
name: 'userDetails',
path: '/users/:userId',
meta: { icon: "details-icon", title: "User Details" },
name: "userDetails",
path: "/users/:userId",
},
] as RouteRecordRaw[];
@@ -115,36 +115,33 @@ describe('generateMenus', () => {
badge: undefined,
badgeType: undefined,
badgeVariants: undefined,
icon: 'details-icon',
name: 'User Details',
icon: "details-icon",
name: "User Details",
order: undefined,
parent: undefined,
parents: undefined,
path: '/users/:userId',
path: "/users/:userId",
show: true,
children: [],
},
]);
});
it('processes routes with redirects correctly', async () => {
it("processes routes with redirects correctly", async () => {
const mockRoutesWithRedirect = [
{
name: 'redirectedRoute',
path: '/old-path',
redirect: '/new-path',
name: "redirectedRoute",
path: "/old-path",
redirect: "/new-path",
},
{
meta: { icon: 'path-icon', title: 'New Path' },
name: 'newPath',
path: '/new-path',
meta: { icon: "path-icon", title: "New Path" },
name: "newPath",
path: "/new-path",
},
] as RouteRecordRaw[];
const menus = await generateMenus(
mockRoutesWithRedirect,
mockRouter as any,
);
const menus = await generateMenus(mockRoutesWithRedirect, mockRouter as any);
expect(menus).toEqual([
// Assuming your generateMenus function excludes redirect routes from the menu
{
@@ -152,11 +149,11 @@ describe('generateMenus', () => {
badgeType: undefined,
badgeVariants: undefined,
icon: undefined,
name: 'redirectedRoute',
name: "redirectedRoute",
order: undefined,
parent: undefined,
parents: undefined,
path: '/old-path',
path: "/old-path",
show: true,
children: [],
},
@@ -164,12 +161,12 @@ describe('generateMenus', () => {
badge: undefined,
badgeType: undefined,
badgeVariants: undefined,
icon: 'path-icon',
name: 'New Path',
icon: "path-icon",
name: "New Path",
order: undefined,
parent: undefined,
parents: undefined,
path: '/new-path',
path: "/new-path",
show: true,
children: [],
},
@@ -178,14 +175,14 @@ describe('generateMenus', () => {
const routes: any = [
{
meta: { order: 2, title: 'Home' },
name: 'home',
path: '/',
meta: { order: 2, title: "Home" },
name: "home",
path: "/",
},
{
meta: { order: 1, title: 'About' },
name: 'about',
path: '/about',
meta: { order: 1, title: "About" },
name: "about",
path: "/about",
},
];
@@ -194,7 +191,7 @@ describe('generateMenus', () => {
routes,
});
it('should generate menu list with correct order', async () => {
it("should generate menu list with correct order", async () => {
const menus = await generateMenus(routes, router);
const expectedMenus = [
{
@@ -202,11 +199,11 @@ describe('generateMenus', () => {
badgeType: undefined,
badgeVariants: undefined,
icon: undefined,
name: 'About',
name: "About",
order: 1,
parent: undefined,
parents: undefined,
path: '/about',
path: "/about",
show: true,
children: [],
},
@@ -215,11 +212,11 @@ describe('generateMenus', () => {
badgeType: undefined,
badgeVariants: undefined,
icon: undefined,
name: 'Home',
name: "Home",
order: 2,
parent: undefined,
parents: undefined,
path: '/',
path: "/",
show: true,
children: [],
},
@@ -228,7 +225,7 @@ describe('generateMenus', () => {
expect(menus).toEqual(expectedMenus);
});
it('should handle empty routes', async () => {
it("should handle empty routes", async () => {
const emptyRoutes: any[] = [];
const menus = await generateMenus(emptyRoutes, router);
expect(menus).toEqual([]);
@@ -1,105 +1,93 @@
import type { RouteRecordRaw } from 'vue-router';
import type { RouteRecordRaw } from "vue-router";
import { describe, expect, it } from 'vitest';
import { describe, expect, it } from "vitest";
import {
generateRoutesByFrontend,
hasAuthority,
} from '../generate-routes-frontend';
import { generateRoutesByFrontend, hasAuthority } from "../generate-routes-frontend";
// Mock 路由数据
const mockRoutes = [
{
meta: {
authority: ['admin', 'user'],
authority: ["admin", "user"],
hideInMenu: false,
},
path: '/dashboard',
path: "/dashboard",
children: [
{
path: '/dashboard/overview',
meta: { authority: ['admin'], hideInMenu: false },
path: "/dashboard/overview",
meta: { authority: ["admin"], hideInMenu: false },
},
{
path: '/dashboard/stats',
meta: { authority: ['user'], hideInMenu: true },
path: "/dashboard/stats",
meta: { authority: ["user"], hideInMenu: true },
},
],
},
{
meta: { authority: ['admin'], hideInMenu: false },
path: '/settings',
meta: { authority: ["admin"], hideInMenu: false },
path: "/settings",
},
{
meta: { hideInMenu: false },
path: '/profile',
path: "/profile",
},
] as RouteRecordRaw[];
describe('hasAuthority', () => {
it('should return true if there is no authority defined', () => {
expect(hasAuthority(mockRoutes[2], ['admin'])).toBe(true);
describe("hasAuthority", () => {
it("should return true if there is no authority defined", () => {
expect(hasAuthority(mockRoutes[2], ["admin"])).toBe(true);
});
it('should return true if the user has the required authority', () => {
expect(hasAuthority(mockRoutes[0], ['admin'])).toBe(true);
it("should return true if the user has the required authority", () => {
expect(hasAuthority(mockRoutes[0], ["admin"])).toBe(true);
});
it('should return false if the user does not have the required authority', () => {
expect(hasAuthority(mockRoutes[1], ['user'])).toBe(false);
it("should return false if the user does not have the required authority", () => {
expect(hasAuthority(mockRoutes[1], ["user"])).toBe(false);
});
});
describe('generateRoutesByFrontend', () => {
it('should handle routes without children', async () => {
const generatedRoutes = await generateRoutesByFrontend(mockRoutes, [
'user',
]);
describe("generateRoutesByFrontend", () => {
it("should handle routes without children", async () => {
const generatedRoutes = await generateRoutesByFrontend(mockRoutes, ["user"]);
expect(generatedRoutes).toEqual(
expect.arrayContaining([
expect.objectContaining({
path: '/profile', // This route has no children and should be included
path: "/profile", // This route has no children and should be included
}),
]),
])
);
});
it('should handle empty roles array', async () => {
it("should handle empty roles array", async () => {
const generatedRoutes = await generateRoutesByFrontend(mockRoutes, []);
expect(generatedRoutes).toEqual(
expect.arrayContaining([
// Only routes without authority should be included
expect.objectContaining({
path: '/profile',
path: "/profile",
}),
]),
])
);
expect(generatedRoutes).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
path: '/dashboard',
path: "/dashboard",
}),
expect.objectContaining({
path: '/settings',
path: "/settings",
}),
]),
])
);
});
it('should handle missing meta fields', async () => {
it("should handle missing meta fields", async () => {
const routesWithMissingMeta = [
{ path: '/path1' }, // No meta
{ meta: {}, path: '/path2' }, // Empty meta
{ meta: { authority: ['admin'] }, path: '/path3' }, // Only authority
{ path: "/path1" }, // No meta
{ meta: {}, path: "/path2" }, // Empty meta
{ meta: { authority: ["admin"] }, path: "/path3" }, // Only authority
];
const generatedRoutes = await generateRoutesByFrontend(
routesWithMissingMeta as RouteRecordRaw[],
['admin'],
);
expect(generatedRoutes).toEqual([
{ path: '/path1' },
{ meta: {}, path: '/path2' },
{ meta: { authority: ['admin'] }, path: '/path3' },
]);
const generatedRoutes = await generateRoutesByFrontend(routesWithMissingMeta as RouteRecordRaw[], ["admin"]);
expect(generatedRoutes).toEqual([{ path: "/path1" }, { meta: {}, path: "/path2" }, { meta: { authority: ["admin"] }, path: "/path3" }]);
});
});
@@ -1,29 +1,29 @@
import type { RouteRecordRaw } from 'vue-router';
import type { RouteRecordRaw } from "vue-router";
import type { RouteModuleType } from '../merge-route-modules';
import type { RouteModuleType } from "../merge-route-modules";
import { describe, expect, it } from 'vitest';
import { describe, expect, it } from "vitest";
import { mergeRouteModules } from '../merge-route-modules';
import { mergeRouteModules } from "../merge-route-modules";
describe('mergeRouteModules', () => {
it('should merge route modules correctly', () => {
describe("mergeRouteModules", () => {
it("should merge route modules correctly", () => {
const routeModules: Record<string, RouteModuleType> = {
'./dynamic-routes/about.ts': {
"./dynamic-routes/about.ts": {
default: [
{
component: () => Promise.resolve({ template: '<div>About</div>' }),
name: 'About',
path: '/about',
component: () => Promise.resolve({ template: "<div>About</div>" }),
name: "About",
path: "/about",
},
],
},
'./dynamic-routes/home.ts': {
"./dynamic-routes/home.ts": {
default: [
{
component: () => Promise.resolve({ template: '<div>Home</div>' }),
name: 'Home',
path: '/',
component: () => Promise.resolve({ template: "<div>Home</div>" }),
name: "Home",
path: "/",
},
],
},
@@ -32,13 +32,13 @@ describe('mergeRouteModules', () => {
const expectedRoutes: RouteRecordRaw[] = [
{
component: expect.any(Function),
name: 'About',
path: '/about',
name: "About",
path: "/about",
},
{
component: expect.any(Function),
name: 'Home',
path: '/',
name: "Home",
path: "/",
},
];
@@ -46,7 +46,7 @@ describe('mergeRouteModules', () => {
expect(mergedRoutes).toEqual(expectedRoutes);
});
it('should handle empty modules', () => {
it("should handle empty modules", () => {
const routeModules: Record<string, RouteModuleType> = {};
const expectedRoutes: RouteRecordRaw[] = [];
@@ -54,9 +54,9 @@ describe('mergeRouteModules', () => {
expect(mergedRoutes).toEqual(expectedRoutes);
});
it('should handle modules with no default export', () => {
it("should handle modules with no default export", () => {
const routeModules: Record<string, RouteModuleType> = {
'./dynamic-routes/empty.ts': {
"./dynamic-routes/empty.ts": {
default: [],
},
};
@@ -21,11 +21,11 @@ function findMenuByPath(list: MenuRecordRaw[], path?: string): MenuRecordRaw | n
function findRootMenuByPath(menus: MenuRecordRaw[], path?: string, level = 0) {
const findMenu = findMenuByPath(menus, path);
const rootMenuPath = findMenu?.parents?.[level];
const rootMenu = rootMenuPath ? menus.find((item) => item.path === rootMenuPath) : undefined;
const rootMenu = rootMenuPath ? menus.find(item => item.path === rootMenuPath) : undefined;
return {
findMenu,
rootMenu,
rootMenuPath
rootMenuPath,
};
}
@@ -29,7 +29,7 @@ async function generateMenus(routes: RouteRecordRaw[], router: Router): Promise<
// 将菜单的所有父级和父级菜单记录到菜单项内
if (resultChildren && resultChildren.length > 0) {
resultChildren.forEach((child) => {
resultChildren.forEach(child => {
child.parents = [...(route.parents || []), path];
child.parent = path;
});
@@ -49,14 +49,14 @@ async function generateMenus(routes: RouteRecordRaw[], router: Router): Promise<
path: resultPath as string,
show: !route?.meta?.hideInMenu && route?.meta?.isMenu !== false,
children: resultChildren || [],
meta: route.meta
meta: route.meta,
};
});
// 对菜单进行排序
menus = sortBy(menus, (item: any) => item.order ?? 0);
const finalMenus = filterTree(menus, (menu) => {
const finalMenus = filterTree(menus, menu => {
return !!menu.show;
});
return finalMenus;
@@ -32,7 +32,7 @@ async function generateRoutesByBackend(options: GenerateMenuAndRoutesOptions): P
}
function convertRoutes(routes: RouteRecordStringComponent[], layoutMap: ComponentRecordType, pageMap: ComponentRecordType): RouteRecordRaw[] {
return mapTree(routes, (node) => {
return mapTree(routes, node => {
const route = node as unknown as RouteRecordRaw;
const { component, name } = node;
@@ -7,7 +7,7 @@ import { filterTree, mapTree } from "/@/vben/shared/utils";
*/
async function generateRoutesByFrontend(routes: RouteRecordRaw[], roles: string[], forbiddenComponent?: RouteRecordRaw["component"]): Promise<RouteRecordRaw[]> {
// 根据角色标识过滤路由表,判断当前用户是否拥有指定权限
const finalRoutes = filterTree(routes, (route) => {
const finalRoutes = filterTree(routes, route => {
return hasAuthority(route, roles);
});
@@ -16,7 +16,7 @@ async function generateRoutesByFrontend(routes: RouteRecordRaw[], roles: string[
}
// 如果有禁止访问的页面,将禁止访问的页面替换为403页面
return mapTree(finalRoutes, (route) => {
return mapTree(finalRoutes, route => {
if (menuHasVisibleWithForbidden(route)) {
route.component = forbiddenComponent;
}
@@ -34,7 +34,7 @@ function hasAuthority(route: RouteRecordRaw, access: string[]) {
if (!authority) {
return true;
}
const canAccess = access.some((value) => authority.includes(value));
const canAccess = access.some(value => authority.includes(value));
return canAccess || (!canAccess && menuHasVisibleWithForbidden(route));
}
@@ -4,7 +4,5 @@
* the document body if the element is not provided.
*/
export function getPopupContainer(node?: HTMLElement): HTMLElement {
return (
node?.closest('form') ?? (node?.parentNode as HTMLElement) ?? document.body
);
return node?.closest("form") ?? (node?.parentNode as HTMLElement) ?? document.body;
}
@@ -1,8 +1,8 @@
export * from './find-menu-by-path';
export * from './generate-menus';
export * from './generate-routes-backend';
export * from './generate-routes-frontend';
export * from './get-popup-container';
export * from './merge-route-modules';
export * from './reset-routes';
export * from './unmount-global-loading';
export * from "./find-menu-by-path";
export * from "./generate-menus";
export * from "./generate-routes-backend";
export * from "./generate-routes-frontend";
export * from "./get-popup-container";
export * from "./merge-route-modules";
export * from "./reset-routes";
export * from "./unmount-global-loading";
@@ -1,21 +1,16 @@
import type { Router, RouteRecordName, RouteRecordRaw } from 'vue-router';
import type { Router, RouteRecordName, RouteRecordRaw } from "vue-router";
import { traverseTreeValues } from '/@/vben/shared/utils';
import { traverseTreeValues } from "/@/vben/shared/utils";
/**
* @zh_CN 重置所有路由,如有指定白名单除外
*/
export function resetStaticRoutes(router: Router, routes: RouteRecordRaw[]) {
// 获取静态路由所有节点包含子节点的 name,并排除不存在 name 字段的路由
const staticRouteNames = traverseTreeValues<
RouteRecordRaw,
RouteRecordName | undefined
>(routes, (route) => {
const staticRouteNames = traverseTreeValues<RouteRecordRaw, RouteRecordName | undefined>(routes, route => {
// 这些路由需要指定 name,防止在路由重置时,不能删除没有指定 name 的路由
if (!route.name) {
console.warn(
`The route with the path ${route.path} needs to have the field name specified.`,
);
console.warn(`The route with the path ${route.path} needs to have the field name specified.`);
}
return route.name;
});
@@ -7,25 +7,23 @@
*/
export function unmountGlobalLoading() {
// 查找全局 loading 元素
const loadingElement = document.querySelector('#__app-loading__');
const loadingElement = document.querySelector("#__app-loading__");
if (loadingElement) {
// 添加隐藏类,触发过渡动画
loadingElement.classList.add('hidden');
loadingElement.classList.add("hidden");
// 查找所有需要移除的注入 loading 元素
const injectLoadingElements = document.querySelectorAll(
'[data-app-loading^="inject"]',
);
const injectLoadingElements = document.querySelectorAll('[data-app-loading^="inject"]');
// 当过渡动画结束时,移除 loading 元素和所有注入的 loading 元素
loadingElement.addEventListener(
'transitionend',
"transitionend",
() => {
loadingElement.remove(); // 移除 loading 元素
injectLoadingElements.forEach((el) => el.remove()); // 移除所有注入的 loading 元素
injectLoadingElements.forEach(el => el.remove()); // 移除所有注入的 loading 元素
},
{ once: true },
{ once: true }
); // 确保事件只触发一次
}
}