index.jsx.bak 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { defineComponent, markRaw, ref } from 'vue'
  2. import { ElDialog, ElButton } from 'element-plus'
  3. import { componentScheme } from './component.scheme'
  4. import { generateProps, generateEmits } from '../helper/component-util'
  5. import './dialog.less'
  6. export default defineComponent({
  7. name: 'CipDialog',
  8. props: generateProps(componentScheme),
  9. emits: generateEmits(componentScheme),
  10. setup (props, { slots, emit }) {
  11. const defaultSlot = ref([])
  12. const isComponent = vnode => !!vnode.component
  13. const isFormComponent = (vnode) => {
  14. if (!isComponent(vnode)) return false
  15. const componentName = (vnode.type?.name ?? '').toLocaleLowerCase()
  16. return componentName.indexOf('form') > -1
  17. }
  18. const getComponent = vnode => vnode?.component
  19. const getMethodByComponent = (component = {}, method) => component.ctx?.[method] ?? component.exposed?.[method]
  20. const clearValidate = (vnodeList = []) => {
  21. // eslint-disable-next-line no-unused-expressions
  22. const handler = (component) => {
  23. const clearValidate = getMethodByComponent(component, 'clearValidate')
  24. // eslint-disable-next-line no-unused-expressions
  25. clearValidate?.()
  26. }
  27. findFormAndHandler(vnodeList, handler).then(() => {})
  28. }
  29. const validForms = async (vnodeList = []) => {
  30. const validList = []
  31. const handler = async (component) => {
  32. try {
  33. const validate = getMethodByComponent(component, 'validate')
  34. await validate?.()
  35. validList.push(true)
  36. } catch (e) {
  37. validList.push(e)
  38. }
  39. }
  40. try {
  41. await findFormAndHandler(vnodeList, handler)
  42. } catch (e) {
  43. console.log('findFormAndHandler', e)
  44. }
  45. return validList
  46. }
  47. const findFormAndHandler = async (vnodeList = [], handler = () => {}, depth = 1) => {
  48. for (let i = 0; i < vnodeList.length; i++) {
  49. const vnode = vnodeList[i]
  50. if (isFormComponent(vnode)) {
  51. const component = getComponent(vnode)
  52. await handler(component)
  53. } else {
  54. if (depth > props.maxDepth) return false
  55. // 使用defineAsyncComponent 是 subTree 及为下个组件
  56. const childVnodeList = isComponent(vnode)
  57. ? (vnode.component.subTree?.children ?? [vnode.component.subTree])
  58. : vnode.children
  59. // 如果是文字节点则跳过不处理
  60. if (typeof childVnodeList === 'string') {
  61. continue
  62. }
  63. if (childVnodeList?.length > 0) {
  64. await findFormAndHandler(childVnodeList, handler, ++depth) // 此处++必须在前
  65. }
  66. }
  67. }
  68. }
  69. const waiting = ref(false)
  70. // 默认使用props.onConfirm当入参为函数时使用函数
  71. const confirm = async (cb) => {
  72. // 防止cb为e导致的错误
  73. if (typeof cb !== 'function') cb = props.onConfirm
  74. try {
  75. waiting.value = true
  76. const validList = await validForms(defaultSlot.value)
  77. if (!validList.some(valid => valid !== true)) {
  78. const res = await new Promise((resolve, reject) => {
  79. if (typeof cb === 'function') {
  80. cb(resolve, reject)
  81. } else {
  82. reject(new TypeError('onConfirm is not a function'))
  83. }
  84. })
  85. updateVisible(false)
  86. return res ?? true
  87. } else {
  88. // 存在未通过验证的表单
  89. throw new Error('未通过表单验证')
  90. }
  91. // eslint-disable-next-line no-useless-catch
  92. } catch (e) {
  93. // 跑出错误
  94. throw e
  95. } finally {
  96. waiting.value = false
  97. }
  98. }
  99. const cancel = () => {
  100. updateVisible(false)
  101. emit('cancel')
  102. }
  103. const openHandler = () => {
  104. clearValidate(defaultSlot.value)
  105. }
  106. const closeHandler = () => {
  107. emit('close')
  108. }
  109. const updateVisible = (val) => {
  110. emit('update:modelValue', val)
  111. }
  112. const dialogSlots = {
  113. header: () => <>
  114. <div class="el-dialog__mainTitle">{ slots.mainTitle?.() || props.title }</div>
  115. <div class="el-dialog__subTitle">{slots.subTitle?.() || props.subTitle}</div>
  116. </>,
  117. default: () => {
  118. const slot = slots.default?.()
  119. if (slot) {
  120. defaultSlot.value = markRaw(slot)
  121. }
  122. return slot
  123. },
  124. footer: () => {
  125. if (!props.showOnly) {
  126. const defaultFooter = <div>
  127. {
  128. !waiting.value && props.showCancel &&
  129. <ElButton
  130. onClick={() => cancel()}
  131. size={props.buttonSize}>
  132. {props.cancelText}
  133. </ElButton>
  134. }
  135. <ElButton
  136. onClick={() => confirm()}
  137. size={props.buttonSize}
  138. type={'primary'}
  139. loading={waiting.value} >
  140. {props.confirmText}
  141. </ElButton>
  142. </div>
  143. const footerSlot = slots.footer?.({ confirm, loading: waiting.value, cancel })
  144. return slots.footer ? footerSlot : defaultFooter
  145. } else {
  146. return slots.footer?.()
  147. }
  148. }
  149. }
  150. return () => (
  151. <ElDialog
  152. customClass={'cip-dialog__wrapper'}
  153. modelValue={props.modelValue}
  154. onUpdate:modelValue={updateVisible}
  155. title={props.title}
  156. width={props.width}
  157. closeOnClickModal={props.closeOnClickModal}
  158. top={props.top}
  159. destroyOnClose={props.destroyOnClose}
  160. appendToBody={true}
  161. onClose={() => closeHandler()}
  162. onOpen={() => openHandler()}
  163. fullscreen={props.fullscreen}
  164. v-slots={dialogSlots}/>
  165. )
  166. }
  167. })