天天看点

动态循环表单,同时进行表单验证

出现的问题

1.el-input输入不上,el-select选择不了

2.使用强制刷新后,能选择,但是表单验证失效

3.最终解决方案(代码里有注释)

   重要部分(思路)

<el-form :model="registerForm" ref="ruleFormProp" :rules="rules">
  <div v-for="(item,index) in registerForm.processData" :key="index">
    <el-form-item :prop="'processData.'+index+'.assetsName'" :rules="rules.assetsName">
      <el-input placeholder="请输入" class="addinput" v-model="item.assetsName">
      </el-input>
    </el-form-item>
  </div>
</el-form>
           

3-1. 后端获取的数组用registerForm对象包裹,processData为后端数组

3-2. :prop="'processData.'+index+'.assetsName'" 绑定动态属性,也可使用模板拼接

        :prop="`processData.${index}.assetsName`"

3-3. :rules="rules.assetsName" 进行表单验证

data() {
  var checkassetsName = (rule, value, callback) => { 
   if (!value) {
     return callback(new Error('请输入资产名称'));
   } else {
     callback();
   }
  };
  return {
    assetsName: [{ validator: checkassetsName, trigger: 'blur' }],
  }
}
           

3-4. 最后确定时触发rlues验证

onSubmit() {
  this.$refs.ruleFormProp.validate((valid)=>{
    if(valid){ }
  }
}
           

4. 完整代码

index.vue页面

<template>

  <div>

    <div style="margin-top: 125px">

      <div class="el-dialog-register-top">资产登记</div>

      <div style="padding: 10px" class="row-col-columns">

        <div class="row-col-columns-1">序号</div>

        <div class="row-col-columns-2">主机序列号</div>

        <div class="row-col-columns-3"><span class="register-star">*</span>辖区</div>

        <div class="row-col-columns-2"><span class="register-star">*</span>型号</div>

        <div class="row-col-columns-2"><span class="register-star">*</span>资产名称</div>

        <div class="row-col-columns-3"><span class="register-star">*</span>所属厂家/品牌</div>

        <div class="row-col-columns-2"><span class="register-star">*</span>使用单位</div>

      </div>

      <el-form style="width: 100%;" size="medium" :model="registerForm" ref="ruleFormProp" :rules="rules">

        <div v-for="(item,index) in registerForm.processData" :key="index" class="row-col-columns">

          <div class="row-col-columns-1 number">{{ index+1 }}</div>

          <div class="row-col-columns-2">

            <el-input v-model="item.serialNumber" disabled></el-input>

          </div>

          <div class="row-col-columns-3">

             <!-- 辖区 -->

            <el-form-item :prop="`processData.${index}.jurisdictionName`" :rules="rules.jurisdictionName">

              <el-input v-model="item.jurisdictionName" disabled></el-input>

            </el-form-item>

          </div>

          <div class="row-col-columns-2">

             <!-- 型号 -->

            <el-form-item :prop="`processData.${index}.model`" :rules="rules.model">

              <el-input v-model="item.model" disabled></el-input>

            </el-form-item>

          </div>

          <div class="row-col-columns-2">

            <el-form-item :prop="'processData.'+index+'.assetsName'" :rules="rules.assetsName">

              <el-input placeholder="请输入" class="addinput" v-model="item.assetsName">

              </el-input>

            </el-form-item>

          </div>

          <div class="row-col-columns-3"> // 所属厂家/品牌

            <el-form-item :prop="`processData.${index}.belongBrandId`" :rules="rules.belongBrandId">

              <el-cascader

                v-model.trim="item.belongBrandId"

                ref="cascaderList"

                @change="handleChange($event, index)"

                :props="{

                  lazy: true,

                  lazyLoad: lazyLoadAdd,

                }">

              </el-cascader>

            </el-form-item>

          </div>

          <div class="row-col-columns-2">

             <!-- 使用单位 -->

            <el-form-item :prop="`processData.${index}.useId`" :rules="rules.useId">

              <el-select v-model="item.useId" clearable placeholder="使用单位" class="inputSelect">

                <el-option v-for="item2 in item.useOptions" :key="item2.value" :label="item2.label" :value="item2.value"></el-option>

              </el-select>

            </el-form-item>

          </div>

          <div class="row-col-columns-1 number" @click="clearItem(item)" >

            <svg class="iconfont" aria-hidden="true" style="width: 18px; height: 18px">

              <use xlink:href="#el-icon-myshanchu" target="_blank" rel="external nofollow" />

            </svg>

          </div>

        </div>

      </el-form>

     

      <div class="footer-btn">

        <el-button @click="onCancel" class="btnSizeStyle">取 消</el-button>

        <el-button type="primary" @click="onSubmit" class="btnSizeStyle">确 定</el-button>

      </div>

    </div>

  </div>

