@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.
Files changed (90) 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 +12 -9
  4. package/admin/{filter → components/filter/src}/FilterParam.vue +15 -15
  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 +9 -9
  10. package/admin/components/text/index.ts +6 -6
  11. package/admin/components/text/src/Amount.vue +22 -19
  12. package/admin/components/text/src/Datetime.vue +12 -12
  13. package/admin/components/text/src/Duration.vue +13 -13
  14. package/admin/components/text/src/Hash.vue +13 -11
  15. package/admin/components/text/src/createTagGetter.ts +7 -7
  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 +48 -48
  31. package/admin/hooks/usePage.ts +67 -65
  32. package/admin/hooks/usePageTab.ts +17 -17
  33. package/admin/layout/large/Breadcrumb.vue +15 -16
  34. package/admin/layout/large/Content.vue +4 -4
  35. package/admin/layout/large/Menu.vue +20 -19
  36. package/admin/layout/large/PageTab.vue +4 -4
  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/types/assist.ts +10 -0
  46. package/admin/unocss/index.ts +1 -1
  47. package/antd/components/InputNumberRange.vue +21 -15
  48. package/antd/directives/formLabelAlign.ts +28 -23
  49. package/antd/hooks/createAntdModal.ts +29 -29
  50. package/antd/hooks/useAntdDrawer.ts +31 -31
  51. package/antd/hooks/useAntdForm.helpers.ts +18 -18
  52. package/antd/hooks/useAntdForm.ts +38 -37
  53. package/antd/hooks/useAntdModal.ts +25 -25
  54. package/antd/hooks/useAntdTable.ts +22 -22
  55. package/antd/hooks/useAntdTheme.ts +86 -0
  56. package/antd/index.ts +8 -7
  57. package/eslint.config.js +50 -0
  58. package/kitDependencies.ts +21 -7
  59. package/package.json +22 -16
  60. package/pnpm-lock.yaml +2147 -56
  61. package/request/helpers.ts +30 -13
  62. package/request/index.ts +2 -2
  63. package/request/interceptors/checkCode.ts +8 -8
  64. package/request/interceptors/filterEmptyValue.ts +9 -9
  65. package/request/interceptors/formatPaging.ts +12 -12
  66. package/request/interceptors/index.ts +7 -6
  67. package/request/interceptors/popupMessage.ts +35 -35
  68. package/request/interceptors/returnResultType.ts +19 -19
  69. package/request/interceptors/toLogin.ts +13 -0
  70. package/request/interceptors/unitizeAxiosError.ts +7 -7
  71. package/request/queryClient.ts +42 -0
  72. package/request/request.ts +21 -21
  73. package/request/type.d.ts +18 -18
  74. package/tsconfig.json +41 -12
  75. package/utils/index.ts +59 -31
  76. package/vue/components/index.ts +1 -0
  77. package/{components → vue/components}/infinite-query/index.ts +1 -1
  78. package/{components → vue/components}/infinite-query/src/InfiniteQuery.vue +29 -29
  79. package/{components → vue/components}/infinite-query/src/useCreateTrigger.ts +13 -13
  80. package/vue/hooks/useComponentRef.ts +12 -12
  81. package/vue/hooks/useIsMounted.ts +4 -4
  82. package/vue/hooks/useTeleportTarget.ts +7 -7
  83. package/vue/index.ts +4 -3
  84. package/admin/defines/definePage.ts +0 -14
  85. package/admin/defines/defineRoute.helpers.ts +0 -37
  86. package/admin/defines/defineRoute.ts +0 -161
  87. package/admin/defines/defineRouteGuard.ts +0 -56
  88. package/admin/defines/defineStartup.ts +0 -41
  89. package/admin/filter/index.ts +0 -5
  90. package/admin/hooks/usePermission.ts +0 -5
@@ -1,16 +1,16 @@
1
- import { createGlobalState, usePrevious } from '@vueuse/core'
2
- import type { RouteLocationNormalizedLoaded } from 'vue-router'
3
- import { shallowRef, ref, reactive, computed, watch, readonly } from 'vue'
4
- import type { VNode } from 'vue'
5
- import { useMenu } from './useMenu'
6
- import type { TMenu } from './useMenu'
7
- import { getTitle } from '../defines/defineRoute.helpers'
8
- import { getDependencies } from "../../kitDependencies";
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 { getMenuPath } = useMenu()
104
- const menuPath = getMenuPath(route.name as string)
105
- const currentMenu = menuPath.pop()
106
- const { icon: mIcon } = route.meta
107
- const title = currentMenu?.label ?? getTitle(route) ?? import.meta.env.VITE_APP_TITLE
108
- const icon = currentMenu?.icon ?? mIcon?.()
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) ?? import.meta.env.VITE_APP_TITLE
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 { ref, computed, watch } from 'vue'
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 "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";
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 "../../../kitDependencies";
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 v-slot="{ Component, route }">
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 "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";
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) return;
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 { Tabs as ATabs, TabPane as ATabPane } from "ant-design-vue";
3
- import { getDependencies } from "../../../kitDependencies";
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,4 @@
1
+ export { setupPermissionRouterGuard } from './routerGuard';
2
+ export { setupPermissionPlugin } from './vuePlugin';
3
+ export { usePermission } from './usePermission';
4
+ export type { THasPermissionsFn } from './vuePlugin';
@@ -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,2 @@
1
+ export { setupPageProgress } from './pageProgress';
2
+ export { setupPageTitle } from './pageTitle';
@@ -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 }>();
@@ -3,4 +3,4 @@ export const shortcuts = [
3
3
  ['page-section', 'p-4 bg-$antd-colorBgContainer'],
4
4
  // 用于 FormItem 在 flex布局下的自适应
5
5
  [/^fiw-(.*?)_(.*?)_(.*?)$/, ([, w1, w2, w3]) => `min-w-${w1} w-${w2} max-w-${w3} flex-auto`],
6
- ]
6
+ ];