@tmagic/form 1.5.2 → 1.5.3

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.
@@ -20,6 +20,7 @@
20
20
  :disabled="disabled"
21
21
  :group-model="model[name]"
22
22
  @remove-item="removeHandler"
23
+ @copy-item="copyHandler"
23
24
  @swap-item="swapHandler"
24
25
  @change="changeHandler"
25
26
  @addDiffCount="onAddDiffCount()"
@@ -41,6 +42,7 @@
41
42
  <script setup lang="ts">
42
43
  import { computed, inject } from 'vue';
43
44
  import { Grid } from '@element-plus/icons-vue';
45
+ import { cloneDeep } from 'lodash-es';
44
46
 
45
47
  import { TMagicButton } from '@tmagic/design';
46
48
 
@@ -131,11 +133,17 @@ const removeHandler = (index: number) => {
131
133
  emit('change', props.model[props.name]);
132
134
  };
133
135
 
136
+ const copyHandler = (index: number) => {
137
+ props.model[props.name].push(cloneDeep(props.model[props.name][index]));
138
+ };
139
+
134
140
  const swapHandler = (idx1: number, idx2: number) => {
135
141
  if (!props.name) return false;
136
142
 
143
+ const { length } = props.model[props.name];
144
+
137
145
  const [currRow] = props.model[props.name].splice(idx1, 1);
138
- props.model[props.name].splice(idx2, 0, currRow);
146
+ props.model[props.name].splice(Math.min(Math.max(idx2, 0), length - 1), 0, currRow);
139
147
  emit('change', props.model[props.name]);
140
148
  };
141
149
 
@@ -6,23 +6,83 @@
6
6
  </TMagicButton>
7
7
 
8
8
  <TMagicButton
9
- v-show="showDelete(parseInt(String(index)))"
10
- style="color: #f56c6c"
9
+ v-show="showDelete"
10
+ type="danger"
11
+ size="small"
11
12
  link
12
13
  :icon="Delete"
13
14
  :disabled="disabled"
14
15
  @click="removeHandler"
15
16
  ></TMagicButton>
16
17
 
17
- <template v-if="movable()">
18
- <TMagicButton v-show="index !== 0" link :disabled="disabled" size="small" @click="changeOrder(-1)"
19
- >上移<TMagicIcon><CaretTop /></TMagicIcon
20
- ></TMagicButton>
21
- <TMagicButton v-show="index !== length - 1" :disabled="disabled" link size="small" @click="changeOrder(1)"
22
- >下移<TMagicIcon><CaretBottom /></TMagicIcon
23
- ></TMagicButton>
18
+ <TMagicButton
19
+ v-if="copyable"
20
+ link
21
+ size="small"
22
+ type="primary"
23
+ :icon="DocumentCopy"
24
+ :disabled="disabled"
25
+ @click="copyHandler"
26
+ >复制</TMagicButton
27
+ >
28
+
29
+ <template v-if="movable">
30
+ <TMagicButton
31
+ v-show="index !== 0"
32
+ link
33
+ size="small"
34
+ :disabled="disabled"
35
+ :icon="CaretTop"
36
+ @click="changeOrder(-1)"
37
+ >上移</TMagicButton
38
+ >
39
+ <TMagicButton
40
+ v-show="index !== length - 1"
41
+ link
42
+ size="small"
43
+ :disabled="disabled"
44
+ :icon="CaretBottom"
45
+ @click="changeOrder(1)"
46
+ >下移</TMagicButton
47
+ >
24
48
  </template>
25
49
 
50
+ <TMagicPopover
51
+ v-if="config.moveSpecifyLocation"
52
+ trigger="click"
53
+ placement="top"
54
+ width="200"
55
+ :visible="moveSpecifyLocationVisible"
56
+ >
57
+ <template #reference>
58
+ <TMagicButton
59
+ link
60
+ size="small"
61
+ type="primary"
62
+ :icon="Position"
63
+ :disabled="disabled"
64
+ @click="moveSpecifyLocationVisible = true"
65
+ >移动至</TMagicButton
66
+ >
67
+ </template>
68
+ <div>
69
+ <div>
70
+ 第<TMagicInputNumber
71
+ style="margin: 0 5px"
72
+ v-model="moveSpecifyLocationIndex"
73
+ size="small"
74
+ :min="1"
75
+ :disabled="disabled"
76
+ ></TMagicInputNumber
77
+ >行
78
+ </div>
79
+ <div style="text-align: right; margin-top: 20px">
80
+ <TMagicButton size="small" text @click="moveSpecifyLocationVisible = false">取消</TMagicButton>
81
+ <TMagicButton size="small" type="primary" @click="moveSpecifyLocationHandler">确认</TMagicButton>
82
+ </div>
83
+ </div>
84
+ </TMagicPopover>
85
+
26
86
  <span v-if="itemExtra" v-html="itemExtra" class="m-form-tip"></span>
