rules.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <script lang="ts" setup>
  2. import { Page } from '@vben/common-ui';
  3. import { Button, Card, message } from 'ant-design-vue';
  4. import { useVbenForm, z } from '#/adapter/form';
  5. const [Form, formApi] = useVbenForm({
  6. // 所有表单项共用,可单独在表单内覆盖
  7. commonConfig: {
  8. // 所有表单项
  9. componentProps: {
  10. class: 'w-full',
  11. },
  12. },
  13. // 提交函数
  14. handleSubmit: onSubmit,
  15. // 垂直布局,label和input在不同行,值为vertical
  16. // 水平布局,label和input在同一行
  17. layout: 'horizontal',
  18. schema: [
  19. {
  20. // 组件需要在 #/adapter.ts内注册,并加上类型
  21. component: 'Input',
  22. // 对应组件的参数
  23. componentProps: {
  24. placeholder: '请输入',
  25. },
  26. // 字段名
  27. fieldName: 'field1',
  28. // 界面显示的label
  29. label: '字段1',
  30. rules: 'required',
  31. },
  32. {
  33. component: 'Input',
  34. componentProps: {
  35. placeholder: '请输入',
  36. },
  37. defaultValue: '默认值',
  38. fieldName: 'field2',
  39. label: '默认值(必填)',
  40. rules: 'required',
  41. },
  42. {
  43. component: 'Input',
  44. componentProps: {
  45. placeholder: '请输入',
  46. },
  47. fieldName: 'field3',
  48. label: '默认值(非必填)',
  49. rules: z.string().default('默认值').optional(),
  50. },
  51. {
  52. component: 'Input',
  53. componentProps: {
  54. placeholder: '请输入',
  55. },
  56. fieldName: 'field31',
  57. label: '自定义信息',
  58. rules: z.string().min(1, { message: '最少输入1个字符' }),
  59. },
  60. {
  61. component: 'Input',
  62. // 对应组件的参数
  63. componentProps: {
  64. placeholder: '请输入',
  65. },
  66. // 字段名
  67. fieldName: 'field4',
  68. // 界面显示的label
  69. label: '邮箱',
  70. rules: z.string().email('请输入正确的邮箱'),
  71. },
  72. {
  73. component: 'InputNumber',
  74. componentProps: {
  75. placeholder: '请输入',
  76. },
  77. fieldName: 'number',
  78. label: '数字',
  79. rules: 'required',
  80. },
  81. {
  82. component: 'Select',
  83. componentProps: {
  84. allowClear: true,
  85. filterOption: true,
  86. options: [
  87. {
  88. label: '选项1',
  89. value: '1',
  90. },
  91. {
  92. label: '选项2',
  93. value: '2',
  94. },
  95. ],
  96. placeholder: '请选择',
  97. showSearch: true,
  98. },
  99. defaultValue: undefined,
  100. fieldName: 'options',
  101. label: '下拉选',
  102. rules: 'selectRequired',
  103. },
  104. {
  105. component: 'RadioGroup',
  106. componentProps: {
  107. options: [
  108. {
  109. label: '选项1',
  110. value: '1',
  111. },
  112. {
  113. label: '选项2',
  114. value: '2',
  115. },
  116. ],
  117. },
  118. fieldName: 'radioGroup',
  119. label: '单选组',
  120. rules: 'selectRequired',
  121. },
  122. {
  123. component: 'CheckboxGroup',
  124. componentProps: {
  125. name: 'cname',
  126. options: [
  127. {
  128. label: '选项1',
  129. value: '1',
  130. },
  131. {
  132. label: '选项2',
  133. value: '2',
  134. },
  135. ],
  136. },
  137. fieldName: 'checkboxGroup',
  138. label: '多选组',
  139. rules: 'selectRequired',
  140. },
  141. {
  142. component: 'Checkbox',
  143. fieldName: 'checkbox',
  144. label: '',
  145. renderComponentContent: () => {
  146. return {
  147. default: () => ['我已阅读并同意'],
  148. };
  149. },
  150. rules: z.boolean().refine((value) => value, {
  151. message: '请勾选',
  152. }),
  153. },
  154. {
  155. component: 'DatePicker',
  156. defaultValue: undefined,
  157. fieldName: 'datePicker',
  158. label: '日期选择框',
  159. rules: 'selectRequired',
  160. },
  161. {
  162. component: 'RangePicker',
  163. defaultValue: undefined,
  164. fieldName: 'rangePicker',
  165. label: '区间选择框',
  166. rules: 'selectRequired',
  167. },
  168. {
  169. component: 'InputPassword',
  170. componentProps: {
  171. placeholder: '请输入',
  172. },
  173. fieldName: 'password',
  174. label: '密码',
  175. rules: 'required',
  176. },
  177. {
  178. component: 'Input',
  179. componentProps: {
  180. placeholder: '请输入',
  181. },
  182. fieldName: 'input-blur',
  183. formFieldProps: {
  184. validateOnChange: false,
  185. validateOnModelUpdate: false,
  186. },
  187. help: 'blur时才会触发校验',
  188. label: 'blur触发',
  189. rules: 'required',
  190. },
  191. {
  192. component: 'Input',
  193. componentProps: {
  194. placeholder: '请输入',
  195. },
  196. fieldName: 'input-async',
  197. label: '异步校验',
  198. rules: z
  199. .string()
  200. .min(3, '用户名至少需要3个字符')
  201. .refine(
  202. async (username) => {
  203. // 假设这是一个异步函数,模拟检查用户名是否已存在
  204. const checkUsernameExists = async (
  205. username: string,
  206. ): Promise<boolean> => {
  207. await new Promise((resolve) => setTimeout(resolve, 1000));
  208. return username === 'existingUser';
  209. };
  210. const exists = await checkUsernameExists(username);
  211. return !exists;
  212. },
  213. {
  214. message: '用户名已存在',
  215. },
  216. ),
  217. },
  218. ],
  219. // 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
  220. wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
  221. });
  222. function onSubmit(values: Record<string, any>) {
  223. message.success({
  224. content: `form values: ${JSON.stringify(values)}`,
  225. });
  226. }
  227. </script>
  228. <template>
  229. <Page description="表单校验示例" title="表单组件">
  230. <Card title="基础组件校验示例">
  231. <template #extra>
  232. <Button @click="() => formApi.validate()">校验表单</Button>
  233. <Button class="mx-2" @click="() => formApi.resetValidate()">
  234. 清空校验信息
  235. </Button>
  236. </template>
  237. <Form />
  238. </Card>
  239. </Page>
  240. </template>