@peng_kai/kit 0.0.14 → 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.
Files changed (91) hide show
  1. package/.vscode/settings.json +41 -0
  2. package/admin/components/filter/index.ts +5 -0
  3. package/admin/{filter → components/filter/src}/FilterDrawer.vue +99 -96
  4. package/admin/{filter → components/filter/src}/FilterParam.vue +76 -76
  5. package/admin/{filter → components/filter/src}/FilterReset.vue +7 -4
  6. package/admin/{filter → components/filter/src}/useFilterParams.ts +9 -9
  7. package/admin/{filter → components/filter/src}/useFilterQuery.ts +11 -11
  8. package/admin/components/scroll-nav/index.ts +1 -1
  9. package/admin/components/scroll-nav/src/ScrollNav.vue +59 -59
  10. package/admin/components/text/index.ts +13 -13
  11. package/admin/components/text/src/Amount.vue +117 -114
  12. package/admin/components/text/src/Datetime.vue +44 -44
  13. package/admin/components/text/src/Duration.vue +26 -26
  14. package/admin/components/text/src/Hash.vue +42 -40
  15. package/admin/components/text/src/createTagGetter.ts +13 -13
  16. package/admin/defines/index.ts +4 -5
  17. package/admin/defines/page/definePage.ts +12 -0
  18. package/admin/defines/page/index.ts +1 -0
  19. package/admin/defines/route/defineRoute.ts +14 -0
  20. package/admin/defines/route/getRoutes.ts +84 -0
  21. package/admin/defines/route/helpers.ts +49 -0
  22. package/admin/defines/route/index.ts +73 -0
  23. package/admin/defines/route-guard/defineRouteGuard.ts +18 -0
  24. package/admin/defines/route-guard/getRouteGuards.ts +40 -0
  25. package/admin/defines/route-guard/index.ts +2 -0
  26. package/admin/defines/startup/defineStartup.ts +11 -0
  27. package/admin/defines/startup/getStartups.ts +30 -0
  28. package/admin/defines/startup/index.ts +2 -0
  29. package/admin/hooks/index.ts +5 -6
  30. package/admin/hooks/useMenu.ts +128 -128
  31. package/admin/hooks/usePage.ts +141 -139
  32. package/admin/hooks/usePageTab.ts +35 -35
  33. package/admin/layout/large/Breadcrumb.vue +69 -70
  34. package/admin/layout/large/Content.vue +24 -24
  35. package/admin/layout/large/Menu.vue +69 -68
  36. package/admin/layout/large/PageTab.vue +71 -71
  37. package/admin/layout/large/index.ts +4 -4
  38. package/admin/permission/index.ts +4 -0
  39. package/admin/permission/routerGuard.ts +43 -0
  40. package/admin/permission/usePermission.ts +52 -0
  41. package/admin/permission/vuePlugin.ts +30 -0
  42. package/admin/route-guards/index.ts +2 -0
  43. package/admin/route-guards/pageProgress.ts +16 -0
  44. package/admin/route-guards/pageTitle.ts +24 -0
  45. package/admin/styles/globalCover.scss +43 -43
  46. package/admin/types/assist.ts +10 -0
  47. package/admin/unocss/index.ts +1 -1
  48. package/antd/components/InputNumberRange.vue +53 -47
  49. package/antd/directives/formLabelAlign.ts +36 -31
  50. package/antd/hooks/createAntdModal.ts +29 -29
  51. package/antd/hooks/useAntdDrawer.ts +73 -73
  52. package/antd/hooks/useAntdForm.helpers.ts +18 -18
  53. package/antd/hooks/useAntdForm.ts +38 -37
  54. package/antd/hooks/useAntdModal.ts +25 -25
  55. package/antd/hooks/useAntdTable.ts +70 -70
  56. package/antd/hooks/useAntdTheme.ts +86 -0
  57. package/antd/index.ts +8 -7
  58. package/eslint.config.js +50 -0
  59. package/kitDependencies.ts +21 -7
  60. package/package.json +46 -40
  61. package/pnpm-lock.yaml +2689 -0
  62. package/request/helpers.ts +49 -32
  63. package/request/index.ts +2 -2
  64. package/request/interceptors/checkCode.ts +8 -8
  65. package/request/interceptors/filterEmptyValue.ts +9 -9
  66. package/request/interceptors/formatPaging.ts +12 -12
  67. package/request/interceptors/index.ts +7 -6
  68. package/request/interceptors/popupMessage.ts +35 -35
  69. package/request/interceptors/returnResultType.ts +19 -19
  70. package/request/interceptors/toLogin.ts +13 -0
  71. package/request/interceptors/unitizeAxiosError.ts +7 -7
  72. package/request/queryClient.ts +42 -0
  73. package/request/request.ts +21 -21
  74. package/request/type.d.ts +89 -89
  75. package/tsconfig.json +47 -18
  76. package/utils/index.ts +67 -29
  77. package/vue/components/index.ts +1 -0
  78. package/{components → vue/components}/infinite-query/index.ts +1 -1
  79. package/{components → vue/components}/infinite-query/src/InfiniteQuery.vue +147 -147
  80. package/{components → vue/components}/infinite-query/src/useCreateTrigger.ts +35 -35
  81. package/vue/hooks/useComponentRef.ts +12 -12
  82. package/vue/hooks/useIsMounted.ts +4 -4
  83. package/vue/hooks/useTeleportTarget.ts +7 -7
  84. package/vue/index.ts +4 -3
  85. package/admin/defines/definePage.ts +0 -14
  86. package/admin/defines/defineRoute.helpers.ts +0 -30
  87. package/admin/defines/defineRoute.ts +0 -161
  88. package/admin/defines/defineRouteGuard.ts +0 -56
  89. package/admin/defines/defineStartup.ts +0 -41
  90. package/admin/filter/index.ts +0 -5
  91. package/admin/hooks/usePermission.ts +0 -5
