270 lines
6.2 KiB
Vue
270 lines
6.2 KiB
Vue
<script setup lang="ts">
|
|
import { ref, watch, onMounted, nextTick } from 'vue';
|
|
const props = defineProps({
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
width: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
height: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
top: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
left: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
id: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
bodyId: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
clearAnimation: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
fix: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
className: {
|
|
type: String
|
|
},
|
|
nofold: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
isfold: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
noClose: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
show: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
closeCallback: {
|
|
type: Function,
|
|
default: () => {}
|
|
}
|
|
});
|
|
// 内部状态
|
|
const first = ref(false);
|
|
const dialogVisible = ref(false);
|
|
const FontChart = ref(undefined);
|
|
const callback = ref(undefined);
|
|
const baseDialog = ref(null);
|
|
const titleBox = ref(null);
|
|
const dialogContent = ref(null);
|
|
const tableData = ref([]);
|
|
// 方法定义
|
|
const open = (data) => {
|
|
if (!first.value) {
|
|
first.value = true;
|
|
dialogVisible.value = true;
|
|
nextTick(() => {
|
|
moveDiv();
|
|
});
|
|
}
|
|
dialogVisible.value = true;
|
|
nextTick(() => {
|
|
// setTimeout(() => {
|
|
// openPosition()
|
|
// }, 0)
|
|
if (baseDialog.value) {
|
|
baseDialog.value.style.width = props.width;
|
|
baseDialog.value.style.height = props.height;
|
|
baseDialog.value.style.top = props.top;
|
|
baseDialog.value.style.left = props.left;
|
|
baseDialog.value.style.position = props.fix ? 'fixed' : 'absolute';
|
|
}
|
|
});
|
|
};
|
|
|
|
const close = () => {
|
|
dialogVisible.value = false;
|
|
if (props.clearAnimation) {
|
|
// 假设mapService是全局可用的
|
|
// window.mapService?.removeAnimation();
|
|
}
|
|
callback.value && callback.value();
|
|
|
|
props.closeCallback && props.closeCallback();
|
|
};
|
|
|
|
const moveDiv = () => {
|
|
let x = 0;
|
|
let y = 0;
|
|
let l = 0;
|
|
let t = 0;
|
|
|
|
const oClickDiv = baseDialog.value;
|
|
const oMoveDiv = titleBox.value;
|
|
if (oClickDiv) {
|
|
// console.log(oMoveDiv);
|
|
oMoveDiv.onmousedown = (e) => {
|
|
// 获取对话框尺寸
|
|
const oMoveDivHeight = baseDialog.value.offsetHeight;
|
|
const oMoveDivWidth = baseDialog.value.offsetWidth;
|
|
|
|
x = e.clientX;
|
|
y = e.clientY;
|
|
|
|
const leftPx = window.getComputedStyle(baseDialog.value).left;
|
|
const topPx = window.getComputedStyle(baseDialog.value).top;
|
|
|
|
l = parseFloat(leftPx);
|
|
t = parseFloat(topPx);
|
|
|
|
// 获取视口大小
|
|
const container = props.bodyId ? document.getElementById(props.bodyId) : document.body;
|
|
const windowHeight = container.clientHeight;
|
|
const windowWidth = container.clientWidth;
|
|
|
|
// 鼠标移动事件处理
|
|
const handleMouseMove = (e) => {
|
|
e.preventDefault();
|
|
const nx = e.clientX;
|
|
const ny = e.clientY;
|
|
|
|
// 计算新位置
|
|
let newLeft = nx - (x - l);
|
|
let newTop = ny - (y - t);
|
|
|
|
// 边界检查
|
|
if (newLeft < 0) {
|
|
newLeft = 0;
|
|
} else if (newLeft + oMoveDivWidth > windowWidth) {
|
|
newLeft = windowWidth - oMoveDivWidth;
|
|
}
|
|
|
|
if (newTop <= 0) {
|
|
newTop = 0;
|
|
} else if (newTop + oMoveDivHeight > windowHeight) {
|
|
newTop = windowHeight - oMoveDivHeight;
|
|
}
|
|
|
|
// 更新位置
|
|
if (baseDialog.value) {
|
|
baseDialog.value.style.left = newLeft + 'px';
|
|
baseDialog.value.style.top = newTop + 'px';
|
|
baseDialog.value.style.bottom = 'unset';
|
|
baseDialog.value.style.right = 'unset';
|
|
}
|
|
};
|
|
|
|
// 鼠标抬起事件处理
|
|
const handleMouseUp = () => {
|
|
window.removeEventListener('mousemove', handleMouseMove);
|
|
window.removeEventListener('mouseup', handleMouseUp);
|
|
};
|
|
|
|
// 添加事件监听
|
|
window.addEventListener('mousemove', handleMouseMove);
|
|
window.addEventListener('mouseup', handleMouseUp);
|
|
};
|
|
}
|
|
};
|
|
|
|
const openPosition = () => {
|
|
const oMoveDiv = baseDialog.value;
|
|
if (!oMoveDiv) return;
|
|
|
|
// 获取对话框尺寸
|
|
const oMoveDivHeight = oMoveDiv.offsetHeight;
|
|
const oMoveDivWidth = oMoveDiv.offsetWidth;
|
|
|
|
// 获取当前位置
|
|
const leftPx = parseFloat(window.getComputedStyle(oMoveDiv).left);
|
|
const topPx = parseFloat(window.getComputedStyle(oMoveDiv).top);
|
|
|
|
// 获取视口大小
|
|
const container = props.bodyId ? document.getElementById(props.bodyId) : document.body;
|
|
const windowHeight = container.clientHeight;
|
|
const windowWidth = container.clientWidth;
|
|
|
|
// 边界检查
|
|
let newLeft = leftPx;
|
|
let newTop = topPx;
|
|
|
|
if (newLeft < 0) {
|
|
newLeft = 0;
|
|
} else if (newLeft + oMoveDivWidth > windowWidth) {
|
|
newLeft = windowWidth - oMoveDivWidth;
|
|
}
|
|
|
|
if (newTop - 10 <= 0) {
|
|
newTop = -10;
|
|
} else if (newTop + oMoveDivHeight > windowHeight) {
|
|
newTop = windowHeight - oMoveDivHeight;
|
|
}
|
|
|
|
// 更新位置
|
|
oMoveDiv.style.left = newLeft + 'px';
|
|
oMoveDiv.style.top = newTop + 'px';
|
|
};
|
|
|
|
// 暴露公共方法
|
|
defineExpose({
|
|
open,
|
|
close,
|
|
moveDiv,
|
|
openPosition
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="YJ-custom-base-dialog" :class="className" ref="baseDialog" :id="id" v-if="dialogVisible" v-show="dialogVisible">
|
|
<div class="title-box" ref="titleBox">
|
|
<span class="title">{{ title }}</span
|
|
><span class="close-box" @click="close"><span class="close"></span><i>✕</i></span>
|
|
</div>
|
|
<div class="content" style="padding: 0 24px 0 24px">
|
|
<div>
|
|
<slot name="content"></slot>
|
|
</div>
|
|
</div>
|
|
<div class="foot">
|
|
<slot name="footer"></slot>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.YJ-custom-base-dialog {
|
|
::v-deep .el-tabs {
|
|
width: 100%;
|
|
.el-tabs__item {
|
|
padding: 0 8px;
|
|
color: #fff;
|
|
}
|
|
.el-tabs__item:nth-child(2) {
|
|
padding-left: 0;
|
|
}
|
|
.el-tabs__item.is-active,
|
|
.el-tabs__item:hover {
|
|
color: #fff;
|
|
}
|
|
.el-tabs__active-bar {
|
|
background-color: rgb(0, 255, 255);
|
|
}
|
|
.el-tabs__nav-wrap:after {
|
|
background-color: rgba(204, 204, 204, 0.2);
|
|
}
|
|
}
|
|
}
|
|
</style>
|