@vue-ui-kit/ant 1.6.0 → 1.7.1
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/dist/cjs/index.js +1 -1
- package/dist/declarations/antProxy.d.ts +6 -1
- package/dist/es/index.js +1496 -1157
- package/dist/packages/components/PromisePicker.vue.d.ts +11 -1
- package/package.json +1 -1
- package/src/declarations/antProxy.ts +6 -1
- package/src/packages/components/PFormGroup.vue +48 -12
- package/src/packages/components/PGrid.vue +26 -4
- package/src/packages/components/PromisePicker.vue +44 -5
|
@@ -5,11 +5,13 @@ declare const _default: <D = Recordable<any>, F = Recordable<any>>(__VLS_props:
|
|
|
5
5
|
title: string;
|
|
6
6
|
width: string | number;
|
|
7
7
|
bodyStyle: Record<string, any>;
|
|
8
|
+
multipleAllowEmpty: boolean;
|
|
8
9
|
}> & Omit<{
|
|
9
10
|
readonly title: string;
|
|
10
11
|
readonly width: string | number;
|
|
11
12
|
readonly bodyStyle: Record<string, any>;
|
|
12
13
|
readonly gridSetting: PGridProps<D, F>;
|
|
14
|
+
readonly multipleAllowEmpty: boolean;
|
|
13
15
|
} & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps & Readonly<import('vue').ExtractPropTypes<{
|
|
14
16
|
gridSetting: {
|
|
15
17
|
type: PropType<PGridProps<D, F>>;
|
|
@@ -23,15 +25,23 @@ declare const _default: <D = Recordable<any>, F = Recordable<any>>(__VLS_props:
|
|
|
23
25
|
type: PropType<string | number>;
|
|
24
26
|
default: string;
|
|
25
27
|
};
|
|
28
|
+
multipleAllowEmpty: {
|
|
29
|
+
type: BooleanConstructor;
|
|
30
|
+
default: boolean;
|
|
31
|
+
};
|
|
26
32
|
bodyStyle: {
|
|
27
33
|
type: ObjectConstructor;
|
|
28
34
|
default: () => {};
|
|
29
35
|
};
|
|
30
|
-
}>> & Readonly<{}>, "title" | "width" | "bodyStyle">, "gridSetting" | ("title" | "width" | "bodyStyle")> & {}> & import('vue').PublicProps;
|
|
36
|
+
}>> & Readonly<{}>, "title" | "width" | "bodyStyle" | "multipleAllowEmpty">, "gridSetting" | ("title" | "width" | "bodyStyle" | "multipleAllowEmpty")> & {}> & import('vue').PublicProps;
|
|
31
37
|
expose(exposed: import('vue').ShallowUnwrapRef<{
|
|
32
38
|
pick: () => Promise<{
|
|
33
39
|
row: D;
|
|
34
40
|
field?: string;
|
|
41
|
+
} | D[]>;
|
|
42
|
+
pickMultiple: () => Promise<D[] | {
|
|
43
|
+
row: D;
|
|
44
|
+
field?: string;
|
|
35
45
|
}>;
|
|
36
46
|
}>): void;
|
|
37
47
|
attrs: any;
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import { ColProps } from 'ant-design-vue/lib/grid/Col';
|
|
|
4
4
|
import { FormProps } from 'ant-design-vue/lib/form/Form';
|
|
5
5
|
import { TableColumnType, TableProps, TooltipProps } from 'ant-design-vue';
|
|
6
6
|
import { ButtonType } from 'ant-design-vue/lib/button/buttonTypes';
|
|
7
|
+
import { ComputedRef } from 'vue';
|
|
7
8
|
|
|
8
9
|
export interface CellFuncArg<D = Recordable> {
|
|
9
10
|
row: D;
|
|
@@ -89,7 +90,7 @@ export type GroupMenuItemHandler<F = Recordable> = ({
|
|
|
89
90
|
}: {
|
|
90
91
|
index: number;
|
|
91
92
|
code: string;
|
|
92
|
-
data: Partial<F>;
|
|
93
|
+
data: Partial<F & { __index: number }>;
|
|
93
94
|
}) => void;
|
|
94
95
|
|
|
95
96
|
export interface GroupMenuItem<F = Recordable> {
|
|
@@ -105,6 +106,8 @@ export interface PFormGroupProps<F = Recordable> {
|
|
|
105
106
|
tabLabel?: string;
|
|
106
107
|
editAble?: boolean;
|
|
107
108
|
showAdd?: boolean;
|
|
109
|
+
/* 是否保持连续编号 */
|
|
110
|
+
keepSerial?: boolean;
|
|
108
111
|
itemMenus?: Array<GroupMenuItem<F>>;
|
|
109
112
|
creatItem?: ({ list }: { list?: Partial<F>[] }) => Promise<Partial<F>>;
|
|
110
113
|
max?: number;
|
|
@@ -256,6 +259,7 @@ export interface PGridInstance<D = Recordable, F = Recordable> {
|
|
|
256
259
|
passQuery: (query: Partial<F>, lazy?: boolean) => Promise<void | D[]>;
|
|
257
260
|
};
|
|
258
261
|
selectedRowKeys: string[] | number[];
|
|
262
|
+
selectedRecords: D[];
|
|
259
263
|
$table: Recordable;
|
|
260
264
|
$form: Recordable;
|
|
261
265
|
setLoadings: (value: boolean) => void;
|
|
@@ -270,6 +274,7 @@ export interface PFormInstance {
|
|
|
270
274
|
|
|
271
275
|
export interface PromisePickerInstance<D = Recordable> {
|
|
272
276
|
pick: () => Promise<{ row: D; field?: string }>;
|
|
277
|
+
pickMultiple: () => Promise<D[]>;
|
|
273
278
|
}
|
|
274
279
|
|
|
275
280
|
export interface PFormBlockInstance {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts" generic="F = Recordable" setup name="PFormGroup">
|
|
2
|
-
import { computed, nextTick, PropType, ref } from 'vue';
|
|
2
|
+
import { computed, nextTick, PropType, ref, watchEffect } from 'vue';
|
|
3
3
|
import { PFormGroupProps, PFormBlockInstance } from '#/antProxy';
|
|
4
4
|
import { MoreOutlined } from '@ant-design/icons-vue';
|
|
5
|
-
import { cloneDeep, toString, isFunction, omit } from 'lodash-es';
|
|
5
|
+
import { cloneDeep, toString, isFunction, omit, maxBy, debounce } from 'lodash-es';
|
|
6
6
|
import PGroupBlock from '@/components/PGroupBlock.vue';
|
|
7
7
|
import {
|
|
8
8
|
Card as ACard,
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
Menu as AMenu,
|
|
14
14
|
MenuItem as AMenuItem,
|
|
15
15
|
} from 'ant-design-vue';
|
|
16
|
+
import { valued } from '@/utils/is';
|
|
17
|
+
import { MenuInfo } from 'ant-design-vue/es/menu/src/interface';
|
|
16
18
|
|
|
17
19
|
const props = defineProps<PFormGroupProps<F>>();
|
|
18
20
|
const model = defineModel({
|
|
19
|
-
type: Array as PropType<Partial<F>[]>,
|
|
21
|
+
type: Array as PropType<Partial<F & { __index: number }>[]>,
|
|
20
22
|
default: () => [],
|
|
21
23
|
});
|
|
22
24
|
const activeKey = ref(0);
|
|
@@ -24,18 +26,38 @@
|
|
|
24
26
|
const setActiveKey = (key: number) => {
|
|
25
27
|
activeKey.value = key;
|
|
26
28
|
};
|
|
27
|
-
const maxLen = props.max ?? Infinity;
|
|
29
|
+
const maxLen = computed(() => props.max ?? Infinity);
|
|
28
30
|
const handleAddItem = (idx: number) => {
|
|
29
31
|
const creator = props.creatItem ?? (() => Promise.resolve({} as Partial<F>));
|
|
30
32
|
creator({ list: model.value }).then((item) => {
|
|
31
|
-
model.value = [
|
|
33
|
+
model.value = [
|
|
34
|
+
...model.value,
|
|
35
|
+
{
|
|
36
|
+
...item,
|
|
37
|
+
__index: (maxBy(model.value, (m) => m.__index ?? -1)?.__index ?? -1) + 1,
|
|
38
|
+
} as Partial<F & { __index: number }>,
|
|
39
|
+
];
|
|
32
40
|
activeKey.value = idx;
|
|
33
41
|
});
|
|
34
42
|
};
|
|
35
|
-
const itemMenus = props.itemMenus ?? [
|
|
36
|
-
|
|
43
|
+
const itemMenus = props.itemMenus ?? [
|
|
44
|
+
{ content: '复制', code: 'copy' },
|
|
45
|
+
{ content: '删除', code: 'delete' },
|
|
46
|
+
];
|
|
47
|
+
watchEffect(() => {
|
|
48
|
+
if (!props.keepSerial) {
|
|
49
|
+
const unSortItems = model.value.filter((f) => !valued(f.__index));
|
|
50
|
+
if (unSortItems.length > 0) {
|
|
51
|
+
unSortItems.forEach((item) => {
|
|
52
|
+
// @ts-ignore
|
|
53
|
+
item.__index = (maxBy(model.value, (m) => m.__index ?? -1)?.__index ?? -1) + 1;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const handleMenu = ({ key }: MenuInfo, item: Partial<F & { __index: number }>, idx: number) => {
|
|
37
59
|
if (props.menuHandler && isFunction(props.menuHandler)) {
|
|
38
|
-
props.menuHandler({ code: key, data: item, index: idx });
|
|
60
|
+
props.menuHandler({ code: toString(key), data: item, index: idx });
|
|
39
61
|
} else {
|
|
40
62
|
switch (key) {
|
|
41
63
|
case 'delete':
|
|
@@ -48,11 +70,25 @@
|
|
|
48
70
|
});
|
|
49
71
|
break;
|
|
50
72
|
case 'copy':
|
|
51
|
-
model.value = [
|
|
73
|
+
model.value = [
|
|
74
|
+
...model.value,
|
|
75
|
+
cloneDeep({
|
|
76
|
+
...omit(item, ['id', '__index']),
|
|
77
|
+
__index: (maxBy(model.value, (m) => m.__index ?? -1)?.__index ?? -1) + 1,
|
|
78
|
+
}),
|
|
79
|
+
] as Partial<F & { __index: number }>[];
|
|
52
80
|
break;
|
|
53
81
|
}
|
|
54
82
|
}
|
|
55
83
|
};
|
|
84
|
+
const debounceHandleMenu = debounce(handleMenu, 100);
|
|
85
|
+
watchEffect(() => {
|
|
86
|
+
if (model.value.length === 0) {
|
|
87
|
+
activeKey.value = 0;
|
|
88
|
+
} else if (activeKey.value >= model.value.length) {
|
|
89
|
+
activeKey.value = model.value.length - 1;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
56
92
|
defineExpose({
|
|
57
93
|
activeKey: computed(() => activeKey.value),
|
|
58
94
|
setActiveKey,
|
|
@@ -69,9 +105,9 @@
|
|
|
69
105
|
<template #rightExtra>
|
|
70
106
|
<slot name="rightExtra">
|
|
71
107
|
<a-button
|
|
108
|
+
v-if="showAdd && model.length < maxLen"
|
|
72
109
|
type="link"
|
|
73
110
|
@click="handleAddItem(model.length)"
|
|
74
|
-
v-if="showAdd && model.length < maxLen"
|
|
75
111
|
>
|
|
76
112
|
+ 新增
|
|
77
113
|
</a-button>
|
|
@@ -80,14 +116,14 @@
|
|
|
80
116
|
<a-tab-pane
|
|
81
117
|
v-for="(item, idx) in model"
|
|
82
118
|
:key="idx"
|
|
83
|
-
:tab="`${tabLabel} ${idx + 1}`"
|
|
119
|
+
:tab="`${tabLabel} ${keepSerial ? idx + 1 : (item.__index ?? 0) + 1}`"
|
|
84
120
|
force-render
|
|
85
121
|
>
|
|
86
122
|
<template #closeIcon>
|
|
87
123
|
<a-dropdown v-if="editAble && itemMenus?.length">
|
|
88
124
|
<MoreOutlined />
|
|
89
125
|
<template #overlay>
|
|
90
|
-
<a-menu @click="(e) =>
|
|
126
|
+
<a-menu @click="(e) => debounceHandleMenu(e, item, idx)">
|
|
91
127
|
<a-menu-item
|
|
92
128
|
v-for="menu in itemMenus.filter(
|
|
93
129
|
(f) => f.visibleMethod?.({ data: item, index: idx }) ?? true,
|
|
@@ -393,7 +393,10 @@
|
|
|
393
393
|
const resizeTable = () => {
|
|
394
394
|
const pNode = boxEl.value?.parentElement;
|
|
395
395
|
const ph = pNode ? window.getComputedStyle(pNode).height : '0px';
|
|
396
|
-
const
|
|
396
|
+
const formOriginHeight = pFormWrapper.value
|
|
397
|
+
? window.getComputedStyle(pFormWrapper.value).height
|
|
398
|
+
: '0px';
|
|
399
|
+
const formHeight = formOriginHeight.includes('px')
|
|
397
400
|
? toNumber(window.getComputedStyle(pFormWrapper.value).height.replace('px', ''))
|
|
398
401
|
: 0;
|
|
399
402
|
|
|
@@ -424,13 +427,32 @@
|
|
|
424
427
|
},
|
|
425
428
|
resizeTable,
|
|
426
429
|
});
|
|
430
|
+
|
|
431
|
+
let observer: MutationObserver;
|
|
427
432
|
onMounted(() => {
|
|
428
433
|
resizeTable();
|
|
429
434
|
window.addEventListener('resize', resizeTable);
|
|
435
|
+
// 还需要在组件根节点由不可见转为可见时重新计算高度(display:none等样式控制时)
|
|
436
|
+
observer = new MutationObserver((mutations) => {
|
|
437
|
+
mutations.forEach((mutation) => {
|
|
438
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
|
|
439
|
+
const el = mutation.target as HTMLElement;
|
|
440
|
+
const style = window.getComputedStyle(el);
|
|
441
|
+
if (style.display !== 'none') {
|
|
442
|
+
handlePageResize();
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
if (boxEl.value) {
|
|
449
|
+
observer.observe(boxEl.value, { attributes: true, attributeFilter: ['style'] });
|
|
450
|
+
}
|
|
430
451
|
resetQueryFormData(props.manualFetch);
|
|
431
452
|
});
|
|
432
453
|
onBeforeUnmount(() => {
|
|
433
454
|
window.removeEventListener('resize', resizeTable);
|
|
455
|
+
observer.disconnect();
|
|
434
456
|
});
|
|
435
457
|
</script>
|
|
436
458
|
<template>
|
|
@@ -529,7 +551,7 @@
|
|
|
529
551
|
</template>
|
|
530
552
|
<a-button
|
|
531
553
|
:type="btn.type"
|
|
532
|
-
:size="btn.size ?? '
|
|
554
|
+
:size="btn.size ?? 'middle'"
|
|
533
555
|
:disabled="toolbarConfig.disabled || btn.disabled"
|
|
534
556
|
:loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])"
|
|
535
557
|
>
|
|
@@ -541,7 +563,7 @@
|
|
|
541
563
|
<a-button
|
|
542
564
|
v-else-if="btn.code"
|
|
543
565
|
:type="btn.type"
|
|
544
|
-
:size="btn.size ?? '
|
|
566
|
+
:size="btn.size ?? 'middle'"
|
|
545
567
|
:disabled="toolbarConfig.disabled || btn.disabled"
|
|
546
568
|
:loading="loading.toolbar || (!!btn.code && codeLoadings[btn.code])"
|
|
547
569
|
@click="debounceToolBtnClick(btn.code)"
|
|
@@ -559,7 +581,7 @@
|
|
|
559
581
|
v-for="(tool, idx) in toolbarConfig.tools"
|
|
560
582
|
:key="idx"
|
|
561
583
|
:type="tool.type"
|
|
562
|
-
size="
|
|
584
|
+
:size="btn.size ?? 'middle'"
|
|
563
585
|
:disabled="toolbarConfig.disabled || tool.disabled"
|
|
564
586
|
@click="debounceToolToolClick(tool.code)"
|
|
565
587
|
:loading="loading.toolbar || (!!tool.code && codeLoadings[tool.code])"
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
<script lang="ts" setup name="PromisePicker" generic="D = Recordable, F = Recordable">
|
|
2
|
-
import { PropType, reactive, ref } from 'vue';
|
|
2
|
+
import { PropType, reactive, ref, computed } from 'vue';
|
|
3
3
|
import { PGridInstance, PGridProps } from '#/antProxy';
|
|
4
4
|
import PGrid from '@/components/PGrid.vue';
|
|
5
|
+
import { $warning } from '@/hooks/useMessage';
|
|
6
|
+
import { Button as AButton, Modal as AModal } from 'ant-design-vue';
|
|
5
7
|
|
|
6
8
|
const gridEl = ref<PGridInstance<D>>();
|
|
7
|
-
defineProps({
|
|
9
|
+
const props = defineProps({
|
|
8
10
|
gridSetting: {
|
|
9
11
|
type: Object as PropType<PGridProps<D, F>>,
|
|
10
12
|
required: true,
|
|
@@ -17,14 +19,20 @@
|
|
|
17
19
|
type: [String, Number] as PropType<string | number>,
|
|
18
20
|
default: '70%',
|
|
19
21
|
},
|
|
22
|
+
multipleAllowEmpty: {
|
|
23
|
+
type: Boolean,
|
|
24
|
+
default: false,
|
|
25
|
+
},
|
|
20
26
|
bodyStyle: {
|
|
21
27
|
type: Object,
|
|
22
28
|
default: () => ({}),
|
|
23
29
|
},
|
|
24
30
|
});
|
|
31
|
+
const isMultiple = computed(() => props.gridSetting.selectConfig?.multiple);
|
|
25
32
|
let resolvePromise: (
|
|
26
33
|
value: { row: D; field?: string } | PromiseLike<{ row: D; field?: string }>,
|
|
27
34
|
) => void;
|
|
35
|
+
let multipleResolver: (rows: D[]) => void;
|
|
28
36
|
let rejectPromise: (reason?: any) => void;
|
|
29
37
|
const visible = reactive({
|
|
30
38
|
modal: false,
|
|
@@ -34,19 +42,42 @@
|
|
|
34
42
|
rejectPromise();
|
|
35
43
|
}
|
|
36
44
|
};
|
|
45
|
+
|
|
46
|
+
const manualCancel = () => {
|
|
47
|
+
visible.modal = false;
|
|
48
|
+
if (rejectPromise) {
|
|
49
|
+
rejectPromise();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
37
52
|
const selectRow = ({ row, field }: { row: D; field?: string }) => {
|
|
38
|
-
|
|
53
|
+
// 单选才关闭结束选择
|
|
54
|
+
if (resolvePromise && !isMultiple.value) {
|
|
39
55
|
visible.modal = false;
|
|
40
56
|
resolvePromise({ row, field });
|
|
41
57
|
}
|
|
42
58
|
};
|
|
59
|
+
const endMultiplePicker = () => {
|
|
60
|
+
const records = gridEl.value?.selectedRecords ?? [];
|
|
61
|
+
if (records.length === 0 && !props.multipleAllowEmpty) {
|
|
62
|
+
$warning('请选择数据');
|
|
63
|
+
} else {
|
|
64
|
+
visible.modal = false;
|
|
65
|
+
multipleResolver(records);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
43
68
|
defineExpose({
|
|
44
69
|
pick: () =>
|
|
45
|
-
new Promise<{ row: D; field?: string }>((resolve, reject) => {
|
|
70
|
+
new Promise<{ row: D; field?: string } | D[]>((resolve, reject) => {
|
|
46
71
|
resolvePromise = resolve;
|
|
47
72
|
rejectPromise = reject;
|
|
48
73
|
visible.modal = true;
|
|
49
74
|
}),
|
|
75
|
+
pickMultiple: () =>
|
|
76
|
+
new Promise<{ row: D; field?: string } | D[]>((resolve, reject) => {
|
|
77
|
+
multipleResolver = resolve;
|
|
78
|
+
rejectPromise = reject;
|
|
79
|
+
visible.modal = true;
|
|
80
|
+
}),
|
|
50
81
|
});
|
|
51
82
|
</script>
|
|
52
83
|
<template>
|
|
@@ -55,10 +86,18 @@
|
|
|
55
86
|
destroy-on-close
|
|
56
87
|
:title="title"
|
|
57
88
|
:width="width"
|
|
58
|
-
:footer="null"
|
|
89
|
+
:footer="isMultiple ? undefined : null"
|
|
59
90
|
@cancel="handleCancel"
|
|
60
91
|
:body-style="bodyStyle"
|
|
61
92
|
>
|
|
62
93
|
<p-grid v-bind="gridSetting" ref="gridEl" @pick="selectRow" />
|
|
94
|
+
<template v-if="isMultiple" #footer>
|
|
95
|
+
<div class="w-full text-right p-2">
|
|
96
|
+
<span>
|
|
97
|
+
<a-button class="mr-4" @click="manualCancel"> 取消 </a-button>
|
|
98
|
+
<a-button type="primary" @click="endMultiplePicker"> 确定 </a-button>
|
|
99
|
+
</span>
|
|
100
|
+
</div>
|
|
101
|
+
</template>
|
|
63
102
|
</a-modal>
|
|
64
103
|
</template>
|