@tmagic/form 1.5.0-beta.9 → 1.5.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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.5.0-beta.9",
2
+ "version": "1.5.1",
3
3
  "name": "@tmagic/form",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -32,11 +32,13 @@
32
32
  "node": ">=18"
33
33
  },
34
34
  "repository": {
35
+ "directory": "packages/form",
35
36
  "type": "git",
36
37
  "url": "https://github.com/Tencent/tmagic-editor.git"
37
38
  },
38
39
  "dependencies": {
39
40
  "@element-plus/icons-vue": "^2.3.1",
41
+ "@popperjs/core": "^2.11.8",
40
42
  "dayjs": "^1.11.11",
41
43
  "lodash-es": "^4.17.21",
42
44
  "sortablejs": "^1.15.2"
@@ -45,18 +47,18 @@
45
47
  "@types/lodash-es": "^4.17.4",
46
48
  "@types/node": "^18.19.0",
47
49
  "@types/sortablejs": "^1.15.8",
48
- "@vitejs/plugin-vue": "^5.1.3",
49
- "@vue/compiler-sfc": "^3.5.0",
50
+ "@vitejs/plugin-vue": "^5.2.1",
51
+ "@vue/compiler-sfc": "^3.5.12",
50
52
  "@vue/test-utils": "^2.4.6",
51
53
  "rimraf": "^3.0.2",
52
- "sass": "^1.78.0",
53
- "vite": "^5.4.3"
54
+ "sass": "^1.83.0",
55
+ "vite": "^6.0.3"
54
56
  },
55
57
  "peerDependencies": {
56
- "vue": "^3.5.0",
58
+ "vue": ">=3.5.0",
57
59
  "typescript": "*",
58
- "@tmagic/design": "1.5.0-beta.9",
59
- "@tmagic/utils": "1.5.0-beta.9"
60
+ "@tmagic/design": "1.5.1",
61
+ "@tmagic/utils": "1.5.1"
60
62
  },
