<template>
  <div class="template-child-form w-100%">
    <el-form
      ref="form-child"
      :model="form"
      :label-width="labelWidth"
      :label-position="labelPosition"
      :disabled="disabled || mode === 'look'"
    >
      <div class="row-box" v-for="(i, index) in form.arr" :key="index">
        <el-row>
          <el-col
            v-for="item in formItems"
            :key="item.prop"
            :span="['7', '16', '17', '18'].includes(item.inputType) ? 24 : colLen"
          >
            <el-form-item
              :label="item.label ? `${item.label}:` : ''"
              :prop="`arr.${index}.${item.prop}`"
              :rules="rules[item.prop]"
            >
              <component
                :is="item.type"
                :ref="item.type"
                v-model="i[item.prop]"
                :form-item="item"
                :mode="mode"
              />
            </el-form-item>
          </el-col>
        </el-row>
      </div>
    </el-form>
    <div
      @click="handleAdd"
      v-if="mode !== 'look' && !disabled"
      class="add-button flex justify-center items-center cursor-pointer h-32px m-t-16px"
    >
      <el-icon class="m-r-4px">
        <Plus />
      </el-icon>
      新增
    </div>
  </div>
</template>
<script>
import { ElMessage } from 'element-plus'
import Input from './Input.vue'
import InputNumber from './InputNumber.vue'
import Select from './Select.vue'
import Date from './Date.vue'
import Cascader from './Cascader.vue'
import Autocomplete from './Autocomplete.vue'
import FileUpload from './FileUpload/FileUpload.vue'
import Radio from './Radio.vue'
import Checkbox from './Checkbox.vue'
import CheckboxOther from './CheckboxOther.vue'
import FormHead2 from './FormHead2.vue'
import Map from './Map.vue'
import { cloneDeep } from 'lodash-es'
import { useValidator } from '@common/src/hooks/web/useValidator'

