@tmagic/form 1.6.0 → 1.7.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/dist/style.css +29 -3
- package/dist/tmagic-form.js +1788 -1581
- package/dist/tmagic-form.umd.cjs +1830 -1619
- package/package.json +6 -6
- package/src/Form.vue +18 -5
- package/src/containers/Container.vue +109 -134
- package/src/containers/Fieldset.vue +31 -7
- package/src/containers/FlexLayout.vue +59 -0
- package/src/containers/Tabs.vue +11 -1
- package/src/fields/Cascader.vue +25 -16
- package/src/fields/Checkbox.vue +3 -3
- package/src/fields/CheckboxGroup.vue +1 -1
- package/src/fields/ColorPicker.vue +2 -2
- package/src/fields/Date.vue +2 -2
- package/src/fields/DateTime.vue +2 -2
- package/src/fields/Daterange.vue +2 -2
- package/src/fields/Number.vue +2 -2
- package/src/fields/NumberRange.vue +6 -6
- package/src/fields/RadioGroup.vue +18 -16
- package/src/fields/Select.vue +2 -2
- package/src/fields/Switch.vue +2 -2
- package/src/fields/Text.vue +21 -9
- package/src/fields/Textarea.vue +2 -2
- package/src/fields/Time.vue +2 -2
- package/src/fields/Timerange.vue +2 -2
- package/src/index.ts +5 -2
- package/src/table/ActionsColumn.vue +97 -0
- package/src/table/SortColumn.vue +101 -0
- package/src/table/Table.vue +170 -0
- package/src/table/type.ts +18 -0
- package/src/table/useAdd.ts +111 -0
- package/src/table/useFullscreen.ts +28 -0
- package/src/table/useImport.ts +68 -0
- package/src/table/usePagination.ts +30 -0
- package/src/table/useSelection.ts +34 -0
- package/src/table/useSortable.ts +48 -0
- package/src/table/useTableColumns.ts +194 -0
- package/src/theme/container.scss +17 -0
- package/src/theme/form.scss +15 -3
- package/src/theme/text.scss +6 -0
- package/src/utils/form.ts +56 -2
- package/types/index.d.ts +103 -56
- package/src/containers/Table.vue +0 -681
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.7.0-beta.0",
|
|
3
3
|
"name": "@tmagic/form",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"@vue/test-utils": "^2.4.6"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"vue": "^3.5.
|
|
53
|
-
"typescript": "^5.9.
|
|
54
|
-
"@tmagic/
|
|
55
|
-
"@tmagic/
|
|
56
|
-
"@tmagic/utils": "1.
|
|
52
|
+
"vue": "^3.5.22",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"@tmagic/design": "1.7.0-beta.0",
|
|
55
|
+
"@tmagic/form-schema": "1.7.0-beta.0",
|
|
56
|
+
"@tmagic/utils": "1.7.0-beta.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"typescript": {
|
package/src/Form.vue
CHANGED
|
@@ -28,10 +28,11 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
|
|
30
30
|
<script setup lang="ts">
|
|
31
|
-
import { provide, reactive, ref, shallowRef, toRaw, watch, watchEffect } from 'vue';
|
|
31
|
+
import { provide, reactive, ref, shallowRef, toRaw, useTemplateRef, watch, watchEffect } from 'vue';
|
|
32
32
|
import { cloneDeep, isEqual } from 'lodash-es';
|
|
33
33
|
|
|
34
34
|
import { TMagicForm, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
|
|
35
|
+
import { setValueByKeyPath } from '@tmagic/utils';
|
|
35
36
|
|
|
36
37
|
import Container from './containers/Container.vue';
|
|
37
38
|
import { getConfig } from './utils/config';
|
|
@@ -83,7 +84,7 @@ const props = withDefaults(
|
|
|
83
84
|
|
|
84
85
|
const emit = defineEmits(['change', 'error', 'field-input', 'field-change', 'update:stepActive']);
|
|
85
86
|
|
|
86
|
-
const
|
|
87
|
+
const tMagicFormRef = useTemplateRef('tMagicForm');
|
|
87
88
|
const initialized = ref(false);
|
|
88
89
|
const values = ref<FormValue>({});
|
|
89
90
|
const lastValuesProcessed = ref<FormValue>({});
|
|
@@ -173,7 +174,18 @@ watch(
|
|
|
173
174
|
|
|
174
175
|
const changeHandler = (v: FormValue, eventData: ContainerChangeEventData) => {
|
|
175
176
|
if (eventData.changeRecords?.length) {
|
|
176
|
-
|
|
177
|
+
for (const record of eventData.changeRecords) {
|
|
178
|
+
if (record.propPath) {
|
|
179
|
+
const index = changeRecords.value.findIndex((item) => item.propPath === record.propPath);
|
|
180
|
+
if (index > -1) {
|
|
181
|
+
changeRecords.value[index] = record;
|
|
182
|
+
} else {
|
|
183
|
+
changeRecords.value.push(record);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
setValueByKeyPath(record.propPath, record.value, values.value);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
177
189
|
}
|
|
178
190
|
emit('change', values.value, eventData);
|
|
179
191
|
};
|
|
@@ -194,13 +206,14 @@ defineExpose({
|
|
|
194
206
|
changeHandler,
|
|
195
207
|
|
|
196
208
|
resetForm: () => {
|
|
197
|
-
|
|
209
|
+
tMagicFormRef.value?.resetFields();
|
|
198
210
|
changeRecords.value = [];
|
|
199
211
|
},
|
|
200
212
|
|
|
201
213
|
submitForm: async (native?: boolean): Promise<any> => {
|
|
202
214
|
try {
|
|
203
|
-
await
|
|
215
|
+
await tMagicFormRef.value?.validate();
|
|
216
|
+
changeRecords.value = [];
|
|
204
217
|
return native ? values.value : cloneDeep(toRaw(values.value));
|
|
205
218
|
} catch (invalidFields: any) {
|
|
206
219
|
emit('error', invalidFields);
|
|
@@ -1,84 +1,55 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
v-if="config"
|
|
4
3
|
:data-tmagic-id="config.id"
|
|
5
4
|
:data-tmagic-form-item-prop="itemProp"
|
|
6
|
-
:
|
|
7
|
-
:
|
|
5
|
+
:class="`m-form-container m-container-${type || ''} ${config.className || ''}${config.tip ? ' has-tip' : ''}`"
|
|
6
|
+
:style="config.style"
|
|
8
7
|
>
|
|
9
|
-
<m-fields-hidden
|
|
10
|
-
v-if="type === 'hidden'"
|
|
11
|
-
:model="model"
|
|
12
|
-
:config="config"
|
|
13
|
-
:name="config.name"
|
|
14
|
-
:disabled="disabled"
|
|
15
|
-
:prop="itemProp"
|
|
16
|
-
></m-fields-hidden>
|
|
8
|
+
<m-fields-hidden v-if="type === 'hidden'" v-bind="fieldsProps" :model="model"></m-fields-hidden>
|
|
17
9
|
|
|
18
10
|
<component
|
|
19
11
|
v-else-if="items && !text && type && display"
|
|
20
|
-
|
|
21
|
-
:size="size"
|
|
12
|
+
v-bind="fieldsProps"
|
|
22
13
|
:is="tagName"
|
|
23
14
|
:model="model"
|
|
24
15
|
:last-values="lastValues"
|
|
25
16
|
:is-compare="isCompare"
|
|
26
|
-
:config="config"
|
|
27
|
-
:disabled="disabled"
|
|
28
|
-
:name="name"
|
|
29
|
-
:prop="itemProp"
|
|
30
17
|
:step-active="stepActive"
|
|
31
18
|
:expand-more="expand"
|
|
32
19
|
:label-width="itemLabelWidth"
|
|
20
|
+
:style="config.fieldStyle"
|
|
33
21
|
@change="onChangeHandler"
|
|
34
22
|
@addDiffCount="onAddDiffCount"
|
|
35
23
|
></component>
|
|
36
24
|
|
|
37
25
|
<template v-else-if="type && display && !showDiff">
|
|
38
|
-
<TMagicFormItem
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
:label-position="config.labelPosition"
|
|
44
|
-
:rules="rule"
|
|
45
|
-
>
|
|
46
|
-
<template #label><span v-html="type === 'checkbox' ? '' : text" :title="config.labelTitle"></span></template>
|
|
47
|
-
<TMagicTooltip v-if="tooltip">
|
|
26
|
+
<TMagicFormItem v-bind="formItemProps" :class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text }">
|
|
27
|
+
<template #label
|
|
28
|
+
><span v-html="type === 'checkbox' && !config.useLabel ? '' : text" :title="config.labelTitle"></span
|
|
29
|
+
></template>
|
|
30
|
+
<TMagicTooltip v-if="tooltip.text" :placement="tooltip.placement">
|
|
48
31
|
<component
|
|
49
|
-
|
|
50
|
-
:size="size"
|
|
32
|
+
v-bind="fieldsProps"
|
|
51
33
|
:is="tagName"
|
|
52
34
|
:model="model"
|
|
53
35
|
:last-values="lastValues"
|
|
54
|
-
:config="config"
|
|
55
|
-
:name="name"
|
|
56
|
-
:disabled="disabled"
|
|
57
|
-
:prop="itemProp"
|
|
58
36
|
@change="onChangeHandler"
|
|
59
37
|
@addDiffCount="onAddDiffCount"
|
|
60
38
|
></component>
|
|
61
39
|
<template #content>
|
|
62
|
-
<div v-html="tooltip"></div>
|
|
40
|
+
<div v-html="tooltip.text"></div>
|
|
63
41
|
</template>
|
|
64
42
|
</TMagicTooltip>
|
|
65
43
|
|
|
66
44
|
<component
|
|
67
45
|
v-else
|
|
68
|
-
|
|
69
|
-
:size="size"
|
|
46
|
+
v-bind="fieldsProps"
|
|
70
47
|
:is="tagName"
|
|
71
48
|
:model="model"
|
|
72
49
|
:last-values="lastValues"
|
|
73
|
-
:config="config"
|
|
74
|
-
:name="name"
|
|
75
|
-
:disabled="disabled"
|
|
76
|
-
:prop="itemProp"
|
|
77
50
|
@change="onChangeHandler"
|
|
78
51
|
@addDiffCount="onAddDiffCount"
|
|
79
52
|
></component>
|
|
80
|
-
|
|
81
|
-
<div v-if="extra && type !== 'table'" v-html="extra" class="m-form-tip"></div>
|
|
82
53
|
</TMagicFormItem>
|
|
83
54
|
|
|
84
55
|
<TMagicTooltip v-if="config.tip" placement="left">
|
|
@@ -93,46 +64,18 @@
|
|
|
93
64
|
<template v-else-if="type && display && showDiff">
|
|
94
65
|
<!-- 上次内容 -->
|
|
95
66
|
<TMagicFormItem
|
|
96
|
-
|
|
97
|
-
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text }"
|
|
98
|
-
:prop="itemProp"
|
|
99
|
-
:label-width="itemLabelWidth"
|
|
100
|
-
:label-position="config.labelPosition"
|
|
101
|
-
:rules="rule"
|
|
102
|
-
style="background: #f7dadd"
|
|
67
|
+
v-bind="formItemProps"
|
|
68
|
+
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text, 'show-diff': true }"
|
|
103
69
|
>
|
|
104
70
|
<template #label><span v-html="type === 'checkbox' ? '' : text" :title="config.labelTitle"></span></template>
|
|
105
|
-
<TMagicTooltip v-if="tooltip">
|
|
106
|
-
<component
|
|
107
|
-
:key="key(config)"
|
|
108
|
-
:size="size"
|
|
109
|
-
:is="tagName"
|
|
110
|
-
:model="lastValues"
|
|
111
|
-
:config="config"
|
|
112
|
-
:name="name"
|
|
113
|
-
:disabled="disabled"
|
|
114
|
-
:prop="itemProp"
|
|
115
|
-
@change="onChangeHandler"
|
|
116
|
-
></component>
|
|
71
|
+
<TMagicTooltip v-if="tooltip.text" :placement="tooltip.placement">
|
|
72
|
+
<component v-bind="fieldsProps" :is="tagName" :model="lastValues" @change="onChangeHandler"></component>
|
|
117
73
|
<template #content>
|
|
118
|
-
<div v-html="tooltip"></div>
|
|
74
|
+
<div v-html="tooltip.text"></div>
|
|
119
75
|
</template>
|
|
120
76
|
</TMagicTooltip>
|
|
121
77
|
|
|
122
|
-
<component
|
|
123
|
-
v-else
|
|
124
|
-
:key="key(config)"
|
|
125
|
-
:size="size"
|
|
126
|
-
:is="tagName"
|
|
127
|
-
:model="lastValues"
|
|
128
|
-
:config="config"
|
|
129
|
-
:name="name"
|
|
130
|
-
:disabled="disabled"
|
|
131
|
-
:prop="itemProp"
|
|
132
|
-
@change="onChangeHandler"
|
|
133
|
-
></component>
|
|
134
|
-
|
|
135
|
-
<div v-if="extra" v-html="extra" class="m-form-tip"></div>
|
|
78
|
+
<component v-else v-bind="fieldsProps" :is="tagName" :model="lastValues" @change="onChangeHandler"></component>
|
|
136
79
|
</TMagicFormItem>
|
|
137
80
|
|
|
138
81
|
<TMagicTooltip v-if="config.tip" placement="left">
|
|
@@ -141,48 +84,22 @@
|
|
|
141
84
|
<div v-html="config.tip"></div>
|
|
142
85
|
</template>
|
|
143
86
|
</TMagicTooltip>
|
|
87
|
+
|
|
144
88
|
<!-- 当前内容 -->
|
|
145
89
|
<TMagicFormItem
|
|
90
|
+
v-bind="formItemProps"
|
|
146
91
|
:style="config.tip ? 'flex: 1' : ''"
|
|
147
|
-
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text }"
|
|
148
|
-
:prop="itemProp"
|
|
149
|
-
:label-width="itemLabelWidth"
|
|
150
|
-
:label-position="config.labelPosition"
|
|
151
|
-
:rules="rule"
|
|
152
|
-
style="background: #def7da"
|
|
92
|
+
:class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text, 'show-diff': true }"
|
|
153
93
|
>
|
|
154
94
|
<template #label><span v-html="type === 'checkbox' ? '' : text" :title="config.labelTitle"></span></template>
|
|
155
|
-
<TMagicTooltip v-if="tooltip">
|
|
156
|
-
<component
|
|
157
|
-
:key="key(config)"
|
|
158
|
-
:size="size"
|
|
159
|
-
:is="tagName"
|
|
160
|
-
:model="model"
|
|
161
|
-
:config="config"
|
|
162
|
-
:name="name"
|
|
163
|
-
:disabled="disabled"
|
|
164
|
-
:prop="itemProp"
|
|
165
|
-
@change="onChangeHandler"
|
|
166
|
-
></component>
|
|
95
|
+
<TMagicTooltip v-if="tooltip.text" :placement="tooltip.placement">
|
|
96
|
+
<component v-bind="fieldsProps" :is="tagName" :model="model" @change="onChangeHandler"></component>
|
|
167
97
|
<template #content>
|
|
168
|
-
<div v-html="tooltip"></div>
|
|
98
|
+
<div v-html="tooltip.text"></div>
|
|
169
99
|
</template>
|
|
170
100
|
</TMagicTooltip>
|
|
171
101
|
|
|
172
|
-
<component
|
|
173
|
-
v-else
|
|
174
|
-
:key="key(config)"
|
|
175
|
-
:size="size"
|
|
176
|
-
:is="tagName"
|
|
177
|
-
:model="model"
|
|
178
|
-
:config="config"
|
|
179
|
-
:name="name"
|
|
180
|
-
:disabled="disabled"
|
|
181
|
-
:prop="itemProp"
|
|
182
|
-
@change="onChangeHandler"
|
|
183
|
-
></component>
|
|
184
|
-
|
|
185
|
-
<div v-if="extra" v-html="extra" class="m-form-tip"></div>
|
|
102
|
+
<component v-else v-bind="fieldsProps" :is="tagName" :model="model" @change="onChangeHandler"></component>
|
|
186
103
|
</TMagicFormItem>
|
|
187
104
|
|
|
188
105
|
<TMagicTooltip v-if="config.tip" placement="left">
|
|
@@ -223,14 +140,21 @@
|
|
|
223
140
|
</template>
|
|
224
141
|
|
|
225
142
|
<script setup lang="ts">
|
|
226
|
-
import { computed, inject, ref, toRaw, watch, watchEffect } from 'vue';
|
|
143
|
+
import { computed, inject, readonly, ref, toRaw, watch, watchEffect } from 'vue';
|
|
227
144
|
import { WarningFilled } from '@element-plus/icons-vue';
|
|
228
145
|
import { isEqual } from 'lodash-es';
|
|
229
146
|
|
|
230
147
|
import { TMagicButton, TMagicFormItem, TMagicIcon, TMagicTooltip } from '@tmagic/design';
|
|
231
|
-
import {
|
|
232
|
-
|
|
233
|
-
import type {
|
|
148
|
+
import { getValueByKeyPath } from '@tmagic/utils';
|
|
149
|
+
|
|
150
|
+
import type {
|
|
151
|
+
ChildConfig,
|
|
152
|
+
ContainerChangeEventData,
|
|
153
|
+
ContainerCommonConfig,
|
|
154
|
+
FormState,
|
|
155
|
+
FormValue,
|
|
156
|
+
ToolTipConfigType,
|
|
157
|
+
} from '../schema';
|
|
234
158
|
import { display as displayFunction, filterFunction, getRules } from '../utils/form';
|
|
235
159
|
|
|
236
160
|
defineOptions({
|
|
@@ -311,9 +235,20 @@ const disabled = computed(() => props.disabled || filterFunction(mForm, props.co
|
|
|
311
235
|
|
|
312
236
|
const text = computed(() => filterFunction(mForm, props.config.text, props));
|
|
313
237
|
|
|
314
|
-
const tooltip = computed(() =>
|
|
238
|
+
const tooltip = computed(() => {
|
|
239
|
+
const config = filterFunction<ToolTipConfigType>(mForm, props.config.tooltip, props);
|
|
240
|
+
if (typeof config === 'string') {
|
|
241
|
+
return {
|
|
242
|
+
text: config,
|
|
243
|
+
placement: 'top',
|
|
244
|
+
};
|
|
245
|
+
}
|
|
315
246
|
|
|
316
|
-
|
|
247
|
+
return {
|
|
248
|
+
text: config?.text,
|
|
249
|
+
placement: config?.placement || 'top',
|
|
250
|
+
};
|
|
251
|
+
});
|
|
317
252
|
|
|
318
253
|
const rule = computed(() => getRules(mForm, props.config.rules, props));
|
|
319
254
|
|
|
@@ -334,6 +269,24 @@ const display = computed((): boolean => {
|
|
|
334
269
|
return value;
|
|
335
270
|
});
|
|
336
271
|
|
|
272
|
+
const fieldsProps = computed(() => ({
|
|
273
|
+
size: props.size,
|
|
274
|
+
config: props.config,
|
|
275
|
+
name: name.value,
|
|
276
|
+
disabled: disabled.value,
|
|
277
|
+
prop: itemProp.value,
|
|
278
|
+
key: props.config[mForm?.keyProps],
|
|
279
|
+
style: props.config.fieldStyle,
|
|
280
|
+
}));
|
|
281
|
+
|
|
282
|
+
const formItemProps = computed(() => ({
|
|
283
|
+
prop: itemProp.value,
|
|
284
|
+
labelWidth: itemLabelWidth.value,
|
|
285
|
+
labelPosition: props.config.labelPosition,
|
|
286
|
+
rules: rule.value,
|
|
287
|
+
extra: filterFunction(mForm, props.config.extra, props),
|
|
288
|
+
}));
|
|
289
|
+
|
|
337
290
|
const itemLabelWidth = computed(() => props.config.labelWidth ?? props.labelWidth);
|
|
338
291
|
|
|
339
292
|
watchEffect(() => {
|
|
@@ -367,6 +320,7 @@ const filterHandler = (filter: any, value: FormValue | number | string) => {
|
|
|
367
320
|
formValue: mForm?.values,
|
|
368
321
|
prop: itemProp.value,
|
|
369
322
|
config: props.config,
|
|
323
|
+
getFormValue: (prop: string) => getValueByKeyPath(prop, mForm?.values || props.model),
|
|
370
324
|
});
|
|
371
325
|
}
|
|
372
326
|
|
|
@@ -406,8 +360,29 @@ const isValidName = () => {
|
|
|
406
360
|
return true;
|
|
407
361
|
};
|
|
408
362
|
|
|
363
|
+
const createModelProxy = (
|
|
364
|
+
target: any,
|
|
365
|
+
setModelFn: (_key: string, _value: any) => void,
|
|
366
|
+
pathPrefix: string = '',
|
|
367
|
+
): any => {
|
|
368
|
+
return new Proxy(target, {
|
|
369
|
+
get: (obj, key: string) => {
|
|
370
|
+
const value = obj[key];
|
|
371
|
+
if (value && typeof value === 'object') {
|
|
372
|
+
const newPath = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
373
|
+
return createModelProxy(value, setModelFn, newPath);
|
|
374
|
+
}
|
|
375
|
+
return value;
|
|
376
|
+
},
|
|
377
|
+
set: (obj, key: string, value) => {
|
|
378
|
+
setModelFn(pathPrefix ? `${pathPrefix}.${key}` : key, value);
|
|
379
|
+
return true;
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
};
|
|
383
|
+
|
|
409
384
|
const onChangeHandler = async function (v: any, eventData: ContainerChangeEventData = {}) {
|
|
410
|
-
const { filter, onChange, trim
|
|
385
|
+
const { filter, onChange, trim } = props.config as any;
|
|
411
386
|
let value: FormValue | number | string | any[] = toRaw(v);
|
|
412
387
|
const changeRecords = eventData.changeRecords || [];
|
|
413
388
|
const newChangeRecords = [...changeRecords];
|
|
@@ -416,20 +391,29 @@ const onChangeHandler = async function (v: any, eventData: ContainerChangeEventD
|
|
|
416
391
|
value = filterHandler(filter, v);
|
|
417
392
|
|
|
418
393
|
if (typeof onChange === 'function') {
|
|
394
|
+
const setModel = (key: string, value: any) => {
|
|
395
|
+
if (props.config.name) {
|
|
396
|
+
newChangeRecords.push({ propPath: itemProp.value.replace(`${props.config.name}`, key), value });
|
|
397
|
+
} else {
|
|
398
|
+
newChangeRecords.push({ propPath: itemProp.value, value });
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const setFormValue = (key: string, value: any) => {
|
|
403
|
+
newChangeRecords.push({ propPath: key, value });
|
|
404
|
+
};
|
|
405
|
+
|
|
419
406
|
value =
|
|
420
407
|
(await onChange(mForm, value, {
|
|
421
|
-
model: props.model,
|
|
422
|
-
values: mForm
|
|
423
|
-
formValue: mForm?.values,
|
|
408
|
+
model: createModelProxy(props.model, setModel),
|
|
409
|
+
values: mForm ? readonly(mForm.initValues) : null,
|
|
410
|
+
formValue: createModelProxy(mForm?.values || {}, setFormValue),
|
|
424
411
|
prop: itemProp.value,
|
|
425
412
|
config: props.config,
|
|
426
413
|
changeRecords: newChangeRecords,
|
|
427
|
-
setModel
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
newChangeRecords.push({ propPath: itemProp.value.replace(`${props.config.name}`, key), value });
|
|
431
|
-
}
|
|
432
|
-
},
|
|
414
|
+
setModel,
|
|
415
|
+
setFormValue,
|
|
416
|
+
getFormValue: (prop: string) => getValueByKeyPath(prop, mForm?.values || props.model),
|
|
433
417
|
})) ?? value;
|
|
434
418
|
}
|
|
435
419
|
value = trimHandler(trim, value) ?? value;
|
|
@@ -440,19 +424,10 @@ const onChangeHandler = async function (v: any, eventData: ContainerChangeEventD
|
|
|
440
424
|
let valueProp = itemProp.value;
|
|
441
425
|
|
|
442
426
|
if (hasModifyKey(eventData)) {
|
|
443
|
-
if (dynamicKey) {
|
|
444
|
-
props.model[eventData.modifyKey!] = value;
|
|
445
|
-
} else if (isValidName()) {
|
|
446
|
-
props.model[name.value][eventData.modifyKey!] = value;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
427
|
valueProp = valueProp ? `${valueProp}.${eventData.modifyKey}` : eventData.modifyKey!;
|
|
450
428
|
|
|
451
429
|
// 需要清除掉modifyKey,不然往上层抛出后还会被认为需要修改
|
|
452
430
|
delete eventData.modifyKey;
|
|
453
|
-
} else if (isValidName() && props.model !== value && (v !== value || props.model[name.value] !== value)) {
|
|
454
|
-
// field内容下包含field-link时,model===value, 这里避免循环引用
|
|
455
|
-
props.model[name.value] = value;
|
|
456
431
|
}
|
|
457
432
|
|
|
458
433
|
if (changeRecords.length === 0) {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
<fieldset v-if="name ? model[name] : model" class="m-fieldset" :style="show ? 'padding: 15px' : 'border: 0'">
|
|
3
3
|
<component v-if="name && config.checkbox" :is="!show ? 'div' : 'legend'">
|
|
4
4
|
<TMagicCheckbox
|
|
5
|
-
|
|
6
|
-
:prop="`${prop}${prop ? '.' : ''}${config.name}
|
|
7
|
-
:true-value="
|
|
8
|
-
:false-value="
|
|
5
|
+
:model-value="(name ? model[name] : model)[checkboxName]"
|
|
6
|
+
:prop="`${prop}${prop ? '.' : ''}${config.name}.${checkboxName}`"
|
|
7
|
+
:true-value="checkboxTrueValue"
|
|
8
|
+
:false-value="checkboxFalseValue"
|
|
9
9
|
@update:modelValue="valueChangeHandler"
|
|
10
10
|
><span v-html="config.legend"></span><span v-if="config.extra" v-html="config.extra" class="m-form-tip"></span
|
|
11
11
|
></TMagicCheckbox>
|
|
@@ -99,9 +99,33 @@ const mForm = inject<FormState | undefined>('mForm');
|
|
|
99
99
|
|
|
100
100
|
const name = computed(() => props.config.name || '');
|
|
101
101
|
|
|
102
|
+
const checkboxName = computed(() => {
|
|
103
|
+
if (typeof props.config.checkbox === 'object' && typeof props.config.checkbox.name === 'string') {
|
|
104
|
+
return props.config.checkbox.name;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return 'value';
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const checkboxTrueValue = computed(() => {
|
|
111
|
+
if (typeof props.config.checkbox === 'object' && typeof props.config.checkbox.trueValue !== 'undefined') {
|
|
112
|
+
return props.config.checkbox.trueValue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return 1;
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const checkboxFalseValue = computed(() => {
|
|
119
|
+
if (typeof props.config.checkbox === 'object' && typeof props.config.checkbox.falseValue !== 'undefined') {
|
|
120
|
+
return props.config.checkbox.falseValue;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return 0;
|
|
124
|
+
});
|
|
125
|
+
|
|
102
126
|
const show = computed(() => {
|
|
103
|
-
if (props.config.expand &&
|
|
104
|
-
return props.model[name.value]?.value;
|
|
127
|
+
if (props.config.expand && checkboxName.value) {
|
|
128
|
+
return (name.value ? props.model[name.value] : props.model)?.[checkboxName.value] === checkboxTrueValue.value;
|
|
105
129
|
}
|
|
106
130
|
return true;
|
|
107
131
|
});
|
|
@@ -114,7 +138,7 @@ const lWidth = computed(() => {
|
|
|
114
138
|
});
|
|
115
139
|
|
|
116
140
|
const valueChangeHandler = (value: number | boolean) => {
|
|
117
|
-
emit('change', value, { modifyKey:
|
|
141
|
+
emit('change', value, { modifyKey: checkboxName.value });
|
|
118
142
|
};
|
|
119
143
|
|
|
120
144
|
const changeHandler = (v: any, eventData: ContainerChangeEventData) => emit('change', v, eventData);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-form-flex-layout" :style="{ display: 'flex', flexWrap: 'wrap', gap }">
|
|
3
|
+
<Container
|
|
4
|
+
v-for="(item, index) in config.items"
|
|
5
|
+
:key="(item as Record<string, any>)[mForm?.keyProp || '__key'] ?? index"
|
|
6
|
+
:config="item"
|
|
7
|
+
:model="name ? model[name] : model"
|
|
8
|
+
:lastValues="name ? lastValues[name] : lastValues"
|
|
9
|
+
:is-compare="isCompare"
|
|
10
|
+
:prop="prop"
|
|
11
|
+
:size="size"
|
|
12
|
+
:disabled="disabled"
|
|
13
|
+
:label-width="config.labelWidth || labelWidth"
|
|
14
|
+
@change="changeHandler"
|
|
15
|
+
@addDiffCount="onAddDiffCount()"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
import { computed, inject } from 'vue';
|
|
22
|
+
|
|
23
|
+
import type { FlexLayoutConfig } from '@tmagic/form-schema';
|
|
24
|
+
|
|
25
|
+
import type { ContainerChangeEventData, FormState } from '../schema';
|
|
26
|
+
|
|
27
|
+
import Container from './Container.vue';
|
|
28
|
+
|
|
29
|
+
defineOptions({
|
|
30
|
+
name: 'MFormFlexLayout',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const props = defineProps<{
|
|
34
|
+
model: any;
|
|
35
|
+
lastValues?: any;
|
|
36
|
+
isCompare?: boolean;
|
|
37
|
+
config: FlexLayoutConfig;
|
|
38
|
+
name?: string;
|
|
39
|
+
labelWidth?: string;
|
|
40
|
+
prop?: string;
|
|
41
|
+
size?: string;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
}>();
|
|
44
|
+
|
|
45
|
+
const emit = defineEmits<{
|
|
46
|
+
change: [v: any, eventData: ContainerChangeEventData];
|
|
47
|
+
addDiffCount: [];
|
|
48
|
+
}>();
|
|
49
|
+
|
|
50
|
+
const mForm = inject<FormState | undefined>('mForm');
|
|
51
|
+
|
|
52
|
+
const gap = computed(() => props.config.gap || '16px');
|
|
53
|
+
|
|
54
|
+
const changeHandler = (v: any, eventData: ContainerChangeEventData) => {
|
|
55
|
+
emit('change', props.model, eventData);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const onAddDiffCount = () => emit('addDiffCount');
|
|
59
|
+
</script>
|
package/src/containers/Tabs.vue
CHANGED
|
@@ -167,7 +167,17 @@ watchEffect(() => {
|
|
|
167
167
|
|
|
168
168
|
const tabItems = (tab: TabPaneConfig) => (props.config.dynamic ? props.config.items : tab.items);
|
|
169
169
|
|
|
170
|
-
const tabClickHandler = (tab: any) =>
|
|
170
|
+
const tabClickHandler = (tab: any) => {
|
|
171
|
+
if (typeof tab === 'object') {
|
|
172
|
+
tabClick(mForm, tab, props);
|
|
173
|
+
} else {
|
|
174
|
+
let item = tabs.value.find((tab: any) => tab.status === tab);
|
|
175
|
+
if (!item) {
|
|
176
|
+
item = tabs.value[tab];
|
|
177
|
+
}
|
|
178
|
+
tabClick(mForm, item, props);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
171
181
|
|
|
172
182
|
const onTabAdd = async () => {
|
|
173
183
|
if (!props.name) throw new Error('dynamic tab 必须配置name');
|
package/src/fields/Cascader.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<TMagicCascader
|
|
3
|
-
|
|
3
|
+
:model-value="value"
|
|
4
4
|
ref="tMagicCascader"
|
|
5
5
|
style="width: 100%"
|
|
6
6
|
clearable
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
emitPath: config.emitPath ?? true,
|
|
16
16
|
checkStrictly: checkStrictly ?? false,
|
|
17
17
|
}"
|
|
18
|
+
@update:model-value="updateModelValueHandler"
|
|
18
19
|
@change="changeHandler"
|
|
19
20
|
></TMagicCascader>
|
|
20
21
|
</template>
|
|
@@ -51,22 +52,31 @@ const remoteData = ref<any>(null);
|
|
|
51
52
|
const checkStrictly = computed(() => filterFunction(mForm, props.config.checkStrictly, props));
|
|
52
53
|
const valueSeparator = computed(() => filterFunction<string>(mForm, props.config.valueSeparator, props));
|
|
53
54
|
|
|
54
|
-
const value = computed({
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return props.model[props.name];
|
|
60
|
-
},
|
|
61
|
-
set(value) {
|
|
62
|
-
let result = value;
|
|
63
|
-
if (valueSeparator.value) {
|
|
64
|
-
result = value.join(valueSeparator.value);
|
|
65
|
-
}
|
|
66
|
-
props.model[props.name] = result;
|
|
67
|
-
},
|
|
55
|
+
const value = computed(() => {
|
|
56
|
+
if (typeof props.model[props.name] === 'string' && valueSeparator.value) {
|
|
57
|
+
return props.model[props.name].split(valueSeparator.value);
|
|
58
|
+
}
|
|
59
|
+
return props.model[props.name];
|
|
68
60
|
});
|
|
69
61
|
|
|
62
|
+
const updateModelValueHandler = (value: string[] | number[] | any) => {
|
|
63
|
+
let result = value;
|
|
64
|
+
if (valueSeparator.value) {
|
|
65
|
+
result = value.join(valueSeparator.value);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof result === 'undefined') {
|
|
69
|
+
if (Array.isArray(props.model[props.name])) {
|
|
70
|
+
emit('change', []);
|
|
71
|
+
} else if (typeof props.model[props.name] === 'string') {
|
|
72
|
+
emit('change', '');
|
|
73
|
+
} else if (typeof props.model[props.name] === 'object') {
|
|
74
|
+
emit('change', null);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
emit('change', result);
|
|
78
|
+
};
|
|
79
|
+
|
|
70
80
|
const setRemoteOptions = async function () {
|
|
71
81
|
const { config } = props;
|
|
72
82
|
const { option } = config;
|
|
@@ -126,6 +136,5 @@ const changeHandler = () => {
|
|
|
126
136
|
if (!tMagicCascader.value) return;
|
|
127
137
|
tMagicCascader.value.setQuery('');
|
|
128
138
|
tMagicCascader.value.setPreviousQuery(null);
|
|
129
|
-
emit('change', props.model[props.name]);
|
|
130
139
|
};
|
|
131
140
|
</script>
|