|
|
<script setup lang="ts"> import { cmdNameMap } from 'libs/utils' import { useSystemStore } from 'stores/systemStore' import { computed, nextTick, ref, watch } from 'vue'
defineProps({ visible: { type: Boolean, default: false, }, })
const systemStore = useSystemStore() const title = computed(() => { return cmdNameMap[systemStore.systemList[0]?.command as keyof typeof cmdNameMap] || systemStore.systemList[0]?.command })
const maskBodyRef = ref<HTMLElement | null>(null) const maskRef = ref<HTMLElement | null>(null) const maskHeaderRef = ref<HTMLElement | null>(null)
const statusMap = { info: 'info', error: 'danger', warn: 'warning', success: 'success', finish: 'primary', SEND: 'primary', receive: 'primary', start: 'primary', result: 'primary', }
watch( () => systemStore.systemList, async () => { await nextTick() if (maskBodyRef.value) { maskBodyRef.value.scrollTop = maskBodyRef.value.scrollHeight } }, { deep: true }, )
// 拖拽相关逻辑
let isDragging = false let offsetX = 0 let offsetY = 0
const handleMouseDown = (event: MouseEvent | TouchEvent) => { if (maskRef.value && maskHeaderRef.value) { isDragging = true const clientX = 'clientX' in event ? event.clientX : event.touches[0].clientX const clientY = 'clientY' in event ? event.clientY : event.touches[0].clientY offsetX = clientX - maskRef.value.offsetLeft offsetY = clientY - maskRef.value.offsetTop document.addEventListener('mousemove', handleMouseMove) document.addEventListener('mouseup', handleMouseUp) document.addEventListener('touchmove', handleMouseMove) document.addEventListener('touchend', handleMouseUp) } }
const handleMouseMove = (event: MouseEvent | TouchEvent) => { if (maskRef.value && isDragging) { const clientX = 'clientX' in event ? event.clientX : event.touches[0].clientX const clientY = 'clientY' in event ? event.clientY : event.touches[0].clientY
// 获取 body 的宽度和高度
const bodyWidth = document.body.clientWidth const bodyHeight = document.body.clientHeight
// 计算新的位置,并确保不会超出 body 的范围
const newLeft = Math.max(0, Math.min(clientX - offsetX, bodyWidth - maskRef.value.offsetWidth)) const newTop = Math.max(0, Math.min(clientY - offsetY, bodyHeight - maskRef.value.offsetHeight))
maskRef.value.style.left = `${newLeft}px` maskRef.value.style.top = `${newTop}px` } }
const handleMouseUp = () => { isDragging = false document.removeEventListener('mousemove', handleMouseMove) document.removeEventListener('mouseup', handleMouseUp) document.removeEventListener('touchmove', handleMouseMove) document.removeEventListener('touchend', handleMouseUp) } </script>
<template> <teleport to="body"> <!-- 使用 transition 组件包裹 mask 元素 --> <transition name="mask-fade"> <div v-if="visible && systemStore.isDebug" ref="maskRef" class="mask" > <div ref="maskHeaderRef" class="mask-header" @mousedown="handleMouseDown" @touchstart="handleMouseDown" > <p>{{ title }}</p> <el-icon @click="systemStore.updateStreamVisible(false)"> <Close /> </el-icon> </div> <div ref="maskBodyRef" class="mask-body"> <el-timeline> <el-timeline-item v-for="item in systemStore.systemList" :key="item" :timestamp="JSON.stringify(item.content)" > <el-tag :type="statusMap[item.level as keyof typeof statusMap]" class="mask-tag"> {{ item.title }} </el-tag> </el-timeline-item> </el-timeline> </div> </div> </transition> </teleport> </template>
<style scoped lang="scss"> .mask { width: 350px; height: 200px; padding: 5px 10px; background: #fff; box-shadow: var(--el-box-shadow-light); position: absolute; bottom: 20px; right: 20px; border-radius: 8px; font-size: 30px; .mask-header { display: flex; justify-content: space-between; align-items: center; height: 30px; font-size: 16px; border-bottom: 1px solid #ddd; cursor: move; // 添加鼠标指针样式
.el-icon svg{ width: 18px; cursor: pointer; } } .mask-body { padding: 5px 2px; height: calc(100% - 31px); overflow: auto; } }
/* 定义过渡效果 */ .mask-fade-enter-active, .mask-fade-leave-active { transition: transform 0.5s ease; }
.mask-fade-enter-from { transform: translateX(100%); }
.mask-fade-leave-to { transform: translateX(100%); } </style>
|