@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
package/admin/hooks/usePage.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { createGlobalState, usePrevious } from '@vueuse/core'
|
|
2
|
-
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
3
|
-
import {
|
|
4
|
-
import type { VNode } from 'vue'
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import { createGlobalState, usePrevious } from '@vueuse/core';
|
|
2
|
+
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
|
3
|
+
import { computed, reactive, readonly, ref, shallowRef, watch } from 'vue';
|
|
4
|
+
import type { VNode } from 'vue';
|
|
5
|
+
import { getTitle } from '../defines/route';
|
|
6
|
+
import { getDependencies } from '../../kitDependencies';
|
|
7
|
+
import { useMenu } from './useMenu';
|
|
8
|
+
import type { TMenu } from './useMenu';
|
|
9
9
|
|
|
10
|
-
export { usePage }
|
|
11
|
-
export type { TPageState, IBreadcrumb }
|
|
10
|
+
export { usePage };
|
|
11
|
+
export type { TPageState, IBreadcrumb };
|
|
12
12
|
|
|
13
|
-
type TPageState = ReturnType<typeof getPageState
|
|
13
|
+
type TPageState = ReturnType<typeof getPageState>;
|
|
14
14
|
|
|
15
15
|
interface IBreadcrumb {
|
|
16
16
|
title: string
|
|
@@ -20,70 +20,70 @@ interface IBreadcrumb {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const usePage = createGlobalState(() => {
|
|
23
|
-
const { useRouter } = getDependencies()
|
|
24
|
-
const router = useRouter()
|
|
25
|
-
const currentPageNode = shallowRef<VNode>()
|
|
26
|
-
const currentPageKey = ref('')
|
|
27
|
-
const pageCacheList = reactive<string[]>([])
|
|
28
|
-
const pageStateMap = new Map<string, TPageState>()
|
|
29
|
-
const currentPageState = computed(() => pageStateMap.get(currentPageKey.value))
|
|
30
|
-
const previousPageState = usePrevious(currentPageState)
|
|
23
|
+
const { useRouter } = getDependencies();
|
|
24
|
+
const router = useRouter();
|
|
25
|
+
const currentPageNode = shallowRef<VNode>();
|
|
26
|
+
const currentPageKey = ref('');
|
|
27
|
+
const pageCacheList = reactive<string[]>([]);
|
|
28
|
+
const pageStateMap = new Map<string, TPageState>();
|
|
29
|
+
const currentPageState = computed(() => pageStateMap.get(currentPageKey.value));
|
|
30
|
+
const previousPageState = usePrevious(currentPageState);
|
|
31
31
|
|
|
32
32
|
const openPage = (key: string) => {
|
|
33
|
-
const route = pageStateMap.get(key)?.route
|
|
33
|
+
const route = pageStateMap.get(key)?.route;
|
|
34
34
|
|
|
35
35
|
if (!route)
|
|
36
|
-
return
|
|
36
|
+
return;
|
|
37
37
|
|
|
38
|
-
router.push(route.fullPath)
|
|
39
|
-
}
|
|
38
|
+
router.push(route.fullPath);
|
|
39
|
+
};
|
|
40
40
|
|
|
41
41
|
const closePage = (key: string) => {
|
|
42
42
|
if (!pageStateMap.has(key))
|
|
43
|
-
return
|
|
43
|
+
return;
|
|
44
44
|
|
|
45
|
-
const cacheIndex = pageCacheList.indexOf(key)
|
|
46
|
-
cacheIndex >= 0 && pageCacheList.splice(cacheIndex, 1)
|
|
45
|
+
const cacheIndex = pageCacheList.indexOf(key);
|
|
46
|
+
cacheIndex >= 0 && pageCacheList.splice(cacheIndex, 1);
|
|
47
47
|
// 关闭当前页面则返回上一个路由
|
|
48
|
-
currentPageKey.value === key && router.go(-1)
|
|
49
|
-
pageStateMap.delete(key)
|
|
50
|
-
}
|
|
48
|
+
currentPageKey.value === key && router.go(-1);
|
|
49
|
+
pageStateMap.delete(key);
|
|
50
|
+
};
|
|
51
51
|
|
|
52
52
|
const setPage = (pageNode: VNode, route: RouteLocationNormalizedLoaded) => {
|
|
53
|
-
const pageKey = route?.meta?.pageKeyFn?.(route) ?? route.fullPath
|
|
54
|
-
const pageInfo = getPageState(route)
|
|
55
|
-
const canKeepAlive = route.meta.keepAlive && !pageCacheList.includes(pageKey)
|
|
53
|
+
const pageKey = route?.meta?.pageKeyFn?.(route) ?? route.fullPath;
|
|
54
|
+
const pageInfo = getPageState(route);
|
|
55
|
+
const canKeepAlive = route.meta.keepAlive && !pageCacheList.includes(pageKey);
|
|
56
56
|
|
|
57
|
-
canKeepAlive && pageCacheList.push(pageKey)
|
|
57
|
+
canKeepAlive && pageCacheList.push(pageKey);
|
|
58
58
|
pageStateMap.has(pageKey) || pageStateMap.set(pageKey, pageInfo)
|
|
59
59
|
|
|
60
|
-
;(pageNode as any).type.name = pageKey
|
|
61
|
-
currentPageKey.value = pageKey
|
|
62
|
-
currentPageNode.value = pageNode
|
|
60
|
+
;(pageNode as any).type.name = pageKey;
|
|
61
|
+
currentPageKey.value = pageKey;
|
|
62
|
+
currentPageNode.value = pageNode;
|
|
63
63
|
|
|
64
|
-
return pageNode
|
|
65
|
-
}
|
|
64
|
+
return pageNode;
|
|
65
|
+
};
|
|
66
66
|
|
|
67
67
|
const getCurrentPageState = () => {
|
|
68
|
-
return pageStateMap.get(currentPageKey.value)
|
|
69
|
-
}
|
|
68
|
+
return pageStateMap.get(currentPageKey.value);
|
|
69
|
+
};
|
|
70
70
|
|
|
71
71
|
// 监听 title 变化
|
|
72
72
|
watch(() => currentPageState.value?.title, (title) => {
|
|
73
|
-
let _title = title
|
|
73
|
+
let _title = title;
|
|
74
74
|
|
|
75
75
|
if (!_title) {
|
|
76
|
-
const pageState = currentPageState.value
|
|
76
|
+
const pageState = currentPageState.value;
|
|
77
77
|
|
|
78
78
|
// 当前 title 为空时,使用路由 title
|
|
79
79
|
if (pageState) {
|
|
80
|
-
_title = getTitle(pageState?.route)
|
|
81
|
-
pageState.title = _title
|
|
80
|
+
_title = getTitle(pageState?.route);
|
|
81
|
+
pageState.title = _title!;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
document.title = _title
|
|
86
|
-
})
|
|
85
|
+
document.title = _title!;
|
|
86
|
+
});
|
|
87
87
|
|
|
88
88
|
return {
|
|
89
89
|
currentPageNode,
|
|
@@ -96,35 +96,37 @@ const usePage = createGlobalState(() => {
|
|
|
96
96
|
setPage,
|
|
97
97
|
openPage,
|
|
98
98
|
closePage,
|
|
99
|
-
}
|
|
100
|
-
})
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
101
|
|
|
102
102
|
function getPageState(route: RouteLocationNormalizedLoaded) {
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
const icon
|
|
103
|
+
const deps = getDependencies();
|
|
104
|
+
const appName = deps.appName as string;
|
|
105
|
+
const { getMenuPath } = useMenu();
|
|
106
|
+
const menuPath = getMenuPath(route.name as string);
|
|
107
|
+
const currentMenu = menuPath.pop();
|
|
108
|
+
const { icon: mIcon } = route.meta;
|
|
109
|
+
const title = currentMenu?.label ?? getTitle(route) ?? appName;
|
|
110
|
+
const icon = currentMenu?.icon ?? mIcon?.();
|
|
109
111
|
const state = reactive({
|
|
110
112
|
title,
|
|
111
113
|
icon,
|
|
112
114
|
breadcrumbs: menuPath.map(menuToBreadcrumb),
|
|
113
115
|
route: readonly(route),
|
|
114
116
|
refresh() {
|
|
115
|
-
const menuKey = this.route.name as string
|
|
116
|
-
const { getMenu, getMenuPath } = useMenu()
|
|
117
|
-
const menu = getMenu(menuKey)
|
|
118
|
-
const menuPath = getMenuPath(menuKey)
|
|
117
|
+
const menuKey = this.route.name as string;
|
|
118
|
+
const { getMenu, getMenuPath } = useMenu();
|
|
119
|
+
const menu = getMenu(menuKey);
|
|
120
|
+
const menuPath = getMenuPath(menuKey);
|
|
119
121
|
|
|
120
|
-
menuPath.pop()
|
|
122
|
+
menuPath.pop();
|
|
121
123
|
|
|
122
|
-
this.title = menu?.label ?? getTitle(this.route) ??
|
|
123
|
-
this.breadcrumbs = menuPath.map(menuToBreadcrumb)
|
|
124
|
+
this.title = menu?.label ?? getTitle(this.route) ?? appName;
|
|
125
|
+
this.breadcrumbs = menuPath.map(menuToBreadcrumb);
|
|
124
126
|
},
|
|
125
|
-
})
|
|
127
|
+
});
|
|
126
128
|
|
|
127
|
-
return state
|
|
129
|
+
return state;
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
function menuToBreadcrumb(menu: TMenu) {
|
|
@@ -133,7 +135,7 @@ function menuToBreadcrumb(menu: TMenu) {
|
|
|
133
135
|
icon: menu.icon,
|
|
134
136
|
trigger: menu.trigger,
|
|
135
137
|
children: menu.children?.map(menuToBreadcrumb),
|
|
136
|
-
})
|
|
138
|
+
});
|
|
137
139
|
|
|
138
|
-
return ret
|
|
140
|
+
return ret;
|
|
139
141
|
}
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import { createGlobalState } from '@vueuse/core'
|
|
2
|
-
import {
|
|
3
|
-
import { usePage } from './usePage'
|
|
1
|
+
import { createGlobalState } from '@vueuse/core';
|
|
2
|
+
import { computed, ref, watch } from 'vue';
|
|
3
|
+
import { usePage } from './usePage';
|
|
4
4
|
|
|
5
|
-
export { usePageTab }
|
|
5
|
+
export { usePageTab };
|
|
6
6
|
|
|
7
7
|
const usePageTab = createGlobalState(() => {
|
|
8
|
-
const { currentPageKey, pageStateMap, openPage, closePage } = usePage()
|
|
9
|
-
const tabKeyList = ref<string[]>([])
|
|
8
|
+
const { currentPageKey, pageStateMap, openPage, closePage } = usePage();
|
|
9
|
+
const tabKeyList = ref<string[]>([]);
|
|
10
10
|
const tabList = computed(() => tabKeyList.value.map((key) => {
|
|
11
|
-
const state = pageStateMap.get(key)
|
|
11
|
+
const state = pageStateMap.get(key);
|
|
12
12
|
|
|
13
|
-
return state ? { key, title: state.title, icon: state.icon } : undefined
|
|
14
|
-
}).filter(tab => !!tab))
|
|
13
|
+
return state ? { key, title: state.title, icon: state.icon } : undefined!;
|
|
14
|
+
}).filter(tab => !!tab));
|
|
15
15
|
|
|
16
16
|
const closeTab = (key: string) => {
|
|
17
|
-
const i = tabKeyList.value.indexOf(key)
|
|
17
|
+
const i = tabKeyList.value.indexOf(key);
|
|
18
18
|
|
|
19
19
|
if (i > -1) {
|
|
20
|
-
closePage(key)
|
|
21
|
-
setTimeout(() => tabKeyList.value.splice(i, 1))
|
|
20
|
+
closePage(key);
|
|
21
|
+
setTimeout(() => tabKeyList.value.splice(i, 1));
|
|
22
22
|
}
|
|
23
|
-
}
|
|
23
|
+
};
|
|
24
24
|
|
|
25
25
|
watch(
|
|
26
26
|
currentPageKey,
|
|
27
27
|
(key) => {
|
|
28
28
|
if (!tabKeyList.value.includes(key))
|
|
29
|
-
tabKeyList.value.push(key)
|
|
29
|
+
tabKeyList.value.push(key);
|
|
30
30
|
},
|
|
31
31
|
{ immediate: true },
|
|
32
|
-
)
|
|
32
|
+
);
|
|
33
33
|
|
|
34
|
-
return { activeTab: currentPageKey, tabList, closeTab, openTab: openPage }
|
|
35
|
-
})
|
|
34
|
+
return { activeTab: currentPageKey, tabList, closeTab, openTab: openPage };
|
|
35
|
+
});
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { computed } from
|
|
3
|
-
import type { VNode } from 'vue'
|
|
4
|
-
import { Breadcrumb as ABreadcrumb } from
|
|
5
|
-
import type { Route as AntdBreadcrumbRoute } from 'ant-design-vue/es/breadcrumb/Breadcrumb'
|
|
6
|
-
import type { IBreadcrumb } from '../../hooks'
|
|
7
|
-
import { getDependencies } from
|
|
8
|
-
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import type { VNode } from 'vue';
|
|
4
|
+
import { Breadcrumb as ABreadcrumb } from 'ant-design-vue';
|
|
5
|
+
import type { Route as AntdBreadcrumbRoute } from 'ant-design-vue/es/breadcrumb/Breadcrumb';
|
|
6
|
+
import type { IBreadcrumb } from '../../hooks';
|
|
7
|
+
import { getDependencies } from '../../../kitDependencies';
|
|
9
8
|
|
|
10
9
|
interface IBreadcrumbRoute extends AntdBreadcrumbRoute {
|
|
11
10
|
icon?: VNode | null
|
|
@@ -19,29 +18,29 @@ function _buildRoute(breadcrumb: IBreadcrumb): IBreadcrumbRoute {
|
|
|
19
18
|
icon: breadcrumb.icon,
|
|
20
19
|
children: breadcrumb.children?.map(child => _buildRoute(child)),
|
|
21
20
|
trigger: breadcrumb.trigger,
|
|
22
|
-
}
|
|
21
|
+
};
|
|
23
22
|
}
|
|
24
23
|
</script>
|
|
25
24
|
|
|
26
25
|
<script setup lang="ts">
|
|
27
|
-
const { usePage } = getDependencies()
|
|
28
|
-
const { currentPageState } = usePage()
|
|
26
|
+
const { usePage } = getDependencies();
|
|
27
|
+
const { currentPageState } = usePage();
|
|
29
28
|
const routes = computed(() => {
|
|
30
|
-
let breadcrumbs: IBreadcrumbRoute[] = []
|
|
29
|
+
let breadcrumbs: IBreadcrumbRoute[] = [];
|
|
31
30
|
|
|
32
31
|
if (!currentPageState.value)
|
|
33
|
-
return breadcrumbs
|
|
32
|
+
return breadcrumbs;
|
|
34
33
|
|
|
35
|
-
breadcrumbs = currentPageState.value.breadcrumbs.map(breadcrumb => _buildRoute(breadcrumb))
|
|
34
|
+
breadcrumbs = currentPageState.value.breadcrumbs.map(breadcrumb => _buildRoute(breadcrumb));
|
|
36
35
|
|
|
37
36
|
breadcrumbs.push({
|
|
38
37
|
path: currentPageState.value.title,
|
|
39
38
|
breadcrumbName: currentPageState.value.title,
|
|
40
39
|
icon: currentPageState.value.icon,
|
|
41
|
-
})
|
|
40
|
+
});
|
|
42
41
|
|
|
43
|
-
return breadcrumbs
|
|
44
|
-
})
|
|
42
|
+
return breadcrumbs;
|
|
43
|
+
});
|
|
45
44
|
</script>
|
|
46
45
|
|
|
47
46
|
<template>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { getDependencies } from
|
|
2
|
+
import { getDependencies } from '../../../kitDependencies';
|
|
3
3
|
|
|
4
|
-
const { usePage } = getDependencies()
|
|
5
|
-
const { pageCacheList, setPage } = usePage()
|
|
4
|
+
const { usePage } = getDependencies();
|
|
5
|
+
const { pageCacheList, setPage } = usePage();
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<template>
|
|
9
|
-
<RouterView
|
|
9
|
+
<RouterView #default="{ Component, route }">
|
|
10
10
|
<KeepAlive :include="pageCacheList">
|
|
11
11
|
<Suspense>
|
|
12
12
|
<component :is="setPage(Component, route)" :key="(Component.type as any).name" />
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { computed, ref, watch } from
|
|
3
|
-
import { Menu as AMenu } from
|
|
4
|
-
import type { ItemType } from 'ant-design-vue'
|
|
5
|
-
import type { TMenu } from '../../hooks'
|
|
6
|
-
import { getDependencies } from
|
|
2
|
+
import { computed, ref, watch } from 'vue';
|
|
3
|
+
import { Menu as AMenu } from 'ant-design-vue';
|
|
4
|
+
import type { ItemType } from 'ant-design-vue';
|
|
5
|
+
import type { TMenu } from '../../hooks';
|
|
6
|
+
import { getDependencies } from '../../../kitDependencies';
|
|
7
7
|
|
|
8
8
|
function formatMenu(menu: TMenu): ItemType {
|
|
9
9
|
return {
|
|
@@ -12,33 +12,34 @@ function formatMenu(menu: TMenu): ItemType {
|
|
|
12
12
|
label: menu.label,
|
|
13
13
|
icon: menu.icon ?? undefined,
|
|
14
14
|
onClick: (e) => {
|
|
15
|
-
(e as any).stopPropagation()
|
|
16
|
-
menu.trigger()
|
|
15
|
+
(e as any).stopPropagation();
|
|
16
|
+
menu.trigger();
|
|
17
17
|
},
|
|
18
18
|
children: menu.children?.map(formatMenu),
|
|
19
|
-
}
|
|
19
|
+
};
|
|
20
20
|
}
|
|
21
21
|
</script>
|
|
22
22
|
|
|
23
23
|
<script setup lang="ts">
|
|
24
|
-
const{ useRouter, useMenu } = getDependencies()
|
|
25
|
-
const router = useRouter()
|
|
26
|
-
const { menus, getMenuPath } = useMenu()
|
|
27
|
-
const items = computed(() => menus.map(formatMenu))
|
|
28
|
-
const openKeys = ref<string[]>([])
|
|
29
|
-
const selectedKeys = ref<string[]>([])
|
|
24
|
+
const { useRouter, useMenu } = getDependencies();
|
|
25
|
+
const router = useRouter();
|
|
26
|
+
const { menus, getMenuPath } = useMenu();
|
|
27
|
+
const items = computed(() => menus.map(formatMenu));
|
|
28
|
+
const openKeys = ref<string[]>([]);
|
|
29
|
+
const selectedKeys = ref<string[]>([]);
|
|
30
30
|
|
|
31
31
|
watch(
|
|
32
32
|
() => router?.currentRoute.value,
|
|
33
33
|
(route) => {
|
|
34
|
-
if (!route)
|
|
34
|
+
if (!route)
|
|
35
|
+
return;
|
|
35
36
|
|
|
36
|
-
const menuPath = getMenuPath(route.name as string)
|
|
37
|
-
openKeys.value = menuPath.map(menu => menu.key)
|
|
38
|
-
selectedKeys.value = [openKeys.value.pop()!]
|
|
37
|
+
const menuPath = getMenuPath(route.name as string);
|
|
38
|
+
openKeys.value = menuPath.map(menu => menu.key);
|
|
39
|
+
selectedKeys.value = [openKeys.value.pop()!];
|
|
39
40
|
},
|
|
40
41
|
{ immediate: true },
|
|
41
|
-
)
|
|
42
|
+
);
|
|
42
43
|
</script>
|
|
43
44
|
|
|
44
45
|
<template>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import { getDependencies } from
|
|
2
|
+
import { TabPane as ATabPane, Tabs as ATabs } from 'ant-design-vue';
|
|
3
|
+
import { getDependencies } from '../../../kitDependencies';
|
|
4
4
|
|
|
5
|
-
const { usePageTab } = getDependencies()
|
|
6
|
-
const { activeTab, tabList, openTab, closeTab } = usePageTab()
|
|
5
|
+
const { usePageTab } = getDependencies();
|
|
6
|
+
const { activeTab, tabList, openTab, closeTab } = usePageTab();
|
|
7
7
|
</script>
|
|
8
8
|
|
|
9
9
|
<template>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { default as Breadcrumb } from './Breadcrumb.vue'
|
|
2
|
-
export { default as Content } from './Content.vue'
|
|
3
|
-
export { default as Menu } from './Menu.vue'
|
|
4
|
-
export { default as PageTab } from './PageTab.vue'
|
|
1
|
+
export { default as Breadcrumb } from './Breadcrumb.vue';
|
|
2
|
+
export { default as Content } from './Content.vue';
|
|
3
|
+
export { default as Menu } from './Menu.vue';
|
|
4
|
+
export { default as PageTab } from './PageTab.vue';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Router } from 'vue-router';
|
|
2
|
+
import { getDependencies } from '../../kitDependencies';
|
|
3
|
+
import { hasToken } from '../../utils';
|
|
4
|
+
|
|
5
|
+
export function setupPermissionRouterGuard(router: Router, rouneNames: { index: string, login: string, 403: string }) {
|
|
6
|
+
const { usePermission } = getDependencies();
|
|
7
|
+
const { refreshPermission, hasPermissions } = usePermission();
|
|
8
|
+
|
|
9
|
+
router.beforeEach(async (to, _, next) => {
|
|
10
|
+
const isLogin = hasToken();
|
|
11
|
+
const needLogin = Boolean(to.meta?.requireAuth);
|
|
12
|
+
let hasPermission = false;
|
|
13
|
+
|
|
14
|
+
if (isLogin) {
|
|
15
|
+
await refreshPermission();
|
|
16
|
+
|
|
17
|
+
const permissionCode = to.meta?.permissionCode;
|
|
18
|
+
hasPermission = permissionCode ? hasPermissions(permissionCode) : true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 已登录状态跳转登录页,跳转至首页
|
|
22
|
+
if (isLogin && to.name === rouneNames.login)
|
|
23
|
+
return next({ name: rouneNames.index, replace: true });
|
|
24
|
+
|
|
25
|
+
// 不需要登录权限的页面直接通行
|
|
26
|
+
else if (!needLogin)
|
|
27
|
+
return next(true);
|
|
28
|
+
|
|
29
|
+
// 未登录状态进入需要登录权限的页面
|
|
30
|
+
else if (!isLogin && needLogin)
|
|
31
|
+
return next({ name: rouneNames.login, replace: true });
|
|
32
|
+
|
|
33
|
+
// 登录状态进入需要登录权限的页面,有权限直接通行
|
|
34
|
+
else if (isLogin && needLogin && hasPermission)
|
|
35
|
+
return next(true);
|
|
36
|
+
|
|
37
|
+
// 登录状态进入需要登录权限的页面,无权限,重定向到无权限页面
|
|
38
|
+
else if (isLogin && needLogin && !hasPermission)
|
|
39
|
+
return next({ name: rouneNames[403], replace: true });
|
|
40
|
+
|
|
41
|
+
return next(false);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createGlobalState } from '@vueuse/core';
|
|
2
|
+
import type { AsyncReturnType } from 'type-fest';
|
|
3
|
+
import { computed, readonly, ref, watch } from 'vue';
|
|
4
|
+
import { getDependencies } from '../../kitDependencies';
|
|
5
|
+
|
|
6
|
+
export { usePermission };
|
|
7
|
+
export type { TRole };
|
|
8
|
+
|
|
9
|
+
type TRole = () => Promise<Record<string, boolean> | null | undefined>;
|
|
10
|
+
|
|
11
|
+
const usePermission = createGlobalState(() => {
|
|
12
|
+
const { roles } = getDependencies();
|
|
13
|
+
const role = ref('main');
|
|
14
|
+
const permissionCodes = ref<AsyncReturnType<TRole>>();
|
|
15
|
+
const permissionCodesStr = computed(() => Object.keys(permissionCodes.value ?? {}).sort().join(','));
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 刷新权限
|
|
19
|
+
*/
|
|
20
|
+
const refreshPermission = async () => {
|
|
21
|
+
permissionCodes.value = await roles[role.value]?.();
|
|
22
|
+
|
|
23
|
+
return permissionCodes.value;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 是否满足权限要求
|
|
28
|
+
* @param codes 权限 code
|
|
29
|
+
*/
|
|
30
|
+
const hasPermissions = (codes: string | string[]) => {
|
|
31
|
+
const _codes = Array.isArray(codes) ? codes : [codes];
|
|
32
|
+
const _permissionCodes = permissionCodes.value;
|
|
33
|
+
|
|
34
|
+
if (_permissionCodes === null)
|
|
35
|
+
return false;
|
|
36
|
+
else if (_permissionCodes === undefined)
|
|
37
|
+
// undefined 则表示没有权限要求,返回 true
|
|
38
|
+
return true;
|
|
39
|
+
else
|
|
40
|
+
return _codes.every(code => !!_permissionCodes[code]);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
watch(role, refreshPermission, { immediate: true });
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
permissionCodes: readonly(permissionCodes),
|
|
47
|
+
permissionCodesStr,
|
|
48
|
+
role,
|
|
49
|
+
hasPermissions,
|
|
50
|
+
refreshPermission,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { App } from 'vue';
|
|
2
|
+
import { getDependencies } from '../../kitDependencies';
|
|
3
|
+
|
|
4
|
+
export type THasPermissionsFn = ReturnType<ReturnType<typeof getDependencies>['usePermission']>['hasPermissions'];
|
|
5
|
+
|
|
6
|
+
export function setupPermissionPlugin(app: App) {
|
|
7
|
+
const { usePermission } = getDependencies();
|
|
8
|
+
const { hasPermissions } = usePermission();
|
|
9
|
+
|
|
10
|
+
app.directive('has-permissions', {
|
|
11
|
+
mounted(el, binding) {
|
|
12
|
+
const codes = binding.value;
|
|
13
|
+
|
|
14
|
+
if (!hasPermissions(codes))
|
|
15
|
+
el.remove();
|
|
16
|
+
},
|
|
17
|
+
updated(el, binding) {
|
|
18
|
+
const codes = binding.value;
|
|
19
|
+
|
|
20
|
+
if (!hasPermissions(codes))
|
|
21
|
+
el.remove();
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
app.use({
|
|
26
|
+
install(app) {
|
|
27
|
+
app.config.globalProperties.$hasPermission = hasPermissions;
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Router } from 'vue-router';
|
|
2
|
+
import { getDependencies } from '../../kitDependencies';
|
|
3
|
+
|
|
4
|
+
export function setupPageProgress(router: Router) {
|
|
5
|
+
const deps = getDependencies();
|
|
6
|
+
|
|
7
|
+
router.afterEach((to, _, err) => {
|
|
8
|
+
const title = to.meta.title;
|
|
9
|
+
|
|
10
|
+
if (!err) {
|
|
11
|
+
document.title = typeof title === 'function'
|
|
12
|
+
? title()
|
|
13
|
+
: title ?? deps.appName;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Router } from 'vue-router';
|
|
2
|
+
import { useStyleTag } from '@vueuse/core';
|
|
3
|
+
import NProgress from 'nprogress';
|
|
4
|
+
import 'nprogress/nprogress.css';
|
|
5
|
+
|
|
6
|
+
export function setupPageTitle(router: Router) {
|
|
7
|
+
NProgress.configure({ showSpinner: false });
|
|
8
|
+
useStyleTag(`
|
|
9
|
+
#nprogress .bar {
|
|
10
|
+
height: 3px;
|
|
11
|
+
background: var(--antd-colorPrimary);
|
|
12
|
+
}
|
|
13
|
+
#nprogress .peg {
|
|
14
|
+
box-shadow: 0 0 10px var(--antd-colorPrimary), 0 0 5px var(--antd-colorPrimary);
|
|
15
|
+
}
|
|
16
|
+
`);
|
|
17
|
+
|
|
18
|
+
router.beforeEach(() => {
|
|
19
|
+
NProgress.start();
|
|
20
|
+
});
|
|
21
|
+
router.afterEach(() => {
|
|
22
|
+
setTimeout(() => NProgress.done(), 200);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createSelfKeyProxy } from '../../utils';
|
|
2
|
+
|
|
3
|
+
export declare interface AppPermissionCodes {}
|
|
4
|
+
export declare interface AppRouteNames {}
|
|
5
|
+
|
|
6
|
+
/** 权限 code 类型辅助(permission code) */
|
|
7
|
+
export const pc_ = createSelfKeyProxy<{ [K in keyof AppPermissionCodes]: K }>();
|
|
8
|
+
|
|
9
|
+
/** 路由 name 类型辅助(route name) */
|
|
10
|
+
export const rn_ = createSelfKeyProxy<{ [K in keyof AppRouteNames]: K }>();
|
package/admin/unocss/index.ts
CHANGED