|
|
@@ -1,6 +1,6 @@
|
|
|
<script lang="ts" setup>
|
|
|
-import {useZIndex, ElIcon, ElInput} from "element-plus";
|
|
|
-import {nextTick, onMounted, ref, h} from "vue";
|
|
|
+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 {
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
} from '@element-plus/icons-vue'
|
|
|
import {getCyId} from "@/components/xiao-chan/cy-message-box/cy-message-box";
|
|
|
import {useCompRef} from "@/utils/useCompRef";
|
|
|
+import {useCyDraggable} from "@/utils/use-cy-draggable";
|
|
|
|
|
|
const props = withDefaults(defineProps<{
|
|
|
message?: string;
|
|
|
@@ -26,27 +27,39 @@ const props = withDefaults(defineProps<{
|
|
|
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
|
|
|
+ title?: string,
|
|
|
+ draggable?: boolean,
|
|
|
+ selectOption?: {
|
|
|
+ value: string,
|
|
|
+ label: string
|
|
|
+ }[]
|
|
|
}>(), {
|
|
|
showCancel: true,
|
|
|
confirmButtonText: '确认',
|
|
|
cancelButtonText: '取消',
|
|
|
inputErrorMessage: '校验未通过',
|
|
|
allowToBeEmpty: false,
|
|
|
- dangerouslyUseHTMLString: false
|
|
|
+ dangerouslyUseHTMLString: false,
|
|
|
+ draggable: true,
|
|
|
+ inputDefaultValue: '',
|
|
|
+ selectOption: null
|
|
|
})
|
|
|
|
|
|
const visible = ref(false)
|
|
|
const headerRef = ref<HTMLHeadElement>(null)
|
|
|
-const inputValue = ref('')
|
|
|
+const inputValue = ref(props.inputDefaultValue)
|
|
|
const errorMsg = ref('')
|
|
|
const inputRef = useCompRef(ElInput)
|
|
|
-
|
|
|
+const confirmRef = ref<HTMLButtonElement>()
|
|
|
+const bodyRef = ref<HTMLDivElement>()
|
|
|
+const mainRef = ref<HTMLDivElement>()
|
|
|
+const isSelectInput = ref<boolean>(props.selectOption !== null)
|
|
|
const inputId = ref(getCyId())
|
|
|
|
|
|
let closeMode = ''
|
|
|
@@ -82,7 +95,12 @@ function onAfterLeave() {
|
|
|
* 开启动画
|
|
|
*/
|
|
|
function onAfterEnter() {
|
|
|
- mainStyle.value.display = 'flex'
|
|
|
+ mainStyle.value.display = 'flex';
|
|
|
+ if (props.showInput && !isSelectInput.value) {
|
|
|
+ inputRef.value.focus();
|
|
|
+ } else {
|
|
|
+ confirmRef.value.focus()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function handleConfirm() {
|
|
|
@@ -131,6 +149,7 @@ function handlePrompt() {
|
|
|
}
|
|
|
|
|
|
function handleClose(val) {
|
|
|
+ bodyRef.value.style.transition = ''
|
|
|
visible.value = false
|
|
|
closeMode = val
|
|
|
}
|
|
|
@@ -160,6 +179,25 @@ function titleRender() {
|
|
|
}
|
|
|
|
|
|
|
|
|
+async function maskClick() {
|
|
|
+ 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'
|
|
|
+ }, () => {
|
|
|
+ mainRef.value.parentElement.style.setProperty('--cy-body-transform', bodyRef.value.style.transform)
|
|
|
+ bodyRef.value.style.transition = ''
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
onMounted(async () => {
|
|
|
mainStyle.value.zIndex = nextZIndex()
|
|
|
contentStyle.value.zIndex = nextZIndex()
|
|
|
@@ -168,21 +206,27 @@ onMounted(async () => {
|
|
|
await sleep(100)
|
|
|
visible.value = true
|
|
|
props.setClose(close)
|
|
|
- if (props.showInput) {
|
|
|
- await inputRef.value.focus();
|
|
|
- }
|
|
|
})
|
|
|
|
|
|
function close() {
|
|
|
handleClose('close')
|
|
|
}
|
|
|
-
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <div class="cy-message-box_main" :style="mainStyle" role="dialog" aria-modal="true">
|
|
|
+ <div class="cy-message-box_main"
|
|
|
+ :style="mainStyle"
|
|
|
+ ref="mainRef"
|
|
|
+ role="dialog"
|
|
|
+ aria-modal="true"
|
|
|
+ @click.stop="maskClick">
|
|
|
<transition name="cy-message_show" @after-enter="onAfterEnter" @after-leave="onAfterLeave">
|
|
|
- <div class="cy-message-box_body" v-show="visible" :style="contentStyle">
|
|
|
+ <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/>
|
|
|
@@ -210,7 +254,21 @@ function close() {
|
|
|
</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"
|
|
|
@@ -226,16 +284,19 @@ function close() {
|
|
|
</div>
|
|
|
</div>
|
|
|
<footer>
|
|
|
- <div class="cancel"
|
|
|
- v-if="props.showCancel"
|
|
|
- @click="handleClose('cancel')"
|
|
|
- :style="{'--cy--bg-color': '245,108,108','--cy-color': '#F56C6C'}">
|
|
|
+ <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 }}
|
|
|
- </div>
|
|
|
- <div class="confirm" :style="{'--cy--bg-color': '26, 92, 255','--cy-color': '#2C69FF'}"
|
|
|
- @click="handleConfirm">
|
|
|
+ </button>
|
|
|
+ <button class="confirm"
|
|
|
+ ref="confirmRef"
|
|
|
+ :style="{'--cy--bg-color': '26, 92, 255','--cy-color': '#2C69FF'}"
|
|
|
+ @click="handleConfirm">
|
|
|
{{ props.confirmButtonText }}
|
|
|
- </div>
|
|
|
+ </button>
|
|
|
</footer>
|
|
|
</div>
|
|
|
</transition>
|
|
|
@@ -253,27 +314,23 @@ function close() {
|
|
|
}
|
|
|
|
|
|
.cy-message_show-leave-active {
|
|
|
- transform: scale(1);
|
|
|
+ transform: var(--cy-body-transform) scale(1) !important;
|
|
|
}
|
|
|
|
|
|
.cy-message_show-leave-to {
|
|
|
- transform: scale(0);
|
|
|
+ transform: var(--cy-body-transform) scale(0) !important;
|
|
|
}
|
|
|
|
|
|
.cy-message-box_main {
|
|
|
- background: rgba(0, 0, 0, .2);
|
|
|
+ background: rgba(0, 0, 0, .5);
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
|
|
|
- justify-content: center;
|
|
|
- align-content: center;
|
|
|
- -webkit-backdrop-filter: saturate(180%) blur(15px);
|
|
|
- backdrop-filter: saturate(180%) blur(15px);
|
|
|
-
|
|
|
.cy-message-box_body {
|
|
|
+ display: inline-block;
|
|
|
height: max-content;
|
|
|
width: 418px;
|
|
|
margin: auto;
|
|
|
@@ -309,6 +366,7 @@ function close() {
|
|
|
}
|
|
|
|
|
|
header {
|
|
|
+ cursor: move;
|
|
|
user-select: none;
|
|
|
display: -webkit-box;
|
|
|
display: -ms-flexbox;
|
|
|
@@ -385,10 +443,12 @@ function close() {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: flex-end;
|
|
|
+ padding: 0 16px 10px 16px;
|
|
|
|
|
|
- div {
|
|
|
- width: 85px;
|
|
|
- line-height: 39px;
|
|
|
+ button {
|
|
|
+ border: 0;
|
|
|
+ width: 60px;
|
|
|
+ line-height: 28px;
|
|
|
text-align: center;
|
|
|
border-radius: 12px;
|
|
|
cursor: pointer;
|
|
|
@@ -397,13 +457,15 @@ function close() {
|
|
|
outline: none;
|
|
|
list-style: none;
|
|
|
user-select: none;
|
|
|
+ background: transparent;
|
|
|
|
|
|
&:hover:before {
|
|
|
- opacity: 1;
|
|
|
- transform: scale(1);
|
|
|
+ transform: scale(1.3);
|
|
|
}
|
|
|
|
|
|
&:before {
|
|
|
+ opacity: 1;
|
|
|
+ transform: scale(1);
|
|
|
content: "";
|
|
|
background: rgba(var(--cy--bg-color), .1);
|
|
|
position: absolute;
|
|
|
@@ -411,13 +473,11 @@ function close() {
|
|
|
left: 0;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
- border-radius: inherit;
|
|
|
+ border-radius: 8px;
|
|
|
pointer-events: none;
|
|
|
-webkit-transition: all .25s ease;
|
|
|
transition: all .25s ease;
|
|
|
z-index: -1;
|
|
|
- transform: scale(.5);
|
|
|
- opacity: 0;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
}
|