61
63
  "peerDependenciesMeta": {
62
64
  "typescript": {
package/src/Form.vue CHANGED
@@ -7,6 +7,7 @@
7
7
  :style="`height: ${height}`"
8
8
  :inline="inline"
9
9
  :label-position="labelPosition"
10
+ @submit="submitHandler"
10
11
  >
11
12
  <template v-if="initialized && Array.isArray(config)">
12
13
  <Container
@@ -27,15 +28,15 @@
27
28
  </template>
28
29
 
29
30
  <script setup lang="ts">
30
- import { provide, reactive, ref, toRaw, watch, watchEffect } from 'vue';
31
+ import { provide, reactive, ref, shallowRef, toRaw, watch, watchEffect } from 'vue';
31
32
  import { cloneDeep, isEqual } from 'lodash-es';
32
33
 
33
- import { TMagicForm } from '@tmagic/design';
34
+ import { TMagicForm, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
34
35
 
35
36
  import Container from './containers/Container.vue';
36
37
  import { getConfig } from './utils/config';
37
38
  import { initValue } from './utils/form';
38
- import type { FormConfig, FormState, FormValue, ValidateError } from './schema';
39
+ import type { ChangeRecord, ContainerChangeEventData, FormConfig, FormState, FormValue, ValidateError } from './schema';
39
40
 
40
41
  defineOptions({
41
42
  name: 'MForm',
@@ -61,6 +62,7 @@ const props = withDefaults(
61
62
  labelPosition?: string;
62
63
  keyProp?: string;
63
64
  popperClass?: string;
65
+ preventSubmitDefault?: boolean;
64
66
  extendState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
65
67
  }>(),
66
68
  {
@@ -79,7 +81,7 @@ const props = withDefaults(
79
81
  },
80
82
  );
81
83
 
82
- const emit = defineEmits(['change', 'error', 'field-input', 'field-change']);
84
+ const emit = defineEmits(['change', 'error', 'field-input', 'field-change', 'update:stepActive']);
83
85
 
84
86
  const tMagicForm = ref<InstanceType<typeof TMagicForm>>();
85
87
  const initialized = ref(false);
@@ -104,11 +106,13 @@ const formState: FormState = reactive<FormState>({
104
106
  setField: (prop: string, field: any) => fields.set(prop, field),
105
107
  getField: (prop: string) => fields.get(prop),
106
108
  deleteField: (prop: string) => fields.delete(prop),
109
+ $messageBox: tMagicMessageBox,
110
+ $message: tMagicMessage,
107
111
  post: (options: any) => {
108
112
  if (requestFuc) {
109
113
  return requestFuc({
110
- ...options,
111
114
  method: 'POST',
115
+ ...options,
112
116
  });
113
117
  }
114
118
  },
@@ -133,9 +137,13 @@ watchEffect(async () => {
133
137
 
134
138
  provide('mForm', formState);
135
139
 
140
+ const changeRecords = shallowRef<ChangeRecord[]>([]);
141
+
136
142
  watch(
137
143
  [() => props.config, () => props.initValues],
138
144
  ([config], [preConfig]) => {
145
+ changeRecords.value = [];
146
+
139
147
  if (!isEqual(toRaw(config), toRaw(preConfig))) {
140
148
  initialized.value = false;
141
149
  }
@@ -163,8 +171,17 @@ watch(
163
171
  { immediate: true },
164
172
  );
165
173
 
166
- const changeHandler = () => {
167
- emit('change', values.value);
174
+ const changeHandler = (v: FormValue, eventData: ContainerChangeEventData) => {
175
+ if (eventData.changeRecords?.length) {
176
+ changeRecords.value.push(...eventData.changeRecords);
177
+ }
178
+ emit('change', values.value, eventData);
179
+ };
180
+
181
+ const submitHandler = (e: SubmitEvent) => {
182
+ if (props.preventSubmitDefault) {
183
+ e.preventDefault();
184
+ }
168
185
  };
169
186
 
170
187
  defineExpose({
@@ -172,10 +189,14 @@ defineExpose({
172
189
  lastValuesProcessed,
173
190
  formState,
174
191
  initialized,
192
+ changeRecords,
175
193
 
176
194
  changeHandler,
177
195
 
178
- resetForm: () => tMagicForm.value?.resetFields(),
196
+ resetForm: () => {
197
+ tMagicForm.value?.resetFields();
198
+ changeRecords.value = [];
199
+ },
179
200
 
180
201
  submitForm: async (native?: boolean): Promise<any> => {
181
202
  try {
package/src/FormBox.vue CHANGED
@@ -12,6 +12,7 @@
12
12
  :label-width="labelWidth"
13
13
  :label-position="labelPosition"
14
14
  :inline="inline"
15
+ :prevent-submit-default="preventSubmitDefault"
15
16
  @change="changeHandler"
16
17
  ></Form>
17
18
  <slot></slot>
@@ -39,7 +40,7 @@ import { computed, ref, watchEffect } from 'vue';
39
40
  import { TMagicButton, TMagicScrollbar } from '@tmagic/design';
40
41
 
41
42
  import Form from './Form.vue';
42
- import type { FormConfig } from './schema';
43
+ import type { ContainerChangeEventData, FormConfig, FormValue } from './schema';
43
44
 
44
45
  defineOptions({
45
46
  name: 'MFormBox',
@@ -58,6 +59,7 @@ const props = withDefaults(
58
59
  confirmText?: string;
59
60
  inline?: boolean;
60
61
  labelPosition?: string;
62
+ preventSubmitDefault?: boolean;
61
63
  }>(),
62
64
  {
63
65
  config: () => [],
@@ -66,7 +68,11 @@ const props = withDefaults(
66
68
  },
67
69
  );
68
70
 
69
- const emit = defineEmits(['submit', 'change', 'error']);
71
+ const emit = defineEmits<{
72
+ change: [v: any, eventData: ContainerChangeEventData];
73
+ submit: [v: any, eventData: ContainerChangeEventData];
74
+ error: [e: any];
75
+ }>();
70
76
 
71
77
  const footerHeight = 60;
72
78
 
@@ -96,14 +102,14 @@ watchEffect(() => {
96
102
  const submitHandler = async () => {
97
103
  try {
98
104
  const values = await form.value?.submitForm();
99
- emit('submit', values);
105
+ emit('submit', values, { changeRecords: form.value?.changeRecords });
100
106
  } catch (e) {
101
107
  emit('error', e);
102
108
  }
103
109
  };
104
110
 
105
- const changeHandler = (value: any) => {
106
- emit('change', value);
111
+ const changeHandler = (value: FormValue, eventData: ContainerChangeEventData) => {
112
+ emit('change', value, eventData);
107
113
  };
108
114
 
109
115
  const show = () => {};
@@ -27,6 +27,7 @@
27
27
  :label-width="labelWidth"
28
28
  :label-position="labelPosition"
29
29
  :inline="inline"
30
+ :prevent-submit-default="preventSubmitDefault"
30
31
  @change="changeHandler"
31
32
  ></Form>
32
33
  <slot></slot>
@@ -64,7 +65,7 @@ import { computed, ref } from 'vue';
64
65
  import { TMagicButton, TMagicCol, TMagicDialog, TMagicRow } from '@tmagic/design';
65
66
 
66
67
  import Form from './Form.vue';
67
- import { FormConfig, StepConfig } from './schema';
68
+ import { ContainerChangeEventData, FormConfig, FormValue, StepConfig } from './schema';
68
69
 
69
70
  defineOptions({
70
71
  name: 'MFormDialog',
@@ -85,6 +86,7 @@ const props = withDefaults(
85
86
  zIndex?: number;
86
87
  size?: 'small' | 'default' | 'large';
87
88
  confirmText?: string;
89
+ preventSubmitDefault?: boolean;
88
90
  }>(),
89
91
  {
90
92
  config: () => [],
@@ -130,7 +132,7 @@ const closeHandler = () => {
130
132
  const save = async () => {
131
133
  try {
132
134
  const values = await form.value?.submitForm();
133
- emit('submit', values);
135
+ emit('submit', values, { changeRecords: form.value?.changeRecords });
134
136
  } catch (e) {
135
137
  emit('error', e);
136
138
  }
@@ -144,8 +146,8 @@ const nextStep = () => {
144
146
  stepActive.value += 1;
145
147
  };
146
148
 
147
- const changeHandler = (value: any) => {
148
- emit('change', value);
149
+ const changeHandler = (value: FormValue, eventData: ContainerChangeEventData) => {
150
+ emit('change', value, eventData);
149
151
  };
150
152
 
151
153
  const show = () => {
@@ -27,6 +27,7 @@
27
27
  :label-width="labelWidth"
28
28
  :label-position="labelPosition"
29
29
  :inline="inline"
30
+ :prevent-submit-default="preventSubmitDefault"
30
31
  @change="changeHandler"
31
32
  ></Form>
32
33
  <slot></slot>
@@ -58,7 +59,7 @@ import { ref, watchEffect } from 'vue';
58
59
  import { TMagicButton, TMagicCol, TMagicDrawer, TMagicRow } from '@tmagic/design';
59
60
 
60
61
  import Form from './Form.vue';
61
- import type { FormConfig } from './schema';
62
+ import type { ContainerChangeEventData, FormConfig, FormValue } from './schema';
62
63
 
63
64
  defineOptions({
64
65
  name: 'MFormDialog',
@@ -79,6 +80,7 @@ withDefaults(
79
80
  confirmText?: string;
80
81
  inline?: boolean;
81
82
  labelPosition?: string;
83
+ preventSubmitDefault?: boolean;
82
84
  /** 关闭前的回调,会暂停 Drawer 的关闭; done 是个 function type 接受一个 boolean 参数, 执行 done 使用 true 参数或不提供参数将会终止关闭 */
83
85
  beforeClose?: (done: (cancel?: boolean) => void) => void;
84
86
  }>(),
@@ -108,14 +110,14 @@ watchEffect(() => {
108
110
  const submitHandler = async () => {
109
111
  try {
110
112
  const values = await form.value?.submitForm();
111
- emit('submit', values);
113
+ emit('submit', values, { changeRecords: form.value?.changeRecords });
112
114
  } catch (e) {
113
115
  emit('error', e);
114
116
  }
115
117
  };
116
118
 
117
- const changeHandler = (value: any) => {
118
- emit('change', value);
119
+ const changeHandler = (value: FormValue, eventData: ContainerChangeEventData) => {
120
+ emit('change', value, eventData);
119
121
  };
120
122
 
121
123
  const openHandler = () => {
@@ -21,7 +21,7 @@ import { computed, inject } from 'vue';
21
21
 
22
22
  import { TMagicCol } from '@tmagic/design';
23
23
 
24
- import { ChildConfig, FormState } from '../schema';
24
+ import type { ChildConfig, ContainerChangeEventData, FormState } from '../schema';
25
25
  import { display as displayFunction } from '../utils/form';
26
26
 
27
27
  import Container from './Container.vue';
@@ -43,10 +43,13 @@ const props = defineProps<{
43
43
  disabled?: boolean;
44
44
  }>();
45
45
 
46
- const emit = defineEmits(['change', 'addDiffCount']);
46
+ const emit = defineEmits<{
47
+ change: [v: any, eventData: ContainerChangeEventData];
48
+ addDiffCount: [];
49
+ }>();
47
50
 
48
51
  const mForm = inject<FormState | undefined>('mForm');
49
52
  const display = computed(() => displayFunction(mForm, props.config.display, props));
50
- const changeHandler = () => emit('change', props.model);
53
+ const changeHandler = (v: any, eventData: ContainerChangeEventData) => emit('change', v, eventData);
51
54
  const onAddDiffCount = () => emit('addDiffCount');
52
55
  </script>
@@ -37,9 +37,10 @@
37
37
  <template v-else-if="type && display && !showDiff">
38
38
  <TMagicFormItem
39
39
  :style="config.tip ? 'flex: 1' : ''"
40
- :class="{ hidden: `${itemLabelWidth}` === '0' || !text }"
40
+ :class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text }"
41
41
  :prop="itemProp"
42
42
  :label-width="itemLabelWidth"
43
+ :label-position="config.labelPosition"
43
44
  :rules="rule"
44
45
  >
45
46
  <template #label><span v-html="type === 'checkbox' ? '' : text" :title="config.labelTitle"></span></template>
@@ -93,9 +94,10 @@
93
94
  <!-- 上次内容 -->
94
95
  <TMagicFormItem
95
96
  :style="config.tip ? 'flex: 1' : ''"
96
- :class="{ hidden: `${itemLabelWidth}` === '0' || !text }"
97
+ :class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text }"
97
98
  :prop="itemProp"
98
99
  :label-width="itemLabelWidth"
100
+ :label-position="config.labelPosition"
99
101
  :rules="rule"
100
102
  style="background: #f7dadd"
101
103
  >
@@ -142,9 +144,10 @@
142
144
  <!-- 当前内容 -->
143
145
  <TMagicFormItem
144
146
  :style="config.tip ? 'flex: 1' : ''"
145
- :class="{ hidden: `${itemLabelWidth}` === '0' || !text }"
147
+ :class="{ 'tmagic-form-hidden': `${itemLabelWidth}` === '0' || !text }"
146
148
  :prop="itemProp"
147
149
  :label-width="itemLabelWidth"
150
+ :label-position="config.labelPosition"
148
151
  :rules="rule"
149
152
  style="background: #def7da"
150
153
  >
@@ -191,12 +194,12 @@
191
194
  </template>
192
195
 
193
196
  <template v-else-if="items && display">
194
- <template v-if="name || name === 0 ? model[name] : model">
197
+ <template v-if="isValidName() ? model[name] : model">
195
198
  <Container
196
199
  v-for="item in items"
197
200
  :key="key(item)"
198
- :model="name || name === 0 ? model[name] : model"
199
- :last-values="name || name === 0 ? lastValues[name] || {} : lastValues"
201
+ :model="isValidName() ? model[name] : model"
202
+ :last-values="isValidName() ? lastValues[name] || {} : lastValues"
200
203
  :is-compare="isCompare"
201
204
  :config="item"
202
205
  :size="size"
@@ -220,13 +223,20 @@
220
223
  </template>
221
224
 
222
225
  <script setup lang="ts">
223
- import { computed, inject, ref, watch, watchEffect } from 'vue';
226
+ import { computed, inject, ref, toRaw, watch, watchEffect } from 'vue';
224
227
  import { WarningFilled } from '@element-plus/icons-vue';
225
228
  import { isEqual } from 'lodash-es';
226
229
 
227
230
  import { TMagicButton, TMagicFormItem, TMagicIcon, TMagicTooltip } from '@tmagic/design';
228
231
 
229
- import { ChildConfig, ContainerCommonConfig, FormState, FormValue, TypeFunction } from '../schema';
232
+ import type {
233
+ ChildConfig,
234
+ ContainerChangeEventData,
235
+ ContainerCommonConfig,
236
+ FormState,
237
+ FormValue,
238
+ TypeFunction,
239
+ } from '../schema';
230
240
  import { display as displayFunction, filterFunction, getRules } from '../utils/form';
231
241
 
232
242
  defineOptions({
@@ -258,7 +268,10 @@ const props = withDefaults(
258
268
  },
259
269
  );
260
270
 
261
- const emit = defineEmits(['change', 'addDiffCount']);
271
+ const emit = defineEmits<{
272
+ change: [v: any, eventData: ContainerChangeEventData];
273
+ addDiffCount: [];
274
+ }>();
262
275
 
263
276
  const mForm = inject<FormState | undefined>('mForm');
264
277
 
@@ -285,7 +298,12 @@ const itemProp = computed(() => {
285
298
  } else {
286
299
  return props.prop;
287
300
  }
288
- return `${props.prop}${props.prop ? '.' : ''}${n}`;
301
+
302
+ if (typeof props.prop !== 'undefined' && props.prop !== '') {
303
+ return `${props.prop}.${n}`;
304
+ }
305
+
306
+ return `${n}`;
289
307
  });
290
308
 
291
309
  const tagName = computed(() => `m-${items.value ? 'form' : 'fields'}-${type.value}`);
@@ -360,18 +378,6 @@ const filterHandler = (filter: any, value: FormValue | number | string) => {
360
378
  return value;
361
379
  };
362
380
 
363
- const changeHandler = (onChange: any, value: FormValue | number | string) => {
364
- if (typeof onChange === 'function') {
365
- return onChange(mForm, value, {
366
- model: props.model,
367
- values: mForm?.initValues,
368
- formValue: mForm?.values,
369
- prop: itemProp.value,
370
- config: props.config,
371
- });
372
- }
373
- };
374
-
375
381
  const trimHandler = (trim: any, value: FormValue | number | string) => {
376
382
  if (typeof value === 'string' && trim) {
377
383
  return value.replace(/^\s*/, '').replace(/\s*$/, '');
@@ -381,28 +387,80 @@ const trimHandler = (trim: any, value: FormValue | number | string) => {
381
387
  // 继续抛出给更高层级的组件
382
388
  const onAddDiffCount = () => emit('addDiffCount');
383
389
 
384
- const onChangeHandler = async function (v: FormValue, key?: string) {
385
- const { filter, onChange, trim, name, dynamicKey } = props.config as any;
386
- let value: FormValue | number | string = v;
390
+ const hasModifyKey = (eventDataItem: ContainerChangeEventData) =>
391
+ typeof eventDataItem?.modifyKey !== 'undefined' && eventDataItem.modifyKey !== '';
392
+
393
+ const isValidName = () => {
394
+ const valueType = typeof name.value;
395
+ if (valueType !== 'string' && valueType !== 'symbol' && valueType !== 'number') {
396
+ return false;
397
+ }
398
+
399
+ if (name.value === '') {
400
+ return false;
401
+ }
402
+
403
+ if (typeof name.value === 'number') {
404
+ return name.value >= 0;
405
+ }
406
+
407
+ return true;
408
+ };
409
+
410
+ const onChangeHandler = async function (v: any, eventData: ContainerChangeEventData = {}) {
411
+ const { filter, onChange, trim, dynamicKey } = props.config as any;
412
+ let value: FormValue | number | string | any[] = toRaw(v);
413
+ const changeRecords = eventData.changeRecords || [];
414
+ const newChangeRecords = [...changeRecords];
387
415
 
388
416
  try {
389
417
  value = filterHandler(filter, v);
390
- value = (await changeHandler(onChange, value)) ?? value;
418
+
419
+ if (typeof onChange === 'function') {
420
+ value =
421
+ (await onChange(mForm, value, {
422
+ model: props.model,
423
+ values: mForm?.initValues,
424
+ formValue: mForm?.values,
425
+ prop: itemProp.value,
426
+ config: props.config,
427
+ changeRecords: newChangeRecords,
428
+ })) ?? value;
429
+ }
391
430
  value = trimHandler(trim, value) ?? value;
392
431
  } catch (e) {
393
432
  console.error(e);
394
433
  }
395
434
 
396
- // field内容下包含field-link时,model===value, 这里避免循环引用
397
- if ((name || name === 0) && props.model !== value && (v !== value || props.model[name] !== value)) {
435
+ let valueProp = itemProp.value;
436
+
437
+ if (hasModifyKey(eventData)) {
438
+ if (dynamicKey) {
439
+ props.model[eventData.modifyKey!] = value;
440
+ } else if (isValidName()) {
441
+ props.model[name.value][eventData.modifyKey!] = value;
442
+ }
443
+
444
+ valueProp = valueProp ? `${valueProp}.${eventData.modifyKey}` : eventData.modifyKey!;
445
+
446
+ // 需要清除掉modifyKey,不然往上层抛出后还会被认为需要修改
447
+ delete eventData.modifyKey;
448
+ } else if (isValidName() && props.model !== value && (v !== value || props.model[name.value] !== value)) {
449
+ // field内容下包含field-link时,model===value, 这里避免循环引用
398
450
  // eslint-disable-next-line vue/no-mutating-props
399
- props.model[name] = value;
451
+ props.model[name.value] = value;
400
452
  }
401
- // 动态表单类型,根据value和key参数,直接修改model
402
- if (key !== undefined && dynamicKey) {
403
- // eslint-disable-next-line vue/no-mutating-props
404
- props.model[key] = value;
453
+
454
+ if (changeRecords.length === 0) {
455
+ newChangeRecords.push({
456
+ propPath: valueProp,
457
+ value,
458
+ });
405
459
  }
406
- emit('change', props.model);
460
+
461
+ emit('change', props.model, {
462
+ ...eventData,
463
+ changeRecords: newChangeRecords,
464
+ });
407
465
  };
408
466
  </script>
@@ -1,16 +1,12 @@
1
1
  <template>
2
- <fieldset
3
- v-if="name ? model[name] : model"
4
- class="m-fieldset"
5
- :style="show ? 'padding: 15px 15px 0 5px;' : 'border: 0'"
6
- >
2
+ <fieldset v-if="name ? model[name] : model" class="m-fieldset" :style="show ? 'padding: 15px' : 'border: 0'">
7
3
  <component v-if="name && config.checkbox" :is="!show ? 'div' : 'legend'">
8
4
  <TMagicCheckbox
9
5
  v-model="model[name].value"
10
6
  :prop="`${prop}${prop ? '.' : ''}${config.name}.value`"
11
7
  :true-value="1"
12
8
  :false-value="0"
13
- @update:modelValue="change"
9
+ @update:modelValue="valueChangeHandler"
14
10
  ><span v-html="config.legend"></span><span v-if="config.extra" v-html="config.extra" class="m-form-tip"></span
15
11
  ></TMagicCheckbox>
16
12
  </component>
@@ -33,7 +29,7 @@
33
29
  :disabled="disabled"
34
30
  :labelWidth="lWidth"
35
31
  :size="size"
36
- @change="change"
32
+ @change="changeHandler"
37
33
  @add-diff-count="onAddDiffCount()"
38
34
  ></Container>
39
35
  </div>
@@ -54,7 +50,7 @@
54
50
  :labelWidth="lWidth"
55
51
  :size="size"
56
52
  :disabled="disabled"
57
- @change="change"
53
+ @change="changeHandler"
58
54
  @addDiffCount="onAddDiffCount()"
59
55
  ></Container>
60
56
  </template>
@@ -66,7 +62,7 @@ import { computed, inject } from 'vue';
66
62
 
67
63
  import { TMagicCheckbox } from '@tmagic/design';
68
64
 
69
- import { FieldsetConfig, FormState } from '../schema';
65
+ import { ContainerChangeEventData, FieldsetConfig, FormState } from '../schema';
70
66
 
71
67
  import Container from './Container.vue';
72
68
 
@@ -94,7 +90,10 @@ const props = withDefaults(
94
90
  },
95
91
  );
96
92
 
97
- const emit = defineEmits(['change', 'addDiffCount']);
93
+ const emit = defineEmits<{
94
+ change: [v: any, eventData: ContainerChangeEventData];
95
+ addDiffCount: [];
96
+ }>();
98
97
 
99
98
  const mForm = inject<FormState | undefined>('mForm');
100
99
 
@@ -114,10 +113,12 @@ const lWidth = computed(() => {
114
113
  return props.config.labelWidth || props.labelWidth || (props.config.text ? undefined : '0');
115
114
  });
116
115
 
117
- const change = () => {
118
- emit('change', props.model);
116
+ const valueChangeHandler = (value: number | boolean) => {
117
+ emit('change', value, { modifyKey: 'value' });
119
118
  };
120
119
 
120
+ const changeHandler = (v: any, eventData: ContainerChangeEventData) => emit('change', v, eventData);
121
+
121
122
  const key = (item: any, index: number) => item[mForm?.keyProp || '__key'] ?? index;
122
123
 
123
124
  const onAddDiffCount = () => emit('addDiffCount');
@@ -25,7 +25,14 @@
25
25
  @addDiffCount="onAddDiffCount()"
26
26
  ></MFieldsGroupListItem>
27
27
 
28
- <TMagicButton @click="addHandler" size="small" :disabled="disabled" v-if="addable">新增</TMagicButton>
28
+ <TMagicButton
29
+ v-if="addable"
30
+ type="primary"
31
+ :size="config.enableToggleMode ? 'small' : 'default'"
32
+ :disabled="disabled"
33
+ @click="addHandler"
34
+ >新增</TMagicButton
35
+ >
29
36
 
30
37
  <TMagicButton :icon="Grid" size="small" @click="toggleMode" v-if="config.enableToggleMode">切换为表格</TMagicButton>
31
38
  </div>
@@ -37,7 +44,7 @@ import { Grid } from '@element-plus/icons-vue';
37
44
 
38
45
  import { TMagicButton } from '@tmagic/design';
39
46
 
40
- import { FormState, GroupListConfig } from '../schema';
47
+ import type { ContainerChangeEventData, FormState, GroupListConfig } from '../schema';
41
48
  import { initValue } from '../utils/form';
42
49
 
43
50
  import MFieldsGroupListItem from './GroupListItem.vue';
@@ -58,7 +65,10 @@ const props = defineProps<{
58
65
  disabled?: boolean;
59
66
  }>();
60
67
 
61
- const emit = defineEmits(['change', 'addDiffCount']);
68
+ const emit = defineEmits<{
69
+ change: [v: any, eventData?: ContainerChangeEventData];
70
+ addDiffCount: [];
71
+ }>();
62
72
 
63
73
  const mForm = inject<FormState | undefined>('mForm');
64
74
 
@@ -77,10 +87,8 @@ const addable = computed(() => {
77
87
  return typeof props.config.addable === 'undefined' ? true : props.config.addable;
78
88
  });
79
89
 
80
- const changeHandler = () => {
81
- if (!props.name) return false;
82
-
83
- emit('change', props.model[props.name]);
90
+ const changeHandler = (v: any, eventData: ContainerChangeEventData) => {
91
+ emit('change', props.model, eventData);
84
92
  };
85
93
 
86
94
  const addHandler = async () => {
@@ -105,14 +113,22 @@ const addHandler = async () => {
105
113
  });
106
114
 
107
115
  props.model[props.name].push(groupValue);
108
- changeHandler();
116
+
117
+ emit('change', props.model[props.name], {
118
+ changeRecords: [
119
+ {
120
+ propPath: `${props.prop}.${props.model[props.name].length - 1}`,
121
+ value: groupValue,
122
+ },
123
+ ],
124
+ });
109
125
  };
110
126
 
111
127
  const removeHandler = (index: number) => {
112
128
  if (!props.name) return false;
113
129
 
114
130
  props.model[props.name].splice(index, 1);
115
- changeHandler();
131
+ emit('change', props.model[props.name]);
116
132
  };
117
133
 
118
134
  const swapHandler = (idx1: number, idx2: number) => {
@@ -120,7 +136,7 @@ const swapHandler = (idx1: number, idx2: number) => {
120
136
 
121
137
  const [currRow] = props.model[props.name].splice(idx1, 1);
122
138
  props.model[props.name].splice(idx2, 0, currRow);
123
- changeHandler();
139
+ emit('change', props.model[props.name]);
124
140
  };
125
141
 
126
142
  const toggleMode = () => {