vue element ui vfor表单验证

vue yekong 1257℃

vue element ui 表单验证规则需要从接口获取,所以rules就需要动态设置了。将自己遇到的问题和解决办法记录一下,方便后期遇到类似的问题可以直接拿来用。
vue element ui vfor表单验证

使用

<template>
  <div class="guidance">
    <headers></headers>
    <div class="guidancebody">
      <div class="guidancebodyhead">
        <el-breadcrumb separator-class="el-icon-arrow-right">
          <el-breadcrumb-item :to="{ path: '/' }">业务办理</el-breadcrumb-item>
          <el-breadcrumb-item>业务申请</el-breadcrumb-item>
        </el-breadcrumb>
      </div>
      <div class="applyTitle">
        学历学位证书翻译申请单
      </div>
      <div class="instructions">
        <div class="instructionsTitle">
          <img src="../assets/tips.png" alt="">
          办理须知
        </div>
        <div class="instructionsInfo">
          <p>1.请上传毕业证书、学位证书扫描电子件;</p>
          <p>2.请填写姓名、学号或班号、身份证号;</p>
        </div>
      </div>
      <div class="formBody">
        <el-form :label-position="labelPosition" label-width="80px">
          <div class="formData">
            <el-form-item label="办理方式">
              <el-radio-group v-model="transactManner">
                <el-radio :label="0">发送电子档</el-radio>
                <el-radio :label="1">邮寄纸质档</el-radio>
                <el-radio :label="2">现场领取</el-radio>
              </el-radio-group>
            </el-form-item>
          </div>
        </el-form>
      </div>
      <div class="formBody classFormBody">
        <div class="formData noborder">
          <div class="maxTitle">基本信息</div>
        </div>
        <div class="formBodyInner">
          <vform class="formBodyInnerItem" :item="item" v-for="(item,index) in applyForms"
                 :key="index" :ref="'vform'+index"></vform>
        </div>
      </div>
      <div v-if="transactManner===1" class="formBody classFormBody">
        <el-form :label-position="labelPosition" label-width="80px">
          <el-form-item label="邮寄地址" class="w100x mr0">
            <el-input placeholder="请输入" v-model="mailAddress"></el-input>
          </el-form-item>
        </el-form>
      </div>
      <div class="formBody classFormBody">
        <div class="formData noborder">
          <div class="maxTitle">材料信息</div>
        </div>
        <div class="tablelist">
          <el-table
            :data="applyCosts"
            highlight-current-row
            stripe
            border
            style="width: 100%">
            <el-table-column
              prop="costName"
              align="center"
              width="100"
              show-overflow-tooltip
              label="材料名称">
            </el-table-column>
            <el-table-column
              prop="baseCount"
              label="办理份数"
              show-overflow-tooltip
              align="left">
              <template slot-scope="scope">
                <el-input-number :min="scope.row.minTransactCount" controls-position="right" v-model="scope.row.number"
                                 :max="scope.row.maxTransactCount"></el-input-number>
              </template>
            </el-table-column>
            <el-table-column
              prop="name"
              show-overflow-tooltip
              label="总价(元)"
              align="left">
              <template slot-scope="scope">
                <totalPrice :totalPrice.sync="scope.row.totalPrice" :row="scope.row"></totalPrice>
              </template>
            </el-table-column>
            <el-table-column
              prop="remark"
              show-overflow-tooltip
              label="备注"
              align="left">
            </el-table-column>
          </el-table>
          <div class="combined">
            <p>合计:<span>{{ heji }}元</span></p>
          </div>
        </div>
      </div>
      <div class="formBody">
        <el-form :label-position="labelPosition" label-width="80px">
          <el-form-item label="请上传以下证明材料">
            <uploadFile></uploadFile>
          </el-form-item>
          <el-form-item label="留言信息">
            <el-input placeholder="请输入" type="textarea" v-model="remark"></el-input>
          </el-form-item>
        </el-form>
      </div>
      <div class="next">
        <div class="nextBut" @click="saveData">
          下一步
        </div>
      </div>
    </div>
    <footers></footers>
  </div>
</template>

<script>
import headers from "@/components/header";
import footers from "@/components/footer";
import {getFormAndCost, transactSave} from "@/api/api/user";
import uploadFile from "@/components/uploadFile";
import totalPrice from "@/views/TotalPrice";
import vform from "@/views/apple/vform";

