<template>
  <!--form表单组件-->
  <el-form
    v-if="model"
    ref="formRef"
    class="def-form"
    :model="model"
    statusIcon
    :validate-on-rule-change="false"
    v-bind="$attrs">
    <slot name="formHeader"></slot>
    <!--响应式栅格布局-->
    <el-row :gutter="layout.gutter">
      <template v-for="item in list" :key="item.prop">
        <el-col
          v-if="!item.hidden"
          :offset="layout.offset || item.layout?.offset"
          :span="item.layout?.span || layout.span"
          :xs="item.layout?.xs || layout.xs"
          :sm="item.layout?.sm || layout.sm"
          :md="item.layout?.md || layout.md"
          :lg="item.layout?.lg || layout.lg"
          :xl="item.layout?.xl || layout.xl">
          <el-form-item
            :label="item.label"
            :prop="item.prop"
            :labelWidth="item.labelWidth"
            :required="item.required"
            :rules="item.rules"
            :error="item.error"
            :showMessage="item.showMessage"
            :inlineMessage="item.inlineMessage"
            :style="item.style">
            <!--表单按钮处理-->
            <template v-if="item.element === 'el-button'">
              <!--action自定义按钮-->
              <template v-if="item.action && item.action.length">
                <template v-for="subItem in item.action" :key="subItem.event">
                  <component
                    v-if="!subItem.hidden"
                    :is="item.element"
                    :type="subItem.type"
                    :size="subItem.size"
                    :disabled="subItem.disabled"
                    @click="handleEvent(subItem.event)">
                    <def-icon
                      v-if="subItem.icon"
                      :icon="subItem.icon"
                      :style="{ fontSize: subItem.iconSize + 'px' }" />
                    <span style="margin-left: 5px">{{ subItem.label }}</span>
                  </component>
                </template>
              </template>
              <!--默认按钮-->
              <template v-else>
                <el-button v-if="!item.hiddenSubmit" type="primary" @click="handleEvent('submit')">
                  <def-icon icon="CircleCheck" />
                  <span style="margin-left: 5px">确认</span>
                </el-button>
                <el-button v-if="!item.hiddenSearch" type="success" @click="handleEvent('search')">
                  <def-icon icon="Search" />
                  <span style="margin-left: 5px">查询</span>
                </el-button>
                <el-button v-if="!item.hiddenReset" @click="handleEvent('reset')">
                  <def-icon icon="RefreshRight" />
                  <span style="margin-left: 5px">重置</span>
                </el-button>
                <el-button v-if="!item.hiddenClear" type="danger" @click="handleEvent('clear')">
                  <def-icon icon="CircleClose" />
                  <span style="margin-left: 5px">清空</span>
                </el-button>
              </template>
            </template>
            <!--表单项处理-->
            <template v-else>
              <!--级联选择器单独处理-->
              <template v-if="item.element === 'el-cascader'">
                <component
                  :is="item.element"
                  v-model="model[item.prop]"
                  :options="item.children"
                  v-bind="item.elementAttrs"></component>
              </template>
              <!--图标选择器-->
              <template v-else-if="item.element === 'def-icon-picker'">
                <component
                  ref="iconPickerRef"
                  :is="item.element"
                  v-model:iconName="model[item.prop]"
                  v-bind="item.elementAttrs"></component>
              </template>
              <!--行政区选择器-->
              <template v-else-if="item.element === 'def-region-picker'">
                <component
                  ref="regionPickerRef"
                  :is="item.element"
                  v-model:region="model[item.prop]"
                  v-bind="item.elementAttrs"></component>
              </template>
              <!--wangEditor富文本编辑器-->
              <template v-else-if="item.element === 'def-editor'">
                <component
                  ref="editorRef"
                  :is="item.element"
                  v-model:content="model[item.prop]"
                  v-bind="item.elementAttrs"></component>
              </template>
              <!--上传组件-->
              <template v-else-if="item.element === 'def-upload'">
                <component
                  ref="uploadRef"
                  :is="item.element"
                  v-model:fileList="model[item.prop]"
                  v-bind="item.elementAttrs"></component>
              </template>
              <!--其他表单项-->
              <template v-else>
                <component :is="item.element" v-model="model[item.prop]" v-bind="item.elementAttrs">
                  <template v-if="item.children && item.children.length">
                    <template v-for="subItem in item.children" :key="subItem.value">
                      <!--单选框 radio / 多选框 checkbox 特殊处理-->
                      <template
                        v-if="item.subElement === 'el-radio' || item.subElement === 'el-checkbox'">
                        <component :is="item.subElement" :label="subItem.value">
                          <slot v-if="subItem.label">{{ subItem.label }}</slot>
                        </component>
                      </template>
                      <template v-else>
                        <component
                          :is="item.subElement"
                          :label="subItem.label"
                          :value="subItem.value"></component>
                      </template>
                    </template>
                  </template>
                </component>
              </template>
            </template>
          </el-form-item>
        </el-col>
      </template>
    </el-row>
    <slot name="formFooter"></slot>
  </el-form>
