@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.
Files changed (43) hide show
  1. package/dist/style.css +29 -3
  2. package/dist/tmagic-form.js +1788 -1581
  3. package/dist/tmagic-form.umd.cjs +1830 -1619
  4. package/package.json +6 -6
  5. package/src/Form.vue +18 -5
  6. package/src/containers/Container.vue +109 -134
  7. package/src/containers/Fieldset.vue +31 -7
  8. package/src/containers/FlexLayout.vue +59 -0
  9. package/src/containers/Tabs.vue +11 -1
  10. package/src/fields/Cascader.vue +25 -16
  11. package/src/fields/Checkbox.vue +3 -3
  12. package/src/fields/CheckboxGroup.vue +1 -1
  13. package/src/fields/ColorPicker.vue +2 -2
  14. package/src/fields/Date.vue +2 -2
  15. package/src/fields/DateTime.vue +2 -2
  16. package/src/fields/Daterange.vue +2 -2
  17. package/src/fields/Number.vue +2 -2
  18. package/src/fields/NumberRange.vue +6 -6
  19. package/src/fields/RadioGroup.vue +18 -16
  20. package/src/fields/Select.vue +2 -2
  21. package/src/fields/Switch.vue +2 -2
  22. package/src/fields/Text.vue +21 -9
  23. package/src/fields/Textarea.vue +2 -2
  24. package/src/fields/Time.vue +2 -2
  25. package/src/fields/Timerange.vue +2 -2
  26. package/src/index.ts +5 -2
  27. package/src/table/ActionsColumn.vue +97 -0
  28. package/src/table/SortColumn.vue +101 -0
  29. package/src/table/Table.vue +170 -0
  30. package/src/table/type.ts +18 -0
  31. package/src/table/useAdd.ts +111 -0
  32. package/src/table/useFullscreen.ts +28 -0
  33. package/src/table/useImport.ts +68 -0
  34. package/src/table/usePagination.ts +30 -0
  35. package/src/table/useSelection.ts +34 -0
  36. package/src/table/useSortable.ts +48 -0
  37. package/src/table/useTableColumns.ts +194 -0
  38. package/src/theme/container.scss +17 -0
  39. package/src/theme/form.scss +15 -3
  40. package/src/theme/text.scss +6 -0
  41. package/src/utils/form.ts +56 -2
  42. package/types/index.d.ts +103 -56
  43. package/src/containers/Table.vue +0 -681
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <TMagicCheckbox
3
- v-model="model[name]"
3
+ :model-value="model[name]"
4
4
  :size="size"
5
5
  :trueValue="activeValue"
6
6
  :falseValue="inactiveValue"
7
7
  :disabled="disabled"
8
- @change="changeHandler"
9
- >{{ config.text }}</TMagicCheckbox
8
+ @update:model-value="changeHandler"
9
+ ><template #default v-if="!config.useLabel">{{ config.text }}</template></TMagicCheckbox
10
10
  >
11
11
  </template>
12
12
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <TMagicCheckboxGroup v-model="model[name]" :size="size" :disabled="disabled" @change="changeHandler">
2
+ <TMagicCheckboxGroup :model-value="model[name]" :size="size" :disabled="disabled" @update:model-value="changeHandler">
3
3
  <TMagicCheckbox v-for="option in options" :value="option.value" :key="option.value" :disabled="option.disabled"
4
4
  >{{ option.text }}
5
5
  </TMagicCheckbox>
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
  <TMagicColorPicker
3
- v-model="model[name]"
3
+ :model-value="model[name]"
4
4
  :size="size"
5
5
  :disabled="disabled"
6
6
  :showAlpha="true"
7
- @change="changeHandler"
7
+ @update:model-value="changeHandler"
8
8
  ></TMagicColorPicker>
9
9
  </template>
10
10
 
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <TMagicDatePicker
3
- v-model="model[name]"
3
+ :model-value="model[name]"
4
4
  type="date"
5
5
  :size="size"
