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

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. <script setup lang="ts">
  2. import { cmdNameMap } from 'libs/utils'
  3. import { useSystemStore } from 'stores/systemStore'
  4. import { computed, nextTick, ref, watch } from 'vue'
  5. defineProps({
  6. visible: {
  7. type: Boolean,
  8. default: false,
  9. },
  10. })
  11. const systemStore = useSystemStore()
  12. const title = computed(() => {
  13. return cmdNameMap[systemStore.systemList[0]?.command as keyof typeof cmdNameMap] || systemStore.systemList[0]?.command
  14. })
  15. const maskBodyRef = ref<HTMLElement | null>(null)
  16. const maskRef = ref<HTMLElement | null>(null)
  17. const maskHeaderRef = ref<HTMLElement | null>(null)
  18. const statusMap = {
  19. info: 'info',
  20. error: 'danger',
  21. warn: 'warning',
  22. success: 'success',
  23. finish: 'primary',
  24. SEND: 'primary',
  25. receive: 'primary',
  26. start: 'primary',
  27. result: 'primary',
  28. }
  29. watch(
  30. () => systemStore.systemList,
  31. async () => {
  32. await nextTick()
  33. if (maskBodyRef.value) {
  34. maskBodyRef.value.scrollTop = maskBodyRef.value.scrollHeight
  35. }
  36. },
  37. { deep: true },
  38. )
  39. // 拖拽相关逻辑
  40. let isDragging = false
  41. let offsetX = 0
  42. let offsetY = 0
  43. const handleMouseDown = (event: MouseEvent | TouchEvent) => {
  44. if (maskRef.value && maskHeaderRef.value) {
  45. isDragging = true
  46. const clientX = 'clientX' in event ? event.clientX : event.touches[0].clientX
  47. const clientY = 'clientY' in event ? event.clientY : event.touches[0].clientY
  48. offsetX = clientX - maskRef.value.offsetLeft
  49. offsetY = clientY - maskRef.value.offsetTop
  50. document.addEventListener('mousemove', handleMouseMove)
  51. document.addEventListener('mouseup', handleMouseUp)
  52. document.addEventListener('touchmove', handleMouseMove)
  53. document.addEventListener('touchend', handleMouseUp)
  54. }
  55. }
  56. const handleMouseMove = (event: MouseEvent | TouchEvent) => {
  57. if (maskRef.value && isDragging) {
  58. const clientX = 'clientX' in event ? event.clientX : event.touches[0].clientX
  59. const clientY = 'clientY' in event ? event.clientY : event.touches[0].clientY
  60. // 获取 body 的宽度和高度
  61. const bodyWidth = document.body.clientWidth
  62. const bodyHeight = document.body.clientHeight
  63. // 计算新的位置,并确保不会超出 body 的范围
  64. const newLeft = Math.max(0, Math.min(clientX - offsetX, bodyWidth - maskRef.value.offsetWidth))
  65. const newTop = Math.max(0, Math.min(clientY - offsetY, bodyHeight - maskRef.value.offsetHeight))
  66. maskRef.value.style.left = `${newLeft}px`
  67. maskRef.value.style.top = `${newTop}px`
  68. }
  69. }
  70. const handleMouseUp = () => {
  71. isDragging = false
  72. document.removeEventListener('mousemove', handleMouseMove)
  73. document.removeEventListener('mouseup', handleMouseUp)
  74. document.removeEventListener('touchmove', handleMouseMove)
  75. document.removeEventListener('touchend', handleMouseUp)
  76. }
  77. </script>
  78. <template>
  79. <teleport to="body">
  80. <!-- 使用 transition 组件包裹 mask 元素 -->
  81. <transition name="mask-fade">
  82. <div
  83. v-if="visible && systemStore.isDebug"
  84. ref="maskRef"
  85. class="mask"
  86. >
  87. <div
  88. ref="maskHeaderRef" class="mask-header" @mousedown="handleMouseDown"
  89. @touchstart="handleMouseDown"
  90. >
  91. <p>{{ title }}</p>
  92. <el-icon @click="systemStore.updateStreamVisible(false)">
  93. <Close />
  94. </el-icon>
  95. </div>
  96. <div ref="maskBodyRef" class="mask-body">
  97. <el-timeline>
  98. <el-timeline-item
  99. v-for="item in systemStore.systemList" :key="item"
  100. :timestamp="JSON.stringify(item.content)"
  101. >
  102. <el-tag :type="statusMap[item.level as keyof typeof statusMap]" class="mask-tag">
  103. {{ item.title }}
  104. </el-tag>
  105. </el-timeline-item>
  106. </el-timeline>
  107. </div>
  108. </div>
  109. </transition>
  110. </teleport>
  111. </template>
  112. <style scoped lang="scss">
  113. .mask {
  114. width: 350px;
  115. height: 200px;
  116. padding: 5px 10px;
  117. background: #fff;
  118. box-shadow: var(--el-box-shadow-light);
  119. position: absolute;
  120. bottom: 20px;
  121. right: 20px;
  122. border-radius: 8px;
  123. font-size: 30px;
  124. .mask-header {
  125. display: flex;
  126. justify-content: space-between;
  127. align-items: center;
  128. height: 30px;
  129. font-size: 16px;
  130. border-bottom: 1px solid #ddd;
  131. cursor: move; // 添加鼠标指针样式
  132. .el-icon svg{
  133. width: 18px;
  134. cursor: pointer;
  135. }
  136. }
  137. .mask-body {
  138. padding: 5px 2px;
  139. height: calc(100% - 31px);
  140. overflow: auto;
  141. }
  142. }
  143. /* 定义过渡效果 */
  144. .mask-fade-enter-active, .mask-fade-leave-active {
  145. transition: transform 0.5s ease;
  146. }
  147. .mask-fade-enter-from {
  148. transform: translateX(100%);
  149. }
  150. .mask-fade-leave-to {
  151. transform: translateX(100%);
  152. }
  153. </style>