diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue index ae11d3d..1d61ced 100644 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue @@ -5,6 +5,47 @@ :class="{ 'is-maximized': isMaximized, 'is-normal': !isMaximized }" :style="areaStyle" > + +
+
+
+
+
+
+
+
@@ -93,6 +134,13 @@ const isDragging = ref(false) const dragStartPos = ref({ x: 0, y: 0 }) const areaStartPos = ref({ x: 0, y: 0 }) +// 调整大小相关状态 +const isResizing = ref(false) +const resizeStartPos = ref({ x: 0, y: 0 }) +const resizeDirection = ref(null) +const resizeStartSize = ref({ width: 0, height: 0 }) +const resizeStartAreaPos = ref({ left: 0, top: 0 }) + // 父容器引用 const parentContainer = ref(null) @@ -229,6 +277,135 @@ const onDragEnd = () => { document.removeEventListener('mouseup', onDragEnd) } +// 调整大小开始 +const onResizeStart = (direction, e) => { + if (isMaximized.value) return + + isResizing.value = true + resizeDirection.value = direction + resizeStartPos.value = { + x: e.clientX, + y: e.clientY + } + resizeStartSize.value = { + width: originalPosition.value.width, + height: originalPosition.value.height + } + resizeStartAreaPos.value = { + left: originalPosition.value.left, + top: originalPosition.value.top + } + + // 添加全局事件监听 + document.addEventListener('mousemove', onResizeMove) + document.addEventListener('mouseup', onResizeEnd) + document.addEventListener('mouseleave', onResizeEnd) + + // 防止文本选择 + e.preventDefault() + e.stopPropagation() +} + +// 调整大小移动 +const onResizeMove = (e) => { + if (!isResizing.value) return + + const deltaX = e.clientX - resizeStartPos.value.x + const deltaY = e.clientY - resizeStartPos.value.y + + let newWidth = resizeStartSize.value.width + let newHeight = resizeStartSize.value.height + let newLeft = resizeStartAreaPos.value.left + let newTop = resizeStartAreaPos.value.top + + // 根据方向调整大小 + switch (resizeDirection.value) { + case 'nw': + newWidth = Math.max(200, resizeStartSize.value.width - deltaX) + newHeight = Math.max(150, resizeStartSize.value.height - deltaY) + newLeft = resizeStartPos.value.left + deltaX + newTop = resizeStartPos.value.top + deltaY + break + case 'ne': + newWidth = Math.max(200, resizeStartSize.value.width + deltaX) + newHeight = Math.max(150, resizeStartSize.value.height - deltaY) + newTop = resizeStartPos.value.top + deltaY + break + case 'sw': + newWidth = Math.max(200, resizeStartSize.value.width - deltaX) + newHeight = Math.max(150, resizeStartSize.value.height + deltaY) + newLeft = resizeStartPos.value.left + deltaX + break + case 'se': + newWidth = Math.max(200, resizeStartSize.value.width + deltaX) + newHeight = Math.max(150, resizeStartSize.value.height + deltaY) + break + case 'n': + newHeight = Math.max(150, resizeStartSize.value.height - deltaY) + newTop = resizeStartPos.value.top + deltaY + break + case 'e': + newWidth = Math.max(200, resizeStartSize.value.width + deltaX) + break + case 's': + newHeight = Math.max(150, resizeStartSize.value.height + deltaY) + break + case 'w': + newWidth = Math.max(200, resizeStartSize.value.width - deltaX) + newLeft = resizeStartPos.value.left + deltaX + break + } + + // 确保不超出父容器边界 + if (parentContainer.value) { + const parentRect = parentContainer.value.getBoundingClientRect() + + // 右边界检查 + if (newLeft + newWidth > parentRect.width) { + newWidth = parentRect.width - newLeft + } + // 下边界检查 + if (newTop + newHeight > parentRect.height) { + newHeight = parentRect.height - newTop + } + // 左边界检查 + if (newLeft < 0) { + newWidth += newLeft + newLeft = 0 + } + // 上边界检查 + if (newTop < 0) { + newHeight += newTop + newTop = 0 + } + } + + // 更新位置和大小 + originalPosition.value.width = newWidth + originalPosition.value.height = newHeight + originalPosition.value.left = newLeft + originalPosition.value.top = newTop + + // 通知父组件位置变化 + emit('update:position', { + left: newLeft, + top: newTop + }) + + // 防止文本选择 + e.preventDefault() +} + +// 调整大小结束 +const onResizeEnd = () => { + isResizing.value = false + resizeDirection.value = null + // 移除全局事件监听 + document.removeEventListener('mousemove', onResizeMove) + document.removeEventListener('mouseup', onResizeEnd) + document.removeEventListener('mouseleave', onResizeEnd) +} + const onToggleMaximize = () => { const next = isMaximized.value ? '正常' : '最大化' @@ -402,6 +579,89 @@ onMounted(() => { min-height: 0; } +/* 调整大小的手柄样式 */ +.resize-handle { + position: absolute; + z-index: 20; + background: transparent; + pointer-events: auto; +} + +/* 四个角 */ +.resize-handle-nw { + width: 12px; + height: 12px; + top: -6px; + left: -6px; + cursor: nwse-resize; +} + +.resize-handle-ne { + width: 12px; + height: 12px; + top: -6px; + right: -6px; + cursor: nesw-resize; +} + +.resize-handle-sw { + width: 12px; + height: 12px; + bottom: -6px; + left: -6px; + cursor: nesw-resize; +} + +.resize-handle-se { + width: 12px; + height: 12px; + bottom: -6px; + right: -6px; + cursor: nwse-resize; +} + +/* 四条边 */ +.resize-handle-n { + height: 12px; + top: -6px; + left: 12px; + right: 12px; + cursor: ns-resize; +} + +.resize-handle-e { + width: 12px; + right: -6px; + top: 12px; + bottom: 12px; + cursor: ew-resize; +} + +.resize-handle-s { + height: 12px; + bottom: -6px; + left: 12px; + right: 12px; + cursor: ns-resize; +} + +.resize-handle-w { + width: 12px; + left: -6px; + top: 12px; + bottom: 12px; + cursor: ew-resize; +} + +/* 鼠标悬停在边框上时的样式提示 */ +.vs-area.is-normal:not(:hover) .resize-handle { + opacity: 0; +} + +.vs-area.is-normal:hover .resize-handle { + opacity: 0.5; +} + /* 左侧输出 */ .vs-left { flex: 1; background: var(--vs-panel); display: flex; } .left-blank { flex: 1; background: #eef1f9; border-right: 1px solid var(--vs-border); }