Files
JoyD/AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/AreaHandler.js

1504 lines
38 KiB
JavaScript
Raw Normal View History

/**
* Area事件处理器
* 专门处理Area相关的所有事件包括浮动区域管理拖拽停靠合并等
*/
2025-12-25 13:53:52 +08:00
import { eventBus } from '../eventBus';
// Area事件类型常量
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_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',
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() {
this.states = new Map();
this.floatingAreas = new Map();
this.hiddenAreas = new Set();
this.dragState = new Map();
this.resizeState = new Map();
this.history = [];
this.maxHistorySize = 100;
}
/**
* 更新Area状态
* @param {string} areaId - Area ID
* @param {Object} updates - 状态更新
*/
updateState(areaId, updates) {
const currentState = this.states.get(areaId) || {};
const newState = { ...currentState, ...updates, lastUpdated: Date.now() };
// 记录历史
this.history.push({
areaId,
oldState: currentState,
newState,
timestamp: Date.now()
});
// 限制历史记录大小
if (this.history.length > this.maxHistorySize) {
this.history.shift();
}
this.states.set(areaId, newState);
// 触发状态更新事件
eventBus.emit(AREA_EVENT_TYPES.AREA_UPDATED, {
areaId,
oldState: currentState,
newState,
updates
});
}
/**
* 创建浮动Area
* @param {Object} areaConfig - Area配置
* @returns {string} Area ID
*/
createFloatingArea(areaConfig) {
const areaId = `floating-area-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const floatingArea = {
id: areaId,
type: 'floating',
x: areaConfig.x || 50,
y: areaConfig.y || 50,
width: areaConfig.width || 400,
height: areaConfig.height || 300,
zIndex: areaConfig.zIndex || 1001,
collapsed: areaConfig.collapsed || false,
windowState: areaConfig.windowState || 'normal', // normal, maximized, minimized
toolbarExpanded: areaConfig.toolbarExpanded !== false,
tabPages: areaConfig.tabPages || [],
createdAt: Date.now(),
...areaConfig
};
this.floatingAreas.set(areaId, floatingArea);
this.states.set(areaId, floatingArea);
// 触发创建事件
eventBus.emit(AREA_EVENT_TYPES.AREA_FLOATING_CREATE, {
areaId,
config: floatingArea,
timestamp: Date.now()
});
return areaId;
}
/**
* 关闭浮动Area
* @param {string} areaId - Area ID
*/
closeFloatingArea(areaId) {
const area = this.floatingAreas.get(areaId);
if (!area) return false;
// 清理状态
this.floatingAreas.delete(areaId);
this.states.delete(areaId);
// 触发关闭事件
eventBus.emit(AREA_EVENT_TYPES.AREA_FLOATING_CLOSE, {
areaId,
config: area,
timestamp: Date.now()
});
return true;
}
/**
* 更新浮动Area位置
* @param {string} areaId - Area ID
* @param {Object} position - 位置信息
*/
updateFloatingAreaPosition(areaId, position) {
const area = this.floatingAreas.get(areaId);
if (!area) return false;
const updatedArea = {
...area,
x: position.left || area.x,
y: position.top || area.y,
lastPositionUpdate: Date.now()
};
this.floatingAreas.set(areaId, updatedArea);
this.states.set(areaId, updatedArea);
// 触发位置更新事件
eventBus.emit(AREA_EVENT_TYPES.AREA_FLOATING_UPDATE_POSITION, {
areaId,
position: {
left: updatedArea.x,
top: updatedArea.y
},
timestamp: Date.now()
});
return true;
}
/**
* 添加到隐藏列表
* @param {string} areaId - Area ID
*/
addToHiddenList(areaId) {
this.hiddenAreas.add(areaId);
this.states.set(areaId, {
...this.states.get(areaId),
hidden: true,
hiddenAt: Date.now()
});
eventBus.emit(AREA_EVENT_TYPES.AREA_HIDE, {
areaId,
reason: 'hidden_list',
timestamp: Date.now()
});
}
/**
* 从隐藏列表移除
* @param {string} areaId - Area ID
*/
removeFromHiddenList(areaId) {
this.hiddenAreas.delete(areaId);
this.states.set(areaId, {
...this.states.get(areaId),
hidden: false,
restoredAt: Date.now()
});
eventBus.emit(AREA_EVENT_TYPES.AREA_SHOW, {
areaId,
reason: 'restored_from_hidden',
timestamp: Date.now()
});
}
/**
* 获取Area状态
* @param {string} areaId - Area ID
* @returns {Object} Area状态
*/
getState(areaId) {
return this.states.get(areaId) || {};
}
/**
* 获取浮动Area列表
* @returns {Array} 浮动Area列表
*/
getFloatingAreas() {
return Array.from(this.floatingAreas.values());
}
/**
* 获取隐藏Area列表
* @returns {Array} 隐藏Area列表
*/
getHiddenAreas() {
return Array.from(this.hiddenAreas);
}
/**
* 记录拖拽状态
* @param {string} areaId - Area ID
* @param {Object} dragInfo - 拖拽信息
*/
setDragState(areaId, dragInfo) {
this.dragState.set(areaId, {
...dragInfo,
timestamp: Date.now()
});
}
/**
* 获取拖拽状态
* @param {string} areaId - Area ID
* @returns {Object} 拖拽状态
*/
getDragState(areaId) {
return this.dragState.get(areaId);
}
/**
* 清理拖拽状态
* @param {string} areaId - Area ID
*/
clearDragState(areaId) {
this.dragState.delete(areaId);
}
/**
* 记录调整大小状态
* @param {string} areaId - Area ID
* @param {Object} resizeInfo - 调整信息
*/
setResizeState(areaId, resizeInfo) {
this.resizeState.set(areaId, {
...resizeInfo,
timestamp: Date.now()
});
}
/**
* 获取调整大小状态
* @param {string} areaId - Area ID
* @returns {Object} 调整大小状态
*/
getResizeState(areaId) {
return this.resizeState.get(areaId);
}
/**
* 清理调整大小状态
* @param {string} areaId - Area ID
*/
clearResizeState(areaId) {
this.resizeState.delete(areaId);
}
/**
* 获取历史记录
* @param {number} limit - 限制数量
* @returns {Array} 历史记录
*/
getHistory(limit = 20) {
return this.history.slice(-limit);
}
/**
* 清理过期历史记录
* @param {number} maxAge - 最大年龄毫秒
*/
cleanupHistory(maxAge = 7200000) { // 2小时
const now = Date.now();
this.history = this.history.filter(record => (now - record.timestamp) < maxAge);
}
/**
* 获取统计信息
* @returns {Object} 统计信息
*/
getStats() {
return {
totalAreas: this.states.size,
floatingAreas: this.floatingAreas.size,
hiddenAreas: this.hiddenAreas.size,
draggingAreas: this.dragState.size,
resizingAreas: this.resizeState.size,
historySize: this.history.length
};
}
}
/**
* Area事件处理器类
*/
class AreaEventHandler {
constructor() {
this.areaStateManager = new AreaStateManager();
this.areaListeners = new Map();
this.activeAreas = new Set();
this.memoryProtection = {
maxAreas: 50,
cleanupInterval: 30000,
lastCleanup: 0
};
// 绑定方法
this._onAreaEvent = this._onAreaEvent.bind(this);
this._onMemoryCheck = this._onMemoryCheck.bind(this);
this._initialize();
}
/**
* 初始化事件处理器
*/
_initialize() {
// 注册事件监听器
this._registerEventListeners();
// 启动内存保护
this._startMemoryProtection();
console.log('✅ Area事件处理器初始化完成');
}
/**
* 添加新的浮动Area从DockLayout.vue迁移
* @param {Object} options - 配置选项
* @returns {string} Area ID
*/
addFloatingPanel(options = {}) {
try {
const areaConfig = {
x: options.x || 50,
y: options.y || 50,
width: options.width || 280,
height: options.height || 200,
title: options.title || `浮动区域 ${Date.now()}`,
showTitleBar: options.showTitleBar !== false,
resizable: options.resizable !== false,
draggable: options.draggable !== false,
tabPages: options.tabPages || [],
content: options.content || this._generateRandomContent(),
...options
};
// 创建浮动Area
const areaId = this.areaStateManager.createFloatingArea(areaConfig);
// 触发成功事件
eventBus.emit(AREA_EVENT_TYPES.AREA_CREATED, {
areaId,
config: areaConfig,
source: 'addFloatingPanel',
timestamp: Date.now()
});
return areaId;
} catch (error) {
console.error('创建浮动Area时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
operation: 'addFloatingPanel',
error: error.message,
timestamp: Date.now()
});
return null;
}
}
/**
* 关闭浮动Area从DockLayout.vue迁移
* @param {string} areaId - Area ID
*/
closeFloatingArea(areaId) {
try {
// 检查Area是否存在
const area = this.areaStateManager.getState(areaId);
if (!area) {
console.warn('找不到要关闭的Area:', areaId);
return false;
}
// 触发关闭开始事件
eventBus.emit(AREA_EVENT_TYPES.AREA_CLOSE, {
areaId,
config: area,
source: 'closeFloatingArea',
timestamp: Date.now()
});
// 执行关闭逻辑
const success = this.areaStateManager.closeFloatingArea(areaId);
if (success) {
// 清理相关状态
this.activeAreas.delete(areaId);
this.areaStateManager.clearDragState(areaId);
this.areaStateManager.clearResizeState(areaId);
// 触发关闭完成事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DESTROYED, {
areaId,
source: 'closeFloatingArea',
timestamp: Date.now()
});
}
return success;
} catch (error) {
console.error('关闭浮动Area时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'closeFloatingArea',
error: error.message,
timestamp: Date.now()
});
return false;
}
}
/**
* 处理Area合并事件从DockLayout.vue迁移
* @param {Object} eventData - 合并事件数据
*/
onAreaMerged(eventData) {
try {
const { sourceArea, targetAreaHasContent } = eventData;
// 获取源Area对象
const sourceAreaState = this.areaStateManager.getState(sourceArea.id);
if (!sourceAreaState) {
console.warn('找不到源Area:', sourceArea.id);
return;
}
// 根据目标Area内容状态执行不同的隐藏逻辑
if (targetAreaHasContent) {
// 目标Area已有内容保存源Area及其TabPage组件到隐藏列表
console.log('目标Area已有内容保存源Area和TabPage组件到隐藏列表');
// 添加到隐藏列表
this.areaStateManager.addToHiddenList(sourceArea.id);
// 存储TabPage相关信息
if (sourceAreaState.tabPages) {
this._storeHiddenAreaTabPages(sourceArea.id, sourceAreaState.tabPages);
}
} else {
// 目标Area为空仅保存源Area到隐藏列表
console.log('目标Area为空保存源Area到隐藏列表');
this.areaStateManager.addToHiddenList(sourceArea.id);
}
// 从浮动区域中移除已合并的源Area
const success = this.areaStateManager.closeFloatingArea(sourceArea.id);
if (success) {
console.log('源Area已从浮动区域移除:', sourceArea.id);
}
// 触发合并完成事件
eventBus.emit(AREA_EVENT_TYPES.AREA_MERGE, {
sourceAreaId: sourceArea.id,
targetAreaHasContent,
timestamp: Date.now()
});
} catch (error) {
console.error('处理Area合并事件时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
operation: 'onAreaMerged',
eventData,
error: error.message,
timestamp: Date.now()
});
}
}
/**
* 切换折叠状态从DockLayout.vue迁移
* @param {string} areaId - Area ID
*/
toggleCollapse(areaId) {
try {
const areaState = this.areaStateManager.getState(areaId);
if (!areaState) {
console.warn('找不到Area:', areaId);
return false;
}
const newCollapsedState = !areaState.collapsed;
// 更新状态
this.areaStateManager.updateState(areaId, {
collapsed: newCollapsedState
});
// 触发折叠/展开事件
eventBus.emit(newCollapsedState ? AREA_EVENT_TYPES.AREA_COLLAPSE : AREA_EVENT_TYPES.AREA_EXPAND, {
areaId,
collapsed: newCollapsedState,
timestamp: Date.now()
});
return true;
} catch (error) {
console.error('切换Area折叠状态时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'toggleCollapse',
error: error.message,
timestamp: Date.now()
});
return false;
}
}
/**
* 切换工具栏状态从DockLayout.vue迁移
* @param {string} areaId - Area ID
*/
toggleToolbar(areaId) {
try {
const areaState = this.areaStateManager.getState(areaId);
if (!areaState) {
console.warn('找不到Area:', areaId);
return false;
}
const newToolbarState = !areaState.toolbarExpanded;
// 更新状态
this.areaStateManager.updateState(areaId, {
toolbarExpanded: newToolbarState
});
// 触发工具栏切换事件
eventBus.emit(AREA_EVENT_TYPES.AREA_TOGGLE_TOOLBAR, {
areaId,
expanded: newToolbarState,
timestamp: Date.now()
});
return true;
} catch (error) {
console.error('切换Area工具栏状态时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'toggleToolbar',
error: error.message,
timestamp: Date.now()
});
return false;
}
}
/**
* 切换最大化状态从DockLayout.vue迁移
* @param {string} areaId - Area ID
* @param {Object} options - 选项
*/
toggleMaximize(areaId, options = {}) {
try {
const areaState = this.areaStateManager.getState(areaId);
if (!areaState) {
console.warn('找不到Area:', areaId);
return false;
}
const isCurrentlyMaximized = areaState.windowState === '最大化' || areaState.windowState === 'maximized';
const newWindowState = isCurrentlyMaximized ? '正常' : '最大化';
// 更新状态
this.areaStateManager.updateState(areaId, {
windowState: newWindowState,
maximized: !isCurrentlyMaximized
});
// 触发最大化/还原事件
eventBus.emit(isCurrentlyMaximized ? AREA_EVENT_TYPES.AREA_RESTORE : AREA_EVENT_TYPES.AREA_MAXIMIZE, {
areaId,
windowState: newWindowState,
timestamp: Date.now()
});
// 如果是最大化状态激活Area
if (!isCurrentlyMaximized) {
this.activateArea(areaId);
}
return true;
} catch (error) {
console.error('切换Area最大化状态时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'toggleMaximize',
error: error.message,
timestamp: Date.now()
});
return false;
}
}
/**
* 激活Area
* @param {string} areaId - Area ID
*/
activateArea(areaId) {
try {
// 添加到活跃区域集合
this.activeAreas.add(areaId);
// 更新最后激活时间
this.areaStateManager.updateState(areaId, {
lastActivated: Date.now(),
active: true
});
// 触发激活事件
eventBus.emit(AREA_EVENT_TYPES.AREA_ACTIVATION, {
areaId,
timestamp: Date.now()
});
} catch (error) {
console.error('激活Area时出错:', error);
eventBus.emit(AREA_EVENT_TYPES.AREA_ERROR, {
areaId,
operation: 'activateArea',
error: error.message,
timestamp: Date.now()
});
}
}
/**
* 生成随机测试内容
* @private
*/
_generateRandomContent() {
const contentTypes = ['图表', '数据', '配置', '文档', '代码', '日志'];
const randomType = contentTypes[Math.floor(Math.random() * contentTypes.length)];
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD'];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
return {
type: randomType,
color: randomColor,
title: `${randomType}区域`,
data: this._generateSampleData(),
timestamp: new Date().toLocaleString()
};
}
/**
* 生成样本数据
* @private
* @param {number} dataIndex - 数据索引
*/
_generateSampleData(dataIndex = 0) {
const data = [];
for (let i = 0; i < 5; i++) {
data.push({
label: `项目 ${String.fromCharCode(65 + i)}`,
value: Math.floor(Math.random() * 100) + 10,
id: `data-${dataIndex}-${i}`
});
}
return data;
}
/**
* 存储隐藏Area的TabPage信息
* @private
*/
_storeHiddenAreaTabPages(areaId, tabPages) {
try {
// 将TabPage信息存储到历史记录中
eventBus.emit(AREA_EVENT_TYPES.AREA_HIDE, {
areaId,
reason: 'merge_with_content',
tabPages: [...tabPages],
timestamp: Date.now()
});
} catch (error) {
console.error('存储隐藏Area的TabPage信息时出错:', error);
}
}
/**
* 注册事件监听器
*/
_registerEventListeners() {
const events = Object.values(AREA_EVENT_TYPES);
events.forEach(eventType => {
const listener = this._onAreaEvent;
eventBus.on(eventType, listener, {
priority: 1,
deduplication: { type: 'TTL_BASED', ttl: 100 }
});
this.areaListeners.set(eventType, listener);
});
}
/**
* 处理Area事件
* @param {Object} data - 事件数据
*/
async _onAreaEvent(data) {
const { eventType } = data;
try {
switch (eventType) {
case AREA_EVENT_TYPES.AREA_DRAG_START:
await this._handleAreaDragStart(data);
break;
case AREA_EVENT_TYPES.AREA_DRAG_MOVE:
await this._handleAreaDragMove(data);
break;
case AREA_EVENT_TYPES.AREA_DRAG_END:
await this._handleAreaDragEnd(data);
break;
case AREA_EVENT_TYPES.AREA_DOCK_CENTER:
await this._handleAreaDockCenter(data);
break;
case AREA_EVENT_TYPES.AREA_MERGE:
await this._handleAreaMerge(data);
break;
case AREA_EVENT_TYPES.AREA_RESIZE_START:
await this._handleAreaResizeStart(data);
break;
case AREA_EVENT_TYPES.AREA_RESIZE:
await this._handleAreaResize(data);
break;
case AREA_EVENT_TYPES.AREA_RESIZE_END:
await this._handleAreaResizeEnd(data);
break;
case AREA_EVENT_TYPES.AREA_FLOATING_CREATE:
await this._handleFloatingAreaCreate(data);
break;
default:
// 记录其他事件但不处理
console.log(`📍 Area事件处理器: ${eventType}`, data);
}
} catch (error) {
console.error(`❌ Area事件处理错误 (${eventType}):`, error);
eventBus.recordError(`areaHandler_${eventType}`, error);
}
}
/**
* 处理Area拖拽开始事件
* @param {Object} data - 事件数据
*/
async _handleAreaDragStart(data) {
const { areaId, event, source = 'direct' } = data;
// 记录拖拽状态
this.areaStateManager.setDragState(areaId, {
isDragging: true,
source,
startPosition: { x: event.clientX, y: event.clientY },
startTime: Date.now(),
dragType: 'area'
});
// 激活Area
this.activeAreas.add(areaId);
// 触发层级管理
eventBus.emit(AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT, {
areaId,
action: 'activate',
reason: 'drag_start'
});
}
/**
* 处理Area拖拽移动事件
* @param {Object} data - 事件数据
*/
async _handleAreaDragMove(data) {
const { areaId, event } = data;
const dragState = this.areaStateManager.getDragState(areaId);
if (!dragState || !dragState.isDragging) return;
// 计算移动距离
const deltaX = event.clientX - dragState.startPosition.x;
const deltaY = event.clientY - dragState.startPosition.y;
// 更新拖拽状态
dragState.lastPosition = { x: event.clientX, y: event.clientY };
dragState.delta = { x: deltaX, y: deltaY };
// 更新Area位置如果是浮动Area
const areaState = this.areaStateManager.getState(areaId);
if (areaState.type === 'floating') {
this.areaStateManager.updateFloatingAreaPosition(areaId, {
left: (areaState.x || 0) + deltaX,
top: (areaState.y || 0) + deltaY
});
}
// 触发拖拽移动事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_MOVE, {
areaId,
delta: { x: deltaX, y: deltaY },
position: { x: event.clientX, y: event.clientY },
isDragging: dragState.isDragging
});
}
/**
* 处理Area拖拽结束事件
* @param {Object} data - 事件数据
*/
async _handleAreaDragEnd(data) {
const { areaId, event } = data;
const dragState = this.areaStateManager.getDragState(areaId);
if (!dragState) return;
const dragDuration = Date.now() - dragState.startTime;
const distance = dragState.delta ?
Math.sqrt(dragState.delta.x ** 2 + dragState.delta.y ** 2) : 0;
// 清理拖拽状态
dragState.isDragging = false;
dragState.endTime = Date.now();
dragState.endPosition = { x: event.clientX, y: event.clientY };
dragState.totalDistance = distance;
dragState.duration = dragDuration;
// 触发拖拽结束事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_END, {
areaId,
dragInfo: {
duration: dragDuration,
distance: distance,
startPosition: dragState.startPosition,
endPosition: dragState.endPosition,
delta: dragState.delta,
source: dragState.source
}
});
// 延迟清理拖拽状态
setTimeout(() => {
this.areaStateManager.clearDragState(areaId);
}, 1000);
}
/**
* 处理Area中心停靠事件
* @param {Object} data - 事件数据
*/
async _handleAreaDockCenter(data) {
const { areaId, targetAreaId = 'main', mergeStrategy = 'auto' } = data;
const areaState = this.areaStateManager.getState(areaId);
// 验证停靠条件
if (!areaState || !areaState.tabPages || areaState.tabPages.length === 0) {
eventBus.emit(AREA_EVENT_TYPES.AREA_DOCK_CENTER, {
areaId,
success: false,
reason: 'invalid_area_state',
message: 'Area状态无效或没有TabPage'
});
return;
}
// 执行停靠逻辑
const dockingResult = {
success: true,
areaId,
targetAreaId,
strategy: mergeStrategy,
timestamp: Date.now(),
mergedTabPages: areaState.tabPages
};
// 触发停靠成功事件
eventBus.emit(AREA_EVENT_TYPES.AREA_DOCK_CENTER, dockingResult);
// 如果停靠成功,从浮动区域移除
if (dockingResult.success && areaState.type === 'floating') {
this.areaStateManager.closeFloatingArea(areaId);
}
}
/**
* 处理Area合并事件
* @param {Object} data - 事件数据
*/
async _handleAreaMerge(data) {
const { sourceAreaId, targetAreaId, mergeType = 'tabPage', mergeOptions = {} } = data;
const sourceState = this.areaStateManager.getState(sourceAreaId);
const targetState = this.areaStateManager.getState(targetAreaId);
if (!sourceState || !targetState) {
console.warn(`❌ 合并失败找不到源Area ${sourceAreaId} 或目标Area ${targetAreaId}`);
return;
}
// 执行合并逻辑
const mergeResult = {
sourceAreaId,
targetAreaId,
mergeType,
sourceTabPages: sourceState.tabPages || [],
targetTabPages: targetState.tabPages || [],
options: mergeOptions,
timestamp: Date.now(),
success: true
};
// 触发合并事件
eventBus.emit(AREA_EVENT_TYPES.AREA_MERGE, mergeResult);
// 隐藏源Area保存到隐藏列表
this.areaStateManager.addToHiddenList(sourceAreaId);
}
/**
* 处理Area调整大小开始事件
* @param {Object} data - 事件数据
*/
async _handleAreaResizeStart(data) {
const { areaId, resizeType = 'split', direction = 'both' } = data;
// 记录调整大小状态
this.areaStateManager.setResizeState(areaId, {
isResizing: true,
resizeType,
direction,
startTime: Date.now(),
originalSize: data.originalSize || {}
});
// 触发调整大小开始事件
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_START, {
areaId,
resizeType,
direction,
timestamp: Date.now()
});
}
/**
* 处理Area调整大小事件
* @param {Object} data - 事件数据
*/
async _handleAreaResize(data) {
const { areaId, size, delta } = data;
const resizeState = this.areaStateManager.getResizeState(areaId);
if (!resizeState || !resizeState.isResizing) return;
// 更新调整大小状态
resizeState.currentSize = size;
resizeState.delta = delta;
resizeState.lastUpdate = Date.now();
// 更新Area状态
const areaState = this.areaStateManager.getState(areaId);
if (areaState) {
this.areaStateManager.updateState(areaId, {
width: size.width,
height: size.height,
ratio: size.ratio
});
}
// 触发调整大小事件
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE, {
areaId,
size,
delta,
resizeType: resizeState.resizeType,
timestamp: Date.now()
});
}
/**
* 处理Area调整大小结束事件
* @param {Object} data - 事件数据
*/
async _handleAreaResizeEnd(data) {
const { areaId, finalSize } = data;
const resizeState = this.areaStateManager.getResizeState(areaId);
if (!resizeState) return;
const resizeDuration = Date.now() - resizeState.startTime;
// 清理调整大小状态
resizeState.isResizing = false;
resizeState.endTime = Date.now();
resizeState.duration = resizeDuration;
resizeState.finalSize = finalSize;
// 更新最终的Area状态
if (finalSize) {
this.areaStateManager.updateState(areaId, {
width: finalSize.width,
height: finalSize.height,
ratio: finalSize.ratio,
lastResizedAt: Date.now()
});
}
// 触发调整大小结束事件
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_END, {
areaId,
resizeInfo: {
duration: resizeDuration,
originalSize: resizeState.originalSize,
finalSize,
delta: resizeState.delta
},
timestamp: Date.now()
});
// 延迟清理调整大小状态
setTimeout(() => {
this.areaStateManager.clearResizeState(areaId);
}, 500);
}
/**
* 处理浮动Area创建事件
* @param {Object} data - 事件数据
*/
async _handleFloatingAreaCreate(data) {
const { areaId, config } = data;
// 激活浮动Area
this.activeAreas.add(areaId);
// 设置默认z-index
const zIndex = config.zIndex || 1001 + this.areaStateManager.floatingAreas.size;
// 更新z-index状态
this.areaStateManager.updateState(areaId, {
zIndex,
lastActivatedAt: Date.now()
});
// 触发层级管理事件
eventBus.emit(AREA_EVENT_TYPES.AREA_ZINDEX_MANAGEMENT, {
areaId,
action: 'create_floating',
zIndex,
timestamp: Date.now()
});
}
/**
* 启动内存保护机制
*/
_startMemoryProtection() {
setInterval(() => {
this._onMemoryCheck();
}, this.memoryProtection.cleanupInterval);
}
/**
* 内存检查和清理
*/
_onMemoryCheck() {
const now = Date.now();
// 清理过期历史记录
this.areaStateManager.cleanupHistory();
// 检查Area数量限制
if (this.areaStateManager.states.size > this.memoryProtection.maxAreas) {
console.warn(`⚠️ Area数量超过限制: ${this.areaStateManager.states.size}`);
// 清理最旧的活动Area
const inactiveAreas = Array.from(this.areaStateManager.states.entries())
.filter(([_, state]) => !state.active && !state.floating)
.sort((a, b) => (a[1].lastActivatedAt || 0) - (b[1].lastActivatedAt || 0));
const toRemove = inactiveAreas.slice(0, 5); // 移除5个最旧的
toRemove.forEach(([areaId]) => {
this.areaStateManager.states.delete(areaId);
console.log(`🗑️ 清理过期Area: ${areaId}`);
});
}
this.memoryProtection.lastCleanup = now;
}
/**
* 获取Area状态
* @param {string} areaId - Area ID
* @returns {Object} Area状态
*/
getAreaState(areaId) {
return this.areaStateManager.getState(areaId);
}
/**
* 获取所有活动Area
* @returns {Array} 活动Area ID列表
*/
getActiveAreas() {
return Array.from(this.activeAreas);
}
/**
* 获取拖拽状态
* @param {string} areaId - Area ID
* @returns {Object} 拖拽状态
*/
getDragState(areaId) {
return this.areaStateManager.getDragState(areaId);
}
/**
* 获取调整大小状态
* @param {string} areaId - Area ID
* @returns {Object} 调整大小状态
*/
getResizeState(areaId) {
return this.areaStateManager.getResizeState(areaId);
}
/**
* 获取统计信息
* @returns {Object} 统计信息
*/
getStats() {
return {
...this.areaStateManager.getStats(),
activeAreas: this.activeAreas.size
};
}
/**
* 销毁事件处理器
*/
destroy() {
// 清理事件监听器
this.areaListeners.forEach((listener, eventType) => {
eventBus.off(eventType, listener);
});
this.areaListeners.clear();
// 清理状态
this.areaStateManager.states.clear();
this.areaStateManager.floatingAreas.clear();
this.areaStateManager.dragState.clear();
this.areaStateManager.resizeState.clear();
this.activeAreas.clear();
console.log('🗑️ Area事件处理器已销毁');
}
}
// 创建单例实例
const areaHandler = new AreaEventHandler();
// Area便捷操作函数
export const areaActions = {
/**
* 创建浮动Area
* @param {Object} config - Area配置
* @returns {string} Area ID
*/
createFloating: (config = {}) => {
const areaId = areaHandler.areaStateManager.createFloatingArea(config);
return areaId;
},
/**
* 关闭浮动Area
* @param {string} areaId - Area ID
* @returns {boolean} 是否成功
*/
closeFloating: (areaId) => {
return areaHandler.areaStateManager.closeFloatingArea(areaId);
},
/**
* 更新浮动Area位置
* @param {string} areaId - Area ID
* @param {Object} position - 位置信息
* @returns {boolean} 是否成功
*/
updatePosition: (areaId, position) => {
return areaHandler.areaStateManager.updateFloatingAreaPosition(areaId, position);
},
/**
* 开始Area拖拽
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
* @param {string} source - 拖拽源
*/
startDrag: (areaId, event, source = 'direct') => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_START, {
areaId,
event,
source,
timestamp: Date.now()
});
},
/**
* Area拖拽移动
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
moveDrag: (areaId, event) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_MOVE, {
areaId,
event,
timestamp: Date.now()
});
},
/**
* 结束Area拖拽
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
endDrag: (areaId, event) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DRAG_END, {
areaId,
event,
timestamp: Date.now()
});
},
/**
* Area停靠到中心
* @param {string} areaId - Area ID
* @param {string} targetAreaId - 目标Area ID
* @param {string} mergeStrategy - 合并策略
*/
dockToCenter: (areaId, targetAreaId = 'main', mergeStrategy = 'auto') => {
eventBus.emit(AREA_EVENT_TYPES.AREA_DOCK_CENTER, {
areaId,
targetAreaId,
mergeStrategy,
timestamp: Date.now()
});
},
/**
* Area合并
* @param {string} sourceAreaId - 源Area ID
* @param {string} targetAreaId - 目标Area ID
* @param {string} mergeType - 合并类型
* @param {Object} mergeOptions - 合并选项
*/
merge: (sourceAreaId, targetAreaId, mergeType = 'tabPage', mergeOptions = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_MERGE, {
sourceAreaId,
targetAreaId,
mergeType,
mergeOptions,
timestamp: Date.now()
});
},
/**
* 开始调整Area大小
* @param {string} areaId - Area ID
* @param {Object} originalSize - 原始大小
* @param {string} resizeType - 调整类型
* @param {string} direction - 调整方向
*/
startResize: (areaId, originalSize, resizeType = 'split', direction = 'both') => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_START, {
areaId,
originalSize,
resizeType,
direction,
timestamp: Date.now()
});
},
/**
* Area调整大小
* @param {string} areaId - Area ID
* @param {Object} size - 当前大小
* @param {Object} delta - 大小变化
*/
resize: (areaId, size, delta) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE, {
areaId,
size,
delta,
timestamp: Date.now()
});
},
/**
* 结束调整Area大小
* @param {string} areaId - Area ID
* @param {Object} finalSize - 最终大小
*/
endResize: (areaId, finalSize) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESIZE_END, {
areaId,
finalSize,
timestamp: Date.now()
});
},
/**
* 最大化Area
* @param {string} areaId - Area ID
* @param {Object} options - 选项
*/
maximize: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_MAXIMIZE, {
areaId,
...options,
timestamp: Date.now()
});
},
/**
* 恢复Area
* @param {string} areaId - Area ID
* @param {Object} options - 选项
*/
restore: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_RESTORE, {
areaId,
...options,
timestamp: Date.now()
});
},
/**
* 折叠Area
* @param {string} areaId - Area ID
* @param {Object} options - 选项
*/
collapse: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_COLLAPSE, {
areaId,
...options,
timestamp: Date.now()
});
},
/**
* 展开Area
* @param {string} areaId - Area ID
* @param {Object} options - 选项
*/
expand: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_EXPAND, {
areaId,
...options,
timestamp: Date.now()
});
},
/**
* 关闭Area
* @param {string} areaId - Area ID
* @param {Object} options - 选项
*/
close: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_CLOSE, {
areaId,
...options,
timestamp: Date.now()
});
},
/**
* 切换工具栏
* @param {string} areaId - Area ID
* @param {Object} options - 选项
*/
toggleToolbar: (areaId, options = {}) => {
eventBus.emit(AREA_EVENT_TYPES.AREA_TOGGLE_TOOLBAR, {
areaId,
...options,
timestamp: Date.now()
});
},
/**
* 更新Area状态
* @param {string} areaId - Area ID
* @param {Object} updates - 状态更新
*/
updateState: (areaId, updates) => {
areaHandler.areaStateManager.updateState(areaId, updates);
}
};
// 导出事件处理器和相关API
export default areaHandler;
// 便利的Area拖拽处理函数
export const triggerAreaDrag = {
/**
* 开始Area拖拽
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
start: (areaId, event) => {
areaActions.startDrag(areaId, event, 'direct');
},
/**
* 处理Area拖拽移动
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
move: (areaId, event) => {
areaActions.moveDrag(areaId, event);
},
/**
* 结束Area拖拽
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
end: (areaId, event) => {
areaActions.endDrag(areaId, event);
}
};