面板最大化和还原
This commit is contained in:
@@ -48,6 +48,11 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, onUnmounted, defineEmits } from 'vue'
|
import { ref, computed, onMounted, onUnmounted, defineEmits } from 'vue'
|
||||||
import Area from './Area.vue';
|
import Area from './Area.vue';
|
||||||
|
import { getAreaHandler } from './handlers/AreaHandler';
|
||||||
|
|
||||||
|
// 获取AreaHandler实例
|
||||||
|
const areaHandler = getAreaHandler();
|
||||||
|
|
||||||
import Panel from './Panel.vue';
|
import Panel from './Panel.vue';
|
||||||
import TabPage from './TabPage.vue';
|
import TabPage from './TabPage.vue';
|
||||||
import DockIndicator from './DockIndicator.vue';
|
import DockIndicator from './DockIndicator.vue';
|
||||||
@@ -171,6 +176,44 @@ const onUpdatePosition = (event) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理Area更新事件
|
||||||
|
const onAreaUpdated = (event) => {
|
||||||
|
const id = event.areaId;
|
||||||
|
const updates = event.updates;
|
||||||
|
const area = floatingAreas.value.find(a => a.id === id);
|
||||||
|
if (area) {
|
||||||
|
// 合并更新到Area对象
|
||||||
|
Object.assign(area, updates);
|
||||||
|
|
||||||
|
// 如果是最大化状态变化,发送panel.maximize.sync事件
|
||||||
|
if ('maximized' in updates || 'windowState' in updates) {
|
||||||
|
// 查找该区域下的所有Panel
|
||||||
|
const areaState = areaHandler.areaStateManager.getState(id);
|
||||||
|
if (areaState && areaState.children) {
|
||||||
|
const childrenArray = Array.isArray(areaState.children) ? areaState.children : [areaState.children];
|
||||||
|
|
||||||
|
// 查找TabPage
|
||||||
|
childrenArray.forEach(child => {
|
||||||
|
if (child.type === 'TabPage' && child.children) {
|
||||||
|
const tabChildrenArray = Array.isArray(child.children) ? child.children : [child.children];
|
||||||
|
|
||||||
|
// 发送panel.maximize.sync事件给每个Panel
|
||||||
|
tabChildrenArray.forEach(tabChild => {
|
||||||
|
if (tabChild.type === 'Panel') {
|
||||||
|
eventBus.emit(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, {
|
||||||
|
panelId: tabChild.id,
|
||||||
|
areaId: id,
|
||||||
|
maximized: updates.maximized !== undefined ? updates.maximized : (updates.windowState === '最大化' || updates.windowState === 'maximized')
|
||||||
|
}, { componentId: 'dock-layout' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onMaximize = (event) => {
|
const onMaximize = (event) => {
|
||||||
const panelId = event.panelId;
|
const panelId = event.panelId;
|
||||||
const areaId = event.areaId;
|
const areaId = event.areaId;
|
||||||
@@ -431,10 +474,10 @@ const setupEventListeners = () => {
|
|||||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_OVER, handleAreaDragOver, { componentId: 'dock-layout' }));
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_OVER, handleAreaDragOver, { componentId: 'dock-layout' }));
|
||||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_LEAVE, handleAreaDragLeave, { componentId: 'dock-layout' }));
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_LEAVE, handleAreaDragLeave, { componentId: 'dock-layout' }));
|
||||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_MERGE_REQUEST, handleAreaMergeRequest, { componentId: 'dock-layout' }));
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_MERGE_REQUEST, handleAreaMergeRequest, { componentId: 'dock-layout' }));
|
||||||
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_UPDATED, onAreaUpdated, { componentId: 'dock-layout' }));
|
||||||
|
|
||||||
// 添加新的下降事件监听器
|
// 添加新的下降事件监听器
|
||||||
unsubscribeFunctions.push(eventBus.on('area.position.update', onAreaPositionUpdate, { componentId: 'dock-layout' }));
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_DRAG_STATE_UPDATE, onAreaDragStateUpdate, { componentId: 'dock-layout' }));
|
||||||
unsubscribeFunctions.push(eventBus.on('area.drag.state.update', onAreaDragStateUpdate, { componentId: 'dock-layout' }));
|
|
||||||
|
|
||||||
// Tab相关事件
|
// Tab相关事件
|
||||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange, { componentId: 'dock-layout' }));
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange, { componentId: 'dock-layout' }));
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
<button class="button-icon p-[2px] rounded hover:opacity-100 opacity-80"
|
<button class="button-icon p-[2px] rounded hover:opacity-100 opacity-80"
|
||||||
@click.stop="onMaximize"
|
@click.stop="onMaximize"
|
||||||
@mousedown.stop
|
@mousedown.stop
|
||||||
:aria-label="maximized ? '还原' : '最大化'">
|
:aria-label="isMaximized ? '还原' : '最大化'">
|
||||||
<!-- 最大化图标 -->
|
<!-- 最大化图标 -->
|
||||||
<template v-if="!maximized">
|
<template v-if="!isMaximized">
|
||||||
<!-- 最大化图标:外框 + 内部线条 -->
|
<!-- 最大化图标:外框 + 内部线条 -->
|
||||||
<svg class="icon-square-svg" width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
|
<svg class="icon-square-svg" width="11" height="11" viewBox="0 0 11 11" aria-hidden="true">
|
||||||
<rect x="0.5" y="0.5" width="10" height="10" fill="#cbd6ff" stroke="#8ea3d8" stroke-width="1" />
|
<rect x="0.5" y="0.5" width="10" height="10" fill="#cbd6ff" stroke="#8ea3d8" stroke-width="1" />
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineProps, onMounted, onUnmounted } from 'vue';
|
import { defineProps, onMounted, onUnmounted, ref } from 'vue';
|
||||||
import {
|
import {
|
||||||
eventBus,
|
eventBus,
|
||||||
EVENT_TYPES,
|
EVENT_TYPES,
|
||||||
@@ -174,6 +174,9 @@ const props = defineProps({
|
|||||||
const subscriptions = new Set();
|
const subscriptions = new Set();
|
||||||
const subscriptionRegistry = new Map();
|
const subscriptionRegistry = new Map();
|
||||||
|
|
||||||
|
// 响应式的最大化状态,初始化为props.maximized
|
||||||
|
const isMaximized = ref(props.maximized);
|
||||||
|
|
||||||
const getCurrentAreaId = () => {
|
const getCurrentAreaId = () => {
|
||||||
const panelElement = document.querySelector(`[data-panel-id="${props.id}"]`);
|
const panelElement = document.querySelector(`[data-panel-id="${props.id}"]`);
|
||||||
if (panelElement) {
|
if (panelElement) {
|
||||||
@@ -212,7 +215,7 @@ const onMaximize = () => {
|
|||||||
emitEvent(EVENT_TYPES.PANEL_MAXIMIZE, {
|
emitEvent(EVENT_TYPES.PANEL_MAXIMIZE, {
|
||||||
panelId: props.id,
|
panelId: props.id,
|
||||||
areaId: getCurrentAreaId(),
|
areaId: getCurrentAreaId(),
|
||||||
currentState: props.maximized
|
currentState: isMaximized.value
|
||||||
}, {
|
}, {
|
||||||
source: { component: 'Panel', panelId: props.id }
|
source: { component: 'Panel', panelId: props.id }
|
||||||
})
|
})
|
||||||
@@ -303,7 +306,7 @@ const onDragStart = (e) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDragEnd = () => {
|
const onDragEnd = (e) => {
|
||||||
if (isDragging) {
|
if (isDragging) {
|
||||||
isDragging = false
|
isDragging = false
|
||||||
// 获取所有浮动区域信息,用于单面板检测
|
// 获取所有浮动区域信息,用于单面板检测
|
||||||
@@ -313,6 +316,7 @@ const onDragStart = (e) => {
|
|||||||
dragId: currentDragId,
|
dragId: currentDragId,
|
||||||
panelId: props.id,
|
panelId: props.id,
|
||||||
areaId: currentAreaId,
|
areaId: currentAreaId,
|
||||||
|
position: { x: e.clientX, y: e.clientY },
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
layout: {
|
layout: {
|
||||||
areas: floatingAreas
|
areas: floatingAreas
|
||||||
@@ -349,8 +353,10 @@ const setupEventListeners = () => {
|
|||||||
|
|
||||||
// 监听面板最大化同步事件
|
// 监听面板最大化同步事件
|
||||||
const unsubscribeMaximizeSync = onEvent(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, (data) => {
|
const unsubscribeMaximizeSync = onEvent(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, (data) => {
|
||||||
if (data.panelId === props.id) {
|
// 同时检查panelId和areaId,确保正确匹配
|
||||||
console.log(`[Panel:${props.id}] 收到最大化同步事件`)
|
if (data.panelId === props.id || data.areaId === getCurrentAreaId()) {
|
||||||
|
console.log(`[Panel:${props.id}] 收到最大化同步事件:`, data);
|
||||||
|
isMaximized.value = data.maximized;
|
||||||
}
|
}
|
||||||
}, { componentId: `panel-${props.id}` })
|
}, { componentId: `panel-${props.id}` })
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,44 @@ import { nanoid } from 'nanoid'
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const EVENT_TYPES = {
|
export const EVENT_TYPES = {
|
||||||
|
// 系统级事件
|
||||||
|
SYSTEM_INIT: 'system.init',
|
||||||
|
SYSTEM_READY: 'system.ready',
|
||||||
|
SYSTEM_DESTROY: 'system.destroy',
|
||||||
|
SYSTEM_ERROR: 'system.error',
|
||||||
|
SYSTEM_PERFORMANCE: 'system.performance',
|
||||||
|
|
||||||
|
// 事件路由
|
||||||
|
EVENT_ROUTE_START: 'event.route.start',
|
||||||
|
EVENT_ROUTE_SUCCESS: 'event.route.success',
|
||||||
|
EVENT_ROUTE_ERROR: 'event.route.error',
|
||||||
|
EVENT_ROUTE_FALLBACK: 'event.route.fallback',
|
||||||
|
EVENT_RISING: 'event.rising',
|
||||||
|
EVENT_FALLING: 'event.falling',
|
||||||
|
|
||||||
|
// 跨组件通信
|
||||||
|
CROSS_COMPONENT_BROADCAST: 'cross.component.broadcast',
|
||||||
|
CROSS_COMPONENT_REQUEST: 'cross.component.request',
|
||||||
|
CROSS_COMPONENT_RESPONSE: 'cross.component.response',
|
||||||
|
|
||||||
|
// 事件链
|
||||||
|
EVENT_CHAIN_START: 'event.chain.start',
|
||||||
|
EVENT_CHAIN_PROGRESS: 'event.chain.progress',
|
||||||
|
EVENT_CHAIN_COMPLETE: 'event.chain.complete',
|
||||||
|
EVENT_CHAIN_ERROR: 'event.chain.error',
|
||||||
|
|
||||||
|
// 性能监控
|
||||||
|
PERFORMANCE_MONITOR_START: 'performance.monitor.start',
|
||||||
|
PERFORMANCE_MONITOR_END: 'performance.monitor.end',
|
||||||
|
PERFORMANCE_THRESHOLD_EXCEEDED: 'performance.threshold.exceeded',
|
||||||
|
|
||||||
|
// 调试和日志
|
||||||
|
DEBUG_EVENT_EMIT: 'debug.event.emit',
|
||||||
|
DEBUG_EVENT_HANDLE: 'debug.event.handle',
|
||||||
|
DEBUG_PERFORMANCE: 'debug.performance',
|
||||||
|
DEBUG_MEMORY: 'debug.memory',
|
||||||
|
DEBUG_TOGGLE: 'debug.toggle',
|
||||||
|
|
||||||
AREA_CLOSE: 'area.close',
|
AREA_CLOSE: 'area.close',
|
||||||
AREA_POSITION_UPDATE: 'area.position.update',
|
AREA_POSITION_UPDATE: 'area.position.update',
|
||||||
AREA_DRAG_START: 'area.drag.start',
|
AREA_DRAG_START: 'area.drag.start',
|
||||||
@@ -102,6 +140,7 @@ export const EVENT_TYPES = {
|
|||||||
AREA_TABPAGE_MERGE: 'area.tabpage.merge',
|
AREA_TABPAGE_MERGE: 'area.tabpage.merge',
|
||||||
AREA_TABPAGE_SYNC: 'area.tabpage.sync',
|
AREA_TABPAGE_SYNC: 'area.tabpage.sync',
|
||||||
AREA_PANEL_SYNC: 'area.panel.sync',
|
AREA_PANEL_SYNC: 'area.panel.sync',
|
||||||
|
AREA_DRAG_STATE_UPDATE: 'area.drag.state.update',
|
||||||
|
|
||||||
PANEL_MAXIMIZE_SYNC: 'panel.maximize.sync',
|
PANEL_MAXIMIZE_SYNC: 'panel.maximize.sync',
|
||||||
PANEL_MAXIMIZE: 'panel.maximize',
|
PANEL_MAXIMIZE: 'panel.maximize',
|
||||||
|
|||||||
@@ -258,8 +258,11 @@ class GlobalEventManager {
|
|||||||
this.debugMode = false;
|
this.debugMode = false;
|
||||||
this.eventListenerUnsubscribers = [];
|
this.eventListenerUnsubscribers = [];
|
||||||
|
|
||||||
|
// 添加拖拽状态缓存,避免在每次移动事件中重复检测
|
||||||
|
this.dragOperationCache = new Map();
|
||||||
|
|
||||||
this._onGlobalEvent = this._onGlobalEvent.bind(this);
|
this._onGlobalEvent = this._onGlobalEvent.bind(this);
|
||||||
this._onSystemError = this._handleSystemError.bind(this);
|
this._handleSystemError = this._handleSystemError.bind(this);
|
||||||
this._cleanupExpiredData = this._cleanupExpiredData.bind(this);
|
this._cleanupExpiredData = this._cleanupExpiredData.bind(this);
|
||||||
|
|
||||||
GlobalEventManager.instance = this;
|
GlobalEventManager.instance = this;
|
||||||
@@ -513,9 +516,15 @@ class GlobalEventManager {
|
|||||||
console.log('👋 处理面板拖拽开始:', data);
|
console.log('👋 处理面板拖拽开始:', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否应该操作区域而非面板
|
// 检查是否应该操作区域而非面板,并缓存结果
|
||||||
const shouldOperateArea = this._shouldOperateAreaInsteadOfPanel(data);
|
const shouldOperateArea = this._shouldOperateAreaInsteadOfPanel(data);
|
||||||
|
|
||||||
|
// 缓存检测结果,用于后续的拖拽移动和结束事件
|
||||||
|
this.dragOperationCache.set(data.dragId, {
|
||||||
|
shouldOperateArea,
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
if (shouldOperateArea) {
|
if (shouldOperateArea) {
|
||||||
// 转换为区域拖拽事件
|
// 转换为区域拖拽事件
|
||||||
const areaDragStartData = {
|
const areaDragStartData = {
|
||||||
@@ -544,8 +553,9 @@ class GlobalEventManager {
|
|||||||
console.log('✋ 处理面板拖拽移动:', data);
|
console.log('✋ 处理面板拖拽移动:', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否应该操作区域而非面板
|
// 从缓存中获取单面板检测结果,避免重复检测
|
||||||
const shouldOperateArea = this._shouldOperateAreaInsteadOfPanel(data);
|
const cache = this.dragOperationCache.get(data.dragId);
|
||||||
|
const shouldOperateArea = cache ? cache.shouldOperateArea : this._shouldOperateAreaInsteadOfPanel(data);
|
||||||
|
|
||||||
if (shouldOperateArea) {
|
if (shouldOperateArea) {
|
||||||
// 转换为区域拖拽移动事件
|
// 转换为区域拖拽移动事件
|
||||||
@@ -574,8 +584,9 @@ class GlobalEventManager {
|
|||||||
console.log('✋ 处理面板拖拽结束:', data);
|
console.log('✋ 处理面板拖拽结束:', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否应该操作区域而非面板
|
// 从缓存中获取单面板检测结果
|
||||||
const shouldOperateArea = this._shouldOperateAreaInsteadOfPanel(data);
|
const cache = this.dragOperationCache.get(data.dragId);
|
||||||
|
const shouldOperateArea = cache ? cache.shouldOperateArea : this._shouldOperateAreaInsteadOfPanel(data);
|
||||||
|
|
||||||
if (shouldOperateArea) {
|
if (shouldOperateArea) {
|
||||||
// 转换为区域拖拽结束事件
|
// 转换为区域拖拽结束事件
|
||||||
@@ -593,6 +604,9 @@ class GlobalEventManager {
|
|||||||
status: 'ended'
|
status: 'ended'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 清理缓存
|
||||||
|
this.dragOperationCache.delete(data.dragId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -609,6 +623,9 @@ class GlobalEventManager {
|
|||||||
...data,
|
...data,
|
||||||
status: 'cancelled'
|
status: 'cancelled'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 清理缓存
|
||||||
|
this.dragOperationCache.delete(data.dragId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -799,10 +816,10 @@ class GlobalEventManager {
|
|||||||
*/
|
*/
|
||||||
_startDebugMode() {
|
_startDebugMode() {
|
||||||
// 监听调试命令
|
// 监听调试命令
|
||||||
eventBus.on('debug.toggle', () => {
|
eventBus.on(EVENT_TYPES.DEBUG_TOGGLE, () => {
|
||||||
this.debugMode = !this.debugMode;
|
this.debugMode = !this.debugMode;
|
||||||
console.log(`🔧 调试模式${this.debugMode ? '开启' : '关闭'}`);
|
console.log(`🔧 调试模式${this.debugMode ? '开启' : '关闭'}`);
|
||||||
});
|
}, { componentId: 'global-event-manager' });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1181,7 +1198,7 @@ export const globalEventActions = {
|
|||||||
* 切换调试模式
|
* 切换调试模式
|
||||||
*/
|
*/
|
||||||
toggleDebug: () => {
|
toggleDebug: () => {
|
||||||
eventBus.emit('debug.toggle');
|
eventBus.emit(EVENT_TYPES.DEBUG_TOGGLE, {}, { componentId: 'global-event-manager' });
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user