@tmagic/form 1.7.0-beta.2 → 1.7.0-beta.4

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.
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <div class="m-fields-text">
3
3
  <TMagicInput
4
- :model-value="model[name]"
4
+ v-model="value"
5
5
  ref="input"
6
6
  clearable
7
7
  :size="size"
8
8
  :placeholder="config.placeholder"
9
9
  :disabled="disabled"
10
- @update:model-value="changeHandler"
10
+ @change="changeHandler"
11
11
  @input="inputHandler"
12
12
  @keyup="keyUpHandler($event)"
13
13
  >
@@ -41,7 +41,7 @@
41
41
  </template>
42
42
 
43
43
  <script lang="ts" setup>
44
- import { computed, inject, ref, shallowRef, watch } from 'vue';
44
+ import { computed, inject, readonly, ref, shallowRef, watch } from 'vue';
45
45
  import type { Instance } from '@popperjs/core';
46
46
  import { createPopper } from '@popperjs/core';
47
47
  import { debounce } from 'lodash-es';
@@ -49,7 +49,7 @@ import { debounce } from 'lodash-es';
49
49
  import { TMagicButton, TMagicInput } from '@tmagic/design';
50
50
  import { isNumber } from '@tmagic/utils';
51
51
 
52
- import type { FieldProps, FormState, TextConfig } from '../schema';
52
+ import type { ChangeRecord, ContainerChangeEventData, FieldProps, FormState, TextConfig } from '../schema';
53
53
  import { useAddField } from '../utils/useAddField';
54
54
 
