需求:
- 根据后端数据,动态渲染表头;
- 根据表头类型,动态提供相应的输入;
- 根据表头类型,实现动态校验,校验条件也来自后端;
- 实现单个和批量数据上传
总之,所有的数据都来自于后端,前端各种动态处理。
<template>
<div>
<el-button icon="el-icon-circle-plus" @click="addLine">添加行</el-button>
</div>
<el-form :model="batchForm" ref="batchForm" class="demo-dynamic">
<el-table class="tb-edit" :data="batchForm.formItems" style="width:100%; margin-top:10px;" height="400" border>
<template v-for="(col, index) in fileData.cols">
<el-table-column v-if="col.itemType==='STRING'" width="200px" :key="index" :prop="col.itemEName" :label="col.itemName">
<template slot-scope="scope">
<el-form-item :prop="'formItems.' + scope.$index + '.' + col.itemEName" :rules="rules.stringRule">
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4}" style="width: 100%; padding: 0px; margin-top: 0px;"
v-model="scope.row[col.itemEName]" :placeholder="col.itemName" @focus="setStrLength(col.itemLength)">
</el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column v-else-if="col.itemType==='TEXT'" width="200px" :key="index" :prop="col.itemEName" :label="col.itemName">
<template slot-scope="scope">
<el-form-item :prop="'formItems.' + scope.$index + '.' + col.itemEName" :rules="rules.stringRule">
<el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4}" style="margin: 0; width: 100%;"
v-model="scope.row[col.itemEName]" :placeholder="col.itemName" @focus="setStrLength(col.itemLength)">
</el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column v-else-if="col.itemType==='DATE' || col.itemType==='DATETIME'" width="230px" :key="index" :prop="col.itemEName" :label="col.itemName">
<template slot-scope="scope">
<el-form-item :prop="'formItems.' + scope.$index + '.' + col.itemEName">
<el-date-picker v-if="col.itemFormat === 'yyyy-MM-dd'" v-model="scope.row[col.itemEName]"
type="date" value-format="yyyy-MM-dd HH:mm:ss" placeholder="yyyy-MM-dd" style="width: 100%;">
</el-date-picker>
<el-date-picker v-else-if="col.itemFormat === 'yyyy-MM-dd HH:mm:ss'" v-model="scope.row[col.itemEName]"
type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="yyyy-MM-dd HH:mm:ss" style="width: 100%;">
</el-date-picker>
</el-form-item>
</template>
</el-table-column>
<el-table-column v-else-if="col.itemType==='NUMBER'" width="130px"
:key="index" :prop="col.itemEName" :label="col.itemName">
<template slot-scope="scope">
<el-form-item :prop="'formItems.' + scope.$index + '.' + col.itemEName" :rules="rules.numberRule">
<el-input style="margin: 0px; padding: 0px; width: 100%;" v-model.number="scope.row[col.itemEName]"
:placeholder="col.itemName" @focus="setNumberRange(col.itemMinValue, col.itemMaxValue)">
</el-input>
</el-form-item>
</template>
</el-table-column>
<el-table-column v-else-if="col.itemType === 'ARRAY'" width="120px"
:key="index" :prop="col.itemEName" :label="col.itemName">
<template slot-scope="scope">
<el-form-item :prop="'formItems.' + scope.$index + '.' + col.itemEName">
<el-select style="width: 100%; margin: 0;" clearable v-model="scope.row[col.itemEName]" :placeholder="col.itemName">
<el-option v-for="d in col.itemDictionaries" :key="d.value" :label="d.label" :value="d.value"></el-option>
</el-select>
</el-form-item>
</template>
</el-table-column>
</template>
<el-table-column label="操作" prop="option" width="55px">
<template slot-scope="scope">
<el-form-item>
<el-button style="margin: 0; width: 100%;" type="mini" icon="el-icon-delete-solid"
@click="handleDelete(scope.$index, scope.row)" circle>
</el-button>
</el-form-item>
</template>
</el-table-column>
</el-table>
</el-form>
<div class="footer">
<el-button type="primary" @click="submitBatchInput('batchForm')">提交</el-button>
<el-button @click="inputClose">取消</el-button>
</div>
</template>
<script>
export default {
data () {
var validateNumber = (rule, value, callback) => {
let thiz = this
if (!value) {
callback()
} else if (!Number.isInteger(value)) {
return callback(new Error('请输入数值'))
} else if (parseInt(thiz.checkValue.minValue) > parseInt(value) || parseInt(thiz.checkValue.maxValue) < parseInt(value)) {
return callback(new Error('范围:[' + thiz.checkValue.minValue + ',' + thiz.checkValue.maxValue + ']'))
} else {
callback()
}
}
var validateString = (rule, value, callback) => {
let thiz = this
if (!value) {
callback()
} else if (value.length > thiz.checkValue.strLen) {
return callback(new Error('长度不大于' + thiz.checkValue.strLen))
} else {
callback()
}
}
return {
checkValue: {
minValue: 0,
maxValue: 0,
strLen: 1
},
batchForm: {
formItems: [{}]
},
rules: {
numberRule: [
{validator: validateNumber, trigger: ['blur', 'change']}
],
stringRule: [
{validator: validateString, trigger: ['blur', 'change']}
]
},
fileData: {
// 表头信息
cols: [
{
'itemName': '',
'itemEName': '',
'itemType': 'STRING',
'itemLength': ''
},
{
'itemName': '',
'itemEName': '',
'itemType': 'TEXT',
'itemLength': ''
},
{
'itemName': '',
'itemEName': '',
'itemType': 'DATE',
'itemFormat': ''
},
{
'itemName': '',
'itemEName': '',
'itemType': 'DATETIME',
'itemFormat': ''
},
{
'itemName': '',
'itemEName': '',
'itemType': 'NUMBER',
'itemMinValue': '',
'itemMaxValue': ''
},
{
'itemName': '',
'itemEName': '',
'itemType': 'ARRAY',
'itemDictionaries': [
{
'value': '',
'label': ''
},
{
'value': '',
'label': ''
},
]
}
]
}
}
},
methods: {
// 添加行数
addLine () {
var newValue = {}
this.batchForm.formItems.push(newValue)
},
// 删除行
handleDelete (index) {
this.batchForm.formItems.splice(index, 1)
},
// 设置判断条件,数值范围
setNumberRange (minValue, maxValue) {
let thiz = this
thiz.checkValue.minValue = minValue
thiz.checkValue.maxValue = maxValue
},
// 设置判断条件,字符串长度
setStrLength (strLen) {
let thiz = this
thiz.checkValue.strLen = strLen
},
submitBatchInput (batchForm) {
let thiz = this
let isEmpty = true
for (let i in thiz.batchForm.formItems) {
let formItem = thiz.batchForm.formItems[i]
if (Object.keys(formItem).length > 0) {
isEmpty = false
}
}
if (isEmpty) {
thiz.$message('录入数据为空')
return
}
thiz.$refs[batchForm].validate((valid) => {
if (valid) {
let loading = thiz.$loading({
lock: true,
text: '录入中,请稍候...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
let saveData = {dataArr: thiz.batchForm.formItems}
thiz.$axios.post(`htpp://localhost:8080/upload/batchInsert`, saveData)
.then(({data}) => {
loading.close()
if (data.statusCode === 233) {
thiz.$message(data.message)
thiz.batchForm.formItems = [{}]
thiz.fileData.cols = []
} else {
thiz.$message(data.message)
}
})
} else {
this.$message('输入数据验证不通过')
}
})
},
inputClose () {
let thiz = this
thiz.batchForm.formItems = [{}]
thiz.fileData.cols = []
}
}
}
</script>
<style lang="scss" scoped>
</style>
总结:
- el-form中的model须是对象,不能为列表;
- el-form-item中的prop须指向列表中的cell,即:指定行和列;
- scope中获取行索引:scope.$index;
- 根据动态属性名称(fieldName),获取属性值(fieldValue)的方法:fieldValue = scope.row[fieldName];
- 由于不同的数据类型,需要不同验证方式,所以具体验证规则放在el-form-item中,并且自定义验证函数。