@veltra/desktop 1.1.35 → 1.2.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 (198) hide show
  1. package/dist/components/action/action-group.vue.d.ts +2 -2
  2. package/dist/components/action/action.vue.d.ts +1 -1
  3. package/dist/components/auto-complete/auto-complete.js +1 -0
  4. package/dist/components/auto-complete/auto-complete.js.map +1 -1
  5. package/dist/components/batch-edit/batch-edit-form.js +12 -5
  6. package/dist/components/batch-edit/batch-edit-form.js.map +1 -1
  7. package/dist/components/batch-edit/batch-edit.js +8 -3
  8. package/dist/components/batch-edit/batch-edit.js.map +1 -1
  9. package/dist/components/batch-edit/batch-edit.vue.d.ts +40 -35
  10. package/dist/components/batch-edit/di.js.map +1 -1
  11. package/dist/components/batch-edit/use-edit.js +41 -23
  12. package/dist/components/batch-edit/use-edit.js.map +1 -1
  13. package/dist/components/cascade/cascade.js +1 -0
  14. package/dist/components/cascade/cascade.js.map +1 -1
  15. package/dist/components/cascade/cascade.vue.d.ts +5 -5
  16. package/dist/components/checkbox/checkbox-button.js +1 -0
  17. package/dist/components/checkbox/checkbox-button.js.map +1 -1
  18. package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
  19. package/dist/components/checkbox/checkbox.js +1 -0
  20. package/dist/components/checkbox/checkbox.js.map +1 -1
  21. package/dist/components/checkbox-group/checkbox-group.js +1 -0
  22. package/dist/components/checkbox-group/checkbox-group.js.map +1 -1
  23. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  24. package/dist/components/code-editor/code-editor.js +1 -0
  25. package/dist/components/code-editor/code-editor.js.map +1 -1
  26. package/dist/components/condition-editor/core/evaluator.js +3 -3
  27. package/dist/components/condition-editor/core/evaluator.js.map +1 -1
  28. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  29. package/dist/components/date-picker/date-picker.js +1 -0
  30. package/dist/components/date-picker/date-picker.js.map +1 -1
  31. package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
  32. package/dist/components/date-range-picker/date-range-picker.js +2 -0
  33. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  34. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
  35. package/dist/components/dialog/use-maximum.js +7 -1
  36. package/dist/components/dialog/use-maximum.js.map +1 -1
  37. package/dist/components/empty/empty.vue.d.ts +1 -1
  38. package/dist/components/expression-editor/expression-editor.js +1 -0
  39. package/dist/components/expression-editor/expression-editor.js.map +1 -1
  40. package/dist/components/file-picker/file-picker.js +1 -0
  41. package/dist/components/file-picker/file-picker.js.map +1 -1
  42. package/dist/components/form/form.js.map +1 -1
  43. package/dist/components/form/form.vue.d.ts +11 -19
  44. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js +24 -26
  45. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
  46. package/dist/components/form/index.d.ts +0 -3
  47. package/dist/components/form/use-form-fields.js +88 -0
  48. package/dist/components/form/use-form-fields.js.map +1 -0
  49. package/dist/components/form/use-node-interceptor.js +19 -30
  50. package/dist/components/form/use-node-interceptor.js.map +1 -1
  51. package/dist/components/form-item/form-item.js.map +1 -1
  52. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js +44 -18
  53. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js.map +1 -1
  54. package/dist/components/form-item/helper.js +4 -1
  55. package/dist/components/form-item/helper.js.map +1 -1
  56. package/dist/components/form-item/validate.d.ts +26 -0
  57. package/dist/components/form-item/validate.js +97 -0
  58. package/dist/components/form-item/validate.js.map +1 -0
  59. package/dist/components/group-input/group-input.js +1 -0
  60. package/dist/components/group-input/group-input.js.map +1 -1
  61. package/dist/components/index.d.ts +0 -3
  62. package/dist/components/index.js +0 -7
  63. package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js +1 -0
  64. package/dist/components/input/input.vue_vue_type_script_setup_true_lang.js.map +1 -1
  65. package/dist/components/loading/style2.css +90 -159
  66. package/dist/components/multi-select/multi-select.js +1 -0
  67. package/dist/components/multi-select/multi-select.js.map +1 -1
  68. package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
  69. package/dist/components/multi-tree-select/multi-tree-select.js +1 -0
  70. package/dist/components/multi-tree-select/multi-tree-select.js.map +1 -1
  71. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +4 -4
  72. package/dist/components/number-input/number-input.js +1 -0
  73. package/dist/components/number-input/number-input.js.map +1 -1
  74. package/dist/components/number-range-input/number-range-input.js +1 -0
  75. package/dist/components/number-range-input/number-range-input.js.map +1 -1
  76. package/dist/components/palette/palette.js +1 -0
  77. package/dist/components/palette/palette.js.map +1 -1
  78. package/dist/components/password-input/password-input.js +1 -0
  79. package/dist/components/password-input/password-input.js.map +1 -1
  80. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  81. package/dist/components/radio/radio.js +1 -0
  82. package/dist/components/radio/radio.js.map +1 -1
  83. package/dist/components/radio-group/radio-group.js +1 -0
  84. package/dist/components/radio-group/radio-group.js.map +1 -1
  85. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  86. package/dist/components/rich-text-editor/rich-text-editor.js +3 -2
  87. package/dist/components/rich-text-editor/rich-text-editor.js.map +1 -1
  88. package/dist/components/rich-text-editor/toolbar.js +10 -7
  89. package/dist/components/rich-text-editor/toolbar.js.map +1 -1
  90. package/dist/components/select/select.js +6 -3
  91. package/dist/components/select/select.js.map +1 -1
  92. package/dist/components/select/select.vue.d.ts +2 -2
  93. package/dist/components/slider/slider.js +15 -2
  94. package/dist/components/slider/slider.js.map +1 -1
  95. package/dist/components/steps/steps.vue.d.ts +1 -1
  96. package/dist/components/switch/switch.js +1 -0
  97. package/dist/components/switch/switch.js.map +1 -1
  98. package/dist/components/table/style2.css +4 -7
  99. package/dist/components/textarea/textarea.js +1 -0
  100. package/dist/components/textarea/textarea.js.map +1 -1
  101. package/dist/components/tip/tip.vue.d.ts +1 -1
  102. package/dist/components/tree-select/tree-select.js +1 -0
  103. package/dist/components/tree-select/tree-select.js.map +1 -1
  104. package/dist/components/tree-select/tree-select.vue.d.ts +4 -4
  105. package/dist/components/watermark/watermark.vue.d.ts +1 -1
  106. package/dist/index.d.ts +5 -6
  107. package/dist/index.js +1 -4
  108. package/dist/types/auto-complete.d.ts +3 -2
  109. package/dist/types/batch-edit.d.ts +4 -5
  110. package/dist/types/cascade.d.ts +3 -2
  111. package/dist/types/checkbox-group.d.ts +2 -2
  112. package/dist/types/checkbox.d.ts +4 -3
  113. package/dist/types/code-editor.d.ts +3 -2
  114. package/dist/types/date-picker.d.ts +3 -2
  115. package/dist/types/date-range-picker.d.ts +3 -2
  116. package/dist/types/expression-editor.d.ts +3 -2
  117. package/dist/types/file-picker.d.ts +3 -2
  118. package/dist/types/form-field.d.ts +12 -0
  119. package/dist/types/form-item.d.ts +2 -2
  120. package/dist/types/form.d.ts +9 -48
  121. package/dist/types/group-input.d.ts +3 -2
  122. package/dist/types/index.d.ts +4 -2
  123. package/dist/types/input.d.ts +3 -2
  124. package/dist/types/loading.d.ts +1 -1
  125. package/dist/types/multi-select.d.ts +3 -2
  126. package/dist/types/multi-tree-select.d.ts +3 -2
  127. package/dist/types/palette.d.ts +3 -2
  128. package/dist/types/radio-group.d.ts +3 -2
  129. package/dist/types/radio.d.ts +3 -2
  130. package/dist/types/rich-text-editor.d.ts +3 -2
  131. package/dist/types/select.d.ts +3 -2
  132. package/dist/types/slider.d.ts +3 -2
  133. package/dist/types/switch.d.ts +3 -2
  134. package/dist/types/text-editor.d.ts +3 -2
  135. package/dist/types/textarea.d.ts +3 -2
  136. package/dist/types/tree-select.d.ts +3 -2
  137. package/package.json +6 -6
  138. package/src/components/batch-edit/batch-edit-form.vue +20 -13
  139. package/src/components/batch-edit/batch-edit.vue +7 -8
  140. package/src/components/batch-edit/di.ts +1 -2
  141. package/src/components/batch-edit/use-edit.ts +58 -36
  142. package/src/components/date-range-picker/date-range-picker.vue +2 -0
  143. package/src/components/dialog/use-maximum.ts +8 -1
  144. package/src/components/form/form.vue +22 -38
  145. package/src/components/form/index.ts +0 -6
  146. package/src/components/form/use-form-fields.ts +126 -0
  147. package/src/components/form/use-node-interceptor.ts +27 -56
  148. package/src/components/form-item/form-item.vue +69 -18
  149. package/src/components/form-item/helper.ts +10 -4
  150. package/src/components/form-item/validate.ts +155 -0
  151. package/src/components/loading/style.scss +126 -355
  152. package/src/components/rich-text-editor/rich-text-editor.vue +28 -25
  153. package/src/components/rich-text-editor/toolbar.vue +23 -19
  154. package/src/components/select/select.vue +6 -4
  155. package/src/components/slider/slider.vue +12 -2
  156. package/src/components/table/style.scss +4 -14
  157. package/src/types/auto-complete.ts +4 -2
  158. package/src/types/batch-edit.ts +4 -5
  159. package/src/types/cascade.ts +4 -2
  160. package/src/types/checkbox-group.ts +2 -2
  161. package/src/types/checkbox.ts +5 -3
  162. package/src/types/code-editor.ts +4 -2
  163. package/src/types/date-picker.ts +4 -2
  164. package/src/types/date-range-picker.ts +4 -2
  165. package/src/types/expression-editor.ts +4 -2
  166. package/src/types/file-picker.ts +4 -2
  167. package/src/types/form-field.ts +11 -0
  168. package/src/types/form-item.ts +2 -2
  169. package/src/types/form.ts +9 -82
  170. package/src/types/group-input.ts +4 -2
  171. package/src/types/index.ts +1 -0
  172. package/src/types/input.ts +4 -2
  173. package/src/types/loading.ts +1 -1
  174. package/src/types/multi-select.ts +4 -2
  175. package/src/types/multi-tree-select.ts +5 -2
  176. package/src/types/palette.ts +4 -2
  177. package/src/types/radio-group.ts +4 -2
  178. package/src/types/radio.ts +4 -2
  179. package/src/types/rich-text-editor.ts +4 -2
  180. package/src/types/select.ts +4 -2
  181. package/src/types/slider.ts +4 -2
  182. package/src/types/switch.ts +4 -2
  183. package/src/types/text-editor.ts +4 -2
  184. package/src/types/textarea.ts +4 -2
  185. package/src/types/tree-select.ts +5 -2
  186. package/dist/components/form/dynamic-form-model.d.ts +0 -73
  187. package/dist/components/form/dynamic-form-model.js +0 -184
  188. package/dist/components/form/dynamic-form-model.js.map +0 -1
  189. package/dist/components/form/form-model.d.ts +0 -73
  190. package/dist/components/form/form-model.js +0 -179
  191. package/dist/components/form/form-model.js.map +0 -1
  192. package/dist/components/form/helper.d.ts +0 -16
  193. package/dist/components/form/helper.js +0 -20
  194. package/dist/components/form/helper.js.map +0 -1
  195. package/src/components/form/__test__/form-model.test.ts +0 -190
  196. package/src/components/form/dynamic-form-model.ts +0 -258
  197. package/src/components/form/form-model.ts +0 -255
  198. package/src/components/form/helper.ts +0 -23