export default {
  name: "home",
  components: {headers, footers, uploadFile, totalPrice, vform},
  props: {
    id: {
      type: String,
      default() {
        return ''
      }
    }
  },
  data() {
    return {
      list: [],
      labelPosition: 'top',
      businessId: this.$route.query.businessId,
      applyCosts: [],
      applyForms: [],
      remark: '',
      mailAddress: '',
      transactManner: 0
    }
  },
  watch: {},
  mounted() {
    new this.$wow.WOW().init()
    this.getData()
  },
  // 合计
  computed: {
    heji() {
      var list = this.applyCosts
      var heji = 0
      list.forEach((type) => {
        heji = heji + type.totalPrice
      });
      return heji
    }
  },
  methods: {
    getData() {
      var that = this
      getFormAndCost({businessId: this.businessId, transactManner: 0}).then((res) => {
        if (res.code == 1) {
          that.applyForms = res.data.applyForms
          that.applyCosts = []
          var list = res.data.applyCosts
          list.forEach((type) => {
            var data = {
              applyCost: type.applyCost,
              number: 1,
              totalPrice: 0,
              baseCount: type.baseCount,
              basePrice: type.basePrice,
              costCode: type.costCode,
              costInformation: type.costInformation,
              costName: type.costName,
              createDate: type.createDate,
              createUserId: type.createUserId,
              id: type.id,
              isCost: type.isCost,
              lastOperateUserId: type.lastOperateUserId,
              maxTransactCount: type.maxTransactCount,
              minTransactCount: type.minTransactCount,
              pid: type.pid,
              remark: type.remark,
              removeDate: type.removeDate,
              restoreDate: type.restoreDate,
              scopes: type.scopes,
              state: type.state,
              unitPrice: type.unitPrice,
              updateDate: type.updateDate,
              version: type.version,
            }
            that.applyCosts.push(data)
          });
        }
      })
    },
    goback() {
      this.$router.go(-1)
    },
    // 保存
    saveData() {
      var that = this
      var applyCosts = []
      that.applyCosts.forEach((type) => {
        var data = {
          costName: type.costName,
          costCode: type.costCode,
          costCount: type.number,
          totalPrice: type.totalPrice
        }
        applyCosts.push(data)
      });
      var applyBaseInfo = {}
      // 校验数据
      try {
        var check = true
        that.applyForms.forEach((type, index) => {
          if (type.fieldValue) {
            applyBaseInfo[type.id] = type.fieldValue
          }
          if (!that.$refs[`vform${index}`][0].submitForm('ruleForm')) {
            check = false
          }
        });
      } catch (e) {
        console.log(e)
      }
      console.log(check)
      if (!check) {
        return
      }
      // 校验数据
      that.applyForms.forEach((type, index) => {
        applyBaseInfo[type.id] = that.$refs[`vform${index}`][0].getFormData() + ''
      });
      transactSave({
        businessId: that.businessId,
        transactManner: that.transactManner,
        mailAddress: that.mailAddress,
        applyFileIds: that.applyFileIds,
        applyBaseInfo: applyBaseInfo,
        applyCosts: applyCosts,
        remark: that.remark
      }).then((res) => {
          if (res.code == 1) {
            that.$message({
              message: '提交成功',
              type: 'success'
            });
            that.goback()
          }
        }
      )
    }
  }
}
</script>

<style lang="scss" scoped>
.guidance {
  background: #F4F5F8;
  min-height: 100%;
  padding-top: 24px;
  padding-bottom: 50px;
  width: 100%;
}

.guidancebodyhead {
  width: 1144px;
  margin: 0 auto;
  height: 69px;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: row;
  border-bottom: 1px solid rgba(238, 238, 238, 1);

  span {
    font-size: 14px;
    font-family: PingFangSC-Medium, PingFang SC;
    font-weight: 400;
  }

  ::v-deep {
    .el-breadcrumb__inner a, .el-breadcrumb__inner.is-link {
      font-weight: 400;
    }
  }
}

.guidancebody {
  width: 1200px;
  position: relative;
  background: #FFFFFF;
  box-shadow: 0px 11px 58px 0px rgba(121, 129, 140, 0.06);
  border-radius: 16px;
  margin: 25px auto 16px auto;
}

.applyTitle {
  height: 72px;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: row;
  margin-left: 28px;
  align-content: flex-start;
  font-size: 22px;
  font-family: PingFangSC-Medium, PingFang SC;
  font-weight: 500;
  color: rgba(0, 0, 0, 0.85);
}

