You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
4.6 KiB
170 lines
4.6 KiB
<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>
|