27
87
  </div>
28
88
 
@@ -44,9 +104,9 @@
44
104
 
45
105
  <script setup lang="ts">
46
106
  import { computed, inject, ref } from 'vue';
47
- import { CaretBottom, CaretRight, CaretTop, Delete } from '@element-plus/icons-vue';
107
+ import { CaretBottom, CaretRight, CaretTop, Delete, DocumentCopy, Position } from '@element-plus/icons-vue';
48
108
 
49
- import { TMagicButton, TMagicIcon } from '@tmagic/design';
109
+ import { TMagicButton, TMagicIcon, TMagicInputNumber, TMagicPopover } from '@tmagic/design';
50
110
 
51
111
  import type { ContainerChangeEventData, FormState, GroupListConfig } from '../schema';
52
112
  import { filterFunction } from '../utils/form';
@@ -70,7 +130,7 @@ const props = defineProps<{
70
130
  disabled?: boolean;
71
131
  }>();
72
132
 
73
- const emit = defineEmits(['swap-item', 'remove-item', 'change', 'addDiffCount']);
133
+ const emit = defineEmits(['swap-item', 'remove-item', 'change', 'addDiffCount', 'copy-item']);
74
134
 
75
135
  const mForm = inject<FormState | undefined>('mForm');
76
136
  const expand = ref(props.config.expandAll || !props.index);
@@ -112,18 +172,18 @@ const expandHandler = () => {
112
172
  };
113
173
 
114
174
  // 希望支持单行可控制是否显示删除按钮,不会影响现有逻辑
115
- const showDelete = (index: number) => {
175
+ const showDelete = computed(() => {
116
176
  const deleteFunc = props.config.delete;
117
177
  if (deleteFunc && typeof deleteFunc === 'function') {
118
- return deleteFunc(props.model, index, mForm?.values);
178
+ return deleteFunc(props.model, props.index, mForm?.values);
119
179
  }
120
180
  return true;
121
- };
181
+ });
122
182
 
123
183
  // 调换顺序
124
184
  const changeOrder = (offset = 0) => emit('swap-item', props.index, props.index + offset);
125
185
 
126
- const movable = () => {
186
+ const movable = computed(() => {
127
187
  const { movable } = props.config;
128
188
 
129
189
  // 没有设置时,默认可移动
@@ -132,6 +192,20 @@ const movable = () => {
132
192
  return movable(mForm, props.index || 0, props.model, props.groupModel);
133
193
  }
134
194
  return movable;
135
- };
195
+ });
196
+
197
+ const copyable = computed(() => filterFunction<boolean>(mForm, props.config.copyable, props));
136
198
  const onAddDiffCount = () => emit('addDiffCount');
199
+
200
+ const copyHandler = () => {
201
+ emit('copy-item', props.index);
202
+ };
203
+
204
+ const moveSpecifyLocationVisible = ref(false);
205
+ const moveSpecifyLocationIndex = ref(1);
206
+
207
+ const moveSpecifyLocationHandler = () => {
208
+ moveSpecifyLocationVisible.value = false;
209
+ emit('swap-item', props.index, moveSpecifyLocationIndex.value - 1);
210
+ };
137
211
  </script>
@@ -26,18 +26,32 @@
26
26
 
27
27
  <TMagicTableColumn
28
28
  label="操作"
29
- :width="config.operateColWidth || 55"
29
+ :width="config.operateColWidth || 100"
30
30
  align="center"
31
31
  :fixed="config.fixed === false ? undefined : 'left'"
32
32
  >
33
33
  <template v-slot="scope">
34
34
  <slot name="operateCol" :scope="scope"></slot>
35
- <TMagicIcon
35
+ <TMagicButton
36
36
  v-show="showDelete(scope.$index + 1 + pagecontext * pagesize - 1)"
37
- class="m-table-delete-icon"
37
+ size="small"
38
+ type="danger"
39
+ link
40
+ title="删除"
41
+ :icon="Delete"
38
42
  @click="removeHandler(scope.$index + 1 + pagecontext * pagesize - 1)"
