天天看點

動态循環表單,同時進行表單驗證

出現的問題

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. 完成頁面

動态循環表單,同時進行表單驗證
動态循環表單,同時進行表單驗證

如有不懂可以詢問,我看到的話必回

繼續閱讀