DynamicForm.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <template>
  2. <Form
  3. ref="formRef"
  4. v-bind="formProps"
  5. :model="formModel"
  6. :rules="formRules"
  7. >
  8. <DynamicFormCate
  9. v-if="formModel"
  10. :formModel="formModel"
  11. :formDefine="formDefine"
  12. :formDefineParentKey="''"
  13. :formDefineParentLabel="''"
  14. />
  15. </Form>
  16. </template>
  17. <script setup lang="ts">
  18. import { computed, onMounted, provide, reactive, ref, toRef, watch, type PropType } from 'vue';
  19. import { waitTimeOut } from '@imengyu/imengyu-utils';
  20. import DynamicFormCate from './DynamicFormCate.vue';
  21. import Form, { type FormProps } from '../form/Form.vue';
  22. import type { FormDefine, FormDefineItem, FormExport } from '.';
  23. import type { Rules } from 'async-validator';
  24. const props = defineProps({
  25. formDefine: {
  26. type: Object as PropType<FormDefine>,
  27. default: () => ({})
  28. },
  29. formProps: {
  30. type: Object as PropType<Omit<FormProps, 'model' | 'rules'>>,
  31. default: () => ({})
  32. },
  33. formGlobalParams: {
  34. type: Object,
  35. default: () => ({})
  36. },
  37. });
  38. const formRef = ref<any>();
  39. const formModel = ref<any>(null);
  40. const formRules = computed(() => {
  41. const rules: Rules = {};
  42. function loop(prevKey: string, arr: FormDefineItem[]) {
  43. if (!arr || !(arr instanceof Array))
  44. return;
  45. for (const item of arr) {
  46. const key = prevKey ? `${prevKey}.${item.name}` : item.name;
  47. if (key && item.rules)
  48. rules[key] = item.rules;
  49. if (item.children) {
  50. loop(
  51. item.children.propNestType === 'flat' ? key : prevKey,
  52. item.children.items
  53. );
  54. }
  55. }
  56. }
  57. loop('', props.formDefine.items);
  58. return rules;
  59. });
  60. const formGlobalParams = toRef(props.formGlobalParams);
  61. provide('formTopModel', formModel);
  62. provide('formGlobalParams', formGlobalParams);
  63. watch(() => props.formDefine, (v) => {
  64. reloadFormData();
  65. });
  66. let isErrorState = false;
  67. let initCb : () => any = () => {
  68. return {};
  69. };
  70. function initFormData(data: () => any) {
  71. initCb = data;
  72. }
  73. function loadFormData(value?: Record<string, any>) {
  74. const obj = reactive(initCb());
  75. function loop(prevKey: string, arr: FormDefineItem[]) {
  76. if (!arr || !(arr instanceof Array))
  77. return;
  78. for (let index = 0; index < arr.length; index++) {
  79. const item = arr[index];
  80. const key = prevKey ? `${prevKey}.${item.name}` : item.name;
  81. if (key) {
  82. const valueProvided = value?.[key] ;
  83. obj[key] = valueProvided == null || valueProvided == undefined ?
  84. (typeof item.defaultValue === 'function' ? item.defaultValue() : item.defaultValue)
  85. : valueProvided ?? null;
  86. item.fullName = key;
  87. } else {
  88. item.fullName = '';
  89. }
  90. if (item.children)
  91. loop(
  92. item.children.propNestType === 'flat' ? key : prevKey,
  93. item.children.items
  94. );
  95. }
  96. }
  97. loop('', props.formDefine.items);
  98. formModel.value = obj;
  99. }
  100. async function submitForm<T = Record<string, any>>() : Promise<T|null> {
  101. await formRef.value.clearValidate();
  102. await waitTimeOut(50);
  103. try {
  104. await formRef.value.validate();
  105. } catch (e) {
  106. if (isErrorState)
  107. uni.showToast({
  108. title: '表单中有未填写项,请检查',
  109. icon: 'none'
  110. });
  111. console.log(e);
  112. isErrorState = true;
  113. return null;
  114. }
  115. isErrorState = false;
  116. return formModel.value;
  117. }
  118. function resetForm() {
  119. loadFormData();
  120. }
  121. function reloadFormData() {
  122. if (!formModel.value)
  123. loadFormData();
  124. }
  125. onMounted(() => {
  126. setTimeout(() => reloadFormData(), 300);
  127. });
  128. defineExpose<FormExport>({
  129. getFormRef: () => formRef.value,
  130. getFormData: () => formModel.value,
  131. initFormData,
  132. loadFormData,
  133. submitForm,
  134. resetForm,
  135. })
  136. </script>