<template>
  <el-col class="cus-form-column" :class="{
    span1: filterSpan == 1,
    span2: filterSpan == 2,
    span3: filterSpan == 3,
    span4: filterSpan == 4,
    span5: filterSpan == 5,
  }" :span="span" :offset="offset" ref="ref_cusFormColumn">
    <el-form-item :label="label" :label-width="labelWidth" :class="{ required: required !== false }"
                  :error="errorMessage" :required="required">
      <slot name="cus" :handleValidate="handleValidate">
        <template v-if="link === 'input'">
          <InputCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
              @emitEnter="handleEnter"
          >
            <template v-if="$slots.prefix" #prefix>
              <slot name="prefix"/>
            </template>
            <template v-if="$slots.suffix" #suffix>
              <slot name="suffix"/>
            </template>
            <template v-if="$slots.prepend" #prepend>
              <slot name="prepend"/>
            </template>
            <template v-if="$slots.append" #append>
              <slot name="append"/>
            </template>
          </InputCom>
        </template>
        <template v-else-if="link === 'select'">
          <SelectCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
            <slot/>
          </SelectCom>
        </template>
        <template v-else-if="link === 'date'">
          <DateCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
            <template #default="{cell}">
              <slot v-bind="cell"/>
            </template>
          </DateCom>
        </template>
        <template v-else-if="link === 'datetime'">
          <DateTimeCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
            <template #default="{cell}">
              <slot v-bind="cell"/>
            </template>
          </DateTimeCom>
        </template>
        <template v-else-if="link === 'time'">
          <TimeCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
          </TimeCom>
        </template>
        <template v-else-if="link === 'cascader'">
          <CascaderCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
            <template v-if="$slots.default" #default="{node, data}">
              <slot v-bind="{node, data}"/>
            </template>
          </CascaderCom>
        </template>
        <template v-else-if="link === 'switch'">
          <SwitchCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
          </SwitchCom>
        </template>
        <template v-else-if="link === 'radio'">
          <RadioCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
          </RadioCom>
        </template>
        <template v-else-if="link === 'checkbox'">
          <CheckboxCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
          </CheckboxCom>
        </template>
        <template v-else-if="link === 'portOfRegistry'">
          <PortOfRegistryCom
              v-bind="$attrs"
              :label="labelCpt"
              :paramOne="paramOne"
              :paramTwo="paramTwo"
              @emitParam="(pOne, pTwo) => {
                $emit('update:paramOne', pOne), $emit('update:paramTwo', pTwo), handleValidate(pOne, pTwo)
              }"
          />
        </template>
        <template v-else-if="link === 'residentMooringPoint'">
          <ResidentMooringPointCom
              v-bind="$attrs"
              :label="labelCpt"
              :paramOne="paramOne"
              :paramTwo="paramTwo"
              @emitParam="(pOne, pTwo) => {
                $emit('update:paramOne', pOne), $emit('update:paramTwo', pTwo), handleValidate(pOne, pTwo)
              }"
          />
        </template>
        <template v-else-if="link === 'dept'">
          <DeptCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
              @emitDefault="val => $emit('getDefault', val)"
          />
        </template>
        <template v-else-if="link === 'upload'">
          <UploadCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          />
        </template>
        <template v-else-if="link === 'number'">
          <NumberCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
              @emitEnter="handleEnter"
          >
            <template v-if="$slots.prefix" #prefix>
              <slot name="prefix"/>
            </template>
            <template v-if="$slots.suffix" #suffix>
              <slot name="suffix"/>
            </template>
            <template v-if="$slots.prepend" #prepend>
              <slot name="prepend"/>
            </template>
            <template v-if="$slots.append" #append>
              <slot name="append"/>
            </template>
          </NumberCom>
        </template>
        <template v-else-if="link === 'input-number'">
          <InputNumberCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
              @emitEnter="handleEnter"
          >
          </InputNumberCom>
        </template>
        <template v-else-if="link === 'tree-select'">
          <TreeSelectCom
              v-bind="$attrs"
              :label="labelCpt"
              :param="param"
              @emitParam="val => {
                $emit('update:param', val), handleValidate(val)
              }"
          >
          </TreeSelectCom>
        </template>
      </slot>
      <div v-if="unit" class="unit">{{unit}}</div>
    </el-form-item>
  </el-col>
