data-form.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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 { ConfigProviderThemeVars } from 'wot-design-uni'
  6. import { DataFormProps, DataFormSchema } from './data-form'
  7. import { addUnit } from 'wot-design-uni/components/common/util'
  8. import { omit } from 'radash'
  9. const modelValue = defineModel({
  10. type: Object,
  11. default: () => ({}),
  12. })
  13. withDefaults(
  14. defineProps<{
  15. schema: DataFormSchema
  16. direction?: 'horizontal' | 'vertical'
  17. }>(),
  18. { direction: 'vertical', labelShow: true },
  19. )
  20. const emits = defineEmits(['submit'])
  21. const form = ref()
  22. const types = {
  23. TextField: WdInput,
  24. Submit: WdButton,
  25. Select: WdPicker,
  26. // Radio: WdRadioGroup,
  27. }
  28. const defaultProps = {
  29. TextField: {
  30. noBorder: true,
  31. style: {},
  32. customClass: 'rounded border border-[#e1e1e1] border-solid p-1',
  33. placeholder: ' ',
  34. },
  35. Submit: {
  36. customClass: 'w-full! rounded-lg! my-4!',
  37. block: true,
  38. },
  39. }
  40. const verticalDefaultProps = {
  41. TextField: {
  42. noBorder: true,
  43. style: {},
  44. customClass: 'rounded border border-[#e1e1e1] border-solid p-1',
  45. placeholder: ' ',
  46. },
  47. Submit: {
  48. customClass: 'w-full! rounded-lg! my-4!',
  49. block: true,
  50. },
  51. }
  52. const horizontalDefaultProps = {
  53. TextField: {
  54. customClass: 'text-red!',
  55. placeholderClass: 'text-black/30',
  56. },
  57. Select: {
  58. customClass: 'text-black/30! border-b-1 border-b-[#e1e1e1] border-b-solid',
  59. },
  60. Radio: {
  61. customClass: 'my--4!',
  62. },
  63. Checkbox: {
  64. customClass: 'my--4!',
  65. },
  66. TimePick: {
  67. customClass: 'm-0!',
  68. },
  69. }
  70. const themeVars: ConfigProviderThemeVars = {
  71. cellPadding: '0',
  72. cellWrapperPadding: '10rpx',
  73. radioButtonRadius: '8rpx',
  74. radioButtonBg: 'transparent',
  75. checkboxButtonRadius: '8rpx',
  76. checkboxButtonBg: 'transparent',
  77. }
  78. const submit = () => {
  79. emits('submit', modelValue)
  80. }
  81. const validate = (): Promise<{ valid: boolean; errors: any[] }> => form.value?.validate()
  82. defineExpose({
  83. validate,
  84. })
  85. </script>
  86. <template>
  87. <wd-config-provider :theme-vars="themeVars">
  88. <wd-form ref="form" :model="modelValue">
  89. <template
  90. v-for="([prop, { type, label, hiddenLabel, existing, props }], index) in Object.entries(
  91. schema,
  92. )"
  93. :key="index"
  94. >
  95. <div
  96. v-if="existing ?? true"
  97. class="grid mb-4"
  98. :class="[direction === 'horizontal' ? 'items-center' : '']"
  99. :style="
  100. direction === 'horizontal'
  101. ? { 'grid-template-columns': `${addUnit(props?.labelWidth)} auto` }
  102. : {}
  103. "
  104. >
  105. <label
  106. v-if="type !== 'Submit' && !hiddenLabel"
  107. class="text-sm font-normal leading-relaxed"
  108. :class="[direction === 'horizontal' ? 'text-black/60' : 'mb-1 text-black/40']"
  109. :for="prop"
  110. >
  111. {{ label || prop }}
  112. </label>
  113. <wd-input
  114. v-if="type === 'TextField'"
  115. v-bind="{
  116. ...(direction === 'vertical'
  117. ? verticalDefaultProps[type]
  118. : horizontalDefaultProps[type]),
  119. ...omit(props, ['labelWidth']),
  120. }"
  121. v-model="modelValue[prop]"
  122. ></wd-input>
  123. <wd-datetime-picker
  124. v-model="modelValue[prop]"
  125. v-if="type === 'TimePick'"
  126. v-bind="{
  127. ...(direction === 'vertical'
  128. ? verticalDefaultProps[type]
  129. : horizontalDefaultProps[type]),
  130. cell: false,
  131. ...props,
  132. }"
  133. />
  134. <wd-textarea
  135. v-if="type === 'Textarea'"
  136. v-model="modelValue[prop]"
  137. v-bind="{
  138. ...(direction === 'vertical'
  139. ? verticalDefaultProps[type]
  140. : horizontalDefaultProps[type]),
  141. cell: false,
  142. ...props,
  143. }"
  144. />
  145. <wd-picker
  146. v-if="type === 'Select'"
  147. v-bind="{
  148. ...(direction === 'vertical'
  149. ? verticalDefaultProps[type]
  150. : horizontalDefaultProps[type]),
  151. cell: false,
  152. ...props,
  153. }"
  154. v-model="modelValue[prop]"
  155. ></wd-picker>
  156. <wd-radio-group
  157. v-if="type === 'Radio'"
  158. v-bind="{
  159. ...(direction === 'vertical'
  160. ? verticalDefaultProps[type]
  161. : horizontalDefaultProps[type]),
  162. ...props,
  163. cell: true,
  164. shape: 'button',
  165. }"
  166. v-model="modelValue[prop]"
  167. >
  168. <template v-for="{ label, value } of props.columns" :key="value">
  169. <wd-radio :value="value">{{ label }}</wd-radio>
  170. </template>
  171. </wd-radio-group>
  172. <wd-checkbox-group
  173. v-if="type === 'Checkbox'"
  174. v-bind="{
  175. ...(direction === 'vertical'
  176. ? verticalDefaultProps[type]
  177. : horizontalDefaultProps[type]),
  178. ...props,
  179. cell: true,
  180. shape: 'button',
  181. }"
  182. v-model="modelValue[prop]"
  183. >
  184. <template v-for="{ label, value } of props.columns" :key="value">
  185. <wd-checkbox custom-class="mr-4!" :modelValue="value">{{ label }}</wd-checkbox>
  186. </template>
  187. </wd-checkbox-group>
  188. <wd-button
  189. v-if="type === 'Submit'"
  190. v-bind="{
  191. ...(direction === 'vertical' ? verticalDefaultProps[type] : {}),
  192. ...props,
  193. formType: 'submit',
  194. }"
  195. @click="submit"
  196. >
  197. <span v-if="type === 'Submit'">提交</span>
  198. </wd-button>
  199. </div>
  200. </template>
  201. </wd-form>
  202. </wd-config-provider>
  203. </template>