<template>
  <div class="ed-form">
    <el-form ref="elForm" :model="model" :rules="rules" v-bind="$props">
      <!-- 默认插槽作为表单项 -->
      <slot/>

      <!-- 自定义插槽作为表单项 -->
      <slot :formDesc="formDesc" :model="model" :props="$props" name="form-content">
        <template v-for="(formItem, field) of formDesc">
          <!-- 自定义内容层 -->
          <slot :data="model[formItem.prop]" :desc="getFormItem(formItem)" :model="model"
                :name="formItem.prop+'Wrapper'"
                :props="$props">
            <el-form-item v-show="formItem.hasOwnProperty('isShow') ? formItem.isShow : true"
                          v-bind="getFormItem(formItem)">
              <template v-if="formItem.hasOwnProperty('tooltip')" #label>
                <span>{{ getFormItem(formItem).label }}</span>
                <el-tooltip class="item" effect="dark" placement="bottom">
                  <div slot="content">{{ formItem.tooltip }}</div>
                  <i class="el-icon-question"></i>
                </el-tooltip>
              </template>


              <!-- 具名 作用域插槽(用于用户自定义显示) -->
              <slot :data="model[formItem.prop]" :desc="formItem" :model="model" :name="formItem.prop"
                    :props="$props">
                <!-- children==array -->
                <template v-if="getVarType(formItem.children) === 'array'">
                  <template v-for="(child, index) in formItem.children">
                    <ed-form-item :key="index" v-model="model[child.prop]" :formItem="child" @input="setValue(child.prop, $event)"></ed-form-item>
                  </template>
                </template>

                <!-- children==object -->
                <template v-else-if="getVarType(formItem.children) === 'object'">
                  <ed-form-item v-model="model[formItem.prop]" :formItem="formItem.children" @input="setValue(formItem.prop, $event)"></ed-form-item>
                </template>
              </slot>

              <!-- children==string -->
              <template v-if="getVarType(formItem.children) === 'string'">{{ formItem.children }}</template>
            </el-form-item>
          </slot>
          <!-- 按钮区域 -->
          <el-form-item v-if="showBtn(formItem)" :key="field+'btn'">
            <slot :btns="formItem.btns" name="form-btn">
              <el-button v-for="(btn, index) of formItem.btns" :key="index" v-bind="btn.attrs" @click="btn.click">{{ btn.text }}</el-button>
            </slot>
          </el-form-item>
        </template>
      </slot>
    </el-form>
  </div>
</template>

<script>
import props        from './Props'
import EdFormItem   from "./components/EdFormItem";
import {getVarType} from "../../../tools/utils";

/**
 * 基础表单组件
 *
 * - 示例
 *
 * ```vue
 *
 * <ed-form ref="ElsForm" v-model="elsFormData" :form-desc="elsFormDesc" :form-rules="elsFormRules">
 * </ed-form>
 * ```
 *
 * [](./EdFormProps.md ':include')
 *
 */
export default {
  name: "EdForm",
  props: props,
  components: {EdFormItem},
  model: {
    prop: 'model',
    event: "input"
  },
  computed: {
    showBtn() {
      return (formItem) => {
        let isBtns = Object.prototype.hasOwnProperty.call(formItem, 'btns')
        let isScopedSlots = Object.prototype.hasOwnProperty.call(this.$scopedSlots, 'form-btn')
        let isSlot = Object.prototype.hasOwnProperty.call(this.$slots, 'form-btn')
        return isScopedSlots || isSlot || isBtns
      }
    },
    getFormItem() {
      return (formItem) => {
        let item = JSON.parse(JSON.stringify(formItem))
        delete item.children
        delete item.tooltip
        return item
      }
    },
  },
  methods: {
    /**
     * @private
     */
    getVarType,

    /**
     * 设置值
     * @param field
     * @param val
     */
    setValue(field, val) {
      this.$set(this.model, field, val)
      this.$emit('input', this.model)
    },

    /**
     * 验证表单
     * @returns {Promise<unknown>}
     */
    validate(callback) {
      return this.$refs.elForm.validate(callback)
    },

    /**
     * @name validateField
     * @param props
     * @param callback
     * @description 对部分表单字段进行校验的方法
     */
    validateField(props, callback) {
      this.$refs.elForm.validateField(props, callback)
    },

    /**
     * 获取数据
     * @param isValidate
     * @returns {Promise<unknown>}
     */
    getFormData(isValidate = false) {
      // eslint-disable-next-line no-async-promise-executor
      return new Promise(async (resolve, reject) => {
        try {
          isValidate ? await this.$refs.elForm.validate() : null;
          resolve(this.model)
        } catch (err) {
          reject(err)
        }
      })
    },
    /**
     * 重置表单
     */
    resetFields() {
      this.$refs.elForm.resetFields()
    },

    /**
     * @name clearValidate
     * @description 移除表单项的校验结果。传入待移除的表单项的 prop 属性或者 prop 组成的数组，如不传则移除整个表单的校验结果
     */
    clearValidate() {
      this.$refs.elForm.clearValidate()
    }
  }
}
</script>

<style lang="scss" scoped>
@import "../../../style/index";
</style>
