<template>
  <el-dialog custom-class="cip-dialog__wrapper"
             :title="title"
             :model-value="modelValue"
             :width="width"
             :close-on-click-modal="closeOnClickModal"
             :top="top"
             append-to-body
             :destroyOnClose="destroyOnClose"
             @close="$emit('close')"
             @update:modelValue="changeVisible"
             @opened="handleOpened">
    <slot></slot>
    <template v-slot:footer v-if="!$slots.footer && !showOnly">
      <div style="text-align:right">
        <el-button @click="cancel"  :size="buttonSize" v-if="!waiting">{{cancelText}}</el-button>
        <el-button @click="confirm" type="primary" :size="buttonSize" :loading="waiting">{{confirmText}}</el-button>
      </div>
    </template>
    <template #footer v-else>
      <slot name="footer" :confirm="confirm" :loading="waiting"></slot>
    </template>
  </el-dialog>
</template>
<script>
import { ref, defineComponent, isRef } from 'vue'
import { ElDialog, ElButton } from 'element-plus'
export default defineComponent({
  name: 'CipDialog',
  components: { ElDialog, ElButton },
  props: {
    title: String,
    modelValue: { default: false }, // 是否显示dialog
    onConfirm: { type: Function }, // Function(resolve,reject)
    beforeConfirm: { type: Function, default: () => {} }, // 触发表单验证前的值设置
    width: { // 设置dialog宽度
      default: '870px'
    },
    top: { default: '15vh' },
    closeOnClickModal: { // 点击遮罩层是否关闭dialog
      type: Boolean,
      default: false
    },
    showOnly: {
      default: false
    },
    buttonSize: { // 设置footer按钮大小
      default: 'small'
    },
    confirmText: { // 触发on-confirm方法的按钮文字
      default: '确认'
    },
    cancelText: { // 触发关闭dialog方法按钮的文字
      default: '取消'
    },
    destroyOnClose: { // 默认关闭时销毁dialog
      type: Boolean,
      default: true
    }
  },
  emits: ['update:modelValue', 'cancel', 'close'],
  setup (props, context) {
    const waiting = ref(false)
    const changeVisible = (val) => {
      context.emit('update:modelValue', val)
    }
    const handleOpened = () => {
      const vnodeList = context.slots.default?.() || []
      vnodeList.forEach(vnode => {
        if (isRef(vnode.ref?.r)) {
          // ref直接勇士ref的变量
          // eslint-disable-next-line no-unused-expressions
          vnode.ref?.r.value?.clearValidate()
        } else {
          // ref使用字符串
          // eslint-disable-next-line no-unused-expressions
          vnode.ref?.i?.refs[vnode.ref?.r ?? 'form']?.clearValidate?.()
        }
      })
    }
    const validElForm = async (vnodeList = [], validList = []) => {
      const vnodeListLen = vnodeList.length
      for (let i = 0; i < vnodeListLen; i++) {
        const vnode = vnodeList[i]
        if (isRef(vnode.ref?.r)) {
          // eslint-disable-next-line no-unused-expressions
          vnode.ref?.r.value?.validate((valid) => {
            validList.push(valid)
          })
        } else {
          // eslint-disable-next-line no-unused-expressions
          vnode.ref?.i?.refs[vnode.ref?.r ?? 'form']?.validate?.((valid) => {
            validList.push(valid)
          })
        }
      }
      return validList
    }
    const confirm = async () => {
      waiting.value = true
      // 校验方法暂不可用
      try {
        const validList = await validElForm(context.slots.default?.())
        if (!validList.includes(false)) {
          await new Promise((resolve, reject) => {
            if (typeof props.onConfirm === 'function') {
              props.onConfirm(resolve, reject)
            } else {
              throw new TypeError('onConfirm is not a function')
            }
          })
          changeVisible(false)
        } else {
          // 存在未通过验证的表单
        }
      } catch (e) {
        // 错误捕捉
        console.error(e)
      }
      waiting.value = false
    }
    const cancel = () => {
      changeVisible(false)
      context.emit('cancel')
    }
    return {
      waiting,
      changeVisible,
      handleOpened,
      confirm,
      cancel
    }
  }
})
</script>
<style lang="less">
.cip-dialog__wrapper{
  &.el-dialog{
    .el-dialog__header{
      border-bottom: 1px solid #ddd;
    }
    .el-dialog__body{
      max-height: 60vh;
      overflow-y: auto;
      overflow-x: hidden;
      padding-bottom: 12px;
    }
    .el-dialog__footer{
      border-top: 1px solid #ddd;
    }
  }
}
</style>
