<template>
  <el-form
    ref="form"
    v-loading="loading"
    class="th-form"
    :label-width="labelWidth"
    :model="data"
    :rules="rules"
    :size="size"
    v-bind="getProps"
  >
    <!-- 顶部插槽 -->
    <slot name="header" />
    <!-- 防止密码自动填写 -->
    <input type="password" style="position: absolute;z-index: -1;width:0;opacity:0;" />
    <input type="text" style="position: absolute;z-index: -1;width:0;opacity:0;" />

    <!-- 表单项列表 -->
    <template v-for="(item, index) in items">
      <transition :key="index" name="fade" mode="out-in">
        <!-- 是否隐藏 -->
        <template v-if="onShow(item)">
          <!-- 标题 -->
          <th-form-title
            v-if="item.component === 'title'"
            :style="item.style"
            :class="item.class"
            v-bind="item.props"
          />

          <!-- 纯文本 -->
          <th-form-item
            v-else-if="item.component === 'text'"
            v-bind="item"
          >
            <span
              class="th-form-item--text"
              v-bind="item.props"
            >{{ data[item.prop] }}</span>
          </th-form-item>

          <!-- 输入框+按钮 -->
          <th-form-item
            v-else-if="item.component === 'input-button'"
            v-bind="item"
          >
            <el-input
              v-model="data[item.prop]"
              class="th-input-button-group"
              v-bind="item.props"
              @change="handleChange($event, item)"
            >
              <el-button
                slot="suffix"
                type="primary"
                v-bind="item.buttonProps"
                @click="(e) => item.buttonClick && item.buttonClick(e)"
              >{{ item.buttonText }}</el-button>
            </el-input>
          </th-form-item>

          <!-- 下拉选择 -->
          <th-form-item
            v-else-if="item.component === 'select'"
            v-bind="item"
          >
            <th-select
              v-model="data[item.prop]"
              v-bind="item.props"
              :options="(item.options || options[item.prop] || [])"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 级联选择 -->
          <th-form-item
            v-else-if="item.component === 'cascader'"
            v-bind="item"
          >
            <el-cascader
              v-model="data[item.prop]"
              :disabled="item.disabled||false"
              :options="(item.options || options[item.prop] || [])"
              :show-all-levels="item.showAllLevels||false"
              v-bind="item.props"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 多选框组 -->
          <th-form-item
            v-else-if="item.component === 'checkbox-group'"
            v-bind="item"
            class-name="th-form-item--checkbox-group"
          >
            <el-checkbox-group v-model="data[item.prop]" @change="handleChange($event, item)">
              <el-checkbox
                v-for="option in (item.options instanceof Array ? item.options : options[item.prop] instanceof Array ? options[item.prop] : [])"
                :key="option[item.optionValue || 'value']"
                :label="option[item.optionValue || 'value']"
                v-bind="item.props"
              >{{ option[item.optionLabel || 'label'] }}</el-checkbox>
            </el-checkbox-group>
          </th-form-item>

          <!-- 单选框组 -->
          <th-form-item
            v-else-if="item.component === 'radio-group'"
            class-name="th-form-item--radio-group"
            v-bind="item"
          >
            <el-radio-group v-model="data[item.prop]" @change="handleChange($event, item)">
              <el-radio
                v-for="option in (item.options || options[item.prop] || [])"
                :key="option[item.optionValue || 'value']"
                :label="option[item.optionValue || 'value']"
              >{{ option[item.optionLabel || 'label'] }}</el-radio>
            </el-radio-group>
          </th-form-item>

          <!-- 日期 -->
          <th-form-item
            v-else-if="item.component === 'date'"
            v-bind="item"
          >
            <el-date-picker
              v-model="data[item.prop]"
              :size="size"
              v-bind="{
                clearable: true,
                type: 'datetime', // year/month/date/week/ datetime/datetimerange/daterange
                isRange: false,
                valueFormat: (/time/ig).test(item.props && item.props.type || 'datetime') ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd',
                placeholder: '选择日期',
                rangeSeparator: '至',
                startPlaceholder: '开始日期',
                endPlaceholder: '结束日期',
                ...item.props
              }"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 时间 -->
          <th-form-item
            v-else-if="item.component === 'time'"
            v-bind="item"
          >
            <el-time-picker
              v-model="data[item.prop]"
              :size="size"
              v-bind="{
                clearable: true,
                valueFormat: 'HH:mm:ss',
                placeholder: '选择时间',
                ...item.props
              }"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 切换开关 -->
          <th-form-item
            v-else-if="item.component === 'switch'"
            v-bind="item"
          >
            <el-switch
              v-model="data[item.prop]"
              v-bind="item.props"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 文件上传 -->
          <th-form-item
            v-else-if="item.component === 'file-upload'"
            v-bind="item"
          >
            <th-file-upload
              :ref="item.prop"
              v-model="data[item.prop]"
              :filed="item.prop"
              v-bind="item.props"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 标签文本框 -->
          <th-form-item
            v-else-if="item.component === 'textarea-tags'"
            v-bind="item"
          >
            <th-textarea-tags
              v-model="data[item.prop]"
              v-bind="item.props"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 树型输入框 -->
          <th-form-item
            v-else-if="item.component === 'input-tree'"
            v-bind="item"
          >
            <th-input-tree
              v-model="data[item.prop]"
              v-bind="item.props"
              :options="(item.options || options[item.prop] || [])"
              @change="handleChange($event, item)"
            />
          </th-form-item>

          <!-- 自定义插槽 -->
          <th-form-item
            v-else-if="item.component === 'slot'"
            v-bind="item"
          >
            <slot :name="item.prop" :data="data" :item="item" />
          </th-form-item>

          <!-- 输入框 -->
          <th-form-item
            v-else
            v-bind="item"
          >
            <el-input
              v-model="data[item.prop]"
              v-bind="item.props"
              @change="handleChange($event, item)"
            />
          </th-form-item>

        </template>
      </transition>
    </template>

    <!-- 按钮组 -->
    <th-form-item
      v-if="$length(buttons)"
      class="th-form--buttons"
    >
      <template v-for="(item, index) in buttons">
        <el-button
          v-if="onShow(item)"
          :key="index"
          :size="size"
          :disabled="item.disabled"
          v-bind="{
            type: 'primary',
            ...item.props
          }"
          @click="handleSubmit(item)"
        >{{ item.label }}</el-button>
      </template>
    </th-form-item>
    <!-- 底部插槽 -->
    <slot name="footer" />
  </el-form>
