<template>
  <el-form v-bind="$attrs" v-on="$listeners" :validate-on-rule-change='false' ref="form" :rules="getRules()" :model="form" :label-width="$attrs.labelWidth || '120px'" :disabled="$attrs.disabled">
    <el-row :gutter="20" type="flex" class="wrap">
      <template v-for="(item, index) in config">
        <el-col :span="item.span || 24" :key="item.label" :class="{'display-none':item.hideShow}" v-if="!item.hide && !(item.hideFun && item.hideFun(form))">
          <hoc :item="item" :formData="form" :ref="formatRef(index)"></hoc>
        </el-col>
      </template>
    </el-row>
  </el-form>
</template>

<script>
import { hoc } from "../Base/BaseItemHoc";
let uuid = 0; // 给ref提供唯一性

export default {
  name: "mgForm",
  components: {
    hoc: hoc(),
  },
  props: {
    rules: {
      type: Object,
      default: function () {
        return {};
      },
    },
    config: {
      type: Array,
      required: true,
    },
    form: {
      type: Object,
      default: function () {
        return {};
      },
    },
  },
  data() {
    return {
      formsList: {}, // 存储form对应的ref的值
      errorMsgList: [], // 存放错误信息的数组
    };
  },
  created() { },
  mounted() { },
  methods: {
    getRules() {
      let self = this;
      let rules = JSON.parse(JSON.stringify(this.rules));
      Object.keys(rules).forEach((key) => {
        rules[key].forEach((item) => {
          item.pattern = eval(item.pattern);
        });
      });

      this.config.forEach((res) => {
        rules[res.prop] = rules[res.prop] || [];
        if (res.required) {
          let validatePass = (rule, value, callback) => {
            if (
              self.form[res.prop] === "" ||
              self.form[res.prop] === undefined
            ) {
              callback(new Error("请输入" + res.label));
            } else {
              callback();
            }
          };
          rules[res.prop].push({
            required: true,
            validator: validatePass,
            trigger: "blur",
          });
        }
        if (res.min || res.max) {
          rules[res.prop].push({
            min: res.min || 0,
            max: res.max || 9999,
            message: "请输入长度在" + res.min + "到" + res.max + "字符",
          });
        }
        if (res.ruleType) {
          rules[res.prop].push({
            type: res.ruleType,
            message: res.msg || `请输入正确的格式`,
          });
        }
        if (res.mobile) {
          rules[res.prop].push({
            pattern: /^1[3456789]{1}\d{9}$/,
            message: `请输入正确的手机格式`,
          });
        }
        if (res.price) {
          rules[res.prop].push({
            pattern: /(^[1-9]\d*(\.\d{1,2})?$)|(^0(\.\d{1,2})?$)/,
            message: `请输入正确的价格`,
          });
        }
        if (res.number) {
          rules[res.prop].push({
            pattern: /^[0-9]{0,9}$/,
            message: `请输入9位以内整数`,
          });
        }
      });
      return rules;
    },
    formatRef(index) {
      ++uuid;
      let key = +new Date();
      const ref = "suiteForm" + key + uuid;
      this.formsList[index] = ref;
      return ref;
    },
    /** 对整个表单进行校验的方法 todo 改成用rules自定义验证调用动态组件 */
    validate(formSuite) {
      let self = this;
      self.errorMsgList = [];
      // this.$forceUpdate()
      return new Promise((resolve, reject) => {
        let success = 0; // 表单验证成功的个数
        self.$refs.form.validate((valid, invalidFields) => {
          for (let i in self.config) {
            if (self.config[i].type && self.config[i].type.indexOf("s-") > -1) {
              // 进入mgSuite组件
              self.$refs[self.formsList[i]]
                .validate()
                .then((successMessage) => {
                  ++success; // mgSuite表单验证成功的个数
                  if (
                    i * 1 === self.config.length - 1 &&
                    success === self.config.length
                  ) {
                    // 当前组件套的表单校验完成，且全部通过
                    resolve(successMessage);
                  }
                  // 此处也需要判断，是因为当前组件套的校验成功，但不能保证其他的组件套也成功
                  if (
                    i * 1 === self.config.length - 1 &&
                    !formSuite &&
                    self.errorMsgList.length > 0
                  ) {
                    self.$message.error(self.errorMsgList[0]);
                  }
                })
                .catch((errorMessage) => {
                  self.errorMsgList.push(errorMessage);
                  if (
                    i * 1 === self.config.length - 1 &&
                    !formSuite &&
                    self.errorMsgList.length > 0
                  ) {
                    self.$message.error(self.errorMsgList[0]);
                  }
                  reject(errorMessage);
                });
            } else {
              // 不是mgSuite，进行基础表单的校验
              if (valid) {
                ++success;
                if (
                  i * 1 === self.config.length - 1 &&
                  success === self.config.length
                ) {
                  // 基础表单的校验完成，且全部通过
                  resolve(self.form);
                }
              } else {
                const errorMessage = Object.values(invalidFields)[0][0].message;
                self.errorMsgList.push(errorMessage);
                if (
                  i * 1 === self.config.length - 1 &&
                  !formSuite &&
                  self.errorMsgList.length > 0
                ) {
                  self.$message.error(self.errorMsgList[0]);
                }
                reject(errorMessage);
              }
            }
          }
        });
      });
    },
    // async submit() {
    //   try {
    //     const formData = await this.$refs.form.validate();
    //     this.$emit("submit", formData);
    //   } catch (error) { }
    // },
    /** 对整个表单进行重置 */
    resetFields() {
      this.$refs.form.resetFields();
      this.$emit("reset");
    },
  },
};
</script>

<style lang="less" scoped>
.wrap {
  flex-wrap: wrap;
  width: 100%;
  justify-content: space-between;
}
::v-deep .el-select {
  width: 100%;
}
.el-radio {
  line-height: 1.5;
}
.display-none {
  display: none;
}
</style>