</template>

<script lang="ts">
import {
  defineComponent,
  computed,
  onMounted,
  ref,
  reactive,
  watch,
  getCurrentInstance,
  ComponentInternalInstance,
  toRefs,
  nextTick,
  inject, onUnmounted, onBeforeUnmount
} from 'vue'
import {useStore} from 'vuex'
import {useRouter, useRoute} from 'vue-router'
import InputCom from './cus-form-link/input.vue'
import InputNumberCom from './cus-form-link/input-number.vue'
import SelectCom from './cus-form-link/select.vue'
import DateCom from './cus-form-link/date.vue'
import DateTimeCom from './cus-form-link/datetime.vue'
import TimeCom from './cus-form-link/time.vue'
import CascaderCom from './cus-form-link/cascader.vue'
import SwitchCom from './cus-form-link/switch.vue'
import RadioCom from './cus-form-link/radio.vue'
import CheckboxCom from './cus-form-link/checkbox.vue'
import PortOfRegistryCom from './cus-form-link/portOfRegistry.vue'
import ResidentMooringPointCom from './cus-form-link/residentMooringPoint.vue'
import DeptCom from './cus-form-link/dept.vue'
import UploadCom from './cus-form-link/upload.vue'
import NumberCom from './cus-form-link/number.vue'
import TreeSelectCom from './cus-form-link/tree-select.vue'
import { v4 } from "uuid";

