@peng_kai/kit 0.1.17 → 0.2.0-beta.0
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/admin/adminPlugin.ts +47 -0
- package/admin/components/filter/src/FilterParam.vue +76 -78
- package/admin/components/filter/src/FilterReset.vue +2 -2
- package/admin/components/filter/src/useFilterParams.ts +75 -25
- package/admin/components/filter/src/useFilterQuery.ts +32 -16
- package/admin/components/rich-text/index.ts +2 -0
- package/admin/components/rich-text/src/RichText.vue +342 -0
- package/admin/components/rich-text/src/imageUploader.ts +34 -0
- package/admin/components/rich-text/src/type.d.ts +7 -0
- package/admin/components/text/src/Datetime.vue +47 -48
- package/admin/components/upload/index.ts +2 -0
- package/admin/components/upload/src/PictureCardUpload.vue +143 -0
- package/admin/components/upload/src/customRequests.ts +31 -0
- package/admin/defines/index.ts +1 -1
- package/admin/defines/route/helpers.ts +0 -1
- package/admin/defines/startup/defineStartup.ts +8 -1
- package/admin/defines/startup/index.ts +1 -1
- package/admin/defines/startup/{getStartups.ts → runStartup.ts} +16 -7
- package/admin/layout/large/Breadcrumb.vue +68 -69
- package/admin/layout/large/Content.vue +23 -24
- package/admin/layout/large/Menu.vue +68 -69
- package/admin/layout/large/PageTab.vue +70 -71
- package/admin/permission/index.ts +2 -4
- package/admin/permission/routerGuard.ts +41 -43
- package/admin/permission/vuePlugin.ts +46 -30
- package/admin/route-guards/collapseMenu.ts +3 -3
- package/admin/route-guards/pageTitle.ts +18 -19
- package/admin/{hooks/useMenu.ts → stores/createUseMenuStore.ts} +133 -128
- package/admin/{hooks/usePage.ts → stores/createUsePageStore.ts} +145 -141
- package/admin/stores/createUsePageTabStore.ts +43 -0
- package/admin/{permission/usePermission.ts → stores/createUsePermissionStore.ts} +57 -52
- package/admin/stores/index.ts +8 -0
- package/admin/styles/classCover.scss +8 -0
- package/antd/hooks/useAntdForm.helpers.ts +92 -8
- package/antd/hooks/useAntdForm.ts +55 -63
- package/antd/hooks/useAntdTable.ts +12 -0
- package/antd/index.ts +1 -1
- package/libs/a-calc.ts +1 -0
- package/libs/axios.ts +2 -0
- package/libs/bignumber.ts +2 -0
- package/libs/dayjs.ts +5 -0
- package/libs/echarts.ts +5 -0
- package/libs/localstorage-slim.ts +2 -0
- package/libs/lodash-es.ts +1 -0
- package/libs/pinia.ts +1 -0
- package/libs/vue-query.ts +1 -0
- package/libs/vueuse.ts +3 -0
- package/package.json +55 -16
- package/request/helpers.ts +20 -1
- package/request/queryClient.ts +34 -21
- package/utils/upload/AwsS3.ts +76 -0
- package/utils/upload/fileHandlers.ts +27 -0
- package/utils/upload/index.ts +2 -0
- package/vite/index.d.ts +1 -0
- package/vite/index.mjs +27 -0
- package/vue/components/echarts/index.ts +1 -0
- package/vue/components/echarts/src/ECharts.vue +48 -0
- package/vue/components/index.ts +1 -0
- package/vue/components/infinite-query/src/InfiniteQuery.vue +2 -8
- package/vue/components/test/KitTest.vue +9 -0
- package/vue/components/test/testStore.ts +11 -0
- package/admin/hooks/index.ts +0 -5
- package/admin/hooks/usePageTab.ts +0 -35
- package/kitDependencies.ts +0 -43
|
@@ -1,141 +1,145 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import type { TMenu } from './
|
|
9
|
-
|
|
10
|
-
export {
|
|
11
|
-
export type { TPageState, IBreadcrumb };
|
|
12
|
-
|
|
13
|
-
type TPageState = ReturnType<typeof getPageState>;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
1
|
+
import { usePrevious } from '@vueuse/core';
|
|
2
|
+
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
|
3
|
+
import { defineStore } from 'pinia';
|
|
4
|
+
import { computed, reactive, readonly, ref, shallowRef, watch } from 'vue';
|
|
5
|
+
import type { VNode } from 'vue';
|
|
6
|
+
import { getTitle } from '../defines/route';
|
|
7
|
+
import { adminPlugin } from '../adminPlugin';
|
|
8
|
+
import type { TMenu } from './createUseMenuStore';
|
|
9
|
+
|
|
10
|
+
export { createUsePageStore };
|
|
11
|
+
export type { TPageState, TUsePageStore, IBreadcrumb };
|
|
12
|
+
|
|
13
|
+
type TPageState = ReturnType<typeof getPageState>;
|
|
14
|
+
type TUsePageStore = ReturnType<typeof createUsePageStore>;
|
|
15
|
+
|
|
16
|
+
interface IBreadcrumb {
|
|
17
|
+
title: string
|
|
18
|
+
icon?: VNode | null
|
|
19
|
+
trigger?: () => void
|
|
20
|
+
children?: IBreadcrumb[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createUsePageStore() {
|
|
24
|
+
return defineStore('appPage', () => {
|
|
25
|
+
return storeSetup();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function storeSetup() {
|
|
30
|
+
const router = adminPlugin.deps.router;
|
|
31
|
+
const currentPageNode = shallowRef<VNode>();
|
|
32
|
+
const currentPageKey = ref('');
|
|
33
|
+
const pageCacheList = reactive<string[]>([]);
|
|
34
|
+
const pageStateMap = new Map<string, TPageState>();
|
|
35
|
+
const currentPageState = computed(() => pageStateMap.get(currentPageKey.value));
|
|
36
|
+
const previousPageState = usePrevious(currentPageState);
|
|
37
|
+
|
|
38
|
+
const openPage = (key: string) => {
|
|
39
|
+
const route = pageStateMap.get(key)?.route;
|
|
40
|
+
|
|
41
|
+
if (!route)
|
|
42
|
+
return;
|
|
43
|
+
|
|
44
|
+
router.push(route.fullPath);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const closePage = (key: string) => {
|
|
48
|
+
if (!pageStateMap.has(key))
|
|
49
|
+
return;
|
|
50
|
+
|
|
51
|
+
const cacheIndex = pageCacheList.indexOf(key);
|
|
52
|
+
cacheIndex >= 0 && pageCacheList.splice(cacheIndex, 1);
|
|
53
|
+
// 关闭当前页面则返回上一个路由
|
|
54
|
+
currentPageKey.value === key && router.go(-1);
|
|
55
|
+
pageStateMap.delete(key);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const setPage = (pageNode: VNode, route: RouteLocationNormalizedLoaded) => {
|
|
59
|
+
const pageKey = route?.meta?.pageKeyFn?.(route) ?? route.fullPath;
|
|
60
|
+
const pageInfo = getPageState(route);
|
|
61
|
+
const canKeepAlive = route.meta.keepAlive && !pageCacheList.includes(pageKey);
|
|
62
|
+
|
|
63
|
+
canKeepAlive && pageCacheList.push(pageKey);
|
|
64
|
+
pageStateMap.has(pageKey) || pageStateMap.set(pageKey, pageInfo)
|
|
65
|
+
|
|
66
|
+
;(pageNode as any).type.name = pageKey;
|
|
67
|
+
currentPageKey.value = pageKey;
|
|
68
|
+
currentPageNode.value = pageNode;
|
|
69
|
+
|
|
70
|
+
return pageNode;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const getCurrentPageState = () => {
|
|
74
|
+
return pageStateMap.get(currentPageKey.value);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// 监听 title 变化
|
|
78
|
+
watch(() => currentPageState.value?.title, (title) => {
|
|
79
|
+
let _title = title;
|
|
80
|
+
|
|
81
|
+
if (!_title) {
|
|
82
|
+
const pageState = currentPageState.value;
|
|
83
|
+
|
|
84
|
+
// 当前 title 为空时,使用路由 title
|
|
85
|
+
if (pageState) {
|
|
86
|
+
_title = getTitle(pageState?.route);
|
|
87
|
+
pageState.title = _title!;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
document.title = _title!;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
currentPageNode,
|
|
96
|
+
pageCacheList,
|
|
97
|
+
pageStateMap,
|
|
98
|
+
currentPageKey,
|
|
99
|
+
currentPageState,
|
|
100
|
+
getCurrentPageState,
|
|
101
|
+
previousPageState,
|
|
102
|
+
setPage,
|
|
103
|
+
openPage,
|
|
104
|
+
closePage,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getPageState(route: RouteLocationNormalizedLoaded) {
|
|
109
|
+
const menuStore = adminPlugin.deps.useMenuStore()!;
|
|
110
|
+
const appName = adminPlugin.meta.appName;
|
|
111
|
+
const menuPath = menuStore.getMenuPath(route.name as string);
|
|
112
|
+
const currentMenu = menuPath.pop();
|
|
113
|
+
const { icon: mIcon } = route.meta;
|
|
114
|
+
const title = currentMenu?.label ?? getTitle(route) ?? appName;
|
|
115
|
+
const icon = currentMenu?.icon ?? mIcon?.();
|
|
116
|
+
const state = reactive({
|
|
117
|
+
title,
|
|
118
|
+
icon,
|
|
119
|
+
breadcrumbs: menuPath.map(menuToBreadcrumb),
|
|
120
|
+
route: readonly(route),
|
|
121
|
+
refresh() {
|
|
122
|
+
const menuKey = this.route.name as string;
|
|
123
|
+
const menu = menuStore.getMenu(menuKey);
|
|
124
|
+
const menuPath = menuStore.getMenuPath(menuKey);
|
|
125
|
+
|
|
126
|
+
menuPath.pop();
|
|
127
|
+
|
|
128
|
+
this.title = menu?.label ?? getTitle(this.route) ?? appName;
|
|
129
|
+
this.breadcrumbs = menuPath.map(menuToBreadcrumb);
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return state;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function menuToBreadcrumb(menu: TMenu) {
|
|
137
|
+
const ret: IBreadcrumb = reactive({
|
|
138
|
+
title: menu.label,
|
|
139
|
+
icon: menu.icon,
|
|
140
|
+
trigger: menu.trigger,
|
|
141
|
+
children: menu.children?.map(menuToBreadcrumb),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return ret;
|
|
145
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { defineStore, storeToRefs } from 'pinia';
|
|
2
|
+
import { computed, ref, watch } from 'vue';
|
|
3
|
+
import { adminPlugin } from '../adminPlugin';
|
|
4
|
+
|
|
5
|
+
export { createUsePageTabStore };
|
|
6
|
+
export type { TUsePageTabStore };
|
|
7
|
+
|
|
8
|
+
type TUsePageTabStore = ReturnType<typeof createUsePageTabStore>;
|
|
9
|
+
|
|
10
|
+
function createUsePageTabStore() {
|
|
11
|
+
return defineStore('appPageTab', () => storeSetup());
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function storeSetup() {
|
|
15
|
+
const pageStore = adminPlugin.deps.usePageStore!();
|
|
16
|
+
const { currentPageKey } = storeToRefs(pageStore);
|
|
17
|
+
const tabKeyList = ref<string[]>([]);
|
|
18
|
+
const tabList = computed(() => tabKeyList.value.map((key) => {
|
|
19
|
+
const state = pageStore.pageStateMap.get(key);
|
|
20
|
+
|
|
21
|
+
return state ? { key, title: state.title, icon: state.icon } : undefined!;
|
|
22
|
+
}).filter(tab => !!tab));
|
|
23
|
+
|
|
24
|
+
const closeTab = (key: string) => {
|
|
25
|
+
const i = tabKeyList.value.indexOf(key);
|
|
26
|
+
|
|
27
|
+
if (i > -1) {
|
|
28
|
+
pageStore.closePage(key);
|
|
29
|
+
setTimeout(() => tabKeyList.value.splice(i, 1));
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
watch(
|
|
34
|
+
() => pageStore.currentPageKey,
|
|
35
|
+
(key) => {
|
|
36
|
+
if (!tabKeyList.value.includes(key))
|
|
37
|
+
tabKeyList.value.push(key);
|
|
38
|
+
},
|
|
39
|
+
{ immediate: true },
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return { activeTab: currentPageKey, tabList, closeTab, openTab: pageStore.openPage };
|
|
43
|
+
}
|
|
@@ -1,52 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
export type { TRole };
|
|
8
|
-
|
|
9
|
-
type TRole = () => Promise<Record<string, boolean> | null | undefined>;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
1
|
+
import { computed, readonly, ref, watch } from 'vue';
|
|
2
|
+
import { defineStore } from 'pinia';
|
|
3
|
+
import type { AsyncReturnType } from 'type-fest';
|
|
4
|
+
import { adminPlugin } from '../adminPlugin';
|
|
5
|
+
|
|
6
|
+
export { createUsePermissionStore };
|
|
7
|
+
export type { TRole, TUsePermissionStore };
|
|
8
|
+
|
|
9
|
+
type TRole = () => Promise<Record<string, boolean> | null | undefined>;
|
|
10
|
+
type TUsePermissionStore = ReturnType<typeof createUsePermissionStore>;
|
|
11
|
+
|
|
12
|
+
function createUsePermissionStore() {
|
|
13
|
+
return defineStore('appPermission', () => storeSetup());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function storeSetup() {
|
|
17
|
+
const roles = adminPlugin.deps.roles;
|
|
18
|
+
const role = ref('main');
|
|
19
|
+
const permissionCodes = ref<AsyncReturnType<TRole>>();
|
|
20
|
+
const permissionCodesStr = computed(() => Object.keys(permissionCodes.value ?? {}).sort().join(','));
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 刷新权限
|
|
24
|
+
*/
|
|
25
|
+
const refreshPermission = async () => {
|
|
26
|
+
permissionCodes.value = await roles?.[role.value]?.();
|
|
27
|
+
|
|
28
|
+
return permissionCodes.value;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 是否满足权限要求
|
|
33
|
+
* @param codes 权限 code
|
|
34
|
+
*/
|
|
35
|
+
const hasPermission = (codes: string | string[]) => {
|
|
36
|
+
const _codes = Array.isArray(codes) ? codes : [codes];
|
|
37
|
+
const _permissionCodes = permissionCodes.value;
|
|
38
|
+
|
|
39
|
+
if (_permissionCodes === null)
|
|
40
|
+
return false;
|
|
41
|
+
else if (_permissionCodes === undefined)
|
|
42
|
+
// undefined 则表示没有权限要求,返回 true
|
|
43
|
+
return true;
|
|
44
|
+
else
|
|
45
|
+
return _codes.every(code => !!_permissionCodes[code]);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
watch(role, refreshPermission, { immediate: true });
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
permissionCodes: readonly(permissionCodes),
|
|
52
|
+
permissionCodesStr,
|
|
53
|
+
role,
|
|
54
|
+
hasPermission,
|
|
55
|
+
refreshPermission,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createUsePageStore } from './createUsePageStore';
|
|
2
|
+
export { createUseMenuStore } from './createUseMenuStore';
|
|
3
|
+
export { createUsePageTabStore } from './createUsePageTabStore';
|
|
4
|
+
export { createUsePermissionStore } from './createUsePermissionStore';
|
|
5
|
+
|
|
6
|
+
export type { TPageState, TUsePageStore, IBreadcrumb } from './createUsePageStore';
|
|
7
|
+
export type { TUseMenuStore } from './createUseMenuStore';
|
|
8
|
+
export type { TUsePageTabStore } from './createUsePageTabStore';
|
|
@@ -48,6 +48,14 @@
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// 表单两列布局
|
|
52
|
+
.ant-form.ant-cover__col2-form {
|
|
53
|
+
display: grid;
|
|
54
|
+
grid-template-columns: repeat(2, 1fr);
|
|
55
|
+
column-gap: 24px;
|
|
56
|
+
align-content: flex-start;
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
// 弹窗的基本款样式
|
|
52
60
|
.ant-modal-wrap.antd-cover__basic-modal {
|
|
53
61
|
--padding-size: 22px;
|
|
@@ -1,15 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
import type { FormItemProps } from 'ant-design-vue/es/form';
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
buildGroupField,
|
|
5
|
+
parseGroupField,
|
|
6
|
+
groupingForm,
|
|
7
|
+
formatGroup,
|
|
8
|
+
isSameGroup,
|
|
9
|
+
isSameField,
|
|
10
|
+
getGroupIndex,
|
|
11
|
+
GROUP_SEP,
|
|
12
|
+
};
|
|
2
13
|
|
|
3
14
|
const GROUP_SEP = '__';
|
|
4
15
|
const groupFieldNameRE = new RegExp(
|
|
5
|
-
`(?<groupName
|
|
16
|
+
`(?<groupName>.+?)${GROUP_SEP}(?<index>\\d+)${GROUP_SEP}(?<fieldName>.+)`,
|
|
6
17
|
);
|
|
7
18
|
|
|
8
|
-
|
|
19
|
+
/**
|
|
20
|
+
* 构建组字段名
|
|
21
|
+
* @param name - 组名
|
|
22
|
+
* @param index - 组索引
|
|
23
|
+
* @param field - 字段名
|
|
24
|
+
* @returns 返回组字段名
|
|
25
|
+
*/
|
|
26
|
+
function buildGroupField(name: string, index: number, field: string) {
|
|
9
27
|
return name + GROUP_SEP + index + GROUP_SEP + field;
|
|
10
28
|
}
|
|
11
29
|
|
|
12
|
-
|
|
30
|
+
/**
|
|
31
|
+
* 解析组字段名
|
|
32
|
+
* @param name - 组字段名
|
|
33
|
+
* @returns 返回一个数组,包含组名、组索引和字段名
|
|
34
|
+
*/
|
|
35
|
+
function parseGroupField(name: string) {
|
|
13
36
|
const res = name.match(groupFieldNameRE);
|
|
14
37
|
const ret = {
|
|
15
38
|
fieldName: '',
|
|
@@ -26,23 +49,84 @@ function parseGroupFieldName(name: string) {
|
|
|
26
49
|
return ret;
|
|
27
50
|
}
|
|
28
51
|
|
|
52
|
+
/**
|
|
53
|
+
* 根据指定的组名对表单项进行分组
|
|
54
|
+
* @param groupName - 要分组的组名
|
|
55
|
+
* @param items - 包含表单项的对象
|
|
56
|
+
* @returns 返回一个对象,其键为组索引,值为该组内的表单项
|
|
57
|
+
*/
|
|
58
|
+
function groupingForm(groupName: string, items: Record<string, FormItemProps>) {
|
|
59
|
+
const _groups: Record<number, typeof items> = {};
|
|
60
|
+
|
|
61
|
+
for (const [key, item] of Object.entries(items)) {
|
|
62
|
+
const { groupName: name, index } = parseGroupField(key);
|
|
63
|
+
|
|
64
|
+
if (name === groupName) {
|
|
65
|
+
_groups[index] ??= {};
|
|
66
|
+
_groups[index][key] = item;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return _groups;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 格式化表单项组
|
|
75
|
+
* @param name - 组名
|
|
76
|
+
* @param items - 包含表单数据
|
|
77
|
+
* @returns 返回一个数组,其元素为分组后的表单项对象,如果没有找到匹配的组名,则返回 undefined
|
|
78
|
+
*/
|
|
79
|
+
function formatGroup(name: string, items: Record<string, any>) {
|
|
80
|
+
const group: any[] = [];
|
|
81
|
+
|
|
82
|
+
for (const k in items) {
|
|
83
|
+
const params = parseGroupField(k);
|
|
84
|
+
|
|
85
|
+
if (params.groupName !== name || params.index === -1)
|
|
86
|
+
continue;
|
|
87
|
+
|
|
88
|
+
group[params.index] ??= {};
|
|
89
|
+
group[params.index][params.fieldName] = items[k];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return group?.length ? group.filter(g => !!g) : undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 获取指定组名的最大索引值
|
|
97
|
+
* @param name - 组名
|
|
98
|
+
* @param schemas - 包含组字段的对象
|
|
99
|
+
* @returns 返回指定组名的最大索引值,如果没有找到匹配的组名,则返回 -1
|
|
100
|
+
*/
|
|
29
101
|
function getGroupIndex(name: string, schemas: Record<string, any>) {
|
|
30
102
|
const indexs = Object.keys(schemas).map((key) => {
|
|
31
|
-
const { groupName, index } =
|
|
103
|
+
const { groupName, index } = parseGroupField(key);
|
|
32
104
|
return groupName === name ? index : -1;
|
|
33
105
|
});
|
|
34
106
|
|
|
35
|
-
return Math.max
|
|
107
|
+
return Math.max(...indexs);
|
|
36
108
|
}
|
|
37
109
|
|
|
110
|
+
/**
|
|
111
|
+
* 判断指定的名称是否属于同一组
|
|
112
|
+
* @param name - 要检查的名称
|
|
113
|
+
* @param groupName - 组名
|
|
114
|
+
* @returns 如果指定的名称属于同一组,则返回 true,否则返回 false
|
|
115
|
+
*/
|
|
38
116
|
function isSameGroup(name: string, groupName: string) {
|
|
39
|
-
const { groupName: gn } =
|
|
117
|
+
const { groupName: gn } = parseGroupField(name);
|
|
40
118
|
|
|
41
119
|
return gn === groupName;
|
|
42
120
|
}
|
|
43
121
|
|
|
122
|
+
/**
|
|
123
|
+
* 判断指定的字段名是否相同
|
|
124
|
+
* @param name - 要检查的名称
|
|
125
|
+
* @param fieldName - 字段名
|
|
126
|
+
* @returns 如果指定的名称和字段名相同,则返回 true,否则返回 false
|
|
127
|
+
*/
|
|
44
128
|
function isSameField(name: string, fieldName: string) {
|
|
45
|
-
const { fieldName: fn } =
|
|
129
|
+
const { fieldName: fn } = parseGroupField(name);
|
|
46
130
|
|
|
47
131
|
return fn === fieldName;
|
|
48
132
|
}
|