修复运行异常

This commit is contained in:
zqm
2025-12-29 09:05:37 +08:00
parent 09e4076635
commit 9aad6ebc21
10 changed files with 448 additions and 281 deletions

View File

@@ -100,17 +100,23 @@
<!-- 内容区域 -->
<div class="vs-content">
<!-- 直接渲染插槽内容Render组件会自动处理children -->
<slot></slot>
<!-- 使用Render组件渲染children配置 -->
<div v-for="child in Array.isArray(children) ? children : [children]" :key="child.id" style="width: 100%; height: 100%;">
<Render
:type="child.type"
:config="child"
/>
</div>
</div>
</div>
</template>
<script setup>
import { defineProps, computed, ref, onMounted, onUnmounted, watch, defineExpose, useSlots } from 'vue'
import { defineProps, computed, ref, onMounted, onUnmounted, watch, defineExpose } from 'vue'
import { emitEvent, EVENT_TYPES, globalEventListenerManager } from './eventBus'
import TabPage from './TabPage.vue'
import Panel from './Panel.vue'
import Render from './Render.vue'
import { zIndexManager, Z_INDEX_LAYERS } from './dockLayers'
const props = defineProps({
@@ -127,7 +133,12 @@ const props = defineProps({
// 位置属性,可选
left: { type: Number, default: undefined },
top: { type: Number, default: undefined },
draggable: { type: Boolean, default: true }
draggable: { type: Boolean, default: true },
// 子组件配置
children: {
type: [Array, Object],
default: () => []
}
})
// 使用全局事件总线和拖拽管理器
@@ -149,30 +160,32 @@ const maximizedFromPosition = ref(null)
// 组件引用
const areaRef = ref(null)
// 获取插槽
const slots = useSlots();
// 不再需要获取插槽改为使用props.children
// 计算属性:是否显示标题栏
const shouldShowTitleBar = computed(() => {
// 基础条件props.showTitleBar为true
if (!props.showTitleBar) return false;
// 获取插槽内容
if (slots.default) {
const slotChildren = slots.default();
// 检查children配置
if (props.children) {
const childrenArray = Array.isArray(props.children) ? props.children : [props.children];
// 如果没有插槽内容,显示标题栏
if (slotChildren.length === 0) return true;
// 如果没有children,显示标题栏
if (childrenArray.length === 0) return true;
// 如果插槽内容不是TabPage显示标题栏
const firstChild = slotChildren[0];
if (firstChild.type.name !== 'TabPage') return true;
// 如果children不是TabPage显示标题栏
const firstChild = childrenArray[0];
if (firstChild.type !== 'TabPage') return true;
// 获取TabPage的插槽内容
const tabPageSlots = firstChild.children?.default ? firstChild.children.default() : [];
// 检查TabPage的children
const tabPageChildren = firstChild.children;
if (!tabPageChildren) return true;
const tabPageChildrenArray = Array.isArray(tabPageChildren) ? tabPageChildren : [tabPageChildren];
// 如果TabPage包含多个Panel显示标题栏
if (tabPageSlots.length !== 1) return true;
if (tabPageChildrenArray.length !== 1) return true;
// 如果TabPage只包含一个Panel不显示标题栏
return false;
@@ -275,17 +288,24 @@ const onPanelMaximize = (panelId) => {
// // console.log('🔸 Area接收最大化事件 - Panel ID:', panelId)
// 检查内容区是否只有一个Panel
const slotChildren = slots.default ? slots.default() : []
let isSinglePanel = false
// 查找TabPage组件
const tabPages = slotChildren.filter(child => child.type.name === 'TabPage')
if (tabPages.length === 1) {
// 获取TabPage的插槽内容
const tabPageSlots = tabPages[0].children?.default ? tabPages[0].children.default() : []
// 如果TabPage只有一个Panel认为是单Panel模式
isSinglePanel = tabPageSlots.length === 1
// 检查children配置
if (props.children) {
const childrenArray = Array.isArray(props.children) ? props.children : [props.children]
// 查找TabPage组件
const tabPages = childrenArray.filter(child => child.type === 'TabPage')
if (tabPages.length === 1) {
// 检查TabPage的children
const tabPageChildren = tabPages[0].children
if (tabPageChildren) {
const tabPageChildrenArray = Array.isArray(tabPageChildren) ? tabPageChildren : [tabPageChildren]
// 如果TabPage只有一个Panel认为是单Panel模式
isSinglePanel = tabPageChildrenArray.length === 1
}
}
}
// // console.log('🔸 检查是否单Panel模式:', { tabPages: tabPages.length, isSinglePanel })

View File

@@ -79,7 +79,11 @@ const mainAreaConfig = ref({
id: 'MainArea',
title: '主区域',
windowState: windowState.value,
showTitleBar: false
showTitleBar: false,
children: {
type: 'TabPage',
children: []
}
})
// 浮动区域列表 - 每个area包含panels数组
@@ -102,7 +106,27 @@ const mainAreaResizeBars = ref([])
// 检查主区域内是否有其他Area简化版
const hasAreasInMainContent = ref(false)
// Area相关事件处理
const shouldOperateAreaInsteadOfPanel = (areaId) => {
const area = floatingAreas.value.find(a => a.id === areaId);
if (!area) return false;
const childrenArray = Array.isArray(area.children) ? area.children : [area.children];
if (childrenArray.length !== 1) return false;
const tabPage = childrenArray[0];
if (tabPage.type !== 'TabPage') return false;
const tabPageChildren = tabPage.children;
const tabPageChildrenArray = Array.isArray(tabPageChildren) ? tabPageChildren : [tabPageChildren];
if (tabPageChildrenArray.length !== 1) return false;
// 检查TabPage的children是否是Panel组件
const childItem = tabPageChildrenArray[0];
if (childItem.type !== 'Panel') return false;
return true;
};
const onCloseFloatingArea = (event) => {
const id = event.areaId;
areaActions.closeFloatingArea(id);
@@ -124,27 +148,55 @@ const onUpdatePosition = (event) => {
const onMaximize = (event) => {
const panelId = event.panelId;
areaActions.toggleMaximize(panelId);
const areaId = event.areaId;
if (shouldOperateAreaInsteadOfPanel(areaId)) {
areaActions.toggleMaximize(areaId);
} else {
panelActions.maximize(panelId);
}
};
const onClosePanel = (event) => {
const onPanelClose = (event) => {
const areaId = event.areaId;
const panelId = event.panelId;
areaActions.closePanel(areaId, panelId);
const area = floatingAreas.value.find(a => a.id === areaId);
if (area && area.children) {
// 移除对应面板
for (const child of area.children) {
if (child.type === 'TabPage' && child.children && child.children.type === 'Panel') {
const panels = child.children.items || [];
const panelIndex = panels.findIndex(p => p.id === panelId);
if (panelIndex !== -1) {
panels.splice(panelIndex, 1);
// 如果没有面板了移除整个TabPage
if (panels.length === 0) {
const tabPageIndex = area.children.indexOf(child);
if (tabPageIndex !== -1) {
area.children.splice(tabPageIndex, 1);
if (shouldOperateAreaInsteadOfPanel(areaId)) {
onCloseFloatingArea({ areaId });
} else {
areaActions.closePanel(areaId, panelId);
const area = floatingAreas.value.find(a => a.id === areaId);
if (area && area.children) {
for (const child of area.children) {
if (child.type === 'TabPage' && child.children) {
// 处理TabPage的children可能是单个Panel或Panel数组
const isArray = Array.isArray(child.children);
const childrenArray = isArray ? child.children : [child.children];
// 检查每个子项是否为Panel组件
for (let i = 0; i < childrenArray.length; i++) {
const item = childrenArray[i];
if (item.type === 'Panel' && item.id === panelId) {
// 从数组中移除Panel
if (isArray) {
child.children.splice(i, 1);
} else {
// 如果是单个Panel移除整个TabPage
const tabPageIndex = area.children.indexOf(child);
if (tabPageIndex !== -1) {
area.children.splice(tabPageIndex, 1);
}
break;
}
// 如果Panel数组为空移除TabPage
if (child.children.length === 0) {
const tabPageIndex = area.children.indexOf(child);
if (tabPageIndex !== -1) {
area.children.splice(tabPageIndex, 1);
}
}
break;
}
}
break;
@@ -170,7 +222,70 @@ const handleAreaDragOver = (event) => {
};
const handleAreaDragLeave = (event) => {
globalEventActions.handleDragLeave('floating-area', event);
globalEventActions.handleDragLeave('floating-area');
};
const onPanelDragStart = (event) => {
const areaId = event.areaId;
if (shouldOperateAreaInsteadOfPanel(areaId)) {
const area = floatingAreas.value.find(a => a.id === areaId);
const startLeft = area ? (area.x || 0) : 0;
const startTop = area ? (area.y || 0) : 0;
eventBus.emit(EVENT_TYPES.AREA_DRAG_START, {
dragId: event.dragId,
areaId: areaId,
event: {
clientX: event.position.x,
clientY: event.position.y
},
element: null,
position: event.position,
clientX: event.position.x,
clientY: event.position.y,
startLeft: startLeft,
startTop: startTop,
timestamp: event.timestamp
});
}
};
const onPanelDragMove = (event) => {
const areaId = event.areaId;
if (shouldOperateAreaInsteadOfPanel(areaId)) {
eventBus.emit(EVENT_TYPES.AREA_DRAG_MOVE, {
dragId: event.dragId,
areaId: areaId,
event: {
clientX: event.position.x,
clientY: event.position.y
},
position: event.position,
clientX: event.position.x,
clientY: event.position.y,
timestamp: event.timestamp
});
}
};
const onPanelDragEnd = (event) => {
const areaId = event.areaId;
if (shouldOperateAreaInsteadOfPanel(areaId)) {
const area = floatingAreas.value.find(a => a.id === areaId);
const left = area ? (area.x || 0) : 0;
const top = area ? (area.y || 0) : 0;
eventBus.emit(EVENT_TYPES.AREA_DRAG_END, {
dragId: event.dragId,
areaId: areaId,
finalPosition: {
x: left,
y: top
},
left: left,
top: top
});
}
};
// 其他事件处理方法
@@ -285,9 +400,12 @@ const setupEventListeners = () => {
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_CLOSE, onPanelClose, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_TOOLBAR, () => emit('toggleToolbar'), { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, onPanelMaximizeSync, { 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' }));
// Resize相关事件
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_START, () => emit('dragStart'), { componentId: 'dock-layout' }));
@@ -300,8 +418,8 @@ const setupEventListeners = () => {
}, { componentId: 'dock-layout' }));
// 自定义事件
unsubscribeFunctions.push(eventBus.on('area-merged', onAreaMerged, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on('dock-zone-active', (event) => onDockZoneActive(event.zoneId), { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_MERGED, onAreaMerged, { componentId: 'dock-layout' }));
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.DOCK_ZONE_ACTIVE, (event) => onDockZoneActive(event.zoneId), { componentId: 'dock-layout' }));
return unsubscribeFunctions;
};
@@ -314,6 +432,11 @@ const cleanup = () => {
// 清理事件监听器和其他资源
console.log('🧹 开始清理DockLayout资源');
// 清理事件监听器
console.log('🔇 开始清理事件监听器');
unsubscribeFunctions.value.forEach(unsubscribe => unsubscribe());
unsubscribeFunctions.value = [];
// 清理浮动区域
floatingAreas.value = [];

View File

@@ -168,11 +168,9 @@ const props = defineProps({
// 事件订阅管理 - 使用Set避免key冲突并添加唯一标识符
const subscriptions = new Set();
const subscriptionRegistry = new Map(); // 用于追踪订阅详细信息
const subscriptionRegistry = new Map();
// 动态获取当前面板所在的Area ID
const getCurrentAreaId = () => {
// 通过DOM向上查找最近的Area容器
const panelElement = document.querySelector(`[data-panel-id="${props.id}"]`);
if (panelElement) {
const areaElement = panelElement.closest('[data-area-id]');
@@ -181,8 +179,6 @@ const getCurrentAreaId = () => {
}
}
// 备用方法:通过父组件查找
// 向上查找vs-area容器
const parentElement = document.querySelector(`[data-panel-id="${props.id}"]`)?.parentElement;
if (parentElement) {
const areaElement = parentElement.closest('.vs-area');
@@ -399,7 +395,6 @@ const onDragStart = (e) => {
const areaId = getCurrentAreaId();
// 2. 使用事件总线触发面板拖拽开始事件,包含统一的 dragId 和标准化数据格式
emitEvent(EVENT_TYPES.PANEL_DRAG_START, {
dragId: currentDragId,
panelId: props.id,
@@ -410,27 +405,9 @@ const onDragStart = (e) => {
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
})
// 3. 同时触发Area拖拽开始事件实现通过Panel标题栏拖拽Area
emitEvent(EVENT_TYPES.AREA_DRAG_START, {
dragId: currentDragId,
areaId: areaId,
event: e,
element: null,
position: { x: e.clientX, y: e.clientY },
clientX: e.clientX,
clientY: e.clientY,
startLeft: 0,
startTop: 0,
timestamp: Date.now()
}, {
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
})
// 4. 防止文本选择和默认行为
e.preventDefault()
e.stopPropagation()
// 5. 添加Document事件监听器使用一次性变量避免内存泄漏
addDocumentDragListeners()
}
};
@@ -444,7 +421,6 @@ const onDragMove = (e) => {
const areaId = getCurrentAreaId();
// 1. 使用事件总线触发面板拖拽移动事件,包含 dragId
emitEvent(EVENT_TYPES.PANEL_DRAG_MOVE, {
dragId: currentDragId,
panelId: props.id,
@@ -454,23 +430,9 @@ const onDragMove = (e) => {
}, {
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
})
// 2. 同时触发Area拖拽移动事件实现通过Panel标题栏拖拽Area
emitEvent(EVENT_TYPES.AREA_DRAG_MOVE, {
dragId: currentDragId,
areaId: areaId,
event: e,
position: { x: e.clientX, y: e.clientY },
clientX: e.clientX,
clientY: e.clientY,
timestamp: Date.now()
}, {
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
})
}
};
// 拖拽结束
const onDragEnd = () => {
if (isDragging && currentDragId) {
isDragging = false;
@@ -479,7 +441,6 @@ const onDragEnd = () => {
const areaId = getCurrentAreaId();
// 1. 使用事件总线触发面板拖拽结束事件,包含 dragId
emitEvent(EVENT_TYPES.PANEL_DRAG_END, {
dragId: currentDragId,
panelId: props.id,
@@ -489,22 +450,8 @@ const onDragEnd = () => {
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
})
// 2. 同时触发Area拖拽结束事件实现通过Panel标题栏拖拽Area
emitEvent(EVENT_TYPES.AREA_DRAG_END, {
dragId: currentDragId,
areaId: areaId,
event: null,
position: null,
timestamp: Date.now()
}, {
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
})
// 3. 使用统一的清理方法,确保一致性和完整性
cleanupDragEventListeners()
// 4. 重置 dragId
currentDragId = null
currentDragId = null;
cleanupDragEventListeners();
}
};
@@ -652,7 +599,7 @@ onUnmounted(() => {
try {
// 1. 立即设置标志位,防止新的异步操作
isDragging = false
isDragging.value = false
// 2. 同步清理所有可以直接清理的资源
const cleanupResult = cleanupEventListeners()
@@ -662,24 +609,12 @@ onUnmounted(() => {
console.log(`[Panel:${props.id}] 组件清理结果:`, cleanupResult)
}
// 4. 清理超时保护 - 简化版本,防止无限等待
const cleanupTimeout = setTimeout(() => {
console.warn(`[Panel:${props.id}] 清理超时,但继续卸载`)
}, 200) // 缩短超时时间
// 5. 清理超时定时器,确保不会泄露
setTimeout(() => {
clearTimeout(cleanupTimeout)
}, 250)
} catch (error) {
console.error(`[Panel:${props.id}] 清理过程中出现异常:`, error)
// 即使出现异常,也要尝试强制清理
try {
isDragging = false
// 强制清理事件监听器
cleanupEventListeners()
isDragging.value = false
} catch (forceError) {
console.error(`[Panel:${props.id}] 强制清理也失败:`, forceError)
}

View File

@@ -74,7 +74,8 @@ const componentProps = computed(() => {
showTitleBar: config.showTitleBar !== false,
left: config.left,
top: config.top,
draggable: config.draggable !== false
draggable: config.draggable !== false,
children: config.children
}
case 'TabPage':
@@ -82,7 +83,8 @@ const componentProps = computed(() => {
id: config.id,
title: config.title || '标签页',
showTabs: config.showTabs !== false,
tabPosition: config.tabPosition || 'top'
tabPosition: config.tabPosition || 'top',
children: config.children
}
case 'Panel':
@@ -125,7 +127,7 @@ const componentListeners = computed(() => {
}
allListeners['area-merged'] = (event) => {
// if (props.debug) console.log(`[Render-Area ${props.config.id}] area-merged:`, event)
eventBus.emit('area-merged', { ...event, areaId: props.config.id })
eventBus.emit(EVENT_TYPES.AREA_MERGED, { ...event, areaId: props.config.id })
}
allListeners['toggleCollapse'] = (event) => {
// if (props.debug) console.log(`[Render-Area ${props.config.id}] toggleCollapse:`, event)

View File

@@ -33,13 +33,6 @@ const props = withDefaults(defineProps<Props>(), {
resizeStep: 10
})
// 事件定义
interface Emits {
resize: [newSize: number]
resizeStart: []
resizeEnd: []
}
// 使用事件总线替代直接emit
// 响应式状态
@@ -167,6 +160,10 @@ defineExpose({
background-color: rgba(64, 158, 255, 0.1);
}
.resize-bar-hover {
background-color: rgba(64, 158, 255, 0.1);
}
.resize-bar-horizontal {
cursor: col-resize;
border-left: 1px solid transparent;
@@ -205,6 +202,10 @@ defineExpose({
background-color: rgba(64, 158, 255, 0.6);
}
.resize-bar-hover .resize-bar-line {
background-color: rgba(64, 158, 255, 0.6);
}
.resize-bar:active .resize-bar-line {
background-color: var(--dock-primary-color, #409eff);
}

View File

@@ -149,6 +149,11 @@ const props = defineProps({
type: String,
default: 'top',
validator: (value) => ['top', 'right', 'bottom', 'left'].includes(value)
},
// 子组件配置,支持数组或单个对象
children: {
type: [Array, Object],
default: null
}
})

View File

@@ -52,9 +52,56 @@ export const EVENT_TYPES = {
AREA_DRAG_START: 'area.drag.start',
AREA_DRAG_MOVE: 'area.drag.move',
AREA_DRAG_END: 'area.drag.end',
AREA_DRAG_CANCEL: 'area.drag.cancel',
AREA_DRAG_OVER: 'area.drag.over',
AREA_DRAG_LEAVE: 'area.drag.leave',
AREA_PANEL_CLOSED: 'area.panel.closed',
AREA_MERGE_REQUEST: 'area.merge.request',
AREA_MERGED: 'area.merged',
// 基础事件
AREA_CREATED: 'area.created',
AREA_DESTROYED: 'area.destroyed',
AREA_UPDATED: 'area.updated',
AREA_ERROR: 'area.error',
// 浮动区域管理
AREA_FLOATING_CREATE: 'area.floating.create',
AREA_FLOATING_CLOSE: 'area.floating.close',
AREA_FLOATING_UPDATE_POSITION: 'area.floating.updatePosition',
AREA_FLOATING_ZINDEX_CHANGE: 'area.floating.zindex.change',
// Area操作
AREA_MAXIMIZE: 'area.maximize',
AREA_RESTORE: 'area.restore',
AREA_COLLAPSE: 'area.collapse',
AREA_EXPAND: 'area.expand',
AREA_TOGGLE_TOOLBAR: 'area.toggleToolbar',
// 停靠相关
AREA_DOCK_CENTER: 'area.dock.center',
AREA_DOCK_EDGE: 'area.dock.edge',
AREA_DOCK_SPLIT: 'area.dock.split',
AREA_MERGE: 'area.merge',
AREA_UNMERGE: 'area.unmerge',
// 调整大小
AREA_RESIZE_START: 'area.resize.start',
AREA_RESIZE: 'area.resize',
AREA_RESIZE_END: 'area.resize.end',
AREA_RATIO_CHANGE: 'area.ratio.change',
AREA_HIDE: 'area.hide',
AREA_SHOW: 'area.show',
AREA_MINIMIZE: 'area.minimize',
AREA_RESTORE_FROM_MINIMIZE: 'area.restoreFromMinimize',
AREA_ZINDEX_MANAGEMENT: 'area.zindex.management',
AREA_ACTIVATION: 'area.activation',
AREA_DEACTIVATION: 'area.deactivation',
AREA_CONTENT_CHANGE: 'area.content.change',
AREA_PANEL_COUNT_CHANGE: 'area.panel.count.change',
AREA_TABPAGE_MERGE: 'area.tabpage.merge',
AREA_TABPAGE_SYNC: 'area.tabpage.sync',
AREA_PANEL_SYNC: 'area.panel.sync',
PANEL_MAXIMIZE_SYNC: 'panel.maximize.sync',
PANEL_MAXIMIZE: 'panel.maximize',
@@ -67,6 +114,7 @@ export const EVENT_TYPES = {
PANEL_DRAG_START: 'panel.drag.start',
PANEL_DRAG_MOVE: 'panel.drag.move',
PANEL_DRAG_END: 'panel.drag.end',
PANEL_DRAG_CANCEL: 'panel.drag.cancel',
PANEL_DRAG_START_FROM_TABPAGE: 'panel.drag.start.fromTabPage',
PANEL_DRAG_MOVE_FROM_TABPAGE: 'panel.drag.move.fromTabPage',
PANEL_DRAG_END_FROM_TABPAGE: 'panel.drag.end.fromTabPage',
@@ -78,6 +126,12 @@ export const EVENT_TYPES = {
TAB_DRAG_MOVE: 'tab.drag.move',
TAB_DRAG_END: 'tab.drag.end',
// 标签页拖拽事件
TABPAGE_DRAG_START: 'tabpage.drag.start',
TABPAGE_DRAG_MOVE: 'tabpage.drag.move',
TABPAGE_DRAG_END: 'tabpage.drag.end',
TABPAGE_DRAG_CANCEL: 'tabpage.drag.cancel',
INDICATOR_SHOW: 'indicator.show',
INDICATOR_HIDE: 'indicator.hide',
INDICATOR_UPDATE: 'indicator.update',
@@ -87,7 +141,10 @@ export const EVENT_TYPES = {
RESIZE_END: 'resize.end',
WINDOW_STATE_CHANGE: 'window.state.change',
Z_INDEX_UPDATE: 'zIndex.update'
Z_INDEX_UPDATE: 'zIndex.update',
// Dock相关事件
DOCK_ZONE_ACTIVE: 'dock.zone.active'
}
export const PRIORITY_LEVELS = {
@@ -278,6 +335,11 @@ class EnhancedEventBus {
retries = 0
} = options
const definedEventTypes = Object.values(EVENT_TYPES)
if (!definedEventTypes.includes(eventType)) {
console.warn(`⚠️ [EventBus] 未定义的事件类型: "${eventType}"。请在 EVENT_TYPES 中定义此事件类型。`)
}
const wrappedHandler = async (event) => {
const startTime = performance.now()

View File

@@ -5,60 +5,6 @@
import { eventBus, EVENT_TYPES } from '../eventBus';
// Area事件类型常量仅包含EVENT_TYPES中没有的
export const AREA_EVENT_TYPES = {
// 基础事件
AREA_CREATED: 'area.created',
AREA_DESTROYED: 'area.destroyed',
AREA_UPDATED: 'area.updated',
// 浮动区域管理
AREA_FLOATING_CREATE: 'area.floating.create',
AREA_FLOATING_CLOSE: 'area.floating.close',
AREA_FLOATING_UPDATE_POSITION: 'area.floating.updatePosition',
AREA_FLOATING_ZINDEX_CHANGE: 'area.floating.zindex.change',
// Area操作
AREA_MAXIMIZE: 'area.maximize',
AREA_RESTORE: 'area.restore',
AREA_COLLAPSE: 'area.collapse',
AREA_EXPAND: 'area.expand',
AREA_TOGGLE_TOOLBAR: 'area.toggleToolbar',
// 停靠相关
AREA_DOCK_CENTER: 'area.dock.center',
AREA_DOCK_EDGE: 'area.dock.edge',
AREA_DOCK_SPLIT: 'area.dock.split',
AREA_MERGE: 'area.merge',
AREA_UNMERGE: 'area.unmerge',
// 调整大小
AREA_RESIZE_START: 'area.resize.start',
AREA_RESIZE: 'area.resize',
AREA_RESIZE_END: 'area.resize.end',
AREA_RATIO_CHANGE: 'area.ratio.change',
// 隐藏/显示
AREA_HIDE: 'area.hide',
AREA_SHOW: 'area.show',
AREA_MINIMIZE: 'area.minimize',
AREA_RESTORE_FROM_MINIMIZE: 'area.restoreFromMinimize',
// 层级管理
AREA_ZINDEX_MANAGEMENT: 'area.zindex.management',
AREA_ACTIVATION: 'area.activation',
AREA_DEACTIVATION: 'area.deactivation',
// 内容管理
AREA_CONTENT_CHANGE: 'area.content.change',
AREA_PANEL_COUNT_CHANGE: 'area.panel.count.change',
AREA_TABPAGE_MERGE: 'area.tabpage.merge',
// 与其他组件的交互
AREA_TABPAGE_SYNC: 'area.tabpage.sync',
AREA_PANEL_SYNC: 'area.panel.sync'
};
// Area状态管理
class AreaStateManager {
constructor() {
@@ -96,7 +42,7 @@ class AreaStateManager {
this.states.set(areaId, newState);
// 触发状态更新事件
eventBus.emit(AREA_EVENT_TYPES.AREA_UPDATED, {
eventBus.emit(EVENT_TYPES.AREA_UPDATED, {
areaId,
oldState: currentState,
newState,
@@ -132,7 +78,7 @@ class AreaStateManager {
this.states.set(areaId, floatingArea);
// 触发创建事件
eventBus.emit(AREA_EVENT_TYPES.AREA_FLOATING_CREATE, {
eventBus.emit(EVENT_TYPES.AREA_FLOATING_CREATE, {
areaId,
config: floatingArea,
timestamp: Date.now()
@@ -154,7 +100,7 @@ class AreaStateManager {
this.states.delete(areaId);
// 触发关闭事件
eventBus.emit(AREA_EVENT_TYPES.AREA_FLOATING_CLOSE, {
eventBus.emit(EVENT_TYPES.AREA_FLOATING_CLOSE, {
areaId,
config: area,
timestamp: Date.now()
@@ -183,7 +129,7 @@ class AreaStateManager {
this.states.set(areaId, updatedArea);
// 触发位置更新事件
eventBus.emit(AREA_EVENT_TYPES.AREA_FLOATING_UPDATE_POSITION, {
eventBus.emit(EVENT_TYPES.AREA_FLOATING_UPDATE_POSITION, {
areaId,
position: {
left: updatedArea.x,
@@ -207,7 +153,7 @@ class AreaStateManager {
hiddenAt: Date.now()
});
eventBus.emit(AREA_EVENT_TYPES.AREA_HIDE, {
eventBus.emit(EVENT_TYPES.AREA_HIDE, {
areaId,
reason: 'hidden_list',
timestamp: Date.now()
@@ -226,7 +172,7 @@ class AreaStateManager {
restoredAt: Date.now()
});
eventBus.emit(AREA_EVENT_TYPES.AREA_SHOW, {
eventBus.emit(EVENT_TYPES.AREA_SHOW, {
areaId,
reason: 'restored_from_hidden',
timestamp: Date.now()
@@ -409,7 +355,7 @@ class AreaEventHandler {
const areaId = this.areaStateManager.createFloatingArea(areaConfig);
// 触发成功事件
eventBus.emit(AREA_EVENT_TYPES.AREA_CREATED, {
eventBus.emit(EVENT_TYPES.AREA_CREATED, {
areaId,
config: areaConfig,
source: 'addFloatingPanel',
@@ -419,7 +365,7 @@ class AreaEventHandler {
return areaId;
} catch (error) {
console.error('创建浮动Area时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
eventBus.emit(EVENT_TYPES.AREA_ERROR, {
operation: 'addFloatingPanel',
error: error.message,
timestamp: Date.now()
@@ -442,7 +388,7 @@ class AreaEventHandler {
}
// 触发关闭开始事件
eventBus.emit(AREA_EVENT_TYPES.AREA_CLOSE, {
eventBus.emit(EVENT_TYPES.AREA_CLOSE, {
areaId,
config: area,
source: 'closeFloatingArea',
@@ -459,7 +405,7 @@ class AreaEventHandler {
this.areaStateManager.clearResizeState(areaId);
// 触发关闭完成事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DESTROYED, {
eventBus.emit(EVENT_TYPES.AREA_DESTROYED, {
areaId,
source: 'closeFloatingArea',
timestamp: Date.now()
@@ -469,7 +415,7 @@ class AreaEventHandler {
return success;
} catch (error) {
console.error('关闭浮动Area时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
eventBus.emit(EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'closeFloatingArea',
error: error.message,
@@ -519,7 +465,7 @@ class AreaEventHandler {
}
// 触发合并完成事件
eventBus.emit(AREA_EVENT_TYPES.AREA_MERGE, {
eventBus.emit(EVENT_TYPES.AREA_MERGE, {
sourceAreaId: sourceArea.id,
targetAreaHasContent,
timestamp: Date.now()
@@ -527,7 +473,7 @@ class AreaEventHandler {
} catch (error) {
console.error('处理Area合并事件时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
eventBus.emit(EVENT_TYPES.AREA_ERROR, {
operation: 'onAreaMerged',
eventData,
error: error.message,
@@ -556,7 +502,7 @@ class AreaEventHandler {
});
// 触发折叠/展开事件
eventBus.emit(newCollapsedState ? AREA_EVENT_TYPES.AREA_COLLAPSE : AREA_EVENT_TYPES.AREA_EXPAND, {
eventBus.emit(newCollapsedState ? EVENT_TYPES.AREA_COLLAPSE : EVENT_TYPES.AREA_EXPAND, {
areaId,
collapsed: newCollapsedState,
timestamp: Date.now()
@@ -565,7 +511,7 @@ class AreaEventHandler {
return true;
} catch (error) {
console.error('切换Area折叠状态时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
eventBus.emit(EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'toggleCollapse',
error: error.message,
@@ -595,16 +541,16 @@ class AreaEventHandler {
});
// 触发工具栏切换事件
eventBus.emit(AREA_EVENT_TYPES.AREA_TOGGLE_TOOLBAR, {
eventBus.emit(EVENT_TYPES.AREA_TOGGLE_TOOLBAR, {
areaId,
expanded: newToolbarState,
expanded: toolbarExpanded,
timestamp: Date.now()
});
return true;
} catch (error) {
console.error('切换Area工具栏状态时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
eventBus.emit(EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'toggleToolbar',
error: error.message,
@@ -637,7 +583,7 @@ class AreaEventHandler {
});
// 触发最大化/还原事件
eventBus.emit(isCurrentlyMaximized ? AREA_EVENT_TYPES.AREA_RESTORE : AREA_EVENT_TYPES.AREA_MAXIMIZE, {
eventBus.emit(isCurrentlyMaximized ? EVENT_TYPES.AREA_RESTORE : EVENT_TYPES.AREA_MAXIMIZE, {
areaId,
windowState: newWindowState,
timestamp: Date.now()
@@ -651,7 +597,7 @@ class AreaEventHandler {
return true;
} catch (error) {
console.error('切换Area最大化状态时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
eventBus.emit(EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'toggleMaximize',
error: error.message,
@@ -677,14 +623,14 @@ class AreaEventHandler {
});
// 触发激活事件
eventBus.emit(AREA_EVENT_TYPES.AREA_ACTIVATION, {
eventBus.emit(EVENT_TYPES.AREA_ACTIVATION, {
areaId,
timestamp: Date.now()
});
} catch (error) {
console.error('激活Area时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
eventBus.emit(EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'activateArea',
error: error.message,
@@ -736,7 +682,7 @@ class AreaEventHandler {
_storeHiddenAreaTabPages(areaId, tabPages) {
try {
// 将TabPage信息存储到历史记录中
eventBus.emit(AREA_EVENT_TYPES.AREA_HIDE, {
eventBus.emit(EVENT_TYPES.AREA_HIDE, {
areaId,
reason: 'merge_with_content',
tabPages: [...tabPages],
@@ -773,8 +719,42 @@ class AreaEventHandler {
this.areaListeners.set(eventType, listener);
});
// 监听 AREA_EVENT_TYPES 中的事件
const areaEventTypes = Object.values(AREA_EVENT_TYPES);
// 监听 Area相关事件
const areaEventTypes = [
EVENT_TYPES.AREA_CREATED,
EVENT_TYPES.AREA_DESTROYED,
EVENT_TYPES.AREA_UPDATED,
EVENT_TYPES.AREA_FLOATING_CREATE,
EVENT_TYPES.AREA_FLOATING_CLOSE,
EVENT_TYPES.AREA_FLOATING_UPDATE_POSITION,
EVENT_TYPES.AREA_FLOATING_ZINDEX_CHANGE,
EVENT_TYPES.AREA_MAXIMIZE,
EVENT_TYPES.AREA_RESTORE,
EVENT_TYPES.AREA_COLLAPSE,
EVENT_TYPES.AREA_EXPAND,
EVENT_TYPES.AREA_TOGGLE_TOOLBAR,
EVENT_TYPES.AREA_DOCK_CENTER,
EVENT_TYPES.AREA_DOCK_EDGE,
EVENT_TYPES.AREA_DOCK_SPLIT,
EVENT_TYPES.AREA_MERGE,
EVENT_TYPES.AREA_UNMERGE,
EVENT_TYPES.AREA_RESIZE_START,
EVENT_TYPES.AREA_RESIZE,
EVENT_TYPES.AREA_RESIZE_END,
EVENT_TYPES.AREA_RATIO_CHANGE,
EVENT_TYPES.AREA_HIDE,
EVENT_TYPES.AREA_SHOW,
EVENT_TYPES.AREA_MINIMIZE,
EVENT_TYPES.AREA_RESTORE_FROM_MINIMIZE,
EVENT_TYPES.AREA_ZINDEX_MANAGEMENT,
EVENT_TYPES.AREA_ACTIVATION,
EVENT_TYPES.AREA_DEACTIVATION,
EVENT_TYPES.AREA_CONTENT_CHANGE,
EVENT_TYPES.AREA_PANEL_COUNT_CHANGE,
EVENT_TYPES.AREA_TABPAGE_MERGE,
EVENT_TYPES.AREA_TABPAGE_SYNC,
EVENT_TYPES.AREA_PANEL_SYNC
];
areaEventTypes.forEach(eventType => {
const listener = this._onAreaEvent;
eventBus.on(eventType, listener, {
@@ -804,25 +784,25 @@ class AreaEventHandler {
case EVENT_TYPES.AREA_DRAG_END:
await this._handleAreaDragEnd(data);
break;
case AREA_EVENT_TYPES.AREA_DOCK_CENTER:
case EVENT_TYPES.AREA_DOCK_CENTER:
await this._handleAreaDockCenter(data);
break;
case AREA_EVENT_TYPES.AREA_MERGE:
case EVENT_TYPES.AREA_MERGE:
await this._handleAreaMerge(data);
break;
case AREA_EVENT_TYPES.AREA_RESIZE_START:
case EVENT_TYPES.AREA_RESIZE_START:
await this._handleAreaResizeStart(data);
break;
case AREA_EVENT_TYPES.AREA_RESIZE:
case EVENT_TYPES.AREA_RESIZE:
await this._handleAreaResize(data);
break;
case AREA_EVENT_TYPES.AREA_RESIZE_END:
case EVENT_TYPES.AREA_RESIZE_END:
await this._handleAreaResizeEnd(data);
break;
case AREA_EVENT_TYPES.AREA_FLOATING_CREATE:
case EVENT_TYPES.AREA_FLOATING_CREATE:
await this._handleFloatingAreaCreate(data);
break;
case AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT:
case EVENT_TYPES.AREA_ZINDEX_MANAGEMENT:
await this._handleAreaZIndexManagement(data);
break;
default:
@@ -854,7 +834,7 @@ class AreaEventHandler {
this.activeAreas.add(areaId);
// 触发层级管理
eventBus.emit(AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT, {
eventBus.emit(EVENT_TYPES.AREA_ZINDEX_MANAGEMENT, {
areaId,
action: 'activate',
reason: 'drag_start'
@@ -889,7 +869,7 @@ class AreaEventHandler {
}
// 触发拖拽移动事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_MOVE, {
eventBus.emit(EVENT_TYPES.AREA_DRAG_MOVE, {
areaId,
delta: { x: deltaX, y: deltaY },
position: { x: event.clientX, y: event.clientY },
@@ -930,7 +910,7 @@ class AreaEventHandler {
dragState.duration = dragDuration;
// 触发拖拽结束事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_END, {
eventBus.emit(EVENT_TYPES.AREA_DRAG_END, {
areaId,
dragInfo: {
duration: dragDuration,
@@ -959,7 +939,7 @@ class AreaEventHandler {
// 验证停靠条件
if (!areaState || !areaState.tabPages || areaState.tabPages.length === 0) {
eventBus.emit(AREA_EVENT_TYPES.AREA_DOCK_CENTER, {
eventBus.emit(EVENT_TYPES.AREA_DOCK_CENTER, {
areaId,
success: false,
reason: 'invalid_area_state',
@@ -979,7 +959,7 @@ class AreaEventHandler {
};
// 触发停靠成功事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DOCK_CENTER, dockingResult);
eventBus.emit(EVENT_TYPES.AREA_DOCK_CENTER, dockingResult);
// 如果停靠成功,从浮动区域移除
if (dockingResult.success && areaState.type === 'floating') {
@@ -1015,7 +995,7 @@ class AreaEventHandler {
};
// 触发合并事件
eventBus.emit(AREA_EVENT_TYPES.AREA_MERGE, mergeResult);
eventBus.emit(EVENT_TYPES.AREA_MERGE, mergeResult);
// 隐藏源Area保存到隐藏列表
this.areaStateManager.addToHiddenList(sourceAreaId);
@@ -1038,7 +1018,7 @@ class AreaEventHandler {
});
// 触发调整大小开始事件
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_START, {
eventBus.emit(EVENT_TYPES.AREA_RESIZE_START, {
areaId,
resizeType,
direction,
@@ -1072,7 +1052,7 @@ class AreaEventHandler {
}
// 触发调整大小事件
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE, {
eventBus.emit(EVENT_TYPES.AREA_RESIZE, {
areaId,
size,
delta,
@@ -1110,7 +1090,7 @@ class AreaEventHandler {
}
// 触发调整大小结束事件
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_END, {
eventBus.emit(EVENT_TYPES.AREA_RESIZE_END, {
areaId,
resizeInfo: {
duration: resizeDuration,
@@ -1147,7 +1127,7 @@ class AreaEventHandler {
});
// 触发层级管理事件
eventBus.emit(AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT, {
eventBus.emit(EVENT_TYPES.AREA_ZINDEX_MANAGEMENT, {
areaId,
action: 'create_floating',
zIndex,
@@ -1350,7 +1330,7 @@ export const areaActions = {
* @param {string} source - 拖拽源
*/
startDrag: (areaId, event, source = 'direct') => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_START, {
eventBus.emit(EVENT_TYPES.AREA_DRAG_START, {
areaId,
event,
source,
@@ -1364,7 +1344,7 @@ export const areaActions = {
* @param {Event} event - 拖拽事件
*/
moveDrag: (areaId, event) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_MOVE, {
eventBus.emit(EVENT_TYPES.AREA_DRAG_MOVE, {
areaId,
event,
timestamp: Date.now()
@@ -1377,7 +1357,7 @@ export const areaActions = {
* @param {Event} event - 拖拽事件
*/
endDrag: (areaId, event) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_END, {
eventBus.emit(EVENT_TYPES.AREA_DRAG_END, {
areaId,
event,
timestamp: Date.now()
@@ -1391,7 +1371,7 @@ export const areaActions = {
* @param {string} mergeStrategy - 合并策略
*/
dockToCenter: (areaId, targetAreaId = 'main', mergeStrategy = 'auto') => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DOCK_CENTER, {
eventBus.emit(EVENT_TYPES.AREA_DOCK_CENTER, {
areaId,
targetAreaId,
mergeStrategy,
@@ -1407,7 +1387,7 @@ export const areaActions = {
* @param {Object} mergeOptions - 合并选项
*/
merge: (sourceAreaId, targetAreaId, mergeType = 'tabPage', mergeOptions = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_MERGE, {
eventBus.emit(EVENT_TYPES.AREA_MERGE, {
sourceAreaId,
targetAreaId,
mergeType,
@@ -1424,7 +1404,7 @@ export const areaActions = {
* @param {string} direction - 调整方向
*/
startResize: (areaId, originalSize, resizeType = 'split', direction = 'both') => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_START, {
eventBus.emit(EVENT_TYPES.AREA_RESIZE_START, {
areaId,
originalSize,
resizeType,
@@ -1440,7 +1420,7 @@ export const areaActions = {
* @param {Object} delta - 大小变化
*/
resize: (areaId, size, delta) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE, {
eventBus.emit(EVENT_TYPES.AREA_RESIZE, {
areaId,
size,
delta,
@@ -1454,7 +1434,7 @@ export const areaActions = {
* @param {Object} finalSize - 最终大小
*/
endResize: (areaId, finalSize) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_END, {
eventBus.emit(EVENT_TYPES.AREA_RESIZE_END, {
areaId,
finalSize,
timestamp: Date.now()
@@ -1467,7 +1447,7 @@ export const areaActions = {
* @param {Object} options - 选项
*/
maximize: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_MAXIMIZE, {
eventBus.emit(EVENT_TYPES.AREA_MAXIMIZE, {
areaId,
...options,
timestamp: Date.now()
@@ -1480,7 +1460,7 @@ export const areaActions = {
* @param {Object} options - 选项
*/
restore: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESTORE, {
eventBus.emit(EVENT_TYPES.AREA_RESTORE, {
areaId,
...options,
timestamp: Date.now()
@@ -1493,7 +1473,7 @@ export const areaActions = {
* @param {Object} options - 选项
*/
collapse: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_COLLAPSE, {
eventBus.emit(EVENT_TYPES.AREA_COLLAPSE, {
areaId,
...options,
timestamp: Date.now()
@@ -1506,7 +1486,7 @@ export const areaActions = {
* @param {Object} options - 选项
*/
expand: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_EXPAND, {
eventBus.emit(EVENT_TYPES.AREA_EXPAND, {
areaId,
...options,
timestamp: Date.now()
@@ -1519,7 +1499,7 @@ export const areaActions = {
* @param {Object} options - 选项
*/
close: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_CLOSE, {
eventBus.emit(EVENT_TYPES.AREA_CLOSE, {
areaId,
...options,
timestamp: Date.now()
@@ -1532,7 +1512,7 @@ export const areaActions = {
* @param {Object} options - 选项
*/
toggleToolbar: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_TOGGLE_TOOLBAR, {
eventBus.emit(EVENT_TYPES.AREA_TOGGLE_TOOLBAR, {
areaId,
...options,
timestamp: Date.now()

View File

@@ -3,7 +3,7 @@
* 统一管理所有组件的拖拽状态,提供拖拽历史、性能监控、冲突检测等功能
*/
import { eventBus } from '../eventBus';
import { eventBus, EVENT_TYPES } from '../eventBus';
import { GLOBAL_EVENT_TYPES, globalEventActions } from './GlobalEventManager';
// 拖拽状态类型
@@ -541,11 +541,11 @@ class DragStateManager {
const dragEvents = [
// Panel拖拽事件
'panel.drag.start', 'panel.drag.move', 'panel.drag.end', 'panel.drag.cancel',
EVENT_TYPES.PANEL_DRAG_START, EVENT_TYPES.PANEL_DRAG_MOVE, EVENT_TYPES.PANEL_DRAG_END, EVENT_TYPES.PANEL_DRAG_CANCEL,
// TabPage拖拽事件
'tabpage.drag.start', 'tabpage.drag.move', 'tabpage.drag.end', 'tabpage.drag.cancel',
EVENT_TYPES.TABPAGE_DRAG_START, EVENT_TYPES.TABPAGE_DRAG_MOVE, EVENT_TYPES.TABPAGE_DRAG_END, EVENT_TYPES.TABPAGE_DRAG_CANCEL,
// Area拖拽事件
'area.drag.start', 'area.drag.move', 'area.drag.end', 'area.drag.cancel'
EVENT_TYPES.AREA_DRAG_START, EVENT_TYPES.AREA_DRAG_MOVE, EVENT_TYPES.AREA_DRAG_END, EVENT_TYPES.AREA_DRAG_CANCEL
];
dragEvents.forEach(eventType => {
@@ -570,11 +570,11 @@ class DragStateManager {
// 清理事件监听器
const dragEvents = [
// Panel拖拽事件
'panel.drag.start', 'panel.drag.move', 'panel.drag.end', 'panel.drag.cancel',
EVENT_TYPES.PANEL_DRAG_START, EVENT_TYPES.PANEL_DRAG_MOVE, EVENT_TYPES.PANEL_DRAG_END, EVENT_TYPES.PANEL_DRAG_CANCEL,
// TabPage拖拽事件
'tabpage.drag.start', 'tabpage.drag.move', 'tabpage.drag.end', 'tabpage.drag.cancel',
EVENT_TYPES.TABPAGE_DRAG_START, EVENT_TYPES.TABPAGE_DRAG_MOVE, EVENT_TYPES.TABPAGE_DRAG_END, EVENT_TYPES.TABPAGE_DRAG_CANCEL,
// Area拖拽事件
'area.drag.start', 'area.drag.move', 'area.drag.end', 'area.drag.cancel'
EVENT_TYPES.AREA_DRAG_START, EVENT_TYPES.AREA_DRAG_MOVE, EVENT_TYPES.AREA_DRAG_END, EVENT_TYPES.AREA_DRAG_CANCEL
];
dragEvents.forEach(eventType => {
@@ -608,22 +608,39 @@ class DragStateManager {
const monitorId = globalEventActions.startMonitor(`drag_${data.eventType}`);
try {
const { eventType = data.type, dragId, componentType, sourceElement } = data;
const { eventType = data.type, dragId, componentType: providedComponentType, sourceElement } = data;
console.log('🔍 _onDragEvent 接收到的数据:', { eventType, dragId, componentType, data });
console.log('🔍 _onDragEvent 接收到的数据:', { eventType, dragId, componentType: providedComponentType, data });
// 推断组件类型
let actualComponentType = componentType;
// 改进从事件类型直接推断组件类型优先级高于提供的componentType
let actualComponentType = providedComponentType;
// 1. 优先从eventType推断组件类型最可靠
if (!actualComponentType) {
if (data.panelId) {
if (eventType.includes('panel.')) {
actualComponentType = 'panel';
} else if (data.tabIndex !== undefined) {
} else if (eventType.includes('tabpage.')) {
actualComponentType = 'tabpage';
} else if (data.areaId) {
} else if (eventType.includes('area.')) {
actualComponentType = 'area';
} else {
// 2. 如果事件类型中没有组件类型信息,再根据事件数据推断
if (data.panelId) {
actualComponentType = 'panel';
} else if (data.tabIndex !== undefined || data.tabPageId) {
actualComponentType = 'tabpage';
} else if (data.areaId) {
actualComponentType = 'area';
}
}
}
// 3. 确保组件类型有效
if (!actualComponentType) {
console.warn('⚠️ 无法推断组件类型,使用默认值 "panel"', data);
actualComponentType = 'panel';
}
// 从事件数据中提取 dragId如果没有则使用统一的生成方法
let actualDragId = dragId || this._generateDragId(actualComponentType);
@@ -637,28 +654,29 @@ class DragStateManager {
sourceElement: sourceElement || data.element
};
// 改进使用EVENT_TYPES常量替代字符串事件类型
switch (eventType) {
case 'panel.drag.start':
case 'tabpage.drag.start':
case 'area.drag.start':
case EVENT_TYPES.PANEL_DRAG_START:
case EVENT_TYPES.TABPAGE_DRAG_START:
case EVENT_TYPES.AREA_DRAG_START:
await this._handleDragStart(dragData);
break;
case 'panel.drag.move':
case 'tabpage.drag.move':
case 'area.drag.move':
case EVENT_TYPES.PANEL_DRAG_MOVE:
case EVENT_TYPES.TABPAGE_DRAG_MOVE:
case EVENT_TYPES.AREA_DRAG_MOVE:
await this._handleDragMove(dragData);
break;
case 'panel.drag.end':
case 'tabpage.drag.end':
case 'area.drag.end':
case EVENT_TYPES.PANEL_DRAG_END:
case EVENT_TYPES.TABPAGE_DRAG_END:
case EVENT_TYPES.AREA_DRAG_END:
await this._handleDragEnd(dragData);
break;
case 'panel.drag.cancel':
case 'tabpage.drag.cancel':
case 'area.drag.cancel':
case EVENT_TYPES.PANEL_DRAG_CANCEL:
case EVENT_TYPES.TABPAGE_DRAG_CANCEL:
case EVENT_TYPES.AREA_DRAG_CANCEL:
await this._handleDragCancel(dragData);
break;
}
@@ -690,8 +708,29 @@ class DragStateManager {
// 检查是否已存在相同 dragId 的拖拽状态
if (this.activeDrags.has(actualDragId)) {
console.log(`⚠️ 拖拽状态已存在: ${actualDragId},跳过创建`);
return actualDragId;
// 拖拽状态已存在,更新现有状态而不是创建新状态
const existingDragState = this.activeDrags.get(actualDragId);
// 如果是同一个拖拽操作,更新组件类型和位置
if (existingDragState && existingDragState.status === 'active') {
// 只有在组件类型不同时才更新
if (existingDragState.componentType !== componentType) {
existingDragState.componentType = componentType;
console.log(`🔄 更新拖拽状态组件类型: ${actualDragId}${existingDragState.componentType}${componentType}`);
}
// 如果提供了新位置,更新位置信息
if (position) {
existingDragState.currentPosition = { ...position };
}
// 如果提供了新的源元素,更新源元素
if (sourceElement) {
existingDragState.sourceElement = sourceElement;
}
return actualDragId;
}
}
// 创建拖拽状态

View File

@@ -3,7 +3,7 @@
* 对所有事件处理器进行集成测试、性能监控和优化建议
*/
import { eventBus } from '../eventBus';
import { eventBus, EVENT_TYPES } from '../eventBus';
import { panelHandler, PANEL_EVENT_TYPES } from './PanelHandler';
import tabPageHandler, { TABPAGE_EVENT_TYPES } from './TabPageHandler';
import areaHandler, { AREA_EVENT_TYPES } from './AreaHandler';
@@ -1048,7 +1048,7 @@ class IntegrationTester {
const startTime = performance.now();
// 模拟拖拽开始
eventBus.emit('panel.drag.start', {
eventBus.emit(EVENT_TYPES.PANEL_DRAG_START, {
dragId: 'test-panel-drag',
panelId: 'test-panel-drag-id',
startPosition: { x: 100, y: 100 }
@@ -1056,7 +1056,7 @@ class IntegrationTester {
// 模拟拖拽移动
for (let i = 0; i < 10; i++) {
eventBus.emit('panel.drag.move', {
eventBus.emit(EVENT_TYPES.PANEL_DRAG_MOVE, {
dragId: 'test-panel-drag',
currentPosition: { x: 100 + i * 10, y: 100 + i * 5 }
});
@@ -1064,7 +1064,7 @@ class IntegrationTester {
}
// 模拟拖拽结束
eventBus.emit('panel.drag.end', {
eventBus.emit(EVENT_TYPES.PANEL_DRAG_END, {
dragId: 'test-panel-drag',
finalPosition: { x: 200, y: 150 },
success: true
@@ -1083,18 +1083,18 @@ class IntegrationTester {
async _testTabPageDrag(result) {
const startTime = performance.now();
eventBus.emit('tabpage.drag.start', {
eventBus.emit(EVENT_TYPES.TABPAGE_DRAG_START, {
dragId: 'test-tabpage-drag',
tabPageId: 'test-tabpage-drag-id',
startPosition: { x: 50, y: 50 }
});
eventBus.emit('tabpage.drag.move', {
eventBus.emit(EVENT_TYPES.TABPAGE_DRAG_MOVE, {
dragId: 'test-tabpage-drag',
currentPosition: { x: 150, y: 100 }
});
eventBus.emit('tabpage.drag.end', {
eventBus.emit(EVENT_TYPES.TABPAGE_DRAG_END, {
dragId: 'test-tabpage-drag',
finalPosition: { x: 150, y: 100 },
success: true
@@ -1113,18 +1113,18 @@ class IntegrationTester {
async _testAreaDrag(result) {
const startTime = performance.now();
eventBus.emit('area.drag.start', {
eventBus.emit(EVENT_TYPES.AREA_DRAG_START, {
dragId: 'test-area-drag',
areaId: 'test-area-drag-id',
startPosition: { x: 200, y: 200 }
});
eventBus.emit('area.drag.move', {
eventBus.emit(EVENT_TYPES.AREA_DRAG_MOVE, {
dragId: 'test-area-drag',
currentPosition: { x: 300, y: 250 }
});
eventBus.emit('area.drag.end', {
eventBus.emit(EVENT_TYPES.AREA_DRAG_END, {
dragId: 'test-area-drag',
finalPosition: { x: 300, y: 250 },
success: true
@@ -1146,7 +1146,7 @@ class IntegrationTester {
// 同时启动多个拖拽
dragIds.forEach((dragId, index) => {
eventBus.emit('panel.drag.start', {
eventBus.emit(EVENT_TYPES.PANEL_DRAG_START, {
dragId,
panelId: `panel-${index}`,
startPosition: { x: 50 + index * 100, y: 50 }
@@ -1156,7 +1156,7 @@ class IntegrationTester {
// 模拟同时移动
for (let i = 0; i < 5; i++) {
dragIds.forEach((dragId, index) => {
eventBus.emit('panel.drag.move', {
eventBus.emit(EVENT_TYPES.PANEL_DRAG_MOVE, {
dragId,
currentPosition: { x: 50 + index * 100 + i * 20, y: 50 + i * 10 }
});
@@ -1166,7 +1166,7 @@ class IntegrationTester {
// 结束所有拖拽
dragIds.forEach((dragId, index) => {
eventBus.emit('panel.drag.end', {
eventBus.emit(EVENT_TYPES.PANEL_DRAG_END, {
dragId,
finalPosition: { x: 50 + index * 100 + 100, y: 50 + 50 },
success: true