vue+element_ui建表,动态渲染表头、提供手动输入、动态校验

需求:

  1. 根据后端数据,动态渲染表头;
  2. 根据表头类型,动态提供相应的输入;
  3. 根据表头类型,实现动态校验,校验条件也来自后端;
  4. 实现单个和批量数据上传

总之,所有的数据都来自于后端,前端各种动态处理。

<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>

总结:

  1. el-form中的model须是对象,不能为列表;
  2. el-form-item中的prop须指向列表中的cell,即:指定行和列;
  3. scope中获取行索引:scope.$index;
  4. 根据动态属性名称(fieldName),获取属性值(fieldValue)的方法:fieldValue = scope.row[fieldName];
  5. 由于不同的数据类型,需要不同验证方式,所以具体验证规则放在el-form-item中,并且自定义验证函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值