</template>

<script>

import { recordFindHost, batchAssetsRegister } from '@/api/property/networkAccess' // 接口

import { organizationApiManagement } from '@/api/property/pointInterface' // 接口

import { belongBrand } from '@/utils/manufacturerBrand'  // 厂家及品牌联级选择

export default {

  data() {

    var checkassetsName = (rule, value, callback) => {

      console.log(value)

      if (!value) {

        return callback(new Error('请输入资产名称'));

      } else {

        callback();

      }

    };

    var checkbelongBrandId = (rule, value, callback) => {

      console.log(value)

      if (value.length === 0) {

        return callback(new Error('请选择所属厂家'));

      } else if (value.length === 1) {

        return callback(new Error('请选择品牌'));

      } else if (value[2] === 0 && value[1] === 'ditto') {

         // value第三个值代表循环数据的下标,下标为0时不能选择同上

        return callback(new Error('第一条数据不能选为同上'));

      }

      else {

        callback();

      }

    };

    var checkuseId = (rule, value, callback) => {

      if (!value) {

        return callback(new Error('请选择使用单位'));

      } else {

        callback();

      }

    };

    return {

      registerForm: { // 表单包含数组

        processData: []

      },

      rules: {

        assetsName: [{ validator: checkassetsName, trigger: 'blur' }],

        belongBrandId: [{ validator: checkbelongBrandId, trigger: 'change' }],

        useId: [{ validator: checkuseId, trigger: 'change'}],

      },

    }

  },

  created() {

    this.assetsRegister()

  },

  methods: {

    async assetsRegister() {

      const useOptions = await this.getUse() // 获取使用单位列表

      const params = { hostSerialNumber: this.$route.query.host }

      recordFindHost(params).then(res => {

        res.data.forEach((item, index) => {

          item.assetsName = '' // 资产名称

          item.jurisdictionCode = item.streetCode // 后端接收的辖区字段

          item.jurisdictionName = item.provinceName + item.cityName + item.areaName + item.streetName // 前端显示省市区街道

          item.belongBrandId = [] // 用于储存所属厂家及品牌的id

          item.useId = '' // 使用单位

          item.useOptions = useOptions // 使用单位

          item.assetsTypeThree = 53 // 添加数据时传给后台默认的值

         

          const dittoVal = [{value: "ditto" , label: '同上'}]

          if (index !== 0) { // 不是第一条,都同上

            item.useId = 'ditto'

            // 不用push是因为会改变原数组,导致第一条使用单位列表也包括同上选项

            item.useOptions = item.useOptions.concat(dittoVal)

          }

        })

        this.registerForm.processData = res.data // 组成自己想要的数据结构

      })

    },



     // 获取厂家及品牌

    async lazyLoadAdd(node, resolve) {

      if (node.level === 0) {

        return resolve(await belongBrand(node.level+1))

      } else if (node.level === 1) {

        return resolve(await belongBrand(node.level+1, node.value ))

      }

    },



    // 即选择厂家也选择品牌,才能给数组push下标,进行rules验证

    handleChange(e,index) {

      if (e.length !== 1) {

        e.push(index)

      }

    },



    // 取消

    onCancel() {

      this.registerForm.processData = []

    },



    // 清除, 只有资产名称,所属厂家/品牌, 使用单位需要清除

    clearItem(item) {

      item.assetsName = ''

      item.belongBrandId = []

      item.useId = ''

    },



    // 确定,这个可以不做参考,只是生成后端想要的值

    onSubmit() {

      this.$refs.ruleFormProp.validate((valid)=>{

        if(valid){

          var serialNumberArr = [], assetsNameArr =[], belongingIdArr = [], modelArr = [],

          brandIdArr = [], jurisdictionCodeArr = [], useIdArr = [], assetsTypeThreeArr = []

          this.registerForm.processData.forEach(item => {

            serialNumberArr.push(item.serialNumber)

            assetsNameArr.push(item.assetsName)

            belongingIdArr.push(item.belongBrandId[0]) // 联动下拉选择,厂家为数组第一个

            brandIdArr.push(item.belongBrandId[1]) // 联动下拉选择,品牌为数组第二个

            modelArr.push(item.model)

            jurisdictionCodeArr.push(item.jurisdictionCode)

            useIdArr.push(item.useId)

            assetsTypeThreeArr.push(item.assetsTypeThree)

          })



          const params = new URLSearchParams()

          params.append('serialNumber', serialNumberArr)

          params.append('assetsName', assetsNameArr)

          params.append('belongingId', belongingIdArr)

          params.append('brandId', brandIdArr)

          params.append('model', modelArr)

          params.append('jurisdictionCode', jurisdictionCodeArr)

          params.append('useId', useIdArr)

          params.append('assetsTypeThree', assetsTypeThreeArr)

         

          batchAssetsRegister(params).then(res => {

            if (res.code !== '0000') {

              this.$message.error(res.message)

              return

            }

            this.$router.push({ path:'/networkAccessList' }) // 返回

          })

        }

      })

    },
   

    // 使用单位

    getUse() {

      return new Promise((resolve) => {

        organizationApiManagement('GET', '', 'find').then(res => {

          const arr = [] // 全部

          if (res.code !== '0000') {

            resolve(arr)

          } else {

            res.data.list.forEach(item => {

              const k = {

                serialNo: item.serialNo,

                value: item.id,

                label: item.organizationName

              }

              arr.push(k)

              resolve(arr)

            })

          }

        })

      })

    },

  }

}

