@vue-ui-kit/ant 1.7.4 → 1.8.2
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/README.md +430 -233
- package/README.zh.md +446 -303
- package/dist/cjs/index.js +1 -1
- package/dist/declarations/antProxy.d.ts +7 -1
- package/dist/es/index.js +3038 -2244
- package/dist/index.d.ts +5 -1
- package/dist/packages/components/PFormCol.vue.d.ts +28 -0
- package/dist/packages/components/PFormGroup.vue.d.ts +2 -2
- package/dist/packages/components/PGrid.vue.d.ts +3 -2
- package/dist/packages/renders/TableInput.vue.d.ts +3 -3
- package/dist/packages/utils/config.d.ts +17 -0
- package/dist/packages/utils/core.d.ts +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -4
- package/src/declarations/antProxy.ts +8 -1
- package/src/index.ts +16 -0
- package/src/packages/components/PForm.vue +34 -85
- package/src/packages/components/PFormCol.vue +97 -0
- package/src/packages/components/PFormGroup.vue +90 -28
- package/src/packages/components/PGrid.vue +38 -81
- package/src/packages/renders/TableInput.vue +1 -1
- package/src/packages/store/renderStore.tsx +1 -1
- package/src/packages/styles/index.scss +80 -1
- package/src/packages/utils/AFormatters.ts +1 -1
- package/src/packages/utils/config.ts +72 -0
- package/src/packages/utils/core.ts +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script lang="ts" generic="F = Recordable" setup name="PFormGroup">
|
|
2
|
-
import { computed, nextTick, PropType, ref, watchEffect } from 'vue';
|
|
2
|
+
import { computed, nextTick, PropType, ref, watch, watchEffect } from 'vue';
|
|
3
3
|
import { PFormGroupProps, PFormBlockInstance } from '#/antProxy';
|
|
4
4
|
import { MoreOutlined } from '@ant-design/icons-vue';
|
|
5
|
+
import type { Tabs } from 'ant-design-vue'
|
|
5
6
|
import { Form } from 'ant-design-vue'
|
|
6
|
-
import {
|
|
7
|
+
import { clone, toString, isFunction, omit, max, debounce } from 'xe-utils';
|
|
7
8
|
import PGroupBlock from '@/components/PGroupBlock.vue';
|
|
8
9
|
import {
|
|
9
10
|
Card as ACard,
|
|
@@ -19,25 +20,28 @@
|
|
|
19
20
|
import { $warning } from '@/hooks/useMessage';
|
|
20
21
|
|
|
21
22
|
const useForm = Form.useForm
|
|
23
|
+
const tabsRef = ref<InstanceType<typeof Tabs>>()
|
|
22
24
|
const props = defineProps<PFormGroupProps<F>>();
|
|
25
|
+
const rootRef = ref<InstanceType<typeof ACard>>()
|
|
23
26
|
const model = defineModel({
|
|
24
27
|
type: Array as PropType<Partial<F & { __index: number }>[]>,
|
|
25
28
|
default: () => [],
|
|
26
29
|
});
|
|
27
30
|
const activeKey = ref(0);
|
|
31
|
+
const error_indexes = ref<number[]>([])
|
|
28
32
|
const blockInstance = ref<PFormBlockInstance[]>([]);
|
|
29
33
|
const setActiveKey = (key: number) => {
|
|
30
34
|
activeKey.value = key;
|
|
31
35
|
};
|
|
32
36
|
const maxLen = computed(() => props.max ?? Infinity);
|
|
33
37
|
const handleAddItem = (idx: number) => {
|
|
34
|
-
const creator = props.
|
|
38
|
+
const creator = props.createItem ?? (() => Promise.resolve({} as Partial<F>));
|
|
35
39
|
creator({ list: model.value }).then((item) => {
|
|
36
40
|
model.value = [
|
|
37
41
|
...model.value,
|
|
38
42
|
{
|
|
39
43
|
...item,
|
|
40
|
-
__index: (
|
|
44
|
+
__index: (max(model.value, (m) => m.__index ?? -1)?.__index ?? -1) + 1,
|
|
41
45
|
} as Partial<F & { __index: number }>,
|
|
42
46
|
];
|
|
43
47
|
activeKey.value = idx;
|
|
@@ -47,26 +51,34 @@
|
|
|
47
51
|
{ content: '复制', code: 'copy' },
|
|
48
52
|
{ content: '删除', code: 'delete' },
|
|
49
53
|
];
|
|
54
|
+
const getPopupContainer = () => rootRef.value?.$el ?? document.body
|
|
50
55
|
// 实际是否强制渲染
|
|
51
56
|
const fr = computed(() => {
|
|
52
57
|
return props.forceRender || model.value.length <= 5
|
|
53
58
|
})
|
|
59
|
+
const handleBlockFocus = (idx: number) => {
|
|
60
|
+
const target_index = model.value.find((f, index) => index === idx)?.__index
|
|
61
|
+
if (valued(target_index)) {
|
|
62
|
+
error_indexes.value = error_indexes.value.filter(f => f !== target_index)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
54
65
|
const handleTabChange = () => {
|
|
55
66
|
nextTick().then(() => {
|
|
67
|
+
handleBlockFocus(activeKey.value)
|
|
56
68
|
blockInstance.value[activeKey.value]?.$form?.validate()
|
|
57
69
|
})
|
|
58
70
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
71
|
+
watch(() => model.value, () => {
|
|
72
|
+
if (!props.keepSerial) {
|
|
73
|
+
const unSortItems = model.value.filter(f => !valued(f.__index))
|
|
74
|
+
if (unSortItems.length > 0) {
|
|
75
|
+
unSortItems.forEach((item) => {
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
item.__index = (max(model.value, m => m.__index ?? -1)?.__index ?? -1) + 1
|
|
78
|
+
})
|
|
68
79
|
}
|
|
69
|
-
}
|
|
80
|
+
}
|
|
81
|
+
}, { immediate: true })
|
|
70
82
|
const handleMenu = ({ key }: MenuInfo, item: Partial<F & { __index: number }>, idx: number) => {
|
|
71
83
|
if (props.menuHandler && isFunction(props.menuHandler)) {
|
|
72
84
|
props.menuHandler({ code: toString(key), data: item, index: idx });
|
|
@@ -88,9 +100,9 @@
|
|
|
88
100
|
}
|
|
89
101
|
model.value = [
|
|
90
102
|
...model.value,
|
|
91
|
-
|
|
103
|
+
clone({
|
|
92
104
|
...omit(item, ['id', '__index']),
|
|
93
|
-
__index: (
|
|
105
|
+
__index: (max(model.value, (m) => m.__index ?? -1)?.__index ?? -1) + 1,
|
|
94
106
|
}),
|
|
95
107
|
] as Partial<F & { __index: number }>[];
|
|
96
108
|
break;
|
|
@@ -105,26 +117,74 @@
|
|
|
105
117
|
activeKey.value = model.value.length - 1;
|
|
106
118
|
}
|
|
107
119
|
});
|
|
120
|
+
|
|
121
|
+
const debounceHandleBlockFocus = debounce(handleBlockFocus, 50)
|
|
122
|
+
watchEffect(() => {
|
|
123
|
+
const errorKeys = model.value.map((m, idx) => error_indexes.value.includes(m.__index!) ? idx : undefined).filter(valued)
|
|
124
|
+
const rootDom = tabsRef.value?.$el
|
|
125
|
+
if (rootDom) {
|
|
126
|
+
const tabPanel = rootDom.querySelectorAll(':scope >.ant-tabs-nav>.ant-tabs-nav-wrap>.ant-tabs-nav-list>.ant-tabs-tab>.ant-tabs-tab-btn')
|
|
127
|
+
tabPanel.forEach((tab, idx) => {
|
|
128
|
+
if (errorKeys.includes(idx)) {
|
|
129
|
+
tab.classList.add('p-error-group-tab')
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
tab.classList.remove('p-error-group-tab')
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
})
|
|
108
137
|
defineExpose({
|
|
109
138
|
activeKey: computed(() => activeKey.value),
|
|
110
139
|
setActiveKey,
|
|
111
140
|
validateAll: () => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
))
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
141
|
+
const promiseList = fr.value
|
|
142
|
+
? blockInstance.value.map(block => block.$form?.validate())
|
|
143
|
+
: model.value.map(m => useForm(m, props.getFormSetting(m).rules)?.validate() ?? Promise.resolve())
|
|
144
|
+
return Promise.allSettled(promiseList).then((results) => {
|
|
145
|
+
// 更新 error_indexes
|
|
146
|
+
error_indexes.value = results
|
|
147
|
+
.map((res, idx) => (res.status === 'rejected' && typeof model.value[idx]?.__index === 'number' ? model.value[idx].__index as number : undefined))
|
|
148
|
+
.filter((v): v is number => typeof v === 'number')
|
|
149
|
+
if (!props.lazyErrorMark && error_indexes.value.length) {
|
|
150
|
+
// 跳到第一个出错的tab
|
|
151
|
+
const firstErrorIndex = error_indexes.value[0]
|
|
152
|
+
const firstErrorTab = model.value.findIndex(f => f.__index === firstErrorIndex)
|
|
153
|
+
if (firstErrorTab !== -1) {
|
|
154
|
+
activeKey.value = firstErrorTab
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// 判断是否有错误
|
|
158
|
+
if (error_indexes.value.length) {
|
|
159
|
+
return Promise.reject({ error_indexes: error_indexes.value, results })
|
|
160
|
+
}
|
|
161
|
+
return Promise.resolve(results)
|
|
162
|
+
})
|
|
163
|
+
},
|
|
164
|
+
validate: async (__index: number) => {
|
|
165
|
+
const index = model.value.findIndex(f => f.__index === __index)
|
|
166
|
+
try {
|
|
167
|
+
await (fr.value
|
|
119
168
|
? (blockInstance.value[index]?.$form?.validate() ?? Promise.resolve())
|
|
120
|
-
: (useForm(model.value[index], props.getFormSetting(model.value[index]).rules)?.validate() ?? Promise.resolve())
|
|
121
|
-
|
|
169
|
+
: (useForm(model.value[index], props.getFormSetting(model.value[index]).rules)?.validate() ?? Promise.resolve()))
|
|
170
|
+
// 校验通过,移除error_indexes中的__index
|
|
171
|
+
error_indexes.value = error_indexes.value.filter(f => f !== __index)
|
|
172
|
+
return Promise.resolve()
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
// 校验失败,加入error_indexes
|
|
176
|
+
if (!error_indexes.value.includes(__index)) {
|
|
177
|
+
error_indexes.value = [...error_indexes.value, __index]
|
|
178
|
+
}
|
|
179
|
+
return Promise.reject(e)
|
|
180
|
+
}
|
|
181
|
+
},
|
|
122
182
|
});
|
|
123
183
|
</script>
|
|
124
184
|
<template>
|
|
125
|
-
<a-card :title="title" size="small">
|
|
185
|
+
<a-card ref="rootRef" :title="title" size="small">
|
|
126
186
|
<a-spin v-if="loading" class="w-full" />
|
|
127
|
-
<a-tabs v-else type="editable-card" v-model:activeKey="activeKey" hide-add @change="handleTabChange">
|
|
187
|
+
<a-tabs v-else ref="tabsRef" type="editable-card" v-model:activeKey="activeKey" hide-add @change="handleTabChange">
|
|
128
188
|
<template #rightExtra>
|
|
129
189
|
<slot name="rightExtra">
|
|
130
190
|
<a-button
|
|
@@ -143,7 +203,7 @@
|
|
|
143
203
|
:force-render="fr"
|
|
144
204
|
>
|
|
145
205
|
<template #closeIcon>
|
|
146
|
-
<a-dropdown v-if="editAble && itemMenus?.length">
|
|
206
|
+
<a-dropdown v-if="editAble && itemMenus?.length" :get-popup-container="getPopupContainer">
|
|
147
207
|
<MoreOutlined />
|
|
148
208
|
<template #overlay>
|
|
149
209
|
<a-menu @click="(e) => debounceHandleMenu(e, item, idx)">
|
|
@@ -173,6 +233,8 @@
|
|
|
173
233
|
:key="idx"
|
|
174
234
|
:source="item"
|
|
175
235
|
:get-form-setting="getFormSetting"
|
|
236
|
+
@focus.capture="debounceHandleBlockFocus(idx)"
|
|
237
|
+
@click.capture="debounceHandleBlockFocus(idx)"
|
|
176
238
|
/>
|
|
177
239
|
</a-tab-pane>
|
|
178
240
|
</a-tabs>
|
|
@@ -11,32 +11,41 @@
|
|
|
11
11
|
toRefs,
|
|
12
12
|
onBeforeUnmount,
|
|
13
13
|
} from 'vue';
|
|
14
|
-
import { debounce, get, isArray, isBoolean, isFunction, isObject, isString, merge, omit, toNumber } from '
|
|
14
|
+
import { debounce, get, isArray, isBoolean, isFunction, isObject, isString, merge, omit, toNumber } from 'xe-utils';
|
|
15
15
|
import { eachTree } from '@/utils/treeHelper';
|
|
16
16
|
import { message as $message } from 'ant-design-vue';
|
|
17
|
-
import RenderAntItem from '@/components/RenderAntItem';
|
|
18
17
|
import RenderTitleSlots from '@/components/RenderTitleSlots';
|
|
19
18
|
import RenderDefaultSlots from '@/components/RenderDefaultSlots';
|
|
20
19
|
import { v4 as uuid_v4 } from 'uuid';
|
|
21
|
-
import { isGoodValue
|
|
22
|
-
import
|
|
23
|
-
import { cleanCol,
|
|
20
|
+
import { isGoodValue } from '@/utils/is';
|
|
21
|
+
import PFormCol from '@/components/PFormCol.vue';
|
|
22
|
+
import { cleanCol, defaultLabelCol } from '@/utils/core';
|
|
23
|
+
import { getGridDefaults } from '@/utils/config';
|
|
24
24
|
import Icon from '@/renders/Icon';
|
|
25
25
|
import { $confirm } from '@/hooks/useMessage';
|
|
26
26
|
import {
|
|
27
27
|
Table as ATable,
|
|
28
28
|
Button as AButton,
|
|
29
29
|
Form as AForm,
|
|
30
|
-
FormItem as AFormItem,
|
|
31
30
|
Row as ARow,
|
|
32
|
-
Col as ACol,
|
|
33
31
|
Spin as ASpin,
|
|
34
|
-
Tooltip as ATooltip,
|
|
35
32
|
} from 'ant-design-vue';
|
|
36
33
|
import { TablePaginationConfig } from 'ant-design-vue/es/table/interface';
|
|
37
|
-
import {
|
|
34
|
+
import { DownOutlined } from '@ant-design/icons-vue';
|
|
38
35
|
|
|
39
36
|
const props = defineProps<PGridProps<D, F>>();
|
|
37
|
+
|
|
38
|
+
// 应用默认值
|
|
39
|
+
const gridDefaults = getGridDefaults();
|
|
40
|
+
const propsWithDefaults = computed(() => ({
|
|
41
|
+
...props,
|
|
42
|
+
rowKey: props.rowKey ?? 'id',
|
|
43
|
+
scrollMode: props.scrollMode ?? 'inner',
|
|
44
|
+
align: props.align ?? gridDefaults.align ?? 'left',
|
|
45
|
+
lazyReset: props.lazyReset ?? gridDefaults.lazyReset ?? false,
|
|
46
|
+
fitHeight: props.fitHeight ?? gridDefaults.fitHeight ?? 170,
|
|
47
|
+
}));
|
|
48
|
+
|
|
40
49
|
const {
|
|
41
50
|
formConfig,
|
|
42
51
|
pageConfig,
|
|
@@ -63,7 +72,6 @@
|
|
|
63
72
|
loading.toolbar = value;
|
|
64
73
|
}
|
|
65
74
|
};
|
|
66
|
-
const submitOnReset = true;
|
|
67
75
|
const boxEl = ref<HTMLDivElement>();
|
|
68
76
|
const pFormWrapper = ref<HTMLDivElement>();
|
|
69
77
|
const renderHeight = ref(500);
|
|
@@ -118,9 +126,7 @@
|
|
|
118
126
|
const tableEl = ref();
|
|
119
127
|
const renderFormKey = ref(uuid_v4());
|
|
120
128
|
const renderTableKey = ref(uuid_v4());
|
|
121
|
-
|
|
122
|
-
renderFormKey.value = uuid_v4();
|
|
123
|
-
};
|
|
129
|
+
|
|
124
130
|
const codeLoadings = reactive<Record<string, boolean>>(
|
|
125
131
|
[
|
|
126
132
|
...(props.toolbarConfig?.buttons?.map((m) => m.code) ?? []).filter((f) => f),
|
|
@@ -139,7 +145,6 @@
|
|
|
139
145
|
const refreshTable = () => {
|
|
140
146
|
renderTableKey.value = uuid_v4();
|
|
141
147
|
};
|
|
142
|
-
const debounceRefreshForm = debounce(refreshForm, 100);
|
|
143
148
|
const debounceRefreshTable = debounce(refreshTable, 100);
|
|
144
149
|
const slotDefaultColumns = computed(() => {
|
|
145
150
|
const cols: ColumnProps<D>[] = [];
|
|
@@ -225,11 +230,18 @@
|
|
|
225
230
|
obj[item.field] = undefined;
|
|
226
231
|
}
|
|
227
232
|
}
|
|
233
|
+
else if (item.field && item.slots) {
|
|
234
|
+
if (isGoodValue(item.slots.defaultValue)) {
|
|
235
|
+
obj[item.field] = item.slots.defaultValue
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
obj[item.field] = undefined
|
|
239
|
+
}
|
|
240
|
+
}
|
|
228
241
|
});
|
|
229
242
|
queryFormData.value = obj;
|
|
230
243
|
}
|
|
231
244
|
emit('resetQuery');
|
|
232
|
-
refreshForm();
|
|
233
245
|
}
|
|
234
246
|
|
|
235
247
|
pagination.page = 1;
|
|
@@ -266,6 +278,8 @@
|
|
|
266
278
|
};
|
|
267
279
|
const enoughSpacing = ref(true);
|
|
268
280
|
const reload = () => {
|
|
281
|
+
selectedCaches.value = []
|
|
282
|
+
selectedRowKeys.value = []
|
|
269
283
|
return resetQueryFormData();
|
|
270
284
|
};
|
|
271
285
|
const resetPage = () => {
|
|
@@ -387,13 +401,6 @@
|
|
|
387
401
|
resetPage();
|
|
388
402
|
};
|
|
389
403
|
|
|
390
|
-
watch(
|
|
391
|
-
() => formConfig.value,
|
|
392
|
-
() => {
|
|
393
|
-
debounceRefreshForm();
|
|
394
|
-
},
|
|
395
|
-
{ deep: true },
|
|
396
|
-
);
|
|
397
404
|
watch(
|
|
398
405
|
() => [columns.value, proxyConfig.value, toolbarConfig.value],
|
|
399
406
|
() => {
|
|
@@ -413,7 +420,7 @@
|
|
|
413
420
|
const showCountHeight = selectConfig.value?.showCount ? 22 : 0
|
|
414
421
|
renderHeight.value =
|
|
415
422
|
props.renderY ??
|
|
416
|
-
toNumber(ph.replace('px', '')) -
|
|
423
|
+
toNumber(ph.replace('px', '')) -propsWithDefaults.value.fitHeight -(props.toolbarConfig ? 30 : 0) -formHeight- showCountHeight;
|
|
417
424
|
enoughSpacing.value = toNumber(ph.replace('px', '')) > 600;
|
|
418
425
|
};
|
|
419
426
|
defineExpose({
|
|
@@ -428,6 +435,7 @@
|
|
|
428
435
|
setBtnLoading,
|
|
429
436
|
selectedRecords,
|
|
430
437
|
$form: computed(() => formEl.value),
|
|
438
|
+
getFormData: () => queryFormData.value,
|
|
431
439
|
setLoadings,
|
|
432
440
|
resizeTable,
|
|
433
441
|
});
|
|
@@ -457,7 +465,7 @@
|
|
|
457
465
|
const passFields = ['align']
|
|
458
466
|
const passDefaultColumnProps = (columns: ColumnProps<D>[]) => columns.map(c => ({
|
|
459
467
|
...passFields.reduce((prev, cur) => ({
|
|
460
|
-
[cur]:
|
|
468
|
+
[cur]: propsWithDefaults.value[cur],
|
|
461
469
|
}), {} as ColumnProps<D>),
|
|
462
470
|
...c,
|
|
463
471
|
}))
|
|
@@ -484,64 +492,13 @@
|
|
|
484
492
|
@submit="handleFormSubmit"
|
|
485
493
|
>
|
|
486
494
|
<a-row :gutter="[6, 12]">
|
|
487
|
-
<
|
|
495
|
+
<p-form-col
|
|
488
496
|
v-for="(item, idx) in formConfig!.items"
|
|
489
|
-
:key="
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
:class="`p-content-align-${item.align ?? 'left'} ${item.forceRequired ? 'p-required' : ''}`"
|
|
495
|
-
:label="item.title"
|
|
496
|
-
:name="item.field"
|
|
497
|
-
v-bind="
|
|
498
|
-
omit(item, [
|
|
499
|
-
'field',
|
|
500
|
-
'title',
|
|
501
|
-
'span',
|
|
502
|
-
'col',
|
|
503
|
-
'itemRender',
|
|
504
|
-
'forceRequired',
|
|
505
|
-
'tooltip',
|
|
506
|
-
])
|
|
507
|
-
"
|
|
508
|
-
>
|
|
509
|
-
<render-item-slots
|
|
510
|
-
v-if="item.slots?.default"
|
|
511
|
-
:key="'_sl_' + (item.field ?? '_') + '_' + idx"
|
|
512
|
-
:form-data="queryFormData"
|
|
513
|
-
:item="item"
|
|
514
|
-
:pass-trigger="() => {}"
|
|
515
|
-
:pass-delay-trigger="() => {}"
|
|
516
|
-
/>
|
|
517
|
-
<render-ant-item
|
|
518
|
-
v-else-if="item.itemRender?.name"
|
|
519
|
-
:key="'_re_' + (item.field ?? '_') + '_' + idx"
|
|
520
|
-
:default-handler="{
|
|
521
|
-
reset: () => {
|
|
522
|
-
resetQueryFormData(!submitOnReset);
|
|
523
|
-
},
|
|
524
|
-
}"
|
|
525
|
-
:item-render="item.itemRender"
|
|
526
|
-
:render-form-params="{ data: queryFormData, field: item.field }"
|
|
527
|
-
/>
|
|
528
|
-
<span v-else></span>
|
|
529
|
-
<template #tooltip v-if="item.tooltipConfig">
|
|
530
|
-
<a-tooltip
|
|
531
|
-
v-if="isFunction(item.tooltipConfig.title)"
|
|
532
|
-
v-bind="omit(item.tooltipConfig, ['title'])"
|
|
533
|
-
>
|
|
534
|
-
<InfoCircleOutlined class="cursor-pointer py-4x px-2x" />
|
|
535
|
-
<template #title>
|
|
536
|
-
<div v-html="item.tooltipConfig.title()"></div>
|
|
537
|
-
</template>
|
|
538
|
-
</a-tooltip>
|
|
539
|
-
<a-tooltip v-else v-bind="item.tooltipConfig">
|
|
540
|
-
<InfoCircleOutlined class="cursor-pointer py-4x px-2x" />
|
|
541
|
-
</a-tooltip>
|
|
542
|
-
</template>
|
|
543
|
-
</a-form-item>
|
|
544
|
-
</a-col>
|
|
497
|
+
:key="`_col_${idx}`"
|
|
498
|
+
:form-data="queryFormData"
|
|
499
|
+
:item="item as PFormItemProps<Partial<F>>"
|
|
500
|
+
@reset="resetQueryFormData(propsWithDefaults.lazyReset)"
|
|
501
|
+
/>
|
|
545
502
|
</a-row>
|
|
546
503
|
</a-form>
|
|
547
504
|
</a-spin>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { ColumnProps } from '#/antProxy';
|
|
5
5
|
import { cleanCol } from '@/utils/core';
|
|
6
6
|
import RenderDefaultSlots from '@/components/RenderDefaultSlots';
|
|
7
|
-
import { merge } from '
|
|
7
|
+
import { merge } from 'xe-utils';
|
|
8
8
|
|
|
9
9
|
const props = defineProps({
|
|
10
10
|
modelValue: {
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
TimePicker,
|
|
22
22
|
TreeSelect,
|
|
23
23
|
} from 'ant-design-vue';
|
|
24
|
-
import { set, isFunction, merge, omit } from '
|
|
24
|
+
import { set, isFunction, merge, omit } from 'xe-utils';
|
|
25
25
|
import { ButtonProps } from 'ant-design-vue/lib/button';
|
|
26
26
|
import { isBadValue, isGoodValue, noValue, valued } from '@/utils/is';
|
|
27
27
|
import TableInput from '@/renders/TableInput.vue';
|
|
@@ -99,7 +99,37 @@
|
|
|
99
99
|
.p-form-wrapper {
|
|
100
100
|
z-index: 4;
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
.p-error-hang-out {
|
|
103
|
+
.ant-input-affix-wrapper-status-error:not(
|
|
104
|
+
.ant-input-affix-wrapper-disabled
|
|
105
|
+
):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper {
|
|
106
|
+
border-color: #d9d9d9 !important;
|
|
107
|
+
|
|
108
|
+
&:focus {
|
|
109
|
+
border-color: #4096ff !important;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
.ant-form-item-explain-error {
|
|
113
|
+
opacity: 0 !important;
|
|
114
|
+
transform: translateY(-10px) !important;
|
|
115
|
+
max-height: 0 !important;
|
|
116
|
+
overflow: hidden !important;
|
|
117
|
+
transition: none !important;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
.ant-form-item-explain-error {
|
|
121
|
+
opacity: 0;
|
|
122
|
+
transform: translateY(-10px);
|
|
123
|
+
max-height: 0;
|
|
124
|
+
overflow: hidden;
|
|
125
|
+
transition: opacity 0.3s ease-out 0.3s, transform 0.3s ease-out 0.3s,
|
|
126
|
+
max-height 0.3s ease-out 0.3s;
|
|
127
|
+
}
|
|
128
|
+
.ant-form-item-has-error .ant-form-item-explain-error {
|
|
129
|
+
opacity: 1;
|
|
130
|
+
transform: translateY(0);
|
|
131
|
+
max-height: 100px;
|
|
132
|
+
}
|
|
103
133
|
.p-toolbar-wrapper {
|
|
104
134
|
box-shadow: 0 8px #fff;
|
|
105
135
|
border-radius: 0.5em 0.5em 0 0;
|
|
@@ -204,7 +234,42 @@
|
|
|
204
234
|
}
|
|
205
235
|
}
|
|
206
236
|
}
|
|
237
|
+
.p-error-group-tab{
|
|
238
|
+
position:relative;
|
|
239
|
+
overflow: visible;
|
|
240
|
+
color:#f5222d!important;
|
|
241
|
+
&:after{
|
|
242
|
+
content:'🏷️';
|
|
243
|
+
position:absolute;
|
|
244
|
+
top:-1em;
|
|
245
|
+
right:0;
|
|
246
|
+
width:1em;
|
|
247
|
+
height:1em;
|
|
248
|
+
font-size:0.8em;
|
|
249
|
+
animation: heartbeat 2s infinite;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
.p-error-hang-out {
|
|
253
|
+
.ant-input-affix-wrapper-status-error:not(
|
|
254
|
+
.ant-input-affix-wrapper-disabled
|
|
255
|
+
):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper {
|
|
256
|
+
border-color: #d9d9d9 !important;
|
|
257
|
+
|
|
258
|
+
&:focus {
|
|
259
|
+
border-color: #4096ff !important;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
.ant-form-item-explain-error {
|
|
263
|
+
display: none;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
.no-error-border {
|
|
267
|
+
border-color: #d9d9d9 !important;
|
|
207
268
|
|
|
269
|
+
&:focus {
|
|
270
|
+
border-color: #4096ff !important;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
208
273
|
//endregion
|
|
209
274
|
|
|
210
275
|
@each $align in right center {
|
|
@@ -220,3 +285,17 @@
|
|
|
220
285
|
text-align: #{$align};
|
|
221
286
|
}
|
|
222
287
|
}
|
|
288
|
+
|
|
289
|
+
@keyframes heartbeat {
|
|
290
|
+
0% { transform: scale(1); }
|
|
291
|
+
6% { transform: scale(1.22); }
|
|
292
|
+
12% { transform: scale(1); }
|
|
293
|
+
18% { transform: scale(1.18); }
|
|
294
|
+
24% { transform: scale(1); }
|
|
295
|
+
48% { transform: scale(1); } // 长停顿
|
|
296
|
+
54% { transform: scale(1.22); }
|
|
297
|
+
60% { transform: scale(1); }
|
|
298
|
+
66% { transform: scale(1.18); }
|
|
299
|
+
72% { transform: scale(1); }
|
|
300
|
+
100% { transform: scale(1); } // 长停顿
|
|
301
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { PFormProps, PGridProps } from '#/antProxy';
|
|
2
|
+
import { clone } from 'xe-utils';
|
|
3
|
+
|
|
4
|
+
// 全局配置接口
|
|
5
|
+
export interface UIKitConfig {
|
|
6
|
+
form?: {
|
|
7
|
+
labelCol?: any;
|
|
8
|
+
wrapperCol?: any;
|
|
9
|
+
};
|
|
10
|
+
grid?: {
|
|
11
|
+
align?: 'left' | 'right' | 'center';
|
|
12
|
+
lazyReset?: boolean;
|
|
13
|
+
fitHeight?: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 默认配置
|
|
18
|
+
const defaultConfig: UIKitConfig = {
|
|
19
|
+
form: {
|
|
20
|
+
labelCol: { span: 6 },
|
|
21
|
+
wrapperCol: { span: 16 },
|
|
22
|
+
},
|
|
23
|
+
grid: {
|
|
24
|
+
align: 'left',
|
|
25
|
+
lazyReset: false,
|
|
26
|
+
fitHeight: 170,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// 当前配置(可被修改)
|
|
31
|
+
let currentConfig: UIKitConfig = clone(defaultConfig);
|
|
32
|
+
|
|
33
|
+
// 设置配置
|
|
34
|
+
export function setUIKitConfig(config: Partial<UIKitConfig>): void {
|
|
35
|
+
currentConfig = {
|
|
36
|
+
form: {
|
|
37
|
+
...currentConfig.form,
|
|
38
|
+
...config.form,
|
|
39
|
+
},
|
|
40
|
+
grid: {
|
|
41
|
+
...currentConfig.grid,
|
|
42
|
+
...config.grid,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 获取配置
|
|
48
|
+
export function getUIKitConfig(): UIKitConfig {
|
|
49
|
+
return currentConfig;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 获取表单默认配置
|
|
53
|
+
export function getFormDefaults(): Partial<PFormProps> {
|
|
54
|
+
return {
|
|
55
|
+
labelCol: currentConfig.form?.labelCol,
|
|
56
|
+
wrapperCol: currentConfig.form?.wrapperCol,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 获取Grid默认配置
|
|
61
|
+
export function getGridDefaults(): Partial<PGridProps> {
|
|
62
|
+
return {
|
|
63
|
+
align: currentConfig.grid?.align,
|
|
64
|
+
lazyReset: currentConfig.grid?.lazyReset,
|
|
65
|
+
fitHeight: currentConfig.grid?.fitHeight,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 重置为默认配置
|
|
70
|
+
export function resetUIKitConfig(): void {
|
|
71
|
+
currentConfig = JSON.parse(JSON.stringify(defaultConfig));
|
|
72
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ColumnProps, Responsive } from '#/antProxy';
|
|
2
2
|
import { TableColumnGroupType, TableColumnType } from 'ant-design-vue';
|
|
3
|
-
import { isArray, isNumber, omit, zipObject } from '
|
|
3
|
+
import { isArray, isNumber, omit, zipObject } from 'xe-utils';
|
|
4
4
|
import { valued } from '@/utils/is';
|
|
5
5
|
|
|
6
6
|
export const cleanCol = (col: ColumnProps): TableColumnType | TableColumnGroupType<Recordable> => {
|