最近有一个分单的需求,需要把一个二维数组通过表单提交传参给后台。
主要数据格式(数组[对象{对象,数组},对象{对象,数组}])示例 this.ruleList:
[{
info: {
name: '1',
paymentTerm: '',
stockPosition: '',
purchaseGroup: '',
},
materialList: [{
a: '',
b: '',
deliveryDate: '2022-3-20'
},
{
a: '',
b: '',
deliveryDate: '2022-3-20'
}
]
},
{
info: {
name: '2',
paymentTerm: '',
stockPosition: '',
purchaseGroup: '',
},
materialList: [{
a: '',
b: '',
deliveryDate: '2022-3-20'
}]
}
]
数据处理部分代码示例:
this.ruleDataList.forEach(item=>{
this.$set(item.info,'materialList',item.materialList);
item.materialList.forEach(ele=>{
this.$set(ele,'defaultDate',ele.deliveryDate);
this.$set(ele,'rule',[
{
required: true,
validator:(rule, value, callback)=>{
this.deliveryDate(rule,callback,ele.defaultDate,ele.deliveryDate)
},
trigger: ['blur','change']
}
])
})
this.validateList.push(item.info)
})
首先将this.ruleDataList 里的对象和数组都合并到info里,materialList数组里新增了两个属性值rule和defaultDate并push到一个新数组validateList里,这样我们就得到this.validateList的数据格式为:
{
name: '1',
paymentTerm: '',
stockPosition: '',
purchaseGroup: '',
materialList: [{
a: '',
b: '',
deliveryDate: '2022-3-20',
rule: '表格项校验规则'
},
{
a: '',
b: '',
deliveryDate: '2022-3-20',
rule: '表格项校验规则'
}
]
},
{
name: '2',
paymentTerm: '',
stockPosition: '',
purchaseGroup: '',
materialList: [{
a: '',
b: '',
deliveryDate: '2022-3-20',
rule: '表格项校验规则'
}]
}
]
这样我们渲染页面时就可以直接用处理后的数组,更方便表单的校验。页面通过v-for来循环validateList,获得多个表单,所以表单的ref拼接了索引,页面代码示例如下:
<div class="separateContent">
<el-row class="soDetailRow" v-for="(item,index) in validateList" :key="index">
<div class="subTitle">
<span>{{item.supplierName}}</span>
</div>
<el-form :model="item" :ref="'ruleForm'+index" label-width="100px">
<el-form-item label="付款条件:" prop="paymentTerm"
:rules="[{ required: true, message: '付款条件不能为空'}]"
class="formRow">
<el-select placeholder="请选择"
filterable
style="width:200px;margin-right:10px"
v-model="item.paymentTerm">
<el-option v-for="ops in paymentClauseList"
:key="ops.value"
:label="ops.label"
:value="ops.value">
</el-option>
</el-select>
</el-form-item>
<el-table
border
:row-class-name="tableRowClassName"
:header-cell-style="{background: '#f7f7f7',padding:'5px 10px'}"
ref="multipleTable"
:data="item.materialList">
<el-table-column align="center" prop="orderUnitDesc" label="单位" ></el-table-column>
<el-table-column align="center" prop="deliveryDate" label="交货期" min-width="130px">
<template slot-scope="scope">
<el-form-item
:prop="'materialList.'+scope.$index+'.deliveryDate'"
:rules="scope.row.rule"
class="costValue">
<el-date-picker
:clearable="false"
style="width:130px"
@change="handleChangeDate(scope.row,`materialList.${scope.$index}.deliveryDate`,`${index}`,)"
v-model="scope.row.deliveryDate"
type="date"
value-format="yyyy-MM-dd"
:placeholder="`选择日期${index}`">
</el-date-picker>
</el-form-item>
</template>
</el-table-column>
</el-table>
</el-form>
</el-row>
</div>
<el-row class="crumbs btns printBtns" type="flex" justify="center">
<el-button class="el-btn" @click="hanldeCheckForm('1')" v-preventReClick>存为待推送</el-button>
<el-button type="primary" class="el-btn" @click="hanldeCheckForm('2')" v-preventReClick>确认分单</el-button>
</el-row>
由于表单是多个,表单里嵌套的表格也是多个,根据prop定义的动态表单校验会有重复值,所以在处理数组时,set了每一项的自定义校验规则(每项的交货期日期组件选择都不能小于默认日期),规则代码如下:
// 自定义日期校验
deliveryDate(rule, callback,defaultDate,deliveryDate){
let index = Number(rule.field.split('.')[1])//获取当前验证项的index,对应数据的index
if(!deliveryDate){
callback(new Error('交货日期不能为空'))
}else if(defaultDate > deliveryDate){
callback(new Error('只能选择'+ defaultDate +'之后的日期'))
}else{
callback()
}
},
表单提交时,由于是多个表单,只有所有的表单校验通过之后再去请求接口,这里用到的是Promise.all的方法,代码示例如下:
// 表单校验
hanldeCheckForm(type){
let _self = this;
let newArr = [];
this.validateList.forEach((item,index)=>{
let result = new Promise(function(resolve, reject) {
_self.$refs['ruleForm'+index][0].validate(valid=>{
if (valid) {
resolve();
} else { reject() }
})
})
newArr.push(result);
})
Promise.all(newArr).then(function() { //都通过了
let paramsList = [];
_self.validateList.forEach(item=>{
paramsList.push({info:item,materialList:item.materialList})
})
if(type == '1'){
_self.handlePushClick(paramsList)
}else{
_self.handleConfirmClick(paramsList)
}
}).catch(function(err) {
console.log(err);
})
},
// 待推送
handlePushClick(params){
saveWaitPush(params).then(res=>{
if(res.code == '200'){
this.$message({
message: '操作成功',
type: 'success'
});
this.$emit('handleClose',false,true)
}
})
},
// 待确认
handleConfirmClick(params){
confirmSplit(params).then(res=>{
if(res.code == '200'){
this.$message({
message: '操作成功',
type: 'success'
});
this.$emit('handleClose',false,true)
}
})
},
由于后台要求入参格式跟未处理之前一致,所以在接口请求之前又重新将对象和数据剥离成 paramsList.push({info:item,materialList:item.materialList})。这里没有专门对info里的materialList做删除处理,可以自行删除。
解决需求痛点:
1.循环(多)表单动态校验。
2.自定义校验传参validator入参无法接收rule, value, callback 之外的参数,导致表格项校验时,无法直接通过索引值获取数组里的某一项做校验,曲线救国通过set以及在validator 通过自定义方法专门对入参做处理。