From 0d0d5f835d30872ee5409678e1a23c0f5a4afdaf Mon Sep 17 00:00:00 2001 From: zqm Date: Thu, 30 Oct 2025 21:03:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=BD=E5=8F=96=E6=B5=AE=E5=8A=A8=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=E4=B8=BA=E7=8B=AC=E7=AB=8BVue3=E7=BB=84=E4=BB=B6Panel?= =?UTF-8?q?.js=E5=B9=B6=E6=9B=B4=E6=96=B0DockLayoutTest.vue=E5=BC=95?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Windows/Robot/Web/src/DockLayout/Panel.js | 211 ++++++++++++++++++ .../Robot/Web/src/views/DockLayoutTest.vue | 58 ++--- 2 files changed, 227 insertions(+), 42 deletions(-) create mode 100644 AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.js diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.js b/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.js new file mode 100644 index 0000000..ebe8923 --- /dev/null +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.js @@ -0,0 +1,211 @@ +import { ref, computed, defineComponent, onMounted, onUnmounted } from 'vue'; + +/** + * 浮动面板组件 + * 提供可拖拽、最大化、最小化、折叠和工具栏扩展功能的窗口组件 + */ +export default defineComponent({ + name: 'Panel', + props: { + panel: { + type: Object, + required: true, + validator: (value) => { + return value && typeof value === 'object' && 'id' in value && 'title' in value; + } + }, + hostRef: { + type: Object, + default: null + } + }, + emits: ['close', 'toggleCollapse', 'toggleToolbar', 'maximize'], + setup(props, { emit }) { + // 响应式状态管理 + const isDragging = ref(false); + const dragStartPos = ref({ x: 0, y: 0 }); + const panelPosition = ref({ + x: props.panel.x || 100, + y: props.panel.y || 100 + }); + const panelSize = ref({ + width: props.panel.width || 300, + height: props.panel.height || 180 + }); + + // 计算面板样式 + const panelStyle = computed(() => { + const style = { + position: 'absolute', + top: `${panelPosition.value.y}px`, + left: `${panelPosition.value.x}px`, + width: `${panelSize.value.width}px`, + height: `${panelSize.value.height}px`, + backgroundColor: 'white', + border: '1px solid #e5e7eb', + borderRadius: '4px', + boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)', + overflow: 'hidden' + }; + + // 最大化状态 + if (props.panel.maximized) { + const host = props.hostRef?.value; + const rect = host?.getBoundingClientRect(); + if (rect) { + style.top = '0px'; + style.left = '0px'; + style.width = `${rect.width - 2}px`; + style.height = `${rect.height - 2}px`; + } else { + style.top = '0px'; + style.left = '0px'; + style.width = '800px'; + style.height = '600px'; + } + } + + return style; + }); + + // 处理标题栏拖拽 + const handleTitleBarMouseDown = (event) => { + if (props.panel.maximized) return; + + isDragging.value = true; + dragStartPos.value = { + x: event.clientX - panelPosition.value.x, + y: event.clientY - panelPosition.value.y + }; + + event.preventDefault(); + }; + + // 处理窗口关闭 + const handleClose = () => { + emit('close', props.panel.id); + }; + + // 处理折叠/展开 + const handleToggleCollapse = () => { + emit('toggleCollapse', props.panel.id); + }; + + // 处理工具栏展开/收起 + const handleToggleToolbar = () => { + emit('toggleToolbar', props.panel.id); + }; + + // 处理最大化/还原 + const handleMaximize = () => { + emit('maximize', props.panel.id); + }; + + // 鼠标移动事件处理 + const handleMouseMove = (event) => { + if (isDragging.value && !props.panel.maximized) { + panelPosition.value = { + x: event.clientX - dragStartPos.value.x, + y: event.clientY - dragStartPos.value.y + }; + } + }; + + // 鼠标松开事件处理 + const handleMouseUp = () => { + isDragging.value = false; + }; + + // 生命周期钩子 + onMounted(() => { + // 同步外部面板状态 + if (props.panel.x !== undefined) panelPosition.value.x = props.panel.x; + if (props.panel.y !== undefined) panelPosition.value.y = props.panel.y; + if (props.panel.width !== undefined) panelSize.value.width = props.panel.width; + if (props.panel.height !== undefined) panelSize.value.height = props.panel.height; + + // 添加全局事件监听 + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + }); + + onUnmounted(() => { + // 清理全局事件监听 + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }); + + return { + isDragging, + panelStyle, + handleTitleBarMouseDown, + handleClose, + handleToggleCollapse, + handleToggleToolbar, + handleMaximize + }; + }, + template: ` +
+
+ +
+
+ {{ panel.title }} +
+
+ + + +
+
+ + +
+
+ 工具栏 + +
+ +
+ + +
+ +
+
+
+ ` +}); diff --git a/AutoRobot/Windows/Robot/Web/src/views/DockLayoutTest.vue b/AutoRobot/Windows/Robot/Web/src/views/DockLayoutTest.vue index f794142..0d20190 100644 --- a/AutoRobot/Windows/Robot/Web/src/views/DockLayoutTest.vue +++ b/AutoRobot/Windows/Robot/Web/src/views/DockLayoutTest.vue @@ -44,56 +44,31 @@
- -
+ -
- -
-
- {{ panel.title }} -
-
- - - -
+ +