解决事件泄漏问题
This commit is contained in:
@@ -180,6 +180,7 @@ const areaRef = ref(null)
|
||||
const isDragging = ref(false)
|
||||
const dragStartPos = ref({ x: 0, y: 0 })
|
||||
const areaStartPos = ref({ x: 0, y: 0 })
|
||||
const currentDragId = ref(null)
|
||||
|
||||
// 调整大小相关状态
|
||||
const isResizing = ref(false)
|
||||
@@ -278,18 +279,24 @@ const onPanelMaximize = (panelId) => {
|
||||
} else {
|
||||
// // console.log('🔸 非单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) => {
|
||||
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) => {
|
||||
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
|
||||
}
|
||||
|
||||
// 使用事件总线通知拖拽开始
|
||||
// 生成统一的 dragId
|
||||
currentDragId.value = `area_${props.id}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
|
||||
|
||||
// 使用事件总线通知拖拽开始,包含 dragId 和标准化数据格式
|
||||
emitEvent(EVENT_TYPES.AREA_DRAG_START, {
|
||||
dragId: currentDragId.value,
|
||||
areaId: props.id,
|
||||
event: e,
|
||||
element: areaRef.value,
|
||||
@@ -316,7 +327,10 @@ const onDragStart = (e) => {
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
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) => {
|
||||
if (!isDragging.value) return
|
||||
if (!isDragging.value || !currentDragId.value) return
|
||||
|
||||
// 计算移动距离
|
||||
const deltaX = e.clientX - dragStartPos.value.x
|
||||
@@ -354,8 +368,9 @@ const onDragMove = (e) => {
|
||||
originalPosition.value.left = newLeft
|
||||
originalPosition.value.top = newTop
|
||||
|
||||
// 使用事件总线通知拖拽移动
|
||||
// 使用事件总线通知拖拽移动,包含 dragId
|
||||
emitEvent(EVENT_TYPES.AREA_DRAG_MOVE, {
|
||||
dragId: currentDragId.value,
|
||||
areaId: props.id,
|
||||
event: e,
|
||||
element: areaRef.value,
|
||||
@@ -363,27 +378,44 @@ const onDragMove = (e) => {
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
left: newLeft,
|
||||
top: newTop
|
||||
top: newTop,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id, dragId: currentDragId.value }
|
||||
})
|
||||
|
||||
// 使用事件总线通知位置变化
|
||||
emitEvent(EVENT_TYPES.AREA_POSITION_UPDATE, { areaId: props.id, left: newLeft, top: newTop })
|
||||
// 使用事件总线通知位置变化,包含 dragId
|
||||
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 = () => {
|
||||
// 使用事件总线通知拖拽结束
|
||||
if (!currentDragId.value) return
|
||||
|
||||
// 使用事件总线通知拖拽结束,包含 dragId 和标准化数据格式
|
||||
emitEvent(EVENT_TYPES.AREA_DRAG_END, {
|
||||
dragId: currentDragId.value,
|
||||
areaId: props.id,
|
||||
finalPosition: {
|
||||
x: originalPosition.value.left,
|
||||
y: originalPosition.value.top
|
||||
},
|
||||
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
|
||||
currentDragId.value = null
|
||||
// 使用全局事件管理器移除事件监听
|
||||
globalEventListenerManager.removeGlobalListener('mousemove', onDragMove)
|
||||
globalEventListenerManager.removeGlobalListener('mouseup', onDragEnd)
|
||||
@@ -507,6 +539,8 @@ const onResizeStart = (direction, e) => {
|
||||
areaId: props.id,
|
||||
left: newLeft,
|
||||
top: newTop
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
|
||||
// 防止文本选择
|
||||
@@ -542,6 +576,8 @@ const onToggleMaximize = () => {
|
||||
areaId: props.id,
|
||||
left: originalPosition.value.left,
|
||||
top: originalPosition.value.top
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -549,11 +585,15 @@ const onToggleMaximize = () => {
|
||||
emitEvent(EVENT_TYPES.WINDOW_STATE_CHANGE, {
|
||||
areaId: props.id,
|
||||
state: next
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
}
|
||||
|
||||
const onClose = () => emitEvent(EVENT_TYPES.PANEL_CLOSE_REQUEST, {
|
||||
areaId: props.id
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
|
||||
// 组件挂载后获取父容器引用并初始化位置
|
||||
@@ -589,6 +629,8 @@ onMounted(() => {
|
||||
areaId: props.id,
|
||||
left: originalPosition.value.left,
|
||||
top: originalPosition.value.top
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -675,6 +717,8 @@ const mergeAreaContent = (sourceArea) => {
|
||||
targetAreaHasContent: false, // 目标Area为空
|
||||
operation: 'add-children',
|
||||
addedTabPages: receivedContent.value
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
|
||||
return true
|
||||
@@ -734,6 +778,8 @@ const mergeAreaContent = (sourceArea) => {
|
||||
targetAreaHasContent: true, // 目标Area已有内容
|
||||
operation: 'merge-tabpages',
|
||||
sourceTabPages: tabPagesData
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
// 更新完成
|
||||
// // console.log(`[Area] 合并完成,现有TabPage共有 ${existingTabPage.tabPage.panels.length} 个Panel`)
|
||||
|
||||
@@ -716,7 +716,9 @@ const enhancedPreviewAreaStyle = computed(() => {
|
||||
|
||||
// 监听activeDockZone变化,触发事件
|
||||
watch(activeDockZone, (newZone) => {
|
||||
emitEvent('dock-zone-active', { zoneId: newZone })
|
||||
emitEvent('dock-zone-active', { zoneId: newZone }, {
|
||||
source: { component: 'DockIndicator' }
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -289,48 +289,48 @@ const setupEventListeners = () => {
|
||||
const unsubscribeFunctions = [];
|
||||
|
||||
// Area相关事件
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_START, onAreaDragStart));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_MOVE, onAreaDragMove));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_END, onAreaDragEnd));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_POSITION_UPDATE, onUpdatePosition));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_OVER, handleAreaDragOver));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_LEAVE, handleAreaDragLeave));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_START, onAreaDragStart, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_MOVE, onAreaDragMove, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_END, onAreaDragEnd, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_POSITION_UPDATE, 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' }));
|
||||
|
||||
// Tab相关事件
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CLOSE, onTabClose));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_ADD, onTabAdd));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_START, onTabDragStart));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_MOVE, onTabDragMove));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_END, onTabDragEnd));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CLOSE, onTabClose, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_ADD, onTabAdd, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_START, onTabDragStart, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_MOVE, onTabDragMove, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_DRAG_END, onTabDragEnd, { componentId: 'dock-layout' }));
|
||||
|
||||
// Panel相关事件
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_COLLAPSE, () => emit('toggleCollapse')));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE, onMaximize));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE_REQUEST, onCloseFloatingArea));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE, onClosePanel));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_TOOLBAR, () => emit('toggleToolbar')));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_START, onPanelDragStart));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_MOVE, onPanelDragMove));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_END, onPanelDragEnd));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_START_FROM_TABPAGE, onPanelDragStartFromTabPage));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_MOVE_FROM_TABPAGE, onPanelDragMoveFromTabPage));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_END_FROM_TABPAGE, onPanelDragEndFromTabPage));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, onPanelMaximizeSync));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_COLLAPSE, () => emit('toggleCollapse'), { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE, onMaximize, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE_REQUEST, onCloseFloatingArea, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE, onClosePanel, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_TOOLBAR, () => emit('toggleToolbar'), { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_START, onPanelDragStart, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_DRAG_MOVE, onPanelDragMove, { componentId: 'dock-layout' }));
|
||||
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, { componentId: 'dock-layout' }));
|
||||
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, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, onPanelMaximizeSync, { componentId: 'dock-layout' }));
|
||||
|
||||
// Resize相关事件
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_START, () => emit('dragStart')));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_MOVE, () => emit('dragMove')));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_END, () => emit('dragEnd')));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_START, () => emit('dragStart'), { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_MOVE, () => emit('dragMove'), { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_END, () => emit('dragEnd'), { componentId: 'dock-layout' }));
|
||||
|
||||
// Window相关事件
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.WINDOW_STATE_CHANGE, (event) => {
|
||||
// 处理窗口状态变化
|
||||
}));
|
||||
}, { componentId: 'dock-layout' }));
|
||||
|
||||
// 自定义事件
|
||||
unsubscribeFunctions.push(eventBus.on('area-merged', onAreaMerged));
|
||||
unsubscribeFunctions.push(eventBus.on('dock-zone-active', (event) => onDockZoneActive(event.zoneId)));
|
||||
unsubscribeFunctions.push(eventBus.on('area-merged', onAreaMerged, { componentId: 'dock-layout' }));
|
||||
unsubscribeFunctions.push(eventBus.on('dock-zone-active', (event) => onDockZoneActive(event.zoneId), { componentId: 'dock-layout' }));
|
||||
|
||||
return unsubscribeFunctions;
|
||||
};
|
||||
|
||||
@@ -202,6 +202,8 @@ const onToggleCollapse = () => {
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
currentState: props.collapsed
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id }
|
||||
})
|
||||
};
|
||||
|
||||
@@ -211,6 +213,8 @@ const onMaximize = () => {
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
currentState: props.maximized
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id }
|
||||
})
|
||||
};
|
||||
|
||||
@@ -222,6 +226,8 @@ const onClose = () => {
|
||||
areaId: getCurrentAreaId(),
|
||||
panelTitle: props.title,
|
||||
requestTime: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id }
|
||||
})
|
||||
};
|
||||
|
||||
@@ -231,11 +237,14 @@ const onToggleToolbar = () => {
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
currentState: props.toolbarExpanded
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id }
|
||||
})
|
||||
};
|
||||
|
||||
// 拖拽相关状态
|
||||
let isDragging = false
|
||||
let currentDragId = null
|
||||
|
||||
// 全局内存泄漏保护机制
|
||||
if (!window.__panelMemoryProtection) {
|
||||
@@ -378,19 +387,25 @@ const onDragStart = (e) => {
|
||||
if (!e.target.closest('.title-bar-buttons') && !e.target.closest('button')) {
|
||||
// 1. 立即重置之前的拖拽状态
|
||||
isDragging = false
|
||||
currentDragId = null
|
||||
cleanupDragEventListeners()
|
||||
|
||||
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, {
|
||||
dragId: currentDragId,
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
position: { x: e.clientX, y: e.clientY },
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id }
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
|
||||
// 3. 防止文本选择和默认行为
|
||||
@@ -404,40 +419,46 @@ const onDragStart = (e) => {
|
||||
|
||||
// 拖拽移动
|
||||
const onDragMove = (e) => {
|
||||
if (isDragging) {
|
||||
if (isDragging && currentDragId) {
|
||||
// 防止文本选择和默认行为
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// 使用事件总线触发拖拽移动事件
|
||||
// 使用事件总线触发拖拽移动事件,包含 dragId
|
||||
emitEvent(EVENT_TYPES.PANEL_DRAG_MOVE, {
|
||||
dragId: currentDragId,
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
position: { x: e.clientX, y: e.clientY },
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id }
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// 拖拽结束
|
||||
const onDragEnd = () => {
|
||||
if (isDragging) {
|
||||
if (isDragging && currentDragId) {
|
||||
isDragging = false;
|
||||
console.log(`[Panel:${props.id}] 结束拖拽`)
|
||||
|
||||
// 使用事件总线触发拖拽结束事件
|
||||
console.log(`[Panel:${props.id}] 结束拖拽, dragId: ${currentDragId}`)
|
||||
|
||||
// 使用事件总线触发拖拽结束事件,包含 dragId
|
||||
emitEvent(EVENT_TYPES.PANEL_DRAG_END, {
|
||||
dragId: currentDragId,
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id }
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
|
||||
// 使用统一的清理方法,确保一致性和完整性
|
||||
cleanupDragEventListeners()
|
||||
|
||||
// 重置 dragId
|
||||
currentDragId = null
|
||||
}
|
||||
};
|
||||
|
||||
@@ -449,10 +470,9 @@ const setupEventListeners = () => {
|
||||
// 监听面板最大化同步事件
|
||||
const unsubscribeMaximizeSync = onEvent(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, (data) => {
|
||||
if (data.panelId === props.id) {
|
||||
// 这里可以添加最大化状态同步的逻辑
|
||||
console.log(`[Panel:${props.id}] 收到最大化同步事件`)
|
||||
}
|
||||
})
|
||||
}, { componentId: `panel-${props.id}` })
|
||||
|
||||
const subscriptionId = `maximizeSync_${props.id}_${Date.now()}`
|
||||
subscriptions.add(unsubscribeMaximizeSync)
|
||||
|
||||
@@ -123,7 +123,9 @@ const handleMouseMove = (event: MouseEvent) => {
|
||||
// 结束调整大小
|
||||
const endResize = () => {
|
||||
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)
|
||||
|
||||
@@ -155,6 +155,7 @@ const activeTabIndex = ref(-1)
|
||||
// 拖拽相关状态
|
||||
let isDragging = false
|
||||
let dragIndex = -1
|
||||
let currentDragId = null
|
||||
|
||||
// 计算属性:获取插槽项的props
|
||||
const slotItems = computed(() => {
|
||||
@@ -198,12 +199,18 @@ const onTabDragStart = (index, event) => {
|
||||
isDragging = true
|
||||
dragIndex = index
|
||||
|
||||
// 传递标签页索引和鼠标位置
|
||||
// 生成统一的 dragId
|
||||
currentDragId = `tabpage_${props.id}_${index}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
|
||||
|
||||
// 传递标签页索引和鼠标位置,包含 dragId
|
||||
emitEvent(EVENT_TYPES.TAB_DRAG_START, {
|
||||
dragId: currentDragId,
|
||||
clientX: event.clientX,
|
||||
clientY: event.clientY,
|
||||
tabIndex: index,
|
||||
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) => {
|
||||
if (isDragging) {
|
||||
if (isDragging && currentDragId) {
|
||||
// 防止文本选择和默认行为
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
emitEvent(EVENT_TYPES.TAB_DRAG_MOVE, {
|
||||
dragId: currentDragId,
|
||||
clientX: event.clientX,
|
||||
clientY: event.clientY,
|
||||
tabIndex: dragIndex
|
||||
@@ -233,10 +241,14 @@ const onTabDragMove = (event) => {
|
||||
|
||||
// 标签拖拽结束
|
||||
const onTabDragEnd = () => {
|
||||
if (isDragging) {
|
||||
if (isDragging && currentDragId) {
|
||||
isDragging = false
|
||||
emitEvent(EVENT_TYPES.TAB_DRAG_END, { tabIndex: dragIndex })
|
||||
emitEvent(EVENT_TYPES.TAB_DRAG_END, {
|
||||
dragId: currentDragId,
|
||||
tabIndex: dragIndex
|
||||
})
|
||||
dragIndex = -1
|
||||
currentDragId = null
|
||||
|
||||
// 拖拽结束后移除事件监听器
|
||||
document.removeEventListener('mousemove', onTabDragMove)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,9 @@
|
||||
* 专门处理Area相关的所有事件,包括浮动区域管理、拖拽、停靠、合并等
|
||||
*/
|
||||
|
||||
import { eventBus } from '../eventBus';
|
||||
import { eventBus, EVENT_TYPES } from '../eventBus';
|
||||
|
||||
// Area事件类型常量
|
||||
// Area事件类型常量(仅包含EVENT_TYPES中没有的)
|
||||
export const AREA_EVENT_TYPES = {
|
||||
// 基础事件
|
||||
AREA_CREATED: 'area.created',
|
||||
@@ -23,16 +23,8 @@ export const AREA_EVENT_TYPES = {
|
||||
AREA_RESTORE: 'area.restore',
|
||||
AREA_COLLAPSE: 'area.collapse',
|
||||
AREA_EXPAND: 'area.expand',
|
||||
AREA_CLOSE: 'area.close',
|
||||
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_EDGE: 'area.dock.edge',
|
||||
@@ -759,12 +751,36 @@ class AreaEventHandler {
|
||||
* 注册事件监听器
|
||||
*/
|
||||
_registerEventListeners() {
|
||||
const events = Object.values(AREA_EVENT_TYPES);
|
||||
events.forEach(eventType => {
|
||||
// 监听 EVENT_TYPES 中的事件
|
||||
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;
|
||||
eventBus.on(eventType, listener, {
|
||||
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);
|
||||
});
|
||||
@@ -775,17 +791,17 @@ class AreaEventHandler {
|
||||
* @param {Object} data - 事件数据
|
||||
*/
|
||||
async _onAreaEvent(data) {
|
||||
const { eventType } = data;
|
||||
const eventType = data.eventType;
|
||||
|
||||
try {
|
||||
switch (eventType) {
|
||||
case AREA_EVENT_TYPES.AREA_DRAG_START:
|
||||
case EVENT_TYPES.AREA_DRAG_START:
|
||||
await this._handleAreaDragStart(data);
|
||||
break;
|
||||
case AREA_EVENT_TYPES.AREA_DRAG_MOVE:
|
||||
case EVENT_TYPES.AREA_DRAG_MOVE:
|
||||
await this._handleAreaDragMove(data);
|
||||
break;
|
||||
case AREA_EVENT_TYPES.AREA_DRAG_END:
|
||||
case EVENT_TYPES.AREA_DRAG_END:
|
||||
await this._handleAreaDragEnd(data);
|
||||
break;
|
||||
case AREA_EVENT_TYPES.AREA_DOCK_CENTER:
|
||||
@@ -806,13 +822,15 @@ class AreaEventHandler {
|
||||
case AREA_EVENT_TYPES.AREA_FLOATING_CREATE:
|
||||
await this._handleFloatingAreaCreate(data);
|
||||
break;
|
||||
case AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT:
|
||||
await this._handleAreaZIndexManagement(data);
|
||||
break;
|
||||
default:
|
||||
// 记录其他事件但不处理
|
||||
console.log(`📍 Area事件处理器: ${eventType}`, data);
|
||||
console.log(`📍 Area事件处理器: ${eventType || 'unknown'}`, data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ Area事件处理错误 (${eventType}):`, error);
|
||||
eventBus.recordError(`areaHandler_${eventType}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,7 +902,7 @@ class AreaEventHandler {
|
||||
* @param {Object} data - 事件数据
|
||||
*/
|
||||
async _handleAreaDragEnd(data) {
|
||||
const { areaId, event } = data;
|
||||
const { areaId, event, finalPosition, left, top } = data;
|
||||
const dragState = this.areaStateManager.getDragState(areaId);
|
||||
|
||||
if (!dragState) return;
|
||||
@@ -896,7 +914,18 @@ class AreaEventHandler {
|
||||
// 清理拖拽状态
|
||||
dragState.isDragging = false;
|
||||
dragState.endTime = Date.now();
|
||||
|
||||
// 使用 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.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();
|
||||
|
||||
/**
|
||||
* 获取Area事件处理器实例
|
||||
* @returns {AreaEventHandler} AreaEventHandler实例
|
||||
*/
|
||||
export const getAreaHandler = () => areaHandler;
|
||||
|
||||
// Area便捷操作函数
|
||||
export const areaActions = {
|
||||
/**
|
||||
|
||||
@@ -495,6 +495,8 @@ class DragStateManager {
|
||||
};
|
||||
this.isEnabled = true;
|
||||
this.debugMode = false;
|
||||
this.eventListenersRegistered = false; // 初始化监听器注册标志
|
||||
this.cleanupScheduler = null; // 初始化清理调度器
|
||||
|
||||
// 绑定方法
|
||||
this._onDragEvent = this._onDragEvent.bind(this);
|
||||
@@ -516,12 +518,24 @@ class DragStateManager {
|
||||
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() {
|
||||
// 防止重复注册监听器
|
||||
if (this.eventListenersRegistered) {
|
||||
console.log('🚫 已经注册了监听器,跳过重复注册');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -537,17 +551,22 @@ class DragStateManager {
|
||||
dragEvents.forEach(eventType => {
|
||||
eventBus.on(eventType, this._onDragEvent, {
|
||||
priority: 1,
|
||||
deduplication: { type: 'EVENT_BASED', key: 'dragState' }
|
||||
deduplication: { type: 'EVENT_BASED', key: 'dragState' },
|
||||
componentId: 'drag-state-manager'
|
||||
});
|
||||
});
|
||||
|
||||
this.eventListenersRegistered = true;
|
||||
console.log('✅ 拖拽管理器事件监听器注册完成');
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁管理器
|
||||
*/
|
||||
destroy() {
|
||||
// 取消所有拖拽
|
||||
this.cancelAllDrags();
|
||||
|
||||
// 清理事件监听器
|
||||
const dragEvents = [
|
||||
// Panel拖拽事件
|
||||
@@ -565,10 +584,17 @@ class DragStateManager {
|
||||
// 清理清理调度器
|
||||
this._stopCleanupScheduler();
|
||||
|
||||
// 清理拖拽状态
|
||||
this.dragStates.clear();
|
||||
// 清理数据
|
||||
this.activeDrags.clear();
|
||||
this.dragHistory = [];
|
||||
this.dragTargets.clear();
|
||||
|
||||
// 清理冲突检测器
|
||||
this.conflictDetector.activeDrags.clear();
|
||||
this.conflictDetector.conflictHistory = [];
|
||||
|
||||
this.isEnabled = false;
|
||||
this.eventListenersRegistered = false;
|
||||
console.log('🗑️ 拖拽状态管理器已销毁');
|
||||
}
|
||||
|
||||
@@ -579,34 +605,66 @@ class DragStateManager {
|
||||
async _onDragEvent(data) {
|
||||
if (!this.isEnabled) return;
|
||||
|
||||
const monitorId = globalEventActions.startMonitor(`drag_${data.eventType || data.type}`);
|
||||
const monitorId = globalEventActions.startMonitor(`drag_${data.eventType}`);
|
||||
|
||||
try {
|
||||
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) {
|
||||
case 'panel.drag.start':
|
||||
case 'tabpage.drag.start':
|
||||
case 'area.drag.start':
|
||||
await this._handleDragStart(data);
|
||||
await this._handleDragStart(dragData);
|
||||
break;
|
||||
|
||||
case 'panel.drag.move':
|
||||
case 'tabpage.drag.move':
|
||||
case 'area.drag.move':
|
||||
await this._handleDragMove(data);
|
||||
await this._handleDragMove(dragData);
|
||||
break;
|
||||
|
||||
case 'panel.drag.end':
|
||||
case 'tabpage.drag.end':
|
||||
case 'area.drag.end':
|
||||
await this._handleDragEnd(data);
|
||||
await this._handleDragEnd(dragData);
|
||||
break;
|
||||
|
||||
case 'panel.drag.cancel':
|
||||
case 'tabpage.drag.cancel':
|
||||
case 'area.drag.cancel':
|
||||
await this._handleDragCancel(data);
|
||||
await this._handleDragCancel(dragData);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -628,28 +686,31 @@ class DragStateManager {
|
||||
async _handleDragStart(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.currentPosition = { ...position };
|
||||
dragState.status = 'active';
|
||||
|
||||
// 保存拖拽状态
|
||||
this.activeDrags.set(dragId, dragState);
|
||||
this.activeDrags.set(actualDragId, dragState);
|
||||
|
||||
// 注册到冲突检测器
|
||||
this.conflictDetector.registerDrag(dragState);
|
||||
|
||||
// 触发状态变更事件
|
||||
// 触发状态变更事件,包含 dragId
|
||||
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
|
||||
dragId,
|
||||
dragId: actualDragId,
|
||||
newStatus: 'active',
|
||||
dragState: dragState.getSummary()
|
||||
});
|
||||
|
||||
// 发送初始反馈
|
||||
if (this.debugMode) {
|
||||
this._updateDragFeedback(dragId, {
|
||||
this._updateDragFeedback(actualDragId, {
|
||||
visible: true,
|
||||
content: `开始拖拽 ${componentType}`,
|
||||
type: 'default',
|
||||
@@ -658,8 +719,10 @@ class DragStateManager {
|
||||
}
|
||||
|
||||
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 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);
|
||||
@@ -726,7 +792,10 @@ class DragStateManager {
|
||||
const { dragId, finalPosition, dropTarget, success = true } = data;
|
||||
const dragState = this.activeDrags.get(dragId);
|
||||
|
||||
if (!dragState) return;
|
||||
if (!dragState) {
|
||||
console.warn(`⚠️ 未找到拖拽状态: ${dragId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 完成拖拽
|
||||
dragState.complete('completed', { success, finalPosition, dropTarget });
|
||||
@@ -743,7 +812,10 @@ class DragStateManager {
|
||||
// 从冲突检测器注销
|
||||
this.conflictDetector.unregisterDrag(dragId);
|
||||
|
||||
// 触发状态变更事件
|
||||
// 清理拖拽目标
|
||||
this.dragTargets.delete(dragId);
|
||||
|
||||
// 触发状态变更事件,包含 dragId
|
||||
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
|
||||
dragId,
|
||||
newStatus: 'completed',
|
||||
@@ -773,7 +845,10 @@ class DragStateManager {
|
||||
const { dragId, reason } = data;
|
||||
const dragState = this.activeDrags.get(dragId);
|
||||
|
||||
if (!dragState) return;
|
||||
if (!dragState) {
|
||||
console.warn(`⚠️ 未找到拖拽状态: ${dragId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 取消拖拽
|
||||
dragState.complete('cancelled', { reason });
|
||||
@@ -790,7 +865,10 @@ class DragStateManager {
|
||||
// 从冲突检测器注销
|
||||
this.conflictDetector.unregisterDrag(dragId);
|
||||
|
||||
// 触发状态变更事件
|
||||
// 清理拖拽目标
|
||||
this.dragTargets.delete(dragId);
|
||||
|
||||
// 触发状态变更事件,包含 dragId
|
||||
eventBus.emit(DRAG_STATE_TYPES.DRAG_STATE_CHANGE, {
|
||||
dragId,
|
||||
newStatus: 'cancelled',
|
||||
@@ -1024,11 +1102,24 @@ class DragStateManager {
|
||||
* 启动清理调度器
|
||||
*/
|
||||
_startCleanupScheduler() {
|
||||
setInterval(() => {
|
||||
if (this.cleanupScheduler) {
|
||||
return;
|
||||
}
|
||||
this.cleanupScheduler = setInterval(() => {
|
||||
this._cleanupExpiredData();
|
||||
}, 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拖拽开始
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
@@ -1878,18 +1949,8 @@ class DragStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// 延迟创建单例实例
|
||||
let dragStateManager = null;
|
||||
|
||||
/**
|
||||
* 确保单例实例存在
|
||||
*/
|
||||
function ensureDragStateManagerInstance() {
|
||||
if (!dragStateManager) {
|
||||
dragStateManager = new DragStateManager();
|
||||
}
|
||||
return dragStateManager;
|
||||
}
|
||||
// 立即创建单例实例,避免并发初始化问题
|
||||
const dragStateManager = new DragStateManager();
|
||||
|
||||
// 便捷操作函数
|
||||
export const dragStateActions = {
|
||||
@@ -1898,150 +1959,153 @@ export const dragStateActions = {
|
||||
* @param {string} dragId - 拖拽ID
|
||||
* @returns {Object} 拖拽状态
|
||||
*/
|
||||
getDragState: (dragId) => ensureDragStateManagerInstance().getDragState(dragId),
|
||||
getDragState: (dragId) => dragStateManager.getDragState(dragId),
|
||||
|
||||
/**
|
||||
* 获取所有活跃拖拽
|
||||
* @returns {Array} 活跃拖拽列表
|
||||
*/
|
||||
getActiveDrags: () => ensureDragStateManagerInstance().getActiveDrags(),
|
||||
getActiveDrags: () => dragStateManager.getActiveDrags(),
|
||||
|
||||
/**
|
||||
* 获取拖拽历史
|
||||
* @param {number} limit - 限制数量
|
||||
* @returns {Array} 历史记录
|
||||
*/
|
||||
getHistory: (limit = 100) => ensureDragStateManagerInstance().getDragHistory(limit),
|
||||
getHistory: (limit = 100) => dragStateManager.getDragHistory(limit),
|
||||
|
||||
/**
|
||||
* 获取统计信息
|
||||
* @returns {Object} 统计信息
|
||||
*/
|
||||
getStats: () => ensureDragStateManagerInstance().getDragStats(),
|
||||
getStats: () => dragStateManager.getDragStats(),
|
||||
|
||||
/**
|
||||
* 设置调试模式
|
||||
* @param {boolean} enabled - 是否启用
|
||||
*/
|
||||
setDebugMode: (enabled) => ensureDragStateManagerInstance().setDebugMode(enabled),
|
||||
setDebugMode: (enabled) => dragStateManager.setDebugMode(enabled),
|
||||
|
||||
/**
|
||||
* 启用/禁用管理器
|
||||
* @param {boolean} enabled - 是否启用
|
||||
*/
|
||||
setEnabled: (enabled) => ensureDragStateManagerInstance().setEnabled(enabled),
|
||||
setEnabled: (enabled) => dragStateManager.setEnabled(enabled),
|
||||
|
||||
/**
|
||||
* 取消所有拖拽
|
||||
*/
|
||||
cancelAll: () => ensureDragStateManagerInstance().cancelAllDrags(),
|
||||
cancelAll: () => dragStateManager.cancelAllDrags(),
|
||||
|
||||
/**
|
||||
* 面板拖拽开始
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {string} 拖拽ID
|
||||
*/
|
||||
onPanelDragStart: (eventData) => ensureDragStateManagerInstance().onPanelDragStart(eventData),
|
||||
onPanelDragStart: (eventData) => dragStateManager.onPanelDragStart(eventData),
|
||||
|
||||
/**
|
||||
* 面板拖拽移动
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onPanelDragMove: (eventData) => ensureDragStateManagerInstance().onPanelDragMove(eventData),
|
||||
onPanelDragMove: (eventData) => dragStateManager.onPanelDragMove(eventData),
|
||||
|
||||
/**
|
||||
* 面板拖拽结束
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onPanelDragEnd: (eventData) => ensureDragStateManagerInstance().onPanelDragEnd(eventData),
|
||||
onPanelDragEnd: (eventData) => dragStateManager.onPanelDragEnd(eventData),
|
||||
|
||||
/**
|
||||
* TabPage拖拽开始
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {string} 拖拽ID
|
||||
*/
|
||||
onPanelDragStartFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragStartFromTabPage(eventData),
|
||||
onPanelDragStartFromTabPage: (eventData) => dragStateManager.onPanelDragStartFromTabPage(eventData),
|
||||
|
||||
/**
|
||||
* TabPage拖拽移动
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onPanelDragMoveFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragMoveFromTabPage(eventData),
|
||||
onPanelDragMoveFromTabPage: (eventData) => dragStateManager.onPanelDragMoveFromTabPage(eventData),
|
||||
|
||||
/**
|
||||
* TabPage拖拽结束
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onPanelDragEndFromTabPage: (eventData) => ensureDragStateManagerInstance().onPanelDragEndFromTabPage(eventData),
|
||||
onPanelDragEndFromTabPage: (eventData) => dragStateManager.onPanelDragEndFromTabPage(eventData),
|
||||
|
||||
/**
|
||||
* Area拖拽开始
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {string} 拖拽ID
|
||||
*/
|
||||
onAreaDragStart: (eventData) => ensureDragStateManagerInstance().onAreaDragStart(eventData),
|
||||
onAreaDragStart: (eventData) => dragStateManager.onAreaDragStart(eventData),
|
||||
|
||||
/**
|
||||
* Area拖拽移动
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onAreaDragMove: (eventData) => ensureDragStateManagerInstance().onAreaDragMove(eventData),
|
||||
onAreaDragMove: (eventData) => dragStateManager.onAreaDragMove(eventData),
|
||||
|
||||
/**
|
||||
* Area拖拽结束
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onAreaDragEnd: (eventData) => ensureDragStateManagerInstance().onAreaDragEnd(eventData),
|
||||
onAreaDragEnd: (eventData) => dragStateManager.onAreaDragEnd(eventData),
|
||||
|
||||
/**
|
||||
* Tab拖拽开始
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {string} 拖拽ID
|
||||
*/
|
||||
onTabDragStart: (eventData) => ensureDragStateManagerInstance().onPanelDragStartFromTabPage(eventData),
|
||||
onTabDragStart: (eventData) => dragStateManager.onPanelDragStartFromTabPage(eventData),
|
||||
|
||||
/**
|
||||
* Tab拖拽移动
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onTabDragMove: (eventData) => ensureDragStateManagerInstance().onPanelDragMoveFromTabPage(eventData),
|
||||
onTabDragMove: (eventData) => dragStateManager.onPanelDragMoveFromTabPage(eventData),
|
||||
|
||||
/**
|
||||
* Tab拖拽结束
|
||||
* @param {Object} eventData - 拖拽事件数据
|
||||
* @returns {boolean} 是否成功
|
||||
*/
|
||||
onTabDragEnd: (eventData) => ensureDragStateManagerInstance().onPanelDragEndFromTabPage(eventData),
|
||||
onTabDragEnd: (eventData) => dragStateManager.onPanelDragEndFromTabPage(eventData),
|
||||
|
||||
/**
|
||||
* 初始化拖拽管理器
|
||||
*/
|
||||
initialize: () => ensureDragStateManagerInstance(),
|
||||
initialize: () => dragStateManager,
|
||||
|
||||
/**
|
||||
* 销毁拖拽管理器
|
||||
*/
|
||||
destroy: () => {
|
||||
if (dragStateManager) {
|
||||
// 清理拖拽管理器资源
|
||||
dragStateManager.activeDrags.clear();
|
||||
dragStateManager.dragHistory = [];
|
||||
// 清理拖拽管理器资源,先调用实例的destroy方法清理监听器
|
||||
try {
|
||||
dragStateManager.destroy();
|
||||
} catch (e) {
|
||||
console.warn('销毁拖拽状态管理器时出错:', e);
|
||||
}
|
||||
dragStateManager = null;
|
||||
console.log('🗑️ 拖拽状态管理器已销毁,所有资源已清理');
|
||||
console.log('🗑️ 拖拽状态管理器已销毁');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 导出
|
||||
export default {
|
||||
getInstance: ensureDragStateManagerInstance,
|
||||
getInstance: () => dragStateManager,
|
||||
actions: dragStateActions
|
||||
};
|
||||
export { DragState };
|
||||
@@ -140,10 +140,10 @@ class EventBusManager {
|
||||
{ name: 'tabpage', handler: tabPageHandler, events: TABPAGE_EVENT_TYPES },
|
||||
{ name: 'area', handler: areaHandler, events: AREA_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];
|
||||
|
||||
if (!handlerConfig?.enabled) {
|
||||
@@ -154,15 +154,20 @@ class EventBusManager {
|
||||
try {
|
||||
console.log(`📝 注册事件处理器: ${name}`);
|
||||
|
||||
// 注册事件处理器到事件总线
|
||||
// 注册事件处理器到事件总线(除非跳过)
|
||||
if (!skipEventRegistration) {
|
||||
Object.values(events).forEach(eventType => {
|
||||
if (typeof handler.handleEvent === 'function') {
|
||||
eventBus.on(eventType, handler.handleEvent.bind(handler), {
|
||||
priority: 1,
|
||||
id: `handler-${name}`
|
||||
id: `handler-${name}`,
|
||||
componentId: `handler-${name}`
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(`⏭️ 跳过事件监听器注册(内部自动注册): ${name}`);
|
||||
}
|
||||
|
||||
// 调用初始化方法(如果存在)
|
||||
if (typeof handler.initialize === 'function') {
|
||||
@@ -236,7 +241,7 @@ class EventBusManager {
|
||||
routeTime: Date.now()
|
||||
});
|
||||
});
|
||||
}, { id: 'router', priority: 0 });
|
||||
}, { id: 'router', priority: 0, componentId: 'event-router' });
|
||||
});
|
||||
|
||||
console.log(`🔗 设置了 ${routes.length} 个事件路由`);
|
||||
|
||||
@@ -4,13 +4,6 @@
|
||||
*/
|
||||
|
||||
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 = {
|
||||
@@ -50,59 +43,7 @@ export const GLOBAL_EVENT_TYPES = {
|
||||
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 {
|
||||
@@ -297,31 +238,26 @@ class GlobalEventManager {
|
||||
static instance = null;
|
||||
|
||||
constructor() {
|
||||
// 单例模式实现:如果已经有实例,直接返回现有实例
|
||||
if (GlobalEventManager.instance) {
|
||||
return GlobalEventManager.instance;
|
||||
}
|
||||
|
||||
this.eventHandlers = new Map();
|
||||
this.eventRoutes = new Map(Object.entries(EVENT_ROUTES));
|
||||
this.eventRoutes = new Map();
|
||||
this.executionMonitor = new EventExecutionMonitor();
|
||||
this.eventChains = new Map();
|
||||
this.crossComponentChannels = new Map();
|
||||
this.isInitialized = false;
|
||||
this.isDestroyed = false;
|
||||
this.eventListenersRegistered = false;
|
||||
this.componentListenersRegistered = false;
|
||||
this.debugMode = false;
|
||||
this.handlerMap = {};
|
||||
this.eventListenerUnsubscribers = [];
|
||||
|
||||
// 绑定方法
|
||||
this._onGlobalEvent = this._onGlobalEvent.bind(this);
|
||||
this._onSystemError = this._handleSystemError.bind(this);
|
||||
this._cleanupExpiredData = this._cleanupExpiredData.bind(this);
|
||||
|
||||
// 延迟初始化,先不调用_initialize()
|
||||
|
||||
// 保存实例到静态属性
|
||||
GlobalEventManager.instance = this;
|
||||
}
|
||||
|
||||
@@ -329,41 +265,29 @@ class GlobalEventManager {
|
||||
* 初始化事件管理器
|
||||
*/
|
||||
async _initialize() {
|
||||
// 防止重复初始化
|
||||
if (this.isInitialized) {
|
||||
console.warn('⚠️ 全局事件管理器已初始化,跳过重复初始化');
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化处理器映射
|
||||
this.handlerMap = {
|
||||
panelHandler,
|
||||
tabPageHandler,
|
||||
areaHandler
|
||||
};
|
||||
this.eventRoutes = new Map();
|
||||
|
||||
// 注册全局事件监听器
|
||||
this._registerGlobalEventListeners();
|
||||
|
||||
// 启动定期清理
|
||||
this._startCleanupScheduler();
|
||||
|
||||
// 启动调试模式监听
|
||||
this._startDebugMode();
|
||||
|
||||
this.isInitialized = true;
|
||||
console.log('✅ 全局事件管理器初始化完成');
|
||||
|
||||
// 触发系统就绪事件
|
||||
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_READY, {
|
||||
manager: 'globalEventManager',
|
||||
timestamp: Date.now(),
|
||||
handlers: Object.keys(this.handlerMap)
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册全局事件监听器
|
||||
* 添加初始化锁防止并发场景下的重复注册
|
||||
*/
|
||||
_registerGlobalEventListeners() {
|
||||
// 检查是否已经注册过事件监听器
|
||||
@@ -372,236 +296,46 @@ class GlobalEventManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// 先标记为正在注册,防止并发
|
||||
this.eventListenersRegistered = true;
|
||||
|
||||
try {
|
||||
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 }
|
||||
deduplication: { type: 'TTL_BASED', ttl: 50 },
|
||||
componentId: 'global-event-manager'
|
||||
});
|
||||
this.eventListenerUnsubscribers.push(unsubscribe);
|
||||
});
|
||||
|
||||
// 注册所有组件事件监听器
|
||||
this._registerComponentEventListeners();
|
||||
|
||||
// 标记为已注册
|
||||
this.eventListenersRegistered = true;
|
||||
} catch (error) {
|
||||
// 如果注册失败,重置标志位
|
||||
this.eventListenersRegistered = false;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册组件事件监听器
|
||||
* 添加初始化锁防止并发场景下的重复注册
|
||||
*/
|
||||
_registerComponentEventListeners() {
|
||||
// 防止重复注册组件事件监听器
|
||||
if (this.componentListenersRegistered) {
|
||||
console.warn('⚠️ 组件事件监听器已经注册,跳过重复注册');
|
||||
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;
|
||||
|
||||
console.log('✅ 组件事件监听器注册完成(Handler自行订阅事件)');
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由事件到相应的处理器
|
||||
* @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 {
|
||||
if (routeConfig) {
|
||||
// 使用配置的路由
|
||||
await this._executeRoutedHandlers(eventId, eventType, eventData, routeConfig);
|
||||
} else {
|
||||
// 默认路由到相应组件处理器
|
||||
await this._executeDefaultHandler(eventId, eventType, eventData, source);
|
||||
}
|
||||
|
||||
// 完成监控
|
||||
this.executionMonitor.completeMonitoring(eventId);
|
||||
|
||||
eventBus.emit(GLOBAL_EVENT_TYPES.EVENT_ROUTE_SUCCESS, {
|
||||
eventId,
|
||||
eventType,
|
||||
source,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
// 记录错误
|
||||
this.executionMonitor.recordError(eventId, error);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 带超时的处理器执行
|
||||
* @param {Object} handler - 处理器对象
|
||||
* @param {string} eventType - 事件类型
|
||||
* @param {Object} eventData - 事件数据
|
||||
* @param {number} timeout - 超时时间
|
||||
* @returns {Promise} 执行结果
|
||||
*/
|
||||
async _executeHandlerWithTimeout(handler, eventType, eventData, timeout) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
reject(new Error(`Handler execution timeout after ${timeout}ms`));
|
||||
}, timeout);
|
||||
|
||||
try {
|
||||
// 假设处理器有处理事件的方法
|
||||
if (typeof handler._onEvent === 'function') {
|
||||
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) {
|
||||
const { eventType } = data;
|
||||
const eventType = data.eventType;
|
||||
|
||||
try {
|
||||
switch (eventType) {
|
||||
@@ -634,18 +368,8 @@ class GlobalEventManager {
|
||||
async _handleSystemInit(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, {
|
||||
manager: 'globalEventManager',
|
||||
handlersStatus,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
@@ -714,37 +438,13 @@ class GlobalEventManager {
|
||||
async _handleCrossComponentRequest(data) {
|
||||
const { requestId, targetComponent, action, payload } = data;
|
||||
|
||||
try {
|
||||
// 查找目标组件的处理器
|
||||
const handler = this.handlerMap[`${targetComponent}Handler`];
|
||||
if (!handler) {
|
||||
throw new Error(`Target component handler ${targetComponent}Handler not found`);
|
||||
}
|
||||
|
||||
// 执行请求
|
||||
const result = await handler[action](payload);
|
||||
|
||||
// 发送响应
|
||||
eventBus.emit(GLOBAL_EVENT_TYPES.CROSS_COMPONENT_RESPONSE, {
|
||||
// 通过事件总线转发跨组件请求
|
||||
// 目标Handler应该监听这个事件并处理
|
||||
eventBus.emit(`${targetComponent}.${action}`, {
|
||||
requestId,
|
||||
targetComponent,
|
||||
action,
|
||||
result,
|
||||
success: true,
|
||||
timestamp: Date.now()
|
||||
payload,
|
||||
isCrossComponent: true
|
||||
});
|
||||
|
||||
} 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() {
|
||||
if (this.isDestroyed) {
|
||||
console.warn('⚠️ 全局事件管理器已经被销毁,跳过重复销毁');
|
||||
return;
|
||||
}
|
||||
|
||||
this.isDestroyed = true;
|
||||
|
||||
// 清理自己注册的所有事件监听器
|
||||
if (this.eventListenerUnsubscribers.length > 0) {
|
||||
this.eventListenerUnsubscribers.forEach(unsubscribe => {
|
||||
try {
|
||||
if (typeof unsubscribe === 'function') {
|
||||
unsubscribe();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('清理监听器时出错:', error);
|
||||
}
|
||||
});
|
||||
this.eventListenerUnsubscribers = [];
|
||||
|
||||
// 销毁各个处理器
|
||||
Object.values(this.handlerMap).forEach(handler => {
|
||||
if (typeof handler.destroy === 'function') {
|
||||
handler.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
// 清理数据
|
||||
this.eventHandlers.clear();
|
||||
this.eventChains.clear();
|
||||
this.crossComponentChannels.clear();
|
||||
this.handlerMap = {};
|
||||
this.eventRoutes.clear();
|
||||
if (this.eventHandlers) this.eventHandlers.clear();
|
||||
if (this.eventChains) this.eventChains.clear();
|
||||
if (this.crossComponentChannels) this.crossComponentChannels.clear();
|
||||
if (this.eventRoutes) this.eventRoutes.clear();
|
||||
|
||||
// 清理执行监控器
|
||||
if (this.executionMonitor) {
|
||||
this.executionMonitor.cleanup();
|
||||
}
|
||||
|
||||
// 重置状态标志
|
||||
this.isInitialized = false;
|
||||
this.eventListenersRegistered = false;
|
||||
this.componentListenersRegistered = false;
|
||||
|
||||
console.log('🗑️ 全局事件管理器已销毁,所有监听器已清理');
|
||||
}
|
||||
}
|
||||
|
||||
// 延迟创建单例实例
|
||||
let globalEventManager = null;
|
||||
// 立即创建单例实例,避免并发初始化问题
|
||||
const globalEventManager = new GlobalEventManager();
|
||||
|
||||
// 全局便捷API
|
||||
export const globalEventActions = {
|
||||
@@ -1076,7 +787,6 @@ export const globalEventActions = {
|
||||
* @returns {string} 监控ID
|
||||
*/
|
||||
startMonitor: (operation) => {
|
||||
ensureInstance();
|
||||
return globalEventManager.startPerformanceMonitor(operation);
|
||||
},
|
||||
|
||||
@@ -1086,7 +796,6 @@ export const globalEventActions = {
|
||||
* @param {Object} metadata - 元数据
|
||||
*/
|
||||
endMonitor: (monitorId, metadata = {}) => {
|
||||
ensureInstance();
|
||||
globalEventManager.endPerformanceMonitor(monitorId, metadata);
|
||||
},
|
||||
|
||||
@@ -1097,7 +806,6 @@ export const globalEventActions = {
|
||||
* @returns {string} 链ID
|
||||
*/
|
||||
createChain: (chainName, events) => {
|
||||
ensureInstance();
|
||||
return globalEventManager.createEventChain(chainName, events);
|
||||
},
|
||||
|
||||
@@ -1108,7 +816,6 @@ export const globalEventActions = {
|
||||
* @param {Array} targets - 目标组件
|
||||
*/
|
||||
broadcast: (message, data = {}, targets = null) => {
|
||||
ensureInstance();
|
||||
globalEventManager.broadcast(message, data, targets);
|
||||
},
|
||||
|
||||
@@ -1120,7 +827,6 @@ export const globalEventActions = {
|
||||
* @returns {Promise} 响应
|
||||
*/
|
||||
request: (component, action, payload) => {
|
||||
ensureInstance();
|
||||
return globalEventManager.request(component, action, payload);
|
||||
},
|
||||
|
||||
@@ -1136,7 +842,6 @@ export const globalEventActions = {
|
||||
* @returns {Object} 统计信息
|
||||
*/
|
||||
getStats: () => {
|
||||
ensureInstance();
|
||||
return globalEventManager.getExecutionStats();
|
||||
},
|
||||
|
||||
@@ -1145,7 +850,6 @@ export const globalEventActions = {
|
||||
* @returns {Array} 链状态
|
||||
*/
|
||||
getChainStatus: () => {
|
||||
ensureInstance();
|
||||
return globalEventManager.getEventChainStatus();
|
||||
},
|
||||
|
||||
@@ -1153,7 +857,7 @@ export const globalEventActions = {
|
||||
* 初始化事件管理器
|
||||
*/
|
||||
initialize: () => {
|
||||
ensureInstance();
|
||||
return globalEventManager;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -1162,31 +866,15 @@ export const globalEventActions = {
|
||||
destroy: () => {
|
||||
if (globalEventManager) {
|
||||
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
|
||||
export default {
|
||||
getInstance: getGlobalEventManager,
|
||||
getInstance: () => globalEventManager,
|
||||
actions: globalEventActions
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { emitEvent, onEvent, onceEvent, registerHandler, unregisterHandler, getHandlerSnapshot } from '../eventBus'
|
||||
import { nanoid } from 'nanoid'
|
||||
import { emitEvent, onEvent, onceEvent, registerHandler, unregisterHandler, getHandlerSnapshot } from '../eventBus'
|
||||
|
||||
// Panel事件类型常量
|
||||
export const PANEL_EVENT_TYPES = {
|
||||
@@ -151,9 +151,11 @@ class PanelEventHandler {
|
||||
// 触发最大化事件(false表示还原)
|
||||
await emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
|
||||
panelId,
|
||||
maximized: false,
|
||||
source: 'PanelHandler'
|
||||
}, { priority })
|
||||
maximized: false
|
||||
}, {
|
||||
priority,
|
||||
source: { component: 'PanelHandler', panelId }
|
||||
})
|
||||
|
||||
// 如果需要同步到Area
|
||||
if (syncToArea) {
|
||||
@@ -171,10 +173,12 @@ class PanelEventHandler {
|
||||
*/
|
||||
requestClose(eventData) {
|
||||
const { areaId, panelId } = eventData;
|
||||
this.emitEvent(PANEL_EVENT_TYPES.CLOSE_REQUEST, {
|
||||
emitEvent(PANEL_EVENT_TYPES.CLOSE_REQUEST, {
|
||||
areaId,
|
||||
panelId,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'PanelHandler', panelId, areaId }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -231,9 +235,11 @@ class PanelEventHandler {
|
||||
|
||||
return emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
|
||||
panelId,
|
||||
toolbarExpanded: panelState.toolbarExpanded,
|
||||
source: 'PanelHandler'
|
||||
}, { priority })
|
||||
toolbarExpanded: panelState.toolbarExpanded
|
||||
}, {
|
||||
priority,
|
||||
source: { component: 'PanelHandler', panelId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,9 +267,11 @@ class PanelEventHandler {
|
||||
return emitEvent(PANEL_EVENT_TYPES.DRAG_START, {
|
||||
panelId,
|
||||
event: dragEvent,
|
||||
dragState,
|
||||
source: 'PanelHandler'
|
||||
}, { priority })
|
||||
dragState
|
||||
}, {
|
||||
priority,
|
||||
source: { component: 'PanelHandler', panelId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,9 +333,11 @@ class PanelEventHandler {
|
||||
panelId,
|
||||
event: dragEvent,
|
||||
dragState,
|
||||
duration: dragState.endTime - dragState.startTime,
|
||||
source: 'PanelHandler'
|
||||
}, { priority })
|
||||
duration: dragState.endTime - dragState.startTime
|
||||
}, {
|
||||
priority,
|
||||
source: { component: 'PanelHandler', panelId }
|
||||
})
|
||||
|
||||
// 清理拖拽状态
|
||||
this.dragStates.delete(panelId)
|
||||
@@ -353,10 +363,11 @@ class PanelEventHandler {
|
||||
this.panelStates.set(panelId, panelState)
|
||||
|
||||
return emitEvent(PANEL_EVENT_TYPES.ACTIVATED, {
|
||||
panelId,
|
||||
source: 'PanelHandler',
|
||||
timestamp: Date.now()
|
||||
}, { priority })
|
||||
panelId
|
||||
}, {
|
||||
priority,
|
||||
source: { component: 'PanelHandler', panelId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,10 +388,11 @@ class PanelEventHandler {
|
||||
this.panelStates.set(panelId, panelState)
|
||||
|
||||
return emitEvent(PANEL_EVENT_TYPES.DEACTIVATED, {
|
||||
panelId,
|
||||
source: 'PanelHandler',
|
||||
timestamp: Date.now()
|
||||
}, { priority })
|
||||
panelId
|
||||
}, {
|
||||
priority,
|
||||
source: { component: 'PanelHandler', panelId }
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -441,10 +453,12 @@ class PanelEventHandler {
|
||||
*/
|
||||
onExpand(eventData) {
|
||||
const { areaId, panelId } = eventData;
|
||||
this.emitEvent(PANEL_EVENT_TYPES.EXPAND, {
|
||||
emitEvent(PANEL_EVENT_TYPES.EXPAND, {
|
||||
areaId,
|
||||
panelId,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'PanelHandler', panelId, areaId }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -454,10 +468,12 @@ class PanelEventHandler {
|
||||
*/
|
||||
onMaximize(eventData) {
|
||||
const { areaId, panelId } = eventData;
|
||||
this.emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
|
||||
emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
|
||||
areaId,
|
||||
panelId,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'PanelHandler', panelId, areaId }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -480,10 +496,12 @@ class PanelEventHandler {
|
||||
*/
|
||||
onToggleToolbar(eventData) {
|
||||
const { areaId, panelId } = eventData;
|
||||
this.emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
|
||||
emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
|
||||
areaId,
|
||||
panelId,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'PanelHandler', panelId, areaId }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -507,11 +525,13 @@ class PanelEventHandler {
|
||||
*/
|
||||
onSizeUpdate(eventData) {
|
||||
const { areaId, panelId, size } = eventData;
|
||||
this.emitEvent('panel.size.update', {
|
||||
emitEvent('panel.size.update', {
|
||||
areaId,
|
||||
panelId,
|
||||
size,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'PanelHandler', panelId, areaId }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -567,8 +587,9 @@ class PanelEventHandler {
|
||||
return emitEvent(PANEL_EVENT_TYPES.MAXIMIZE_SYNC, {
|
||||
panelId,
|
||||
maximized,
|
||||
areaId: panelState.areaId,
|
||||
source: 'PanelHandler'
|
||||
areaId: panelState.areaId
|
||||
}, {
|
||||
source: { component: 'PanelHandler', panelId, areaId: panelState.areaId }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ class TabPageEventHandler {
|
||||
* @param {string} data.eventType - 事件类型
|
||||
*/
|
||||
async _onTabPageEvent(data) {
|
||||
const { eventType } = data;
|
||||
const eventType = data.eventType;
|
||||
|
||||
try {
|
||||
switch (eventType) {
|
||||
@@ -222,7 +222,6 @@ class TabPageEventHandler {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ TabPage事件处理错误 (${eventType}):`, error);
|
||||
eventBus.recordError(`tabPageHandler_${eventType}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,6 +590,9 @@ function ensureInstance() {
|
||||
return tabPageHandler;
|
||||
}
|
||||
|
||||
// 导出单例实例访问方法
|
||||
export const getTabPageHandler = ensureInstance;
|
||||
|
||||
// TabPage便捷操作函数
|
||||
export const tabPageActions = {
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user