data-form.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <script setup lang="ts">
  2. import WdButton from 'wot-design-uni/components/wd-button/wd-button.vue'
  3. import WdInput from 'wot-design-uni/components/wd-input/wd-input.vue'
  4. import WdPicker from 'wot-design-uni/components/wd-picker/wd-picker.vue'
  5. import { ref } from 'vue'
  6. const modelValue = defineModel({
  7. type: Object,
  8. default: () => ({}),
  9. })
  10. defineProps({
  11. schema: {
  12. type: Object as PropType<{
  13. [key: string | symbol]: { type: 'TextField' | 'Submit' | string; label?: string; props?: any }
  14. }>,
  15. required: true,
  16. default: () => ({}),
  17. },
  18. direction: {
  19. type: String as PropType<'horizontal' | 'vertical'>,
  20. default: 'vertical',
  21. },
  22. })
  23. const emits = defineEmits(['submit'])
  24. const form = ref()
  25. const types = {
  26. TextField: WdInput,
  27. Submit: WdButton,
  28. Select: WdPicker,
  29. // Radio: WdRadioGroup,
  30. }
  31. const defaultProps = {
  32. TextField: {
  33. noBorder: true,
  34. style: {},
  35. customClass: 'rounded border border-[#e1e1e1] border-solid p-1',
  36. placeholder: ' ',
  37. },
  38. Submit: {
  39. customClass: 'w-full! rounded-lg! my-4!',
  40. block: true,
  41. },
  42. }
  43. const verticalDefaultProps = {
  44. TextField: {
  45. noBorder: true,
  46. style: {},
  47. customClass: 'rounded border border-[#e1e1e1] border-solid p-1',
  48. placeholder: ' ',
  49. },
  50. Submit: {
  51. customClass: 'w-full! rounded-lg! my-4!',
  52. block: true,
  53. },
  54. }
  55. const submit = () => {
  56. emits('submit', modelValue)
  57. }
  58. const validate = (): Promise<{ valid: boolean; errors: any[] }> => form.value?.validate()
  59. defineExpose({
  60. validate,
  61. })
  62. </script>
  63. <template>
  64. <wd-form ref="form" :model="modelValue">
  65. <template
  66. v-for="([prop, { type, label, props }], index) in Object.entries(schema)"
  67. :key="index"
  68. >
  69. <div class="grid mb-4">
  70. <label
  71. v-if="type !== 'Submit' && direction === 'vertical'"
  72. class="text-black/40 text-sm font-normal font-['PingFang SC'] leading-relaxed mb-1"
  73. :for="prop"
  74. >
  75. {{ label || prop }}
  76. </label>
  77. <!-- #ifdef H5 -->
  78. <component :is="types[type]" :name="prop" v-bind="defaultProps[type]">
  79. <span v-if="type === 'Submit'">提交</span>
  80. </component>
  81. <!-- #endif -->
  82. <!-- #ifdef MP-WEIXIN -->
  83. <wd-input
  84. v-if="type === 'TextField'"
  85. v-bind="{
  86. ...(direction === 'vertical' ? verticalDefaultProps[type] : {}),
  87. ...props,
  88. }"
  89. v-model="modelValue[prop]"
  90. ></wd-input>
  91. <wd-picker
  92. v-if="type === 'Select'"
  93. v-bind="{ label, ...props }"
  94. v-model="modelValue[prop]"
  95. ></wd-picker>
  96. <wd-radio-group
  97. v-if="type === 'Radio'"
  98. v-bind="{ label, ...props, cell: true, shape: 'button' }"
  99. v-model="modelValue[prop]"
  100. >
  101. <template v-for="{ label, value } of props.columns" :key="value">
  102. <wd-radio :value="value">{{ label }}</wd-radio>
  103. </template>
  104. </wd-radio-group>
  105. <wd-button
  106. v-if="type === 'Submit'"
  107. v-bind="{
  108. ...(direction === 'vertical' ? verticalDefaultProps[type] : {}),
  109. ...props,
  110. formType: 'submit',
  111. }"
  112. @click="submit"
  113. >
  114. <span v-if="type === 'Submit'">提交</span>
  115. </wd-button>
  116. <!-- #endif -->
  117. </div>
  118. </template>
  119. </wd-form>
  120. </template>