export default defineComponent({
  name: 'CusFormColumn',
  components: {
    InputCom,
    InputNumberCom,
    SelectCom,
    DateCom,
    DateTimeCom,
    TimeCom,
    CascaderCom,
    SwitchCom,
    RadioCom,
    CheckboxCom,
    PortOfRegistryCom,
    ResidentMooringPointCom,
    DeptCom,
    UploadCom,
    NumberCom,
    TreeSelectCom
  },
  props: {
    span: {type: Number, default: 6},
    filterSpan: { default: null },
    offset: {type: Number, default: 0},
    param: {},
    paramOne: {},
    paramTwo: {},
    label: {type: String, default: ''},
    required: {default: false},
    labelWidth: {type: String, default: ''},
    link: {type: String, default: 'input', validator(val: string) {
      return ['cascader', 'checkbox', 'date', 'datetime', 'input', 'radio', 'select', 'switch', 'portOfRegistry', 'residentMooringPoint', 'dept', 'time', 'upload', 'number', 'input-number', 'tree-select'].includes(val)
    }},
    rules: {type: Array, default: () => []},
    maxLength: {type: Number, default: null},
    minLength: {type: Number, default: null},
    defaultErrorMsg: {default: null},
    unit: {default: '', type: String}
  },
  setup(props) {
    const store = useStore();
    const router = useRouter();
    const route = useRoute();
    const that = (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties
    const state = reactive({
      errorMessage: null,
      uuid: ''
    })
    const ref_cusFormColumn: any = ref(null)
    const isValue = (val: any) => {
      if (val === null || val === undefined || (typeof val === 'string' && val.trim() === '') || (typeof val === 'object' && val?.length === 0)) {
        return false
      }
      return true
    }
    const labelCpt = computed(() => {
      return props.label.replace(/[::]([^::]*)$/, "")
    })
    const rulesCpt = computed(() => {
      const r = [...props.rules]
      if (isValue(props.minLength)) {
        r.unshift({
          handle: (val: any) => !isValue(val) || (isValue(val) && String(val).length >= props.minLength),
          message: `内容过短,字数需大于等于${props.minLength}`
        })
      }
      if (isValue(props.maxLength)) {
        r.unshift({
          handle: (val: any) => !isValue(val) || (isValue(val) && String(val).length <= props.maxLength),
          message: `内容过长,字数需小于等于${props.maxLength}`
        })
      }
      const doStr = ['input', 'number', 'input-number'].includes(props.link) ? '输入' : '选择'
      if (props.required !== false && !props.rules.some((v: any) => v.type === 'default')) {
        if (['portOfRegistry', 'residentMooringPoint'].includes(props.link)) {
          r.unshift({
            handle: (pOne: any, pTwo: any) => isValue(pOne) && isValue(pTwo),
            message: props.defaultErrorMsg ?? `请${doStr}${labelCpt.value}`
          })
        } else {
          r.unshift({
            handle: (val: any) => isValue(val),
            message: props.defaultErrorMsg ?? `请${doStr}${labelCpt.value}`
          })
        }
      }
      return r
    })
    const handleValidate = (val: any = undefined, val2: any = undefined) => {
      state.errorMessage = null
      for (let i = 0; i < rulesCpt.value.length; i++) {
        const item: any = rulesCpt.value[i]
        if (['portOfRegistry', 'residentMooringPoint'].includes(props.link)) {
          if (!item.handle(val === undefined ? props.paramOne : val, val2 === undefined ? props.paramTwo : val2)) {
            state.errorMessage = item.message
            break
          }
        } else {
          if (!item.handle(val === undefined ? props.param : val)) {
            state.errorMessage = item.message
            break
          }
        }
      }
      return state.errorMessage
    }
    const handleEnterFunc = inject('handle-enter', () => {})
    const handleEnter = () => {
      handleEnterFunc?.()
    }
    const reset = () => {
      state.errorMessage = null
    }
    watch(() => state.errorMessage, (n) => {
      const p = ref_cusFormColumn.value?.$el?.getElementsByClassName('el-form-item')?.[0]
      if (n) {
        setTimeout(() => {
          const e = p?.getElementsByClassName('el-form-item__content')?.[0]?.getElementsByClassName('el-form-item__error')?.[0]
          if (e?.clientHeight) {
            p.style.marginBottom = `${e.clientHeight + 4}px`
          }
        }, 200)
      } else {
        p.style.marginBottom = '18px'
      }
    })
    onMounted(() => {
      state.uuid = v4()
      const formChildrenMap: any = inject('cus-form-children-map', new Map())
      let flag = true
      const deep = (dom) => {
        if (dom.className === 'hidden-columns') {
          flag = false
        }
        if (dom.parentElement) {
          deep(dom.parentElement)
        }
      }
      deep(ref_cusFormColumn.value.$parent.$el)
      if (flag) {
        formChildrenMap.set(state.uuid, ref_cusFormColumn.value.$parent)
      }
    })
    onBeforeUnmount(() => {
      const formChildrenMap: any = inject('cus-form-children-map', new Map())
      formChildrenMap.delete(state.uuid)
    })
    return {
      ...toRefs(state),
      handleValidate,
      handleEnter,
      ref_cusFormColumn,
      reset,
      labelCpt
    }
  },
})
</script>

<style scoped lang="scss">
.cus-form-column {
  &.span1 {
    width: 20%;
    max-width: 20%;
    flex: unset;
  }
  &.span2 {
    width: 40%;
    max-width: 40%;
    flex: unset;
  }
  &.span3 {
    width: 60%;
    max-width: 60%;
    flex: unset;
  }
  &.span4 {
    width: 80%;
    max-width: 80%;
    flex: unset;
  }
  &.span5 {
    width: 100%;
    max-width: 100%;
    flex: unset;
  }
  :deep(.el-form-item) {
    .el-form-item__label {
      word-break: keep-all;
      line-height: 1;
      text-align: right;
      display: flex;
      align-items: center;
      padding-left: 10px;
      font-size: 14px;
      font-family: Microsoft YaHei;
      font-weight: 400;
      color: #434343;
      height: 36px;
    }
    .el-form-item__content {
      height: 36px;
      flex-wrap: unset;
      >div:first-child {
        flex: 1;
        height: 100%;
      }
      .unit {
        margin-left: 6px;
        font-size: 14px;
        font-family: PingFang SC-Regular, PingFang SC;
        font-weight: 400;
        color: #606266;
      }
      .el-input {
        height: 100%;
        .el-input__wrapper {
          border-radius: 2px;
        }
      }
      .el-select {
        height: 100%;
        .select-trigger {
          height: 100%;
        }
      }
    }
  }
}
</style>