<!--
 * @Company: 沈阳信诚科技
 * @Email: html_venustar@163.com
 * @Author: Liuqiming
 * @Description: 公共表单组件
 * @LastEditors: Liuqiming
 * @LastEditTime: 2024-03-29 15:37:43
 * @Date: 2024-02-02 13:46:04
-->
<template>
  <div class="els-form els-form-container">
    <el-form :model="formData" ref="formRef" :inline="formOption.inline" :label-width="formOption.labelWidth" :scroll-to-error="formOption.scrollToError" v-loading="formLoading" :label-position="formOption.labelPosition">
      <template v-for="item in fieldData" :key="item.field">
        <el-form-item v-if="item.type === 'select' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :clearable="item.clearable" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-select v-model="formData[item.field]" :placeholder="item.placeholder"
            :filterable="item.filterable"
            :multiple="item.multiple"
            :collapse-tags="item.multiple"
            @change="
              () => {
                handlerNoBtn(item.field, formData[item.field])
                handlerSelectData(item, formData[item.field])
            }" :disabled="item.disabled" style="width: 100%;" :clearable="item.clearable">
            <el-option v-for="i in item.options" :key="i.value" :label="i.label" :value="i.value" :disabled="i.disabled" />
          </el-select>
        </el-form-item>
        <el-form-item v-else-if="item.type === 'cascader' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :clearable="item.clearable" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-cascader v-model="formData[item.field]" :options="item.options" :props="item.props"
            @change="
              () => {
                handlerNoBtn(item.field, formData[item.field])
            }" :disabled="item.disabled" style="width: 100%;" :clearable="item.clearable" />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'treeSelect' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :clearable="item.clearable" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-tree-select
            v-model="formData[item.field]"
            :data="item.options"
            :props="item.props ? item.props : { value: 'id', label: 'label', children: 'children' }"
            :value-key="item.props ? item.props.value : 'id'"
            :placeholder="item.placeholder"
            check-strictly
            @node-click="
              (val) => {
                handlerTreeClick(item.met, val, item.field, val[item.field])
              }
            "
            @change="
              (val) => {
                handlerNoBtn(item.field, formData[item.field])
              }
            "
            style="width: 100%;"
            :disabled="item.disabled"
            :filterable="item.filterable"
            :clearable="item.clearable"
          />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'checkbox' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-checkbox-group v-model="formData[item.field]"
            @change="
              () => {
                handlerNoBtn(item.field, formData[item.field])
            }" :disabled="item.disabled">
            <el-checkbox v-for="i in item.options" :key="i.label" :label="i.label" :disabled="i.disabled" />
          </el-checkbox-group>
        </el-form-item>
        <el-form-item v-else-if="item.type === 'radio' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-radio-group v-model="formData[item.field]"
            @change="
              () => {
                handlerNoBtn(item.field, formData[item.field])
                handlerSelectData(item, formData[item.field])
            }" :disabled="item.disabled">
            <template v-if="!item.radioButton">
              <el-radio v-for="i in item.options" :key="i.value" :label="i.value" :disabled="i.disabled" >{{ i.label }}</el-radio>
            </template>
            <template v-else>
              <el-radio-button v-for="i in item.options" :key="i.value" :label="i.value" :disabled="i.disabled" >{{ i.label }}</el-radio-button>
            </template>
          </el-radio-group>
        </el-form-item>
        <el-form-item v-else-if="item.type === 'date' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-date-picker v-if="item.enum === 'daterange'"
            v-model="formData[item.field]"
            :type="item.enum"
            range-separator="至"
            :start-placeholder="item.placeholder.split('-')[0]"
            :end-placeholder="item.placeholder.split('-')[1]"
            @change="
              () => {
                handlerNoBtn(item.field, formData[item.field])
            }"
            value-format="YYYY-MM-DD"
            :disabled="item.disabled"
            style="width: 100%;"
            :clearable="item.clearable"
          />
          <el-date-picker v-else
            v-model="formData[item.field]"
            :type="item.enum"
            :value-format="item.valueFormat || 'YYYY-MM-DD HH:mm:ss'"
            :format="item.format || 'YYYY-MM-DD HH:mm:ss'"
            :placeholder="item.placeholder"
            @change="
              () => {
                handlerNoBtn(item.field, formData[item.field])
            }"
            :disabled="item.disabled"
            style="width: 100%;"
            :clearable="item.clearable"
          />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'time' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-time-picker v-model="formData[item.field]"
          @change="
            () => {
              handlerNoBtn(item.field, formData[item.field])
            }" :placeholder="item.placeholder" :disabled="item.disabled" style="width: 100%;" :clearable="item.clearable" />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'timeRange' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-time-picker is-range v-model="formData[item.field]"
          style="width: 100%;"
          :clearable="item.clearable"
          @change="
            () => {
              handlerNoBtn(item.field, formData[item.field])
            }" range-separator="至" :start-placeholder="item.placeholder.split('-')[0]" :end-placeholder="item.placeholder.split('-')[1]" :disabled="item.disabled" />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'timeSelect' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-time-select v-model="formData[item.field]"
          style="width: 100%;"
          :clearable="item.clearable"
          @change="
            () => {
              handlerNoBtn(item.field, formData[item.field])
            }" :start="item.start || '00:00'" :step="item.step || '00:30'" :end="item.end || '23:30'" :placeholder="item.placeholder" :disabled="item.disabled" />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'switch' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-switch v-model="formData[item.field]" 
          @change="
            () => {
              handlerNoBtn(item.field, formData[item.field])
            }" :active-value="item.values[0] || 0" :inactive-value="item.values[1] || 1" :disabled="item.disabled" />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'number' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-input-number v-model="formData[item.field]"
            style="width: 100%;"
            @blur="
              () => {
                handlerNoBtn(item.field, formData[item.field])
              }"
            @keyup.enter.native="
              () => {
                handlerNoBtn(item.field, formData[item.field])
            }" controls-position="right" :min="item.min || 0" :max="item.max || 9999999999" :disabled="item.disabled" />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'textarea' && !item.hidden" :label="item.label" :rules="item.rules || null" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-input v-model="formData[item.field]" type="textarea" :maxlength="item.max"
            style="width: 100%;"
            @blur="
              () => {
                handlerNoBtn(item.field, formData[item.field])
              }"
            @keyup.enter.native="
              () => {
                handlerNoBtn(item.field, formData[item.field])
            }" :placeholder="item.placeholder" :disabled="item.disabled" />
        </el-form-item>
        <el-form-item v-else-if="item.type === 'imageUpload' && !item.hidden" :label="item.label" :rules="item.rules" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <imageUpload
            v-model="formData[item.field]"
            :uploadType="item.uploadType"
            :limit="item.limit"
            :fileSize="item.fileSize"
            :fileType="item.fileType"
            :isShowTip="item.isShowTip"
            style="width: 100%;"
            :disabled="item.disabled"
          ></imageUpload>
        </el-form-item>
        <el-form-item v-else-if="item.type === 'password' && !item.hidden" :label="item.label" :rules="item.rules" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-input v-model="formData[item.field]" :placeholder="item.placeholder" maxlength="20"
            style="width: 100%;"
            :type="'password'"
            :show-password="true"
            @blur="
            () => {
              handlerNoBtn(item.field, formData[item.field])
            }"
            @keyup.enter.native="
            () => {
              handlerNoBtn(item.field, formData[item.field])
            }" :disabled="item.disabled">
          </el-input>
        </el-form-item>
        <el-form-item v-else-if="!item.hidden" :label="item.label" :rules="item.rules" :prop="item.field" :style="{ width: item.width || 'auto' }">
          <template #label>
            {{ item.label }}
            <el-tooltip v-if="item.tooltip && item.tooltip !== ''" effect="dark" :content="item.tooltip" placement="top">
              <el-icon><InfoFilled /></el-icon>
            </el-tooltip>
          </template>
          <el-input v-model="formData[item.field]" :placeholder="item.placeholder" :maxlength="item.max"
            style="width: 100%;"
            @blur="
            () => {
              handlerNoBtn(item.field, formData[item.field])
            }"
            @keyup.enter.native="
            () => {
              handlerNoBtn(item.field, formData[item.field])
              handlerEnter(item.field, formData[item.field])
            }" :disabled="item.disabled" :clearable="item.clearable">
            <template #prepend v-if="item.prepend && item.prepend !== ''">{{ item.prepend }}</template>
            <template #append v-if="item.append && item.append !== ''">{{ item.append }}</template>
            <template #append v-if="item.searchBtn">
              <el-button type="primary" @click="handlerNoBtn(item.field, formData[item.field])">
                <el-icon><Search /></el-icon>
              </el-button>
            </template>
          </el-input>
        </el-form-item>
      </template>
      <slot name="formItem"></slot>
      <el-form-item v-if="formOption.btn && !formOption.btnCenter && formOption.btn.length > 0 && !is_view">
        <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'cancel')" @click="cancel">取消</el-button>
        <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'submit')" @click="submit" type="primary" v-preventClick="1000">确定</el-button>
        <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'search')" @click="submit" type="primary" v-preventClick="1000">搜索</el-button>
        <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'reset')" @click="cancel" v-preventClick="1000">重置</el-button>
      </el-form-item>
      <el-form-item v-if="formOption.btn && !formOption.btnCenter && formOption.btn.length > 0 && is_view">
        <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'cancel')" @click="cancel">返回</el-button>
      </el-form-item>
    </el-form>
    <!-- 按钮组 -->
    <div v-if="formOption.btn && formOption.btnCenter && formOption.btn.length > 0 && !is_view" style="width:100%;text-align: right;">
      <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'cancel')" @click="cancel">取消</el-button>
      <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'submit')" @click="submit" type="primary" v-preventClick="1000">确定</el-button>
      <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'search')" @click="submit" type="primary" v-preventClick="1000">搜索</el-button>
      <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'reset')" @click="cancel" v-preventClick="1000">重置</el-button>
    </div>
    <div v-if="formOption.btn && formOption.btnCenter && formOption.btn.length > 0 && is_view" style="width:100%;text-align: right;">
      <el-button v-if="formOption.btn && formOption.btn.find(item => item === 'cancel')" @click="cancel">返回</el-button>
    </div>
  </div>
