vue3项目结合antdesignvue封装form表单及校验

发布时间 2023-09-27 18:05:06作者: 程序员肉包子

效果图

 完整代码

  1 <script setup>
  2   import { defineProps, onMounted, reactive, ref, defineEmits} from 'vue'
  3   import { Card, Input, Select, DatePicker, FormItem, Form, Button } from 'ant-design-vue'
  4   import { useRuleCheckStore } from '@/stores/ruleCheck' // 后端接口
  5 
  6   const ruleCheckStore = useRuleCheckStore()
  7   const formModel = reactive({
  8     // policyInfo: {
  9     //   bigPolicyNumber: '', // 大保单号
 10     //   smallPolicyNumber: '', // 小保单号
 11     //   province: '', // 省份
 12     //   city: '', // 城市 
 13     // }, // 保单信息
 14     // peopleInfo: {
 15     //   applicantPeople: '', // 投保人
 16     //   assuredPeople: '', // 被保险人
 17     //   carOwnerGender: '', // 车主性别
 18     //   carOwnerAge: '', // 车主年龄
 19     // }, // 人员信息
 20     // dateInfo: {
 21     //   recordingTime: '', // 录单时间
 22     //   underwritingTime: '', // 核保完成时间 
 23     //   startTime: '', // 起保时间
 24     //   finalTime: '', // 终保时间
 25     // }, // 日期信息
 26   })
 27   // // 封装select下拉框,哪里需要就调用这个方法
 28   function useOptions(request, format) {
 29     const options = ref([]);
 30     async function getOptions (...args) {
 31       let data = await request(...args);
 32       if (typeof format === 'function') {
 33         data = data.map(format);
 34       }
 35       console.log('options:', data)
 36       options.value = data
 37     }
 38     return [options, getOptions];
 39   }
 40   // 生命周期里面调用
 41   onMounted(()=>{
 42     getOptionsProvince();
 43   })
 44   // 省份名称下拉列表
 45   const [ProvinceList, getOptionsProvince] = useOptions(
 46     // 后端提供的接口
 47     ruleCheckStore.getProvinceList,
 48     (item) => ({
 49       original: item,
 50       label: item.name,
 51       value: item.code,
 52     }),
 53   );
 54   // change事件
 55   const provinceHandleChange = (item) => {
 56     ProvinceList.value = [];
 57     getOptionsProvince();
 58   }
 59   // 遍历的数据
 60   const dataList = [
 61     {
 62       "formTitle": "保单信息",
 63       "formFields": [
 64         {
 65           "label": "大保单号",
 66           "name": "bigPolicyNumber",
 67           "type": "input",
 68         },
 69         {
 70           "label": "小保单号",
 71           "name": "smallPolicyNumber",
 72           "type": "input"
 73         },
 74         {
 75           "label": "省份名称",
 76           "name": "province",
 77           "type": "select",
 78           "options": ProvinceList
 79         },
 80         {
 81           "label": "城市名称",
 82           "name": "city",
 83           "type": "select",
 84           "options": ProvinceList
 85         }
 86       ]
 87     },
 88     {
 89       "formTitle": "人员信息",
 90       "formFields": [
 91         {
 92           "label": "投保人",
 93           "name": "applicantPeople",
 94           "type": "input"
 95         },
 96         {
 97           "label": "被投保人",
 98           "name": "assuredPeople",
 99           "type": "input"
100         },
101         {
102           "label": "车主性别",
103           "name": "carOwnerGender",
104           "type": "select",
105           "options": ProvinceList
106         },
107         {
108           "label": "车主年龄",
109           "name": "carOwnerAge",
110           "type": "input"
111         },
112       ]
113     },
114     {
115       "formTitle": "日期信息",
116       "formFields": [
117         {
118           "label": "录单时间",
119           "name": "recordingTime",
120           "type": "DatePicker"
121         },
122         {
123           "label": "核保完成时间",
124           "name": "underwritingTime",
125           "type": "DatePicker"
126         },
127         {
128           "label": "起保时间",
129           "name": "startTime",
130           "type": "DatePicker"
131         },
132         {
133           "label": "终保时间",
134           "name": "finalTime",
135           "type": "DatePicker"
136         },
137       ]
138     }
139   ]
140   // 自定义校验验证车主年龄不能超过71岁
141   const checkName = async (_rule, value) => {
142     if (value > 71 ) {
143       return Promise.reject('车主的年龄不能超过71岁');
144     } else {
145       return Promise.resolve();
146     }
147   }
148   // 验证数据
149   const rules = {
150     bigPolicyNumber: [
151       {
152         required: true,
153         message: '请输入大保单号',
154         trigger: 'blur',
155       },
156     ],
157     province: [
158       {
159         required: true,
160         message: '请选择省份',
161         trigger: 'blur',
162       },
163     ],
164     city: [
165       {
166         required: true,
167         message: '请选择城市',
168         trigger: 'blur',
169       },
170     ],
171     carOwnerGender: [
172       {
173         required: true,
174         message: '请选择车主性别',
175         trigger: 'blur',
176       },
177     ],
178     carOwnerAge: [
179       {
180         required: true,
181         message: '请输入车主年龄',
182         trigger: 'blur',
183       },
184       {
185         validator:checkName    //自定义的校验函数
186       }
187     ],
188     recordingTime: [
189       {
190         required: true,
191         message: '请选择录单时间',
192         trigger: 'blur',
193       }
194     ],
195     underwritingTime: [
196       {
197         required: true,
198         message: '核保完成时间',
199         trigger: 'blur',
200       }
201     ],
202     startTime: [
203       {
204         required: true,
205         message: '请选择起保时间',
206         trigger: 'blur',
207       }
208     ],
209     finalTime: [
210       {
211         required: true,
212         message: '请选择终保时间',
213         trigger: 'blur',
214       }
215     ],
216     
217   }
218   // 提交数据按钮
219   // 获取form表单
220   const formRef = ref(null)
221   const create = async () => {
222     try {
223       await formRef.value.validate().then(()=>{
224         // 后端接口
225         // ruleCheckStore.getAddValidationDataById(formState)
226       })
227     } catch (error) {
228       console.log(error);
229     }
230   }
231 
232 </script>
template代码
 1 <template>
 2   <div class="expectedResult">
 3       <div style="display:flex;justifyContent:space-between">
 4         <div class="expectedResult-title">输入数据信息</div>
 5         <Button @click="create" style="marginBottom:16px;color:#0058FB ">
 6           提交
 7         </Button>
 8       </div>
 9       <Card :bordered="false" v-for="(iten,index) in dataList" :key="index">
