@peng_kai/kit 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +41 -0
- package/admin/components/filter/index.ts +5 -0
- package/admin/{filter → components/filter/src}/FilterDrawer.vue +12 -9
- package/admin/{filter → components/filter/src}/FilterParam.vue +15 -15
- package/admin/{filter → components/filter/src}/FilterReset.vue +7 -4
- package/admin/{filter → components/filter/src}/useFilterParams.ts +9 -9
- package/admin/{filter → components/filter/src}/useFilterQuery.ts +11 -11
- package/admin/components/scroll-nav/index.ts +1 -1
- package/admin/components/scroll-nav/src/ScrollNav.vue +9 -9
- package/admin/components/text/index.ts +6 -6
- package/admin/components/text/src/Amount.vue +22 -19
- package/admin/components/text/src/Datetime.vue +12 -12
- package/admin/components/text/src/Duration.vue +13 -13
- package/admin/components/text/src/Hash.vue +13 -11
- package/admin/components/text/src/createTagGetter.ts +7 -7
- package/admin/defines/index.ts +4 -5
- package/admin/defines/page/definePage.ts +12 -0
- package/admin/defines/page/index.ts +1 -0
- package/admin/defines/route/defineRoute.ts +14 -0
- package/admin/defines/route/getRoutes.ts +84 -0
- package/admin/defines/route/helpers.ts +49 -0
- package/admin/defines/route/index.ts +73 -0
- package/admin/defines/route-guard/defineRouteGuard.ts +18 -0
- package/admin/defines/route-guard/getRouteGuards.ts +40 -0
- package/admin/defines/route-guard/index.ts +2 -0
- package/admin/defines/startup/defineStartup.ts +11 -0
- package/admin/defines/startup/getStartups.ts +30 -0
- package/admin/defines/startup/index.ts +2 -0
- package/admin/hooks/index.ts +5 -6
- package/admin/hooks/useMenu.ts +48 -48
- package/admin/hooks/usePage.ts +67 -65
- package/admin/hooks/usePageTab.ts +17 -17
- package/admin/layout/large/Breadcrumb.vue +15 -16
- package/admin/layout/large/Content.vue +4 -4
- package/admin/layout/large/Menu.vue +20 -19
- package/admin/layout/large/PageTab.vue +4 -4
- package/admin/layout/large/index.ts +4 -4
- package/admin/permission/index.ts +4 -0
- package/admin/permission/routerGuard.ts +43 -0
- package/admin/permission/usePermission.ts +52 -0
- package/admin/permission/vuePlugin.ts +30 -0
- package/admin/route-guards/index.ts +2 -0
- package/admin/route-guards/pageProgress.ts +16 -0
- package/admin/route-guards/pageTitle.ts +24 -0
- package/admin/types/assist.ts +10 -0
- package/admin/unocss/index.ts +1 -1
- package/antd/components/InputNumberRange.vue +21 -15
- package/antd/directives/formLabelAlign.ts +28 -23
- package/antd/hooks/createAntdModal.ts +29 -29
- package/antd/hooks/useAntdDrawer.ts +31 -31
- package/antd/hooks/useAntdForm.helpers.ts +18 -18
- package/antd/hooks/useAntdForm.ts +38 -37
- package/antd/hooks/useAntdModal.ts +25 -25
- package/antd/hooks/useAntdTable.ts +22 -22
- package/antd/hooks/useAntdTheme.ts +86 -0
- package/antd/index.ts +8 -7
- package/eslint.config.js +50 -0
- package/kitDependencies.ts +21 -7
- package/package.json +22 -16
- package/pnpm-lock.yaml +2147 -56
- package/request/helpers.ts +30 -13
- package/request/index.ts +2 -2
- package/request/interceptors/checkCode.ts +8 -8
- package/request/interceptors/filterEmptyValue.ts +9 -9
- package/request/interceptors/formatPaging.ts +12 -12
- package/request/interceptors/index.ts +7 -6
- package/request/interceptors/popupMessage.ts +35 -35
- package/request/interceptors/returnResultType.ts +19 -19
- package/request/interceptors/toLogin.ts +13 -0
- package/request/interceptors/unitizeAxiosError.ts +7 -7
- package/request/queryClient.ts +42 -0
- package/request/request.ts +21 -21
- package/request/type.d.ts +18 -18
- package/tsconfig.json +41 -12
- package/utils/index.ts +59 -31
- package/vue/components/index.ts +1 -0
- package/{components → vue/components}/infinite-query/index.ts +1 -1
- package/{components → vue/components}/infinite-query/src/InfiniteQuery.vue +29 -29
- package/{components → vue/components}/infinite-query/src/useCreateTrigger.ts +13 -13
- package/vue/hooks/useComponentRef.ts +12 -12
- package/vue/hooks/useIsMounted.ts +4 -4
- package/vue/hooks/useTeleportTarget.ts +7 -7
- package/vue/index.ts +4 -3
- package/admin/defines/definePage.ts +0 -14
- package/admin/defines/defineRoute.helpers.ts +0 -37
- package/admin/defines/defineRoute.ts +0 -161
- package/admin/defines/defineRouteGuard.ts +0 -56
- package/admin/defines/defineStartup.ts +0 -41
- package/admin/filter/index.ts +0 -5
- package/admin/hooks/usePermission.ts +0 -5
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { RouteRecordRaw } from 'vue-router';
|
|
2
|
+
import merge from 'lodash-es/merge';
|
|
3
|
+
import { ENV } from '../../../utils';
|
|
4
|
+
import { RouteSymbol } from './defineRoute';
|
|
5
|
+
|
|
6
|
+
export { getRoutes };
|
|
7
|
+
|
|
8
|
+
/** 获取路由 */
|
|
9
|
+
async function getRoutes() {
|
|
10
|
+
const routeFileRE = /\/([A-Za-z0-9-]+.)?route\.ts$/;
|
|
11
|
+
const routeFiles = Object.fromEntries(
|
|
12
|
+
Object.entries(getRoutes.modules).filter(([n]) => routeFileRE.test(n)),
|
|
13
|
+
) as Record<string, Function>;
|
|
14
|
+
let routes: RouteRecordRaw[] = [];
|
|
15
|
+
|
|
16
|
+
for (const name in routeFiles) {
|
|
17
|
+
const module: any = await routeFiles[name]();
|
|
18
|
+
|
|
19
|
+
if (Object.hasOwn(module?.default ?? {}, RouteSymbol))
|
|
20
|
+
Array.prototype.push.apply(routes, module.default());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 处理路由
|
|
24
|
+
routes = meregeDefaultRouteParams(routes);
|
|
25
|
+
routes = sortRoute(routes);
|
|
26
|
+
|
|
27
|
+
// 输出路由
|
|
28
|
+
if (!ENV.isProd) {
|
|
29
|
+
console.groupCollapsed('一级路由');
|
|
30
|
+
console.table(
|
|
31
|
+
routes.map(route => ({ order: route.meta?.order, ...route })),
|
|
32
|
+
['order', 'name', 'path'],
|
|
33
|
+
);
|
|
34
|
+
console.groupEnd();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return routes;
|
|
38
|
+
}
|
|
39
|
+
getRoutes.modules = {} as any;
|
|
40
|
+
|
|
41
|
+
/** 给路由填充默认参数 */
|
|
42
|
+
const defaultRouteParams: Partial<RouteRecordRaw> = {
|
|
43
|
+
meta: {
|
|
44
|
+
title: '标题',
|
|
45
|
+
icon: undefined,
|
|
46
|
+
order: 10,
|
|
47
|
+
requireAuth: true,
|
|
48
|
+
keepAlive: false,
|
|
49
|
+
hiddenTab: false,
|
|
50
|
+
pageKeyFn: route => route.path,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function meregeDefaultRouteParams(routes: RouteRecordRaw[], parentRoute?: RouteRecordRaw) {
|
|
55
|
+
const _routes: typeof routes = [];
|
|
56
|
+
|
|
57
|
+
for (const route of routes) {
|
|
58
|
+
if (route.children?.length)
|
|
59
|
+
route.children = meregeDefaultRouteParams(route.children, route);
|
|
60
|
+
|
|
61
|
+
const newRoute = merge({}, defaultRouteParams, route);
|
|
62
|
+
const { menuOrder } = newRoute.meta!;
|
|
63
|
+
|
|
64
|
+
// 处理 menuOrder
|
|
65
|
+
if (typeof menuOrder === 'string')
|
|
66
|
+
newRoute.meta!.menuOrder = menuOrder.replace('..', (parentRoute?.name ?? '') as string);
|
|
67
|
+
|
|
68
|
+
_routes.push(newRoute);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return _routes;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 给路由排序 */
|
|
75
|
+
function sortRoute(routes: RouteRecordRaw[]) {
|
|
76
|
+
const _routes = routes.sort((r1, r2) => Number(r2?.meta?.order) - Number(r1?.meta?.order));
|
|
77
|
+
|
|
78
|
+
for (const route of _routes) {
|
|
79
|
+
if (route.children?.length)
|
|
80
|
+
route.children = sortRoute(route.children);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return _routes;
|
|
84
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RouteLocationNormalizedLoaded, Router } from 'vue-router';
|
|
2
|
+
|
|
3
|
+
export function getTitle(route?: Pick<RouteLocationNormalizedLoaded, 'meta'>) {
|
|
4
|
+
const mTitle = route?.meta?.title;
|
|
5
|
+
|
|
6
|
+
return typeof mTitle === 'function' ? mTitle() : mTitle;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getMenusByRouter(router: Router) {
|
|
10
|
+
const menuOrderRE = /^(?<key>\w*)@(?<order>\d+)$/;
|
|
11
|
+
const routes = router.getRoutes();
|
|
12
|
+
const menus = routes
|
|
13
|
+
.filter(route => menuOrderRE.test((route.meta.menuOrder ?? '')))
|
|
14
|
+
.map((route) => {
|
|
15
|
+
const res = route.meta!.menuOrder!.match(menuOrderRE);
|
|
16
|
+
const parentKey = res?.groups?.key;
|
|
17
|
+
const order = Number(res?.groups?.order);
|
|
18
|
+
const name = route.name as string;
|
|
19
|
+
const menu = {
|
|
20
|
+
key: name,
|
|
21
|
+
label: route.meta.title ?? name,
|
|
22
|
+
icon: route.meta.icon,
|
|
23
|
+
trigger: () => router.push({ name }),
|
|
24
|
+
order,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return { parentKey, menu };
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// 将含有子菜单的菜单的 trigger 设置为空函数
|
|
31
|
+
const hasSubMenus = menus.filter(menu => menus.some(m => m.parentKey === menu.menu.key));
|
|
32
|
+
hasSubMenus.forEach((menu) => {
|
|
33
|
+
menu.menu.trigger = (() => {}) as any;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return menus;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function printRounesNameInterface(routes: { name: PropertyKey }[]) {
|
|
40
|
+
console.groupCollapsed('路由命名');
|
|
41
|
+
console.log('复制以下内容到 AppRouteNames');
|
|
42
|
+
const routesName = new Set();
|
|
43
|
+
routes.forEach((route) => {
|
|
44
|
+
if (typeof route.name === 'string')
|
|
45
|
+
routesName.add(route.name);
|
|
46
|
+
});
|
|
47
|
+
console.log([...routesName.values()].sort().filter(name => !!name).map(name => `${name}: true`).join('\n'));
|
|
48
|
+
console.groupEnd();
|
|
49
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { VNode } from 'vue';
|
|
2
|
+
|
|
3
|
+
export { defineRoute } from './defineRoute';
|
|
4
|
+
export { getRoutes } from './getRoutes';
|
|
5
|
+
export { getTitle, getMenusByRouter, printRounesNameInterface } from './helpers';
|
|
6
|
+
|
|
7
|
+
declare module 'vue-router' {
|
|
8
|
+
interface RouteMeta {
|
|
9
|
+
/**
|
|
10
|
+
* 路由标题
|
|
11
|
+
*
|
|
12
|
+
* @description 可用来作 document.title 和菜单的名称
|
|
13
|
+
*
|
|
14
|
+
* 默认:APP 名称
|
|
15
|
+
*/
|
|
16
|
+
title?: string | (() => string)
|
|
17
|
+
/**
|
|
18
|
+
* 菜单和面包屑对应的图标
|
|
19
|
+
*
|
|
20
|
+
* 默认:`''`
|
|
21
|
+
*/
|
|
22
|
+
icon?: (() => VNode)
|
|
23
|
+
/**
|
|
24
|
+
* 路由添加顺序,仅作用于一级路由
|
|
25
|
+
*
|
|
26
|
+
* 默认:`10`
|
|
27
|
+
*/
|
|
28
|
+
order?: number
|
|
29
|
+
/**
|
|
30
|
+
* 是否需要登录
|
|
31
|
+
*
|
|
32
|
+
* 默认:`false`
|
|
33
|
+
*/
|
|
34
|
+
requireAuth?: boolean
|
|
35
|
+
/**
|
|
36
|
+
* 权限码
|
|
37
|
+
*/
|
|
38
|
+
permissionCode?: string
|
|
39
|
+
/**
|
|
40
|
+
* 缓存页面
|
|
41
|
+
*
|
|
42
|
+
* 默认:`true`
|
|
43
|
+
*/
|
|
44
|
+
keepAlive?: boolean
|
|
45
|
+
/**
|
|
46
|
+
* 菜单排序(越大越前)
|
|
47
|
+
*
|
|
48
|
+
* 格式:[parent]@[order]
|
|
49
|
+
* - `parent`:可选。不填则默认取路由的 name 值,并在作为一级菜单显示
|
|
50
|
+
* - `order`:必选。路由排序,值越小排越前
|
|
51
|
+
*
|
|
52
|
+
* 例子:
|
|
53
|
+
* - `@10`:一级菜单
|
|
54
|
+
* - `..@10`:所在的路由层级的父级菜单,例如父级菜单是 admin,那么`..`就是`admin`
|
|
55
|
+
* - `admin@10`:指定菜单的父级为 `admin`
|
|
56
|
+
*
|
|
57
|
+
* 默认:undefined。不在菜单中显示
|
|
58
|
+
*/
|
|
59
|
+
menuOrder?: string
|
|
60
|
+
/**
|
|
61
|
+
* 是否隐藏标签页
|
|
62
|
+
*
|
|
63
|
+
* 默认:`false`
|
|
64
|
+
*/
|
|
65
|
+
hiddenTab?: boolean
|
|
66
|
+
/**
|
|
67
|
+
* 用于生成页面运行时的 key
|
|
68
|
+
*
|
|
69
|
+
* 默认:取 route 对象中 path 值
|
|
70
|
+
*/
|
|
71
|
+
pageKeyFn?: (route: RouteLocationNormalizedLoaded) => string
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Router } from 'vue-router';
|
|
2
|
+
|
|
3
|
+
export interface IGuardConfig {
|
|
4
|
+
/** 路由守卫添加顺序(升序加载) */
|
|
5
|
+
order?: number
|
|
6
|
+
setup: (router: Router) => void
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// 路由守卫标识
|
|
10
|
+
export const RouteGuardSymbol = Symbol('app-route-guard');
|
|
11
|
+
|
|
12
|
+
// 定义路由守卫
|
|
13
|
+
export function defineRouteGuard(guard: IGuardConfig) {
|
|
14
|
+
(guard as any)[RouteGuardSymbol] = true;
|
|
15
|
+
guard.order ??= 10;
|
|
16
|
+
|
|
17
|
+
return guard;
|
|
18
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ENV } from '../../../utils';
|
|
2
|
+
import { RouteGuardSymbol } from './defineRouteGuard';
|
|
3
|
+
import type { IGuardConfig } from './defineRouteGuard';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 获取路由守卫
|
|
7
|
+
*/
|
|
8
|
+
export async function getRouteGuards() {
|
|
9
|
+
const routeGuardFileRE = /\/([A-Za-z0-9-]+.)?route-guard\.ts$/;
|
|
10
|
+
const routeGuardFiles = Object.fromEntries(
|
|
11
|
+
Object.entries(getRouteGuards.modules).filter(([n]) => routeGuardFileRE.test(n)),
|
|
12
|
+
) as Record<string, Function>;
|
|
13
|
+
const routeGuards: Array<IGuardConfig> = [];
|
|
14
|
+
const routeGuardRecord: { file: string, order: number }[] = [];
|
|
15
|
+
|
|
16
|
+
for (const name in routeGuardFiles) {
|
|
17
|
+
const module: any = await routeGuardFiles[name]();
|
|
18
|
+
|
|
19
|
+
if (Object.hasOwn(module?.default ?? {}, RouteGuardSymbol)) {
|
|
20
|
+
const guard = module.default;
|
|
21
|
+
|
|
22
|
+
routeGuards.push(guard);
|
|
23
|
+
routeGuardRecord.push({ file: name, order: guard.order });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 处理路由守卫
|
|
28
|
+
routeGuards.sort((g1, g2) => Number(g2.order) - Number(g1.order));
|
|
29
|
+
routeGuardRecord.sort((g1, g2) => Number(g2.order) - Number(g1.order));
|
|
30
|
+
|
|
31
|
+
// 输出路由守卫
|
|
32
|
+
if (!ENV.isProd) {
|
|
33
|
+
console.groupCollapsed('路由守卫');
|
|
34
|
+
console.table(routeGuardRecord, ['order', 'file']);
|
|
35
|
+
console.groupEnd();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return routeGuards;
|
|
39
|
+
}
|
|
40
|
+
getRouteGuards.modules = {} as any;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { App } from 'vue';
|
|
2
|
+
|
|
3
|
+
export type StartupFn = (app: App) => void | Promise<void>;
|
|
4
|
+
|
|
5
|
+
export const StartupSymbol = Symbol('app-startup');
|
|
6
|
+
|
|
7
|
+
export function defineStartup(startup: StartupFn) {
|
|
8
|
+
(startup as any)[StartupSymbol] = true;
|
|
9
|
+
|
|
10
|
+
return startup;
|
|
11
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ENV } from '../../../utils';
|
|
2
|
+
import { StartupSymbol } from './defineStartup';
|
|
3
|
+
import type { StartupFn } from './defineStartup';
|
|
4
|
+
|
|
5
|
+
export async function getStartups() {
|
|
6
|
+
const moduleLoaders = getStartups.modules as Record<string, Function>;
|
|
7
|
+
const startupPaths: string[] = [];
|
|
8
|
+
const startups: Array<StartupFn> = [];
|
|
9
|
+
|
|
10
|
+
for (const [path, moduleLoader] of Object.entries(moduleLoaders)) {
|
|
11
|
+
const module: any = await moduleLoader();
|
|
12
|
+
const plugin: StartupFn = module?.default ?? {};
|
|
13
|
+
|
|
14
|
+
if (!Object.hasOwn(plugin, StartupSymbol))
|
|
15
|
+
continue;
|
|
16
|
+
|
|
17
|
+
startupPaths.push(path);
|
|
18
|
+
startups.push(plugin);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 输出 App 插件
|
|
22
|
+
if (!ENV.isProd) {
|
|
23
|
+
console.groupCollapsed('启动时');
|
|
24
|
+
console.table(startupPaths.map(path => ({ path })), ['path']);
|
|
25
|
+
console.groupEnd();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return startups;
|
|
29
|
+
}
|
|
30
|
+
getStartups.modules = {} as any;
|
package/admin/hooks/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
export { usePage } from './usePage'
|
|
2
|
-
export type { TPageState, IBreadcrumb } from './usePage'
|
|
3
|
-
export { useMenu } from './useMenu'
|
|
4
|
-
export type { TMenu } from './useMenu'
|
|
5
|
-
export { usePageTab } from './usePageTab'
|
|
6
|
-
export { usePermission } from './usePermission'
|
|
1
|
+
export { usePage } from './usePage';
|
|
2
|
+
export type { TPageState, IBreadcrumb } from './usePage';
|
|
3
|
+
export { useMenu } from './useMenu';
|
|
4
|
+
export type { TMenu } from './useMenu';
|
|
5
|
+
export { usePageTab } from './usePageTab';
|
package/admin/hooks/useMenu.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createGlobalState } from '@vueuse/core'
|
|
2
|
-
import { reactive, ref
|
|
3
|
-
import type { UnwrapNestedRefs, VNode
|
|
1
|
+
import { createGlobalState } from '@vueuse/core';
|
|
2
|
+
import { computed, reactive, ref } from 'vue';
|
|
3
|
+
import type { Ref, UnwrapNestedRefs, VNode } from 'vue';
|
|
4
4
|
|
|
5
|
-
export { useMenu }
|
|
6
|
-
export type { TMenu }
|
|
5
|
+
export { useMenu };
|
|
6
|
+
export type { TMenu };
|
|
7
7
|
|
|
8
8
|
interface IMenuConfig {
|
|
9
9
|
key: string
|
|
@@ -23,61 +23,61 @@ interface IMenuReactive {
|
|
|
23
23
|
children?: IMenuReactive[]
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
type TMenu = UnwrapNestedRefs<IMenuReactive
|
|
26
|
+
type TMenu = UnwrapNestedRefs<IMenuReactive>;
|
|
27
27
|
|
|
28
28
|
const useMenu = createGlobalState(() => {
|
|
29
|
-
const menus = reactive<TMenu[]>([])
|
|
30
|
-
const collapsed = ref(false)
|
|
29
|
+
const menus = reactive<TMenu[]>([]);
|
|
30
|
+
const collapsed = ref(false);
|
|
31
31
|
|
|
32
32
|
const findMenu = (menus: TMenu[], key: string) => {
|
|
33
|
-
const queue = [...menus]
|
|
33
|
+
const queue = [...menus];
|
|
34
34
|
|
|
35
35
|
while (queue.length > 0) {
|
|
36
|
-
const menu = queue.shift()
|
|
36
|
+
const menu = queue.shift()!;
|
|
37
37
|
|
|
38
38
|
if (menu.key === key)
|
|
39
|
-
return menu
|
|
39
|
+
return menu;
|
|
40
40
|
|
|
41
41
|
if (menu.children)
|
|
42
|
-
queue.push(...menu.children)
|
|
42
|
+
queue.push(...menu.children);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
return undefined
|
|
46
|
-
}
|
|
45
|
+
return undefined;
|
|
46
|
+
};
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* 获取目标路由的路径
|
|
50
50
|
* @param key 目标路由
|
|
51
51
|
*/
|
|
52
52
|
const getMenuPath = (key: string) => {
|
|
53
|
-
const path: TMenu[] = []
|
|
53
|
+
const path: TMenu[] = [];
|
|
54
54
|
|
|
55
55
|
const _getMenuPath = (menus: TMenu[], key: string) => {
|
|
56
56
|
for (const menu of menus) {
|
|
57
57
|
if (menu.key === key) {
|
|
58
|
-
path.push(menu)
|
|
59
|
-
return true
|
|
58
|
+
path.push(menu);
|
|
59
|
+
return true;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (menu.children) {
|
|
63
|
-
path.push(menu)
|
|
63
|
+
path.push(menu);
|
|
64
64
|
if (_getMenuPath(menu.children, key))
|
|
65
|
-
return true
|
|
66
|
-
path.pop()
|
|
65
|
+
return true;
|
|
66
|
+
path.pop();
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
return false
|
|
71
|
-
}
|
|
70
|
+
return false;
|
|
71
|
+
};
|
|
72
72
|
|
|
73
|
-
_getMenuPath(menus, key)
|
|
73
|
+
_getMenuPath(menus, key);
|
|
74
74
|
|
|
75
|
-
return path
|
|
76
|
-
}
|
|
75
|
+
return path;
|
|
76
|
+
};
|
|
77
77
|
|
|
78
78
|
const addMenu = (menuConfig: IMenuConfig, parentKey?: string) => {
|
|
79
|
-
const labelGetter = typeof menuConfig.label === 'function' ? menuConfig.label : (() => menuConfig.label) as (() => string)
|
|
80
|
-
const iconGetter = typeof menuConfig.icon === 'function' ? menuConfig.icon : () => null
|
|
79
|
+
const labelGetter = typeof menuConfig.label === 'function' ? menuConfig.label : (() => menuConfig.label) as (() => string);
|
|
80
|
+
const iconGetter = typeof menuConfig.icon === 'function' ? menuConfig.icon : () => null;
|
|
81
81
|
|
|
82
82
|
const _menu = reactive<IMenuReactive>({
|
|
83
83
|
key: menuConfig.key,
|
|
@@ -85,44 +85,44 @@ const useMenu = createGlobalState(() => {
|
|
|
85
85
|
icon: computed(iconGetter),
|
|
86
86
|
trigger: menuConfig.trigger,
|
|
87
87
|
order: menuConfig.order,
|
|
88
|
-
})
|
|
88
|
+
});
|
|
89
89
|
|
|
90
90
|
if (parentKey) {
|
|
91
|
-
const parentMenu = findMenu(menus, parentKey)
|
|
91
|
+
const parentMenu = findMenu(menus, parentKey);
|
|
92
92
|
|
|
93
93
|
if (!parentMenu)
|
|
94
|
-
return
|
|
94
|
+
return;
|
|
95
95
|
|
|
96
|
-
const children = reactive(parentMenu.children ?? [])
|
|
97
|
-
children.push(_menu)
|
|
98
|
-
children.sort((a, b) =>
|
|
99
|
-
parentMenu.children = children
|
|
96
|
+
const children = reactive(parentMenu.children ?? []);
|
|
97
|
+
children.push(_menu);
|
|
98
|
+
children.sort((a, b) => b.order - a.order);
|
|
99
|
+
parentMenu.children = children;
|
|
100
100
|
}
|
|
101
101
|
else {
|
|
102
|
-
menus.push(_menu)
|
|
103
|
-
menus.sort((a, b) =>
|
|
102
|
+
menus.push(_menu);
|
|
103
|
+
menus.sort((a, b) => b.order - a.order);
|
|
104
104
|
}
|
|
105
|
-
}
|
|
105
|
+
};
|
|
106
106
|
|
|
107
107
|
const removeMenu = (key: string) => {
|
|
108
108
|
const _remove = (menus: TMenu[], key: string) => {
|
|
109
109
|
for (let i = 0; i < menus.length; i++) {
|
|
110
|
-
const menu = menus[i]
|
|
110
|
+
const menu = menus[i];
|
|
111
111
|
if (menu.key === key) {
|
|
112
|
-
menus.splice(i, 1)
|
|
113
|
-
return
|
|
112
|
+
menus.splice(i, 1);
|
|
113
|
+
return;
|
|
114
114
|
}
|
|
115
115
|
if (menu.children)
|
|
116
|
-
_remove(menu.children, key)
|
|
116
|
+
_remove(menu.children, key);
|
|
117
117
|
}
|
|
118
|
-
}
|
|
118
|
+
};
|
|
119
119
|
|
|
120
|
-
return _remove(menus, key)
|
|
121
|
-
}
|
|
120
|
+
return _remove(menus, key);
|
|
121
|
+
};
|
|
122
122
|
|
|
123
123
|
const getMenu = (key: string) => {
|
|
124
|
-
return findMenu(menus, key)
|
|
125
|
-
}
|
|
124
|
+
return findMenu(menus, key);
|
|
125
|
+
};
|
|
126
126
|
|
|
127
|
-
return { menus, collapsed, getMenuPath, addMenu, removeMenu, getMenu }
|
|
128
|
-
})
|
|
127
|
+
return { menus, collapsed, getMenuPath, addMenu, removeMenu, getMenu };
|
|
128
|
+
});
|