@@ -1,147 +1,147 @@
1
- <script lang="ts">
2
- import { computed, ref, unref } from "vue";
3
- import type { UseInfiniteQueryReturnType } from '@tanstack/vue-query'
4
- import { useCreateTrigger } from './useCreateTrigger'
5
- </script>
6
-
7
- <script setup lang="ts" generic="T extends UseInfiniteQueryReturnType<any, any>">
8
- type TPage = T extends UseInfiniteQueryReturnType<infer P, any> ? NonNullable<P> : any
9
- type TRecord = TPage extends { list: Array<infer I> } ? I : any
10
-
11
- const props = defineProps<{
12
- queryier: T
13
- }>()
14
-
15
- const { queryier } = props
16
- const pages = computed(() => queryier.data.value?.pages)
17
- // TODO: 状态之间的互斥仍有问题
18
- const isInitialLoading = computed(() => queryier.isInitialLoading.value)
19
- const isInitialLoadingError = computed(() => queryier.isLoadingError.value && !isInitialLoading.value)
20
- const isMoreLoading = computed(
21
- () => (queryier.isFetchingNextPage.value || queryier.isFetching.value) && !isInitialLoading.value,
22
- )
23
- const isMoreLoadingError = computed(() => queryier.isRefetchError.value && !isMoreLoading.value)
24
- const noMore = computed(
25
- () =>
26
- !queryier.hasNextPage?.value
27
- && !isInitialLoading.value
28
- && !isInitialLoadingError.value
29
- && !isMoreLoading.value
30
- && !isMoreLoadingError.value,
31
- )
32
- const $container = ref<HTMLElement>()
33
- const containerCssVars = computed(() => {
34
- const ctnEle = unref($container)
35
-
36
- if (!ctnEle)
37
- return {}
38
-
39
- const rect = ctnEle.getBoundingClientRect()
40
-
41
- return {
42
- '--ctn-height': `${rect.height}px`,
43
- }
44
- })
45
-
46
- function refetch() {
47
- queryier.refetch()
48
- }
49
-
50
- function refetchLastPage() {
51
- queryier.refetch({
52
- refetchPage(lastPage: any, _index, allPages: any[]) {
53
- const lastIndex = allPages?.length - 1
54
- return lastPage?.pagination?.page === allPages?.[lastIndex]?.pagination?.page
55
- },
56
- })
57
- }
58
-
59
- function fetchNextPage() {
60
- const { isFetching, isLoading, hasNextPage } = queryier
61
-
62
- if (isFetching.value || isLoading.value || !hasNextPage?.value)
63
- return
64
-
65
- queryier.fetchNextPage()
66
- }
67
-
68
- function triggerFetchNextPage() {
69
- if (queryier.isError.value)
70
- return
71
-
72
- fetchNextPage()
73
- }
74
-
75
- useCreateTrigger($container, triggerFetchNextPage)
76
- </script>
77
-
78
- <template>
79
- <div ref="$container" class="infinite-query-wrapper" :style="containerCssVars">
80
- <div v-if="isInitialLoading" class="initial-loading">
81
- <i class="i-svg-spinners:180-ring-with-bg loading-icon" />
82
- </div>
83
- <div v-if="isInitialLoadingError" class="initial-loading-error" @click="refetch()">
84
- <span>加载失败,点击重试</span>
85
- </div>
86
-
87
- <div v-for="(page, i) of pages" :key="i">
88
- <template v-for="record of page.list">
89
- <slot :record="record as TRecord" />
90
- </template>
91
- </div>
92
-
93
- <div v-if="isMoreLoading" class="more-loading">
94
- <i class="i-svg-spinners:180-ring-with-bg loading-icon" />
95
- <span class="ml-1 text">加载中...</span>
96
- </div>
97
- <div v-if="isMoreLoadingError" class="more-loading-error" @click="fetchNextPage()">
98
- <span class="text">加载失败,点击重试</span>
99
- </div>
100
- <div v-if="noMore" class="no-more" @click="refetchLastPage()">
101
- <span class="text">暂无更多</span>
102
- </div>
103
- </div>
104
- </template>
105
-
106
- <style scoped lang="scss">
107
- .infinite-query-wrapper {
108
- overflow: auto;
109
- font-size: 14px;
110
- }
111
-
112
- .loading-icon {
113
- display: block;
114
- color: var(--antd-colorPrimary);
115
- font-size: 1.2em;
116
- }
117
-
118
- .initial-loading,
119
- .initial-loading-error,
120
- .more-loading,
121
- .more-loading-error,
122
- .no-more {
123
- display: flex;
124
- align-items: center;
125
- justify-content: center;
126
- color: var(--antd-colorTextSecondary);
127
- }
128
-
129
- .initial-loading,
130
- .initial-loading-error {
131
- height: var(--ctn-height, 100px);
132
- }
133
-
134
- .initial-loading-error {
135
- cursor: pointer;
136
- }
137
-
138
- .more-loading,
139
- .more-loading-error,
140
- .no-more {
141
- height: 50px;
142
- }
143
-
144
- .more-loading-error {
145
- cursor: pointer;
146
- }
147
- </style>
1
+ <script lang="ts">
2
+ import { computed, ref, unref } from 'vue';
3
+ import type { UseInfiniteQueryReturnType } from '@tanstack/vue-query';
4
+ import { useCreateTrigger } from './useCreateTrigger';
5
+ </script>
6
+
7
+ <script setup lang="ts" generic="T extends UseInfiniteQueryReturnType<any, any>">
8
+ type TPage = T extends UseInfiniteQueryReturnType<infer P, any> ? NonNullable<P> : any;
9
+ type TRecord = TPage extends { list: Array<infer I> } ? I : any;
10
+
11
+ const props = defineProps<{
12
+ queryier: T
13
+ }>();
14
+
15
+ const { queryier } = props;
16
+ const pages = computed(() => queryier.data.value?.pages);
17
+ // TODO: 状态之间的互斥仍有问题
18
+ const isInitialLoading = computed(() => queryier.isInitialLoading.value);
19
+ const isInitialLoadingError = computed(() => queryier.isLoadingError.value && !isInitialLoading.value);
20
+ const isMoreLoading = computed(
21
+ () => (queryier.isFetchingNextPage.value || queryier.isFetching.value) && !isInitialLoading.value,
22
+ );
23
+ const isMoreLoadingError = computed(() => queryier.isRefetchError.value && !isMoreLoading.value);
24
+ const noMore = computed(
25
+ () =>
26
+ !queryier.hasNextPage?.value
27
+ && !isInitialLoading.value
28
+ && !isInitialLoadingError.value
29
+ && !isMoreLoading.value
30
+ && !isMoreLoadingError.value,
31
+ );
32
+ const $container = ref<HTMLElement>();
33
+ const containerCssVars = computed(() => {
34
+ const ctnEle = unref($container);
35
+
36
+ if (!ctnEle)
37
+ return {};
38
+
39
+ const rect = ctnEle.getBoundingClientRect();
40
+
41
+ return {
42
+ '--ctn-height': `${rect.height}px`,
43
+ };
44
+ });
45
+
46
+ function refetch() {
47
+ queryier.refetch();
48
+ }
49
+
50
+ function refetchLastPage() {
51
+ queryier.refetch({
52
+ refetchPage(lastPage: any, _index, allPages: any[]) {
53
+ const lastIndex = allPages?.length - 1;
54
+ return lastPage?.pagination?.page === allPages?.[lastIndex]?.pagination?.page;
55
+ },
56
+ });
57
+ }
58
+
59
+ function fetchNextPage() {
60
+ const { isFetching, isLoading, hasNextPage } = queryier;
61
+
62
+ if (isFetching.value || isLoading.value || !hasNextPage?.value)
63
+ return;
64
+
65
+ queryier.fetchNextPage();
66
+ }
67
+
68
+ function triggerFetchNextPage() {
69
+ if (queryier.isError.value)
70
+ return;
71
+
72
+ fetchNextPage();
73
+ }
74
+
75
+ useCreateTrigger($container, triggerFetchNextPage);
76
+ </script>
77
+
78
+ <template>
79
+ <div ref="$container" class="infinite-query-wrapper" :style="containerCssVars">
80
+ <div v-if="isInitialLoading" class="initial-loading">
81
+ <i class="i-svg-spinners:180-ring-with-bg loading-icon" />
82
+ </div>
83
+ <div v-if="isInitialLoadingError" class="initial-loading-error" @click="refetch()">
84
+ <span>加载失败,点击重试</span>
85
+ </div>
86
+
87
+ <div v-for="(page, i) of pages" :key="i">
88
+ <template v-for="record of page.list">
89
+ <slot :record="record as TRecord" />
90
+ </template>
91
+ </div>
92
+
93
+ <div v-if="isMoreLoading" class="more-loading">
94
+ <i class="i-svg-spinners:180-ring-with-bg loading-icon" />
95
+ <span class="ml-1 text">加载中...</span>
96
+ </div>
97
+ <div v-if="isMoreLoadingError" class="more-loading-error" @click="fetchNextPage()">
98
+ <span class="text">加载失败,点击重试</span>
99
+ </div>
100
+ <div v-if="noMore" class="no-more" @click="refetchLastPage()">
101
+ <span class="text">暂无更多</span>
102
+ </div>
103
+ </div>
104
+ </template>
105
+
106
+ <style scoped lang="scss">
107
+ .infinite-query-wrapper {
108
+ overflow: auto;
109
+ font-size: 14px;
110
+ }
111
+
112
+ .loading-icon {
113
+ display: block;
114
+ color: var(--antd-colorPrimary);
115
+ font-size: 1.2em;
116
+ }
117
+
118
+ .initial-loading,
119
+ .initial-loading-error,
120
+ .more-loading,
121
+ .more-loading-error,
122
+ .no-more {
123
+ display: flex;
124
+ align-items: center;
125
+ justify-content: center;
126
+ color: var(--antd-colorTextSecondary);
127
+ }
128
+
129
+ .initial-loading,
130
+ .initial-loading-error {
131
+ height: var(--ctn-height, 100px);
132
+ }
133
+
134
+ .initial-loading-error {
135
+ cursor: pointer;
136
+ }
137
+
138
+ .more-loading,
139
+ .more-loading-error,
140
+ .no-more {
141
+ height: 50px;
142
+ }
143
+
144
+ .more-loading-error {
145
+ cursor: pointer;
146
+ }
147
+ </style>
@@ -1,35 +1,35 @@
1
- import { watch } from "vue";
2
- import type { Ref } from "vue";
3
- import { useIntersectionObserver, useIntervalFn } from '@vueuse/core'
4
-
5
- export function useCreateTrigger(containerEle: Ref<HTMLElement | undefined>, callback: Function) {
6
- const triggerEl = document.createElement('div')
7
-
8
- Object.assign(triggerEl.style, {
9
- position: 'relative',
10
- zIndex: '5',
11
- marginTop: '-150px',
12
- marginBottom: '150px',
13
- width: '5px',
14
- height: '5px',
15
- // background: 'red',
16
- } satisfies Partial<CSSStyleDeclaration>)
17
-
18
- useIntervalFn(() => {
19
- const { transform } = triggerEl.style
20
-
21
- if (transform)
22
- triggerEl.style.removeProperty('transform')
23
- else triggerEl.style.setProperty('transform', 'translateX(-200%)')
24
- }, 500)
25
-
26
- useIntersectionObserver(triggerEl, ([entry]) => {
27
- if (entry.isIntersecting)
28
- callback()
29
- })
30
-
31
- watch(containerEle, (ele) => {
32
- if (ele)
33
- ele.append(triggerEl)
34
- })
35
- }
1
+ import { watch } from 'vue';
2
+ import type { Ref } from 'vue';
3
+ import { useIntersectionObserver, useIntervalFn } from '@vueuse/core';
4
+
5
+ export function useCreateTrigger(containerEle: Ref<HTMLElement | undefined>, callback: Function) {
6
+ const triggerEl = document.createElement('div');
7
+
8
+ Object.assign(triggerEl.style, {
9
+ position: 'relative',
10
+ zIndex: '5',
11
+ marginTop: '-150px',
12
+ marginBottom: '150px',
13
+ width: '5px',
14
+ height: '5px',
15
+ // background: 'red',
16
+ } satisfies Partial<CSSStyleDeclaration>);
17
+
18
+ useIntervalFn(() => {
19
+ const { transform } = triggerEl.style;
20
+
21
+ if (transform)
22
+ triggerEl.style.removeProperty('transform');
23
+ else triggerEl.style.setProperty('transform', 'translateX(-200%)');
24
+ }, 500);
25
+
26
+ useIntersectionObserver(triggerEl, ([entry]) => {
27
+ if (entry.isIntersecting)
28
+ callback();
29
+ });
30
+
31
+ watch(containerEle, (ele) => {
32
+ if (ele)
33
+ ele.append(triggerEl);
34
+ });
35
+ }
@@ -1,27 +1,27 @@
1
- import { ref } from "vue";
2
- import type { Component } from 'vue'
3
- import type { ComponentExposed } from 'vue-component-type-helpers'
1
+ import { ref } from 'vue';
2
+ import type { Component } from 'vue';
3
+ import type { ComponentExposed } from 'vue-component-type-helpers';
4
4
 