10        <div class="expectedResult-content">{{ iten.formTitle }}</div>
11        <Form 
12           ref="formRef" 
13           :model="formModel" 
14           :rules="rules" 
15         >
16         <template v-for="item in iten.formFields" :key="item.name">
17           <FormItem :label="item.label" :name="item.name" v-if="item.type == 'input'">
18             <Input v-model:value="formModel[item.name]" :bordered="false"/>
19           </FormItem>
20           <FormItem :label="item.label" :name="item.name" v-if="item.type == 'select'">
21             <Select
22               v-model:value="formModel[item.name]"
23               show-search
24               placeholder="请选择"
25               :options="item.options"
26               @change="provinceHandleChange"
27               :bordered="false"
28               style="width: 240px;"
29             ></Select>
30           </FormItem>
31           <FormItem :label="item.label" :name="item.name" v-if="item.type == 'DatePicker'">
32              <DatePicker v-model:value="formModel[item.name]" :bordered='false' show-time value-format='YYYY-MM-DD HH:mm:ss'/>
33           </FormItem>
34         </template>
35       </Form>
36       </Card>
37   </div>
38 </template>

css样式代码

 1 <style lang="less" scoped>
 2  .expectedResult {
 3     padding: 16px;
 4     margin-top: 16px;
 5     
 6     &-title {
 7         padding: 14px 0 14px 24px;
 8         font-size: 14px;
 9         font-family: PingFangSC-Medium, PingFang SC;
10         font-weight: 500;
11         color: rgba(0,0,0,0.85);
12         background: #F5F6FB;
13         line-height: 20px;
14       }
15       .expectedResult{
16         background-color:#fff ;
17         &-content{
18         width: 64px;
19         border-left: 4px solid #0058FB ;
20         padding-left: 4px;
21         margin: 0px 0 16px 0px;
22         font-size: 14px;
23       }
24     }
25     :deep(.ant-form){
26       display:flex;
27         justify-content: flex-start;
28         flex-wrap: wrap;
29     }
30     :deep(.ant-form-item){
31       display: flex;
32       border: 1px solid #ECEBF2;
33       margin-bottom: 0;
34       &-label{
35         width: 140px;
36         font-size: 14px;
37         font-weight: 400;
38         text-align: right;
39         padding: 10px 8px;
40         background: #F7F8F9;
41         color: rgba(0,0,0,0.65);
42         overflow: hidden;
43         white-space: normal;
44       }
45       .ant-input{
46         line-height: 42px;
47       }
48       .ant-form-item-control-input-content{
49         width: 240px;
50         line-height: 52px;
51       }
52     }
53  }
54 </style>