<template> <Teleport> <Transition name="fade"> <div :class="['mask-layer', { 'none-mask': noneMask }]" v-if="modelVisible"> <BackgroundClip class='dialog' clipPath="polygon(calc(100% - var(--clip-width)) 0, 100% var(--clip-width), 100% 100%, var(--clip-width) 100%, 0 calc(100% - var(--clip-width)), 0 0)" borderColor="linear-gradient(180deg, rgba(78, 174, 204, .9), rgba(78, 174, 204, 0))" bgColor="linear-gradient(180deg, rgba(14, 69, 92, 0.9) 0%, rgba(20, 89, 119, 0.9) 100%)" ref="DialogContentRef"> <div class="dialog-title"> <img class="title-icon" src="@screen/images/dialog/title-icon.svg" /> <span>{{ title }}</span> <img class="icon-close" @click.stop="modelVisible = false" src="@screen/images/dialog/icon-close.svg" /> </div> <div class="dialog-content"> <slot /> </div> <img class="bottom-right" src="@screen/images/dialog/right-bottom.svg"> <div class="footer" v-if="$slots.footer"> <slot name="footer"></slot> </div> </BackgroundClip> </div> </Transition> </Teleport> </template> <script> import Teleport from '../Teleport.vue'; import BackgroundClip from "@screen/components/Decorations/BackgroundClip.vue"; import { moveable, stopPropagation } from "./utils" export default { components: { Teleport, BackgroundClip }, model: { prop: 'visible', event: "update:value" }, name: 'Dialog', props: { title: { type: String }, visible: Boolean, noneMask: { type: Boolean, default: false } }, watch: { visible: { deep: true, handler(bool) { this.$nextTick(() => { if (!bool) return this.destroyMoveable?.() const container = this.$refs.DialogContentRef.$el; this.destroyMoveable = moveable(container, { target: container.querySelector(".dialog-title") }); stopPropagation(container.querySelector(".dialog-title").lastChild) this.$once("hook:beforeDestroy", () => this.destroyMoveable?.()); }) } } }, computed: { modelVisible: { get() { return this.visible }, set(val) { this.$emit('update:value', val) } } }, beforeDestroy() { this.modelVisible = false; }, } </script> <style lang='scss' scoped> .mask-layer { position: fixed; top: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, .36); border-radius: 0px 0px 0px 0px; z-index: 100; display: flex; align-items: center; justify-content: center; --border-width: 1px; --clip-width-num: 24; --clip-width: calc(var(--clip-width-num) * 1px); } .none-mask { background: rgba(0, 0, 0, 0); pointer-events: none; } .fade-enter-active, .fade-leave-active { transition: opacity .24s; } .fade-enter, .fade-leave-to { opacity: 0; } .dialog { max-width: 72vw; opacity: 1; background-clip: padding-box; position: relative; box-sizing: border-box; margin: calc(var(--border-width) / 2); pointer-events: all; .dialog-title { position: relative; width: calc(100% - 2px); height: 51px; display: flex; padding-top: 3px; align-items: center; justify-content: space-between; background: linear-gradient(90deg, #267494 0%, rgba(38, 116, 148, 0) 100%); font-size: 19px; font-family: PingFang SC, PingFang SC; font-weight: 500; color: #3de8ff; .title-icon { position: absolute; top: -1px; left: -1px; height: 6px; } .icon-close { cursor: pointer; margin-right: 21px; } span { margin-left: 20px; height: 48px; display: flex; align-items: center; } } .dialog-content { padding: 9px 21px 27px 21px; max-height: 75vh; overflow-y: auto; } .bottom-right { position: absolute; right: 0; bottom: 0; } .footer { display: flex; align-items: center; gap: 9px; width: 100%; justify-content: flex-end; margin-bottom: 21px; padding: 0 27px; ::v-deep { >div { min-width: 96px; } } // padding: 21px 36px; // padding-top: 9px; } } </style>