6
6
  :placeholder="config.placeholder"
7
7
  :disabled="disabled"
8
8
  :format="config.format || 'YYYY/MM/DD'"
9
9
  :value-format="config.valueFormat || 'YYYY/MM/DD'"
10
- @change="changeHandler"
10
+ @update:model-value="changeHandler"
11
11
  ></TMagicDatePicker>
12
12
  </template>
13
13
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <TMagicDatePicker
3
- v-model="model[name]"
3
+ :model-value="model[name]"
4
4
  popper-class="magic-datetime-picker-popper"
5
5
  type="datetime"
6
6
  :size="size"
@@ -9,7 +9,7 @@
9
9
  :format="config.format || 'YYYY/MM/DD HH:mm:ss'"
10
10
  :value-format="config.valueFormat || 'YYYY/MM/DD HH:mm:ss'"
11
11
  :default-time="config.defaultTime"
12
- @change="changeHandler"
12
+ @update:model-value="changeHandler"
13
13
  ></TMagicDatePicker>
14
14
  </template>
15
15
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <TMagicDatePicker
3
- v-model="value"
3
+ :model-value="value"
4
4
  type="datetimerange"
5
5
  range-separator="-"
6
6
  start-placeholder="开始日期"
@@ -12,7 +12,7 @@
12
12
  :value-format="config.valueFormat || 'YYYY/MM/DD HH:mm:ss'"
13
13
  :date-format="config.dateFormat || 'YYYY/MM/DD'"
14
14
  :time-format="config.timeFormat || 'HH:mm:ss'"
15
- @change="changeHandler"
15
+ @update:model-value="changeHandler"
16
16
  ></TMagicDatePicker>
17
17
  </template>
18
18
 
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <TMagicInputNumber
3
3
  v-if="model"
4
- v-model="model[name]"
4
+ :model-value="model[name]"
5
5
  clearable
6
6
  controls-position="right"
7
7
  :size="size"
@@ -10,7 +10,7 @@
10
10
  :step="config.step"
11
11
  :placeholder="config.placeholder"
12
12
  :disabled="disabled"
13
- @change="changeHandler"
13
+ @update:model-value="changeHandler"
14
14
  @input="inputHandler"
15
15
  ></TMagicInputNumber>
16
16
  </template>
@@ -1,19 +1,19 @@
1
1
  <template>
2
2
  <div class="m-fields-number-range">
3
3
  <TMagicInput
4
- v-model="model[name][0]"
5
- clearable
4
+ :model-value="model[name][0]"
5
+ :clearable="config.clearable ?? true"
6
6
  :size="size"
7
7
  :disabled="disabled"
8
- @change="minChangeHandler"
8
+ @update:model-value="minChangeHandler"
9
9
  ></TMagicInput>
10
10
  <span class="split-tag">-</span>
11
11
  <TMagicInput
12
- v-model="model[name][1]"
13
- clearable
12
+ :model-value="model[name][1]"
13
+ :clearable="config.clearable ?? true"
14
14
  :size="size"
15
15
  :disabled="disabled"
16
- @change="maxChangeHandler"
16
+ @update:model-value="maxChangeHandler"
17
17
  ></TMagicInput>
18
18
  </div>
19
19
  </template>
@@ -1,22 +1,18 @@
1
1
  <template>
2
- <TMagicRadioGroup v-if="model" v-model="model[name]" :size="size" :disabled="disabled">
2
+ <TMagicRadioGroup v-if="model" :model-value="model[name]" :size="size" :disabled="disabled">
3
3
  <component
4
- :is="itemComponent"
5
4
  v-for="option in config.options"
5
+ :is="itemComponent"
6
6
  :value="option.value"
7
7
  :key="`${option.value}`"
8
- @click.prevent="clickHandler(option.value)"
8
+ @click="clickHandler(option.value)"
9
9
  >