</template>

<script setup>

const { proxy } = getCurrentInstance();
const props = defineProps({
  // 渲染的表单元素
  fieldList: {
    type: Array,
    default: () => []
  },
  // 表格基础配置
  formOption: {
    type: Object,
    default: () => {
      return {
        inline: false,
        labelPosition: 'right',
        labelWidth: '120px',
        btnCenter: false,
        scrollToError: true, // 当校验失败时，滚动到第一个错误表单项
        btn: ['search', 'reset', 'cancel', 'submit'] // 表单按钮组
      }
    }
  },
  // 回显绑定数据
  form: {
    type: Object,
    default: () => {
      return {}
    }
  },
  // 表单加载动画
  formLoading: {
    type: Boolean,
    default: false
  },
})
const emit = defineEmits();
// 表单绑定数据
const formData = ref({})
// 表单元素
const fieldData = ref([])
// 是否详情页
const is_view = ref(false)
// 设置表单绑定数据字段
const setFormData = () => {
  fieldData.value = props.fieldList
  changeFormUpdate()
  Object.keys(props.form).forEach(item => {
    formData.value[item] = props.form[item]
  })
}
const changeFormUpdate = (list = fieldData.value) => {
  list && list.forEach(item => {
    switch (item.type) {
      case 'checkbox' : 
        formData.value[item.field] = []
        break;
      case 'cascader' : 
        formData.value[item.field] = []
        break;
      case 'timeRange' : 
        formData.value[item.field] = []
        break;
      case 'radio' : // 单选框默认选中第一项
        formData.value[item.field] = item.options.filter(i => !i.disabled)[0].value
        break;
      case 'switch' : // 单选框默认选中第一项
        formData.value[item.field] = item.values[0] || 0
        break;
      case 'number' : 
        formData.value[item.field] = 0
        break;
      case 'imageUpload' : 
        formData.value[item.field] = []
        break;
      case 'treeSelect' : 
        formData.value[item.field] = ''
        break;
      default : formData.value[item.field] = ''
    }
    if (item.type === 'date' && item.enum === 'daterange') {
      formData.value[item.field] = []
    } else if (item.type === 'select' && item.multiple) {
      formData.value[item.field] = []
    }
  })
}
// 提交
const submit = () => {
  proxy.$refs.formRef.validate(valid => {
    if (valid) {
      emit('ok', formData)
    }
  })
}
// 取消，关闭
const cancel = () => {
  changeFormUpdate()
  proxy.$refs.formRef.resetFields()
  let obj = {
    value: {}
  }
  fieldData.value.forEach(i => {
    obj.value[i.field] = formData.value[i.field]
  })
  if (formData.value.pageSize || formData.value.pageNum) {
    obj.value.pageSize = formData.value.pageSize
    obj.value.pageNum = formData.value.pageNum
  }
  formData.value = obj.value
  emit('cancel', formData)
}
// 没有提交或搜索按钮时，表单的每一项发生改变触发提交
const handlerNoBtn = (field, val) => {
  if(!props.formOption.btn || !props.formOption.btn.length > 0){
    submit()
  }
  // 侦听表单元素改变事件
  emit('formChange', { field: field, val: val })
}
const handlerEnter = () => {
  submit()
}
// 下拉框特殊处理,同时返回名称和id
const handlerSelectData = (data, val) => {
  const selectVal = data.options.find(item => item.value === val)
  for (let i in selectVal) {
    if (i !== 'label' && i !== 'value' && i !== 'id'){
      formData.value[i] = selectVal[i]
    }
    formData.value[`${data.field}Name`] = selectVal.label
  }
}
// 树下拉选择的选中事件
const handlerTreeClick = (met, val, field, formVal) => {
  formData.value[field] = val[field]
  if (met) {
    emit(met, { field: field, val: val, formVal: formVal })
  }
}
// 禁用某一项元素
const disabled = (field, status) => {
  fieldData.value = fieldData.value.map(item => {
    if (item.field === field) {
      return {
        ...item,
        disabled: status
      }
    } else {
      return item
    }
  })
}
// 修改某一项值的参数
const change = (field, key, data) => {
  fieldData.value = fieldData.value.map(item => {
    if (item.field === field) {
      item[key] = data
      return item
    } else {
      return item
    }
  })
}
// 修改某一项是否隐藏
const hidden = (field, status) => {
  fieldData.value = fieldData.value.map(item => {
    if (item.field === field) {
      return {
        ...item,
        hidden: status
      }
    } else {
      return item
    }
  })
}
// 设置某一项的值
const setValue = (field, value) => {
  formData.value[field] = value
}
// 获取某一项的值
const getValue = (field) => {
  return formData.value[field]
}
// 手动隐藏表单按钮，详情页面中使用
const isView = (val = false) => {
  is_view.value = val
}

proxy.bus.on("change",(val)=>{
  // console.log(val)
  switch (val.type) {
    case 'setValue':
      setValue(val.a, val.b)
      break;
    case 'disabled':
      disabled(val.a, val.b)
      break;
    case 'change':
      change(val.a, val.b, val.c)
      break;
    case 'hidden':
      hidden(val.a, val.b)
      break;
    case 'getValue':
      getValue(val.a)
      break;
    case 'isView':
      isView(val.a)
      break;
    default: null
  }
})
// const formRef = ref(null)
setFormData()
defineExpose({
  disabled,
  change,
  hidden,
  setValue,
  getValue,
  isView,
});
</script>

<style lang="scss" scoped>

</style>