完善事件总线功能,创建专门的事件处理器模块
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局事件总线实例
|
||||
|
||||
1504
AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/AreaHandler.js
Normal file
1504
AutoRobot/Windows/Robot/Web/src/DockLayout/handlers/AreaHandler.js
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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')
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user