5
5
  export function useComponentRef<C extends Component>(_component: C) {
6
- const _cpt = ref<any>()
6
+ const _cpt = ref<any>();
7
7
  const refFn = (cpt: any) => {
8
- _cpt.value = cpt
9
- }
8
+ _cpt.value = cpt;
9
+ };
10
10
 
11
- type Exposed = typeof refFn & Partial<ComponentExposed<C>>
11
+ type Exposed = typeof refFn & Partial<ComponentExposed<C>>;
12
12
 
13
13
  return new Proxy(refFn as Exposed, {
14
14
  get(_target, p) {
15
15
  if (!_cpt.value)
16
- return
16
+ return;
17
17
 
18
- return Reflect.get(_cpt.value, p)
18
+ return Reflect.get(_cpt.value, p);
19
19
  },
20
20
  set(_target, p, newValue) {
21
21
  if (!_cpt.value)
22
- return false
22
+ return false;
23
23
 
24
- return Reflect.set(_cpt.value, p, newValue)
24
+ return Reflect.set(_cpt.value, p, newValue);
25
25
  },
26
- })
26
+ });
27
27
  }
@@ -1,9 +1,9 @@
1
- import { ref, onMounted } from "vue";
1
+ import { onMounted, ref } from 'vue';
2
2
 