39
- ><Delete
40
- /></TMagicIcon>
43
+ ></TMagicButton>
44
+
45
+ <TMagicButton
46
+ v-if="copyable(scope.$index + 1 + pagecontext * pagesize - 1)"
47
+ link
48
+ size="small"
49
+ type="primary"
50
+ title="复制"
51
+ :icon="DocumentCopy"
52
+ :disabled="disabled"
53
+ @click="copyHandler(scope.$index + 1 + pagecontext * pagesize - 1)"
54
+ ></TMagicButton>
41
55
  </template>
42
56
  </TMagicTableColumn>
43
57
 
@@ -189,13 +203,12 @@
189
203
 
190
204
  <script setup lang="ts">
191
205
  import { computed, inject, onMounted, ref, toRefs, watchEffect } from 'vue';
192
- import { ArrowDown, ArrowUp, Delete, FullScreen, Grid } from '@element-plus/icons-vue';
206
+ import { ArrowDown, ArrowUp, Delete, DocumentCopy, FullScreen, Grid } from '@element-plus/icons-vue';
193
207
  import { cloneDeep } from 'lodash-es';
194
208
  import Sortable, { SortableEvent } from 'sortablejs';
195
209
 
196
210
  import {
197
211
  TMagicButton,
198
- TMagicIcon,
199
212
  tMagicMessage,
200
213
  TMagicPagination,
201
214
  TMagicTable,
@@ -550,6 +563,22 @@ const showDelete = (index: number) => {
550
563
  return true;
551
564
  };
552
565
 
566
+ const copyable = (index: number) => {
567
+ const copyableFunc = props.config.copyable;
568
+ if (copyableFunc && typeof copyableFunc === 'function') {
569
+ return copyableFunc(mForm, {
570
+ values: mForm?.initValues || {},
571
+ model: props.model,
572
+ parent: mForm?.parentValues || {},
573
+ formValue: mForm?.values || props.model,
574
+ prop: props.prop,
575
+ config: props.config,
576
+ index,
577
+ });
578
+ }
579
+ return true;
580
+ };
581
+
553
582
  const clearHandler = () => {
554
583
  const len = props.model[modelName.value].length;
555
584
  props.model[modelName.value].splice(0, len);
@@ -594,6 +623,10 @@ const handleCurrentChange = (val: number) => {
594
623
  pagecontext.value = val - 1;
595
624
  };
596
625
 
626
+ const copyHandler = (index: number) => {
627
+ props.model[modelName.value].push(cloneDeep(props.model[modelName.value][index]));
628
+ };
629
+
597
630
  const toggleMode = () => {
598
631
  const calcLabelWidth = (label: string) => {
599
632
  if (!label) return '0px';
@@ -1,13 +1,30 @@
1
1
  <template>
2
- <TMagicRadioGroup v-if="model" v-model="model[name]" :size="size" :disabled="disabled" @change="changeHandler">
3
- <TMagicRadio v-for="option in config.options" :value="option.value" :key="`${option.value}`">{{
4
- option.text
5
- }}</TMagicRadio>
2
+ <TMagicRadioGroup v-if="model" v-model="model[name]" :size="size" :disabled="disabled">
3
+ <component
4
+ :is="itemComponent"
5
+ v-for="option in config.options"
6
+ :value="option.value"
7
+ :key="`${option.value}`"
8
+ @click.prevent="clickHandler(option.value)"
9
+ >
10
+ <TMagicTooltip v-if="option.tooltip" placement="top-start" :content="option.tooltip">
11
+ <div>
12
+ <TMagicIcon v-if="option.icon" :size="'16'"><component :is="option.icon"></component></TMagicIcon>
13
+ <span>{{ option.text }}</span>
14
+ </div>
15
+ </TMagicTooltip>
16
+ <div v-else>
17
+ <TMagicIcon v-if="option.icon" :size="'16'"><component :is="option.icon"></component></TMagicIcon>
18
+ <span>{{ option.text }}</span>
19
+ </div>
20
+ </component>
6
21
  </TMagicRadioGroup>
7
22
  </template>
8
23
 
9
24
  <script lang="ts" setup>
10
- import { TMagicRadio, TMagicRadioGroup } from '@tmagic/design';
25
+ import { computed } from 'vue';
26
+
27
+ import { TMagicIcon, TMagicRadio, TMagicRadioButton, TMagicRadioGroup, TMagicTooltip } from '@tmagic/design';
11
28
 
12
29
  import type { FieldProps, RadioGroupConfig } from '../schema';
13
30
  import { useAddField } from '../utils/useAddField';
@@ -18,11 +35,18 @@ defineOptions({
18
35
 
19
36
  const props = defineProps<FieldProps<RadioGroupConfig>>();
20
37
 
38
+ const itemComponent = computed(() => (props.config.childType === 'button' ? TMagicRadioButton : TMagicRadio));
39
+
21
40
  const emit = defineEmits(['change']);
22
41
 
23
42
  const changeHandler = (value: number) => {
24
43
  emit('change', value);
25
44
  };
26
45
 
46
+ const clickHandler = (item: any) => {
47
+ props.model[props.name] = props.model[props.name] === item ? '' : item;
48
+ changeHandler(props.model[props.name]);
49
+ };
50
+
27
51
  useAddField(props.prop);
28
52
  </script>
package/src/schema.ts CHANGED
@@ -438,9 +438,12 @@ export interface SwitchConfig extends FormItem {
438
438
  */
439
439
  export interface RadioGroupConfig extends FormItem {
440
440
  type: 'radio-group';
441
+ childType?: 'default' | 'button';
441
442
  options: {
442
443
  value: string | number | boolean;
443
444
  text: string;
445
+ icon?: any;
446
+ tooltip?: string;
444
447
  }[];
445
448
  }
446
449
 
@@ -681,6 +684,7 @@ export interface TableConfig extends FormItem {
681
684
  addable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
682
685
  /** 是否显示删除按钮 */
683
686
  delete?: (model: any, index: number, values: any) => boolean | boolean;
687
+ copyable?: (model: any, data: any) => boolean | boolean;
684
688
  /** 是否显示导入按钮 */
685
689
  importable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
686
690
  /** 是否显示checkbox */
@@ -715,12 +719,14 @@ export interface GroupListConfig extends FormItem {
715
719
  addable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
716
720
  defaultAdd?: (mForm: FormState | undefined, data: any) => any;
717
721
  delete?: (model: any, index: number | string | symbol, values: any) => boolean | boolean;
722
+ copyable?: FilterFunction<boolean>;
718
723
  movable?: (
719
724
  mForm: FormState | undefined,
720
725
  index: number | string | symbol,
721
726
  model: any,
722
727
  groupModel: any,
723
728
  ) => boolean | boolean;
729
+ moveSpecifyLocation?: boolean;
724
730
  [key: string]: any;
725
731
  }
726
732
 
@@ -62,9 +62,4 @@
62
62
  .el-form-item {
63
63
  margin-bottom: 0;
64
64
  }
65
-
66
- .m-table-delete-icon {
67
- color: #f56c6c;
68
- cursor: pointer;
69
- }
70
65
  }
package/types/index.d.ts CHANGED
@@ -359,9 +359,12 @@ interface SwitchConfig extends FormItem {
359
359
  */
360
360
  interface RadioGroupConfig extends FormItem {
361
361
  type: 'radio-group';
362
+ childType?: 'default' | 'button';
362
363
  options: {
363
364
  value: string | number | boolean;
364
365
  text: string;
366
+ icon?: any;
367
+ tooltip?: string;
365
368
  }[];
366
369
  }
367
370
  /**
@@ -571,6 +574,7 @@ interface TableConfig extends FormItem {
571
574
  addable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
572
575
  /** 是否显示删除按钮 */
573
576
  delete?: (model: any, index: number, values: any) => boolean | boolean;
577
+ copyable?: (model: any, data: any) => boolean | boolean;
574
578
  /** 是否显示导入按钮 */
575
579
  importable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
576
580
  /** 是否显示checkbox */
@@ -604,7 +608,9 @@ interface GroupListConfig extends FormItem {
604
608
  addable?: (mForm: FormState | undefined, data: any) => boolean | 'undefined' | boolean;
605
609
  defaultAdd?: (mForm: FormState | undefined, data: any) => any;
606
610
  delete?: (model: any, index: number | string | symbol, values: any) => boolean | boolean;
611
+ copyable?: FilterFunction<boolean>;
607
612
  movable?: (mForm: FormState | undefined, index: number | string | symbol, model: any, groupModel: any) => boolean | boolean;
613
+ moveSpecifyLocation?: boolean;
608
614
  [key: string]: any;
609
615
  }
610
616
  interface StepItemConfig extends FormItem, ContainerCommonConfig {