.instructions {
  background: rgba(#3379EF, 0.05);
  border-radius: 4px;
  margin: auto;
  margin-left: 28px;
  margin-right: 28px;
  min-height: 100px;
  padding: 20px;

  .instructionsTitle {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: row;
    align-content: flex-start;
    margin-bottom: 10px;

    img {
      width: 18px;
      margin-right: 3px;
    }
  }

  .instructionsInfo {
    font-size: 14px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: rgba(0, 0, 0, 0.65);
    line-height: 30px;
  }
}

.next {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: row;
  align-content: flex-start;

  .nextBut {
    width: 320px;
    height: 48px;
    cursor: pointer;
    background: #3379EF;
    border-radius: 4px;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: nowrap;
    flex-direction: row;
    align-content: flex-start;
    font-size: 14px;
    font-family: PingFangSC-Medium, PingFang SC;
    font-weight: 500;
    color: #FFFFFF;
    margin-top: 50px;
    margin-bottom: 30px;
  }
}

.formBody {
  margin-left: 28px;
  margin-right: 28px;

  .formData {
    width: 100%;
    border-bottom: 1px solid rgba(238, 238, 238, 1);
  }
}

.maxTitle {
  font-size: 18px;
  font-family: PingFangSC-Medium, PingFang SC;
  font-weight: 500;
  color: rgba(0, 0, 0, 0.85);
  padding-top: 20px;
  padding-bottom: 20px;
}

.classFormBody {
  ::v-deep {
    .el-form {
      display: flex;
      justify-content: flex-start;
      align-items: flex-start;
      flex-wrap: wrap;
      flex-direction: row;
      align-content: flex-start;
    }
  }
}

.combined {
  border: 1px solid #F0F0F0;
  border-top: 0;
  height: 61px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  flex-wrap: nowrap;
  flex-direction: row;
  align-content: flex-start;
  padding-right: 22px;

  p {
    color: rgba(106, 106, 106, 1);

    span {
      color: rgba(255, 65, 63, 1);
    }
  }
}

.formBodyInner {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  flex-wrap: wrap;
  flex-direction: row;
  align-content: flex-start;

  .formBodyInnerItem {
    width: 33.33%;
  }
}
</style>

组件

/**
* @Author: 858834013@qq.com
* @Name: vform
* @Date: 2022-05-30
* @Desc: 表单验证 vfor
*/
<template>
  <div class="elForm">
    <el-form v-if="show" :model="applyForm" :rules="rules" ref="ruleForm" label-position="top" label-width="80px">
      <el-form-item :label="item.fieldName" prop="value">
        <!--            没有枚举值-->
        <el-input v-if="item.isEnumeration==0" placeholder="请输入" v-model="applyForm.value"></el-input>
        <!--            有枚举值 下拉选择-->
        <el-select class="w100x" v-model="applyForm.value" :multiple="item.isMulti?true:false"
                   v-if="item.isEnumeration==1"
                   placeholder="请选择">
          <el-option
            v-for="items in enumerationValue"
            :key="items"
            :label="items"
            :value="items">
          </el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </div>
</template>

<script>

export default {
  name: "vform",
  components: {},
  props: {
    item: {
      type: Object,
      default() {
        return ''
      }
    }
  },
  data() {
    return {
      show: false,
      enumerationValue: [],
      rules: {
        value: []
      },
      applyForm: {
        value: ''
      }
    }
  },
  watch: {
    item: {
      handler(newVal) {
        this.getdata()
      },
      deep: true
    },
  },
  mounted() {
    this.getdata()
  },
  methods: {
    submitForm(formName) {
      var that = this;
      var data = false
      that.$refs[formName].validate((valid) => {
        if (valid) {
          data = true
        } else {
          console.log('error submit!!');
          data = false
        }
      });
      return data
    },
    getFormData() {
      return this.applyForm.value
    },
    getdata() {
      var that = this;
      that.show = false
      // 如果有枚举值
      if (that.item.enumerationValue) {
        that.enumerationValue = that.item.enumerationValue.split(",")
      }
      // 校验规则
      that.rules.value = []
      // 必填校验
      if (that.item.isMust && !that.item.isEnumeration) {
        var rule = {required: true, message: '请输入' + that.item.fieldName}
        that.rules.value.push(rule)
      }
      // 长度校验
      if (that.item.minCharacterCount && that.item.maxCharacterCount) {
        var rule = {
          min: that.item.minCharacterCount,
          max: that.item.maxCharacterCount,
          message: '长度在 ' + that.item.minCharacterCount + ' 到 ' + that.item.maxCharacterCount + ' 个字符',
          trigger: 'blur'
        }
        that.rules.value.push(rule)
      }
      if (that.item.minCharacterCount && !that.item.maxCharacterCount) {
        var rule = {
          min: that.item.minCharacterCount,
          message: '长度不能小于 ' + that.item.minCharacterCount + ' 个字符',
          trigger: 'blur'
        }
        that.rules.value.push(rule)
      }
      if (!that.item.minCharacterCount && that.item.maxCharacterCount) {
        var rule = {
          min: that.item.maxCharacterCount,
          message: '长度不能大于 ' + that.item.maxCharacterCount + ' 个字符',
          trigger: 'blur'
        }
        that.rules.value.push(rule)
      }
      that.$nextTick(() => {
        that.show = true
      })
    }
  }
}
</script>

<style lang="scss" scoped>


.elForm {
  width: 100%;

  .el-form-item {
    width: calc(100% - 60px);
    margin-right: 60px;
  }
}
</style>

喜欢 (0)