3
3
  export function useIsMounted() {
4
- const mounted = ref(false)
4
+ const mounted = ref(false);
5
5
 
6
- onMounted(() => (mounted.value = true))
6
+ onMounted(() => (mounted.value = true));
7
7
 
8
- return mounted
8
+ return mounted;
9
9
  }
@@ -1,13 +1,13 @@
1
- import { ref, onMounted } from "vue";
1
+ import { onMounted, ref } from 'vue';
2
2
 
3
3
  export function useTeleportTarget(selectors: string) {
4
- const target = ref<HTMLElement | null>()
4
+ const target = ref<HTMLElement | null>();
5
5
 
6
6
  onMounted(() => {
7
7
  setTimeout(() => {
8
- target.value = document.querySelector<HTMLElement>(selectors)
9
- })
10
- })
8
+ target.value = document.querySelector<HTMLElement>(selectors);
9
+ });
10
+ });
11
11
 
12
- return target
13
- }
12
+ return target;
13
+ }
package/vue/index.ts CHANGED
@@ -1,3 +1,4 @@
1
- export { useComponentRef } from './hooks/useComponentRef'
2
- export { useTeleportTarget } from './hooks/useTeleportTarget'
3
- export { useIsMounted } from './hooks/useIsMounted'
1
+ export { useComponentRef } from './hooks/useComponentRef';
2
+ export { useTeleportTarget } from './hooks/useTeleportTarget';
3
+ export { useIsMounted } from './hooks/useIsMounted';
4
+ export { InfiniteQuery } from './components/infinite-query';
@@ -1,14 +0,0 @@
1
- import { defineComponent, defineAsyncComponent, h } from 'vue'
2
- import type { AsyncComponentLoader } from 'vue'
3
-
4
- export { definePage }
5
-
6
- function definePage(loader: AsyncComponentLoader) {
7
- return defineComponent({
8
- setup() {
9
- const Page = defineAsyncComponent(loader)
10
-
11
- return () => h(Page, null)
12
- },
13
- })
14
- }
@@ -1,30 +0,0 @@
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
-
13
- return routes
14
- .filter(route => menuOrderRE.test((route.meta.menuOrder ?? '')))
15
- .map((route) => {
16
- const res = route.meta!.menuOrder!.match(menuOrderRE)
17
- const parentKey = res?.groups?.key
18
- const order = Number(res?.groups?.order)
19
- const name = route.name as string
20
- const menu = {
21
- key: name,
22
- label: route.meta.title ?? name,
23
- icon: route.meta.icon,
24
- trigger: parentKey ? () => router.push({ name }) : () => {},
25
- order,
26
- }
27
-
28
- return { parentKey, menu }
29
- })
30
- }
@@ -1,161 +0,0 @@
1
- import type { RouteRecordRaw } from 'vue-router'
2
- import merge from 'lodash-es/merge'
3
- import type { VNode } from 'vue'
4
- import { definePage } from './definePage'
5
- import { ENV } from "../../utils";
6
-
7
- export { defineRoute, getRoutes }
8
-
9
- const RouteSymbol = Symbol('app-route')
10
-
11
- /** 定义路由 */
12
- function defineRoute(route: (params: { definePage: typeof definePage }) => RouteRecordRaw[]) {
13
- const routeFn: any = () => route({ definePage })
14
- routeFn[RouteSymbol] = true
15
-
16
- return routeFn
17
- }
18
-
19
- /** 获取路由 */
20
- async function getRoutes() {
21
- const routeFileRE = /\/([A-Za-z0-9-]+.)?route\.ts$/
22
- const routeFiles = Object.fromEntries(
23
- Object.entries(getRoutes.modules).filter(([n]) => routeFileRE.test(n)),
24
- ) as Record<string, Function>
25
- let routes: RouteRecordRaw[] = []
26
-
27
- for (const name in routeFiles) {
28
- const module: any = await routeFiles[name]()
29
-
30
- if (Object.hasOwn(module?.default ?? {}, RouteSymbol))
31
- Array.prototype.push.apply(routes, module.default())
32
- }
33
-
34
- // 处理路由
35
- routes = meregeDefaultRouteParams(routes)
36
- routes = sortRoute(routes)
37
-
38
- // 输出路由
39
- if (!ENV.isProd) {
40
- console.groupCollapsed('一级路由')
41
-
42
- console.table(
43
- routes.map(route => ({ order: route.meta?.order, ...route })),
44
- ['order', 'name', 'path'],
45
- )
46
-
47
- console.groupEnd()
48
- }
49
-
50
- return routes
51
- }
52
- getRoutes.modules = {} as any
53
-
54
- /** 给路由填充默认参数 */
55
- const defaultRouteParams: Partial<RouteRecordRaw> = {
56
- meta: {
57
- title: '标题',
58
- icon: undefined,
59
- order: 10,
60
- requireAuth: true,
61
- keepAlive: false,
62
- hiddenTab: false,
63
- pageKeyFn: route => route.path,
64
- },
65
- }
66
-
67
- function meregeDefaultRouteParams(routes: RouteRecordRaw[], parentRoute?: RouteRecordRaw) {
68
- const _routes: typeof routes = []
69
-
70
- for (const route of routes) {
71
- if (route.children?.length)
72
- route.children = meregeDefaultRouteParams(route.children, route)
73
-
74
- const newRoute = merge({}, defaultRouteParams, route)
75
- const { menuOrder } = newRoute.meta!
76
-
77
- // 处理 menuOrder
78
- if (typeof menuOrder === 'string')
79
- newRoute.meta!.menuOrder = menuOrder.replace('..', (parentRoute?.name ?? '') as string)
80
-
81
- _routes.push(newRoute)
82
- }
83
-
84
- return _routes
85
- }
86
-
87
- /** 给路由排序 */
88
- function sortRoute(routes: RouteRecordRaw[]) {
89
- const _routes = routes.sort((r1, r2) => r1!.meta!.order! - r2!.meta!.order!)
90
-
91
- for (const route of _routes) {
92
- if (route.children?.length)
93
- route.children = sortRoute(route.children)
94
- }
95
-
96
- return _routes
97
- }
98
-
99
- declare module 'vue-router' {
100
- interface RouteMeta {
101
- /**
102
- * 路由标题
103
- *
104
- * @description 可用来作 document.title 和菜单的名称
105
- *
106
- * 默认:APP 名称
107
- */
108
- title?: string | (() => string)
109
- /**
110
- * 菜单和面包屑对应的图标
111
- *
112
- * 默认:`''`
113
- */
114
- icon?: (() => VNode)
115
- /**
116
- * 路由添加顺序,仅作用于一级路由
117
- *
118
- * 默认:`10`
119
- */
120
- order?: number
121
- /**
122
- * 是否需要登录
123
- *
124
- * 默认:`false`
125
- */
126
- requireAuth?: boolean
127
- /**
128
- * 缓存页面
129
- *
130
- * 默认:`true`
131
- */
132
- keepAlive?: boolean
133
- /**
134
- * 菜单排序(升序)
135
- *
136
- * 格式:[parent]@[order]
137
- * - `parent`:可选。不填则默认取路由的 name 值,并在作为一级菜单显示
138
- * - `order`:必选。路由排序,值越小排越前
139
- *
140
- * 例子:
141
- * - `@10`:一级菜单
142
- * - `..@10`:所在的路由层级的父级菜单,例如父级菜单是 admin,那么`..`就是`admin`
143
- * - `admin@10`:指定菜单的父级为 `admin`
144
- *
145
- * 默认:undefined。不在菜单中显示
146
- */
147
- menuOrder?: string
148
- /**
149
- * 是否隐藏标签页
150
- *
151
- * 默认:`false`
152
- */
153
- hiddenTab?: boolean
154
- /**
155
- * 用于生成页面运行时的 key
156
- *
157
- * 默认:取 route 对象中 path 值
158
- */
159
- pageKeyFn?: (route: RouteLocationNormalizedLoaded) => string
160
- }
161
- }