@@ -1,9 +1,10 @@
1
+ import { FormFieldComponentProps } from "./form-field.js";
1
2
  import { CSSProperties, ShallowRef } from "vue";
2
- import { DeconstructValue, FormComponentProps } from "@veltra/utils";
3
+ import { DeconstructValue } from "@veltra/utils";
3
4
 
4
5
  //#region src/types/select.d.ts
5
6
  /** 选择器组件属性 */
6
- interface SelectProps extends FormComponentProps {
7
+ interface SelectProps extends FormFieldComponentProps {
7
8
  /** 绑定值 */
8
9
  modelValue?: any;
9
10
  /** 文本内容 */
@@ -1,8 +1,9 @@
1
- import { DeconstructValue, FormComponentProps } from "@veltra/utils";
1
+ import { FormFieldComponentProps } from "./form-field.js";
2
+ import { DeconstructValue } from "@veltra/utils";
2
3
 
3
4
  //#region src/types/slider.d.ts
4
5
  /** 滑块组件属性 */
5
- interface SliderProps<T extends number | [number, number]> extends FormComponentProps {
6
+ interface SliderProps<T extends number | [number, number]> extends FormFieldComponentProps {
6
7
  modelValue?: T;
7
8
  /**
8
9
  * 最小值
@@ -1,8 +1,9 @@
1
- import { DeconstructValue, FormComponentProps } from "@veltra/utils";
1
+ import { FormFieldComponentProps } from "./form-field.js";
2
+ import { DeconstructValue } from "@veltra/utils";
2
3
 
3
4
  //#region src/types/switch.d.ts
4
5
  /** 开关组件属性 */
5
- interface SwitchProps extends FormComponentProps {
6
+ interface SwitchProps extends FormFieldComponentProps {
6
7
  /** 开关状态 */
7
8
  modelValue?: boolean;
8
9
  /** 打开时显示的文字 */
@@ -1,4 +1,5 @@
1
- import { DeconstructValue, FormComponentProps } from "@veltra/utils";
1
+ import { FormFieldComponentProps } from "./form-field.js";
2
+ import { DeconstructValue } from "@veltra/utils";
2
3
 
3
4
  //#region src/types/text-editor.d.ts
4
5
  /** text-editor组件属性 */
@@ -6,7 +7,7 @@ interface BarType {
6
7
  content: string;
7
8
  bar: string;
8
9
  }
9
- interface TextEditorProps extends FormComponentProps {
10
+ interface TextEditorProps extends FormFieldComponentProps {
10
11
  modelValue?: string;
11
12
  placeholder?: string;
12
13
  toolbar?: BarType[];
@@ -1,8 +1,9 @@
1
- import { DeconstructValue, FormComponentProps } from "@veltra/utils";
1
+ import { FormFieldComponentProps } from "./form-field.js";
2
+ import { DeconstructValue } from "@veltra/utils";
2
3
 
3
4
  //#region src/types/textarea.d.ts
4
5
  /** textarea组件属性 */
5
- interface TextareaProps extends FormComponentProps {
6
+ interface TextareaProps extends FormFieldComponentProps {
6
7
  /**
7
8
  * 文本域的值
8
9
  */
@@ -1,10 +1,11 @@
1
+ import { FormFieldComponentProps } from "./form-field.js";
1
2
  import { TreeProps } from "./tree.js";
2
3
  import { CSSProperties } from "vue";
3
- import { DeconstructValue, FormComponentProps } from "@veltra/utils";
4
+ import { DeconstructValue } from "@veltra/utils";
4
5
 
5
6
  //#region src/types/tree-select.d.ts
6
7
  /** 树形选择器组件属性 */
7
- interface TreeSelectProps extends FormComponentProps, Omit<TreeProps, 'selected' | 'checked' | 'selectable' | 'checkable'> {
8
+ interface TreeSelectProps extends FormFieldComponentProps, Omit<TreeProps, 'selected' | 'checked' | 'selectable' | 'checkable'> {
8
9
  modelValue?: string | number;
9
10
  /** 自定义占位文字 */
10
11
  placeholder?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veltra/desktop",
3
- "version": "1.1.35",
3
+ "version": "1.2.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -68,11 +68,11 @@
68
68
  "@cat-kit/core": ">=1.1.6",
69
69
  "@cat-kit/excel": ">=1.0.0",
70
70
  "@cat-kit/fe": "^1.1.6",
71
- "@veltra/compositions": "1.1.35",
72
- "@veltra/directives": "1.1.35",
73
- "@veltra/icons": "1.1.35",
74
- "@veltra/styles": "1.1.35",
75
- "@veltra/utils": "1.1.35",
71
+ "@veltra/compositions": "1.2.0",
72
+ "@veltra/directives": "1.2.0",
73
+ "@veltra/icons": "1.2.0",
74
+ "@veltra/styles": "1.2.0",
75
+ "@veltra/utils": "1.2.0",
76
76
  "vue": ">=3.5.0"
77
77
  }
78
78
  }
@@ -26,23 +26,20 @@
26
26
  <u-scroll always :class="cls.e('form-body')" :key="bodyKey">
27
27
  <transition name="fade" appear mode="out-in">
28
28
  <u-form
29
+ ref="formComponentRef"
29
30
  :model="props.model"
30
31
  :readonly="props.readonly"
31
32
  @keydown="handleFormKeydown"
32
33
  :label-width="props.labelWidth"
33
34
  >
34
- <template #default="{ data, model }">
35
- <slot
36
- v-bind="{
37
- data,
38
- model,
39
- row: state.row,
40
- depth: state.depth,
41
- indexes: insertIndexes,
42
- index: state.row?.index
43
- }"
44
- />
45
- </template>
35
+ <slot
36
+ v-bind="{
37
+ row: state.row,
38
+ depth: state.depth,
39
+ indexes: insertIndexes,
40
+ index: state.row?.index
41
+ }"
42
+ />
46
43
  </u-form>
47
44
  </transition>
48
45
  </u-scroll>
@@ -75,8 +72,9 @@
75
72
  <script lang="ts" setup>
76
73
  import { AddChild, Close, EditPen, Plus, View } from '@veltra/icons/normal'
77
74
  import { bem } from '@veltra/utils'
78
- import { computed, inject, type Component } from 'vue'
75
+ import { computed, inject, shallowRef, toRef, type Component } from 'vue'
79
76
 
77
+ import type { _FormExposed, FormExposed } from '../../types/form'
80
78
  import { UButton } from '../button'
81
79
  import { UForm } from '../form'
82
80
  import { UIcon } from '../icon'
@@ -97,6 +95,15 @@ const {
97
95
  dynamicFeatures
98
96
  } = inject(BatchEditDIKey)!
99
97
 
98
+ const formComponentRef = shallowRef<FormExposed>()
99
+
100
+ defineExpose<_FormExposed>({
101
+ el: toRef(() => formComponentRef.value?.el),
102
+ validate: () => formComponentRef.value?.validate() ?? Promise.resolve(true),
103
+ clearValidate: () => formComponentRef.value?.clearValidate(),
104
+ reset: () => formComponentRef.value?.reset()
105
+ })
106
+
100
107
  const creatable = computed(() => {
101
108
  return (
102
109
  state.type === 'create' &&
@@ -12,14 +12,14 @@
12
12
  <BatchEditList :slots="slots" />
13
13
 
14
14
  <!-- 编辑表单 -->
15
- <BatchEditForm v-slot="scoped">
15
+ <BatchEditForm ref="formRef" v-slot="scoped">
16
16
  <!-- @vue-ignore -->
17
17
  <slot name="form" v-bind="scoped" />
18
18
  </BatchEditForm>
19
19
  </u-layout>
20
20
  </template>
21
21
 
22
- <script lang="ts" setup generic="Model extends IFormModel">
22
+ <script lang="ts" setup>
23
23
  import { bem } from '@veltra/utils'
24
24
  import { computed, inject, provide, shallowRef, watch } from 'vue'
25
25
 
@@ -27,11 +27,11 @@ import type {
27
27
  BatchEditEmits,
28
28
  BatchEditFeature,
29
29
  BatchEditProps,
30
- IFormModel,
31
30
  TableColumnSlotsScope,
32
31
  TableExposed,
33
32
  TableRow
34
33
  } from '../../types'
34
+ import type { FormExposed } from '../../types/form'
35
35
  import { DialogDIKey } from '../dialog/di'
36
36
  import { ULayout } from '../layout'
37
37
  import BatchEditForm from './batch-edit-form.vue'
@@ -41,7 +41,7 @@ import { useEdit } from './use-edit'
41
41
 
42
42
  defineOptions({ name: 'BatchEdit' })
43
43
 
44
- const props = withDefaults(defineProps<BatchEditProps<Model>>(), {
44
+ const props = withDefaults(defineProps<BatchEditProps>(), {
45
45
  cols: () => ['1fr', '420px'],
46
46
  mode: 'normal'
47
47
  })
@@ -99,9 +99,7 @@ const slots = defineSlots<
99
99
  {
100
100
  form?: (props: {
101
101
  /** 表单数据 */
102
- data: Model['data']
103
- /** 表单模型 */
104
- model: Model
102
+ data: Record<string, any> | undefined
105
103
  /** 当前编辑的层级 */
106
104
  depth?: number
107
105
  /** 当前编辑的行 */
@@ -119,8 +117,9 @@ const slots = defineSlots<
119
117
  const cls = bem('batch-edit')
120
118
 
121
119
  const tableRef = shallowRef<TableExposed>()
120
+ const formRef = shallowRef<FormExposed>()
122
121
 
123
- const editCtx = useEdit({ props, emit, tableRef })
122
+ const editCtx = useEdit({ props, emit, tableRef, formRef })
124
123
 
125
124
  const { state, handleClose, handleSave, handleDelete, handleCreate } = editCtx
126
125
 
@@ -5,7 +5,6 @@ import type {
5
5
  BatchEditEmits,
6
6
  BatchEditFeature,
7
7
  BatchEditProps,
8
- IFormModel,
9
8
  TableExposed,
10
9
  TableRow
11
10
  } from '../../types'
@@ -13,7 +12,7 @@ import type { EditReturned } from './use-edit'
13
12
  export const BatchEditDIKey: InjectionKey<
14
13
  {
15
14
  cls: BEM<'batch-edit', 'u-'>
16
- props: BatchEditProps<IFormModel>
15
+ props: BatchEditProps
17
16
  emit: BatchEditEmits
18
17
  tableRef: ShallowRef<TableExposed | undefined>
19
18
  staticFeatures: ComputedRef<Set<BatchEditFeature>>
@@ -2,6 +2,7 @@ import { last, o, safeRun } from '@cat-kit/core'
2
2
  import { computed, nextTick, shallowReactive, shallowRef, watch, type ShallowRef } from 'vue'
3
3
 
4
4
  import type { TableRow, BatchEditEmits, BatchEditProps, TableExposed } from '../../types'
5
+ import type { FormExposed } from '../../types/form'
5
6
 
6
7
  /** 按索引路径在原始数据树中定位节点(等价于历史 Forest.visit 路径访问) */
7
8
  function visitDataByIndexPath<T extends Record<string, unknown>>(
@@ -29,6 +30,7 @@ interface Options {
29
30
  props: BatchEditProps
30
31
  emit: BatchEditEmits
31
32
  tableRef: ShallowRef<TableExposed | undefined>
33
+ formRef: ShallowRef<FormExposed | undefined>
32
34
  }
33
35
 
34
36
  export interface BatchEditStates {
@@ -58,8 +60,19 @@ export interface EditReturned {
58
60
  handleInsertChild: (row: TableRow) => void
59
61
  }
60
62
 
63
+ function snapshotData(data?: Record<string, any>) {
64
+ return safeRun(() => JSON.parse(JSON.stringify(data ?? {})), {})
65
+ }
66
+
67
+ function replaceModelData(model: Record<string, any>, data: Record<string, any>) {
68
+ for (const key of Object.keys(model)) {
69
+ delete model[key]
70
+ }
71
+ Object.assign(model, data)
72
+ }
73
+
61
74
  export function useEdit(options: Options): EditReturned {
62
- const { props, emit, tableRef } = options
75
+ const { props, emit, tableRef, formRef } = options
63
76
 
64
77
  /** 组件状态 */
65
78
  const state = shallowReactive<BatchEditStates>({
@@ -88,19 +101,39 @@ export function useEdit(options: Options): EditReturned {
88
101
  * 阶段把规范化后的值再写回模型时被误判为「用户已修改」
89
102
  */
90
103
  let baselineSnapshot: Record<string, any> | undefined
104
+ let emptySnapshot: Record<string, any> | undefined
91
105
 
92
106
  function snapshotModelData() {
93
- return safeRun(() => JSON.parse(JSON.stringify(props.model?.data ?? {})), {})
107
+ return snapshotData(props.model)
108
+ }
109
+
110
+ function resetFormData(data?: Record<string, any>) {
111
+ if (!props.model) return
112
+ replaceModelData(props.model, snapshotData(data ?? emptySnapshot))
113
+ formRef.value?.clearValidate()
114
+ }
115
+
116
+ function setFormData(formData: Record<string, any>) {
117
+ if (!props.model) return
118
+ replaceModelData(props.model, snapshotData(formData))
94
119
  }
95
120
 
121
+ watch(
122
+ () => props.model,
123
+ (model) => {
124
+ emptySnapshot = snapshotData(model)
125
+ },
126
+ { immediate: true }
127
+ )
128
+
96
129
  watch(
97
130
  () => state.row,
98
131
  (row) => {
99
- props.model?.resetData()
132
+ resetFormData()
100
133
  if (row) {
101
134
  state.type = 'update'
102
135
  state.visible = true
103
- props.model?.setData(row.data)
136
+ setFormData(row.data)
104
137
  } else {
105
138
  state.visible = false
106
139
  }
@@ -111,16 +144,14 @@ export function useEdit(options: Options): EditReturned {
111
144
  { flush: 'sync' }
112
145
  )
113
146
 
114
- const changeCb = (field: string, val: any) => {
115
- // 与基线比较 — 同值(如组件 mount 时把当前值再写一次)不算"用户修改"
116
- if (baselineSnapshot) {
117
- const baseVal = o(baselineSnapshot).get(field)
118
- if (isSameValue(baseVal, val)) {
119
- return
120
- }
121
- }
122
- state.dataUpdated = true
123
- }
147
+ watch(
148
+ () => props.model,
149
+ () => {
150
+ if (!baselineSnapshot || !state.visible) return
151
+ state.dataUpdated = !isSameValue(baselineSnapshot, snapshotModelData())
152
+ },
153
+ { deep: true }
154
+ )
124
155
 
125
156
  function isSameValue(a: any, b: any) {
126
157
  if (a === b) return true
@@ -136,19 +167,6 @@ export function useEdit(options: Options): EditReturned {
136
167
  return false
137
168
  }
138
169
 
139
- watch(
140
- () => props.model,
141
- (model, oldModel) => {
142
- if (oldModel) {
143
- oldModel.offChange(changeCb)
144
- }
145
- if (model) {
146
- model.onChange(changeCb)
147
- }
148
- },
149
- { immediate: true }
150
- )
151
-
152
170
  const childrenKey = computed(() => {
153
171
  return typeof props.tree === 'string' ? props.tree : 'children'
154
172
  })
@@ -183,7 +201,7 @@ export function useEdit(options: Options): EditReturned {
183
201
  }
184
202
 
185
203
  function getInsertData(): Record<string, any> {
186
- return safeRun(() => JSON.parse(JSON.stringify(props.model?.data ?? {})), {})
204
+ return snapshotModelData()
187
205
  }
188
206
 
189
207
  async function runCreate(cb: () => void) {
@@ -193,7 +211,7 @@ export function useEdit(options: Options): EditReturned {
193
211
  }
194
212
  state.row = undefined
195
213
  state.type = 'create'
196
- props.model?.resetData()
214
+ resetFormData()
197
215
  cb()
198
216
 
199
217
  let item: Record<string, any> | undefined = undefined
@@ -201,6 +219,8 @@ export function useEdit(options: Options): EditReturned {
201
219
  await nextTick()
202
220
 
203
221
  state.visible = true
222
+ baselineSnapshot = snapshotModelData()
223
+ state.dataUpdated = false
204
224
 
205
225
  if (item) {
206
226
  const row = tableRef.value?.getRowByData(item)
@@ -256,8 +276,9 @@ export function useEdit(options: Options): EditReturned {
256
276
  runCreate(() => {
257
277
  state.depth = row.depth
258
278
  insertIndexes.value = [...row.indexes.slice(0, -1), row.index + 1]
259
- const cloned = safeRun(() => JSON.parse(JSON.stringify(row.data ?? {})), {})
260
- props.model?.setData(cloned)
279
+ setFormData(row.data)
280
+ baselineSnapshot = snapshotModelData()
281
+ state.dataUpdated = false
261
282
  })
262
283
  }
263
284
 
@@ -285,8 +306,8 @@ export function useEdit(options: Options): EditReturned {
285
306
 
286
307
  if (!model) return
287
308
 
288
- model.clearValidate()
289
- const valid = await model.validate()
309
+ formRef.value?.clearValidate()
310
+ const valid = await formRef.value?.validate()
290
311
 
291
312
  if (!valid) return
292
313
 
@@ -304,13 +325,14 @@ export function useEdit(options: Options): EditReturned {
304
325
  if (state.type === 'create') {
305
326
  insert(item)
306
327
 
307
- return model?.resetData()
328
+ resetFormData()
329
+ return
308
330
  }
309
331
  // 更新
310
332
  if (state.type === 'update') {
311
333
  const { row } = state
312
334
  row &&
313
- model.allKeys.forEach((key) => {
335
+ Object.keys(item).forEach((key) => {
314
336
  o(row.data).set(key, o(item).get(key))
315
337
  })
316
338
  }
@@ -354,7 +376,7 @@ export function useEdit(options: Options): EditReturned {
354
376
  state.row = undefined
355
377
  state.parentRow = undefined
356
378
  state.depth = undefined
357
- props.model?.resetData()
379
+ resetFormData()
358
380
  insertIndexes.value = []
359
381
  }
360
382
 
@@ -127,6 +127,8 @@ watch(
127
127
  if (isUserActive()) return
128
128
  if (val?.length === 2) {
129
129
  currentRangeDate.value = [date(val[0]), date(val[1])]
130
+ } else {
131
+ currentRangeDate.value = undefined
130
132
  }
131
133
  },
132
134
  { immediate: true }
@@ -24,11 +24,15 @@ export function useMaximum(options: Options): Returned {
24
24
 
25
25
  const maximized = shallowRef(false)
26
26
 
27
+ let needRmoveHeight = false
28
+
27
29
  const maximizeTransition = useTransition('css', {
28
30
  target: dialogRef,
29
31
  name: 'dialog-maximize',
30
32
  keepEnterTo: true,
31
33
  afterLeave() {
34
+ if (!maximized.value || !needRmoveHeight) return
35
+ needRmoveHeight = false
32
36
  dialogRef.value && removeStyles(dialogRef.value, ['height'])
33
37
  }
34
38
  })
@@ -40,7 +44,10 @@ export function useMaximum(options: Options): Returned {
40
44
  if (!dom) return
41
45
  if (maxim) {
42
46
  // 先设置一个高度才会有过渡动画
43
- setStyles(dom, { height: `${dom.offsetHeight}px` })
47
+ if (!dom.style.height) {
48
+ needRmoveHeight = true
49
+ setStyles(dom, { height: `${dom.offsetHeight}px` })
50
+ }
44
51
  maximizeTransition.enter()
45
52
  } else {
46
53
  maximizeTransition.leave()
@@ -10,26 +10,20 @@
10
10
  v-for="{ node, isFormItem, formItemProps, field, modelValue } of getSlotsNodes()"
11
11
  :key="node.key"
12
12
  >
13
- <component v-if="isFormItem || !field" :is="node" />
14
-
15
- <u-form-item v-else v-bind="formItemProps">
13
+ <u-form-item v-if="!isFormItem && field" v-bind="formItemProps">
16
14
  <component
17
15
  :is="node"
18
- :model-value="modelValue ?? o(model?.data ?? {}).get(field)"
16
+ :model-value="modelValue ?? o(model ?? {}).get(field)"
19
17
  @update:model-value="handleUpdateValue(field, $event)"
20
18
  />
21
-
22
- <div :class="cls.e('data-before')" v-if="showInitialNode(field)">
23
- <i :class="cls.e('changed-tag')">变更前:</i>
24
-
25
- <component :is="node" readonly :model-value="o(model?.initialData ?? {}).get(field)" />
26
- </div>
27
19
  </u-form-item>
20
+
21
+ <component v-else :is="node" />
28
22
  </template>
29
23
  </u-grid>
30
24
  </template>
31
25
 
32
- <script lang="tsx" setup generic="Model extends FormModel | DynamicFormModel">
26
+ <script lang="tsx" setup>
33
27
  import { o } from '@cat-kit/core'
34
28
  import { bem } from '@veltra/utils'
35
29
  import { provideFormContext } from '@veltra/utils'
@@ -38,48 +32,38 @@ import { shallowRef, toRef } from 'vue'
38
32
  import type { BreakCols, GridExposed, FormProps, _FormExposed } from '../../types'
39
33
  import { UFormItem } from '../form-item'
40
34
  import { UGrid } from '../grid'
41
- import type { DynamicFormModel } from './dynamic-form-model'
42
- import type { FormModel } from './form-model'
35
+ import { useFormFields } from './use-form-fields'
43
36
  import { useNodeInterceptor } from './use-node-interceptor'
44
37
 
45
38
  defineOptions({ name: 'Form' })
46
39
 
47
- const props = defineProps<FormProps<Model>>()
40
+ const props = defineProps<FormProps>()
48
41
 
49
- defineSlots<{
50
- default(props: {
51
- /** 表单数据 */
52
- data: Model['data']
53
- /** 表单模型 */
54
- model: Model
55
- }): any
56
- }>()
42
+ defineSlots<{ default(props?: { data: Record<string, any> | undefined }): any }>()
57
43
 
58
44
  const cls = bem('form')
59
45
 
60
46
  const breakpointCols: BreakCols = { xs: 1, md: 2, lg: 3, xl: 4, default: 4 }
61
47
 
62
- provideFormContext(props)
48
+ const { validate, clearValidate, reset, registerField, unregisterField, shouldValidate } =
49
+ useFormFields({ props })
63
50
 
64
- const { getSlotsNodes } = useNodeInterceptor({ props })
51
+ provideFormContext({
52
+ formProps: props,
53
+ registerField,
54
+ unregisterField,
55
+ validateFields: validate,
56
+ shouldValidate
57
+ })
65
58
 
66
- function handleUpdateValue(field: string, value: any) {
67
- const { model } = props
68
- if (!model) return
69
- o(model.data).set(field, value)
70
- }
71
-
72
- function showInitialNode(field: string) {
73
- const { data, initialData } = props.model || {}
59
+ const { getSlotsNodes } = useNodeInterceptor()
74
60
 
75
- const currentValue = o(data ?? {}).get(field)
76
- const initialValue = o(initialData ?? {}).get(field)
77
- const notEqual = !(initialValue === currentValue || (!initialValue && !currentValue))
78
-
79
- return props.showInitialData && notEqual
61
+ function handleUpdateValue(field: string, value: any) {
62
+ if (!props.model) return
63
+ o(props.model).set(field, value)
80
64
  }
81
65
 
82
66
  const gridRef = shallowRef<GridExposed>()
83
67
 
84
- defineExpose<_FormExposed>({ el: toRef(() => gridRef.value?.el) })
68
+ defineExpose<_FormExposed>({ el: toRef(() => gridRef.value?.el), validate, clearValidate, reset })
85
69
  </script>
@@ -1,7 +1 @@
1
1
  export { default as UForm } from './form.vue'
2
-
3
- export { formField, nestField } from './helper'
4
- export type { NestedFieldMarker } from './helper'
5
-
6
- export { FormModel } from './form-model'
7
- export { DynamicFormModel } from './dynamic-form-model'