cl-confirm.uvue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <cl-popup
  3. v-model="visible"
  4. :pt="{
  5. className: '!rounded-[60rpx]'
  6. }"
  7. size="70%"
  8. :show-close="false"
  9. :show-header="false"
  10. :mask-closable="false"
  11. direction="center"
  12. @mask-close="onAction('close')"
  13. @closed="onClosed"
  14. >
  15. <view class="cl-confirm">
  16. <text class="cl-confirm__title">{{ config.title }}</text>
  17. <text class="cl-confirm__message">{{ config.message }}</text>
  18. <view class="cl-confirm__actions">
  19. <cl-button
  20. v-if="config.showCancel"
  21. size="large"
  22. text
  23. rounded
  24. border
  25. type="info"
  26. :pt="{
  27. className: 'flex-1 h-[80rpx]'
  28. }"
  29. @tap="onAction('cancel')"
  30. >{{ config.cancelText }}</cl-button
  31. >
  32. <cl-button
  33. v-if="config.showConfirm"
  34. size="large"
  35. rounded
  36. :loading="loading"
  37. :pt="{
  38. className: 'flex-1 h-[80rpx]'
  39. }"
  40. @tap="onAction('confirm')"
  41. >{{ config.confirmText }}</cl-button
  42. >
  43. </view>
  44. </view>
  45. </cl-popup>
  46. </template>
  47. <script setup lang="ts">
  48. import { ref, reactive } from "vue";
  49. import type { ClConfirmAction, ClConfirmOptions } from "../../types";
  50. import { t } from "@/locale";
  51. // 控制弹窗显示/隐藏
  52. const visible = ref(false);
  53. // 控制弹窗是否关闭
  54. const closed = ref(true);
  55. // 确认弹窗配置项,包含标题、内容、按钮文本等
  56. const config = reactive<ClConfirmOptions>({
  57. title: "",
  58. message: ""
  59. });
  60. // 控制确认按钮loading状态
  61. const loading = ref(false);
  62. // 显示loading
  63. function showLoading() {
  64. loading.value = true;
  65. }
  66. // 隐藏loading
  67. function hideLoading() {
  68. loading.value = false;
  69. }
  70. // 关闭弹窗
  71. function close() {
  72. visible.value = false;
  73. }
  74. /**
  75. * 打开确认弹窗,并设置相关配置
  76. * @param options ClConfirmOptions 配置项
  77. */
  78. let timer: number = 0;
  79. function open(options: ClConfirmOptions) {
  80. const next = () => {
  81. // 清除之前的定时器
  82. clearTimeout(timer);
  83. // 设置弹窗状态为打开
  84. closed.value = false;
  85. // 显示弹窗
  86. visible.value = true;
  87. // 设置弹窗标题
  88. config.title = options.title;
  89. // 设置弹窗内容
  90. config.message = options.message;
  91. // 是否显示取消按钮,默认显示
  92. config.showCancel = options.showCancel ?? true;
  93. // 是否显示确认按钮,默认显示
  94. config.showConfirm = options.showConfirm ?? true;
  95. // 取消按钮文本,默认"取消"
  96. config.cancelText = options.cancelText ?? t("取消");
  97. // 确认按钮文本,默认"确定"
  98. config.confirmText = options.confirmText ?? t("确定");
  99. // 显示时长,默认0不自动关闭
  100. config.duration = options.duration ?? 0;
  101. // 回调函数
  102. config.callback = options.callback;
  103. // 关闭前钩子
  104. config.beforeClose = options.beforeClose;
  105. // 如果设置了显示时长且不为0,则启动自动关闭定时器
  106. if (config.duration != 0) {
  107. // 设置定时器,在指定时长后自动关闭弹窗
  108. // @ts-ignore
  109. timer = setTimeout(() => {
  110. // 调用关闭方法
  111. close();
  112. }, config.duration!);
  113. }
  114. };
  115. if (closed.value) {
  116. next();
  117. } else {
  118. setTimeout(() => {
  119. next();
  120. }, 360);
  121. }
  122. }
  123. // 弹窗关闭后,重置loading状态
  124. function onClosed() {
  125. hideLoading();
  126. closed.value = true;
  127. }
  128. /**
  129. * 处理用户操作(确认、取消、关闭)
  130. * @param action ClConfirmAction 操作类型
  131. */
  132. function onAction(action: ClConfirmAction) {
  133. // 如果没有beforeClose钩子,直接关闭并回调
  134. if (config.beforeClose == null) {
  135. visible.value = false;
  136. if (config.callback != null) {
  137. config.callback!(action);
  138. }
  139. } else {
  140. // 有beforeClose钩子时,传递操作方法
  141. config.beforeClose!(action, {
  142. close,
  143. showLoading,
  144. hideLoading
  145. });
  146. }
  147. }
  148. defineExpose({
  149. open,
  150. close
  151. });
  152. </script>
  153. <style lang="scss" scoped>
  154. .cl-confirm {
  155. @apply p-4;
  156. &__title {
  157. @apply text-lg text-center text-surface-700 font-bold mb-2;
  158. }
  159. &__message {
  160. @apply text-md text-center text-surface-700 mb-8;
  161. }
  162. &__actions {
  163. @apply flex flex-row items-center justify-center;
  164. }
  165. }
  166. </style>