10
- <TMagicTooltip v-if="option.tooltip" placement="top-start" :content="option.tooltip">
10
+ <TMagicTooltip :disabled="!Boolean(option.tooltip)" placement="top-start" :content="option.tooltip">
11
11
  <div>
12
- <TMagicIcon v-if="option.icon" :size="'16'"><component :is="option.icon"></component></TMagicIcon>
12
+ <TMagicIcon v-if="option.icon" :size="iconSize"><component :is="option.icon"></component></TMagicIcon>
13
13
  <span>{{ option.text }}</span>
14
14
  </div>
15
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
16
  </component>
21
17
  </TMagicRadioGroup>
22
18
  </template>
@@ -39,14 +35,20 @@ const itemComponent = computed(() => (props.config.childType === 'button' ? TMag
39
35
 
40
36
  const emit = defineEmits(['change']);
41
37
 
42
- const changeHandler = (value: number) => {
43
- emit('change', value);
44
- };
45
-
46
- const clickHandler = (item: any) => {
47
- props.model[props.name] = props.model[props.name] === item ? '' : item;
48
- changeHandler(props.model[props.name]);
38
+ const clickHandler = (item: string | number | boolean) => {
39
+ // 再次点击取消选中
40
+ emit('change', props.model[props.name] === item ? '' : item);
49
41
  };
50
42
 
51
43
  useAddField(props.prop);
44
+
45
+ const iconSize = computed(() => {
46
+ if (props.size === 'small') {
47
+ return '12';
48
+ }
49
+ if (props.size === 'large') {
50
+ return '16';
51
+ }
52
+ return '14';
53
+ });
52
54
  </script>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <TMagicSelect
3
3
  v-if="model"
4
- v-model="model[name]"
4
+ :model-value="model[name]"
5
5
  v-loading="loading"
6
6
  class="m-select"
7
7
  ref="tMagicSelect"
@@ -16,7 +16,7 @@
16
16
  :allow-create="config.allowCreate"
17
17
  :disabled="disabled"
18
18
  :remote-method="config.remote && remoteMethod"
19
- @change="changeHandler"
19
+ @update:model-value="changeHandler"
20
20
  @visible-change="visibleHandler"
21
21
  >
22
22
  <template v-if="config.group">
@@ -1,11 +1,11 @@
1
1
  <template>
2
2
  <TMagicSwitch
3
- v-model="model[name]"
3
+ :model-value="model[name]"
4
4
  :size="size"
5
5
  :activeValue="activeValue"
6
6
  :inactiveValue="inactiveValue"
7
7
  :disabled="disabled"
8
- @change="changeHandler"
8
+ @update:model-value="changeHandler"
9
9
  ></TMagicSwitch>
10
10
  </template>
11
11
 
@@ -1,16 +1,19 @@
1
1
  <template>
2
- <div style="width: 100%">
2
+ <div class="m-fields-text">
3
3
  <TMagicInput
4
- v-model="model[name]"
4
+ :model-value="model[name]"
5
5
  ref="input"
6
6
  clearable
7
7
  :size="size"
8
8
  :placeholder="config.placeholder"
9
9
  :disabled="disabled"
10
- @change="changeHandler"
10
+ @update:model-value="changeHandler"
11
11
  @input="inputHandler"
12
12
  @keyup="keyUpHandler($event)"
13
13
  >
14
+ <template #prepend v-if="config.prepend">
15
+ <span>{{ config.prepend }}</span>
16
+ </template>
14
17
  <template #append v-if="appendConfig">
15
18
  <TMagicButton
16
19
  v-if="appendConfig.type === 'button'"
@@ -20,6 +23,7 @@
20
23
  >
21
24
  {{ appendConfig.text }}
22
25
  </TMagicButton>
26
+ <span v-else>{{ appendConfig.text }}</span>
23
27
  </template>
24
28
  </TMagicInput>
25
29
 
@@ -66,18 +70,26 @@ const mForm = inject<FormState | undefined>('mForm');
66
70
  const appendConfig = computed(() => {
67
71
  if (typeof props.config.append === 'string') {
68
72
  return {
73
+ type: 'text',
69
74
  text: props.config.append,
70
- type: 'button',
71
75
  handler: undefined,
72
76
  };
73
77
  }
74
-
75
- if (props.config.append && typeof props.config.append === 'object') {
76
- if (props.config.append.value === 0) {
77
- return false;
78
+ if (typeof props.config.append === 'object') {
79
+ if (typeof props.config.append?.handler === 'function') {
80
+ return {
81
+ type: 'button',
82
+ text: props.config.append.text,
83
+ handler: props.config.append.handler,
84
+ };
78
85
  }
86
+ if (props.config.append) {
87
+ if (props.config.append.value === 0) {
88
+ return false;
89
+ }
79
90
 
80
- return props.config.append;
91
+ return props.config.append;
92
+ }
81
93
  }
82
94
 
83
95
  return false;
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <TMagicInput
3
- v-model="model[name]"
3
+ :model-value="model[name]"
4
4
  type="textarea"
5
5
  :size="size"
6
6
  clearable
7
7
  :placeholder="config.placeholder"
8
8
  :disabled="disabled"
9
- @change="changeHandler"
9
+ @update:model-value="changeHandler"
10
10
  @input="inputHandler"
11
11
  >
12
12
  </TMagicInput>
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <TMagicTimePicker
3
- v-model="model[name]"
3
+ :model-value="model[name]"
4
4
  :value-format="config.valueFormat || 'HH:mm:ss'"
5
5
  :format="config.format || 'HH:mm:ss'"
6
6
  :size="size"
7
7
  :placeholder="config.placeholder"
8
8
  :disabled="disabled"
9
- @change="changeHandler"
9
+ @update:model-value="changeHandler"
10
10
  ></TMagicTimePicker>
11
11
  </template>
12
12
 
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <TMagicTimePicker
3
- v-model="value"
3
+ :model-value="value"
4
4
  is-range
5
5
  range-separator="-"
6
6
  start-placeholder="开始时间"
@@ -9,7 +9,7 @@
9
9
  :unlink-panels="true"
10
10
  :disabled="disabled"
11
11
  :default-time="config.defaultTime"
12
- @change="changeHandler"
12
+ @update:model-value="changeHandler"
13
13
  ></TMagicTimePicker>
14
14
  </template>
15
15
 
package/src/index.ts CHANGED
@@ -20,11 +20,11 @@ import type { App } from 'vue';
20
20
 
21
21
  import Container from './containers/Container.vue';
22
22
  import Fieldset from './containers/Fieldset.vue';
23
+ import FlexLayout from './containers/FlexLayout.vue';
23
24
  import GroupList from './containers/GroupList.vue';
24
25
  import Panel from './containers/Panel.vue';
25
26
  import Row from './containers/Row.vue';
26
27
  import MStep from './containers/Step.vue';
27
- import Table from './containers/Table.vue';
28
28
  import Tabs from './containers/Tabs.vue';
29
29
  import Cascader from './fields/Cascader.vue';
30
30
  import Checkbox from './fields/Checkbox.vue';
@@ -46,6 +46,7 @@ import Text from './fields/Text.vue';
46
46
  import Textarea from './fields/Textarea.vue';
47
47
  import Time from './fields/Time.vue';
48
48
  import Timerange from './fields/Timerange.vue';
49
+ import Table from './table/Table.vue';
49
50
  import { setConfig } from './utils/config';
50
51
  import Form from './Form.vue';
51
52
  import FormDialog from './FormDialog.vue';
@@ -63,10 +64,11 @@ export { default as MFormDrawer } from './FormDrawer.vue';
63
64
  export { default as MFormBox } from './FormBox.vue';
64
65
  export { default as MContainer } from './containers/Container.vue';
65
66
  export { default as MFieldset } from './containers/Fieldset.vue';
67
+ export { default as MFlexLayout } from './containers/FlexLayout.vue';
66
68
  export { default as MPanel } from './containers/Panel.vue';
67
69
  export { default as MRow } from './containers/Row.vue';
68
70
  export { default as MTabs } from './containers/Tabs.vue';
69
- export { default as MTable } from './containers/Table.vue';
71
+ export { default as MTable } from './table/Table.vue';
70
72
  export { default as MGroupList } from './containers/GroupList.vue';
71
73
  export { default as MText } from './fields/Text.vue';
72
74
  export { default as MNumber } from './fields/Number.vue';
@@ -114,6 +116,7 @@ export default {
114
116
  app.component('m-form-step', MStep);
115
117
  app.component('m-form-table', Table);
116
118
  app.component('m-form-tab', Tabs);
119
+ app.component('m-form-flex-layout', FlexLayout);
117
120
  app.component('m-fields-text', Text);
118
121
  app.component('m-fields-img-upload', Text);
119
122
  app.component('m-fields-number', Number);
@@ -0,0 +1,97 @@
1
+ <template>
2
+ <slot name="operateCol" :scope="{ $index: index, row: row }"></slot>
3
+ <TMagicButton
4
+ v-show="showDelete(index + 1 + currentPage * pageSize - 1)"
5
+ size="small"
6
+ type="danger"
7
+ link
8
+ title="删除"
9
+ :icon="Delete"
10
+ @click="removeHandler(index + 1 + currentPage * pageSize - 1)"
11
+ ></TMagicButton>
12
+
13
+ <TMagicButton
14
+ v-if="copyable(index + 1 + currentPage * pageSize - 1)"
15
+ link
16
+ size="small"
17
+ type="primary"
18
+ title="复制"
19
+ :icon="DocumentCopy"
20
+ :disabled="disabled"
21
+ @click="copyHandler(index + 1 + currentPage * pageSize - 1)"
22
+ ></TMagicButton>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { inject } from 'vue';
27
+ import { Delete, DocumentCopy } from '@element-plus/icons-vue';
28
+ import { cloneDeep } from 'lodash-es';
29
+
30
+ import { TMagicButton } from '@tmagic/design';
31
+
32
+ import type { FormState, TableConfig } from '../schema';
33
+
34
+ const emit = defineEmits(['change']);
35
+
36
+ const props = defineProps<{
37
+ config: TableConfig;
38
+ model: any;
39
+ name: string | number;
40
+ disabled?: boolean;
41
+ currentPage: number;
42
+ pageSize: number;
43
+ index: number;
44
+ row: any;
45
+ prop?: string;
46
+ sortKey?: string;
47
+ }>();
48
+
49
+ const mForm = inject<FormState | undefined>('mForm');
50
+
51
+ const removeHandler = (index: number) => {
52
+ if (props.disabled) return;
53
+ emit('change', props.model[props.name].toSpliced(index, 1));
54
+ };
55
+
56
+ const copyHandler = (index: number) => {
57
+ const inputs = cloneDeep(props.model[props.name][index]);
58
+ const { length } = props.model[props.name];
59
+ if (props.sortKey && length) {
60
+ inputs[props.sortKey] = props.model[props.name][length - 1][props.sortKey] - 1;
61
+ }
62
+
63
+ emit('change', [...props.model[props.name], inputs], {
64
+ changeRecords: [
65
+ {
66
+ propPath: `${props.prop}.${props.model[props.name].length}`,
67
+ value: inputs,
68
+ },
69
+ ],
70
+ });
71
+ };
72
+
73
+ // 希望支持单行可控制是否显示删除按钮,不会影响现有逻辑
74
+ const showDelete = (index: number) => {
75
+ const deleteFunc = props.config.delete;
76
+ if (deleteFunc && typeof deleteFunc === 'function') {
77
+ return deleteFunc(props.model[props.name], index, mForm?.values);
78
+ }
79
+ return props.config.delete ?? true;
80
+ };
81
+
82
+ const copyable = (index: number) => {
83
+ const copyableFunc = props.config.copyable;
84
+ if (copyableFunc && typeof copyableFunc === 'function') {
85
+ return copyableFunc(mForm, {
86
+ values: mForm?.initValues || {},
87
+ model: props.model,
88
+ parent: mForm?.parentValues || {},
89
+ formValue: mForm?.values || props.model,
90
+ prop: props.prop,
91
+ config: props.config,
92
+ index,
93
+ });
94
+ }
95
+ return props.config.copyable ?? true;
96
+ };
97
+ </script>
@@ -0,0 +1,101 @@
1
+ <template>
2
+ <TMagicTooltip v-if="index + 1 + currentPage * pageSize - 1 !== 0" content="点击上移,双击置顶" placement="top">
3
+ <TMagicButton
4
+ plain
5
+ size="small"
6
+ type="primary"
7
+ :icon="ArrowUp"
8
+ :disabled="disabled"
9
+ link
10
+ @click="upHandler(index + 1 + currentPage * pageSize - 1)"
11
+ @dblclick="topHandler(index + 1 + currentPage * pageSize - 1)"
12
+ ></TMagicButton>
13
+ </TMagicTooltip>
14
+ <TMagicTooltip
15
+ v-if="index + 1 + currentPage * pageSize - 1 !== model[name].length - 1"
16
+ content="点击下移,双击置底"
17
+ placement="top"
18
+ >
19
+ <TMagicButton
20
+ plain
21
+ size="small"
22
+ type="primary"
23
+ :icon="ArrowDown"
24
+ :disabled="disabled"
25
+ link
26
+ @click="downHandler(index + 1 + currentPage * pageSize - 1)"
27
+ @dblclick="bottomHandler(index + 1 + currentPage * pageSize - 1)"
28
+ ></TMagicButton>
29
+ </TMagicTooltip>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
34
+
35
+ import { TMagicButton, TMagicTooltip } from '@tmagic/design';
36
+
37
+ const props = defineProps<{
38
+ index: number;
39
+ disabled?: boolean;
40
+ currentPage: number;
41
+ pageSize: number;
42
+ name: string | number;
43
+ model: any;
44
+ }>();
45
+
46
+ const emit = defineEmits(['swap']);
47
+
48
+ let timer: ReturnType<typeof setTimeout> | null = null;
49
+
50
+ const upHandler = (index: number) => {
51
+ if (timer) {
52
+ clearTimeout(timer);
53
+ }
54
+
55
+ timer = setTimeout(() => {
56
+ emit('swap', index, index - 1);
57
+ timer = null;
58
+ }, 300);
59
+ };
60
+
61
+ const topHandler = (index: number) => {
62
+ if (timer) {
63
+ clearTimeout(timer);
64
+ }
65
+
66
+ // 首先判断当前元素需要上移几个位置,置底移动到数组的第一位
67
+ const moveNum = index;
68
+
69
+ // 循环出需要一个一个上移的次数
70
+ for (let i = 0; i < moveNum; i++) {
71
+ emit('swap', index, index - 1);
72
+ index -= 1;
73
+ }
74
+ };
75
+
76
+ const downHandler = (index: number) => {
77
+ if (timer) {
78
+ clearTimeout(timer);
79
+ }
80
+
81
+ timer = setTimeout(() => {
82
+ emit('swap', index, index + 1);
83
+ timer = null;
84
+ }, 300);
85
+ };
86
+
87
+ const bottomHandler = (index: number) => {
88
+ if (timer) {
89
+ clearTimeout(timer);
90
+ }
91
+
92
+ // 首先判断当前元素需要上移几个位置,置底移动到数组的第一位
93
+ const moveNum = props.model[props.name].length - 1 - index;
94
+
95
+ // 循环出需要一个一个上移的次数
96
+ for (let i = 0; i < moveNum; i++) {
97
+ emit('swap', index, index + 1);
98
+ index += 1;
99
+ }
100
+ };
101
+ </script>