</template>

<script>
import { deepClone } from '../../../src/utils/util.js'
export default {
  name: 'ThForm',
  props: {
    // 加载状态
    loading: {
      type: Boolean,
      default: false
    },
    // 文字宽度
    labelWidth: {
      type: String,
      default: '120px'
    },
    // 表单属性
    props: {
      type: Object,
      default: () => ({})
    },
    // 提交按钮
    buttons: {
      type: Array,
      default: () => [
        // {
        //   label: '提交',
        //   key: 'submit'
        // }
      ]
    },
    // 表单数据
    data: {
      type: Object,
      default: () => ({})
    },
    // 表单项
    items: {
      type: Array,
      default: () => []
    },
    // 规则
    rules: {
      type: Object,
      default: () => ({})
    },
    // 下拉选项
    options: {
      type: Object,
      default: () => ({})
    },
    // 表单项大小
    size: {
      type: String,
      default: 'mini'
    },
    // 是否搜索表单
    isSearch: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    getProps() {
      const props = {
        labelSuffix: ':',
        inlineMessage: false,
        ...this.props
      }
      if (this.isSearch) {
        props.inline = true
        if (Array.isArray(props.class)) {
          props.class.push('is-search')
        } else {
          props.class = [props.class || '', 'is-search']
        }
      }
      return props
    }
  },
  methods: {
    // 表单项改变事件
    handleChange($event, item) {
      this.$emit('handleChange', $event, item, this.data)
    },
    // 清空校验
    clearValidate() {
      this.$refs.form.clearValidate()
    },
    // 清空某项检验
    clearValidateItem(name) {
      this.$refs.form.clearValidate(name)
    },
    // 重置表单
    resetFields() {
      this.$refs.form.resetFields()
    },
    // 提交按钮
    handleSubmit(btn) {
      const data = deepClone(this.data)
      if (btn && btn.skip) {
        this.$emit('handleSubmit', data, btn)
        return
      }
      this.$refs.form.validate(valid => {
        if (valid) {
          this.$emit('handleSubmit', data, btn)
          if (btn && btn.reset) {
            this.resetFields()
          }
        } else {
          return false
        }
      })
    },
    // 判断是否显示
    onShow(item) {
      return item.show instanceof Function ? item.show(this.data) : true
    }
  }
}

</script>