</template>

<script lang="ts" setup>
import { PropType, ref, watchEffect } from 'vue'
import { IFormItem, ILayout, TActionEvent } from './types'
import { ElMessage, FormInstance, FormRules } from 'element-plus/es'

/* 参数声明 */
const props = defineProps({
  data: {
    // 表单回显数据
    type: Object,
    default: () => null
  },
  list: {
    // 表单项配置数组
    type: Array as PropType<IFormItem[]>,
    required: true
  },
  layout: {
    // 表单整体布局
    type: Object as PropType<ILayout>,
    default: () => ({})
  }
})
/* 事件声明 */
const emits = defineEmits(['submit', 'search', 'reset', 'clear'])

/* 表单处理 */
const formRef = ref<FormInstance>()
const model = ref<Record<string, any>>({})
const rules = ref<FormRules>({})
// 初始化表单
const initForm = () => {
  if (!props.list || !props.list.length) return
  props.list.forEach((item) => {
    if (item.element === 'el-button') return
    model.value[item.prop] = item.value
    if (item.rules) rules.value[item.prop] = item.rules
  })
}
watchEffect(() => {
  if (props.data) {
    model.value = props.data
    return
  }
  initForm()
})

// 确认/查询/重置 action 事件处理
const handleEvent = async (event: TActionEvent) => {
  switch (event) {
    case 'submit':
      console.log('确认')
      await formRef.value?.validate((valid) => {
        if (valid) {
          ElMessage.success('操作成功')
          emits('submit', model.value)
        } else {
          ElMessage.error('表单输入不完整')
          emits('submit', null)
        }
      })
      break
    case 'search':
      console.log('查询')
      emits('search', model.value)
      break
    case 'reset':
      console.log('重置/取消')
      initForm()
      handleClear()
      emits('reset')
      break
    case 'clear':
      console.log('清空/取消')
      // 清空表单内容
      handleClear()
      formRef.value?.resetFields()
      emits('clear')
      break
  }
}
// 获取组件实例
const editorRef = ref<any>()
const iconPickerRef = ref<any>()
const regionPickerRef = ref<any>()
const uploadRef = ref<any>()
// 清空组件内容
const handleClear = () => {
  // 清空
  iconPickerRef.value[0].clear()
  regionPickerRef.value[0].clear()
  editorRef.value[0].clear()
  uploadRef.value[0].clear()
}
</script>

<style scoped lang="scss">
.def-form {
  min-width: 400px;
  .el-col {
    margin: 5px 0;
  }
  :deep(.el-form-item) {
    .el-form-item__label {
      font-weight: 700;
    }
    .el-form-item__content {
      // 继承el-form-item样式来调整按钮位置
      justify-content: inherit;
      .el-textarea {
        height: 100%;
      }
      .el-textarea__inner {
        height: 100%;
      }
      .el-rate__item {
        line-height: normal;
      }
    }
  }
  :deep(.el-button) {
    // 解决按钮点击后移开鼠标颜色仍然聚焦的解决方法
    &:focus {
      color: var(--el-button-text-color);
      background-color: var(--el-button-bg-color);
      border: var(--el-border);
      border-color: var(--el-button-border-color);
    }
    &:hover {
      color: var(--el-button-hover-text-color);
      background-color: var(--el-button-hover-bg-color);
      border-color: var(--el-button-hover-border-color);
      outline: 0;
    }
  }
}
</style>
