diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue index 0024de7..a0bfe76 100644 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue @@ -37,6 +37,9 @@ @maximize="onMaximize" @close="onClosePanel(area.id, panel.id)" @toggleToolbar="onToggleToolbar" + @dragStart="onPanelDragStart(area.id, $event)" + @dragMove="onPanelDragMove(area.id, $event)" + @dragEnd="onPanelDragEnd" /> @@ -67,6 +70,14 @@ const dockLayoutRef = ref(null) // 区域ID计数器 let areaIdCounter = 1 +// Panel拖拽相关状态 +const panelDragState = ref({ + isDragging: false, + currentAreaId: null, + startClientPos: { x: 0, y: 0 }, + startAreaPos: { x: 0, y: 0 } +}) + // 添加新的浮动面板 const addFloatingPanel = () => { // 获取父容器尺寸以计算居中位置 @@ -169,6 +180,59 @@ const onToggleToolbar = (id) => { } } +// Panel拖拽开始 +const onPanelDragStart = (areaId, event) => { + const area = floatingAreas.value.find(a => a.id === areaId) + // 只有当Area中只有一个Panel时才允许通过Panel标题栏移动Area + if (area && area.panels.length === 1) { + panelDragState.value.isDragging = true + panelDragState.value.currentAreaId = areaId + panelDragState.value.startClientPos = { + x: event.clientX, + y: event.clientY + } + panelDragState.value.startAreaPos = { + x: area.x, + y: area.y + } + } +} + +// Panel拖拽移动 +const onPanelDragMove = (areaId, event) => { + if (panelDragState.value.isDragging && panelDragState.value.currentAreaId === areaId) { + const area = floatingAreas.value.find(a => a.id === areaId) + if (area) { + // 计算移动距离 + const deltaX = event.clientX - panelDragState.value.startClientPos.x + const deltaY = event.clientY - panelDragState.value.startClientPos.y + + // 计算新位置 + let newLeft = panelDragState.value.startAreaPos.x + deltaX + let newTop = panelDragState.value.startAreaPos.y + deltaY + + // 确保不超出父容器边界 + if (dockLayoutRef.value) { + const parentRect = dockLayoutRef.value.getBoundingClientRect() + + // 严格边界检查 + newLeft = Math.max(0, Math.min(newLeft, parentRect.width - area.width)) + newTop = Math.max(0, Math.min(newTop, parentRect.height - area.height)) + } + + // 更新位置 + area.x = newLeft + area.y = newTop + } + } +} + +// Panel拖拽结束 +const onPanelDragEnd = () => { + panelDragState.value.isDragging = false + panelDragState.value.currentAreaId = null +} + // 暴露方法给父组件 defineExpose({ addFloatingPanel diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue index 0be7e66..2a02825 100644 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue @@ -3,7 +3,11 @@ :style="{ top: y + 'px', left: x + 'px', width: width + 'px', height: height + 'px' }">
-
+
{{ title }}
@@ -98,7 +102,7 @@ const props = defineProps({ }); // 定义事件 -const emit = defineEmits(['toggleCollapse', 'maximize', 'close', 'toggleToolbar']); +const emit = defineEmits(['toggleCollapse', 'maximize', 'close', 'toggleToolbar', 'dragStart', 'dragMove', 'dragEnd']); // 事件处理函数 const onToggleCollapse = () => { @@ -116,6 +120,41 @@ const onClose = () => { const onToggleToolbar = () => { emit('toggleToolbar', props.id); }; + +// 拖拽相关状态 +let isDragging = false; + +// 拖拽开始 +const onDragStart = (e) => { + // 只有当点击的是标题栏区域(不是按钮)时才触发拖拽 + if (!e.target.closest('.title-bar-buttons') && !e.target.closest('button')) { + isDragging = true; + emit('dragStart', { + clientX: e.clientX, + clientY: e.clientY + }); + // 防止文本选择 + e.preventDefault(); + } +}; + +// 拖拽移动 +const onDragMove = (e) => { + if (isDragging) { + emit('dragMove', { + clientX: e.clientX, + clientY: e.clientY + }); + } +}; + +// 拖拽结束 +const onDragEnd = () => { + if (isDragging) { + isDragging = false; + emit('dragEnd'); + } +};