</script>

<style  scoped>

.el-dialog-register-top {

  margin-top: -30px;

  padding: 10px;

  border-bottom: 1px solid #E4E7ED;

}

.row-col-columns {

  display: flex;

  margin-left: 8px;

  div{

    padding-right: 5px;

  }

  ::v-deep .el-input.is-disabled .el-input__inner{

    color: #333;

  }



  .number{

    padding: 10px 0 0 15px;

  }

  .row-col-columns-1 {

    width: 40px;

  }

  .row-col-columns-2 {

    width: 142px;

    // width: 125px;

  }

  .row-col-columns-3 {

    width: 200px;

    // width: 175px;

  }

  .register-star {

    color: #F56C6C;

  }

}

.footer-btn {

  display: flex;

  justify-content: center;

}

</style>

           

2.厂家,品牌联级选择 manufacturerBrand.js页面,使用Promise将值返回给index.vue页面

import { organizationApiManagement } from '@/api/property/pointInterface'
import { getBrandApi } from '@/api/property/assets'

const belongBrand = async (level, id) => {
  return new Promise((resolve) => {
    console.log(level)
    if (level === 1) {
      const organizationArr = []
      // 获取所属厂家
      organizationApiManagement('GET', '', 'findList').then(res => {
        if (res.code === '0000') {
          res.data.forEach((item) => {
            const k = {
              value: item.id,
              label: item.organizationName,
              children: []
            }
            organizationArr.push(k)
          })
          const ditto = {value: "ditto" , label: '同上'}
          organizationArr.push(ditto)
          resolve(organizationArr)
        } else {
          resolve(organizationArr)
        }
      })
    } else if (level === 2) {
      if (id === 'ditto') { // 如果厂家选中为同上,厂家数据只有同上
        const val = [{ value: 'ditto', label: '同上', children: [], leaf: true }]
        resolve(val)
      } else {
        const arr = []
        const params = {
          factoryId: id
        }
        // 获取品牌
        getBrandApi(params).then(res => {
          if (res.code === '0000') {
            res.data.forEach(item => {
              const k = {
                value: item.id,
                label: item.typeName,
                children: [],
                leaf: true
              }
              arr.push(k)
            })
            resolve(arr)
          } else {
            resolve(arr)
          }
        })
      }
    }
  })
}
export { belongBrand }
           

4. 完成页面

动态循环表单,同时进行表单验证
动态循环表单,同时进行表单验证

如有不懂可以询问,我看到的话必回

继续阅读