From 526ac8641425fb3ba02d5875890e3cc1f0117887 Mon Sep 17 00:00:00 2001 From: zqm Date: Wed, 31 Dec 2025 10:51:47 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=BE=AA=E7=8E=AF=E5=AF=BC?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Windows/Robot/Web/src/DockLayout/Area.vue | 8 +- .../Robot/Web/src/DockLayout/DockLayout.vue | 537 ++++++++- .../Robot/Web/src/DockLayout/README.md | 1029 ----------------- .../Robot/Web/src/DockLayout/Render.vue | 8 +- 4 files changed, 493 insertions(+), 1089 deletions(-) delete mode 100644 AutoRobot/Windows/Robot/Web/src/DockLayout/README.md diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue index 6ffd3a8..ff35711 100644 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue @@ -426,10 +426,15 @@ const onDragEnd = (eventData) => { // 处理事件总线的area.resize.move事件 const onAreaResizeMove = (eventData) => { + console.log(`[Area:${props.id}] 收到AREA_RESIZE_MOVE事件:`, eventData) // 添加调试日志 const { areaId, size, position, direction } = eventData - if (areaId !== props.id) return + if (areaId !== props.id) { + console.log(`[Area:${props.id}] areaId不匹配,期望: ${props.id}, 实际: ${areaId}`) // 添加调试日志 + return + } + console.log(`[Area:${props.id}] 更新前originalPosition:`, originalPosition.value) // 添加调试日志 if (direction.includes('right') || direction.includes('left')) { originalPosition.value.width = size.width if (direction.includes('left')) { @@ -442,6 +447,7 @@ const onAreaResizeMove = (eventData) => { originalPosition.value.top = position.top } } + console.log(`[Area:${props.id}] 更新后originalPosition:`, originalPosition.value) // 添加调试日志 emitEvent(EVENT_TYPES.AREA_POSITION_UPDATE, { areaId: props.id, diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue index 6d21ada..3029219 100644 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue @@ -111,6 +111,11 @@ const mainAreaResizeBars = ref([]) // 检查主区域内是否有其他Area(简化版) const hasAreasInMainContent = ref(false) +// 添加拖拽操作缓存,避免在每次移动事件中重复检测 +const dragOperationCache = new Map(); + + + /** * 检查是否应该操作区域而非面板 * 当只有一个面板时,操作区域而不是面板 @@ -165,6 +170,33 @@ const shouldOperateAreaInsteadOfPanel = (areaId) => { } }; +/** + * 检查是否应该操作区域而非面板(从GlobalEventManager.js迁移) + * 当只有一个面板时,操作区域而不是面板 + * @param {Object} data - 事件数据 + * @returns {boolean} 是否应该操作区域 + */ +const shouldOperateAreaInsteadOfPanelFromData = (data) => { + const { panelId, areaId } = data; + + console.log(`🔍 检查单面板模式: areaId=${areaId}, panelId=${panelId}`); + + // 从AreaHandler获取区域状态 + const areaState = areaHandler.getAreaState(areaId); + + // 检查区域是否只有一个面板 + let panelCount = 0; + if (areaState.children && areaState.children.type === 'TabPage') { + const tabChildren = Array.isArray(areaState.children.children) ? areaState.children.children : [areaState.children.children]; + panelCount = tabChildren.filter(child => child.type === 'Panel').length; + } + + // 如果区域中只有一个面板,返回true + const result = panelCount === 1; + console.log(`✅ 单面板检测结果: ${result} (面板数量: ${panelCount})`); + return result; +}; + const onCloseFloatingArea = (event) => { const id = event.areaId; areaActions.closeFloating(id); @@ -303,61 +335,91 @@ const handleAreaDragLeave = (event) => { globalEventActions.handleDragLeave('floating-area'); }; -const onPanelDragStart = (event) => { - const areaId = event.areaId; - const panelId = event.panelId; +// 处理面板拖拽开始事件 +const onPanelDragStart = async (event) => { + console.log(`📈 收到面板拖拽开始事件:`, { event }); - // 触发面板拖拽开始上升事件 - eventBus.emit(EVENT_TYPES.PANEL_DRAG_START, { - dragId: event.dragId, - panelId: panelId, - areaId: areaId, - position: event.position, - timestamp: event.timestamp, - layout: { - areas: floatingAreas.value - } + // 检查是否应该操作区域而非面板,并缓存结果 + const shouldOperateArea = shouldOperateAreaInsteadOfPanelFromData(event); + + // 缓存检测结果,用于后续的拖拽移动和结束事件 + dragOperationCache.set(event.dragId, { + shouldOperateArea, + timestamp: Date.now() }); - console.log(`🚀 面板拖拽开始: panelId=${panelId}, areaId=${areaId}, dragId=${event.dragId}`); + if (shouldOperateArea) { + // 转换为区域拖拽事件 + const areaDragStartData = { + ...event, + eventType: 'area.drag.start', + dragId: event.dragId || `area_${Date.now()}_${Math.random().toString(36).substring(2, 9)}` + }; + + // 发送区域拖拽开始事件 + eventBus.emit('area.drag.start', areaDragStartData, { componentId: 'dock-layout' }); + } else { + // 发送面板拖拽状态更新事件(下降事件) + eventBus.emit(EVENT_TYPES.PANEL_DRAG_STATE_UPDATE, { + ...event, + status: 'active' + }, { componentId: 'dock-layout' }); + } }; -const onPanelDragMove = (event) => { - const areaId = event.areaId; - const panelId = event.panelId; +// 处理面板拖拽移动事件 +const onPanelDragMove = async (event) => { + console.log(`📈 收到面板拖拽移动事件:`, { event }); - // 触发面板拖拽移动上升事件 - eventBus.emit(EVENT_TYPES.PANEL_DRAG_MOVE, { - dragId: event.dragId, - panelId: panelId, - areaId: areaId, - position: event.position, - timestamp: event.timestamp, - layout: { - areas: floatingAreas.value - } - }); + // 从缓存中获取单面板检测结果,避免重复检测 + const cache = dragOperationCache.get(event.dragId); + const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(event); - console.log(`📱 面板拖拽移动: panelId=${panelId}, areaId=${areaId}, position=${JSON.stringify(event.position)}`); + if (shouldOperateArea) { + // 转换为区域拖拽移动事件 + const areaDragMoveData = { + ...event, + eventType: 'area.drag.move' + }; + + // 发送区域拖拽移动事件 + eventBus.emit('area.drag.move', areaDragMoveData, { componentId: 'dock-layout' }); + } else { + // 发送面板拖拽状态更新事件(下降事件) + eventBus.emit(EVENT_TYPES.PANEL_DRAG_STATE_UPDATE, { + ...event, + status: 'moving' + }, { componentId: 'dock-layout' }); + } }; -const onPanelDragEnd = (event) => { - const areaId = event.areaId; - const panelId = event.panelId; +// 处理面板拖拽结束事件 +const onPanelDragEnd = async (event) => { + console.log(`📈 收到面板拖拽结束事件:`, { event }); - // 触发面板拖拽结束上升事件 - eventBus.emit(EVENT_TYPES.PANEL_DRAG_END, { - dragId: event.dragId, - panelId: panelId, - areaId: areaId, - position: event.position, - timestamp: event.timestamp, - layout: { - areas: floatingAreas.value - } - }); + // 从缓存中获取单面板检测结果 + const cache = dragOperationCache.get(event.dragId); + const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(event); - console.log(`✅ 面板拖拽结束: panelId=${panelId}, areaId=${areaId}, finalPosition=${JSON.stringify(event.position)}`); + if (shouldOperateArea) { + // 转换为区域拖拽结束事件 + const areaDragEndData = { + ...event, + eventType: 'area.drag.end' + }; + + // 发送区域拖拽结束事件 + eventBus.emit('area.drag.end', areaDragEndData, { componentId: 'dock-layout' }); + } else { + // 发送面板拖拽状态更新事件(下降事件) + eventBus.emit(EVENT_TYPES.PANEL_DRAG_STATE_UPDATE, { + ...event, + status: 'ended' + }, { componentId: 'dock-layout' }); + } + + // 清理缓存 + dragOperationCache.delete(event.dragId); }; // 监听区域位置更新下降事件 @@ -479,15 +541,13 @@ const setupEventListeners = () => { const unsubscribeFunctions = []; // Area相关事件 - unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_POSITION_UPDATE, onUpdatePosition, { componentId: 'dock-layout' })); - unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_FLOATING_UPDATE_POSITION, onUpdatePosition, { componentId: 'dock-layout' })); + unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_OVER, handleAreaDragOver, { componentId: 'dock-layout' })); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_LEAVE, handleAreaDragLeave, { componentId: 'dock-layout' })); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_MERGE_REQUEST, handleAreaMergeRequest, { componentId: 'dock-layout' })); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_UPDATED, onAreaUpdated, { componentId: 'dock-layout' })); - // 添加新的下降事件监听器 - unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_STATE_UPDATE, onAreaDragStateUpdate, { componentId: 'dock-layout' })); + // Tab相关事件 unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange, { componentId: 'dock-layout' })); @@ -687,18 +747,385 @@ const findOrCreateMainAreaTabPage = () => { }; } +// 处理上升事件(用户触发的原始事件)- 从GlobalEventManager.js迁移 +const handleRisingEvent = async (data, event) => { + // 从事件对象中获取事件类型 + const eventType = event.type; + + try { + // 总是输出日志,便于调试 + console.log(`📈 收到上升事件: ${eventType}`, { data }); + + // 根据事件类型分发到不同的处理方法 + switch (eventType) { + // 面板拖拽事件 + case EVENT_TYPES.PANEL_DRAG_START: + await handlePanelDragStart(data); + break; + case EVENT_TYPES.PANEL_DRAG_MOVE: + await handlePanelDragMove(data); + break; + case EVENT_TYPES.PANEL_DRAG_END: + await handlePanelDragEnd(data); + break; + case EVENT_TYPES.PANEL_DRAG_CANCEL: + await handlePanelDragCancel(data); + break; + // 面板resize事件 + case EVENT_TYPES.PANEL_RESIZE_START: + await handlePanelResizeStart(data); + break; + case EVENT_TYPES.PANEL_RESIZE_MOVE: + await handlePanelResizeMove(data); + break; + case EVENT_TYPES.PANEL_RESIZE_END: + await handlePanelResizeEnd(data); + break; + // 区域拖拽事件 + case EVENT_TYPES.AREA_DRAG_START: + await handleAreaDragStart(data); + break; + case EVENT_TYPES.AREA_DRAG_MOVE: + await handleAreaDragMove(data); + break; + case EVENT_TYPES.AREA_DRAG_END: + await handleAreaDragEnd(data); + break; + case EVENT_TYPES.AREA_DRAG_CANCEL: + await handleAreaDragCancel(data); + break; + // 区域resize事件 + case EVENT_TYPES.AREA_RESIZE_START: + await handleAreaResizeStart(data); + break; + case EVENT_TYPES.AREA_RESIZE_MOVE: + await handleAreaResizeMove(data); + break; + case EVENT_TYPES.AREA_RESIZE_END: + await handleAreaResizeEnd(data); + break; + // 标签页拖拽事件 + case EVENT_TYPES.TABPAGE_DRAG_START: + await handleTabPageDragStart(data); + break; + case EVENT_TYPES.TABPAGE_DRAG_MOVE: + await handleTabPageDragMove(data); + break; + case EVENT_TYPES.TABPAGE_DRAG_END: + await handleTabPageDragEnd(data); + break; + case EVENT_TYPES.TABPAGE_DRAG_CANCEL: + await handleTabPageDragCancel(data); + break; + // 默认处理 + default: + console.log(`🌐 全局事件: ${eventType}`, data); + } + } catch (error) { + console.error(`❌ 上升事件处理错误 (${eventType}):`, error); + } +}; + +// 面板拖拽开始处理 +const handlePanelDragStart = async (data) => { + if (debugMode) { + console.log('👋 处理面板拖拽开始:', data); + } + + // 检查是否应该操作区域而非面板,并缓存结果 + const shouldOperateArea = shouldOperateAreaInsteadOfPanelFromData(data); + + // 缓存检测结果,用于后续的拖拽移动和结束事件 + dragOperationCache.set(data.dragId, { + shouldOperateArea, + timestamp: Date.now() + }); + + if (shouldOperateArea) { + // 转换为区域拖拽事件 + const areaDragStartData = { + ...data, + eventType: 'area.drag.start', + dragId: data.dragId || `area_${Date.now()}_${Math.random().toString(36).substring(2, 9)}` + }; + + // 发送区域拖拽开始事件 + eventBus.emit('area.drag.start', areaDragStartData); + } else { + // 发送面板拖拽状态更新事件(下降事件) + eventBus.emit('panel.drag.state.update', { + ...data, + status: 'active' + }); + } +}; + +// 面板拖拽移动处理 +const handlePanelDragMove = async (data) => { + if (debugMode) { + console.log('✋ 处理面板拖拽移动:', data); + } + + // 从缓存中获取单面板检测结果,避免重复检测 + const cache = dragOperationCache.get(data.dragId); + const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(data); + + if (shouldOperateArea) { + // 转换为区域拖拽移动事件 + const areaDragMoveData = { + ...data, + eventType: 'area.drag.move' + }; + + // 发送区域拖拽移动事件 + eventBus.emit('area.drag.move', areaDragMoveData); + } else { + // 发送面板拖拽状态更新事件(下降事件) + eventBus.emit('panel.drag.state.update', { + ...data, + status: 'moving' + }); + } +}; + +// 面板拖拽结束处理 +const handlePanelDragEnd = async (data) => { + if (debugMode) { + console.log('✋ 处理面板拖拽结束:', data); + } + + // 从缓存中获取单面板检测结果 + const cache = dragOperationCache.get(data.dragId); + const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(data); + + if (shouldOperateArea) { + // 转换为区域拖拽结束事件 + const areaDragEndData = { + ...data, + eventType: 'area.drag.end' + }; + + // 发送区域拖拽结束事件 + eventBus.emit('area.drag.end', areaDragEndData); + } else { + // 发送面板拖拽状态更新事件(下降事件) + eventBus.emit('panel.drag.state.update', { + ...data, + status: 'ended' + }); + } + + // 清理缓存 + dragOperationCache.delete(data.dragId); +}; + +// 面板拖拽取消处理 +const handlePanelDragCancel = async (data) => { + if (debugMode) { + console.log('✋ 处理面板拖拽取消:', data); + } + + // 发送面板拖拽状态更新事件(下降事件) + eventBus.emit('panel.drag.state.update', { + ...data, + status: 'cancelled' + }); + + // 清理缓存 + dragOperationCache.delete(data.dragId); +}; + +// 区域拖拽开始处理 +const handleAreaDragStart = async (data) => { + if (debugMode) { + console.log('👋 处理区域拖拽开始:', data); + } + + // 发送区域拖拽状态更新事件(下降事件) + eventBus.emit('area.drag.state.update', { + ...data, + status: 'active' + }); +}; + +// 区域拖拽移动处理 +const handleAreaDragMove = async (data) => { + if (debugMode) { + console.log('✋ 处理区域拖拽移动:', data); + } + + // 发送区域拖拽状态更新事件(下降事件) + eventBus.emit('area.drag.state.update', { + ...data, + status: 'moving' + }); + + // 发送区域位置更新事件(下降事件) + eventBus.emit('area.position.update', { + ...data, + position: data.position + }); +}; + +// 区域拖拽结束处理 +const handleAreaDragEnd = async (data) => { + if (debugMode) { + console.log('✋ 处理区域拖拽结束:', data); + } + + // 发送区域拖拽状态更新事件(下降事件) + eventBus.emit('area.drag.state.update', { + ...data, + status: 'ended' + }); +}; + +// 区域拖拽取消处理 +const handleAreaDragCancel = async (data) => { + if (debugMode) { + console.log('✋ 处理区域拖拽取消:', data); + } + + // 发送区域拖拽状态更新事件(下降事件) + eventBus.emit('area.drag.state.update', { + ...data, + status: 'cancelled' + }); +}; + +// 面板resize处理 +const handlePanelResizeStart = async (data) => { + if (debugMode) { + console.log('👋 处理面板resize开始:', data); + } + + eventBus.emit(EVENT_TYPES.AREA_RESIZE_START, { + ...data, + resizeType: 'panel' + }); +}; + +const handlePanelResizeMove = async (data) => { + if (debugMode) { + console.log('✋ 处理面板resize移动:', data); + } + + eventBus.emit(EVENT_TYPES.AREA_RESIZE, { + ...data, + resizeType: 'panel' + }); + + eventBus.emit(EVENT_TYPES.AREA_RESIZE_MOVE, { + ...data, + resizeType: 'panel' + }); +}; + +const handlePanelResizeEnd = async (data) => { + if (debugMode) { + console.log('✋ 处理面板resize结束:', data); + } + + eventBus.emit(EVENT_TYPES.AREA_RESIZE_END, { + ...data, + resizeType: 'panel' + }); +}; + +// 区域resize处理 +const handleAreaResizeStart = async (data) => { + if (debugMode) { + console.log('👋 处理区域resize开始:', data); + } + + eventBus.emit(EVENT_TYPES.AREA_RESIZE_START, { + ...data, + resizeType: 'area' + }); +}; + +const handleAreaResizeMove = async (data) => { + if (debugMode) { + console.log('✋ 处理区域resize移动:', data); + } + + eventBus.emit(EVENT_TYPES.AREA_RESIZE, { + ...data, + resizeType: 'area' + }); + + eventBus.emit(EVENT_TYPES.AREA_RESIZE_MOVE, { + ...data, + resizeType: 'area' + }); +}; + +const handleAreaResizeEnd = async (data) => { + if (debugMode) { + console.log('✋ 处理区域resize结束:', data); + } + + eventBus.emit(EVENT_TYPES.AREA_RESIZE_END, { + ...data, + resizeType: 'area' + }); +}; + +// 标签页拖拽处理 +const handleTabPageDragStart = async (data) => { + if (debugMode) { + console.log('👋 处理标签页拖拽开始:', data); + } + + // 标签页拖拽逻辑 + eventBus.emit('tabpage.drag.state.update', { + ...data, + status: 'active' + }); +}; + +const handleTabPageDragMove = async (data) => { + if (debugMode) { + console.log('✋ 处理标签页拖拽移动:', data); + } + + eventBus.emit('tabpage.drag.state.update', { + ...data, + status: 'moving' + }); +}; + +const handleTabPageDragEnd = async (data) => { + if (debugMode) { + console.log('✋ 处理标签页拖拽结束:', data); + } + + eventBus.emit('tabpage.drag.state.update', { + ...data, + status: 'ended' + }); +}; + +const handleTabPageDragCancel = async (data) => { + if (debugMode) { + console.log('✋ 处理标签页拖拽取消:', data); + } + + eventBus.emit('tabpage.drag.state.update', { + ...data, + status: 'cancelled' + }); +}; + // 单面板检测处理函数 const onCheckSinglePanel = (event) => { - const areaId = event.areaId; - const panelId = event.panelId; - - // 使用现有的shouldOperateAreaInsteadOfPanel函数检查是否为单面板 - const isSinglePanel = shouldOperateAreaInsteadOfPanel(areaId); + // 使用新的shouldOperateAreaInsteadOfPanelFromData函数检查是否为单面板 + const isSinglePanel = shouldOperateAreaInsteadOfPanelFromData(event); // 发送检测结果 eventBus.emit(EVENT_TYPES.PANEL_SINGLE_PANEL_RESULT, { - areaId, - panelId, + areaId: event.areaId, + panelId: event.panelId, isSinglePanel }, { componentId: 'dock-layout' }); }; diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/README.md b/AutoRobot/Windows/Robot/Web/src/DockLayout/README.md deleted file mode 100644 index 372ca2a..0000000 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/README.md +++ /dev/null @@ -1,1029 +0,0 @@ -# DockLayout 可停靠布局系统 - -## 项目概述 - -DockLayout 是一个基于 Vue 3 的可停靠布局系统,提供了灵活的面板管理、拖拽停靠、标签页切换、窗口调整大小等功能。该系统采用事件驱动架构,支持浮动面板、停靠面板、并排布局等多种布局模式,适用于需要复杂界面布局的应用场景。 - -### 核心特性 - -- **灵活的面板管理**:支持浮动面板、停靠面板、标签页面板 -- **拖拽停靠**:支持面板拖拽到不同位置进行停靠 -- **动态调整大小**:支持通过拖拽边框或调整条改变面板大小 -- **标签页系统**:支持多标签页切换、拖拽重排 -- **并排布局**:支持面板并排显示,可动态调整比例 -- **事件驱动架构**:采用事件总线实现组件间通信 -- **内存保护机制**:自动清理过期资源,防止内存泄漏 -- **性能监控**:内置性能监控和集成测试框架 - -## 系统架构 - -### 整体架构 - -``` -DockLayout -├── 核心组件层 -│ ├── DockLayout.vue # 根组件,布局管理器 -│ ├── Area.vue # 面板区容器 -│ ├── TabPage.vue # 标签页容器 -│ ├── Panel.vue # 面板组件 -│ ├── Render.vue # 动态组件渲染器 -│ ├── DockIndicator.vue # 停靠指示器 -│ └── ResizeBar.vue # 调整条组件 -├── 事件处理层 -│ ├── DragStateManager.js # 拖拽状态管理 -│ ├── EventBusManager.js # 事件总线管理 -│ ├── AreaHandler.js # Area事件处理 -│ ├── PanelHandler.js # Panel事件处理 -│ ├── TabPageHandler.js # TabPage事件处理 -│ ├── GlobalEventManager.js # 全局事件管理 -│ └── IntegrationTester.js # 集成测试 -├── 工具层 -│ ├── eventBus.js # 增强事件总线 -│ ├── dockLayers.js # Z-index层级管理 -│ └── types.d.ts # TypeScript类型定义 -└── 文档层 - ├── DockIndicator指示器命名约定.md - └── ToDoList.md -``` - -### 架构设计原则 - -1. **分层架构**:组件层、事件层、工具层清晰分离 -2. **事件驱动**:所有组件间通信通过事件总线实现 -3. **单例模式**:关键管理器采用单例模式确保全局唯一 -4. **内存保护**:自动清理过期资源,防止内存泄漏 -5. **类型安全**:使用TypeScript提供类型检查 -6. **可扩展性**:模块化设计,易于扩展新功能 - -## 核心功能模块 - -### 1. 布局管理模块 - -**组件**:[DockLayout.vue](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/DockLayout.vue) - -**功能**: -- 管理所有浮动面板和隐藏面板 -- 提供面板添加、移除、查找接口 -- 协调组件间的事件通信 -- 资源清理和生命周期管理 - -**核心接口**: -```javascript -{ - // 数据 - floatingAreas: ref([]), // 浮动面板列表 - hiddenAreas: ref([]), // 隐藏面板列表 - - // 方法 - addFloatingPanel(panel), // 添加浮动面板 - findOrCreateMainAreaTabPage(), // 查找或创建主区域标签页 - handleDockingEnding(), // 停靠结束处理 - handleEdgeDocking(), // 边缘停靠处理 - handleSideBySideDocking(), // 并排停靠处理 -} -``` - -### 2. 面板区模块 - -**组件**:[Area.vue](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/Area.vue) - -**功能**: -- 面板区容器,支持浮动和停靠两种模式 -- 拖拽移动(带边界约束) -- 调整大小(8个方向) -- 最大化/还原/关闭 -- 单面板时显示标题栏 - -**核心特性**: -- 初始尺寸:300px × 250px,居中显示 -- 最大化时填充父容器 -- 拖拽时不超出父容器边界 -- 支持边框拖拽改变大小 -- 单面板时标题栏与Panel联动 - -**事件系统**: -```javascript -EVENT_TYPES = { - AREA_DRAG_START, // 面板拖拽开始 - AREA_DRAG_MOVE, // 面板拖拽移动 - AREA_DRAG_END, // 面板拖拽结束 - AREA_RESIZE_START, // 面板调整开始 - AREA_RESIZE_MOVE, // 面板调整移动 - AREA_RESIZE_END, // 面板调整结束 - AREA_MAXIMIZE, // 面板最大化 - AREA_RESTORE, // 面板还原 - AREA_CLOSE, // 面板关闭 - AREA_POSITION_UPDATE, // 面板位置更新 -} -``` - -### 3. 标签页模块 - -**组件**:[TabPage.vue](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/TabPage.vue) - -**功能**: -- 多标签页容器 -- 标签页切换 -- 标签页拖拽重排 -- 标签页关闭 -- 支持4个方向(上/右/下/左) - -**样式特性**: -- 背景颜色:#5D6B99 -- 激活标签:#F5CC84,文字黑色 -- 未激活标签:与Area背景相同,文字白色 -- 激活标签不显示关闭按钮 -- 激活标签鼠标显示移动,否则显示手型 - -**方向支持**: -- `top`:标签在上方(默认) -- `right`:标签在右侧 -- `bottom`:标签在下方 -- `left`:标签在左侧 - -### 4. 面板模块 - -**组件**:[Panel.vue](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/Panel.vue) - -**功能**: -- 单个面板内容容器 -- 填充父容器 -- 最大化/还原 -- 拖拽(单面板时拖动标题栏相当于拖动Area) - -**核心特性**: -- 始终填充父容器 -- 最大化时图标变为还原图标 -- 单面板时与Area标题栏联动 - -### 5. 停靠指示器模块 - -**组件**:[DockIndicator.vue](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/DockIndicator.vue) - -**功能**: -- 提供可视化的停靠位置指示 -- 支持全局边缘停靠 -- 支持中心区域停靠 -- 支持子区域停靠 -- 动态显示停靠预览 - -**指示器分类**: - -1. **外部边缘指示器**(全局停靠) - - `global-top-indicator`:全局顶部 - - `global-right-indicator`:全局右侧 - - `global-bottom-indicator`:全局底部 - - `global-left-indicator`:全局左侧 - -2. **中心区域指示器** - - `center-dock-zone`:中心停靠区 - - `center-edge-top`:中心上边缘 - - `center-edge-right`:中心右边缘 - - `center-edge-bottom`:中心下边缘 - - `center-edge-left`:中心左边缘 - -3. **子区域指示器** - - `center-top-area`:中心上方区域 - - `center-right-area`:中心右侧区域 - - `center-bottom-area`:中心下方区域 - - `center-left-area`:中心左侧区域 - -4. **独立中心指示器** - - `center-main-indicator`:独立中心指示器(z-index: 10000) - -**命名约定**:详见 [DockIndicator指示器命名约定.md](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/DockIndicator指示器命名约定.md) - -### 6. 调整条模块 - -**组件**:[ResizeBar.vue](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/ResizeBar.vue) - -**功能**: -- 在并排布局中提供尺寸调整功能 -- 支持水平和垂直两种方向 -- 实时调整面板大小 -- 支持最小/最大尺寸限制 - -**事件系统**: -```javascript -EVENT_TYPES = { - RESIZE_START, // 调整开始 - RESIZE_MOVE, // 调整移动 - RESIZE_END, // 调整结束 -} -``` - -**使用场景**: -- 外部边缘停靠后的并排布局 -- 两个Area之间的尺寸调整 -- 保持比例总和为1 - -### 7. 拖拽状态管理模块 - -**处理器**:[DragStateManager.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/DragStateManager.js) - -**功能**: -- 管理拖拽状态 -- 跟踪拖拽位置和速度 -- 冲突检测和解决 -- 性能监控 - -**核心功能**: -```javascript -class DragStateManager { - // 状态管理 - startDrag(dragId, source, position) - updateDrag(dragId, position) - endDrag(dragId) - - // 冲突检测 - checkConflict(dragId) - resolveConflict(dragId, conflictId) - - // 性能监控 - startPerformanceMonitor(operation) - endPerformanceMonitor(monitorId) -} -``` - -### 8. 事件总线管理模块 - -**处理器**:[EventBusManager.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/EventBusManager.js) - -**功能**: -- 统一事件路由和分发 -- 全局错误处理 -- 事件去重 -- 性能监控 - -**核心功能**: -```javascript -class EventBusManager { - // 事件管理 - registerEventRoute(eventType, handler) - unregisterEventRoute(eventType) - routeEvent(eventType, data) - - // 监控 - startMonitoring(eventId, eventData) - completeMonitoring(eventId) - getExecutionStats() -} -``` - -### 9. 全局事件管理模块 - -**处理器**:[GlobalEventManager.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/GlobalEventManager.js) - -**功能**: -- 系统级事件管理 -- 跨组件通信 -- 事件链执行 -- 性能监控和告警 - -**核心功能**: -```javascript -class GlobalEventManager { - // 系统事件 - handleSystemInit(data) - handleSystemError(data) - handlePerformanceThresholdExceeded(data) - - // 跨组件通信 - broadcast(message, data, targetComponents) - request(targetComponent, action, payload) - - // 事件链 - createEventChain(chainName, events) - getEventChainStatus() -} -``` - -### 10. Area事件处理模块 - -**处理器**:[AreaHandler.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/AreaHandler.js) - -**功能**: -- 处理Area相关事件 -- Area状态管理 -- 停靠逻辑实现 -- 并排布局创建 - -**核心功能**: -```javascript -class AreaHandler { - // Area管理 - handleAreaCreated(data) - handleAreaDestroyed(data) - handleAreaDragStart(data) - handleAreaDragEnd(data) - - // 停靠逻辑 - handleEdgeDocking(data) - handleSideBySideDocking(data) - createSideBySideLayout(sourceArea, targetArea, direction) -} -``` - -### 11. Panel事件处理模块 - -**处理器**:[PanelHandler.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/PanelHandler.js) - -**功能**: -- 处理Panel相关事件 -- Panel状态管理 -- Panel生命周期管理 - -**核心功能**: -```javascript -class PanelHandler { - // Panel管理 - handlePanelCreated(data) - handlePanelDestroyed(data) - handlePanelDragStart(data) - handlePanelDragEnd(data) - - // 状态管理 - getPanelState(panelId) - updatePanelState(panelId, updates) -} -``` - -### 12. TabPage事件处理模块 - -**处理器**:[TabPageHandler.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/TabPageHandler.js) - -**功能**: -- 处理TabPage相关事件 -- TabPage状态管理 -- 标签页拖拽和切换 -- 标签页组合并 - -**核心功能**: -```javascript -class TabPageHandler { - // TabPage管理 - handleTabPageCreated(data) - handleTabPageDestroyed(data) - handleTabPageDragStart(data) - handleTabPageDragEnd(data) - - // 标签页操作 - handleTabPageSwitch(data) - handleTabPageCloseRequest(data) - handleTabPageGroupMerge(data) -} -``` - -### 13. 集成测试模块 - -**处理器**:[IntegrationTester.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/IntegrationTester.js) - -**功能**: -- 集成测试框架 -- 性能监控 -- 测试报告生成 - -**核心功能**: -```javascript -class IntegrationTester { - // 测试执行 - runTestSuite(testSuite) - runSingleTest(testCase) - - // 性能监控 - startPerformanceMonitor() - endPerformanceMonitor() - getPerformanceStats() -} -``` - -## 关键技术栈及依赖 - -### 核心技术栈 - -- **Vue 3**:渐进式JavaScript框架 - - Composition API - - 响应式系统 - - 组件化开发 - -- **TypeScript**:JavaScript超集 - - 类型安全 - - 接口定义 - - 类型推断 - -- **Vite**:下一代前端构建工具 - - 快速热更新 - - 优化的生产构建 - - 原生ES模块支持 - -### 依赖库 - -根据项目package.json分析: - -```json -{ - "dependencies": { - "vue": "^3.x.x", - "pinia": "^2.x.x" // 状态管理 - }, - "devDependencies": { - "vite": "^5.x.x", - "typescript": "^5.x.x" - } -} -``` - -### 内部依赖 - -DockLayout模块内部依赖: -- [eventBus.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/eventBus.js):增强事件总线 -- [dockLayers.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/dockLayers.js):Z-index层级管理 -- [types.d.ts](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/types.d.ts):类型定义 - -## 项目目录结构 - -``` -DockLayout/ -├── handlers/ # 事件处理器目录 -│ ├── DragStateManager.js # 拖拽状态管理器 -│ ├── EventBusManager.js # 事件总线管理器 -│ ├── AreaHandler.js # Area事件处理器 -│ ├── PanelHandler.js # Panel事件处理器 -│ ├── TabPageHandler.js # TabPage事件处理器 -│ ├── GlobalEventManager.js # 全局事件管理器 -│ └── IntegrationTester.js # 集成测试器 -├── Area.vue # 面板区组件 -├── DockIndicator.vue # 停靠指示器组件 -├── DockLayout.vue # 根组件 -├── Panel.vue # 面板组件 -├── Render.vue # 动态组件渲染器 -├── ResizeBar.vue # 调整条组件 -├── TabPage.vue # 标签页组件 -├── dockLayers.js # Z-index层级管理 -├── eventBus.js # 增强事件总线 -├── types.d.ts # TypeScript类型定义 -├── DockIndicator指示器命名约定.md # 指示器命名约定文档 -└── ToDoList.md # 待办事项文档 -``` - -## 组件设计 - -### 组件层次结构 - -``` -DockLayout (根组件) -├── Render (动态组件渲染器) -│ ├── Area (面板区) -│ │ ├── TabPage (标签页) -│ │ │ └── Panel (面板) -│ │ └── ResizeBar (调整条) -│ └── DockIndicator (停靠指示器) -``` - -### 组件通信机制 - -1. **父子通信**:props和emit -2. **兄弟通信**:事件总线(eventBus) -3. **跨层级通信**:事件总线(eventBus) -4. **全局通信**:全局事件管理器(GlobalEventManager) - -### 组件生命周期 - -1. **创建阶段**: - - 组件初始化 - - 事件监听器注册 - - 状态初始化 - -2. **运行阶段**: - - 事件处理 - - 状态更新 - - UI渲染 - -3. **销毁阶段**: - - 事件监听器清理 - - 状态清理 - - 资源释放 - -## 事件系统 - -### 事件总线架构 - -DockLayout采用增强的事件总线系统,支持以下特性: - -1. **优先级队列**:事件按优先级处理 -2. **去重机制**:防止重复事件 -3. **性能监控**:跟踪事件处理时间 -4. **错误处理**:全局错误捕获 - -### 事件分类 - -#### 1. 系统级事件 - -```javascript -GLOBAL_EVENT_TYPES = { - SYSTEM_INIT: 'system.init', - SYSTEM_READY: 'system.ready', - SYSTEM_DESTROY: 'system.destroy', - SYSTEM_ERROR: 'system.error', - SYSTEM_PERFORMANCE: 'system.performance', -} -``` - -#### 2. Area事件 - -```javascript -AREA_EVENT_TYPES = { - AREA_CREATED: 'area.created', - AREA_DESTROYED: 'area.destroyed', - AREA_DRAG_START: 'area.drag.start', - AREA_DRAG_MOVE: 'area.drag.move', - AREA_DRAG_END: 'area.drag.end', - AREA_RESIZE_START: 'area.resize.start', - AREA_RESIZE_MOVE: 'area.resize.move', - AREA_RESIZE_END: 'area.resize.end', - AREA_MAXIMIZE: 'area.maximize', - AREA_RESTORE: 'area.restore', - AREA_CLOSE: 'area.close', - AREA_POSITION_UPDATE: 'area.position.update', -} -``` - -#### 3. Panel事件 - -```javascript -PANEL_EVENT_TYPES = { - PANEL_CREATED: 'panel.created', - PANEL_DESTROYED: 'panel.destroyed', - PANEL_DRAG_START: 'panel.drag.start', - PANEL_DRAG_MOVE: 'panel.drag.move', - PANEL_DRAG_END: 'panel.drag.end', - PANEL_MAXIMIZE: 'panel.maximize', - PANEL_RESTORE: 'panel.restore', - PANEL_CLOSE: 'panel.close', -} -``` - -#### 4. TabPage事件 - -```javascript -TABPAGE_EVENT_TYPES = { - TABPAGE_CREATED: 'tabPage.created', - TABPAGE_DESTROYED: 'tabPage.destroyed', - TABPAGE_SWITCH: 'tabPage.switch', - TABPAGE_CLOSE_REQUEST: 'tabPage.close.request', - TABPAGE_CLOSE: 'tabPage.close', - TABPAGE_DRAG_START: 'tabPage.drag.start', - TABPAGE_DRAG_MOVE: 'tabPage.drag.move', - TABPAGE_DRAG_END: 'tabPage.drag.end', - TABPAGE_GROUP_MERGE: 'tabPage.group.merge', - TABPAGE_ACTIVATED: 'tabPage.activated', - TABPAGE_DEACTIVATED: 'tabPage.deactivated', -} -``` - -#### 5. ResizeBar事件 - -```javascript -RESIZE_EVENT_TYPES = { - RESIZE_START: 'resize.start', - RESIZE_MOVE: 'resize.move', - RESIZE_END: 'resize.end', -} -``` - -### 事件流程示例 - -#### 面板拖拽流程 - -``` -1. 用户开始拖拽面板 - ↓ -2. Panel触发 PANEL_DRAG_START 事件 - ↓ -3. DragStateManager记录拖拽状态 - ↓ -4. EventBusManager路由事件到相关处理器 - ↓ -5. AreaHandler处理拖拽逻辑 - ↓ -6. DockIndicator显示停靠指示器 - ↓ -7. 用户拖拽面板移动 - ↓ -8. Panel触发 PANEL_DRAG_MOVE 事件 - ↓ -9. 更新拖拽状态和UI - ↓ -10. 用户释放面板 - ↓ -11. Panel触发 PANEL_DRAG_END 事件 - ↓ -12. 执行停靠逻辑(如果停靠到指示器) - ↓ -13. 清理拖拽状态 -``` - -## 类型定义 - -### 核心类型 - -**文件**:[types.d.ts](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/types.d.ts) - -#### 1. 面板位置类型 - -```typescript -export type PanelPosition = 'left' | 'right' | 'top' | 'bottom' | 'center' | 'floating'; -``` - -#### 2. 面板元数据 - -```typescript -export interface PanelMeta { - id: string; - title: string; - icon?: string; - component?: unknown; - initialPosition?: PanelPosition; - tags?: string[]; - flags?: { collapsed?: boolean; floating?: boolean }; -} -``` - -#### 3. 面板区 - -```typescript -export interface PanelArea { - id: string; - parentAreaId?: string; - position: PanelPosition; - subAreas: SubArea[]; - activeTabIndex?: number; - influence: InfluenceEntry[]; - influencedBy: InfluenceEntry[]; - pendingUpdates: Set; - x: number; - y: number; - width: number; - height: number; - widthRatios: number; - heightRatios: number; -} -``` - -#### 4. 子面板区 - -```typescript -export interface SubArea { - id: string; - position: PanelPosition; - panels: Panel[]; - activePanelId?: string; -} -``` - -#### 5. 面板 - -```typescript -export interface Panel { - id: string; - title: string; - component?: unknown; - isMaximized: boolean; - isMinimized: boolean; -} -``` - -## 测试和监控 - -### 集成测试 - -**文件**:[IntegrationTester.js](file:///d:/Projects/trunk/JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/IntegrationTester.js) - -#### 测试配置 - -```javascript -TEST_CONFIG = { - performanceThresholds: { - eventEmitTime: 10, // 事件发射时间阈值(毫秒) - eventHandleTime: 50, // 事件处理时间阈值(毫秒) - memoryUsage: 50 * 1024 * 1024, // 内存使用阈值(50MB) - cpuUsage: 80, // CPU使用率阈值(%) - dragFPS: 30, // 拖拽帧率阈值 - dragDuration: 3000, // 拖拽持续时间阈值(毫秒) - concurrentEvents: 100 // 并发事件数量阈值 - }, - - testCases: { - panel: { - createPanel: { priority: 1, timeout: 5000 }, - destroyPanel: { priority: 1, timeout: 5000 }, - maximizePanel: { priority: 1, timeout: 3000 }, - minimizePanel: { priority: 1, timeout: 3000 }, - restorePanel: { priority: 1, timeout: 3000 }, - closePanel: { priority: 1, timeout: 5000 } - }, - tabPage: { - createTabPage: { priority: 1, timeout: 5000 }, - switchTabPage: { priority: 1, timeout: 3000 }, - closeTabPage: { priority: 1, timeout: 5000 }, - mergeTabPage: { priority: 1, timeout: 5000 } - }, - area: { - createArea: { priority: 1, timeout: 5000 }, - dragArea: { priority: 1, timeout: 5000 }, - resizeArea: { priority: 1, timeout: 5000 }, - maximizeArea: { priority: 1, timeout: 3000 }, - restoreArea: { priority: 1, timeout: 3000 } - }, - drag: { - startDrag: { priority: 1, timeout: 3000 }, - moveDrag: { priority: 1, timeout: 5000 }, - endDrag: { priority: 1, timeout: 3000 }, - dockToEdge: { priority: 1, timeout: 5000 }, - dockToCenter: { priority: 1, timeout: 5000 } - } - } -} -``` - -#### 性能监控 - -```javascript -class PerformanceMonitor { - start() // 开始监控 - stop() // 停止监控 - recordMetric(name, value) // 记录指标 - getMetrics() // 获取指标 - checkThresholds() // 检查阈值 -} -``` - -### 内存保护 - -所有处理器都实现了内存保护机制: - -1. **自动清理**:定期清理过期数据 -2. **数量限制**:限制最大对象数量 -3. **历史清理**:限制历史记录大小 -4. **泄漏检测**:检测和报告内存泄漏 - -## 使用指南 - -### 基本使用 - -#### 1. 添加浮动面板 - -```javascript -import { ref } from 'vue'; - -const floatingAreas = ref([]); - -// 添加浮动面板 -const addFloatingPanel = (panel) => { - floatingAreas.value.push({ - id: `area-${Date.now()}`, - x: 100, - y: 100, - width: 300, - height: 250, - panels: [panel] - }); -}; -``` - -#### 2. 创建面板 - -```javascript -const panel = { - id: 'panel-1', - title: '示例面板', - component: 'ExampleComponent' -}; -``` - -#### 3. 监听事件 - -```javascript -import { eventBus } from './eventBus'; - -// 监听面板拖拽开始 -eventBus.on('panel.drag.start', (data) => { - console.log('面板拖拽开始:', data); -}); - -// 监听面板停靠 -eventBus.on('panel.dock', (data) => { - console.log('面板停靠:', data); -}); -``` - -### 高级使用 - -#### 1. 自定义停靠逻辑 - -```javascript -import { eventBus } from './eventBus'; - -// 监听停靠事件 -eventBus.on('panel.dock', (data) => { - const { panel, targetArea, position } = data; - - // 自定义停靠逻辑 - if (position === 'center') { - // 中心停靠逻辑 - } else if (position === 'edge') { - // 边缘停靠逻辑 - } -}); -``` - -#### 2. 性能监控 - -```javascript -import { getIntegrationTester } from './handlers/IntegrationTester'; - -const tester = getIntegrationTester(); - -// 开始性能监控 -tester.startPerformanceMonitor(); - -// 执行测试 -await tester.runTestSuite('panel'); - -// 获取性能报告 -const report = tester.getPerformanceReport(); -console.log(report); -``` - -#### 3. 自定义事件处理器 - -```javascript -import { eventBus } from './eventBus'; - -// 注册自定义事件处理器 -eventBus.on('custom.event', (data) => { - console.log('自定义事件:', data); -}, { - priority: 1, - deduplication: { type: 'TTL_BASED', ttl: 100 } -}); -``` - -## 最佳实践 - -### 1. 组件开发 - -- 使用Composition API编写组件 -- 遵循单一职责原则 -- 合理拆分组件 -- 使用TypeScript提供类型安全 - -### 2. 事件处理 - -- 使用事件总线进行组件通信 -- 合理设置事件优先级 -- 启用事件去重 -- 及时清理事件监听器 - -### 3. 性能优化 - -- 避免频繁的状态更新 -- 使用computed缓存计算结果 -- 合理使用v-show和v-if -- 及时清理过期数据 - -### 4. 内存管理 - -- 在组件卸载时清理资源 -- 使用单例模式避免重复创建 -- 定期清理过期数据 -- 监控内存使用情况 - -### 5. 错误处理 - -- 使用try-catch捕获错误 -- 记录错误日志 -- 提供友好的错误提示 -- 实现错误恢复机制 - -## 常见问题 - -### Q1: 如何添加自定义面板? - -A: 创建面板组件,然后在DockLayout中添加浮动面板或停靠面板。 - -```javascript -const customPanel = { - id: 'custom-panel', - title: '自定义面板', - component: CustomPanelComponent -}; -``` - -### Q2: 如何实现自定义停靠逻辑? - -A: 监听停靠事件,在事件处理器中实现自定义逻辑。 - -```javascript -eventBus.on('panel.dock', (data) => { - // 自定义停靠逻辑 -}); -``` - -### Q3: 如何优化性能? - -A: -- 使用事件去重 -- 及时清理过期数据 -- 避免频繁的状态更新 -- 使用性能监控工具 - -### Q4: 如何处理内存泄漏? - -A: -- 在组件卸载时清理事件监听器 -- 使用单例模式避免重复创建 -- 定期清理过期数据 -- 使用内存监控工具 - -### Q5: 如何调试事件? - -A: -- 启用调试模式 -- 使用事件监控工具 -- 查看事件日志 -- 使用浏览器开发者工具 - -## 更新日志 - -### v1.8 -- 修正DockIndicator文档,移除不准确的描述 -- 增强中文沟通用词建议 -- 修正独立中心指示器z-index为10000 - -### v1.7 -- 实现将中心指示器移到与中心区域容器同级 -- 保持中心指示器位置相对于中心区域容器正中央 -- 更新层级结构图 - -### v1.6 -- 根据实际代码情况更新文档结构 -- 移除独立中心指示器相关内容 -- 更新层级结构图 - -### v1.3 -- 添加独立中心指示器相关命名约定 -- 更新层级结构图 -- 更新中文沟通用词建议 - -### v1.2 -- 添加子区域指示器功能实现记录 -- 更新文档以反映半透明依靠区功能的完成状态 - -### v1.1 -- 修正层级结构图,添加完整的外部边缘指示器 -- 在层级结构图中标注当前实际使用的类名 -- 完善命名体系的一致性 - -### v1.0 -- 初始版本,建立基础命名约定体系 - -## 贡献指南 - -欢迎贡献代码、报告问题或提出改进建议。 - -### 开发环境 - -1. 克隆项目 -2. 安装依赖:`npm install` -3. 启动开发服务器:`npm run dev` -4. 运行测试:`npm run test` - -### 代码规范 - -- 使用ESLint进行代码检查 -- 使用Prettier进行代码格式化 -- 遵循Vue 3风格指南 -- 编写单元测试和集成测试 - -### 提交规范 - -- 使用清晰的提交信息 -- 遵循Conventional Commits规范 -- 提交前运行测试 -- 更新相关文档 - -## 许可证 - -本项目采用 MIT 许可证。 - -## 联系方式 - -如有问题或建议,请联系项目维护者。 - ---- - -**文档版本**:v1.0 -**创建日期**:2024年 -**最后更新**:2024年 -**适用范围**:DockLayout 可停靠布局系统 diff --git a/AutoRobot/Windows/Robot/Web/src/DockLayout/Render.vue b/AutoRobot/Windows/Robot/Web/src/DockLayout/Render.vue index cf79009..77b6c79 100644 --- a/AutoRobot/Windows/Robot/Web/src/DockLayout/Render.vue +++ b/AutoRobot/Windows/Robot/Web/src/DockLayout/Render.vue @@ -19,10 +19,10 @@