export default {
  name: 'FormChild',
  components: {
    Input,
    InputNumber,
    Select,
    Date,
    Cascader,
    FileUpload,
    Autocomplete,
    Radio,
    Checkbox,
    CheckboxOther,
    FormHead2,
    Map
  },
  props: {
    formItem: {
      type: Object,
      default: () => {}
    },
    modelValue: {
      type: String,
      default: '[]'
    },
    mode: {
      type: String,
      default: 'add'
    },
    disabled: {
      type: Boolean,
      default: false
    },
    labelPosition: {
      type: String,
      default: 'left'
    },
    labelWidth: {
      type: String,
      default: '120px'
    },
    // 表单列数
    col: {
      type: Number,
      default: 3
    }
  },
  data() {
    return {
      valids: {},
      form: {
        arr: []
      },
      formItems: [], // 用于渲染表单的表单项数组
      tempForm: [],
      formType: {
        1: 'Input',
        2: 'Input',
        3: 'Select',
        4: 'Select',
        5: 'Cascader',
        6: 'Cascader',
        7: 'FileUpload',
        8: 'Date',
        10: 'Date',
        11: 'Autocomplete',
        12: 'InputNumber',
        13: 'Radio',
        14: 'Checkbox',
        15: 'CheckboxOther',
        17: 'FormHead2',
        19: 'Map',
        20: 'Editor',
        21: 'Cascader'
      },
      customForm: {}
    }
  },
  computed: {
    filedForm() {
      return this.formItem.fieldTemplateList || []
    },
    // 动态生成规则
    rules() {
      const obj = {}
      this.tempForm.forEach((item) => {
        obj[item.prop] = []
        // 判断是否是输入型表单
        const isText = item.type === 'Input'
        if (item.required) {
          obj[item.prop].push({
            required: true,
            message: isText ? '请输入' : '请选择',
            trigger: isText ? 'blur' : 'change'
          })
        }
        // 自定义验证规则
        if (item.valid) {
          obj[item.prop].push({
            validator: item.valid,
            trigger: isText ? 'blur' : 'change'
          })
        }
        // 有字数限制时验证规则
        if (item.maxLength) {
          obj[item.prop].push({
            message: `最多 ${item.maxLength} 个字符`,
            trigger: 'blur',
            max: item.maxLength
          })
        }
      })
      return obj
    },
    modelValueArr() {
      return this.modelValue ? JSON.parse(this.modelValue) : []
    },
    colLen() {
      return 24 / this.col
    }
  },
  watch: {
    modelValue: {
      handler(val) {
        this.setForm()
        if (this.mode === 'add') return
        this.setParams()
      },
      immediate: true
    }
  },
  methods: {
    handleAdd() {
      this.addRow()
    },
    addRow() {
      const obj = cloneDeep(this.customForm)
      this.form.arr.push(obj)
    },
    setForm() {
      // 根据表单配置生成 对应验证规则
      const { idCard, phone, email } = useValidator()
      const valids = [idCard(), phone(), email()]

      this.form = {
        arr: []
      }
      this.tempForm = this.filedForm.map((item) => {
        return {
          label: item.fieldDesc,
          prop: item.fieldName,
          index: item.orderNo, // 排序
          type: this.formType[item.inputType],
          inputState: item.inputType === '2' ? 'textarea' : '', // 输入框的类型
          inputType: item.inputType,
          required: item.isNull === '1', // 是否必填(0:否，1:是)
          maxLength: item.limitLength,
          fieldType: item.fieldType, // 字段类型(int,varchar等)
          isPrimaryKey: item.isPrimaryKey, // 是否主键(0:否，1:是)
          isMultiple: ['4', '6', '14', '15'].includes(item.inputType), // 下拉和树 有多选
          // 字典与业务表查询时所用字段
          contactType: item.contactType,
          contactNo: item.contactNo,
          formHead: item.formHead || '',
          isAddReadonly: item.isAddReadonly === '1', // 只读
          defaultValue: item.defaultValue,
          valueType: item.valueType,
          isFormShow: item.isFormShow === '1',
          valid: (item.valueType && valids[Number(item.valueType) - 1].validator) || null
        }
      })

      // 动态生成表单
      this.tempForm
        .filter((item) => item.prop)
        .forEach((item) => {
          // item.isMultiple || item.formType === 7 时，默认值为数组
          this.customForm[item.prop] = item.defaultValue || item.isMultiple ? [] : ''
        })
      // 处理默认的表单项数
      const obj = cloneDeep(this.customForm)

      if (this.modelValueArr.length) {
        const arr = []
        for (let i = 0; i < this.modelValueArr.length; i++) {
          arr.push(obj)
        }
        this.form.arr = arr
      } else {
        this.$nextTick(() => {
          this.form.arr.push(obj)
        })
      }

      // 排序
      this.formItems = this.tempForm
        .sort((a, b) => a.index - b.index)
        .filter((item) => item.isFormShow)
    },
    resetForm() {
      this.form = {
        arr: []
      }
      this.formItems = []
      this.$nextTick(() => {
        this.$refs['form-child'] && this.$refs['form-child'].clearValidate()
        // 文件上传 清空列表
        this.$refs.FileUpload?.length && this.$refs.FileUpload[0].reset()
      })
    },
    // 设置表单值
    setParams() {
      for (const m of this.modelValueArr) {
        // 对多选的数据进行处理 按逗号 隔开
        for (const i of this.tempForm) {
          if (i.isMultiple) {
            m[i.prop] = m[i.prop]?.split(',').filter((i) => i !== '') || []
          }
        }
      }
      this.form.arr = this.modelValueArr
    },
    // 获取表单值
    getParams() {
      return new Promise((resolve, reject) => {
        this.$refs['form-child'].validate((valid) => {
          if (valid) {
            const form = cloneDeep(this.form)
            for (const i1 of this.form.arr) {
              for (const i2 in i1) {
                const item = this.tempForm.find((item) => item.prop === i2)
                // 该数据为输入类型且为整型时  为空时转为null
                if (i1[i2] === '' && item?.fieldType === '1') {
                  i1[i2] = null
                }
                // 数组转字符串
                if (Array.isArray(i1[i2])) {
                  i1[i2] = i1[i2].join(',')
                }
              }
              // 移除为空的key
              delete i1['']
            }
            resolve(form.arr)
          } else {
            ElMessage.warning('有必填项未完成')
            reject(new Error(false))
          }
        })
      })
    }
  }
}
</script>
<style lang="less">
.template-child-form {
  .el-form {
    .row-box + .row-box {
      margin-top: 16px;
      padding-top: 16px;
      border-top: 1px dashed #e6e6e6;
    }

    .el-row {
      margin-left: 0;
    }

    .el-form-item {
      margin-bottom: 20px;
    }
  }

  .add-button {
    border: 1px dashed var(--el-color-primary);
    color: var(--el-color-primary);
  }
}
</style>
