ソースを参照

修复$ref和cymessagebox

xiaochan 1 年間 前
コミット
59c861c2cd

BIN
deps/element-plus.tar.gz → deps/element-plus.2.0.4.1.tar.gz


+ 3 - 3
package-lock.json

@@ -19,7 +19,7 @@
         "dayjs": "^1.11.7",
         "driver.js": "^1.3.0",
         "echarts": "^5.2.0",
-        "element-plus": "file:deps/element-plus.tar.gz",
+        "element-plus": "file:deps/element-plus.2.0.4.1.tar.gz",
         "file-saver": "^2.0.5",
         "iconv-lite": "^0.6.3",
         "jquery": "^3.6.0",
@@ -3849,8 +3849,8 @@
     },
     "node_modules/element-plus": {
       "version": "0.0.0-dev.1",
-      "resolved": "file:deps/element-plus.tar.gz",
-      "integrity": "sha512-fRL56HYS5Yt0oJ1rfWt/McK0S5HSobYtDpAR4PeiaXFQZpwxwPSsL9KiTUYCBy0WFzzYCEY9hKHTxju1ao8Q1w==",
+      "resolved": "file:deps/element-plus.2.0.4.1.tar.gz",
+      "integrity": "sha512-DcI/g9dC+ZK/AADVkU+st/QyqxIFlJOCkmjnk1K/DpcwgRJcwmLcV9QsojsdSvxrP7LnA/CduTtZ88gYXPVC9g==",
       "license": "MIT",
       "dependencies": {
         "@ctrl/tinycolor": "^3.4.1",

+ 2 - 1
package.json

@@ -4,6 +4,7 @@
   "scripts": {
     "dev": "vite",
     "start": "vite",
+    "update:element": "npm install element-plus deps/element-plus.2.0.4.1.tar.gz",
     "build": "vite build --mode=production",
     "build:development": "vite build --mode=development",
     "build:stag": "vite build --mode=staging",
@@ -24,7 +25,7 @@
     "dayjs": "^1.11.7",
     "driver.js": "^1.3.0",
     "echarts": "^5.2.0",
-    "element-plus": "file:deps/element-plus.tar.gz",
+    "element-plus": "file:deps/element-plus.2.0.4.1.tar.gz",
     "file-saver": "^2.0.5",
     "iconv-lite": "^0.6.3",
     "jquery": "^3.6.0",

+ 108 - 0
src/components/cy/message-box/cy-message-box.ts

@@ -0,0 +1,108 @@
+//@ts-ignore
+import MessageBoxConstructor from './index.vue';
+import {createVNode, render} from "vue";
+import {
+    Warning,
+    SuccessFilled,
+    InfoFilled,
+    CircleCloseFilled,
+    DeleteFilled
+} from '@element-plus/icons-vue'
+import {IElMessageBox, MessageBoxType} from "./message-box.type";
+
+const iconData = {
+    success: {
+        icon: SuccessFilled,
+        title: '成功',
+        iconColor: '#67c23a'
+    },
+    warning: {
+        icon: Warning,
+        title: '警告',
+        iconColor: '#e6a23c'
+    },
+    info: {
+        icon: InfoFilled,
+        title: '提示',
+        iconColor: '#909399'
+    },
+    error: {
+        icon: CircleCloseFilled,
+        title: '错误',
+        iconColor: '#f56c6c'
+    },
+    delete: {
+        icon: DeleteFilled,
+        title: '删除',
+        iconColor: '#f56c6c'
+    }
+}
+
+
+const MESSAGE_BOX_VARIANTS = ['alert', 'confirm', 'prompt'] as const
+const MESSAGE_BOX_DEFAULT_OPTS: {
+    [key in typeof MESSAGE_BOX_VARIANTS[number]]?: MessageBoxType
+} = {
+    alert: {closeOnPressEscape: false, closeOnClickModal: false, showCancelButton: false},
+    confirm: {showCancelButton: true},
+    prompt: {showInput: true},
+}
+
+MESSAGE_BOX_VARIANTS.forEach(item => {
+    MessageBox[item] = messageBoxFactory(item)
+})
+
+function messageBoxFactory(boxType: typeof MESSAGE_BOX_VARIANTS[number]) {
+    return (options: MessageBoxType) => {
+        return MessageBox(
+            Object.assign(
+                options,
+                {
+                    ...MESSAGE_BOX_DEFAULT_OPTS[boxType]
+                }
+            )
+        )
+    }
+}
+
+function getIcon(options: MessageBoxType) {
+    const data = iconData[options.type || 'info'];
+    data.title = options.title || data.title;
+    return data
+}
+
+function MessageBox(options: MessageBoxType) {
+    const div = document.createElement('div');
+    document.body.appendChild(div);
+    const icon = getIcon(options)
+
+    function clearDiv() {
+        render(null, div);
+        div.remove();
+    }
+
+    return new Promise((resolve, reject) => {
+
+        const data = {
+            onCancel: (val: string) => {
+                reject(val)
+            },
+            onConfirm: (val: string) => {
+                resolve(val);
+            },
+            onVanish: () => {
+                clearDiv();
+            }
+        }
+
+        Object.assign(data, options, {...icon});
+
+        const vNode = createVNode(MessageBoxConstructor,
+            data,
+            null);
+        render(vNode, div);
+    });
+
+}
+
+export default MessageBox as IElMessageBox;

+ 4 - 0
src/components/cy/message-box/index.ts

@@ -0,0 +1,4 @@
+import MessageBox from './cy-message-box'
+
+export default MessageBox
+export const CyMessageBox = MessageBox

+ 489 - 0
src/components/cy/message-box/index.vue

@@ -0,0 +1,489 @@
+<script setup lang="ts">
+import {
+  ElOverlay,
+  ElFocusTrap,
+  useZIndex,
+  ElInput,
+  ElSelect,
+  ElOption,
+  ElIcon,
+  useDraggable,
+  ElButton,
+} from "element-plus";
+import {nextTick, onMounted, ref, computed, watch} from "vue";
+import sleep from "@/utils/sleep";
+import {Close} from '@element-plus/icons-vue'
+import {useCompRef} from "@/utils/useCompRef";
+import {uuid} from '@/utils/getUuid'
+
+const props = defineProps({
+  title: {
+    type: String,
+    default: '提示'
+  },
+  draggable: {
+    type: Boolean,
+    default: true
+  },
+  message: {
+    type: String,
+    default: ''
+  },
+  showInput: {
+    type: Boolean,
+    default: false
+  },
+  icon: {
+    type: Object,
+    default: null
+  },
+  iconColor: {
+    type: String,
+    default: '',
+  },
+  closeOnClickModal: {
+    type: Boolean,
+    default: true
+  },
+  closeOnPressEscape: {
+    type: Boolean,
+    default: true
+  },
+  inputErrorMessage: {
+    type: String,
+    default: '检验未通过'
+  },
+  inputMaxLength: {
+    type: Number,
+    default: null
+  },
+  inputAllowEmpty: {
+    type: Boolean,
+    default: false
+  },
+  inputValidator: {
+    type: Function,
+    default: null
+  },
+  selectOption: {
+    type: Array,
+    default: null
+  },
+  dangerouslyUseHTMLString: {
+    type: Boolean,
+    default: false
+  },
+  inputDefaultValue: {
+    type: String,
+    default: ''
+  },
+  inputRows: {
+    type: Number,
+    default: null
+  },
+  showCancelButton: {
+    type: Boolean,
+    default: true
+  }
+})
+
+const emits = defineEmits(['cancel', 'confirm', 'vanish'])
+
+const visible = ref(false)
+const zIndex = ref(0)
+const rootRef = ref<HTMLDivElement>()
+const focusStartRef = ref<HTMLElement>()
+const inputRef = ref()
+const headerRef = ref<HTMLElement>()
+const draggable = computed(() => props.draggable)
+const confirmRef = useCompRef(ElButton)
+const dithering = ref(false)
+const inputValue = ref(props.inputDefaultValue)
+const errorMsg = ref('')
+const inputId = 'cy-message' + uuid(5, 62)
+
+const reboundClick = async () => {
+  dithering.value = true
+  await sleep(300)
+  dithering.value = false
+}
+
+const overlayClick = () => {
+  if (props.closeOnClickModal) {
+    handelClose('close')
+  } else {
+    reboundClick()
+  }
+}
+
+const outputErrorMessage = (value) => {
+  errorMsg.value = value
+  console.warn(value)
+}
+
+const submitVerification = (val): boolean => {
+  if (val === 'confirm' && props.showInput) {
+    if (!props.inputAllowEmpty) {
+      if (inputValue.value === '') {
+        outputErrorMessage('不允许为空。')
+        return false
+      }
+    }
+    if (props.inputMaxLength && inputValue.value.length > props.inputMaxLength) {
+      outputErrorMessage(`输入内容长度不能超过${props.inputMaxLength}`)
+      return false
+    }
+    if (props.inputValidator) {
+      const res = props.inputValidator(inputValue.value)
+      if (typeof res === 'string' && res.length > 0) {
+        outputErrorMessage(res)
+        return false
+      }
+      if (typeof res === 'boolean' && !res) {
+        outputErrorMessage(props.inputErrorMessage)
+        return false
+      }
+
+    }
+  }
+  return true
+}
+
+const handelClose = (val: 'cancel' | 'confirm' | 'close') => {
+  if (!submitVerification(val)) return
+  visible.value = false
+  if (val === 'confirm') {
+    emits('confirm', props.showInput ? inputValue.value : val)
+  } else {
+    emits('cancel', val)
+  }
+}
+
+const onCloseRequested = () => {
+  if (props.closeOnPressEscape) {
+    handelClose('close')
+  } else {
+    reboundClick()
+  }
+}
+
+
+watch(() => visible.value, (val) => {
+  if (val) {
+    nextTick(() => {
+      if (props.showInput) {
+        focusStartRef.value = inputRef.value?.$el ?? rootRef.value
+        sleep(200).then(() => {
+          inputRef.value?.focus()
+        })
+      } else {
+        focusStartRef.value = confirmRef.value?.$el ?? rootRef.value
+      }
+    })
+  }
+})
+
+useDraggable(rootRef, headerRef, draggable)
+
+onMounted(async () => {
+  zIndex.value = useZIndex().nextZIndex()
+  await nextTick()
+  await sleep(100);
+  visible.value = true
+})
+
+</script>
+
+<template>
+  <transition name="overlay_background">
+    <ElOverlay v-show="visible"
+               overlay-class="cy-message_overlay"
+               :z-index="zIndex">
+      <transition name="cy-enlarge" @after-leave="emits('vanish')">
+        <div role="dialog"
+             v-show="visible"
+             aria-modal="true"
+             class="cy-overlay-message-box"
+             @click="overlayClick">
+          <ElFocusTrap loop
+                       :trapped="visible"
+                       :focus-trap-el="rootRef"
+                       :focus-start-el="focusStartRef"
+                       @release-requested="onCloseRequested">
+            <div :class="dithering ? 'cy-message-box_dithering' : ''">
+              <div ref="rootRef" tabindex="-1" class="cy-message-box" @click.stop>
+                <header ref="headerRef">
+                  <div class="cy-message-box_title">
+                    <el-icon v-if="props.icon"
+                             :size="24"
+                             :style="{color: props.iconColor}">
+                      <component :is="props.icon"/>
+                    </el-icon>
+                    {{ props.title }}
+                  </div>
+
+                  <button @click.stop="handelClose('close')"
+                          @keydown.prevent.enter="handelClose('close')">
+                    <el-icon>
+                      <Close/>
+                    </el-icon>
+                  </button>
+
+                </header>
+                <div class="cy-message-box_body">
+                  <div class="cy-message-box_message">
+                    <component :is="props.showInput ? 'label' : 'p'"
+                               v-if="props.dangerouslyUseHTMLString"
+                               v-html="props.message"
+                               :for="inputId"></component>
+                    <component :is="props.showInput ? 'label' : 'p'"
+                               v-else
+                               :for="inputId">
+                      {{ props.message }}
+                    </component>
+                  </div>
+                  <div v-if="props.showInput" style="margin-top: 3px">
+                    <el-select v-model="inputValue"
+                               v-if="props.selectOption"
+                               size="small"
+                               filterable
+                               style="width: 100%"
+                               allow-create
+                               :reserve-keyword="true"
+                               default-first-option
+                               :id="inputId"
+                               ref="inputRef">
+                      <el-option v-for="item in props.selectOption"
+                                 :label="item.name"
+                                 :value="item.code"
+                                 :key="item.code"/>
+                    </el-select>
+                    <el-input v-model="inputValue"
+                              size="small"
+                              v-else
+                              :type="props.inputRows ? 'textarea' : 'text'"
+                              :rows="props.inputRows"
+                              :id="inputId"
+                              ref="inputRef"
+                              :maxlength="props.inputMaxLength"
+                              show-word-limit/>
+                    <div class="cy-message-box_error-msg"
+                         :style="{visibility: errorMsg ? 'visible' : 'hidden'}">
+                      {{ errorMsg }}
+                    </div>
+                  </div>
+                </div>
+                <footer>
+                  <el-button text
+                             v-if="props.showCancelButton"
+                             @click.stop="handelClose('cancel')"
+                             type="danger"
+                             @keydown.prevent.enter="handelClose('cancel')"
+                             class="cancel">取消
+                  </el-button>
+                  <el-button type="primary"
+                             class="confirm"
+                             @keydown.prevent.enter="handelClose('confirm')"
+                             ref="confirmRef"
+                             @click.stop="handelClose('confirm')">
+                    确认
+                  </el-button>
+                </footer>
+              </div>
+            </div>
+          </ElFocusTrap>
+        </div>
+      </transition>
+    </ElOverlay>
+  </transition>
+</template>
+
+<style lang="scss">
+
+
+@keyframes background {
+  0% {
+    background-color: rgba(0, 0, 0, 0.1);
+  }
+  100% {
+    background-color: rgba(0, 0, 0, 0.5);
+  }
+}
+
+.overlay_background-enter-active {
+  animation: background .25s ease;
+}
+
+.overlay_background-leave-active {
+  animation: background .25s reverse;
+}
+
+.cy-enlarge-enter-active {
+  animation: open .25s ease;
+  background-color: transparent;
+
+  @keyframes open {
+    0% {
+      transform: scale(.8);
+    }
+    40% {
+      transform: scale(1.08);
+    }
+    80% {
+      transform: scale(0.98);
+    }
+    90% {
+      transform: scale(1);
+    }
+    100% {
+      opacity: 1;
+      transform: scale(1)
+    }
+  }
+}
+
+
+.cy-enlarge-leave-active {
+  background-color: transparent;
+  animation: close .25s ease;
+
+  @keyframes close {
+    0% {
+      transform: scale(1)
+    }
+    100% {
+      transform: scale(0)
+    }
+  }
+
+}
+
+
+@keyframes reboundClick {
+  0% {
+    transform: scale(1)
+  }
+  40% {
+    transform: scale(1.05)
+  }
+  80% {
+    transform: scale(0.96)
+  }
+  100% {
+    transform: scale(1);
+  }
+}
+
+.cy-message_overlay {
+  //transition: background-color .15s ease;
+}
+
+.cy-overlay-message-box {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  padding: 16px;
+  overflow: auto;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  .cy-message-box_dithering {
+    animation: reboundClick .3s ease;
+  }
+
+  .cy-message-box {
+    display: inline-block;
+    border-radius: 20px;
+    background: #fff;
+
+    header {
+      padding: 15px 17px 9px 17px;
+      text-align: left;
+      position: relative;
+      cursor: move;
+      user-select: none;
+
+      .cy-message-box_title {
+        font-size: 18px;
+        display: flex;
+        align-items: center;
+
+        .el-icon {
+          margin-right: 10px;
+        }
+      }
+
+      button {
+        position: absolute;
+        top: -6px;
+        right: -6px;
+        border: 0;
+        height: 34px;
+        width: 34px;
+        box-sizing: border-box;
+        background: white;
+        border-radius: 12px;
+        box-shadow: 0 5px 20px 0 rgba(0, 0, 0, .05);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 20px;
+        color: black;
+        cursor: pointer;
+
+        &:hover {
+          -webkit-box-shadow: 0 0 4px 0 rgba(0, 0, 0, .05);
+          box-shadow: 0 0 4px 0 rgba(0, 0, 0, .05);
+          transform: translate(-2px, 2px);
+        }
+      }
+    }
+
+    .cy-message-box_body {
+      padding: 0 16px;
+      min-width: 420px;
+      max-width: 420px;
+
+      .cy-message-box_message {
+        max-height: 200px;
+        overflow: auto;
+        min-height: 30px;
+
+        &::-webkit-scrollbar {
+          width: 10px;
+          height: 10px;
+          display: block;
+          background: white;
+          cursor: pointer;
+        }
+
+        &::-webkit-scrollbar-thumb {
+          cursor: pointer;
+          border-radius: 5px;
+          background: #2C3E50;
+        }
+      }
+
+      .cy-message-box_error-msg {
+        height: 10px;
+        font-size: 12px;
+        color: var(--el-color-error);
+        min-height: 18px;
+      }
+
+    }
+
+    footer {
+      padding: 10px 16px;
+      display: flex;
+      justify-content: end;
+    }
+
+  }
+
+}
+
+</style>

+ 35 - 0
src/components/cy/message-box/message-box.type.ts

@@ -0,0 +1,35 @@
+export interface MessageBoxType {
+    message?: string;
+    title?: string;
+    showInput?: boolean;
+    type?: 'success' | 'warning' | 'info' | 'error' | 'delete';
+    closeOnClickModal?: boolean;
+    closeOnPressEscape?: boolean
+    inputMaxLength?: number,
+    inputAllowEmpty?: boolean,
+    inputValidator?: (inputValue: string) => boolean | string,
+    inputErrorMessage?: string;
+    dangerouslyUseHTMLString?: boolean
+    selectOption?: { code: string, name: string }[],
+    inputRows?: number;
+    showCancelButton?: boolean,
+    inputDefaultValue?: string
+}
+
+export type CyMessageBoxShortcutMethod = ((
+    options: MessageBoxType
+) => Promise<string>
+    )
+
+export interface IElMessageBox {
+    (options: MessageBoxType): Promise<string>
+
+    /** Show an alert message box */
+    alert: CyMessageBoxShortcutMethod
+
+    /** Show a confirm message box */
+    confirm: CyMessageBoxShortcutMethod
+
+    /** Show a prompt message box */
+    prompt: CyMessageBoxShortcutMethod
+}

+ 0 - 68
src/components/xiao-chan/cy-message-box-v2/cy-message-box-v2.ts

@@ -1,68 +0,0 @@
-//@ts-ignore
-import CyDialog from "../cy-dialog/cy-dialog.vue";
-import {createVNode, h, render} from "vue";
-import {uuid} from "../../../utils/getUuid";
-import {
-    Close,
-    Warning,
-    SuccessFilled,
-    InfoFilled,
-    CircleCloseFilled,
-    DeleteFilled
-} from '@element-plus/icons-vue'
-
-interface CyMessageBox {
-    message?: string;
-    type?: 'success' | 'error' | 'warning' | 'info' | 'delete',
-    titleAlign?: string;
-    titleIcon?: any;
-    titleIconColor?: any,
-    title?: string,
-    confirmButtonText?: string,
-    cancelButtonText?: string,
-}
-
-const headerIconData = {
-    success: {
-        icon: h(SuccessFilled),
-        title: '成功',
-        color: '#67c23a'
-    },
-    warning: {
-        icon: h(Warning),
-        title: '警告',
-        color: '#e6a23c'
-    },
-    info: {
-        icon: h(InfoFilled),
-        title: '提示',
-        color: '#909399'
-    },
-    error: {
-        icon: h(CircleCloseFilled),
-        title: '错误',
-        color: '#f56c6c'
-    },
-    delete: {
-        icon: h(DeleteFilled),
-        title: '删除',
-        color: '#f56c6c'
-    }
-}
-
-
-export function showMessage(options: CyMessageBox) {
-    const div = document.createElement('div');
-    document.body.appendChild(div)
-    return new Promise((resolve, reject) => {
-        const icon = headerIconData[options.type];
-        const data: CyMessageBox = {
-            titleAlign: 'left',
-            titleIcon: options.titleIcon || icon.icon,
-        }
-        //@ts-ignore
-        const vNode = createVNode(CyDialog, data, () => null)
-        render(vNode, div)
-    })
-
-}

+ 0 - 91
src/components/xiao-chan/cy-message-box-v2/index.vue

@@ -1,91 +0,0 @@
-<script setup lang="ts">
-import {onMounted, ref} from "vue";
-import CyDialog from "@/components/xiao-chan/cy-dialog/cy-dialog.vue";
-import {ElButton} from "element-plus";
-
-const props = defineProps({
-  title: {
-    type: String,
-    default: '提示'
-  },
-  closeOnClickModal: {
-    type: Boolean,
-    default: true
-  },
-  closeOnPressEscape: {
-    type: Boolean,
-    default: true
-  },
-  message: {
-    type: String,
-    default: '内容'
-  },
-  titleIcon: {
-    type: Object,
-  },
-  titleIconColor: {
-    type: String,
-    default: ''
-  },
-  confirmButtonText: {
-    type: String,
-    default: '确认'
-  },
-  cancelButtonText: {
-    type: String,
-    default: "取消"
-  }
-})
-
-const dialog = ref<boolean>(true)
-const dialogRef = ref<{
-  handleMakeClick: () => void
-}>()
-let close = null
-
-const beforeClose = (done, type) => {
-  close = close || 'close'
-  done()
-}
-
-function handelClose(val) {
-  close = val
-  dialog.value = false
-}
-
-function onClose() {
-  console.log(close)
-}
-
-onMounted(() => {
-  console.log(dialog.value);
-})
-console.log(dialog.value);
-</script>
-
-<template>
-  <cy-dialog v-model="dialog"
-             :title="props.title"
-             @closed="onClose"
-             ref="dialogRef"
-             :close-on-click-modal="props.closeOnClickModal"
-             :close-on-press-escape="props.closeOnPressEscape"
-             append-to-body
-             :before-close="beforeClose"
-             :title-icon-color="props.titleIconColor"
-             :title-icon="props.titleIcon">
-    {{ props.message }}
-    <template #footer>
-      <el-button type="danger" text size="default" @click="handelClose('cancel')">
-        {{ props.cancelButtonText }}
-      </el-button>
-      <el-button type="primary" size="default" @click="handelClose('confirm')">
-        {{ props.cancelButtonText }}
-      </el-button>
-    </template>
-  </cy-dialog>
-</template>
-
-<style scoped lang="scss">
-
-</style>

+ 0 - 134
src/components/xiao-chan/cy-message-box/cy-message-box.ts

@@ -1,134 +0,0 @@
-// @ts-ignore
-import messageBox from "./index.vue";
-import {createVNode, render} from "vue";
-import {uuid} from "../../../utils/getUuid";
-
-interface CyMessageBox {
-    message?: string;
-    showCancel?: boolean,
-    confirmClick?: (value: string) => void;
-    cancel?: (val: string) => void;
-    type?: 'success' | 'error' | 'warning' | 'info' | 'delete',
-    confirmButtonText?: string,
-    cancelButtonText?: string,
-    showInput?: boolean,
-    inputMinLength?: number,
-    inputMaxLength?: number,
-    inputValidator?: (val: string) => boolean | string,
-    inputErrorMessage?: string,
-    inputDefaultValue?: string,
-    setClose?: (val: any) => void,
-    inputRows?: number,
-    boxId?: string,
-    allowToBeEmpty?: boolean,
-    dangerouslyUseHTMLString?: boolean,
-    title?: string,
-    draggable?: boolean,
-    selectOption?: {
-        value: string,
-        label: string
-    }[],
-    closeOnPressEscape?: boolean;
-    closeOnClickModal?: boolean;
-}
-
-const currentBox: Map<string, HTMLDivElement> = new Map<string, HTMLDivElement>()
-
-const showMessage = (options: CyMessageBox): Promise<string> => {
-    const div = document.createElement('div');
-    div.style.setProperty('--cy-body-transform', 'translate(0px, 0px)')
-    document.body.appendChild(div);
-    div.id = options.boxId || 'cy-' + uuid(5);
-
-    if (currentBox.has(div.id)) {
-        closeByHtml(currentBox.get(div.id))
-    }
-
-    currentBox.set(div.id, div);
-
-    function closeBox(): void {
-        document.body.removeChild(div);
-        currentBox.delete(div.id);
-        if (currentBox.size === 0) {
-            document.body.className = ''
-        }
-    }
-
-    return new Promise((resolve, reject) => {
-        const data: CyMessageBox = {
-            confirmClick: (val) => {
-                resolve(val)
-                closeBox()
-            },
-            cancel: (val: string) => {
-                reject(val)
-                closeBox()
-            },
-            setClose: (val: any) => {
-                div['close'] = val
-            },
-        };
-
-        Object.assign(data, options)
-        const vNode = createVNode(messageBox, data as any, () => null)
-        render(vNode, div)
-    })
-}
-
-function closeByHtml(html: HTMLDivElement) {
-    try {
-        html && html['close']()
-    } catch {
-
-    }
-}
-
-function MessageBox(options: CyMessageBox) {
-    return showMessage(options)
-}
-
-const MESSAGE_BOX_VARIANTS = ['alert', 'confirm', 'prompt']
-const MESSAGE_BOX_DEFAULT_OPTS: {
-    [key: string]: CyMessageBox
-} = {
-    alert: {showCancel: false, closeOnPressEscape: false, closeOnClickModal: false},
-    confirm: {showCancel: true},
-    prompt: {showInput: true}
-}
-
-MESSAGE_BOX_VARIANTS.forEach(item => {
-    MessageBox[item] = messageBoxFactory(item)
-})
-
-MessageBox.close = (id?: string) => {
-    if (id) {
-        if (currentBox.has(id)) {
-            closeByHtml(currentBox.get(id))
-        }
-    } else {
-        currentBox.forEach(item => {
-            closeByHtml(item)
-        })
-    }
-}
-
-function messageBoxFactory(boxType: typeof MESSAGE_BOX_VARIANTS[number]) {
-    return (options: CyMessageBox) => {
-        return MessageBox(Object.assign({...MESSAGE_BOX_DEFAULT_OPTS[boxType]}, options))
-    }
-}
-
-interface CyMessageBoxShortcutMethod {
-    (options: CyMessageBox): Promise<string>
-}
-
-interface IElMessageBox {
-    (options: CyMessageBox): Promise<string>,
-
-    alert: CyMessageBoxShortcutMethod;
-    confirm: CyMessageBoxShortcutMethod;
-    prompt: CyMessageBoxShortcutMethod;
-    close: (boxId?: string) => void
-}
-
-export default MessageBox as IElMessageBox

+ 0 - 6
src/components/xiao-chan/cy-message-box/index.ts

@@ -1,6 +0,0 @@
-import MessageBox from "./cy-message-box";
-import type {Plugin} from 'vue'
-
-type SFCWithInstall<T> = T & Plugin
-const _MessageBox = MessageBox as SFCWithInstall<typeof MessageBox>
-export const CyMessageBox = _MessageBox

+ 0 - 548
src/components/xiao-chan/cy-message-box/index.vue

@@ -1,548 +0,0 @@
-<script lang="ts" setup>
-import {useZIndex, ElIcon, ElInput, ElSelect, ElOption} from "element-plus";
-import {nextTick, onMounted, ref, h, computed} from "vue";
-import sleep from "@/utils/sleep";
-// @ts-ignore
-import {
-  Close,
-  Warning,
-  SuccessFilled,
-  InfoFilled,
-  CircleCloseFilled,
-  DeleteFilled
-} from '@element-plus/icons-vue'
-import {useCompRef} from "@/utils/useCompRef";
-import {useCyDraggable} from "@/utils/use-cy-draggable";
-import {uuid} from "@/utils/getUuid";
-import ElFocusTrap from "@/components/xiao-chan/focus-trap/src/focus-trap.vue";
-
-const props = withDefaults(defineProps<{
-  message?: string;
-  showCancel?: boolean,
-  confirmClick?: (value: string) => void;
-  cancel?: (val: string) => void;
-  type?: 'success' | 'error' | 'warning' | 'info',
-  confirmButtonText?: string,
-  cancelButtonText?: string,
-  showInput?: boolean,
-  inputMinLength?: number,
-  inputMaxLength?: number,
-  inputValidator?: (val: string) => boolean | string,
-  inputErrorMessage?: string,
-  inputDefaultValue?: string,
-  setClose?: (val: any) => void,
-  inputRows?: number,
-  boxId?: string,
-  allowToBeEmpty?: boolean,
-  dangerouslyUseHTMLString?: boolean,
-  title?: string,
-  draggable?: boolean,
-  selectOption?: {
-    value: string,
-    label: string
-  }[],
-  closeOnPressEscape?: boolean;
-  closeOnClickModal?: boolean
-}>(), {
-  type: 'info',
-  showCancel: true,
-  confirmButtonText: '确认',
-  cancelButtonText: '取消',
-  inputErrorMessage: '校验未通过',
-  allowToBeEmpty: false,
-  dangerouslyUseHTMLString: false,
-  draggable: true,
-  inputDefaultValue: '',
-  selectOption: null,
-  inputRows: 0,
-  inputMaxLength: 0,
-  closeOnPressEscape: true,
-  closeOnClickModal: true
-})
-
-const visible = ref(false)
-const headerRef = ref<HTMLHeadElement>(null)
-const inputValue = ref(props.inputDefaultValue)
-const errorMsg = ref('')
-const inputRef = useCompRef(ElInput)
-const confirmRef = ref<HTMLElement>()
-const bodyRef = ref<HTMLElement>()
-const mainRef = ref<HTMLElement>()
-const focusStartRef = ref<HTMLElement>()
-const isSelectInput = ref<boolean>(props.selectOption !== null)
-const inputId = ref('cy-' + uuid(5, 62))
-
-let closeMode = ''
-
-const mainStyle = ref({
-  zIndex: 0,
-  display: 'flex'
-})
-
-const contentStyle = ref({
-  zIndex: 0,
-})
-
-function nextZIndex() {
-  return useZIndex().nextZIndex()
-}
-
-/**
- * 关闭动画
- */
-function onAfterLeave() {
-  mainStyle.value.display = 'none'
-  if (!visible.value) {
-    if (closeMode === 'close' || closeMode === 'cancel') {
-      props.cancel(closeMode)
-    } else {
-      props.confirmClick(inputValue.value)
-    }
-  }
-}
-
-/**
- * 开启动画
- */
-function onAfterEnter() {
-  mainStyle.value.display = 'flex';
-}
-
-function handleConfirm() {
-  if (props.showInput) {
-    handlePrompt()
-  } else {
-    visible.value = false;
-    closeMode = ''
-  }
-}
-
-function verificationFailed(value: string) {
-  errorMsg.value = value
-  popupJitter()
-}
-
-function handlePrompt() {
-  function next() {
-    visible.value = false;
-    closeMode = ''
-  }
-
-  if (!props.allowToBeEmpty) {
-    if (inputValue.value === '') {
-      verificationFailed('不允许为空。')
-      return
-    }
-  }
-
-  if (props.inputMaxLength !== 0) {
-    if (inputValue.value.length > props.inputMaxLength) {
-      verificationFailed(`最大长度不得超过${props.inputMaxLength}个字。`)
-      return
-    }
-  }
-
-
-  if (props.inputValidator) {
-    const inputValidator = props.inputValidator(inputValue.value)
-    if (typeof inputValidator === 'boolean') {
-      if (inputValidator) {
-        next()
-      } else {
-        verificationFailed(props.inputErrorMessage)
-      }
-    }
-
-    if (typeof inputValidator === 'string') {
-      if (inputValidator) {
-        verificationFailed(inputValidator)
-      } else {
-        next()
-      }
-    }
-
-  } else {
-    next()
-  }
-}
-
-function handleClose(val: 'close' | 'cancel') {
-  bodyRef.value.style.transition = ''
-  visible.value = false
-  closeMode = val
-}
-
-const headerData = {
-  success: {
-    icon: h(SuccessFilled),
-    title: '成功',
-    color: '#67c23a'
-  },
-  warning: {
-    icon: h(Warning),
-    title: '警告',
-    color: '#e6a23c'
-  },
-  info: {
-    icon: h(InfoFilled),
-    title: '提示',
-    color: '#909399'
-  },
-  error: {
-    icon: h(CircleCloseFilled),
-    title: '错误',
-    color: '#f56c6c'
-  },
-  delete: {
-    icon: h(DeleteFilled),
-    title: '删除',
-    color: '#f56c6c'
-  }
-}
-
-function headerColor() {
-  return headerData[props.type].color
-}
-
-function headerIcon() {
-  return headerData[props.type].icon
-}
-
-function titleRender() {
-  return h('span', {style: {marginLeft: '8px'}}, props.title || headerData[props.type].title)
-}
-
-/**
- * 弹窗抖动
- */
-async function popupJitter() {
-  const oldTransform = bodyRef.value.style.transform
-  bodyRef.value.style.transform = oldTransform + ' scale(1.1)';
-  await sleep(100)
-  bodyRef.value.style.transform = oldTransform;
-}
-
-const draggable = computed(() => props.draggable)
-
-useCyDraggable(bodyRef, headerRef, draggable,
-    () => {
-      bodyRef.value.style.transition = 'none'
-      inputRef.value.blur();
-    }, () => {
-      mainRef.value.parentElement.style.setProperty('--cy-body-transform', bodyRef.value.style.transform)
-      bodyRef.value.style.transition = ''
-    }
-)
-
-function onCloseRequested() {
-  if (props.closeOnPressEscape) {
-    handleClose('close')
-  } else {
-    popupJitter()
-  }
-}
-
-function maskClick() {
-  if (props.closeOnClickModal) {
-    handleClose('close')
-  } else {
-    popupJitter()
-  }
-}
-
-
-onMounted(async () => {
-  mainStyle.value.zIndex = nextZIndex()
-  contentStyle.value.zIndex = nextZIndex()
-  document.body.className = 'el-popup-parent--hidden'
-  await nextTick()
-  if (props.showInput) {
-    focusStartRef.value = mainRef.value
-  } else {
-    focusStartRef.value = confirmRef?.value ?? mainRef.value
-  }
-  await sleep(100)
-  visible.value = true
-  props.setClose(close)
-})
-
-function close() {
-  handleClose('close')
-}
-</script>
-
-<template>
-  <div class="cy-message-box_main"
-       :style="mainStyle"
-       ref="mainRef"
-       role="dialog"
-       aria-modal="true"
-       @click.stop="maskClick">
-    <el-focus-trap
-        :trapped="visible"
-        :focus-trap-el="mainRef"
-        :focus-start-el="focusStartRef"
-        @release-requested="onCloseRequested">
-      <transition name="cy-message_show" @after-enter="onAfterEnter" @after-leave="onAfterLeave">
-        <div class="cy-message-box_body"
-             tabindex="-1"
-             v-show="visible"
-             :style="contentStyle"
-             @click.stop
-             ref="bodyRef">
-          <div class="cy-message-box_close" @click.stop="handleClose('close')">
-            <ElIcon>
-              <Close/>
-            </ElIcon>
-          </div>
-          <header ref="headerRef">
-            <el-icon :style="{color: headerColor() }"
-                     class="cy-message_header-icon">
-              <component :is="headerIcon"/>
-            </el-icon>
-            <Component :is="titleRender"/>
-          </header>
-          <div class="cy_message-box_content">
-            <div class="message" v-if="props.message">
-              <component
-                  v-if="props.dangerouslyUseHTMLString"
-                  :for="inputId"
-                  :is="props.showInput ? 'label' : 'span'"
-                  v-html="props.message">
-              </component>
-              <component v-else
-                         :is="props.showInput ? 'label' : 'span'"
-                         :for="inputId">
-                {{ props.message }}
-              </component>
-            </div>
-            <div v-if="props.showInput" style="margin-top: 9px">
-              <ElSelect v-model="inputValue"
-                        v-if="isSelectInput"
-                        :id="inputId"
-                        style="width: 100%"
-                        :multiple="false"
-                        :filterable="true"
-                        :allow-create="true"
-                        :default-first-option="true"
-                        :reserve-keyword="false"
-                        ref="inputRef">
-                <ElOption v-for="item in props.selectOption" :key="item.value" :label="item.label" :value="item.value"/>
-              </ElSelect>
-              <ElInput
-                  v-else
-                  ref="inputRef"
-                  :autofocus="true"
-                  :rows="props.inputRows"
-                  :type="props.inputRows === 0 ? '' : 'textarea'"
-                  :minlength="props.inputMinLength"
-                  :maxlength="props.inputMaxLength"
-                  :show-word-limit="true"
-                  :id="inputId"
-                  v-model.trim="inputValue"/>
-            </div>
-            <div v-if="props.showInput" class="error_msg">
-              {{ errorMsg }}
-            </div>
-          </div>
-          <footer>
-            <button class="cancel"
-                    style="margin-right: 12px"
-                    v-if="props.showCancel"
-                    @click="handleClose('cancel')"
-                    :style="{'--cy--bg-color': '245,108,108','--cy-color': '#F56C6C'}">
-              {{ props.cancelButtonText }}
-            </button>
-            <button class="confirm"
-                    ref="confirmRef"
-                    :style="{'--cy--bg-color': '26, 92, 255','--cy-color': '#2C69FF'}"
-                    @click="handleConfirm">
-              {{ props.confirmButtonText }}
-            </button>
-          </footer>
-        </div>
-      </transition>
-    </el-focus-trap>
-  </div>
-</template>
-
-<style lang="scss">
-.cy-message_show-enter-active {
-  transform: scale(0.9);
-}
-
-.cy-message_show-enter-to {
-  transform: scale(1);
-}
-
-.cy-message_show-leave-active {
-  transform: var(--cy-body-transform) scale(1) !important;
-}
-
-.cy-message_show-leave-to {
-  transform: var(--cy-body-transform) scale(0) !important;
-}
-
-.cy-message-box_main {
-  background: rgba(0, 0, 0, .2);
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-
-  .cy-message-box_body {
-    display: inline-block;
-    height: max-content;
-    width: 418px;
-    background-color: white;
-    border-radius: 20px;
-    padding: 5px;
-    position: relative;
-    transition: transform .2s ease-out;
-
-    .cy-message-box_close {
-      position: absolute;
-      top: -6px;
-      right: -6px;
-      border: 0;
-      height: 34px;
-      width: 34px;
-      box-sizing: border-box;
-      background: inherit;
-      border-radius: 12px;
-      box-shadow: 0 5px 20px 0 rgba(0, 0, 0, .05);
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 20px;
-      color: black;
-      cursor: pointer;
-
-      &:hover {
-        -webkit-box-shadow: 0 0 4px 0 rgba(0, 0, 0, .05);
-        box-shadow: 0 0 4px 0 rgba(0, 0, 0, .05);
-        transform: translate(-2px, 2px);
-      }
-    }
-
-    header {
-      cursor: move;
-      user-select: none;
-      display: -webkit-box;
-      display: -ms-flexbox;
-      display: flex;
-      align-items: center;
-      justify-content: start;
-      padding: 10px 16px;
-      box-sizing: border-box !important;
-
-      span {
-        margin-left: 8px;
-        font-size: 20px;
-        font-weight: bold;
-      }
-
-      .cy-message_header-icon {
-        font-size: 24px;
-      }
-
-    }
-
-    .cy_message-box_content {
-      padding: 10px 16px;
-      width: 100%;
-      position: relative;
-      border-radius: inherit;
-      box-sizing: border-box;
-
-      .error_msg {
-        color: #f56c6c;
-        font-size: 12px;
-        min-height: 18px;
-        margin-top: 2px;
-      }
-
-      .message {
-        box-sizing: border-box;
-        min-height: 20px;
-        max-height: 200px;
-        overflow: auto;
-
-        &::-webkit-scrollbar {
-          width: 5px;
-          height: 5px;
-          display: block;
-          background: white;
-        }
-
-        &::-webkit-scrollbar-thumb {
-          background: #2C3E50;
-          border-radius: 5px;
-        }
-
-      }
-
-    }
-
-    footer {
-      display: flex;
-      align-items: center;
-      justify-content: flex-end;
-      padding: 0 16px 10px 16px;
-
-      button {
-        width: 60px;
-        line-height: 28px;
-        text-align: center;
-        border-radius: 12px;
-        cursor: pointer;
-        position: relative;
-        color: var(--cy-color);
-        outline: none;
-        list-style: none;
-        user-select: none;
-        background: transparent;
-        box-sizing: border-box;
-        border: 1px solid transparent;
-        transition: border .3s ease-out;
-
-        &:focus-visible {
-          border: 1px solid var(--cy-color);
-        }
-
-        &:hover {
-          border: 1px solid transparent !important;
-        }
-
-        &:hover:before {
-          transform: scale(1.3);
-        }
-
-        &:before {
-          opacity: 1;
-          transform: scale(1);
-          content: "";
-          background: rgba(var(--cy--bg-color), .1);
-          position: absolute;
-          bottom: 0;
-          left: 0;
-          width: 100%;
-          height: 100%;
-          border-radius: 8px;
-          pointer-events: none;
-          -webkit-transition: all .25s ease;
-          transition: all .25s ease;
-          z-index: -1;
-          box-sizing: border-box;
-        }
-      }
-
-    }
-
-  }
-}
-</style>

+ 1 - 1
src/components/zhu-yuan-yi-sheng/yi-zhu-lu-ru/yz-edit/YzEditor.vue

@@ -300,7 +300,7 @@ import {
 } from 'vue'
 import {userInfoStore} from "@/utils/store-public";
 import {getServerDate} from "@/utils/moment-utils";
-import {CyMessageBox} from "@/components/xiao-chan/cy-message-box/index";
+import {CyMessageBox} from "@/components/cy/message-box";
 
 const props = withDefaults(defineProps<{
   patientInfo: {

+ 6 - 6
src/views/examination/BloodSugarQuery/BloodSugarQuery.vue

@@ -107,22 +107,22 @@ const print = () => {
             </tr>
             <tr class="no_border">
                 <th colspan="3">
-                    姓名:${nullToEmpty(patientInfo?.name)}
+                    姓名:${nullToEmpty(patientInfo.value?.name)}
                 </th>
                 <th colspan="3">
-                    性别:${nullToEmpty(patientInfo?.sexName)}
+                    性别:${nullToEmpty(patientInfo.value?.sexName)}
                 </th>
                 <th colspan="3">
-                    年龄:${nullToEmpty(patientInfo?.age)}
+                    年龄:${nullToEmpty(patientInfo.value?.age)}
                 </th>
                 <th colspan="3">
-                    科室:${nullToEmpty(patientInfo?.zkWardName)}
+                    科室:${nullToEmpty(patientInfo.value?.zkWardName)}
                 </th>
                 <th colspan="3">
-                    床号:${nullToEmpty(patientInfo?.bedNo)}
+                    床号:${nullToEmpty(patientInfo.value?.bedNo)}
                 </th>
                 <th colspan="3">
-                    住院号: ${nullToEmpty(patientInfo?.inpatientNo)}
+                    住院号: ${nullToEmpty(patientInfo.value?.inpatientNo)}
                 </th>
                 <th colspan="3">
                     单位:mmol/L

+ 11 - 16
src/views/hospitalization/zhu-yuan-yi-sheng/yi-zhu-lu-ru/YiZhuLuRu.vue

@@ -47,8 +47,6 @@
 <script setup lang="ts">
 import {
   deleteMultipleOrders,
-  getFrequency,
-  getSupplyType,
   insertTemplateOrder,
 } from '@/api/zhu-yuan-yi-sheng/yi-zhu-lu-ru'
 import {
@@ -63,12 +61,9 @@ import {
   yzData,
   errorMsg,
   yzMitt,
-  geiYaoFangShiData,
-  yaoPinPingLvData,
   confirmLoading,
   setYzOrderGroup, YzType
 } from '../public-js/zhu-yuan-yi-sheng'
-import store from '@/store'
 import {stringIsBlank, stringNotBlank} from '@/utils/blank-utils'
 import {getTheTransferList} from '@/api/public-api'
 import router from '@/router'
@@ -89,7 +84,7 @@ import {applicationForRevocation} from "@/api/zhu-yuan-yi-sheng/qrder-quash";
 import XEUtils from 'xe-utils'
 import {isDev} from "@/utils/public";
 import {ref, onMounted, onActivated, nextTick} from 'vue'
-import {CyMessageBox} from "@/components/xiao-chan/cy-message-box/index";
+import {CyMessageBox} from "@/components/cy/message-box";
 
 let allergen = ref({
   dialog: false,
@@ -180,16 +175,16 @@ const orderQuash = async (val) => {
     dangerouslyUseHTMLString: true,
     inputDefaultValue: '医嘱开错',
     selectOption: [
-      {value: '医嘱开错', label: '医嘱开错'},
-      {value: '未充分告知患者', label: '未充分告知患者'},
-      {value: '临时出院', label: '临时出院'},
-      {value: '患者拒绝用药', label: '患者拒绝用药'},
-      {value: '药房缺药', label: '药房缺药'},
-      {value: '药物不耐受或过敏', label: '药物不耐受或过敏'},
-      {value: '药品更换厂家或规格', label: '药品更换厂家或规格'},
-      {value: '转科或者转院', label: '转科或者转院'},
-      {value: '病情变化', label: '病情变化'},
-      {value: '患者欠费未生成药单', label: '患者欠费未生成药单'},
+      {code: '医嘱开错', name: '医嘱开错'},
+      {code: '未充分告知患者', name: '未充分告知患者'},
+      {code: '临时出院', name: '临时出院'},
+      {code: '患者拒绝用药', name: '患者拒绝用药'},
+      {code: '药房缺药', name: '药房缺药'},
+      {code: '药物不耐受或过敏', name: '药物不耐受或过敏'},
+      {code: '药品更换厂家或规格', name: '药品更换厂家或规格'},
+      {code: '转科或者转院', name: '转科或者转院'},
+      {code: '病情变化', name: '病情变化'},
+      {code: '患者欠费未生成药单', name: '患者欠费未生成药单'},
     ],
     inputValidator: (val: string) => {
       if (val.length > 50) {