完善事件总线功能,创建专门的事件处理器模块

This commit is contained in:
zqm
2025-11-20 13:14:31 +08:00
parent 10557a5466
commit e9ef33bd62
9 changed files with 8784 additions and 2233 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -53,6 +53,177 @@ export const EVENT_TYPES = {
Z_INDEX_UPDATE: 'zIndex.update'
}
// 事件优先级常量
export const PRIORITY_LEVELS = {
CRITICAL: 0, // 关键事件(如错误、安全)
HIGH: 1, // 高优先级(用户交互)
NORMAL: 2, // 普通优先级
LOW: 3 // 低优先级(统计、日志)
}
// 事件去重选项
export const DEDUP_OPTIONS = {
NONE: 0, // 不去重
TTL_BASED: 1, // 基于TTL去重
CONTENT_BASED: 2 // 基于内容去重
}
// 事件去重器
class EventDeduplicator {
constructor(ttl = 100) {
this.recentEvents = new Map()
this.ttl = ttl
}
/**
* 检查事件是否应该被处理(去重)
*/
shouldProcess(eventType, data, dedupType = DEDUP_OPTIONS.TTL_BASED) {
const now = Date.now()
if (dedupType === DEDUP_OPTIONS.NONE) {
return true
}
let key
if (dedupType === DEDUP_OPTIONS.CONTENT_BASED) {
// 基于内容和类型去重
key = `${eventType}:${JSON.stringify(data)}`
} else {
// 基于TTL的去重仅基于事件类型
key = eventType
}
const lastTime = this.recentEvents.get(key)
if (lastTime && (now - lastTime) < this.ttl) {
return false // 跳过重复事件
}
this.recentEvents.set(key, now)
// 定期清理过期的事件
if (this.recentEvents.size > 1000) {
this._cleanup()
}
return true
}
/**
* 清理过期的事件记录
*/
_cleanup() {
const now = Date.now()
for (const [key, timestamp] of this.recentEvents.entries()) {
if (now - timestamp > this.ttl * 2) {
this.recentEvents.delete(key)
}
}
}
/**
* 清除所有记录
*/
clear() {
this.recentEvents.clear()
}
}
// 事件优先级队列管理器
class PriorityEventQueue {
constructor() {
this.queues = {
[PRIORITY_LEVELS.CRITICAL]: [],
[PRIORITY_LEVELS.HIGH]: [],
[PRIORITY_LEVELS.NORMAL]: [],
[PRIORITY_LEVELS.LOW]: []
}
this.processing = false
}
/**
* 添加事件到队列
*/
add(event, priority = PRIORITY_LEVELS.NORMAL) {
this.queues[priority].push(event)
this._processQueue()
}
/**
* 处理事件队列
*/
async _processQueue() {
if (this.processing) return
this.processing = true
try {
// 按优先级顺序处理
for (const priority of Object.keys(this.queues).map(Number).sort()) {
const queue = this.queues[priority]
while (queue.length > 0) {
const event = queue.shift()
await this._processEvent(event)
}
}
} finally {
this.processing = false
}
}
/**
* 处理单个事件
*/
async _processEvent(event) {
if (event.bus && event.bus._handlePriorityEvent) {
await event.bus._handlePriorityEvent(event)
}
}
/**
* 获取队列统计
*/
getStats() {
const stats = {}
let total = 0
for (const [priority, queue] of Object.entries(this.queues)) {
stats[priority] = {
count: queue.length,
priorityName: this._getPriorityName(Number(priority))
}
total += queue.length
}
stats.total = total
stats.isProcessing = this.processing
return stats
}
/**
* 获取优先级名称
*/
_getPriorityName(priority) {
const priorityMap = {
[PRIORITY_LEVELS.CRITICAL]: 'CRITICAL',
[PRIORITY_LEVELS.HIGH]: 'HIGH',
[PRIORITY_LEVELS.NORMAL]: 'NORMAL',
[PRIORITY_LEVELS.LOW]: 'LOW'
}
return priorityMap[priority] || 'UNKNOWN'
}
/**
* 清除所有队列
*/
clear() {
for (const queue of Object.values(this.queues)) {
queue.length = 0
}
}
}
// 增强的事件总线类
class EnhancedEventBus {
constructor() {
@@ -61,6 +232,9 @@ class EnhancedEventBus {
this.debugMode = false
this.eventHistory = []
this.maxHistorySize = 100
this.deduplicator = new EventDeduplicator(100) // 100ms TTL
this.priorityQueue = new PriorityEventQueue()
this.performanceMetrics = new Map()
}
/**
@@ -71,64 +245,241 @@ class EnhancedEventBus {
}
/**
* 订阅事件
* 监听事件
* @param {string} eventType 事件类型
* @param {function} handler 事件处理函数
* @param {object} options 监听选项
* @returns {function} 取消监听的函数
*/
on(eventType, callback, options = {}) {
const unsubscribe = this.bus.on(eventType, (data) => {
const event = {
id: nanoid(),
type: eventType,
data,
timestamp: Date.now(),
source: {
instanceId: this.instanceId,
...options.source
}
}
if (this.debugMode) {
console.log(`[EventBus] ${eventType} event received:`, event)
}
// 记录事件历史
this.recordEvent(event)
on(eventType, handler, options = {}) {
const {
priority = PRIORITY_LEVELS.NORMAL,
async = false,
timeout = 30000,
retries = 0
} = options
// 包装处理函数以添加上下文和错误处理
const wrappedHandler = async (event) => {
const startTime = performance.now()
try {
callback(event.data, event)
// 调试日志
if (this.debugMode) {
console.group(`📥 Event: ${eventType}`)
console.log('Received data:', event.data)
console.log('Handler:', handler.name || 'anonymous')
console.log('Priority:', this._getPriorityName(priority))
console.log('Async:', async)
console.groupEnd()
}
// 异步处理
if (async) {
// 设置超时处理
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Handler timeout after ${timeout}ms`)), timeout)
})
// 执行处理函数,支持重试
let result
let lastError
for (let attempt = 0; attempt <= retries; attempt++) {
try {
result = await Promise.race([
handler(event.data, event),
timeoutPromise
])
break // 成功,退出重试循环
} catch (error) {
lastError = error
if (attempt < retries) {
if (this.debugMode) {
console.log(`🔄 Retrying event handler for ${eventType} (attempt ${attempt + 1}/${retries + 1})`)
}
// 等待重试间隔(指数退避)
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100))
}
}
}
if (result === undefined && lastError) {
throw lastError
}
} else {
// 同步处理
const result = handler(event.data, event)
// 如果返回Promise等待其完成
if (result && typeof result.then === 'function') {
await result
}
}
// 记录成功
this._recordSuccess(eventType, performance.now() - startTime)
return true
} catch (error) {
console.error(`[EventBus] Error in event listener for ${eventType}:`, error)
// 记录错误
this._recordError(eventType, error)
// 调试模式输出错误
if (this.debugMode) {
console.error(`❌ Error in event handler for ${eventType}:`, error)
}
throw error
}
})
// 返回增强的取消订阅函数
}
// 实际监听事件
this.bus.on(eventType, wrappedHandler)
// 返回取消监听的函数
return () => {
unsubscribe()
this.off(eventType, wrappedHandler)
}
}
/**
* 触发事件
* @param {string} eventType 事件类型
* @param {any} data 事件数据
* @param {object} options 事件选项
*/
emit(eventType, data, options = {}) {
const event = {
id: nanoid(),
const startTime = performance.now()
const eventInfo = {
type: eventType,
data,
timestamp: Date.now(),
source: {
instanceId: this.instanceId,
...options.source
}
timestamp: new Date().toISOString(),
instanceId: this.instanceId,
priority: options.priority || PRIORITY_LEVELS.NORMAL,
async: options.async || false,
dedupType: options.dedupType || DEDUP_OPTIONS.TTL_BASED,
...options
}
if (this.debugMode) {
console.log(`[EventBus] Emitting ${eventType}:`, event)
}
this.recordEvent(event)
this.bus.emit(eventType, data)
return event
// 检查是否需要去重
if (!this.deduplicator.shouldProcess(eventType, data, eventInfo.dedupType)) {
if (this.debugMode) {
console.log(`🔁 Event skipped (dedup): ${eventType}`)
}
return Promise.resolve(false)
}
// 添加到事件历史
this._addToHistory(eventInfo)
// 调试日志
if (this.debugMode) {
console.group(`🚀 Event: ${eventType}`)
console.log('Data:', data)
console.log('Options:', options)
console.log('Priority:', this._getPriorityName(eventInfo.priority))
console.log('Async:', eventInfo.async)
console.log('Deduplication:', this._getDedupName(eventInfo.dedupType))
console.log('Timestamp:', eventInfo.timestamp)
console.groupEnd()
}
// 异步事件处理
if (eventInfo.async) {
return this._handleAsyncEvent(eventInfo)
}
// 优先处理关键事件
if (eventInfo.priority === PRIORITY_LEVELS.CRITICAL) {
return this._handlePriorityEvent({ ...eventInfo, bus: this })
}
// 添加到优先级队列
this.priorityQueue.add({ ...eventInfo, bus: this }, eventInfo.priority)
// 记录性能指标
const duration = performance.now() - startTime
this._recordPerformance(eventType, duration)
return Promise.resolve(true)
}
/**
* 处理优先级事件
*/
async _handlePriorityEvent(event) {
const startTime = performance.now()
try {
// 触发事件
this.bus.emit(event.type, {
type: event.type,
data: event.data,
timestamp: event.timestamp,
priority: event.priority,
...event
})
// 记录性能指标
const duration = performance.now() - startTime
this._recordPerformance(event.type, duration)
return true
} catch (error) {
// 记录错误
this._recordError(event.type, error)
// 调试模式输出错误
if (this.debugMode) {
console.error(`❌ Error in priority event ${event.type}:`, error)
}
throw error
}
}
/**
* 处理异步事件
*/
async _handleAsyncEvent(eventInfo) {
const startTime = performance.now()
try {
// 调试日志
if (this.debugMode) {
console.log(`⚡ Async event: ${eventInfo.type}`)
}
// 异步触发事件
const result = await new Promise((resolve, reject) => {
this.bus.emit(eventInfo.type, {
type: eventInfo.type,
data: eventInfo.data,
timestamp: eventInfo.timestamp,
priority: eventInfo.priority,
async: true,
...eventInfo
})
resolve(true)
})
// 记录性能指标
const duration = performance.now() - startTime
this._recordPerformance(eventInfo.type, duration)
return result
} catch (error) {
// 记录错误
this._recordError(eventInfo.type, error)
// 调试模式输出错误
if (this.debugMode) {
console.error(`❌ Error in async event ${eventInfo.type}:`, error)
}
throw error
}
}
/**
@@ -187,6 +538,125 @@ class EnhancedEventBus {
}
return stats
}
/**
* 添加事件到历史
*/
_addToHistory(eventInfo) {
this.eventHistory.push({
...eventInfo,
historyId: nanoid(),
instanceId: this.instanceId
})
// 保持历史记录在指定大小内
if (this.eventHistory.length > this.maxHistorySize) {
this.eventHistory.shift()
}
}
/**
* 记录性能指标
*/
_recordPerformance(eventType, duration) {
if (!this.performanceMetrics.has(eventType)) {
this.performanceMetrics.set(eventType, {
count: 0,
totalDuration: 0,
maxDuration: 0,
minDuration: Infinity,
errors: 0,
successes: 0
})
}
const metrics = this.performanceMetrics.get(eventType)
metrics.count++
metrics.totalDuration += duration
metrics.maxDuration = Math.max(metrics.maxDuration, duration)
metrics.minDuration = Math.min(metrics.minDuration, duration)
}
/**
* 记录成功事件
*/
_recordSuccess(eventType, duration) {
const metrics = this.performanceMetrics.get(eventType)
if (metrics) {
metrics.successes++
this._recordPerformance(eventType, duration)
}
}
/**
* 记录错误事件
*/
_recordError(eventType, error) {
const metrics = this.performanceMetrics.get(eventType)
if (metrics) {
metrics.errors++
metrics.lastError = {
message: error.message,
stack: error.stack,
timestamp: new Date().toISOString()
}
}
}
/**
* 获取性能指标
*/
getPerformanceMetrics() {
const metrics = {}
for (const [eventType, data] of this.performanceMetrics.entries()) {
metrics[eventType] = {
...data,
avgDuration: data.count > 0 ? data.totalDuration / data.count : 0,
errorRate: data.count > 0 ? data.errors / data.count : 0,
successRate: data.count > 0 ? data.successes / data.count : 0
}
}
return metrics
}
/**
* 获取优先级名称
*/
_getPriorityName(priority) {
const priorityMap = {
[PRIORITY_LEVELS.CRITICAL]: 'CRITICAL',
[PRIORITY_LEVELS.HIGH]: 'HIGH',
[PRIORITY_LEVELS.NORMAL]: 'NORMAL',
[PRIORITY_LEVELS.LOW]: 'LOW'
}
return priorityMap[priority] || 'UNKNOWN'
}
/**
* 获取去重类型名称
*/
_getDedupName(dedupType) {
const dedupMap = {
[DEDUP_OPTIONS.NONE]: 'NONE',
[DEDUP_OPTIONS.TTL_BASED]: 'TTL_BASED',
[DEDUP_OPTIONS.CONTENT_BASED]: 'CONTENT_BASED'
}
return dedupMap[dedupType] || 'UNKNOWN'
}
/**
* 获取队列统计
*/
getQueueStats() {
return this.priorityQueue.getStats()
}
/**
* 清除去重器
*/
clearDeduplicator() {
this.deduplicator.clear()
}
}
// 创建全局事件总线实例

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,584 @@
/**
* 事件总线集成模块
* 统一管理所有事件处理器和功能模块
*/
import { eventBus, eventBusActions, EVENT_TYPES } from '../eventBus.js';
import { panelHandler, PANEL_EVENT_TYPES, panelActions } from './PanelHandler.js';
import tabPageHandler, { TABPAGE_EVENT_TYPES, tabPageActions } from './TabPageHandler.js';
import areaHandler, { AREA_EVENT_TYPES, areaActions } from './AreaHandler.js';
import globalEventManager, { GLOBAL_EVENT_TYPES, globalEventActions } from './GlobalEventManager.js';
import dragStateManager, { DRAG_STATE_TYPES, dragStateActions } from './DragStateManager.js';
import integrationTester, { testActions, TEST_CONFIG } from './IntegrationTester.js';
// 事件总线配置
export const EVENT_BUS_CONFIG = {
// 事件总线配置
bus: {
enableDebug: true,
enablePerformance: true,
maxHistorySize: 1000,
cleanupInterval: 30000 // 30秒清理一次
},
// 处理器配置
handlers: {
panel: {
enabled: true,
autoRegister: true,
eventBufferSize: 100
},
tabpage: {
enabled: true,
autoRegister: true,
eventBufferSize: 100
},
area: {
enabled: true,
autoRegister: true,
eventBufferSize: 100
},
global: {
enabled: true,
autoRegister: true,
routing: true
},
drag: {
enabled: true,
autoRegister: true,
conflictDetection: true
}
},
// 集成测试配置
testing: {
enabled: true,
autoRun: false,
reportInterval: 60000, // 1分钟
performanceThreshold: {
eventEmitTime: 10,
eventHandleTime: 50,
memoryUsage: 50 * 1024 * 1024
}
}
};
// 事件总线管理器类
class EventBusManager {
constructor() {
this.isInitialized = false;
this.isDestroyed = false;
this.components = new Map();
this.eventRoutes = new Map();
this.performanceMonitor = null;
this.healthCheckInterval = null;
this.initializedHandlers = new Set();
// 绑定方法
this._handleGlobalError = this._handleGlobalError.bind(this);
this._handleUnhandledRejection = this._handleUnhandledRejection.bind(this);
this._healthCheck = this._healthCheck.bind(this);
}
/**
* 初始化事件总线系统
* @param {Object} config - 配置选项
*/
async initialize(config = {}) {
if (this.isInitialized) {
console.warn('⚠️ 事件总线系统已经初始化');
return;
}
console.log('🚀 初始化事件总线系统...');
this.isInitialized = true;
try {
// 合并配置
this.config = { ...EVENT_BUS_CONFIG, ...config };
// 初始化全局错误处理
this._setupGlobalErrorHandling();
// 注册事件处理器
await this._registerAllHandlers();
// 设置事件路由
this._setupEventRoutes();
// 启动性能监控(如果启用)
if (this.config.testing.enabled && this.config.testing.autoRun) {
await this._startPerformanceMonitoring();
}
// 启动健康检查
this._startHealthCheck();
// 发布初始化完成事件
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_INITIALIZED, {
timestamp: Date.now(),
version: '1.0.0',
components: Array.from(this.initializedHandlers)
});
console.log('✅ 事件总线系统初始化完成');
console.log(`📋 已注册组件: ${Array.from(this.initializedHandlers).join(', ')}`);
} catch (error) {
console.error('❌ 事件总线系统初始化失败:', error);
this.isInitialized = false;
throw error;
}
}
/**
* 注册所有事件处理器
*/
async _registerAllHandlers() {
const handlers = [
{ name: 'panel', handler: panelHandler, events: PANEL_EVENT_TYPES },
{ 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 }
];
for (const { name, handler, events } of handlers) {
const handlerConfig = this.config.handlers[name];
if (!handlerConfig?.enabled) {
console.log(`⏭️ 跳过禁用的事件处理器: ${name}`);
continue;
}
try {
console.log(`📝 注册事件处理器: ${name}`);
// 注册事件处理器到事件总线
Object.values(events).forEach(eventType => {
if (typeof handler.handleEvent === 'function') {
eventBus.on(eventType, handler.handleEvent.bind(handler), {
priority: 1,
id: `handler-${name}`
});
}
});
// 调用初始化方法(如果存在)
if (typeof handler.initialize === 'function') {
await handler.initialize();
}
this.initializedHandlers.add(name);
this.components.set(name, {
handler,
events: Object.values(events),
config: handlerConfig,
status: 'active',
initializedAt: Date.now()
});
console.log(`✅ 事件处理器注册成功: ${name}`);
} catch (error) {
console.error(`❌ 事件处理器注册失败 [${name}]:`, error);
this.components.set(name, {
handler,
events: Object.values(events),
config: handlerConfig,
status: 'error',
error: error.message,
initializedAt: Date.now()
});
}
}
}
/**
* 设置事件路由
*/
_setupEventRoutes() {
// 设置跨组件事件路由
const routes = [
// Panel相关路由
{ from: PANEL_EVENT_TYPES.PANEL_CREATE_REQUEST, to: [GLOBAL_EVENT_TYPES.PANEL_CREATED] },
{ from: PANEL_EVENT_TYPES.PANEL_CLOSE_REQUEST, to: [GLOBAL_EVENT_TYPES.PANEL_CLOSED] },
{ from: PANEL_EVENT_TYPES.PANEL_MAXIMIZE, to: [GLOBAL_EVENT_TYPES.PANEL_STATE_CHANGED] },
// TabPage相关路由
{ from: TABPAGE_EVENT_TYPES.TABPAGE_CREATE_REQUEST, to: [GLOBAL_EVENT_TYPES.TABPAGE_CREATED] },
{ from: TABPAGE_EVENT_TYPES.TABPAGE_CLOSE_REQUEST, to: [GLOBAL_EVENT_TYPES.TABPAGE_CLOSED] },
{ from: TABPAGE_EVENT_TYPES.TABPAGE_SWITCH, to: [GLOBAL_EVENT_TYPES.TABPAGE_SWITCHED] },
// Area相关路由
{ from: AREA_EVENT_TYPES.AREA_CREATE_REQUEST, to: [GLOBAL_EVENT_TYPES.AREA_CREATED] },
{ from: AREA_EVENT_TYPES.AREA_DESTROY_REQUEST, to: [GLOBAL_EVENT_TYPES.AREA_DESTROYED] },
{ from: AREA_EVENT_TYPES.AREA_MERGE, to: [GLOBAL_EVENT_TYPES.AREA_MERGED] },
// 拖拽相关路由
{ from: 'panel.drag.start', to: [GLOBAL_EVENT_TYPES.DRAG_STARTED] },
{ from: 'panel.drag.end', to: [GLOBAL_EVENT_TYPES.DRAG_ENDED] },
{ from: 'tabpage.drag.start', to: [GLOBAL_EVENT_TYPES.DRAG_STARTED] },
{ from: 'tabpage.drag.end', to: [GLOBAL_EVENT_TYPES.DRAG_ENDED] },
{ from: 'area.drag.start', to: [GLOBAL_EVENT_TYPES.DRAG_STARTED] },
{ from: 'area.drag.end', to: [GLOBAL_EVENT_TYPES.DRAG_ENDED] }
];
routes.forEach(route => {
this.eventRoutes.set(route.from, route.to);
eventBus.on(route.from, (data) => {
// 自动路由到目标事件
route.to.forEach(targetEvent => {
eventBus.emit(targetEvent, {
...data,
sourceEvent: route.from,
routed: true,
routeTime: Date.now()
});
});
}, { id: 'router', priority: 0 });
});
console.log(`🔗 设置了 ${routes.length} 个事件路由`);
}
/**
* 设置全局错误处理
*/
_setupGlobalErrorHandling() {
// 捕获未处理的错误
window.addEventListener('error', this._handleGlobalError);
// 捕获未处理的Promise拒绝
window.addEventListener('unhandledrejection', this._handleUnhandledRejection);
console.log('🔧 全局错误处理已设置');
}
/**
* 处理全局错误
* @param {ErrorEvent} event - 错误事件
*/
_handleGlobalError(event) {
console.error('🚨 全局错误捕获:', {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error
});
// 发布错误事件
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_ERROR, {
type: 'javascript_error',
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
stack: event.error?.stack,
timestamp: Date.now()
});
}
/**
* 处理未捕获的Promise拒绝
* @param {PromiseRejectionEvent} event - Promise拒绝事件
*/
_handleUnhandledRejection(event) {
console.error('🚨 未处理的Promise拒绝:', {
reason: event.reason,
promise: event.promise
});
// 发布错误事件
eventBus.emit(GLOBAL_EVENT_TYPES.SYSTEM_ERROR, {
type: 'unhandled_promise_rejection',
reason: event.reason?.toString(),
stack: event.reason?.stack,
timestamp: Date.now()
});
}
/**
* 启动性能监控
*/
async _startPerformanceMonitoring() {
console.log('📊 启动性能监控...');
// 运行快速性能测试
try {
const report = await testActions.runAll(['panel', 'tabpage', 'area']);
console.log('✅ 初始性能测试完成');
// 发布性能报告
eventBus.emit(GLOBAL_EVENT_TYPES.PERFORMANCE_REPORT, {
type: 'initial_test',
report,
timestamp: Date.now()
});
} catch (error) {
console.warn('⚠️ 初始性能测试失败:', error.message);
}
}
/**
* 启动健康检查
*/
_startHealthCheck() {
// 每分钟执行一次健康检查
this.healthCheckInterval = setInterval(this._healthCheck, 60000);
console.log('💚 健康检查已启动');
}
/**
* 执行健康检查
*/
_healthCheck() {
if (this.isDestroyed) return;
const healthStatus = {
timestamp: Date.now(),
components: {},
eventBus: {
isActive: eventBus.isActive(),
handlerCount: eventBus.getHandlerCount(),
queuedEvents: eventBus.getQueuedEvents()
},
memory: performance.memory ? {
used: performance.memory.usedJSHeapSize,
total: performance.memory.totalJSHeapSize,
limit: performance.memory.jsHeapSizeLimit
} : null,
issues: []
};
// 检查组件状态
for (const [name, component] of this.components) {
component.status = 'active'; // 简化实现,实际应该检查组件健康状态
healthStatus.components[name] = {
status: component.status,
error: component.error,
initializedAt: component.initializedAt
};
if (component.status === 'error') {
healthStatus.issues.push({
component: name,
type: 'component_error',
message: component.error
});
}
}
// 检查事件总线状态
if (healthStatus.eventBus.handlerCount === 0) {
healthStatus.issues.push({
component: 'eventBus',
type: 'no_handlers',
message: '事件总线没有注册的事件处理器'
});
}
// 发布健康检查结果
eventBus.emit(GLOBAL_EVENT_TYPES.HEALTH_CHECK, healthStatus);
}
/**
* 获取系统状态
* @returns {Object} 系统状态
*/
getSystemStatus() {
return {
initialized: this.isInitialized,
destroyed: this.isDestroyed,
config: this.config,
components: Object.fromEntries(this.components),
eventRoutes: Object.fromEntries(this.eventRoutes),
initializedHandlers: Array.from(this.initializedHandlers),
eventBusStats: eventBus.getStats(),
uptime: Date.now() - (this.startTime || Date.now())
};
}
/**
* 重启组件
* @param {string} componentName - 组件名称
*/
async restartComponent(componentName) {
const component = this.components.get(componentName);
if (!component) {
throw new Error(`未找到组件: ${componentName}`);
}
console.log(`🔄 重启组件: ${componentName}`);
try {
// 销毁组件
if (typeof component.handler.destroy === 'function') {
await component.handler.destroy();
}
// 重新初始化组件
if (typeof component.handler.initialize === 'function') {
await component.handler.initialize();
}
// 更新状态
component.status = 'active';
component.error = null;
component.restartedAt = Date.now();
console.log(`✅ 组件重启成功: ${componentName}`);
// 发布重启事件
eventBus.emit(GLOBAL_EVENT_TYPES.COMPONENT_RESTARTED, {
componentName,
timestamp: Date.now()
});
} catch (error) {
component.status = 'error';
component.error = error.message;
console.error(`❌ 组件重启失败 [${componentName}]:`, error);
throw error;
}
}
/**
* 销毁事件总线系统
*/
async destroy() {
if (!this.isInitialized || this.isDestroyed) {
return;
}
console.log('🗑️ 销毁事件总线系统...');
this.isDestroyed = true;
try {
// 停止健康检查
if (this.healthCheckInterval) {
clearInterval(this.healthCheckInterval);
this.healthCheckInterval = null;
}
// 移除全局错误处理
window.removeEventListener('error', this._handleGlobalError);
window.removeEventListener('unhandledrejection', this._handleUnhandledRejection);
// 销毁所有组件
for (const [name, component] of this.components) {
try {
if (typeof component.handler.destroy === 'function') {
await component.handler.destroy();
}
console.log(`✅ 组件销毁成功: ${name}`);
} catch (error) {
console.error(`❌ 组件销毁失败 [${name}]:`, error);
}
}
// 清空数据
this.components.clear();
this.eventRoutes.clear();
this.initializedHandlers.clear();
// 销毁测试器
if (typeof integrationTester.destroy === 'function') {
integrationTester.destroy();
}
console.log('✅ 事件总线系统已完全销毁');
} catch (error) {
console.error('❌ 事件总线系统销毁过程中发生错误:', error);
throw error;
}
}
}
// 创建单例实例
const eventBusManager = new EventBusManager();
// 便捷API
export const systemActions = {
/**
* 初始化事件总线系统
* @param {Object} config - 配置选项
*/
initialize: (config) => eventBusManager.initialize(config),
/**
* 获取系统状态
* @returns {Object} 系统状态
*/
getStatus: () => eventBusManager.getSystemStatus(),
/**
* 重启组件
* @param {string} componentName - 组件名称
*/
restartComponent: (componentName) => eventBusManager.restartComponent(componentName),
/**
* 运行集成测试
* @param {Array} suites - 测试套件列表
* @returns {Promise} 测试报告
*/
runTests: (suites) => testActions.runAll(suites),
/**
* 获取性能摘要
* @returns {Object} 性能摘要
*/
getPerformanceSummary: () => testActions.getPerformanceSummary(),
/**
* 销毁系统
*/
destroy: () => eventBusManager.destroy()
};
// 导出所有API
export const dockLayoutActions = {
// 事件总线API
...eventBusActions,
// Panel API
...panelActions,
// TabPage API
...tabPageActions,
// Area API
...areaActions,
// 全局事件 API
...globalEventActions,
// 拖拽状态 API
...dragStateActions,
// 系统 API
...systemActions
};
// 默认导出管理器实例
export default eventBusManager;
// 导出的常量
export {
EVENT_BUS_CONFIG,
EVENT_TYPES,
PANEL_EVENT_TYPES,
TABPAGE_EVENT_TYPES,
AREA_EVENT_TYPES,
GLOBAL_EVENT_TYPES,
DRAG_STATE_TYPES,
TEST_CONFIG
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,834 @@
import { emitEvent, onEvent, onceEvent, registerHandler, unregisterHandler, getHandlerSnapshot } from '../eventBus.js'
import { nanoid } from 'nanoid'
// Panel事件类型常量
export const PANEL_EVENT_TYPES = {
TOGGLE_COLLAPSE: 'panel.toggleCollapse',
MAXIMIZE: 'panel.maximize',
CLOSE_REQUEST: 'panel.close.request',
CLOSE: 'panel.close',
CLOSED: 'panel.closed',
TOGGLE_TOOLBAR: 'panel.toggleToolbar',
DRAG_START: 'panel.drag.start',
DRAG_MOVE: 'panel.drag.move',
DRAG_END: 'panel.drag.end',
MAXIMIZE_SYNC: 'panel.maximize.sync',
ACTIVATED: 'panel.activated',
DEACTIVATED: 'panel.deactivated'
}
/**
* Panel事件处理器类
* 负责处理所有Panel相关的事件处理逻辑
*/
class PanelEventHandler {
constructor() {
this.handlerId = nanoid()
this.panelStates = new Map() // 面板状态缓存
this.dragStates = new Map() // 拖拽状态
this.memoryProtection = null // 内存保护
this.subscriptions = new Map() // 订阅记录
this.isInitialized = false
}
/**
* 初始化Panel事件处理器
*/
async initialize() {
if (this.isInitialized) return
try {
// 初始化内存保护
this._initializeMemoryProtection()
// 注册事件监听器
await this._registerEventListeners()
// 启动内存泄漏检测
this._startMemoryLeakDetection()
this.isInitialized = true
console.log(`[PanelHandler:${this.handlerId}] Panel事件处理器初始化完成`)
} catch (error) {
console.error(`[PanelHandler:${this.handlerId}] 初始化失败:`, error)
throw error
}
}
/**
* 销毁Panel事件处理器
*/
async destroy() {
if (!this.isInitialized) return
try {
// 清理事件监听器
await this._cleanupEventListeners()
// 清理内存保护
this._cleanupMemoryProtection()
// 清理所有状态
this.panelStates.clear()
this.dragStates.clear()
this.subscriptions.clear()
this.isInitialized = false
console.log(`[PanelHandler:${this.handlerId}] Panel事件处理器已销毁`)
} catch (error) {
console.error(`[PanelHandler:${this.handlerId}] 销毁失败:`, error)
throw error
}
}
/**
* 切换Panel折叠状态
*/
async toggleCollapse(panelId, options = {}) {
const { priority = 2, silent = false } = options
if (!silent) {
console.log(`[PanelHandler] 切换Panel折叠状态: ${panelId}`)
}
// 更新本地状态
const panelState = this.panelStates.get(panelId) || { id: panelId }
panelState.collapsed = !panelState.collapsed
panelState.lastModified = Date.now()
this.panelStates.set(panelId, panelState)
// 触发事件
return emitEvent(PANEL_EVENT_TYPES.TOGGLE_COLLAPSE, {
panelId,
collapsed: panelState.collapsed,
source: 'PanelHandler'
}, { priority })
}
/**
* 最大化Panel
*/
async maximize(panelId, options = {}) {
const { priority = 1, syncToArea = false } = options
console.log(`[PanelHandler] 最大化Panel: ${panelId}`)
// 更新本地状态
const panelState = this.panelStates.get(panelId) || { id: panelId }
panelState.maximized = true
panelState.lastModified = Date.now()
this.panelStates.set(panelId, panelState)
// 触发最大化事件
await emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
panelId,
maximized: true,
source: 'PanelHandler'
}, { priority })
// 如果需要同步到Area
if (syncToArea) {
await this._syncMaximizeToArea(panelId)
}
return true
}
/**
* 还原Panel
*/
async restore(panelId, options = {}) {
const { priority = 1, syncToArea = false } = options
console.log(`[PanelHandler] 还原Panel: ${panelId}`)
// 更新本地状态
const panelState = this.panelStates.get(panelId) || { id: panelId }
panelState.maximized = false
panelState.lastModified = Date.now()
this.panelStates.set(panelId, panelState)
// 触发最大化事件false表示还原
await emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
panelId,
maximized: false,
source: 'PanelHandler'
}, { priority })
// 如果需要同步到Area
if (syncToArea) {
await this._syncMaximizeToArea(panelId, false)
}
return true
}
/**
* 请求关闭Panel
* @param {Object} eventData - 事件数据
* @param {string} eventData.areaId - 区域ID
* @param {string} eventData.panelId - 面板ID
*/
requestClose(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.CLOSE_REQUEST, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* 执行Panel关闭
*/
async _executeClose(panelId) {
console.log(`[PanelHandler] 执行Panel关闭: ${panelId}`)
// 更新状态
const panelState = this.panelStates.get(panelId)
if (panelState) {
panelState.closed = true
panelState.closedAt = Date.now()
}
// 触发关闭事件
await emitEvent(PANEL_EVENT_TYPES.CLOSE, {
panelId,
source: 'PanelHandler',
timestamp: Date.now()
})
// 延迟触发已关闭事件(给组件销毁留时间)
setTimeout(() => {
emitEvent(PANEL_EVENT_TYPES.CLOSED, {
panelId,
source: 'PanelHandler',
timestamp: Date.now()
})
}, 100)
// 清理本地状态
this.panelStates.delete(panelId)
return true
}
/**
* 切换工具栏显示
*/
async toggleToolbar(panelId, options = {}) {
const { priority = 3, silent = false } = options
if (!silent) {
console.log(`[PanelHandler] 切换工具栏: ${panelId}`)
}
// 更新本地状态
const panelState = this.panelStates.get(panelId) || { id: panelId }
panelState.toolbarExpanded = !panelState.toolbarExpanded
panelState.lastModified = Date.now()
this.panelStates.set(panelId, panelState)
return emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
panelId,
toolbarExpanded: panelState.toolbarExpanded,
source: 'PanelHandler'
}, { priority })
}
/**
* 开始拖拽
*/
async startDrag(panelId, dragEvent, options = {}) {
const { priority = 1 } = options
console.log(`[PanelHandler] 开始拖拽: ${panelId}`)
// 创建拖拽状态
const dragState = {
panelId,
startTime: Date.now(),
startPosition: {
x: dragEvent.clientX,
y: dragEvent.clientY
},
isActive: true
}
this.dragStates.set(panelId, dragState)
// 触发拖拽开始事件
return emitEvent(PANEL_EVENT_TYPES.DRAG_START, {
panelId,
event: dragEvent,
dragState,
source: 'PanelHandler'
}, { priority })
}
/**
* 拖拽移动
*/
async moveDrag(panelId, dragEvent, options = {}) {
const { priority = 2 } = options
const dragState = this.dragStates.get(panelId)
if (!dragState || !dragState.isActive) {
console.warn(`[PanelHandler] Panel ${panelId} 不在拖拽状态`)
return false
}
// 更新拖拽状态
dragState.currentPosition = {
x: dragEvent.clientX,
y: dragEvent.clientY
}
dragState.lastMove = Date.now()
// 触发拖拽移动事件
return emitEvent(PANEL_EVENT_TYPES.DRAG_MOVE, {
panelId,
event: dragEvent,
dragState,
delta: {
x: dragEvent.clientX - dragState.startPosition.x,
y: dragEvent.clientY - dragState.startPosition.y
},
source: 'PanelHandler'
}, { priority })
}
/**
* 结束拖拽
*/
async endDrag(panelId, dragEvent, options = {}) {
const { priority = 1 } = options
console.log(`[PanelHandler] 结束拖拽: ${panelId}`)
const dragState = this.dragStates.get(panelId)
if (!dragState) {
console.warn(`[PanelHandler] Panel ${panelId} 没有拖拽状态`)
return false
}
// 更新拖拽状态
dragState.isActive = false
dragState.endTime = Date.now()
dragState.endPosition = {
x: dragEvent.clientX,
y: dragEvent.clientY
}
// 触发拖拽结束事件
const result = await emitEvent(PANEL_EVENT_TYPES.DRAG_END, {
panelId,
event: dragEvent,
dragState,
duration: dragState.endTime - dragState.startTime,
source: 'PanelHandler'
}, { priority })
// 清理拖拽状态
this.dragStates.delete(panelId)
return result
}
/**
* 激活Panel
*/
async activate(panelId, options = {}) {
const { priority = 3, silent = false } = options
if (!silent) {
console.log(`[PanelHandler] 激活Panel: ${panelId}`)
}
// 更新本地状态
const panelState = this.panelStates.get(panelId) || { id: panelId }
panelState.active = true
panelState.activatedAt = Date.now()
panelState.lastModified = Date.now()
this.panelStates.set(panelId, panelState)
return emitEvent(PANEL_EVENT_TYPES.ACTIVATED, {
panelId,
source: 'PanelHandler',
timestamp: Date.now()
}, { priority })
}
/**
* 停用Panel
*/
async deactivate(panelId, options = {}) {
const { priority = 3, silent = false } = options
if (!silent) {
console.log(`[PanelHandler] 停用Panel: ${panelId}`)
}
// 更新本地状态
const panelState = this.panelStates.get(panelId) || { id: panelId }
panelState.active = false
panelState.deactivatedAt = Date.now()
panelState.lastModified = Date.now()
this.panelStates.set(panelId, panelState)
return emitEvent(PANEL_EVENT_TYPES.DEACTIVATED, {
panelId,
source: 'PanelHandler',
timestamp: Date.now()
}, { priority })
}
/**
* Panel拖拽结束处理
* @param {Object} eventData - 拖拽结束事件数据
*/
onDragEnd(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.DRAG_END, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel激活处理
* @param {Object} eventData - 激活事件数据
*/
onActivate(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.ACTIVATED, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel失活处理
* @param {Object} eventData - 失活事件数据
*/
onDeactivate(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.DEACTIVATED, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel折叠处理
* @param {Object} eventData - 折叠事件数据
*/
onCollapse(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.COLLAPSE, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel展开处理
* @param {Object} eventData - 展开事件数据
*/
onExpand(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.EXPAND, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel最大化处理
* @param {Object} eventData - 最大化事件数据
*/
onMaximize(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.MAXIMIZE, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel还原处理
* @param {Object} eventData - 还原事件数据
*/
onRestore(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.RESTORE, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel工具栏切换处理
* @param {Object} eventData - 工具栏切换事件数据
*/
onToggleToolbar(eventData) {
const { areaId, panelId } = eventData;
this.emitEvent(PANEL_EVENT_TYPES.TOGGLE_TOOLBAR, {
areaId,
panelId,
timestamp: Date.now()
});
}
/**
* Panel位置更新处理
* @param {Object} eventData - 位置更新事件数据
*/
onPositionUpdate(eventData) {
const { areaId, panelId, position } = eventData;
this.emitEvent('panel.position.update', {
areaId,
panelId,
position,
timestamp: Date.now()
});
}
/**
* Panel大小更新处理
* @param {Object} eventData - 大小更新事件数据
*/
onSizeUpdate(eventData) {
const { areaId, panelId, size } = eventData;
this.emitEvent('panel.size.update', {
areaId,
panelId,
size,
timestamp: Date.now()
});
}
/**
* 事件监听器注册
* @private
*/
_registerAdditionalEventListeners() {
// 监听来自事件总线的面板关闭请求
this.onEvent('PANEL_CLOSE_REQUEST', (eventData) => {
this.handlePanelCloseRequest(eventData);
});
// 监听最大化切换请求
this.onEvent('PANEL_MAXIMIZE_TOGGLE_REQUEST', (eventData) => {
const { panelId } = eventData;
this.maximize(panelId);
});
// 监听折叠切换请求
this.onEvent('PANEL_COLLAPSE_TOGGLE_REQUEST', (eventData) => {
const { panelId } = eventData;
this.toggleCollapse(panelId);
});
// 监听工具栏切换请求
this.onEvent('PANEL_TOOLBAR_TOGGLE_REQUEST', (eventData) => {
const { areaId, panelId } = eventData;
this.onToggleToolbar({ areaId, panelId });
});
// 监听激活请求
this.onEvent('PANEL_ACTIVATE_REQUEST', (eventData) => {
const { areaId, panelId } = eventData;
this.onActivate({ areaId, panelId });
});
// 监听失活请求
this.onEvent('PANEL_DEACTIVATE_REQUEST', (eventData) => {
const { areaId, panelId } = eventData;
this.onDeactivate({ areaId, panelId });
});
}
/**
* 同步最大化状态到Area
*/
async _syncMaximizeToArea(panelId, maximized = true) {
const panelState = this.panelStates.get(panelId)
if (!panelState) return
// 触发Area同步事件
return emitEvent(PANEL_EVENT_TYPES.MAXIMIZE_SYNC, {
panelId,
maximized,
areaId: panelState.areaId,
source: 'PanelHandler'
})
}
/**
* 注册事件监听器
*/
async _registerEventListeners() {
const events = [
PANEL_EVENT_TYPES.CLOSE_REQUEST,
PANEL_EVENT_TYPES.DRAG_START,
PANEL_EVENT_TYPES.DRAG_MOVE,
PANEL_EVENT_TYPES.DRAG_END,
PANEL_EVENT_TYPES.MAXIMIZE_SYNC
]
for (const eventType of events) {
const unsubscribe = await this._subscribeToEvent(eventType)
this.subscriptions.set(eventType, unsubscribe)
}
}
/**
* 订阅事件
*/
async _subscribeToEvent(eventType) {
return onEvent(eventType, (data, event) => {
this._handleEvent(eventType, data, event)
})
}
/**
* 处理事件
*/
_handleEvent(eventType, data, event) {
switch (eventType) {
case PANEL_EVENT_TYPES.CLOSE_REQUEST:
this._handleCloseRequest(data, event)
break
case PANEL_EVENT_TYPES.DRAG_START:
this._handleDragStart(data, event)
break
case PANEL_EVENT_TYPES.DRAG_MOVE:
this._handleDragMove(data, event)
break
case PANEL_EVENT_TYPES.DRAG_END:
this._handleDragEnd(data, event)
break
case PANEL_EVENT_TYPES.MAXIMIZE_SYNC:
this._handleMaximizeSync(data, event)
break
}
}
/**
* 处理关闭请求事件
*/
_handleCloseRequest(data, event) {
// 可以在这里添加关闭前的验证逻辑
console.log(`[PanelHandler] 处理关闭请求: ${data.panelId}`)
}
/**
* 处理拖拽开始事件
*/
_handleDragStart(data, event) {
console.log(`[PanelHandler] 处理拖拽开始: ${data.panelId}`)
}
/**
* 处理拖拽移动事件
*/
_handleDragMove(data, event) {
console.log(`[PanelHandler] 处理拖拽移动: ${data.panelId}`)
}
/**
* 处理拖拽结束事件
*/
_handleDragEnd(data, event) {
console.log(`[PanelHandler] 处理拖拽结束: ${data.panelId}`)
}
/**
* 处理最大化同步事件
*/
_handleMaximizeSync(data, event) {
console.log(`[PanelHandler] 处理最大化同步: ${data.panelId} -> ${data.maximized}`)
}
/**
* 清理事件监听器
*/
async _cleanupEventListeners() {
for (const [eventType, unsubscribe] of this.subscriptions.entries()) {
try {
unsubscribe()
console.log(`[PanelHandler:${this.handlerId}] 已清理事件监听: ${eventType}`)
} catch (error) {
console.warn(`[PanelHandler:${this.handlerId}] 清理事件监听失败: ${eventType}`, error)
}
}
this.subscriptions.clear()
}
/**
* 初始化内存保护
*/
_initializeMemoryProtection() {
if (!window.__panelMemoryProtection) {
window.__panelMemoryProtection = {
panelInstances: new Map(),
handlers: new Map(),
startLeakDetection: () => {
setInterval(() => {
this._checkMemoryLeaks()
}, 30000) // 30秒检查一次
}
}
}
this.memoryProtection = window.__panelMemoryProtection
}
/**
* 清理内存保护
*/
_cleanupMemoryProtection() {
if (this.memoryProtection) {
this.memoryProtection.handlers.delete(this.handlerId)
}
}
/**
* 启动内存泄漏检测
*/
_startMemoryLeakDetection() {
if (this.memoryProtection) {
this.memoryProtection.handlers.set(this.handlerId, {
createdAt: Date.now(),
type: 'PanelHandler',
subscriptions: this.subscriptions.size,
dragStates: this.dragStates.size,
panelStates: this.panelStates.size
})
}
}
/**
* 检查内存泄漏
*/
_checkMemoryLeaks() {
const activeDrags = this.dragStates.size
const registeredHandlers = this.memoryProtection?.handlers.size || 0
if (activeDrags > 10) {
console.warn(`[PanelHandler] 发现大量活跃拖拽状态: ${activeDrags}`)
}
if (registeredHandlers > 5) {
console.warn(`[PanelHandler] 发现多个PanelHandler实例: ${registeredHandlers}`)
}
}
/**
* 获取Panel状态
*/
getPanelState(panelId) {
return this.panelStates.get(panelId)
}
/**
* 获取所有Panel状态
*/
getAllPanelStates() {
return Object.fromEntries(this.panelStates)
}
/**
* 获取拖拽状态
*/
getDragState(panelId) {
return this.dragStates.get(panelId)
}
/**
* 获取活跃的拖拽状态
*/
getActiveDrags() {
return Array.from(this.dragStates.values()).filter(state => state.isActive)
}
/**
* 取消所有拖拽
*/
cancelAllDrags() {
const activeDrags = this.getActiveDrags()
for (const dragState of activeDrags) {
this.endDrag(dragState.panelId, {
clientX: dragState.endPosition?.x || dragState.startPosition.x,
clientY: dragState.endPosition?.y || dragState.startPosition.y
})
}
}
/**
* 获取统计信息
*/
getStats() {
return {
handlerId: this.handlerId,
isInitialized: this.isInitialized,
panelCount: this.panelStates.size,
activeDrags: this.getActiveDrags().length,
subscriptionCount: this.subscriptions.size,
memoryProtected: !!this.memoryProtection
}
}
}
// 创建全局Panel事件处理器实例
export const panelHandler = new PanelEventHandler()
// 便捷的操作函数
export const panelActions = {
// 基础操作
toggleCollapse: (panelId, options) => panelHandler.toggleCollapse(panelId, options),
maximize: (panelId, options) => panelHandler.maximize(panelId, options),
restore: (panelId, options) => panelHandler.restore(panelId, options),
requestClose: (panelId, options) => panelHandler.requestClose(panelId, options),
toggleToolbar: (panelId, options) => panelHandler.toggleToolbar(panelId, options),
// 拖拽操作
startDrag: (panelId, event, options) => panelHandler.startDrag(panelId, event, options),
moveDrag: (panelId, event, options) => panelHandler.moveDrag(panelId, event, options),
endDrag: (panelId, event, options) => panelHandler.endDrag(panelId, event, options),
// 状态操作
activate: (panelId, options) => panelHandler.activate(panelId, options),
deactivate: (panelId, options) => panelHandler.deactivate(panelId, options),
// 批量操作
cancelAllDrags: () => panelHandler.cancelAllDrags(),
// 查询操作
getState: (panelId) => panelHandler.getPanelState(panelId),
getAllStates: () => panelHandler.getAllPanelStates(),
getDragState: (panelId) => panelHandler.getDragState(panelId),
getActiveDrags: () => panelHandler.getActiveDrags(),
getStats: () => panelHandler.getStats()
}
// 初始化和销毁函数
export const initializePanelHandler = () => panelHandler.initialize()
export const destroyPanelHandler = () => panelHandler.destroy()
// 注册到事件处理器注册表
export const registerPanelHandler = () => {
return registerHandler('PanelHandler', Object.values(PANEL_EVENT_TYPES), panelHandler)
}
export const unregisterPanelHandler = () => {
return unregisterHandler('PanelHandler')
}

View File

@@ -0,0 +1,749 @@
/**
* TabPage事件处理器
* 专门处理TabPage相关的所有事件包括标签页拖拽、切换、关闭、激活等
*/
import { eventBus } from '../eventBus.js';
// TabPage事件类型常量
export const TABPAGE_EVENT_TYPES = {
// 基础事件
TABPAGE_CREATED: 'tabPage.created',
TABPAGE_DESTROYED: 'tabPage.destroyed',
TABPAGE_UPDATED: 'tabPage.updated',
// 标签页操作
TABPAGE_SWITCH: 'tabPage.switch',
TABPAGE_CLOSE_REQUEST: 'tabPage.close.request',
TABPAGE_CLOSE: 'tabPage.close',
TABPAGE_CLOSED: 'tabPage.closed',
// 拖拽相关
TABPAGE_DRAG_START: 'tabPage.drag.start',
TABPAGE_DRAG_MOVE: 'tabPage.drag.move',
TABPAGE_DRAG_END: 'tabPage.drag.end',
TABPAGE_DRAG_OVER: 'tabPage.drag.over',
TABPAGE_DRAG_LEAVE: 'tabPage.drag.leave',
// 标签页组操作
TABPAGE_GROUP_CREATE: 'tabPage.group.create',
TABPAGE_GROUP_CLOSE: 'tabPage.group.close',
TABPAGE_GROUP_MERGE: 'tabPage.group.merge',
TABPAGE_GROUP_SPLIT: 'tabPage.group.split',
// 激活状态
TABPAGE_ACTIVATED: 'tabPage.activated',
TABPAGE_DEACTIVATED: 'tabPage.deactivated',
TABPAGE_FOCUS_CHANGED: 'tabPage.focus.changed',
// 内容相关
TABPAGE_CONTENT_LOAD: 'tabPage.content.load',
TABPAGE_CONTENT_UNLOAD: 'tabPage.content.unload',
TABPAGE_CONTENT_ERROR: 'tabPage.content.error',
// 与Area的交互
TABPAGE_AREA_SYNC: 'tabPage.area.sync',
TABPAGE_AREA_MAXIMIZE: 'tabPage.area.maximize'
};
// TabPage状态管理
class TabPageStateManager {
constructor() {
this.states = new Map();
this.history = [];
this.maxHistorySize = 50;
}
/**
* 更新TabPage状态
* @param {string} tabPageId - TabPage ID
* @param {Object} updates - 状态更新
*/
updateState(tabPageId, updates) {
const currentState = this.states.get(tabPageId) || {};
const newState = { ...currentState, ...updates, lastUpdated: Date.now() };
// 记录历史
this.history.push({
tabPageId,
oldState: currentState,
newState,
timestamp: Date.now()
});
// 限制历史记录大小
if (this.history.length > this.maxHistorySize) {
this.history.shift();
}
this.states.set(tabPageId, newState);
// 触发状态更新事件
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_UPDATED, {
tabPageId,
oldState: currentState,
newState,
updates
});
}
/**
* 获取TabPage状态
* @param {string} tabPageId - TabPage ID
* @returns {Object} TabPage状态
*/
getState(tabPageId) {
return this.states.get(tabPageId) || {};
}
/**
* 检查TabPage是否存在
* @param {string} tabPageId - TabPage ID
* @returns {boolean} 是否存在
*/
hasTabPage(tabPageId) {
return this.states.has(tabPageId);
}
/**
* 删除TabPage状态
* @param {string} tabPageId - TabPage ID
*/
removeState(tabPageId) {
this.states.delete(tabPageId);
}
/**
* 获取历史记录
* @param {number} limit - 限制数量
* @returns {Array} 历史记录
*/
getHistory(limit = 10) {
return this.history.slice(-limit);
}
/**
* 清理过期的历史记录
* @param {number} maxAge - 最大年龄(毫秒)
*/
cleanupHistory(maxAge = 3600000) { // 1小时
const now = Date.now();
this.history = this.history.filter(record => (now - record.timestamp) < maxAge);
}
}
/**
* TabPage事件处理器类
*/
class TabPageEventHandler {
constructor() {
this.tabPageStateManager = new TabPageStateManager();
this.dragState = new Map();
this.activeTabPages = new Set();
this.tabPageListeners = new Map();
this.memoryProtection = {
maxTabPages: 100,
cleanupInterval: 30000,
lastCleanup: 0
};
// 绑定方法
this._onTabPageEvent = this._onTabPageEvent.bind(this);
this._onMemoryCheck = this._onMemoryCheck.bind(this);
this._initialize();
}
/**
* 初始化事件处理器
*/
_initialize() {
// 监听各种TabPage事件
this._registerEventListeners();
// 定期内存检查
this._startMemoryProtection();
console.log('✅ TabPage事件处理器初始化完成');
}
/**
* 注册事件监听器
*/
_registerEventListeners() {
const events = Object.values(TABPAGE_EVENT_TYPES);
events.forEach(eventType => {
const listener = this._onTabPageEvent;
eventBus.on(eventType, listener, {
priority: 1,
deduplication: { type: 'TTL_BASED', ttl: 100 }
});
this.tabPageListeners.set(eventType, listener);
});
}
/**
* 处理TabPage事件
* @param {Object} data - 事件数据
* @param {string} data.eventType - 事件类型
*/
async _onTabPageEvent(data) {
const { eventType } = data;
try {
switch (eventType) {
case TABPAGE_EVENT_TYPES.TABPAGE_CREATED:
await this._handleTabPageCreated(data);
break;
case TABPAGE_EVENT_TYPES.TABPAGE_DESTROYED:
await this._handleTabPageDestroyed(data);
break;
case TABPAGE_EVENT_TYPES.TABPAGE_DRAG_START:
await this._handleTabPageDragStart(data);
break;
case TABPAGE_EVENT_TYPES.TABPAGE_DRAG_MOVE:
await this._handleTabPageDragMove(data);
break;
case TABPAGE_EVENT_TYPES.TABPAGE_DRAG_END:
await this._handleTabPageDragEnd(data);
break;
case TABPAGE_EVENT_TYPES.TABPAGE_SWITCH:
await this._handleTabPageSwitch(data);
break;
case TABPAGE_EVENT_TYPES.TABPAGE_CLOSE_REQUEST:
await this._handleTabPageCloseRequest(data);
break;
case TABPAGE_EVENT_TYPES.TABPAGE_GROUP_MERGE:
await this._handleTabPageGroupMerge(data);
break;
default:
// 记录其他事件但不处理
console.log(`📋 TabPage事件处理器: ${eventType}`, data);
}
} catch (error) {
console.error(`❌ TabPage事件处理错误 (${eventType}):`, error);
eventBus.recordError(`tabPageHandler_${eventType}`, error);
}
}
/**
* 处理TabPage创建事件
* @param {Object} data - 事件数据
*/
async _handleTabPageCreated(data) {
const { tabPageId, areaId, config } = data;
// 初始化TabPage状态
this.tabPageStateManager.updateState(tabPageId, {
id: tabPageId,
areaId,
active: false,
panels: [],
title: config?.title || `标签页 ${tabPageId}`,
closable: config?.closable !== false,
draggable: config?.draggable !== false,
createdAt: Date.now(),
lastActiveAt: null
});
// 触发TabPage组创建事件
if (data.panels && data.panels.length > 0) {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_GROUP_CREATE, {
tabPageId,
areaId,
panelCount: data.panels.length,
panels: data.panels
});
}
}
/**
* 处理TabPage销毁事件
* @param {Object} data - 事件数据
*/
async _handleTabPageDestroyed(data) {
const { tabPageId, areaId } = data;
// 清理状态
this.tabPageStateManager.removeState(tabPageId);
// 从活动TabPage集合中移除
this.activeTabPages.delete(tabPageId);
// 清理拖拽状态
this.dragState.delete(tabPageId);
// 触发销毁完成事件
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CLOSED, {
tabPageId,
areaId,
destroyedAt: Date.now()
});
}
/**
* 处理TabPage拖拽开始事件
* @param {Object} data - 事件数据
*/
async _handleTabPageDragStart(data) {
const { tabPageId, areaId, event } = data;
// 记录拖拽状态
this.dragState.set(tabPageId, {
areaId,
startTime: Date.now(),
startPosition: {
x: event.clientX,
y: event.clientY
},
isDragging: true,
dragSource: 'tabPage'
});
// 检查是否可以通过TabPage标签移动Area
const state = this.tabPageStateManager.getState(tabPageId);
if (state.panels && state.panels.length === 1) {
// 允许通过TabPage标签拖动Area
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_AREA_SYNC, {
tabPageId,
areaId,
allowAreaDrag: true,
reason: 'singlePanelTabPage'
});
}
}
/**
* 处理TabPage拖拽移动事件
* @param {Object} data - 事件数据
*/
async _handleTabPageDragMove(data) {
const { tabPageId, event } = data;
const dragInfo = this.dragState.get(tabPageId);
if (!dragInfo || !dragInfo.isDragging) return;
// 计算移动距离
const deltaX = event.clientX - dragInfo.startPosition.x;
const deltaY = event.clientY - dragInfo.startPosition.y;
// 更新拖拽状态
dragInfo.lastPosition = { x: event.clientX, y: event.clientY };
dragInfo.delta = { x: deltaX, y: deltaY };
// 触发TabPage移动事件
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_DRAG_MOVE, {
tabPageId,
areaId: dragInfo.areaId,
delta: { x: deltaX, y: deltaY },
position: { x: event.clientX, y: event.clientY },
isDragging: dragInfo.isDragging
});
}
/**
* 处理TabPage拖拽结束事件
* @param {Object} data - 事件数据
*/
async _handleTabPageDragEnd(data) {
const { tabPageId, event } = data;
const dragInfo = this.dragState.get(tabPageId);
if (!dragInfo) return;
const dragDuration = Date.now() - dragInfo.startTime;
const distance = dragInfo.delta ?
Math.sqrt(dragInfo.delta.x ** 2 + dragInfo.delta.y ** 2) : 0;
// 清理拖拽状态
dragInfo.isDragging = false;
dragInfo.endTime = Date.now();
dragInfo.endPosition = { x: event.clientX, y: event.clientY };
dragInfo.totalDistance = distance;
dragInfo.duration = dragDuration;
// 触发拖拽结束事件
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_DRAG_END, {
tabPageId,
areaId: dragInfo.areaId,
dragInfo: {
duration: dragDuration,
distance: distance,
startPosition: dragInfo.startPosition,
endPosition: dragInfo.endPosition,
delta: dragInfo.delta
}
});
// 延迟清理拖拽状态
setTimeout(() => {
this.dragState.delete(tabPageId);
}, 1000);
}
/**
* 处理TabPage切换事件
* @param {Object} data - 事件数据
*/
async _handleTabPageSwitch(data) {
const { tabPageId, areaId, fromTabPageId } = data;
// 更新状态
if (fromTabPageId) {
this.tabPageStateManager.updateState(fromTabPageId, { active: false });
this.activeTabPages.delete(fromTabPageId);
}
this.tabPageStateManager.updateState(tabPageId, {
active: true,
lastActiveAt: Date.now()
});
this.activeTabPages.add(tabPageId);
// 触发激活/停用事件
if (fromTabPageId) {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_DEACTIVATED, {
tabPageId: fromTabPageId,
areaId
});
}
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_ACTIVATED, {
tabPageId,
areaId,
previousTabPageId: fromTabPageId
});
}
/**
* 处理TabPage关闭请求事件
* @param {Object} data - 事件数据
*/
async _handleTabPageCloseRequest(data) {
const { tabPageId, areaId, reason = 'user' } = data;
const state = this.tabPageStateManager.getState(tabPageId);
// 检查是否可以关闭
if (!state.closable) {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CLOSE, {
tabPageId,
areaId,
success: false,
reason: 'not_closable',
message: '该标签页不允许关闭'
});
return;
}
// 触发内容卸载事件
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CONTENT_UNLOAD, {
tabPageId,
areaId,
panels: state.panels || []
});
// 触发关闭事件
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CLOSE, {
tabPageId,
areaId,
success: true,
reason,
timestamp: Date.now()
});
}
/**
* 处理TabPage组合并事件
* @param {Object} data - 事件数据
*/
async _handleTabPageGroupMerge(data) {
const { sourceTabPageId, targetTabPageId, sourceAreaId, targetAreaId } = data;
// 获取源和目标TabPage状态
const sourceState = this.tabPageStateManager.getState(sourceTabPageId);
const targetState = this.tabPageStateManager.getState(targetTabPageId);
// 执行合并逻辑
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_GROUP_MERGE, {
sourceTabPageId,
targetTabPageId,
sourceAreaId,
targetAreaId,
sourcePanels: sourceState.panels || [],
targetPanels: targetState.panels || [],
mergeType: 'tabGroup',
timestamp: Date.now()
});
// 更新状态
this.tabPageStateManager.updateState(targetTabPageId, {
panels: [...(targetState.panels || []), ...(sourceState.panels || [])]
});
}
/**
* 启动内存保护机制
*/
_startMemoryProtection() {
setInterval(() => {
this._onMemoryCheck();
}, this.memoryProtection.cleanupInterval);
}
/**
* 内存检查和清理
*/
_onMemoryCheck() {
const now = Date.now();
// 清理过期的历史记录
this.tabPageStateManager.cleanupHistory();
// 检查TabPage数量限制
if (this.tabPageStateManager.states.size > this.memoryProtection.maxTabPages) {
console.warn(`⚠️ TabPage数量超过限制: ${this.tabPageStateManager.states.size}`);
// 清理最旧的非活动TabPage
const inactiveTabPages = Array.from(this.tabPageStateManager.states.entries())
.filter(([_, state]) => !state.active)
.sort((a, b) => (a[1].lastActiveAt || 0) - (b[1].lastActiveAt || 0));
const toRemove = inactiveTabPages.slice(0, 10); // 移除10个最旧的
toRemove.forEach(([tabPageId]) => {
this.tabPageStateManager.removeState(tabPageId);
console.log(`🗑️ 清理过期TabPage: ${tabPageId}`);
});
}
this.memoryProtection.lastCleanup = now;
}
/**
* 获取TabPage状态
* @param {string} tabPageId - TabPage ID
* @returns {Object} TabPage状态
*/
getTabPageState(tabPageId) {
return this.tabPageStateManager.getState(tabPageId);
}
/**
* 获取所有活动TabPage
* @returns {Array} 活动TabPage ID列表
*/
getActiveTabPages() {
return Array.from(this.activeTabPages);
}
/**
* 获取拖拽状态
* @param {string} tabPageId - TabPage ID
* @returns {Object} 拖拽状态
*/
getDragState(tabPageId) {
return this.dragState.get(tabPageId);
}
/**
* 获取统计信息
* @returns {Object} 统计信息
*/
getStats() {
return {
totalTabPages: this.tabPageStateManager.states.size,
activeTabPages: this.activeTabPages.size,
draggingTabPages: this.dragState.size,
historySize: this.tabPageStateManager.history.length
};
}
/**
* 销毁事件处理器
*/
destroy() {
// 清理事件监听器
this.tabPageListeners.forEach((listener, eventType) => {
eventBus.off(eventType, listener);
});
this.tabPageListeners.clear();
// 清理状态
this.tabPageStateManager.states.clear();
this.activeTabPages.clear();
this.dragState.clear();
console.log('🗑️ TabPage事件处理器已销毁');
}
}
// 创建单例实例
const tabPageHandler = new TabPageEventHandler();
// TabPage便捷操作函数
export const tabPageActions = {
/**
* 创建新TabPage
* @param {string} areaId - 所属Area ID
* @param {Object} config - TabPage配置
* @returns {string} TabPage ID
*/
create: (areaId, config = {}) => {
const tabPageId = `tabPage-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CREATED, {
tabPageId,
areaId,
config,
timestamp: Date.now()
});
return tabPageId;
},
/**
* 切换到指定TabPage
* @param {string} tabPageId - TabPage ID
* @param {string} areaId - Area ID
* @param {string} fromTabPageId - 源TabPage ID
*/
switch: (tabPageId, areaId, fromTabPageId = null) => {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_SWITCH, {
tabPageId,
areaId,
fromTabPageId,
timestamp: Date.now()
});
},
/**
* 开始TabPage拖拽
* @param {string} tabPageId - TabPage ID
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
startDrag: (tabPageId, areaId, event) => {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_DRAG_START, {
tabPageId,
areaId,
event,
timestamp: Date.now()
});
},
/**
* TabPage拖拽移动
* @param {string} tabPageId - TabPage ID
* @param {Event} event - 拖拽事件
*/
moveDrag: (tabPageId, event) => {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_DRAG_MOVE, {
tabPageId,
event,
timestamp: Date.now()
});
},
/**
* 结束TabPage拖拽
* @param {string} tabPageId - TabPage ID
* @param {Event} event - 拖拽事件
*/
endDrag: (tabPageId, event) => {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_DRAG_END, {
tabPageId,
event,
timestamp: Date.now()
});
},
/**
* 请求关闭TabPage
* @param {string} tabPageId - TabPage ID
* @param {string} areaId - Area ID
* @param {string} reason - 关闭原因
*/
requestClose: (tabPageId, areaId, reason = 'user') => {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_CLOSE_REQUEST, {
tabPageId,
areaId,
reason,
timestamp: Date.now()
});
},
/**
* 更新TabPage状态
* @param {string} tabPageId - TabPage ID
* @param {Object} updates - 状态更新
*/
updateState: (tabPageId, updates) => {
tabPageHandler.tabPageStateManager.updateState(tabPageId, updates);
},
/**
* 合并TabPage组
* @param {string} sourceTabPageId - 源TabPage ID
* @param {string} targetTabPageId - 目标TabPage ID
* @param {string} sourceAreaId - 源Area ID
* @param {string} targetAreaId - 目标Area ID
*/
mergeGroup: (sourceTabPageId, targetTabPageId, sourceAreaId, targetAreaId) => {
eventBus.emit(TABPAGE_EVENT_TYPES.TABPAGE_GROUP_MERGE, {
sourceTabPageId,
targetTabPageId,
sourceAreaId,
targetAreaId,
timestamp: Date.now()
});
}
};
// 导出事件处理器和相关API
export default tabPageHandler;
// 便利的TabPage拖拽处理函数
export const triggerTabPageDrag = {
/**
* 开始TabPage标签拖拽
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
start: (areaId, event) => {
// 获取当前TabPage ID
const tabPageId = event.currentTarget?.getAttribute('data-tabpage-id') ||
event.currentTarget?.closest('[data-tabpage-id]')?.getAttribute('data-tabpage-id');
if (tabPageId) {
tabPageActions.startDrag(tabPageId, areaId, event);
}
},
/**
* 处理TabPage标签拖拽移动
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
move: (areaId, event) => {
const tabPageId = event.currentTarget?.getAttribute('data-tabpage-id') ||
event.currentTarget?.closest('[data-tabpage-id]')?.getAttribute('data-tabpage-id');
if (tabPageId) {
tabPageActions.moveDrag(tabPageId, event);
}
},
/**
* 结束TabPage标签拖拽
* @param {string} areaId - Area ID
* @param {Event} event - 拖拽事件
*/
end: (areaId, event) => {
const tabPageId = event.currentTarget?.getAttribute('data-tabpage-id') ||
event.currentTarget?.closest('[data-tabpage-id]')?.getAttribute('data-tabpage-id');
if (tabPageId) {
tabPageActions.endDrag(tabPageId, event);
}
}
};