解决事件泄漏问题

This commit is contained in:
zqm
2025-12-26 13:09:35 +08:00
parent efa9fd64c7
commit 7f2f31156f
13 changed files with 924 additions and 1098 deletions

View File

@@ -180,6 +180,7 @@ const areaRef = ref(null)
const isDragging = ref(false) const isDragging = ref(false)
const dragStartPos = ref({ x: 0, y: 0 }) const dragStartPos = ref({ x: 0, y: 0 })
const areaStartPos = ref({ x: 0, y: 0 }) const areaStartPos = ref({ x: 0, y: 0 })
const currentDragId = ref(null)
// 调整大小相关状态 // 调整大小相关状态
const isResizing = ref(false) const isResizing = ref(false)
@@ -278,18 +279,24 @@ const onPanelMaximize = (panelId) => {
} else { } else {
// // console.log('🔸 非单Panel模式转发到父组件') // // console.log('🔸 非单Panel模式转发到父组件')
// 如果不是单Panel转发给父组件处理 // 如果不是单Panel转发给父组件处理
emitEvent(EVENT_TYPES.PANEL_MAXIMIZE, { panelId, areaId: props.id }) emitEvent(EVENT_TYPES.PANEL_MAXIMIZE, { panelId, areaId: props.id }, {
source: { component: 'Area', areaId: props.id }
})
} }
} }
// 处理拖拽悬停事件 // 处理拖拽悬停事件
const handleDragOver = (event) => { const handleDragOver = (event) => {
emitEvent(EVENT_TYPES.AREA_DRAG_OVER, { event, areaId: props.id }) emitEvent(EVENT_TYPES.AREA_DRAG_OVER, { event, areaId: props.id }, {
source: { component: 'Area', areaId: props.id }
})
} }
// 处理拖拽离开事件 // 处理拖拽离开事件
const handleDragLeave = (event) => { const handleDragLeave = (event) => {
emitEvent(EVENT_TYPES.AREA_DRAG_LEAVE, { event, areaId: props.id }) emitEvent(EVENT_TYPES.AREA_DRAG_LEAVE, { event, areaId: props.id }, {
source: { component: 'Area', areaId: props.id }
})
} }
// 拖拽开始 // 拖拽开始
@@ -307,8 +314,12 @@ const onDragStart = (e) => {
y: originalPosition.value.top || 0 y: originalPosition.value.top || 0
} }
// 使用事件总线通知拖拽开始 // 生成统一的 dragId
currentDragId.value = `area_${props.id}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
// 使用事件总线通知拖拽开始,包含 dragId 和标准化数据格式
emitEvent(EVENT_TYPES.AREA_DRAG_START, { emitEvent(EVENT_TYPES.AREA_DRAG_START, {
dragId: currentDragId.value,
areaId: props.id, areaId: props.id,
event: e, event: e,
element: areaRef.value, element: areaRef.value,
@@ -316,7 +327,10 @@ const onDragStart = (e) => {
clientX: e.clientX, clientX: e.clientX,
clientY: e.clientY, clientY: e.clientY,
startLeft: originalPosition.value.left || 0, startLeft: originalPosition.value.left || 0,
startTop: originalPosition.value.top || 0 startTop: originalPosition.value.top || 0,
timestamp: Date.now()
}, {
source: { component: 'Area', areaId: props.id, dragId: currentDragId.value }
}) })
// 使用全局事件管理器添加事件监听 // 使用全局事件管理器添加事件监听
@@ -329,7 +343,7 @@ const onDragStart = (e) => {
// 拖拽移动 // 拖拽移动
const onDragMove = (e) => { const onDragMove = (e) => {
if (!isDragging.value) return if (!isDragging.value || !currentDragId.value) return
// 计算移动距离 // 计算移动距离
const deltaX = e.clientX - dragStartPos.value.x const deltaX = e.clientX - dragStartPos.value.x
@@ -354,8 +368,9 @@ const onDragMove = (e) => {
originalPosition.value.left = newLeft originalPosition.value.left = newLeft
originalPosition.value.top = newTop originalPosition.value.top = newTop
// 使用事件总线通知拖拽移动 // 使用事件总线通知拖拽移动,包含 dragId
emitEvent(EVENT_TYPES.AREA_DRAG_MOVE, { emitEvent(EVENT_TYPES.AREA_DRAG_MOVE, {
dragId: currentDragId.value,
areaId: props.id, areaId: props.id,
event: e, event: e,
element: areaRef.value, element: areaRef.value,
@@ -363,27 +378,44 @@ const onDragMove = (e) => {
clientX: e.clientX, clientX: e.clientX,
clientY: e.clientY, clientY: e.clientY,
left: newLeft, left: newLeft,
top: newTop top: newTop,
timestamp: Date.now()
}, {
source: { component: 'Area', areaId: props.id, dragId: currentDragId.value }
}) })
// 使用事件总线通知位置变化 // 使用事件总线通知位置变化,包含 dragId
emitEvent(EVENT_TYPES.AREA_POSITION_UPDATE, { areaId: props.id, left: newLeft, top: newTop }) emitEvent(EVENT_TYPES.AREA_POSITION_UPDATE, {
dragId: currentDragId.value,
areaId: props.id,
left: newLeft,
top: newTop
}, {
source: { component: 'Area', areaId: props.id, dragId: currentDragId.value }
})
} }
// 拖拽结束 // 拖拽结束
const onDragEnd = () => { const onDragEnd = () => {
// 使用事件总线通知拖拽结束 if (!currentDragId.value) return
// 使用事件总线通知拖拽结束,包含 dragId 和标准化数据格式
emitEvent(EVENT_TYPES.AREA_DRAG_END, { emitEvent(EVENT_TYPES.AREA_DRAG_END, {
dragId: currentDragId.value,
areaId: props.id, areaId: props.id,
finalPosition: { finalPosition: {
x: originalPosition.value.left, x: originalPosition.value.left,
y: originalPosition.value.top y: originalPosition.value.top
}, },
left: originalPosition.value.left, left: originalPosition.value.left,
top: originalPosition.value.top top: originalPosition.value.top,
timestamp: Date.now()
}, {
source: { component: 'Area', areaId: props.id, dragId: currentDragId.value }
}) })
isDragging.value = false isDragging.value = false
currentDragId.value = null
// 使用全局事件管理器移除事件监听 // 使用全局事件管理器移除事件监听
globalEventListenerManager.removeGlobalListener('mousemove', onDragMove) globalEventListenerManager.removeGlobalListener('mousemove', onDragMove)
globalEventListenerManager.removeGlobalListener('mouseup', onDragEnd) globalEventListenerManager.removeGlobalListener('mouseup', onDragEnd)
@@ -507,6 +539,8 @@ const onResizeStart = (direction, e) => {
areaId: props.id, areaId: props.id,
left: newLeft, left: newLeft,
top: newTop top: newTop
}, {
source: { component: 'Area', areaId: props.id }
}) })
// 防止文本选择 // 防止文本选择
@@ -542,6 +576,8 @@ const onToggleMaximize = () => {
areaId: props.id, areaId: props.id,
left: originalPosition.value.left, left: originalPosition.value.left,
top: originalPosition.value.top top: originalPosition.value.top
}, {
source: { component: 'Area', areaId: props.id }
}) })
} }
@@ -549,11 +585,15 @@ const onToggleMaximize = () => {
emitEvent(EVENT_TYPES.WINDOW_STATE_CHANGE, { emitEvent(EVENT_TYPES.WINDOW_STATE_CHANGE, {
areaId: props.id, areaId: props.id,
state: next state: next
}, {
source: { component: 'Area', areaId: props.id }
}) })
} }
const onClose = () => emitEvent(EVENT_TYPES.PANEL_CLOSE_REQUEST, { const onClose = () => emitEvent(EVENT_TYPES.PANEL_CLOSE_REQUEST, {
areaId: props.id areaId: props.id
}, {
source: { component: 'Area', areaId: props.id }
}) })
// 组件挂载后获取父容器引用并初始化位置 // 组件挂载后获取父容器引用并初始化位置
@@ -589,6 +629,8 @@ onMounted(() => {
areaId: props.id, areaId: props.id,
left: originalPosition.value.left, left: originalPosition.value.left,
top: originalPosition.value.top top: originalPosition.value.top
}, {
source: { component: 'Area', areaId: props.id }
}) })
} }
}) })
@@ -675,6 +717,8 @@ const mergeAreaContent = (sourceArea) => {
targetAreaHasContent: false, // 目标Area为空 targetAreaHasContent: false, // 目标Area为空
operation: 'add-children', operation: 'add-children',
addedTabPages: receivedContent.value addedTabPages: receivedContent.value
}, {
source: { component: 'Area', areaId: props.id }
}) })
return true return true
@@ -734,6 +778,8 @@ const mergeAreaContent = (sourceArea) => {
targetAreaHasContent: true, // 目标Area已有内容 targetAreaHasContent: true, // 目标Area已有内容
operation: 'merge-tabpages', operation: 'merge-tabpages',
sourceTabPages: tabPagesData sourceTabPages: tabPagesData
}, {
source: { component: 'Area', areaId: props.id }
}) })
// 更新完成 // 更新完成
// // console.log(`[Area] 合并完成现有TabPage共有 ${existingTabPage.tabPage.panels.length} 个Panel`) // // console.log(`[Area] 合并完成现有TabPage共有 ${existingTabPage.tabPage.panels.length} 个Panel`)

View File

@@ -716,7 +716,9 @@ const enhancedPreviewAreaStyle = computed(() => {
// 监听activeDockZone变化触发事件 // 监听activeDockZone变化触发事件
watch(activeDockZone, (newZone) => { watch(activeDockZone, (newZone) => {
emitEvent('dock-zone-active', { zoneId: newZone }) emitEvent('dock-zone-active', { zoneId: newZone }, {
source: { component: 'DockIndicator' }
})
}) })
</script> </script>

View File

@@ -289,48 +289,48 @@ const setupEventListeners = () => {
const unsubscribeFunctions = []; const unsubscribeFunctions = [];
// Area相关事件 // Area相关事件
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_START, onAreaDragStart)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_START, onAreaDragStart, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_MOVE, onAreaDragMove)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_MOVE, onAreaDragMove, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_END, onAreaDragEnd)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_END, onAreaDragEnd, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_POSITION_UPDATE, onUpdatePosition)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_POSITION_UPDATE, onUpdatePosition, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_OVER, handleAreaDragOver)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_OVER, handleAreaDragOver, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_LEAVE, handleAreaDragLeave)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_LEAVE, handleAreaDragLeave, { componentId: 'dock-layout' }));
// Tab相关事件 // Tab相关事件
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CLOSE, onTabClose)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CLOSE, onTabClose, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_ADD, onTabAdd)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_ADD, onTabAdd, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_START, onTabDragStart)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_START, onTabDragStart, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_MOVE, onTabDragMove)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_MOVE, onTabDragMove, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_END, onTabDragEnd)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_END, onTabDragEnd, { componentId: 'dock-layout' }));
// Panel相关事件 // Panel相关事件
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_COLLAPSE, () => emit('toggleCollapse'))); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_COLLAPSE, () => emit('toggleCollapse'), { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE, onMaximize)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE, onMaximize, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE_REQUEST, onCloseFloatingArea)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE_REQUEST, onCloseFloatingArea, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE, onClosePanel)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE, onClosePanel, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_TOOLBAR, () => emit('toggleToolbar'))); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_TOOLBAR, () => emit('toggleToolbar'), { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_START, onPanelDragStart)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_START, onPanelDragStart, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_MOVE, onPanelDragMove)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_MOVE, onPanelDragMove, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_END, onPanelDragEnd)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_END, onPanelDragEnd, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_START_FROM_TABPAGE, onPanelDragStartFromTabPage)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_START_FROM_TABPAGE, onPanelDragStartFromTabPage, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_MOVE_FROM_TABPAGE, onPanelDragMoveFromTabPage)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_MOVE_FROM_TABPAGE, onPanelDragMoveFromTabPage, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_END_FROM_TABPAGE, onPanelDragEndFromTabPage)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_END_FROM_TABPAGE, onPanelDragEndFromTabPage, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, onPanelMaximizeSync)); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, onPanelMaximizeSync, { componentId: 'dock-layout' }));
// Resize相关事件 // Resize相关事件
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_START, () => emit('dragStart'))); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_START, () => emit('dragStart'), { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_MOVE, () => emit('dragMove'))); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_MOVE, () => emit('dragMove'), { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_END, () => emit('dragEnd'))); unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_END, () => emit('dragEnd'), { componentId: 'dock-layout' }));
// Window相关事件 // Window相关事件
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.WINDOW_STATE_CHANGE, (event) => { unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.WINDOW_STATE_CHANGE, (event) => {
// 处理窗口状态变化 // 处理窗口状态变化
})); }, { componentId: 'dock-layout' }));
// 自定义事件 // 自定义事件
unsubscribeFunctions.push(eventBus.on('area-merged', onAreaMerged)); unsubscribeFunctions.push(eventBus.on('area-merged', onAreaMerged, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on('dock-zone-active', (event) => onDockZoneActive(event.zoneId))); unsubscribeFunctions.push(eventBus.on('dock-zone-active', (event) => onDockZoneActive(event.zoneId), { componentId: 'dock-layout' }));
return unsubscribeFunctions; return unsubscribeFunctions;
}; };

View File

@@ -202,6 +202,8 @@ const onToggleCollapse = () => {
panelId: props.id, panelId: props.id,
areaId: getCurrentAreaId(), areaId: getCurrentAreaId(),
currentState: props.collapsed currentState: props.collapsed
}, {
source: { component: 'Panel', panelId: props.id }
}) })
}; };
@@ -211,6 +213,8 @@ const onMaximize = () => {
panelId: props.id, panelId: props.id,
areaId: getCurrentAreaId(), areaId: getCurrentAreaId(),
currentState: props.maximized currentState: props.maximized
}, {
source: { component: 'Panel', panelId: props.id }
}) })
}; };
@@ -222,6 +226,8 @@ const onClose = () => {
areaId: getCurrentAreaId(), areaId: getCurrentAreaId(),
panelTitle: props.title, panelTitle: props.title,
requestTime: Date.now() requestTime: Date.now()
}, {
source: { component: 'Panel', panelId: props.id }
}) })
}; };
@@ -231,11 +237,14 @@ const onToggleToolbar = () => {
panelId: props.id, panelId: props.id,
areaId: getCurrentAreaId(), areaId: getCurrentAreaId(),
currentState: props.toolbarExpanded currentState: props.toolbarExpanded
}, {
source: { component: 'Panel', panelId: props.id }
}) })
}; };
// 拖拽相关状态 // 拖拽相关状态
let isDragging = false let isDragging = false
let currentDragId = null
// 全局内存泄漏保护机制 // 全局内存泄漏保护机制
if (!window.__panelMemoryProtection) { if (!window.__panelMemoryProtection) {
@@ -378,19 +387,25 @@ const onDragStart = (e) => {
if (!e.target.closest('.title-bar-buttons') && !e.target.closest('button')) { if (!e.target.closest('.title-bar-buttons') && !e.target.closest('button')) {
// 1. 立即重置之前的拖拽状态 // 1. 立即重置之前的拖拽状态
isDragging = false isDragging = false
currentDragId = null
cleanupDragEventListeners() cleanupDragEventListeners()
isDragging = true isDragging = true
console.log(`[Panel:${props.id}] 开始拖拽`)
// 2. 使用事件总线触发拖拽开始事件 // 生成统一的 dragId
currentDragId = `panel_${props.id}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
console.log(`[Panel:${props.id}] 开始拖拽, dragId: ${currentDragId}`)
// 2. 使用事件总线触发拖拽开始事件,包含统一的 dragId 和标准化数据格式
emitEvent(EVENT_TYPES.PANEL_DRAG_START, { emitEvent(EVENT_TYPES.PANEL_DRAG_START, {
dragId: currentDragId,
panelId: props.id, panelId: props.id,
areaId: getCurrentAreaId(), areaId: getCurrentAreaId(),
position: { x: e.clientX, y: e.clientY }, position: { x: e.clientX, y: e.clientY },
timestamp: Date.now() timestamp: Date.now()
}, { }, {
source: { component: 'Panel', panelId: props.id } source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
}) })
// 3. 防止文本选择和默认行为 // 3. 防止文本选择和默认行为
@@ -404,40 +419,46 @@ const onDragStart = (e) => {
// 拖拽移动 // 拖拽移动
const onDragMove = (e) => { const onDragMove = (e) => {
if (isDragging) { if (isDragging && currentDragId) {
// 防止文本选择和默认行为 // 防止文本选择和默认行为
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
// 使用事件总线触发拖拽移动事件 // 使用事件总线触发拖拽移动事件,包含 dragId
emitEvent(EVENT_TYPES.PANEL_DRAG_MOVE, { emitEvent(EVENT_TYPES.PANEL_DRAG_MOVE, {
dragId: currentDragId,
panelId: props.id, panelId: props.id,
areaId: getCurrentAreaId(), areaId: getCurrentAreaId(),
position: { x: e.clientX, y: e.clientY }, position: { x: e.clientX, y: e.clientY },
timestamp: Date.now() timestamp: Date.now()
}, { }, {
source: { component: 'Panel', panelId: props.id } source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
}) })
} }
}; };
// 拖拽结束 // 拖拽结束
const onDragEnd = () => { const onDragEnd = () => {
if (isDragging) { if (isDragging && currentDragId) {
isDragging = false; isDragging = false;
console.log(`[Panel:${props.id}] 结束拖拽`)
// 使用事件总线触发拖拽结束事件 console.log(`[Panel:${props.id}] 结束拖拽, dragId: ${currentDragId}`)
// 使用事件总线触发拖拽结束事件,包含 dragId
emitEvent(EVENT_TYPES.PANEL_DRAG_END, { emitEvent(EVENT_TYPES.PANEL_DRAG_END, {
dragId: currentDragId,
panelId: props.id, panelId: props.id,
areaId: getCurrentAreaId(), areaId: getCurrentAreaId(),
timestamp: Date.now() timestamp: Date.now()
}, { }, {
source: { component: 'Panel', panelId: props.id } source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
}) })
// 使用统一的清理方法,确保一致性和完整性 // 使用统一的清理方法,确保一致性和完整性
cleanupDragEventListeners() cleanupDragEventListeners()
// 重置 dragId
currentDragId = null
} }
}; };
@@ -449,10 +470,9 @@ const setupEventListeners = () => {
// 监听面板最大化同步事件 // 监听面板最大化同步事件
const unsubscribeMaximizeSync = onEvent(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, (data) => { const unsubscribeMaximizeSync = onEvent(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, (data) => {
if (data.panelId === props.id) { if (data.panelId === props.id) {
// 这里可以添加最大化状态同步的逻辑
console.log(`[Panel:${props.id}] 收到最大化同步事件`) console.log(`[Panel:${props.id}] 收到最大化同步事件`)
} }
}) }, { componentId: `panel-${props.id}` })
const subscriptionId = `maximizeSync_${props.id}_${Date.now()}` const subscriptionId = `maximizeSync_${props.id}_${Date.now()}`
subscriptions.add(unsubscribeMaximizeSync) subscriptions.add(unsubscribeMaximizeSync)

View File

@@ -123,7 +123,9 @@ const handleMouseMove = (event: MouseEvent) => {
// 结束调整大小 // 结束调整大小
const endResize = () => { const endResize = () => {
isResizing.value = false isResizing.value = false
emitEvent(EVENT_TYPES.RESIZE_END, { direction: props.direction, targetId: props.targetId }) emitEvent(EVENT_TYPES.RESIZE_END, { direction: props.direction, targetId: props.targetId }, {
source: { component: 'ResizeBar', targetId: props.targetId, direction: props.direction }
})
// 移除全局鼠标事件监听 // 移除全局鼠标事件监听
document.removeEventListener('mousemove', handleMouseMove) document.removeEventListener('mousemove', handleMouseMove)

View File

@@ -155,6 +155,7 @@ const activeTabIndex = ref(-1)
// 拖拽相关状态 // 拖拽相关状态
let isDragging = false let isDragging = false
let dragIndex = -1 let dragIndex = -1
let currentDragId = null
// 计算属性获取插槽项的props // 计算属性获取插槽项的props
const slotItems = computed(() => { const slotItems = computed(() => {
@@ -198,12 +199,18 @@ const onTabDragStart = (index, event) => {
isDragging = true isDragging = true
dragIndex = index dragIndex = index
// 传递标签页索引和鼠标位置 // 生成统一的 dragId
currentDragId = `tabpage_${props.id}_${index}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
// 传递标签页索引和鼠标位置,包含 dragId
emitEvent(EVENT_TYPES.TAB_DRAG_START, { emitEvent(EVENT_TYPES.TAB_DRAG_START, {
dragId: currentDragId,
clientX: event.clientX, clientX: event.clientX,
clientY: event.clientY, clientY: event.clientY,
tabIndex: index, tabIndex: index,
tabId: $slots.default()[index]?.props?.id tabId: $slots.default()[index]?.props?.id
}, {
source: { component: 'TabPage', tabPageId: props.id, tabIndex: index, dragId: currentDragId }
}) })
// 防止文本选择和默认行为 // 防止文本选择和默认行为
@@ -219,11 +226,12 @@ const onTabDragStart = (index, event) => {
// 标签拖拽移动 // 标签拖拽移动
const onTabDragMove = (event) => { const onTabDragMove = (event) => {
if (isDragging) { if (isDragging && currentDragId) {
// 防止文本选择和默认行为 // 防止文本选择和默认行为
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
emitEvent(EVENT_TYPES.TAB_DRAG_MOVE, { emitEvent(EVENT_TYPES.TAB_DRAG_MOVE, {
dragId: currentDragId,
clientX: event.clientX, clientX: event.clientX,
clientY: event.clientY, clientY: event.clientY,
tabIndex: dragIndex tabIndex: dragIndex
@@ -233,10 +241,14 @@ const onTabDragMove = (event) => {
// 标签拖拽结束 // 标签拖拽结束
const onTabDragEnd = () => { const onTabDragEnd = () => {
if (isDragging) { if (isDragging && currentDragId) {
isDragging = false isDragging = false
emitEvent(EVENT_TYPES.TAB_DRAG_END, { tabIndex: dragIndex }) emitEvent(EVENT_TYPES.TAB_DRAG_END, {
dragId: currentDragId,
tabIndex: dragIndex
})
dragIndex = -1 dragIndex = -1
currentDragId = null
// 拖拽结束后移除事件监听器 // 拖拽结束后移除事件监听器
document.removeEventListener('mousemove', onTabDragMove) document.removeEventListener('mousemove', onTabDragMove)

File diff suppressed because it is too large Load Diff

View File

@@ -3,9 +3,9 @@
* 专门处理Area相关的所有事件包括浮动区域管理、拖拽、停靠、合并等 * 专门处理Area相关的所有事件包括浮动区域管理、拖拽、停靠、合并等
*/ */
import { eventBus } from '../eventBus'; import { eventBus, EVENT_TYPES } from '../eventBus';
// Area事件类型常量 // Area事件类型常量仅包含EVENT_TYPES中没有的
export const AREA_EVENT_TYPES = { export const AREA_EVENT_TYPES = {
// 基础事件 // 基础事件
AREA_CREATED: 'area.created', AREA_CREATED: 'area.created',
@@ -23,16 +23,8 @@ export const AREA_EVENT_TYPES = {
AREA_RESTORE: 'area.restore', AREA_RESTORE: 'area.restore',
AREA_COLLAPSE: 'area.collapse', AREA_COLLAPSE: 'area.collapse',
AREA_EXPAND: 'area.expand', AREA_EXPAND: 'area.expand',
AREA_CLOSE: 'area.close',
AREA_TOGGLE_TOOLBAR: 'area.toggleToolbar', AREA_TOGGLE_TOOLBAR: 'area.toggleToolbar',
// 拖拽相关
AREA_DRAG_START: 'area.drag.start',
AREA_DRAG_MOVE: 'area.drag.move',
AREA_DRAG_END: 'area.drag.end',
AREA_DRAG_OVER: 'area.drag.over',
AREA_DRAG_LEAVE: 'area.drag.leave',
// 停靠相关 // 停靠相关
AREA_DOCK_CENTER: 'area.dock.center', AREA_DOCK_CENTER: 'area.dock.center',
AREA_DOCK_EDGE: 'area.dock.edge', AREA_DOCK_EDGE: 'area.dock.edge',
@@ -759,12 +751,36 @@ class AreaEventHandler {
* 注册事件监听器 * 注册事件监听器
*/ */
_registerEventListeners() { _registerEventListeners() {
const events = Object.values(AREA_EVENT_TYPES); // 监听 EVENT_TYPES 中的事件
events.forEach(eventType => { const eventTypes = [
EVENT_TYPES.AREA_DRAG_START,
EVENT_TYPES.AREA_DRAG_MOVE,
EVENT_TYPES.AREA_DRAG_END,
EVENT_TYPES.AREA_DRAG_OVER,
EVENT_TYPES.AREA_DRAG_LEAVE,
EVENT_TYPES.AREA_CLOSE,
EVENT_TYPES.AREA_POSITION_UPDATE,
EVENT_TYPES.AREA_PANEL_CLOSED
];
eventTypes.forEach(eventType => {
const listener = this._onAreaEvent; const listener = this._onAreaEvent;
eventBus.on(eventType, listener, { eventBus.on(eventType, listener, {
priority: 1, priority: 1,
deduplication: { type: 'TTL_BASED', ttl: 100 } deduplication: { type: 'TTL_BASED', ttl: 100 },
componentId: 'area-handler'
});
this.areaListeners.set(eventType, listener);
});
// 监听 AREA_EVENT_TYPES 中的事件
const areaEventTypes = Object.values(AREA_EVENT_TYPES);
areaEventTypes.forEach(eventType => {
const listener = this._onAreaEvent;
eventBus.on(eventType, listener, {
priority: 1,
deduplication: { type: 'TTL_BASED', ttl: 100 },
componentId: 'area-handler'
}); });
this.areaListeners.set(eventType, listener); this.areaListeners.set(eventType, listener);
}); });
@@ -775,17 +791,17 @@ class AreaEventHandler {
* @param {Object} data - 事件数据 * @param {Object} data - 事件数据
*/ */
async _onAreaEvent(data) { async _onAreaEvent(data) {
const { eventType } = data; const eventType = data.eventType;
try { try {
switch (eventType) { switch (eventType) {
case AREA_EVENT_TYPES.AREA_DRAG_START: case EVENT_TYPES.AREA_DRAG_START:
await this._handleAreaDragStart(data); await this._handleAreaDragStart(data);
break; break;
case AREA_EVENT_TYPES.AREA_DRAG_MOVE: case EVENT_TYPES.AREA_DRAG_MOVE:
await this._handleAreaDragMove(data); await this._handleAreaDragMove(data);
break; break;
case AREA_EVENT_TYPES.AREA_DRAG_END: case EVENT_TYPES.AREA_DRAG_END:
await this._handleAreaDragEnd(data); await this._handleAreaDragEnd(data);
break; break;
case AREA_EVENT_TYPES.AREA_DOCK_CENTER: case AREA_EVENT_TYPES.AREA_DOCK_CENTER:
@@ -806,13 +822,15 @@ class AreaEventHandler {
case AREA_EVENT_TYPES.AREA_FLOATING_CREATE: case AREA_EVENT_TYPES.AREA_FLOATING_CREATE:
await this._handleFloatingAreaCreate(data); await this._handleFloatingAreaCreate(data);
break; break;
case AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT:
await this._handleAreaZIndexManagement(data);
break;
default: default:
// 记录其他事件但不处理 // 记录其他事件但不处理
console.log(`📍 Area事件处理器: ${eventType}`, data); console.log(`📍 Area事件处理器: ${eventType || 'unknown'}`, data);
} }
} catch (error) { } catch (error) {
console.error(`❌ Area事件处理错误 (${eventType}):`, error); console.error(`❌ Area事件处理错误 (${eventType}):`, error);
eventBus.recordError(`areaHandler_${eventType}`, error);
} }
} }
@@ -884,7 +902,7 @@ class AreaEventHandler {
* @param {Object} data - 事件数据 * @param {Object} data - 事件数据
*/ */
async _handleAreaDragEnd(data) { async _handleAreaDragEnd(data) {
const { areaId, event } = data; const { areaId, event, finalPosition, left, top } = data;
const dragState = this.areaStateManager.getDragState(areaId); const dragState = this.areaStateManager.getDragState(areaId);
if (!dragState) return; if (!dragState) return;
@@ -896,7 +914,18 @@ class AreaEventHandler {
// 清理拖拽状态 // 清理拖拽状态
dragState.isDragging = false; dragState.isDragging = false;
dragState.endTime = Date.now(); dragState.endTime = Date.now();
dragState.endPosition = { x: event.clientX, y: event.clientY };
// 使用 finalPosition 或 left/top 作为结束位置
if (finalPosition) {
dragState.endPosition = { x: finalPosition.x, y: finalPosition.y };
} else if (left !== undefined && top !== undefined) {
dragState.endPosition = { x: left, y: top };
} else if (event) {
dragState.endPosition = { x: event.clientX, y: event.clientY };
} else {
dragState.endPosition = dragState.startPosition;
}
dragState.totalDistance = distance; dragState.totalDistance = distance;
dragState.duration = dragDuration; dragState.duration = dragDuration;
@@ -1126,6 +1155,50 @@ class AreaEventHandler {
}); });
} }
/**
* 处理Area层级管理事件
* @param {Object} data - 事件数据
*/
async _handleAreaZIndexManagement(data) {
const { areaId, action, zIndex, reason } = data;
try {
switch (action) {
case 'activate':
// 激活Area时更新z-index
this.activeAreas.add(areaId);
this.areaStateManager.updateState(areaId, {
lastActivatedAt: Date.now()
});
break;
case 'create_floating':
// 创建浮动Area时设置z-index
if (zIndex) {
this.areaStateManager.updateState(areaId, {
zIndex,
lastActivatedAt: Date.now()
});
}
break;
case 'update':
// 更新z-index
if (zIndex) {
this.areaStateManager.updateState(areaId, {
zIndex
});
}
break;
default:
console.log(`📍 Area层级管理: ${action}`, data);
}
} catch (error) {
console.error(`❌ Area层级管理错误 (${action}):`, error);
}
}
/** /**
* 启动内存保护机制 * 启动内存保护机制
*/ */
@@ -1233,6 +1306,12 @@ class AreaEventHandler {
// 创建单例实例 // 创建单例实例
const areaHandler = new AreaEventHandler(); const areaHandler = new AreaEventHandler();
/**
* 获取Area事件处理器实例
* @returns {AreaEventHandler} AreaEventHandler实例
*/
export const getAreaHandler = () => areaHandler;
// Area便捷操作函数 // Area便捷操作函数
export const areaActions = { export const areaActions = {
/** /**

View File

@@ -495,6 +495,8 @@ class DragStateManager {
}; };
this.isEnabled = true; this.isEnabled = true;
this.debugMode = false; this.debugMode = false;
this.eventListenersRegistered = false; // 初始化监听器注册标志
this.cleanupScheduler = null; // 初始化清理调度器
// 绑定方法 // 绑定方法
this._onDragEvent = this._onDragEvent.bind(this); this._onDragEvent = this._onDragEvent.bind(this);
@@ -516,12 +518,24 @@ class DragStateManager {
console.log('🎯 拖拽状态管理器初始化完成'); console.log('🎯 拖拽状态管理器初始化完成');
} }
/**
* 生成唯一的拖拽ID
* @param {string} componentType - 组件类型
* @returns {string} 拖拽ID
*/
_generateDragId(componentType) {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2, 9);
return `${componentType}_${timestamp}_${random}`;
}
/** /**
* 注册事件监听器 * 注册事件监听器
*/ */
_registerEventListeners() { _registerEventListeners() {
// 防止重复注册监听器 // 防止重复注册监听器
if (this.eventListenersRegistered) { if (this.eventListenersRegistered) {
console.log('🚫 已经注册了监听器,跳过重复注册');
return; return;
} }
@@ -537,17 +551,22 @@ class DragStateManager {
dragEvents.forEach(eventType => { dragEvents.forEach(eventType => {
eventBus.on(eventType, this._onDragEvent, { eventBus.on(eventType, this._onDragEvent, {
priority: 1, priority: 1,
deduplication: { type: 'EVENT_BASED', key: 'dragState' } deduplication: { type: 'EVENT_BASED', key: 'dragState' },
componentId: 'drag-state-manager'
}); });
}); });
this.eventListenersRegistered = true; this.eventListenersRegistered = true;
console.log('✅ 拖拽管理器事件监听器注册完成');
} }
/** /**
* 销毁管理器 * 销毁管理器
*/ */
destroy() { destroy() {
// 取消所有拖拽
this.cancelAllDrags();
// 清理事件监听器 // 清理事件监听器
const dragEvents = [ const dragEvents = [
// Panel拖拽事件 // Panel拖拽事件
@@ -565,10 +584,17 @@ class DragStateManager {
// 清理清理调度器 // 清理清理调度器
this._stopCleanupScheduler(); this._stopCleanupScheduler();
// 清理拖拽状态 // 清理数据
this.dragStates.clear(); this.activeDrags.clear();
this.dragHistory = []; this.dragHistory = [];
this.dragTargets.clear();
// 清理冲突检测器
this.conflictDetector.activeDrags.clear();
this.conflictDetector.conflictHistory = [];
this.isEnabled = false;
this.eventListenersRegistered = false;
console.log('🗑️ 拖拽状态管理器已销毁'); console.log('🗑️ 拖拽状态管理器已销毁');
} }
@@ -579,34 +605,66 @@ class DragStateManager {
async _onDragEvent(data) { async _onDragEvent(data) {
if (!this.isEnabled) return; if (!this.isEnabled) return;
const monitorId = globalEventActions.startMonitor(`drag_${data.eventType || data.type}`); const monitorId = globalEventActions.startMonitor(`drag_${data.eventType}`);
try { try {
const { eventType = data.type, dragId, componentType, sourceElement } = data; const { eventType = data.type, dragId, componentType, sourceElement } = data;
// 从事件数据中提取 dragId如果没有则根据组件类型推断
let actualDragId = dragId;
if (!actualDragId) {
if (data.panelId) {
actualDragId = `panel_${data.panelId}_${data.timestamp || Date.now()}`;
} else if (data.tabIndex !== undefined) {
actualDragId = `tabpage_${data.tabId}_${data.tabIndex}_${data.timestamp || Date.now()}`;
} else if (data.areaId) {
actualDragId = `area_${data.areaId}_${data.timestamp || Date.now()}`;
}
}
// 推断组件类型
let actualComponentType = componentType;
if (!actualComponentType) {
if (data.panelId) {
actualComponentType = 'panel';
} else if (data.tabIndex !== undefined) {
actualComponentType = 'tabpage';
} else if (data.areaId) {
actualComponentType = 'area';
}
}
// 准备标准化的拖拽数据
const dragData = {
...data,
dragId: actualDragId,
componentType: actualComponentType,
sourceElement: sourceElement || data.element
};
switch (eventType) { switch (eventType) {
case 'panel.drag.start': case 'panel.drag.start':
case 'tabpage.drag.start': case 'tabpage.drag.start':
case 'area.drag.start': case 'area.drag.start':
await this._handleDragStart(data); await this._handleDragStart(dragData);
break; break;
case 'panel.drag.move': case 'panel.drag.move':
case 'tabpage.drag.move': case 'tabpage.drag.move':
case 'area.drag.move': case 'area.drag.move':
await this._handleDragMove(data); await this._handleDragMove(dragData);
break; break;
case 'panel.drag.end': case 'panel.drag.end':
case 'tabpage.drag.end': case 'tabpage.drag.end':
case 'area.drag.end': case 'area.drag.end':
await this._handleDragEnd(data); await this._handleDragEnd(dragData);
break; break;
case 'panel.drag.cancel': case 'panel.drag.cancel':
case 'tabpage.drag.cancel': case 'tabpage.drag.cancel':
case 'area.drag.cancel': case 'area.drag.cancel':
await this._handleDragCancel(data); await this._handleDragCancel(dragData);
break; break;
} }
} catch (error) { } catch (error) {
@@ -628,28 +686,31 @@ class DragStateManager {
async _handleDragStart(data) { async _handleDragStart(data) {
const { dragId, componentType, sourceElement, position, options = {} } = data; const { dragId, componentType, sourceElement, position, options = {} } = data;
// 如果没有提供 dragId生成一个唯一的 dragId
const actualDragId = dragId || this._generateDragId(componentType);
// 创建拖拽状态 // 创建拖拽状态
const dragState = new DragState(dragId, componentType, sourceElement, options); const dragState = new DragState(actualDragId, componentType, sourceElement, options);
dragState.startPosition = { ...position }; dragState.startPosition = { ...position };
dragState.currentPosition = { ...position }; dragState.currentPosition = { ...position };
dragState.status = 'active'; dragState.status = 'active';
// 保存拖拽状态 // 保存拖拽状态
this.activeDrags.set(dragId, dragState); this.activeDrags.set(actualDragId, dragState);
// 注册到冲突检测器 // 注册到冲突检测器
this.conflictDetector.registerDrag(dragState); this.conflictDetector.registerDrag(dragState);
// 触发状态变更事件 // 触发状态变更事件,包含 dragId
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, { eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
dragId, dragId: actualDragId,
newStatus: 'active', newStatus: 'active',
dragState: dragState.getSummary() dragState: dragState.getSummary()
}); });
// 发送初始反馈 // 发送初始反馈
if (this.debugMode) { if (this.debugMode) {
this._updateDragFeedback(dragId, { this._updateDragFeedback(actualDragId, {
visible: true, visible: true,
content: `开始拖拽 ${componentType}`, content: `开始拖拽 ${componentType}`,
type: 'default', type: 'default',
@@ -658,8 +719,10 @@ class DragStateManager {
} }
if (this.debugMode) { if (this.debugMode) {
console.log(`🎯 拖拽开始: ${dragId} (${componentType})`, position); console.log(`🎯 拖拽开始: ${actualDragId} (${componentType})`, position);
} }
return actualDragId;
} }
/** /**
@@ -670,7 +733,10 @@ class DragStateManager {
const { dragId, position, targetElement, targetArea } = data; const { dragId, position, targetElement, targetArea } = data;
const dragState = this.activeDrags.get(dragId); const dragState = this.activeDrags.get(dragId);
if (!dragState || dragState.status !== 'active') return; if (!dragState || dragState.status !== 'active') {
console.warn(`⚠️ 未找到活跃的拖拽状态: ${dragId}`);
return;
}
// 更新位置 // 更新位置
dragState.updatePosition(position.x, position.y); dragState.updatePosition(position.x, position.y);
@@ -726,7 +792,10 @@ class DragStateManager {
const { dragId, finalPosition, dropTarget, success = true } = data; const { dragId, finalPosition, dropTarget, success = true } = data;
const dragState = this.activeDrags.get(dragId); const dragState = this.activeDrags.get(dragId);
if (!dragState) return; if (!dragState) {
console.warn(`⚠️ 未找到拖拽状态: ${dragId}`);
return;
}
// 完成拖拽 // 完成拖拽
dragState.complete('completed', { success, finalPosition, dropTarget }); dragState.complete('completed', { success, finalPosition, dropTarget });
@@ -743,7 +812,10 @@ class DragStateManager {
// 从冲突检测器注销 // 从冲突检测器注销
this.conflictDetector.unregisterDrag(dragId); this.conflictDetector.unregisterDrag(dragId);
// 触发状态变更事件 // 清理拖拽目标
this.dragTargets.delete(dragId);
// 触发状态变更事件,包含 dragId
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, { eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
dragId, dragId,
newStatus: 'completed', newStatus: 'completed',
@@ -773,7 +845,10 @@ class DragStateManager {
const { dragId, reason } = data; const { dragId, reason } = data;
const dragState = this.activeDrags.get(dragId); const dragState = this.activeDrags.get(dragId);
if (!dragState) return; if (!dragState) {
console.warn(`⚠️ 未找到拖拽状态: ${dragId}`);
return;
}
// 取消拖拽 // 取消拖拽
dragState.complete('cancelled', { reason }); dragState.complete('cancelled', { reason });
@@ -790,7 +865,10 @@ class DragStateManager {
// 从冲突检测器注销 // 从冲突检测器注销
this.conflictDetector.unregisterDrag(dragId); this.conflictDetector.unregisterDrag(dragId);
// 触发状态变更事件 // 清理拖拽目标
this.dragTargets.delete(dragId);
// 触发状态变更事件,包含 dragId
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, { eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
dragId, dragId,
newStatus: 'cancelled', newStatus: 'cancelled',
@@ -1024,11 +1102,24 @@ class DragStateManager {
* 启动清理调度器 * 启动清理调度器
*/ */
_startCleanupScheduler() { _startCleanupScheduler() {
setInterval(() => { if (this.cleanupScheduler) {
return;
}
this.cleanupScheduler = setInterval(() => {
this._cleanupExpiredData(); this._cleanupExpiredData();
}, 300000); // 每5分钟清理一次 }, 300000); // 每5分钟清理一次
} }
/**
* 停止清理调度器
*/
_stopCleanupScheduler() {
if (this.cleanupScheduler) {
clearInterval(this.cleanupScheduler);
this.cleanupScheduler = null;
}
}
/** /**
* 清理过期数据 * 清理过期数据
*/ */
@@ -1663,26 +1754,6 @@ class DragStateManager {
} }
} }
/**
* 销毁管理器
*/
destroy() {
// 取消所有拖拽
this.cancelAllDrags();
// 清理数据
this.activeDrags.clear();
this.dragHistory = [];
this.dragTargets.clear();
// 清理冲突检测器
this.conflictDetector.activeDrags.clear();
this.conflictDetector.conflictHistory = [];
this.isEnabled = false;
console.log('🗑️ 拖拽状态管理器已销毁');
}
/** /**
* Area拖拽开始 * Area拖拽开始
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
@@ -1878,18 +1949,8 @@ class DragStateManager {
} }
} }
// 延迟创建单例实例 // 立即创建单例实例,避免并发初始化问题
let dragStateManager = null; const dragStateManager = new DragStateManager();
/**
* 确保单例实例存在
*/
function ensureDragStateManagerInstance() {
if (!dragStateManager) {
dragStateManager = new DragStateManager();
}
return dragStateManager;
}
// 便捷操作函数 // 便捷操作函数
export const dragStateActions = { export const dragStateActions = {
@@ -1898,150 +1959,153 @@ export const dragStateActions = {
* @param {string} dragId - 拖拽ID * @param {string} dragId - 拖拽ID
* @returns {Object} 拖拽状态 * @returns {Object} 拖拽状态
*/ */
getDragState: (dragId) => ensureDragStateManagerInstance().getDragState(dragId), getDragState: (dragId) => dragStateManager.getDragState(dragId),
/** /**
* 获取所有活跃拖拽 * 获取所有活跃拖拽
* @returns {Array} 活跃拖拽列表 * @returns {Array} 活跃拖拽列表
*/ */
getActiveDrags: () => ensureDragStateManagerInstance().getActiveDrags(), getActiveDrags: () => dragStateManager.getActiveDrags(),
/** /**
* 获取拖拽历史 * 获取拖拽历史
* @param {number} limit - 限制数量 * @param {number} limit - 限制数量
* @returns {Array} 历史记录 * @returns {Array} 历史记录
*/ */
getHistory: (limit = 100) => ensureDragStateManagerInstance().getDragHistory(limit), getHistory: (limit = 100) => dragStateManager.getDragHistory(limit),
/** /**
* 获取统计信息 * 获取统计信息
* @returns {Object} 统计信息 * @returns {Object} 统计信息
*/ */
getStats: () => ensureDragStateManagerInstance().getDragStats(), getStats: () => dragStateManager.getDragStats(),
/** /**
* 设置调试模式 * 设置调试模式
* @param {boolean} enabled - 是否启用 * @param {boolean} enabled - 是否启用
*/ */
setDebugMode: (enabled) => ensureDragStateManagerInstance().setDebugMode(enabled), setDebugMode: (enabled) => dragStateManager.setDebugMode(enabled),
/** /**
* 启用/禁用管理器 * 启用/禁用管理器
* @param {boolean} enabled - 是否启用 * @param {boolean} enabled - 是否启用
*/ */
setEnabled: (enabled) => ensureDragStateManagerInstance().setEnabled(enabled), setEnabled: (enabled) => dragStateManager.setEnabled(enabled),
/** /**
* 取消所有拖拽 * 取消所有拖拽
*/ */
cancelAll: () => ensureDragStateManagerInstance().cancelAllDrags(), cancelAll: () => dragStateManager.cancelAllDrags(),
/** /**
* 面板拖拽开始 * 面板拖拽开始
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID * @returns {string} 拖拽ID
*/ */
onPanelDragStart: (eventData) => ensureDragStateManagerInstance().onPanelDragStart(eventData), onPanelDragStart: (eventData) => dragStateManager.onPanelDragStart(eventData),
/** /**
* 面板拖拽移动 * 面板拖拽移动
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onPanelDragMove: (eventData) => ensureDragStateManagerInstance().onPanelDragMove(eventData), onPanelDragMove: (eventData) => dragStateManager.onPanelDragMove(eventData),
/** /**
* 面板拖拽结束 * 面板拖拽结束
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onPanelDragEnd: (eventData) => ensureDragStateManagerInstance().onPanelDragEnd(eventData), onPanelDragEnd: (eventData) => dragStateManager.onPanelDragEnd(eventData),
/** /**
* TabPage拖拽开始 * TabPage拖拽开始
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID * @returns {string} 拖拽ID
*/ */
onPanelDragStartFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragStartFromTabPage(eventData), onPanelDragStartFromTabPage: (eventData) => dragStateManager.onPanelDragStartFromTabPage(eventData),
/** /**
* TabPage拖拽移动 * TabPage拖拽移动
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onPanelDragMoveFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragMoveFromTabPage(eventData), onPanelDragMoveFromTabPage: (eventData) => dragStateManager.onPanelDragMoveFromTabPage(eventData),
/** /**
* TabPage拖拽结束 * TabPage拖拽结束
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onPanelDragEndFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragEndFromTabPage(eventData), onPanelDragEndFromTabPage: (eventData) => dragStateManager.onPanelDragEndFromTabPage(eventData),
/** /**
* Area拖拽开始 * Area拖拽开始
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID * @returns {string} 拖拽ID
*/ */
onAreaDragStart: (eventData) => ensureDragStateManagerInstance().onAreaDragStart(eventData), onAreaDragStart: (eventData) => dragStateManager.onAreaDragStart(eventData),
/** /**
* Area拖拽移动 * Area拖拽移动
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onAreaDragMove: (eventData) => ensureDragStateManagerInstance().onAreaDragMove(eventData), onAreaDragMove: (eventData) => dragStateManager.onAreaDragMove(eventData),
/** /**
* Area拖拽结束 * Area拖拽结束
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onAreaDragEnd: (eventData) => ensureDragStateManagerInstance().onAreaDragEnd(eventData), onAreaDragEnd: (eventData) => dragStateManager.onAreaDragEnd(eventData),
/** /**
* Tab拖拽开始 * Tab拖拽开始
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {string} 拖拽ID * @returns {string} 拖拽ID
*/ */
onTabDragStart: (eventData) => ensureDragStateManagerInstance().onPanelDragStartFromTabPage(eventData), onTabDragStart: (eventData) => dragStateManager.onPanelDragStartFromTabPage(eventData),
/** /**
* Tab拖拽移动 * Tab拖拽移动
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onTabDragMove: (eventData) => ensureDragStateManagerInstance().onPanelDragMoveFromTabPage(eventData), onTabDragMove: (eventData) => dragStateManager.onPanelDragMoveFromTabPage(eventData),
/** /**
* Tab拖拽结束 * Tab拖拽结束
* @param {Object} eventData - 拖拽事件数据 * @param {Object} eventData - 拖拽事件数据
* @returns {boolean} 是否成功 * @returns {boolean} 是否成功
*/ */
onTabDragEnd: (eventData) => ensureDragStateManagerInstance().onPanelDragEndFromTabPage(eventData), onTabDragEnd: (eventData) => dragStateManager.onPanelDragEndFromTabPage(eventData),
/** /**
* 初始化拖拽管理器 * 初始化拖拽管理器
*/ */
initialize: () => ensureDragStateManagerInstance(), initialize: () => dragStateManager,
/** /**
* 销毁拖拽管理器 * 销毁拖拽管理器
*/ */
destroy: () => { destroy: () => {
if (dragStateManager) { if (dragStateManager) {
// 清理拖拽管理器资源 // 清理拖拽管理器资源先调用实例的destroy方法清理监听器
dragStateManager.activeDrags.clear(); try {
dragStateManager.dragHistory = []; dragStateManager.destroy();
} catch (e) {
console.warn('销毁拖拽状态管理器时出错:', e);
}
dragStateManager = null; dragStateManager = null;
console.log('🗑️ 拖拽状态管理器已销毁,所有资源已清理'); console.log('🗑️ 拖拽状态管理器已销毁');
} }
} }
}; };
// 导出 // 导出
export default { export default {
getInstance: ensureDragStateManagerInstance, getInstance: () => dragStateManager,
actions: dragStateActions actions: dragStateActions
}; };
export { DragState }; export { DragState };

View File

@@ -140,10 +140,10 @@ class EventBusManager {
{ name: 'tabpage', handler: tabPageHandler, events: TABPAGE_EVENT_TYPES }, { name: 'tabpage', handler: tabPageHandler, events: TABPAGE_EVENT_TYPES },
{ name: 'area', handler: areaHandler, events: AREA_EVENT_TYPES }, { name: 'area', handler: areaHandler, events: AREA_EVENT_TYPES },
{ name: 'global', handler: globalEventManager, events: GLOBAL_EVENT_TYPES }, { name: 'global', handler: globalEventManager, events: GLOBAL_EVENT_TYPES },
{ name: 'drag', handler: dragStateManager, events: DRAG_STATE_TYPES } { name: 'drag', handler: dragStateManager.getInstance(), events: DRAG_STATE_TYPES, skipEventRegistration: true }
]; ];
for (const { name, handler, events } of handlers) { for (const { name, handler, events, skipEventRegistration = false } of handlers) {
const handlerConfig = this.config.handlers[name]; const handlerConfig = this.config.handlers[name];
if (!handlerConfig?.enabled) { if (!handlerConfig?.enabled) {
@@ -154,15 +154,20 @@ class EventBusManager {
try { try {
console.log(`📝 注册事件处理器: ${name}`); console.log(`📝 注册事件处理器: ${name}`);
// 注册事件处理器到事件总线 // 注册事件处理器到事件总线(除非跳过)
Object.values(events).forEach(eventType => { if (!skipEventRegistration) {
if (typeof handler.handleEvent === 'function') { Object.values(events).forEach(eventType => {
eventBus.on(eventType, handler.handleEvent.bind(handler), { if (typeof handler.handleEvent === 'function') {
priority: 1, eventBus.on(eventType, handler.handleEvent.bind(handler), {
id: `handler-${name}` priority: 1,
}); id: `handler-${name}`,
} componentId: `handler-${name}`
}); });
}
});
} else {
console.log(`⏭️ 跳过事件监听器注册(内部自动注册): ${name}`);
}
// 调用初始化方法(如果存在) // 调用初始化方法(如果存在)
if (typeof handler.initialize === 'function') { if (typeof handler.initialize === 'function') {
@@ -236,7 +241,7 @@ class EventBusManager {
routeTime: Date.now() routeTime: Date.now()
}); });
}); });
}, { id: 'router', priority: 0 }); }, { id: 'router', priority: 0, componentId: 'event-router' });
}); });
console.log(`🔗 设置了 ${routes.length} 个事件路由`); console.log(`🔗 设置了 ${routes.length} 个事件路由`);

View File

@@ -4,13 +4,6 @@
*/ */
import { eventBus } from '../eventBus'; import { eventBus } from '../eventBus';
import { PANEL_EVENT_TYPES, panelActions, panelHandler } from './PanelHandler';
import tabPageHandlerModule, { TABPAGE_EVENT_TYPES, tabPageActions } from './TabPageHandler';
import areaHandlerModule, { AREA_EVENT_TYPES, areaActions } from './AreaHandler';
// 获取处理器实例
const tabPageHandler = tabPageHandlerModule.getInstance ? tabPageHandlerModule.getInstance() : tabPageHandlerModule;
const areaHandler = areaHandlerModule;
// 全局事件类型常量 // 全局事件类型常量
export const GLOBAL_EVENT_TYPES = { export const GLOBAL_EVENT_TYPES = {
@@ -50,59 +43,7 @@ export const GLOBAL_EVENT_TYPES = {
DEBUG_MEMORY: 'debug.memory' DEBUG_MEMORY: 'debug.memory'
}; };
// 事件路由配置 // 事件路由配置将在构造函数中动态创建
const EVENT_ROUTES = {
// Panel事件路由
[PANEL_EVENT_TYPES.PANEL_DRAG_START]: {
handlers: ['panelHandler', 'areaHandler'],
priority: 1,
timeout: 5000
},
[PANEL_EVENT_TYPES.PANEL_MAXIMIZE]: {
handlers: ['panelHandler', 'areaHandler'],
priority: 1,
timeout: 3000
},
[PANEL_EVENT_TYPES.PANEL_CLOSE_REQUEST]: {
handlers: ['panelHandler', 'tabPageHandler'],
priority: 2,
timeout: 5000
},
// TabPage事件路由
[TABPAGE_EVENT_TYPES.TABPAGE_DRAG_START]: {
handlers: ['tabPageHandler', 'areaHandler'],
priority: 1,
timeout: 5000
},
[TABPAGE_EVENT_TYPES.TABPAGE_SWITCH]: {
handlers: ['tabPageHandler', 'panelHandler'],
priority: 2,
timeout: 3000
},
[TABPAGE_EVENT_TYPES.TABPAGE_CLOSE_REQUEST]: {
handlers: ['tabPageHandler', 'panelHandler'],
priority: 2,
timeout: 5000
},
// Area事件路由
[AREA_EVENT_TYPES.AREA_DRAG_START]: {
handlers: ['areaHandler', 'tabPageHandler'],
priority: 1,
timeout: 5000
},
[AREA_EVENT_TYPES.AREA_MERGE]: {
handlers: ['areaHandler', 'tabPageHandler', 'panelHandler'],
priority: 1,
timeout: 10000
},
[AREA_EVENT_TYPES.AREA_DOCK_CENTER]: {
handlers: ['areaHandler', 'tabPageHandler'],
priority: 1,
timeout: 8000
}
};
// 事件执行监控 // 事件执行监控
class EventExecutionMonitor { class EventExecutionMonitor {
@@ -297,31 +238,26 @@ class GlobalEventManager {
static instance = null; static instance = null;
constructor() { constructor() {
// 单例模式实现:如果已经有实例,直接返回现有实例
if (GlobalEventManager.instance) { if (GlobalEventManager.instance) {
return GlobalEventManager.instance; return GlobalEventManager.instance;
} }
this.eventHandlers = new Map(); this.eventHandlers = new Map();
this.eventRoutes = new Map(Object.entries(EVENT_ROUTES)); this.eventRoutes = new Map();
this.executionMonitor = new EventExecutionMonitor(); this.executionMonitor = new EventExecutionMonitor();
this.eventChains = new Map(); this.eventChains = new Map();
this.crossComponentChannels = new Map(); this.crossComponentChannels = new Map();
this.isInitialized = false; this.isInitialized = false;
this.isDestroyed = false;
this.eventListenersRegistered = false; this.eventListenersRegistered = false;
this.componentListenersRegistered = false; this.componentListenersRegistered = false;
this.debugMode = false; this.debugMode = false;
this.handlerMap = {};
this.eventListenerUnsubscribers = []; this.eventListenerUnsubscribers = [];
// 绑定方法
this._onGlobalEvent = this._onGlobalEvent.bind(this); this._onGlobalEvent = this._onGlobalEvent.bind(this);
this._onSystemError = this._handleSystemError.bind(this); this._onSystemError = this._handleSystemError.bind(this);
this._cleanupExpiredData = this._cleanupExpiredData.bind(this); this._cleanupExpiredData = this._cleanupExpiredData.bind(this);
// 延迟初始化先不调用_initialize()
// 保存实例到静态属性
GlobalEventManager.instance = this; GlobalEventManager.instance = this;
} }
@@ -329,41 +265,29 @@ class GlobalEventManager {
* 初始化事件管理器 * 初始化事件管理器
*/ */
async _initialize() { async _initialize() {
// 防止重复初始化
if (this.isInitialized) { if (this.isInitialized) {
console.warn('⚠️ 全局事件管理器已初始化,跳过重复初始化'); console.warn('⚠️ 全局事件管理器已初始化,跳过重复初始化');
return; return;
} }
// 初始化处理器映射 this.eventRoutes = new Map();
this.handlerMap = {
panelHandler,
tabPageHandler,
areaHandler
};
// 注册全局事件监听器
this._registerGlobalEventListeners(); this._registerGlobalEventListeners();
// 启动定期清理
this._startCleanupScheduler(); this._startCleanupScheduler();
// 启动调试模式监听
this._startDebugMode(); this._startDebugMode();
this.isInitialized = true; this.isInitialized = true;
console.log('✅ 全局事件管理器初始化完成'); console.log('✅ 全局事件管理器初始化完成');
// 触发系统就绪事件
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_READY, { eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_READY, {
manager: 'globalEventManager', manager: 'globalEventManager',
timestamp: Date.now(), timestamp: Date.now()
handlers: Object.keys(this.handlerMap)
}); });
} }
/** /**
* 注册全局事件监听器 * 注册全局事件监听器
* 添加初始化锁防止并发场景下的重复注册
*/ */
_registerGlobalEventListeners() { _registerGlobalEventListeners() {
// 检查是否已经注册过事件监听器 // 检查是否已经注册过事件监听器
@@ -372,236 +296,46 @@ class GlobalEventManager {
return; return;
} }
const globalEvents = Object.values(GLOBAL_EVENT_TYPES); // 先标记为正在注册,防止并发
globalEvents.forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._onGlobalEvent, {
priority: 0, // 最高优先级
deduplication: { type: 'TTL_BASED', ttl: 50 }
});
this.eventListenerUnsubscribers.push(unsubscribe);
});
// 注册所有组件事件监听器
this._registerComponentEventListeners();
// 标记为已注册
this.eventListenersRegistered = true; this.eventListenersRegistered = true;
}
/**
* 注册组件事件监听器
*/
_registerComponentEventListeners() {
// 防止重复注册组件事件监听器
if (this.componentListenersRegistered) {
return;
}
// Panel事件监听
Object.values(PANEL_EVENT_TYPES).forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._routeEvent.bind(this, eventType, null, 'panel'), { priority: 1 });
this.eventListenerUnsubscribers.push(unsubscribe);
});
// TabPage事件监听
Object.values(TABPAGE_EVENT_TYPES).forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._routeEvent.bind(this, eventType, null, 'tabPage'), { priority: 1 });
this.eventListenerUnsubscribers.push(unsubscribe);
});
// Area事件监听
Object.values(AREA_EVENT_TYPES).forEach(eventType => {
const unsubscribe = eventBus.on(eventType, this._routeEvent.bind(this, eventType, null, 'area'), { priority: 1 });
this.eventListenerUnsubscribers.push(unsubscribe);
});
this.componentListenersRegistered = true;
}
/**
* 路由事件到相应的处理器
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {string} source - 事件源
*/
async _routeEvent(eventType, eventData, source) {
const eventId = `${eventType}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const routeConfig = this.eventRoutes.get(eventType);
// 开始监控
this.executionMonitor.startMonitoring(eventId, { ...eventData, eventType });
eventBus.emit(GLOBAL_EVENT_TYPES.EVENT_ROUTE_START, {
eventId,
eventType,
source,
routeConfig
});
try { try {
if (routeConfig) { const globalEvents = Object.values(GLOBAL_EVENT_TYPES);
// 使用配置的路由 globalEvents.forEach(eventType => {
await this._executeRoutedHandlers(eventId, eventType, eventData, routeConfig); const unsubscribe = eventBus.on(eventType, this._onGlobalEvent, {
} else { priority: 0, // 最高优先级
// 默认路由到相应组件处理器 deduplication: { type: 'TTL_BASED', ttl: 50 },
await this._executeDefaultHandler(eventId, eventType, eventData, source); componentId: 'global-event-manager'
} });
this.eventListenerUnsubscribers.push(unsubscribe);
// 完成监控
this.executionMonitor.completeMonitoring(eventId);
eventBus.emit(GLOBAL_EVENT_TYPES.EVENT_ROUTE_SUCCESS, {
eventId,
eventType,
source,
timestamp: Date.now()
}); });
// 注册所有组件事件监听器
this._registerComponentEventListeners();
} catch (error) { } catch (error) {
// 记录错误 // 如果注册失败,重置标志位
this.executionMonitor.recordError(eventId, error); this.eventListenersRegistered = false;
eventBus.emit(GLOBAL_EVENT_TYPES.EVENT_ROUTE_ERROR, {
eventId,
eventType,
source,
error: error.message,
timestamp: Date.now()
});
// 触发系统错误事件
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_ERROR, {
eventId,
eventType,
source,
error,
timestamp: Date.now()
});
}
}
/**
* 执行路由的处理器
* @param {string} eventId - 事件ID
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {Object} routeConfig - 路由配置
*/
async _executeRoutedHandlers(eventId, eventType, eventData, routeConfig) {
const { handlers, priority, timeout = 5000 } = routeConfig;
const handlerPromises = handlers.map(async (handlerName) => {
const startTime = Date.now();
this.executionMonitor.recordHandlerStart(eventId, handlerName);
try {
const handler = this.handlerMap[handlerName];
if (!handler) {
throw new Error(`Handler ${handlerName} not found`);
}
// 执行处理器
const result = await this._executeHandlerWithTimeout(
handler,
eventType,
eventData,
timeout
);
const duration = Date.now() - startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, true, duration);
return { handlerName, result, duration };
} catch (error) {
const duration = Date.now() - startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, false, duration, error);
throw error;
}
});
// 等待所有处理器完成
const results = await Promise.allSettled(handlerPromises);
// 检查是否有失败的处理器
const failures = results.filter(result => result.status === 'rejected');
if (failures.length > 0) {
throw new Error(`Handler execution failed: ${failures.map(f => f.reason.message).join(', ')}`);
}
return results.map(result => result.value);
}
/**
* 执行默认处理器
* @param {string} eventId - 事件ID
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {string} source - 事件源
*/
async _executeDefaultHandler(eventId, eventType, eventData, source) {
const handlerName = `${source}Handler`;
const handler = this.handlerMap[handlerName];
if (!handler) {
throw new Error(`Default handler ${handlerName} not found`);
}
this.executionMonitor.recordHandlerStart(eventId, handlerName);
try {
const result = await this._executeHandlerWithTimeout(handler, eventType, eventData, 5000);
const duration = Date.now() - this.executionMonitor.getExecutionDetail(eventId).startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, true, duration);
return result;
} catch (error) {
const duration = Date.now() - this.executionMonitor.getExecutionDetail(eventId).startTime;
this.executionMonitor.recordHandlerComplete(eventId, handlerName, false, duration, error);
throw error; throw error;
} }
} }
/** /**
* 带超时的处理器执行 * 注册组件事件监听器
* @param {Object} handler - 处理器对象 * 添加初始化锁防止并发场景下的重复注册
* @param {string} eventType - 事件类型
* @param {Object} eventData - 事件数据
* @param {number} timeout - 超时时间
* @returns {Promise} 执行结果
*/ */
async _executeHandlerWithTimeout(handler, eventType, eventData, timeout) { _registerComponentEventListeners() {
return new Promise((resolve, reject) => { if (this.componentListenersRegistered) {
const timer = setTimeout(() => { console.warn('⚠️ 组件事件监听器已经注册,跳过重复注册');
reject(new Error(`Handler execution timeout after ${timeout}ms`)); return;
}, timeout); }
try { this.componentListenersRegistered = true;
// 假设处理器有处理事件的方法
if (typeof handler._onEvent === 'function') { console.log('✅ 组件事件监听器注册完成Handler自行订阅事件');
const result = handler._onEvent({ eventType, ...eventData });
if (result instanceof Promise) {
result.then(resolve).catch(reject).finally(() => clearTimeout(timer));
} else {
resolve(result);
clearTimeout(timer);
}
} else {
// 如果处理器没有_onEvent方法直接解析
resolve(true);
clearTimeout(timer);
}
} catch (error) {
reject(error);
clearTimeout(timer);
}
});
} }
/**
* 处理全局事件
* @param {Object} data - 事件数据
*/
async _onGlobalEvent(data) { async _onGlobalEvent(data) {
const { eventType } = data; const eventType = data.eventType;
try { try {
switch (eventType) { switch (eventType) {
@@ -634,18 +368,8 @@ class GlobalEventManager {
async _handleSystemInit(data) { async _handleSystemInit(data) {
console.log('🚀 系统初始化开始...', data); console.log('🚀 系统初始化开始...', data);
// 检查所有处理器是否就绪
const handlersStatus = {};
for (const [name, handler] of Object.entries(this.handlerMap)) {
handlersStatus[name] = {
ready: typeof handler === 'object',
methods: Object.getOwnPropertyNames(Object.getPrototypeOf(handler))
};
}
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_READY, { eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_READY, {
manager: 'globalEventManager', manager: 'globalEventManager',
handlersStatus,
timestamp: Date.now() timestamp: Date.now()
}); });
} }
@@ -714,37 +438,13 @@ class GlobalEventManager {
async _handleCrossComponentRequest(data) { async _handleCrossComponentRequest(data) {
const { requestId, targetComponent, action, payload } = data; const { requestId, targetComponent, action, payload } = data;
try { // 通过事件总线转发跨组件请求
// 查找目标组件的处理 // 目标Handler应该监听这个事件并处理
const handler = this.handlerMap[`${targetComponent}Handler`]; eventBus.emit(`${targetComponent}.${action}`, {
if (!handler) { requestId,
throw new Error(`Target component handler ${targetComponent}Handler not found`); payload,
} isCrossComponent: true
});
// 执行请求
const result = await handler[action](payload);
// 发送响应
eventBus.emit(GLOBAL_EVENT_TYPES.CROSS_COMPONENT_RESPONSE, {
requestId,
targetComponent,
action,
result,
success: true,
timestamp: Date.now()
});
} catch (error) {
// 发送错误响应
eventBus.emit(GLOBAL_EVENT_TYPES.CROSS_COMPONENT_RESPONSE, {
requestId,
targetComponent,
action,
error: error.message,
success: false,
timestamp: Date.now()
});
}
} }
/** /**
@@ -1032,41 +732,52 @@ class GlobalEventManager {
/** /**
* 销毁事件管理器 * 销毁事件管理器
* 添加销毁锁防止重复销毁,确保正确清理所有监听器
*/ */
destroy() { destroy() {
// 清理自己注册的所有事件监听器 if (this.isDestroyed) {
this.eventListenerUnsubscribers.forEach(unsubscribe => { console.warn('⚠️ 全局事件管理器已经被销毁,跳过重复销毁');
try { return;
unsubscribe(); }
} catch (error) {
console.warn('清理监听器时出错:', error);
}
});
this.eventListenerUnsubscribers = [];
// 销毁各个处理器 this.isDestroyed = true;
Object.values(this.handlerMap).forEach(handler => {
if (typeof handler.destroy === 'function') { // 清理自己注册的所有事件监听器
handler.destroy(); if (this.eventListenerUnsubscribers.length > 0) {
} this.eventListenerUnsubscribers.forEach(unsubscribe => {
}); try {
if (typeof unsubscribe === 'function') {
unsubscribe();
}
} catch (error) {
console.warn('清理监听器时出错:', error);
}
});
this.eventListenerUnsubscribers = [];
}
// 清理数据 // 清理数据
this.eventHandlers.clear(); if (this.eventHandlers) this.eventHandlers.clear();
this.eventChains.clear(); if (this.eventChains) this.eventChains.clear();
this.crossComponentChannels.clear(); if (this.crossComponentChannels) this.crossComponentChannels.clear();
this.handlerMap = {}; if (this.eventRoutes) this.eventRoutes.clear();
this.eventRoutes.clear();
// 清理执行监控器
if (this.executionMonitor) {
this.executionMonitor.cleanup();
}
// 重置状态标志
this.isInitialized = false; this.isInitialized = false;
this.eventListenersRegistered = false; this.eventListenersRegistered = false;
this.componentListenersRegistered = false; this.componentListenersRegistered = false;
console.log('🗑️ 全局事件管理器已销毁,所有监听器已清理'); console.log('🗑️ 全局事件管理器已销毁,所有监听器已清理');
} }
} }
// 延迟创建单例实例 // 立即创建单例实例,避免并发初始化问题
let globalEventManager = null; const globalEventManager = new GlobalEventManager();
// 全局便捷API // 全局便捷API
export const globalEventActions = { export const globalEventActions = {
@@ -1076,7 +787,6 @@ export const globalEventActions = {
* @returns {string} 监控ID * @returns {string} 监控ID
*/ */
startMonitor: (operation) => { startMonitor: (operation) => {
ensureInstance();
return globalEventManager.startPerformanceMonitor(operation); return globalEventManager.startPerformanceMonitor(operation);
}, },
@@ -1086,7 +796,6 @@ export const globalEventActions = {
* @param {Object} metadata - 元数据 * @param {Object} metadata - 元数据
*/ */
endMonitor: (monitorId, metadata = {}) => { endMonitor: (monitorId, metadata = {}) => {
ensureInstance();
globalEventManager.endPerformanceMonitor(monitorId, metadata); globalEventManager.endPerformanceMonitor(monitorId, metadata);
}, },
@@ -1097,7 +806,6 @@ export const globalEventActions = {
* @returns {string} 链ID * @returns {string} 链ID
*/ */
createChain: (chainName, events) => { createChain: (chainName, events) => {
ensureInstance();
return globalEventManager.createEventChain(chainName, events); return globalEventManager.createEventChain(chainName, events);
}, },
@@ -1108,7 +816,6 @@ export const globalEventActions = {
* @param {Array} targets - 目标组件 * @param {Array} targets - 目标组件
*/ */
broadcast: (message, data = {}, targets = null) => { broadcast: (message, data = {}, targets = null) => {
ensureInstance();
globalEventManager.broadcast(message, data, targets); globalEventManager.broadcast(message, data, targets);
}, },
@@ -1120,7 +827,6 @@ export const globalEventActions = {
* @returns {Promise} 响应 * @returns {Promise} 响应
*/ */
request: (component, action, payload) => { request: (component, action, payload) => {
ensureInstance();
return globalEventManager.request(component, action, payload); return globalEventManager.request(component, action, payload);
}, },
@@ -1136,7 +842,6 @@ export const globalEventActions = {
* @returns {Object} 统计信息 * @returns {Object} 统计信息
*/ */
getStats: () => { getStats: () => {
ensureInstance();
return globalEventManager.getExecutionStats(); return globalEventManager.getExecutionStats();
}, },
@@ -1145,7 +850,6 @@ export const globalEventActions = {
* @returns {Array} 链状态 * @returns {Array} 链状态
*/ */
getChainStatus: () => { getChainStatus: () => {
ensureInstance();
return globalEventManager.getEventChainStatus(); return globalEventManager.getEventChainStatus();
}, },
@@ -1153,7 +857,7 @@ export const globalEventActions = {
* 初始化事件管理器 * 初始化事件管理器
*/ */
initialize: () => { initialize: () => {
ensureInstance(); return globalEventManager;
}, },
/** /**
@@ -1162,31 +866,15 @@ export const globalEventActions = {
destroy: () => { destroy: () => {
if (globalEventManager) { if (globalEventManager) {
globalEventManager.destroy(); globalEventManager.destroy();
globalEventManager = null;
} }
} }
}; };
/**
* 确保单例实例存在
*/
async function ensureInstance() {
if (!globalEventManager) {
globalEventManager = new GlobalEventManager();
// 异步初始化
await globalEventManager._initialize();
} else if (!globalEventManager.isInitialized) {
// 如果实例存在但未初始化,完成初始化
await globalEventManager._initialize();
}
return globalEventManager;
}
// 导出单例实例访问方法 // 导出单例实例访问方法
export const getGlobalEventManager = ensureInstance; export const getGlobalEventManager = () => globalEventManager;
// 导出事件管理器和相关API // 导出事件管理器和相关API
export default { export default {
getInstance: getGlobalEventManager, getInstance: () => globalEventManager,
actions: globalEventActions actions: globalEventActions
}; };

View File

@@ -1,5 +1,5 @@
import { emitEvent, onEvent, onceEvent, registerHandler, unregisterHandler, getHandlerSnapshot } from '../eventBus'
import { nanoid } from 'nanoid' import { nanoid } from 'nanoid'
import { emitEvent, onEvent, onceEvent, registerHandler, unregisterHandler, getHandlerSnapshot } from '../eventBus'
// Panel事件类型常量 // Panel事件类型常量
export const PANEL_EVENT_TYPES = { export const PANEL_EVENT_TYPES = {
@@ -151,9 +151,11 @@ class PanelEventHandler {
// 触发最大化事件false表示还原 // 触发最大化事件false表示还原
await emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, { await emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
panelId, panelId,
maximized: false, maximized: false
source: 'PanelHandler' }, {
}, { priority }) priority,
source: { component: 'PanelHandler', panelId }
})
// 如果需要同步到Area // 如果需要同步到Area
if (syncToArea) { if (syncToArea) {
@@ -171,10 +173,12 @@ class PanelEventHandler {
*/ */
requestClose(eventData) { requestClose(eventData) {
const { areaId, panelId } = eventData; const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.CLOSE_REQUEST, { emitEvent(PANEL_EVENT_TYPES.CLOSE_REQUEST, {
areaId, areaId,
panelId, panelId,
timestamp: Date.now() timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
}); });
} }
@@ -231,9 +235,11 @@ class PanelEventHandler {
return emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, { return emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
panelId, panelId,
toolbarExpanded: panelState.toolbarExpanded, toolbarExpanded: panelState.toolbarExpanded
source: 'PanelHandler' }, {
}, { priority }) priority,
source: { component: 'PanelHandler', panelId }
})
} }
/** /**
@@ -261,9 +267,11 @@ class PanelEventHandler {
return emitEvent(PANEL_EVENT_TYPES.DRAG_START, { return emitEvent(PANEL_EVENT_TYPES.DRAG_START, {
panelId, panelId,
event: dragEvent, event: dragEvent,
dragState, dragState
source: 'PanelHandler' }, {
}, { priority }) priority,
source: { component: 'PanelHandler', panelId }
})
} }
/** /**
@@ -325,9 +333,11 @@ class PanelEventHandler {
panelId, panelId,
event: dragEvent, event: dragEvent,
dragState, dragState,
duration: dragState.endTime - dragState.startTime, duration: dragState.endTime - dragState.startTime
source: 'PanelHandler' }, {
}, { priority }) priority,
source: { component: 'PanelHandler', panelId }
})
// 清理拖拽状态 // 清理拖拽状态
this.dragStates.delete(panelId) this.dragStates.delete(panelId)
@@ -353,10 +363,11 @@ class PanelEventHandler {
this.panelStates.set(panelId, panelState) this.panelStates.set(panelId, panelState)
return emitEvent(PANEL_EVENT_TYPES.ACTIVATED, { return emitEvent(PANEL_EVENT_TYPES.ACTIVATED, {
panelId, panelId
source: 'PanelHandler', }, {
timestamp: Date.now() priority,
}, { priority }) source: { component: 'PanelHandler', panelId }
})
} }
/** /**
@@ -377,10 +388,11 @@ class PanelEventHandler {
this.panelStates.set(panelId, panelState) this.panelStates.set(panelId, panelState)
return emitEvent(PANEL_EVENT_TYPES.DEACTIVATED, { return emitEvent(PANEL_EVENT_TYPES.DEACTIVATED, {
panelId, panelId
source: 'PanelHandler', }, {
timestamp: Date.now() priority,
}, { priority }) source: { component: 'PanelHandler', panelId }
})
} }
/** /**
@@ -441,10 +453,12 @@ class PanelEventHandler {
*/ */
onExpand(eventData) { onExpand(eventData) {
const { areaId, panelId } = eventData; const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.EXPAND, { emitEvent(PANEL_EVENT_TYPES.EXPAND, {
areaId, areaId,
panelId, panelId,
timestamp: Date.now() timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
}); });
} }
@@ -454,10 +468,12 @@ class PanelEventHandler {
*/ */
onMaximize(eventData) { onMaximize(eventData) {
const { areaId, panelId } = eventData; const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, { emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
areaId, areaId,
panelId, panelId,
timestamp: Date.now() timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
}); });
} }
@@ -480,10 +496,12 @@ class PanelEventHandler {
*/ */
onToggleToolbar(eventData) { onToggleToolbar(eventData) {
const { areaId, panelId } = eventData; const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, { emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
areaId, areaId,
panelId, panelId,
timestamp: Date.now() timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
}); });
} }
@@ -507,11 +525,13 @@ class PanelEventHandler {
*/ */
onSizeUpdate(eventData) { onSizeUpdate(eventData) {
const { areaId, panelId, size } = eventData; const { areaId, panelId, size } = eventData;
this.emitEvent('panel.size.update', { emitEvent('panel.size.update', {
areaId, areaId,
panelId, panelId,
size, size,
timestamp: Date.now() timestamp: Date.now()
}, {
source: { component: 'PanelHandler', panelId, areaId }
}); });
} }
@@ -567,8 +587,9 @@ class PanelEventHandler {
return emitEvent(PANEL_EVENT_TYPES.MAXIMIZE_SYNC, { return emitEvent(PANEL_EVENT_TYPES.MAXIMIZE_SYNC, {
panelId, panelId,
maximized, maximized,
areaId: panelState.areaId, areaId: panelState.areaId
source: 'PanelHandler' }, {
source: { component: 'PanelHandler', panelId, areaId: panelState.areaId }
}) })
} }

View File

@@ -188,7 +188,7 @@ class TabPageEventHandler {
* @param {string} data.eventType - 事件类型 * @param {string} data.eventType - 事件类型
*/ */
async _onTabPageEvent(data) { async _onTabPageEvent(data) {
const { eventType } = data; const eventType = data.eventType;
try { try {
switch (eventType) { switch (eventType) {
@@ -222,7 +222,6 @@ class TabPageEventHandler {
} }
} catch (error) { } catch (error) {
console.error(`❌ TabPage事件处理错误 (${eventType}):`, error); console.error(`❌ TabPage事件处理错误 (${eventType}):`, error);
eventBus.recordError(`tabPageHandler_${eventType}`, error);
} }
} }
@@ -591,6 +590,9 @@ function ensureInstance() {
return tabPageHandler; return tabPageHandler;
} }
// 导出单例实例访问方法
export const getTabPageHandler = ensureInstance;
// TabPage便捷操作函数 // TabPage便捷操作函数
export const tabPageActions = { export const tabPageActions = {
/** /**