import { defineComponent, markRaw, ref } from 'vue' import { ElDialog, ElButton } from 'element-plus' import { componentScheme } from './component.scheme' import { generateProps, generateEmits } from '../helper/component-util' import './dialog.less' export default defineComponent({ name: 'CipDialog', props: generateProps(componentScheme), emits: generateEmits(componentScheme), setup (props, { slots, emit }) { const defaultSlot = ref([]) const isComponent = vnode => !!vnode.component const isFormComponent = (vnode) => { if (!isComponent(vnode)) return false const componentName = (vnode.type?.name ?? '').toLocaleLowerCase() return componentName.indexOf('form') > -1 } const getComponent = vnode => vnode?.component const getMethodByComponent = (component = {}, method) => component.ctx?.[method] ?? component.exposed?.[method] const clearValidate = (vnodeList = []) => { // eslint-disable-next-line no-unused-expressions const handler = (component) => { const clearValidate = getMethodByComponent(component, 'clearValidate') // eslint-disable-next-line no-unused-expressions clearValidate?.() } findFormAndHandler(vnodeList, handler).then(() => {}) } const validForms = async (vnodeList = []) => { const validList = [] const handler = async (component) => { try { const validate = getMethodByComponent(component, 'validate') await validate?.() validList.push(true) } catch (e) { validList.push(e) } } try { await findFormAndHandler(vnodeList, handler) } catch (e) { console.log('findFormAndHandler', e) } return validList } const findFormAndHandler = async (vnodeList = [], handler = () => {}, depth = 1) => { for (let i = 0; i < vnodeList.length; i++) { const vnode = vnodeList[i] if (isFormComponent(vnode)) { const component = getComponent(vnode) await handler(component) } else { if (depth > props.maxDepth) return false // 使用defineAsyncComponent 是 subTree 及为下个组件 const childVnodeList = isComponent(vnode) ? (vnode.component.subTree?.children ?? [vnode.component.subTree]) : vnode.children // 如果是文字节点则跳过不处理 if (typeof childVnodeList === 'string') { continue } if (childVnodeList?.length > 0) { await findFormAndHandler(childVnodeList, handler, ++depth) // 此处++必须在前 } } } } const waiting = ref(false) // 默认使用props.onConfirm当入参为函数时使用函数 const confirm = async (cb) => { // 防止cb为e导致的错误 if (typeof cb !== 'function') cb = props.onConfirm try { waiting.value = true const validList = await validForms(defaultSlot.value) if (!validList.some(valid => valid !== true)) { const res = await new Promise((resolve, reject) => { if (typeof cb === 'function') { cb(resolve, reject) } else { reject(new TypeError('onConfirm is not a function')) } }) updateVisible(false) return res ?? true } else { // 存在未通过验证的表单 throw new Error('未通过表单验证') } // eslint-disable-next-line no-useless-catch } catch (e) { // 跑出错误 throw e } finally { waiting.value = false } } const cancel = () => { updateVisible(false) emit('cancel') } const openHandler = () => { clearValidate(defaultSlot.value) } const closeHandler = () => { emit('close') } const updateVisible = (val) => { emit('update:modelValue', val) } const dialogSlots = { header: () => <>
{ slots.mainTitle?.() || props.title }
{slots.subTitle?.() || props.subTitle}
, default: () => { const slot = slots.default?.() if (slot) { defaultSlot.value = markRaw(slot) } return slot }, footer: () => { if (!props.showOnly) { const defaultFooter =
{ !waiting.value && props.showCancel && cancel()} size={props.buttonSize}> {props.cancelText} } confirm()} size={props.buttonSize} type={'primary'} loading={waiting.value} > {props.confirmText}
const footerSlot = slots.footer?.({ confirm, loading: waiting.value, cancel }) return slots.footer ? footerSlot : defaultFooter } else { return slots.footer?.() } } } return () => ( closeHandler()} onOpen={() => openHandler()} fullscreen={props.fullscreen} v-slots={dialogSlots}/> ) } })