55
55
  defineOptions({
@@ -59,7 +59,7 @@ defineOptions({
59
59
  const props = defineProps<FieldProps<TextConfig>>();
60
60
 
61
61
  const emit = defineEmits<{
62
- change: [value: string];
62
+ change: [value: string, eventData?: ContainerChangeEventData];
63
63
  input: [value: string];
64
64
  }>();
65
65
 
@@ -67,6 +67,18 @@ useAddField(props.prop);
67
67
 
68
68
  const mForm = inject<FormState | undefined>('mForm');
69
69
 
70
+ const value = ref('');
71
+
72
+ watch(
73
+ () => props.model[props.name],
74
+ (v) => {
75
+ value.value = v;
76
+ },
77
+ {
78
+ immediate: true,
79
+ },
80
+ );
81
+
70
82
  const appendConfig = computed(() => {
71
83
  if (typeof props.config.append === 'string') {
72
84
  return {
@@ -121,10 +133,28 @@ const inputHandler = (v: string) => {
121
133
  const buttonClickHandler = () => {
122
134
  if (!appendConfig.value) return;
123
135
  if (typeof appendConfig.value.handler === 'function') {
136
+ const newChangeRecords: ChangeRecord[] = [];
137
+ const setModel = (key: string, value: any) => {
138
+ newChangeRecords.push({ propPath: props.prop.replace(`${props.name}`, key), value });
139
+ };
140
+
141
+ const setFormValue = (key: string, value: any) => {
142
+ newChangeRecords.push({ propPath: key, value });
143
+ };
144
+
124
145
  appendConfig.value.handler(mForm, {
125
146
  model: props.model,
126
- values: mForm?.values,
147
+ values: mForm ? readonly(mForm.initValues) : null,
148
+ formValue: props.values || {},
149
+ setModel,
150
+ setFormValue,
127
151
  });
152
+
153
+ if (newChangeRecords.length > 0) {
154
+ emit('change', props.model[props.name], {
155
+ changeRecords: newChangeRecords,
156
+ });
157
+ }
128
158
  }
129
159
  };
130
160
 
@@ -1,20 +1,20 @@
1
1
  <template>
2
2
  <TMagicInput
3
- :model-value="model[name]"
3
+ v-model="value"
4
4
  type="textarea"
5
5
  :size="size"
6
6
  clearable
7
7
  :placeholder="config.placeholder"
8
8
  :disabled="disabled"
9
9
  :rows="config.rows"
10
- @update:model-value="changeHandler"
10
+ @change="changeHandler"
11
11
  @input="inputHandler"
12
12
  >
13
13
  </TMagicInput>
14
14
  </template>
15
15
 
16
16
  <script lang="ts" setup>
17
- import { inject } from 'vue';
17
+ import { inject, ref, watch } from 'vue';
18
18
 
19
19
  import { TMagicInput } from '@tmagic/design';
20
20
 
@@ -32,6 +32,18 @@ const emit = defineEmits<{
32
32
  input: [value: string];
33
33
  }>();
34
34
 
35
+ const value = ref('');
36
+
37
+ watch(
38
+ () => props.model[props.name],
39
+ (v) => {
40
+ value.value = v;
41
+ },
42
+ {
43
+ immediate: true,
44
+ },
45
+ );
46
+
35
47
  useAddField(props.prop);
36
48
 
37
49
  const mForm = inject<FormState | null>('mForm');
@@ -1,7 +1,12 @@
1
1
  <template>
2
- <div class="m-fields-table-wrap">
3
- <teleport to="body" :disabled="!isFullscreen">
4
- <div ref="mTable" class="m-fields-table" :class="{ 'm-fields-table-item-extra': config.itemExtra }">
2
+ <teleport to="body" :disabled="!isFullscreen">
3
+ <div
4
+ v-bind="$attrs"
5
+ class="m-fields-table-wrap"
6
+ :class="{ fixed: isFullscreen }"
7
+ :style="isFullscreen ? `z-index: ${nextZIndex()}` : ''"
8
+ >
9
+ <div class="m-fields-table" :class="{ 'm-fields-table-item-extra': config.itemExtra }">
5
10
  <span v-if="config.extra" style="color: rgba(0, 0, 0, 0.45)" v-html="config.extra"></span>
6
11
  <TMagicTooltip content="拖拽可排序" placement="left-start" :disabled="config.dropSort !== true">
7
12
  <TMagicTable
@@ -28,7 +33,6 @@
28
33
  <TMagicButton
29
34
  :icon="Grid"
30
35
  size="small"
31
- type="defalut"
32
36
  @click="toggleMode"
33
37
  v-if="enableToggleMode && config.enableToggleMode !== false && !isFullscreen"
34
38
  >展开配置</TMagicButton
@@ -36,7 +40,6 @@
36
40
  <TMagicButton
37
41
  :icon="FullScreen"
38
42
  size="small"
39
- type="defalut"
40
43
  @click="toggleFullscreen"
41
44
  v-if="config.enableFullscreen !== false"
42
45
  >
@@ -57,8 +60,16 @@
57
60
  >清空</TMagicButton
58
61
  >
59
62
  </div>
60
- <TMagicButton v-if="addable" size="small" type="primary" :disabled="disabled" plain @click="newHandler()"
61
- >新增一行</TMagicButton
63
+ <TMagicButton
64
+ v-if="addable"
65
+ class="m-form-table-add-button"
66
+ size="small"
67
+ plain
68
+ :icon="Plus"
69
+ v-bind="config.addButtonConfig?.props || { type: 'primary' }"
70
+ :disabled="disabled"
71
+ @click="newHandler()"
72
+ >{{ config.addButtonConfig?.text || '新增一行' }}</TMagicButton
62
73
  >
63
74
  </div>
64
75
 
@@ -76,15 +87,15 @@
76
87
  </TMagicPagination>
77
88
  </div>
78
89
  </div>
79
- </teleport>
80
- </div>
90
+ </div>
91
+ </teleport>
81
92
  </template>
82
93
 
83
94
  <script setup lang="ts">
84
95
  import { computed, ref, useTemplateRef } from 'vue';
85
- import { FullScreen, Grid } from '@element-plus/icons-vue';
96
+ import { FullScreen, Grid, Plus } from '@element-plus/icons-vue';
86
97
 
87
- import { TMagicButton, TMagicPagination, TMagicTable, TMagicTooltip, TMagicUpload } from '@tmagic/design';
98
+ import { TMagicButton, TMagicPagination, TMagicTable, TMagicTooltip, TMagicUpload, useZIndex } from '@tmagic/design';
88
99
 
89
100
  import type { SortProp } from '../schema';
90
101
  import { sortChange } from '../utils/form';
@@ -121,6 +132,8 @@ const { pageSize, currentPage, paginationData, handleSizeChange, handleCurrentCh
121
132
  modelName,
122
133
  );
123
134
 
135
+ const { nextZIndex } = useZIndex();
136
+
124
137
  const { addable, newHandler } = useAdd(props, emit);
125
138
  const { columns } = useTableColumns(props, emit, currentPage, pageSize, modelName);
126
139
  useSortable(props, emit, tMagicTableRef, modelName);
@@ -78,6 +78,7 @@ export const useAdd = (
78
78
  if (typeof props.config.defaultAdd === 'function') {
79
79
  inputs = await props.config.defaultAdd(mForm, {
80
80
  model: props.model[modelName],
81
+ prop: props.prop,
81
82
  formValue: mForm?.values,
82
83
  });
83
84
  } else if (props.config.defaultAdd) {
@@ -1,22 +1,12 @@
1
- import { ref, useTemplateRef } from 'vue';
2
-
3
- import { useZIndex } from '@tmagic/design';
1
+ import { ref } from 'vue';
4
2
 
5
3
  export const useFullscreen = () => {
6
4
  const isFullscreen = ref(false);
7
- const mTableEl = useTemplateRef<HTMLDivElement>('mTable');
8
-
9
- const { nextZIndex } = useZIndex();
10
5
 
11
6
  const toggleFullscreen = () => {
12
- if (!mTableEl.value) return;
13
-
14
7
  if (isFullscreen.value) {
15
- mTableEl.value.classList.remove('fixed');
16
8
  isFullscreen.value = false;
17
9
  } else {
18
- mTableEl.value.classList.add('fixed');
19
- mTableEl.value.style.zIndex = `${nextZIndex()}`;
20
10
  isFullscreen.value = true;
21
11
  }
22
12
  };
@@ -20,7 +20,7 @@ export const useSortable = (
20
20
  const rowDrop = () => {
21
21
  sortable?.destroy();
22
22
  const tableEl = tMagicTableRef.value?.getEl();
23
- const tBodyEl = tableEl?.querySelector('.el-table__body > tbody');
23
+ const tBodyEl = tableEl?.querySelector('.el-table__body > tbody') || tableEl?.querySelector('.t-table__body');
24
24
  if (!tBodyEl) {
25
25
  return;
26
26
  }
@@ -1,7 +1,8 @@
1
1
  import { computed, h, inject, type Ref } from 'vue';
2
+ import { WarningFilled } from '@element-plus/icons-vue';
2
3
  import { cloneDeep } from 'lodash-es';
3
4
 
4
- import type { TableColumnOptions } from '@tmagic/design';
5
+ import { type TableColumnOptions, TMagicIcon, TMagicTooltip } from '@tmagic/design';
5
6
  import type { FormState, TableColumnConfig } from '@tmagic/form-schema';
6
7
 
7
8
  import Container from '../containers/Container.vue';
@@ -43,6 +44,19 @@ export const useTableColumns = (
43
44
  return fuc;
44
45
  };
45
46
 
47
+ const titleTip = (fuc: any) => {
48
+ if (typeof fuc === 'function') {
49
+ return fuc(mForm, {
50
+ values: mForm?.initValues,
51
+ model: props.model,
52
+ formValue: mForm ? mForm.values : props.model,
53
+ prop: props.prop,
54
+ });
55
+ }
56
+
57
+ return fuc;
58
+ };
59
+
46
60
  const selection = computed(() => {
47
61
  if (typeof props.config.selection === 'function') {
48
62
  return props.config.selection(mForm, { model: props.model[modelName.value] });
@@ -87,10 +101,16 @@ export const useTableColumns = (
87
101
  });
88
102
  }
89
103
 
90
- columns.push({
104
+ let actionFixed: 'left' | 'right' | undefined = props.config.fixed === false ? undefined : 'left';
105
+
106
+ if (typeof props.config.fixed === 'string' && ['left', 'right'].includes(props.config.fixed)) {
107
+ actionFixed = props.config.fixed;
108
+ }
109
+
110
+ const actionClumn = {
91
111
  props: {
92
112
  label: '操作',
93
- fixed: props.config.fixed === false ? undefined : 'left',
113
+ fixed: actionFixed,
94
114
  width: props.config.operateColWidth || 112,
95
115
  align: 'center',
96
116
  },
@@ -110,7 +130,11 @@ export const useTableColumns = (
110
130
  emit('change', v);
111
131
  },
112
132
  }),
113
- });
133
+ };
134
+
135
+ if (actionFixed !== 'right') {
136
+ columns.push(actionClumn);
137
+ }
114
138
 
115
139
  if (props.sort && props.model[modelName.value] && props.model[modelName.value].length > 1) {
116
140
  columns.push({
@@ -158,6 +182,8 @@ export const useTableColumns = (
158
182
 
159
183
  for (const column of props.config.items) {
160
184
  if (column.type !== 'hidden' && display(column.display)) {
185
+ const titleTipValue = titleTip(column.titleTip);
186
+
161
187
  columns.push({
162
188
  props: {
163
189
  prop: column.name,
@@ -181,10 +207,39 @@ export const useTableColumns = (
181
207
  onChange: changeHandler,
182
208
  onAddDiffCount,
183
209
  }),
210
+ title: titleTipValue
211
+ ? () =>
212
+ h(
213
+ TMagicTooltip,
214
+ { placement: 'top' },
215
+ {
216
+ default: () =>
217
+ h(
218
+ 'span',
219
+ {
220
+ style: {
221
+ display: 'inline-flex',
222
+ alignItems: 'center',
223
+ gap: '5px',
224
+ },
225
+ },
226
+ [h('span', column.label), h(TMagicIcon, {}, { default: () => h(WarningFilled) })],
227
+ ),
228
+ content: () =>
229
+ h('div', {
230
+ innerHTML: titleTipValue,
231
+ }),
232
+ },
233
+ )
234
+ : undefined,
184
235
  });
185
236
  }
186
237
  }
187
238
 
239
+ if (actionFixed === 'right') {
240
+ columns.push(actionClumn);
241
+ }
242
+
188
243
  return columns;
189
244
  });
190
245
 
@@ -20,4 +20,19 @@
20
20
  border-bottom: 0;
21
21
  }
22
22
  }
23
+
24
+ .tmagic-design-card {
25
+ .el-card__header {
26
+ padding: 5px 20px;
27
+ }
28
+ .t-card__header {
29
+ padding: 5px 0;
30
+ }
31
+ }
32
+
33
+ .m-fields-group-list-footer {
34
+ display: flex;
35
+ justify-content: space-between;
36
+ margin-top: 10px;
37
+ }
23
38
  }
@@ -1,9 +1,6 @@
1
1
  .m-fields-table-wrap {
2
2
  width: 100%;
3
- }
4
3
 
5
- .m-fields-table {
6
- width: 100%;
7
4
  &.fixed {
8
5
  position: fixed;
9
6
  height: 100%;
@@ -14,6 +11,8 @@
14
11
  bottom: 0;
15
12
  z-index: 100;
16
13
  background: rgba(0, 0, 0, 0.5);
14
+ align-items: center;
15
+ display: flex;
17
16
 
18
17
  & > .el-form-item__content {
19
18
  z-index: 101;
@@ -25,6 +24,10 @@
25
24
  width: 95vw !important;
26
25
  }
27
26
  }
27
+ }
28
+
29
+ .m-fields-table {
30
+ width: 100%;
28
31
 
29
32
  th {
30
33
  background-color: #f2f2f2 !important;
package/src/utils/form.ts CHANGED
@@ -341,7 +341,7 @@ export const sortArray = (data: any[], newIndex: number, oldIndex: number, sortK
341
341
  }
342
342
  }
343
343
 
344
- return newData;
344
+ return cloneDeep(newData);
345
345
  };
346
346
 
347
347
  export const sortChange = (data: any[], { prop, order }: SortProp) => {
package/types/index.d.ts CHANGED
@@ -109,6 +109,11 @@ type __VLS_Props$t = {
109
109
  size?: 'small' | 'default' | 'large';
110
110
  confirmText?: string;
111
111
  preventSubmitDefault?: boolean;
112
+ closeOnClickModal?: boolean;
113
+ closeOnPressEscape?: boolean;
114
+ destroyOnClose?: boolean;
115
+ showClose?: boolean;
116
+ showCancel?: boolean;
112
117
  };
113
118
  declare var __VLS_19$1: {};
114
119
  declare var __VLS_32: {};
@@ -350,8 +355,13 @@ declare const __VLS_base$4: _vue_runtime_core.DefineComponent<__VLS_Props$t, {
350
355
  onSubmit?: ((...args: any[]) => any) | undefined;
351
356
  }>, {
352
357
  values: Object;
358
+ closeOnClickModal: boolean;
359
+ closeOnPressEscape: boolean;
360
+ destroyOnClose: boolean;
361
+ showClose: boolean;
353
362
  config: FormConfig;
354
363
  confirmText: string;
364
+ showCancel: boolean;
355
365
  }, {}, {}, {}, string, _vue_runtime_core.ComponentProvideOptions, false, {}, any>;
356
366
  declare const __VLS_export$u: __VLS_WithSlots$4<typeof __VLS_base$4, __VLS_Slots$4>;
357
367
  declare const _default$v: typeof __VLS_export$u;
@@ -992,7 +1002,10 @@ type __VLS_Slots$1 = {} & {
992
1002
  } & {
993
1003
  default?: (props: typeof __VLS_18) => any;
994
1004
  };
995
- declare const __VLS_base$1: _vue_runtime_core.DefineComponent<__VLS_Props$n, {}, {}, {}, {}, _vue_runtime_core.ComponentOptionsMixin, _vue_runtime_core.ComponentOptionsMixin, {
1005
+ declare const __VLS_base$1: _vue_runtime_core.DefineComponent<__VLS_Props$n, {
1006
+ getExpand: () => boolean;
1007
+ setExpand: (v: boolean) => void;
1008
+ }, {}, {}, {}, _vue_runtime_core.ComponentOptionsMixin, _vue_runtime_core.ComponentOptionsMixin, {
996
1009
  change: (v: any, eventData: ContainerChangeEventData) => any;
997
1010
  addDiffCount: () => any;
998
1011
  }, string, _vue_runtime_core.PublicProps, Readonly<__VLS_Props$n> & Readonly<{
@@ -1123,10 +1136,10 @@ declare const _default$l: typeof __VLS_export$k;
1123
1136
 
1124
1137
  type __VLS_Props$j = FieldProps<TextConfig>;
1125
1138
  declare const __VLS_export$j: _vue_runtime_core.DefineComponent<__VLS_Props$j, {}, {}, {}, {}, _vue_runtime_core.ComponentOptionsMixin, _vue_runtime_core.ComponentOptionsMixin, {
1126
- change: (value: string) => any;
1139
+ change: (value: string, eventData?: ContainerChangeEventData | undefined) => any;
1127
1140
  input: (value: string) => any;
1128
1141
  }, string, _vue_runtime_core.PublicProps, Readonly<__VLS_Props$j> & Readonly<{
1129
- onChange?: ((value: string) => any) | undefined;
1142
+ onChange?: ((value: string, eventData?: ContainerChangeEventData | undefined) => any) | undefined;
1130
1143
  onInput?: ((value: string) => any) | undefined;
1131
1144
  }>, {}, {}, {}, {}, string, _vue_runtime_core.ComponentProvideOptions, false, {}, any>;
1132
1145
  declare const _default$k: typeof __VLS_export$j;