Parcourir la source

新的 useDialog

xiaochan il y a 11 mois
Parent
commit
8133a976a7
3 fichiers modifiés avec 182 ajouts et 1 suppressions
  1. 2 1
      src/App.vue
  2. 77 0
      src/components/cy/CyDialog/index.ts
  3. 103 0
      src/components/cy/CyDialog/index.vue

+ 2 - 1
src/App.vue

@@ -3,6 +3,7 @@
   <soctet-dialog v-if="socketErrDialog"/>
   <progress-bar/>
   <JsDialogComp/>
+  <CyDialogV2/>
 </template>
 
 <script setup lang="jsx">
@@ -20,6 +21,7 @@ import {useProgressBarStore} from "@/pinia/progress-bar-store";
 import {useUserStore} from "@/pinia/user-store";
 import {useSystemStore} from "@/pinia/system-store";
 import useChangeToken from "@/utils/cy-use/useChangeToken";
+import CyDialogV2 from "@/components/cy/CyDialog/index.vue";
 
 const progressBarStore = useProgressBarStore()
 const systemStore = useSystemStore()
@@ -32,7 +34,6 @@ progressBarStore.initialize({
   abnormalClosing: false,
 })
 
-
 function avatarNotification(data) {
   const message = (
       <div>

+ 77 - 0
src/components/cy/CyDialog/index.ts

@@ -0,0 +1,77 @@
+import { ref, shallowRef } from "vue";
+import XEUtils from "xe-utils";
+
+interface DialogProps {
+  title: string;
+  fullscreen?: boolean;
+  width?: number | string;
+  top?: string;
+}
+
+type CloseValue = "close" | "confirm" | "cancel";
+
+export interface DialogExpose {
+  // 如果报错了会阻止关闭弹窗
+  confirm: () => any | Promise<any>;
+  // 如果报错了会阻止关闭弹窗
+  cancel: () => any | Promise<any>;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-namespace
+export namespace UseDialog {
+  export interface Expose extends DialogExpose {}
+
+  export interface Emits {
+    (e: "cyDialogConfirm" | "cyDialogCancel", value?: any): void;
+  }
+}
+
+export interface DialogOptions {
+  dialogProps: DialogProps;
+  showCancel?: boolean;
+  showConfirm?: boolean;
+  cancelText?: string;
+  confirmText?: string;
+  visible?: boolean;
+  component?: any;
+  componentRef?: DialogExpose;
+
+  propsData?: {
+    [key: string]: any;
+  };
+}
+
+export interface DialogState extends DialogOptions {
+  resolve: (val: { value: CloseValue; data: any }) => void;
+  reject: (val: { value: CloseValue; data: any }) => void;
+
+  dialogKey?: number;
+  closeValue?: CloseValue;
+}
+
+export const dialogStore = ref<DialogState[]>([]);
+export const dialogKey = ref(1);
+
+export function useDialog(component: any, props: DialogOptions) {
+  return new Promise<any>((resolve, reject) => {
+    props = {
+      visible: true,
+      component: shallowRef(component),
+      showCancel: true,
+      showConfirm: true,
+      ...props
+    };
+    dialogKey.value++;
+    dialogStore.value.push({
+      ...props,
+      resolve: XEUtils.once(value => {
+        resolve(value);
+      }),
+      reject: XEUtils.once(value => {
+        reject(value);
+      }),
+      dialogKey: dialogKey.value,
+      closeValue: "close"
+    });
+  });
+}

+ 103 - 0
src/components/cy/CyDialog/index.vue

@@ -0,0 +1,103 @@
+<script setup lang="ts">
+import {DialogState, dialogStore} from "./index";
+import {ElButton} from "element-plus";
+import XEUtils from "xe-utils";
+import sleep from "@/utils/sleep";
+import {nextTick} from "vue";
+
+function next(item: DialogState, data: any) {
+  if (item.closeValue === "confirm") {
+    item.resolve(data);
+  } else {
+    item.reject({value: item.closeValue, data});
+  }
+  item.visible = false;
+}
+
+async function handleCancel(item: DialogState, emits = false, value = null) {
+  if (emits) {
+    item.closeValue = "cancel";
+    next(item, value);
+    return;
+  }
+  try {
+    const fn = item.componentRef?.cancel ?? XEUtils.noop;
+    const data = await fn();
+    item.closeValue = "cancel";
+    next(item, data);
+  } catch {
+  }
+}
+
+async function handleConfirm(item: DialogState, emits = false, value = null) {
+  if (emits) {
+    item.closeValue = "confirm";
+    next(item, value);
+    return;
+  }
+  const fn = item.componentRef?.confirm ?? XEUtils.noop;
+  try {
+    const data = await fn();
+    item.closeValue = "confirm";
+    next(item, data);
+  } catch {
+  }
+}
+
+async function closed(item: DialogState, index: number) {
+  item.reject({value: item.closeValue, data: null});
+  await nextTick();
+  await sleep();
+  dialogStore.value.splice(index, 1);
+}
+
+function setRef(el, item) {
+  item.componentRef = el;
+}
+</script>
+
+<template>
+  <el-dialog
+      v-for="(item, index) in dialogStore"
+      :key="`Cy-dialog_${item.dialogKey}`"
+      v-model="item.visible"
+      draggable
+      v-bind="item.dialogProps"
+      @closed="closed(item, index)"
+  >
+    <component
+        :is="item.component"
+        :ref="el => setRef(el, item)"
+        v-bind="item.propsData"
+        @cyDialogCancel="value => handleCancel(item, true, value)"
+        @cyDialogConfirm="value => handleConfirm(item, true, value)"
+    />
+
+    <template v-if="item.showCancel || item.showConfirm" #footer>
+      <el-button size="default" @click="handleCancel(item)">
+        {{ item.cancelText || "取消" }}
+      </el-button>
+
+      <el-button
+          type="primary"
+          size="default"
+          color="hsl(240 5.9% 10%)"
+          @click="handleConfirm(item)"
+      >
+        {{ item.confirmText || "确认" }}
+      </el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<style lang="scss">
+.el-dialog.is-fullscreen {
+  display: flex;
+  flex-direction: column;
+
+  .el-dialog__body {
+    flex: 1;
+    height: 0;
+  }
+}
+</style>