2025-10-31 23:58:26 +08:00
|
|
|
|
<template>
|
2025-12-04 14:58:41 +08:00
|
|
|
|
<div class="dock-layout" ref="dockLayoutRef" style="display: flex; flex-direction: column; position: relative; width: 100%; height: 100%;">
|
2025-11-07 15:41:44 +08:00
|
|
|
|
<!-- 停靠指示器组件 - 设置高z-index确保显示在最顶层 -->
|
|
|
|
|
|
<DockIndicator
|
2025-11-14 09:39:59 +08:00
|
|
|
|
:visible="showDockIndicator"
|
2025-11-07 15:41:44 +08:00
|
|
|
|
:target-rect="targetAreaRect"
|
|
|
|
|
|
:mouse-position="currentMousePosition"
|
2025-11-14 14:23:10 +08:00
|
|
|
|
:hide-edge-indicators="hideEdgeIndicators"
|
2025-11-07 15:41:44 +08:00
|
|
|
|
@zone-active="onDockZoneActive"
|
|
|
|
|
|
style="z-index: 9999;"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
<!-- 主区域使用Render组件统一渲染 -->
|
|
|
|
|
|
<div class="main-area-container" style="position: relative; width: 100%; height: 100%;">
|
|
|
|
|
|
<Render
|
|
|
|
|
|
:type="'Area'"
|
|
|
|
|
|
:config="mainAreaConfig"
|
|
|
|
|
|
ref="mainAreaRef"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ResizeBar直接渲染在主区域容器中 -->
|
|
|
|
|
|
<ResizeBar
|
|
|
|
|
|
v-for="resizeBar in mainAreaResizeBars"
|
|
|
|
|
|
:key="resizeBar.id"
|
|
|
|
|
|
:target-id="resizeBar.targetId"
|
|
|
|
|
|
:direction="resizeBar.direction"
|
|
|
|
|
|
:min-size="resizeBar.minSize"
|
|
|
|
|
|
:max-size="resizeBar.maxSize"
|
|
|
|
|
|
:initial-size="resizeBar.initialSize"
|
|
|
|
|
|
@resize="(size) => handleMainAreaResizeBar(resizeBar.id, size)"
|
|
|
|
|
|
@resize-start="() => handleMainAreaResizeBarStart(resizeBar.id)"
|
|
|
|
|
|
@resize-end="() => handleMainAreaResizeBarEnd(resizeBar.id)"
|
|
|
|
|
|
:style="getMainAreaResizeBarStyle(resizeBar)"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
2025-11-20 13:14:31 +08:00
|
|
|
|
|
2025-11-19 13:57:51 +08:00
|
|
|
|
<!-- 浮动区域使用Render组件统一渲染 -->
|
|
|
|
|
|
<Render
|
2025-11-07 14:44:07 +08:00
|
|
|
|
v-for="area in floatingAreas"
|
|
|
|
|
|
:key="area.id"
|
2025-11-19 15:26:39 +08:00
|
|
|
|
:type="'Area'"
|
2025-11-19 13:57:51 +08:00
|
|
|
|
:config="area"
|
|
|
|
|
|
/>
|
2025-11-02 17:19:53 +07:00
|
|
|
|
</div>
|
2025-10-31 23:58:26 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-12-04 14:58:41 +08:00
|
|
|
|
import { ref, computed, onMounted, onUnmounted, defineEmits } from 'vue'
|
2025-10-31 23:58:26 +08:00
|
|
|
|
import Area from './Area.vue';
|
2025-12-30 10:50:48 +08:00
|
|
|
|
import { getAreaHandler } from './handlers/AreaHandler';
|
|
|
|
|
|
|
|
|
|
|
|
// 获取AreaHandler实例
|
|
|
|
|
|
const areaHandler = getAreaHandler();
|
|
|
|
|
|
|
2025-11-02 17:06:40 +07:00
|
|
|
|
import Panel from './Panel.vue';
|
2025-11-05 09:02:11 +08:00
|
|
|
|
import TabPage from './TabPage.vue';
|
2025-11-07 15:41:44 +08:00
|
|
|
|
import DockIndicator from './DockIndicator.vue';
|
2025-11-18 15:39:46 +08:00
|
|
|
|
import ResizeBar from './ResizeBar.vue';
|
2025-11-19 13:57:51 +08:00
|
|
|
|
import Render from './Render.vue';
|
2025-12-25 13:53:52 +08:00
|
|
|
|
import { zIndexManager } from './dockLayers';
|
2026-01-15 14:28:29 +08:00
|
|
|
|
import { eventBus, EVENT_TYPES, emitEvent } from './eventBus';
|
2025-12-25 13:53:52 +08:00
|
|
|
|
import { areaActions } from './handlers/AreaHandler';
|
|
|
|
|
|
import { dragStateActions } from './handlers/DragStateManager';
|
|
|
|
|
|
import { panelActions } from './handlers/PanelHandler';
|
|
|
|
|
|
import { tabPageActions } from './handlers/TabPageHandler';
|
|
|
|
|
|
import { globalEventActions } from './handlers/GlobalEventManager';
|
2025-11-02 17:06:40 +07:00
|
|
|
|
|
2025-11-18 13:48:13 +08:00
|
|
|
|
// 定义组件可以发出的事件
|
|
|
|
|
|
const emit = defineEmits([
|
|
|
|
|
|
'maximize', // 面板最大化事件
|
|
|
|
|
|
'toggleCollapse', // 折叠状态切换事件
|
|
|
|
|
|
'toggleToolbar', // 工具栏切换事件
|
|
|
|
|
|
'dragStart', // 拖拽开始事件
|
|
|
|
|
|
'dragMove', // 拖拽移动事件
|
|
|
|
|
|
'dragEnd' // 拖拽结束事件
|
|
|
|
|
|
])
|
|
|
|
|
|
|
2025-11-02 17:06:40 +07:00
|
|
|
|
// 主区域状态
|
2025-11-01 14:23:35 +07:00
|
|
|
|
const windowState = ref('最大化')
|
2025-11-02 17:06:40 +07:00
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
// 主区域配置
|
|
|
|
|
|
const mainAreaConfig = ref({
|
|
|
|
|
|
id: 'MainArea',
|
|
|
|
|
|
title: '主区域',
|
|
|
|
|
|
windowState: windowState.value,
|
2025-12-29 09:05:37 +08:00
|
|
|
|
showTitleBar: false,
|
|
|
|
|
|
children: {
|
|
|
|
|
|
type: 'TabPage',
|
2026-01-13 16:56:27 +08:00
|
|
|
|
id: `tabPage-${Date.now()}`,
|
2025-12-29 09:05:37 +08:00
|
|
|
|
children: []
|
|
|
|
|
|
}
|
2025-12-15 09:03:32 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-04 10:53:22 +08:00
|
|
|
|
// 浮动区域列表 - 每个area包含panels数组
|
2025-11-02 17:06:40 +07:00
|
|
|
|
const floatingAreas = ref([])
|
|
|
|
|
|
|
2025-11-04 09:45:51 +08:00
|
|
|
|
// 容器引用
|
|
|
|
|
|
const dockLayoutRef = ref(null)
|
2025-11-14 14:23:10 +08:00
|
|
|
|
// 主区域引用
|
|
|
|
|
|
const mainAreaRef = ref(null)
|
2025-11-02 17:06:40 +07:00
|
|
|
|
|
2026-01-04 16:47:46 +08:00
|
|
|
|
// 调试模式开关
|
|
|
|
|
|
const debugMode = ref(false)
|
|
|
|
|
|
|
2025-11-07 15:41:44 +08:00
|
|
|
|
// 停靠指示器相关状态
|
|
|
|
|
|
const showDockIndicator = ref(false)
|
|
|
|
|
|
const currentMousePosition = ref({ x: 0, y: 0 })
|
|
|
|
|
|
const targetAreaRect = ref({ left: 0, top: 0, width: 0, height: 0 })
|
|
|
|
|
|
const activeDockZone = ref(null)
|
|
|
|
|
|
|
2025-11-18 15:39:46 +08:00
|
|
|
|
// 主区域ResizeBar列表
|
|
|
|
|
|
const mainAreaResizeBars = ref([])
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 检查主区域内是否有其他Area(简化版)
|
|
|
|
|
|
const hasAreasInMainContent = ref(false)
|
2025-11-14 14:23:10 +08:00
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 添加拖拽操作缓存,避免在每次移动事件中重复检测
|
|
|
|
|
|
const dragOperationCache = new Map();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-29 13:18:13 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 检查是否应该操作区域而非面板
|
|
|
|
|
|
* 当只有一个面板时,操作区域而不是面板
|
|
|
|
|
|
* @param {string} areaId - Area ID
|
|
|
|
|
|
* @returns {boolean} 是否应该操作区域
|
|
|
|
|
|
*/
|
2025-12-29 09:05:37 +08:00
|
|
|
|
const shouldOperateAreaInsteadOfPanel = (areaId) => {
|
2025-12-29 13:18:13 +08:00
|
|
|
|
try {
|
2026-01-07 14:03:56 +08:00
|
|
|
|
// 从floatingAreas中查找对应areaId的区域
|
|
|
|
|
|
const area = floatingAreas.value.find(a => a.id === areaId);
|
|
|
|
|
|
if (!area) return false;
|
|
|
|
|
|
|
2026-01-07 10:50:54 +08:00
|
|
|
|
// 检查区域的子元素结构
|
|
|
|
|
|
// 如果有一个TabPage和任意数量的Panel,返回true
|
2025-12-29 13:18:13 +08:00
|
|
|
|
const childrenArray = Array.isArray(area.children) ? area.children : [area.children];
|
|
|
|
|
|
|
|
|
|
|
|
for (const child of childrenArray) {
|
|
|
|
|
|
if (child.type === 'TabPage' && child.children) {
|
|
|
|
|
|
const tabChildrenArray = Array.isArray(child.children) ? child.children : [child.children];
|
2026-01-07 10:50:54 +08:00
|
|
|
|
const panelCount = tabChildrenArray.filter(tabChild => tabChild.type === 'Panel').length;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果TabPage有Panel,返回true
|
|
|
|
|
|
if (panelCount > 0) {
|
|
|
|
|
|
return true;
|
2025-12-29 13:18:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-07 10:50:54 +08:00
|
|
|
|
return false;
|
2025-12-29 13:18:13 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-12-29 09:05:37 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 检查是否应该操作区域而非面板(从GlobalEventManager.js迁移)
|
2026-01-07 10:50:54 +08:00
|
|
|
|
* 当有一个TabPage和任意数量的Panel时,操作区域而不是面板
|
2025-12-31 10:51:47 +08:00
|
|
|
|
* @param {Object} data - 事件数据
|
|
|
|
|
|
* @returns {boolean} 是否应该操作区域
|
|
|
|
|
|
*/
|
|
|
|
|
|
const shouldOperateAreaInsteadOfPanelFromData = (data) => {
|
|
|
|
|
|
const { panelId, areaId } = data;
|
|
|
|
|
|
|
|
|
|
|
|
// 从AreaHandler获取区域状态
|
|
|
|
|
|
const areaState = areaHandler.getAreaState(areaId);
|
|
|
|
|
|
|
2026-01-07 10:50:54 +08:00
|
|
|
|
// 检查区域是否有一个TabPage和任意数量的Panel
|
2025-12-31 10:51:47 +08:00
|
|
|
|
if (areaState.children && areaState.children.type === 'TabPage') {
|
|
|
|
|
|
const tabChildren = Array.isArray(areaState.children.children) ? areaState.children.children : [areaState.children.children];
|
2026-01-07 10:50:54 +08:00
|
|
|
|
const panelCount = tabChildren.filter(child => child.type === 'Panel').length;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果TabPage有Panel,返回true
|
|
|
|
|
|
return panelCount > 0;
|
2025-12-31 10:51:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-07 10:50:54 +08:00
|
|
|
|
// 默认不是
|
|
|
|
|
|
return false;
|
2025-12-31 10:51:47 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const onCloseFloatingArea = (event) => {
|
|
|
|
|
|
const id = event.areaId;
|
2025-12-29 13:18:13 +08:00
|
|
|
|
areaActions.closeFloating(id);
|
2025-11-20 13:14:31 +08:00
|
|
|
|
const index = floatingAreas.value.findIndex(a => a.id === id);
|
2025-11-02 17:06:40 +07:00
|
|
|
|
if (index !== -1) {
|
2025-11-20 13:14:31 +08:00
|
|
|
|
floatingAreas.value.splice(index, 1);
|
2025-11-02 17:06:40 +07:00
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-29 13:18:13 +08:00
|
|
|
|
// 保持旧的onUpdatePosition函数以兼容现有事件
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const onUpdatePosition = (event) => {
|
|
|
|
|
|
const id = event.areaId;
|
2025-12-29 13:18:13 +08:00
|
|
|
|
// 处理不同事件类型的数据结构
|
|
|
|
|
|
const position = event.position || event;
|
2025-11-20 13:14:31 +08:00
|
|
|
|
const area = floatingAreas.value.find(a => a.id === id);
|
|
|
|
|
|
if (area) {
|
2025-12-29 13:18:13 +08:00
|
|
|
|
area.left = position.left;
|
|
|
|
|
|
area.top = position.top;
|
2025-11-20 13:14:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-30 10:50:48 +08:00
|
|
|
|
// 处理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' });
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const onMaximize = (event) => {
|
|
|
|
|
|
const panelId = event.panelId;
|
2025-12-29 09:05:37 +08:00
|
|
|
|
const areaId = event.areaId;
|
|
|
|
|
|
|
2026-01-07 10:13:35 +08:00
|
|
|
|
// 检查是否应该操作区域而非面板
|
|
|
|
|
|
// 1. 只有一个面板时,操作区域
|
|
|
|
|
|
// 2. 有一个TabPage和多个Panel时,也操作区域
|
|
|
|
|
|
const shouldOperateArea = shouldOperateAreaInsteadOfPanelFromData(event);
|
|
|
|
|
|
|
|
|
|
|
|
// 从AreaHandler获取区域状态,检查是否有一个TabPage和多个Panel
|
|
|
|
|
|
const areaState = areaHandler.getAreaState(areaId);
|
|
|
|
|
|
const hasOneTabPageWithMultiplePanels = areaState?.children?.type === 'TabPage' &&
|
|
|
|
|
|
Array.isArray(areaState.children.children) &&
|
|
|
|
|
|
areaState.children.children.length > 1;
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldOperateArea || hasOneTabPageWithMultiplePanels) {
|
2025-12-29 09:05:37 +08:00
|
|
|
|
areaActions.toggleMaximize(areaId);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
panelActions.maximize(panelId);
|
|
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
2025-11-02 17:06:40 +07:00
|
|
|
|
|
2025-12-29 09:05:37 +08:00
|
|
|
|
const onPanelClose = (event) => {
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const areaId = event.areaId;
|
|
|
|
|
|
const panelId = event.panelId;
|
2025-12-29 09:05:37 +08:00
|
|
|
|
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 1. 先找到要移除的面板
|
2026-01-08 14:51:40 +08:00
|
|
|
|
const area = floatingAreas.value.find(a => a.id === areaId);
|
|
|
|
|
|
if (area && area.children) {
|
|
|
|
|
|
const areaChildrenArray = Array.isArray(area.children) ? area.children : [area.children];
|
|
|
|
|
|
for (const child of areaChildrenArray) {
|
|
|
|
|
|
if (child.type === 'TabPage' && child.children) {
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 确保TabPage的children是数组,方便统一处理
|
|
|
|
|
|
let isArray = Array.isArray(child.children);
|
|
|
|
|
|
if (!isArray) {
|
|
|
|
|
|
// 如果不是数组,将其转换为数组
|
|
|
|
|
|
child.children = [child.children];
|
|
|
|
|
|
isArray = true;
|
|
|
|
|
|
}
|
2026-01-08 14:51:40 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查每个子项是否为Panel组件
|
2026-01-09 13:45:34 +08:00
|
|
|
|
for (let i = 0; i < child.children.length; i++) {
|
|
|
|
|
|
const item = child.children[i];
|
2026-01-08 14:51:40 +08:00
|
|
|
|
if (item.type === 'Panel' && item.id === panelId) {
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 2. 调用PanelActions关闭面板资源
|
|
|
|
|
|
panelActions.close(panelId, areaId);
|
2026-01-08 14:51:40 +08:00
|
|
|
|
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 3. 只移除指定的面板,不影响其他面板
|
|
|
|
|
|
child.children.splice(i, 1);
|
|
|
|
|
|
|
2026-01-13 16:56:27 +08:00
|
|
|
|
// 发送面板移除事件,通知TabPage组件调整activeTabIndex
|
|
|
|
|
|
const tabPageId = child.id || `tabPage-${areaId}`;
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.TABPAGE_PANEL_REMOVED, {
|
|
|
|
|
|
tabPageId,
|
|
|
|
|
|
removedPanelId: panelId,
|
|
|
|
|
|
removedIndex: i,
|
|
|
|
|
|
remainingPanelCount: child.children.length
|
|
|
|
|
|
}, { componentId: 'dock-layout' });
|
|
|
|
|
|
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 4. 检查TabPage是否还有子元素
|
|
|
|
|
|
// 当child.children为空数组时,认为TabPage没有子元素
|
|
|
|
|
|
if (child.children.length === 0) {
|
|
|
|
|
|
// 如果TabPage没有任何子元素,移除TabPage
|
2026-01-08 14:51:40 +08:00
|
|
|
|
const tabPageIndex = areaChildrenArray.indexOf(child);
|
|
|
|
|
|
if (tabPageIndex !== -1) {
|
|
|
|
|
|
if (Array.isArray(area.children)) {
|
|
|
|
|
|
area.children.splice(tabPageIndex, 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果area.children是单个对象,直接设为null
|
|
|
|
|
|
area.children = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2025-11-06 13:32:18 +08:00
|
|
|
|
}
|
2026-01-08 14:51:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-09 13:45:34 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 如果找不到Area或TabPage,仍需关闭面板资源
|
|
|
|
|
|
panelActions.close(panelId, areaId);
|
2026-01-08 14:51:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 5. 检查Area是否还有子元素,如果没有,关闭整个Area
|
|
|
|
|
|
const updatedArea = floatingAreas.value.find(a => a.id === areaId);
|
|
|
|
|
|
if (updatedArea) {
|
|
|
|
|
|
if (!updatedArea.children) {
|
|
|
|
|
|
// Area没有children,直接关闭
|
|
|
|
|
|
onCloseFloatingArea({ areaId });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 检查Area的children是否还有有效的TabPage
|
|
|
|
|
|
let hasValidTabPage = false;
|
|
|
|
|
|
const areaChildrenArray = Array.isArray(updatedArea.children) ? updatedArea.children : [updatedArea.children];
|
|
|
|
|
|
for (const child of areaChildrenArray) {
|
|
|
|
|
|
if (child.type === 'TabPage' && child.children) {
|
|
|
|
|
|
// 检查TabPage是否还有子元素,无论是数组还是单个对象
|
|
|
|
|
|
const hasChildren = Array.isArray(child.children) ? child.children.length > 0 : true;
|
|
|
|
|
|
if (hasChildren) {
|
|
|
|
|
|
hasValidTabPage = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-11-06 13:32:18 +08:00
|
|
|
|
}
|
2025-11-04 10:53:22 +08:00
|
|
|
|
}
|
2026-01-09 13:45:34 +08:00
|
|
|
|
|
|
|
|
|
|
if (!hasValidTabPage) {
|
|
|
|
|
|
onCloseFloatingArea({ areaId });
|
|
|
|
|
|
}
|
2025-11-04 10:53:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
2025-11-04 10:53:22 +08:00
|
|
|
|
|
2026-01-15 14:28:29 +08:00
|
|
|
|
// 处理Area关闭请求事件
|
|
|
|
|
|
const onAreaCloseRequest = (event) => {
|
|
|
|
|
|
const { areaId } = event;
|
|
|
|
|
|
|
|
|
|
|
|
// 查找要关闭的Area
|
|
|
|
|
|
const areaIndex = floatingAreas.value.findIndex(a => a.id === areaId);
|
|
|
|
|
|
if (areaIndex === -1) {
|
|
|
|
|
|
console.error(`❌ 找不到要关闭的Area: ${areaId}`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const area = floatingAreas.value[areaIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 处理Area下的所有子组件
|
|
|
|
|
|
if (area.children) {
|
|
|
|
|
|
const areaChildrenArray = Array.isArray(area.children) ? area.children : [area.children];
|
|
|
|
|
|
|
|
|
|
|
|
areaChildrenArray.forEach((child, childIndex) => {
|
|
|
|
|
|
if (child.type === 'TabPage') {
|
|
|
|
|
|
// 2. 处理TabPage下的所有Panel
|
|
|
|
|
|
if (child.children) {
|
|
|
|
|
|
const tabChildrenArray = Array.isArray(child.children) ? child.children : [child.children];
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 遍历并关闭每个Panel
|
|
|
|
|
|
tabChildrenArray.forEach(panel => {
|
|
|
|
|
|
if (panel.type === 'Panel' && panel.id) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 4. 关闭Panel资源(异步执行)
|
|
|
|
|
|
panelActions.close(panel.id, areaId);
|
|
|
|
|
|
// 注意:panelActions.close内部已经会发送PANEL_CLOSED事件,不需要手动发送
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error(`❌ 关闭Panel ${panel.id}失败:`, error);
|
|
|
|
|
|
// 继续处理下一个Panel,避免单个Panel关闭失败导致整个流程中断
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 清理TabPage的children引用
|
|
|
|
|
|
child.children = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 7. 从Area中移除TabPage
|
|
|
|
|
|
if (Array.isArray(area.children)) {
|
|
|
|
|
|
area.children.splice(childIndex, 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
area.children = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 8. 关闭Area资源(此时Area的children已清空)
|
|
|
|
|
|
areaActions.closeFloating(areaId);
|
|
|
|
|
|
|
|
|
|
|
|
// 9. 从floatingAreas中移除Area
|
|
|
|
|
|
floatingAreas.value.splice(areaIndex, 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 10. 发送Area关闭事件
|
|
|
|
|
|
emitEvent(EVENT_TYPES.AREA_CLOSED, {
|
|
|
|
|
|
areaId: areaId
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`✅ 成功关闭Area及其所有子组件: ${areaId}`);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 简单的拖拽事件处理
|
|
|
|
|
|
const handleMainAreaDragOver = (event) => {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
globalEventActions.handleDragOver('main-area', event);
|
|
|
|
|
|
};
|
2025-11-20 09:51:08 +08:00
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
const handleMainAreaDragLeave = () => {
|
|
|
|
|
|
globalEventActions.handleDragLeave('main-area');
|
|
|
|
|
|
};
|
2025-11-02 17:12:40 +07:00
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
const handleAreaDragOver = (event) => {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
globalEventActions.handleDragOver('floating-area', event);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const handleAreaDragLeave = (event) => {
|
2025-12-29 09:05:37 +08:00
|
|
|
|
globalEventActions.handleDragLeave('floating-area');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 处理面板拖拽开始事件
|
|
|
|
|
|
const onPanelDragStart = async (event) => {
|
|
|
|
|
|
console.log(`📈 收到面板拖拽开始事件:`, { event });
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 检查是否应该操作区域而非面板,并缓存结果
|
|
|
|
|
|
const shouldOperateArea = shouldOperateAreaInsteadOfPanelFromData(event);
|
|
|
|
|
|
|
|
|
|
|
|
// 缓存检测结果,用于后续的拖拽移动和结束事件
|
|
|
|
|
|
dragOperationCache.set(event.dragId, {
|
|
|
|
|
|
shouldOperateArea,
|
|
|
|
|
|
timestamp: Date.now()
|
2025-12-29 13:18:13 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
if (shouldOperateArea) {
|
|
|
|
|
|
// 转换为区域拖拽事件
|
|
|
|
|
|
const areaDragStartData = {
|
|
|
|
|
|
...event,
|
|
|
|
|
|
eventType: 'area.drag.start',
|
|
|
|
|
|
dragId: event.dragId || `area_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽开始事件
|
|
|
|
|
|
eventBus.emit('area.drag.start', areaDragStartData, { componentId: 'dock-layout' });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 发送面板拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.PANEL_DRAG_STATE_UPDATE, {
|
|
|
|
|
|
...event,
|
|
|
|
|
|
status: 'active'
|
|
|
|
|
|
}, { componentId: 'dock-layout' });
|
|
|
|
|
|
}
|
2025-12-29 09:05:37 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 处理面板拖拽移动事件
|
|
|
|
|
|
const onPanelDragMove = async (event) => {
|
|
|
|
|
|
console.log(`📈 收到面板拖拽移动事件:`, { event });
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 从缓存中获取单面板检测结果,避免重复检测
|
|
|
|
|
|
const cache = dragOperationCache.get(event.dragId);
|
|
|
|
|
|
const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(event);
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
if (shouldOperateArea) {
|
|
|
|
|
|
// 转换为区域拖拽移动事件
|
|
|
|
|
|
const areaDragMoveData = {
|
|
|
|
|
|
...event,
|
|
|
|
|
|
eventType: 'area.drag.move'
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽移动事件
|
|
|
|
|
|
eventBus.emit('area.drag.move', areaDragMoveData, { componentId: 'dock-layout' });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 发送面板拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.PANEL_DRAG_STATE_UPDATE, {
|
|
|
|
|
|
...event,
|
|
|
|
|
|
status: 'moving'
|
|
|
|
|
|
}, { componentId: 'dock-layout' });
|
|
|
|
|
|
}
|
2025-12-29 09:05:37 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 处理面板拖拽结束事件
|
|
|
|
|
|
const onPanelDragEnd = async (event) => {
|
|
|
|
|
|
console.log(`📈 收到面板拖拽结束事件:`, { event });
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 从缓存中获取单面板检测结果
|
|
|
|
|
|
const cache = dragOperationCache.get(event.dragId);
|
|
|
|
|
|
const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(event);
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
if (shouldOperateArea) {
|
|
|
|
|
|
// 转换为区域拖拽结束事件
|
|
|
|
|
|
const areaDragEndData = {
|
|
|
|
|
|
...event,
|
|
|
|
|
|
eventType: 'area.drag.end'
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽结束事件
|
|
|
|
|
|
eventBus.emit('area.drag.end', areaDragEndData, { componentId: 'dock-layout' });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 发送面板拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.PANEL_DRAG_STATE_UPDATE, {
|
|
|
|
|
|
...event,
|
|
|
|
|
|
status: 'ended'
|
|
|
|
|
|
}, { componentId: 'dock-layout' });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清理缓存
|
|
|
|
|
|
dragOperationCache.delete(event.dragId);
|
2025-12-29 13:18:13 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-04 10:15:39 +08:00
|
|
|
|
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听区域拖拽状态更新下降事件
|
|
|
|
|
|
const onAreaDragStateUpdate = (event) => {
|
|
|
|
|
|
const id = event.areaId;
|
|
|
|
|
|
const status = event.status;
|
|
|
|
|
|
const area = floatingAreas.value.find(a => a.id === id);
|
|
|
|
|
|
if (area) {
|
|
|
|
|
|
area.isDragging = status === 'active' || status === 'moving';
|
2025-12-29 09:05:37 +08:00
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 其他事件处理方法
|
|
|
|
|
|
const onDockZoneActive = (zone) => {
|
|
|
|
|
|
activeDockZone.value = zone;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const onPanelMaximizeSync = ({ areaId, maximized }) => {
|
2025-12-15 09:03:32 +08:00
|
|
|
|
// 使用areaActions.updateState来更新区域的最大化状态
|
|
|
|
|
|
areaActions.updateState(areaId, { maximized });
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const onAreaMerged = (event) => {
|
|
|
|
|
|
areaActions.handleAreaMerged(event.areaId);
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
// 标签页切换事件处理
|
|
|
|
|
|
const onTabChange = async (data) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await tabPageActions.switch(data.tabPageId, data.areaId, data.fromTabPageId);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Failed to handle tab change:', error);
|
|
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const onTabClose = async (data) => {
|
|
|
|
|
|
try {
|
2026-01-07 13:33:52 +08:00
|
|
|
|
// 适配数据结构:从data.id获取Panel ID
|
|
|
|
|
|
const panelId = data.id;
|
|
|
|
|
|
if (!panelId) {
|
|
|
|
|
|
console.error('Tab close event missing panelId');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`📋 处理标签页关闭事件:`, { data, panelId });
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 查找包含该Panel的Area
|
|
|
|
|
|
let targetArea = null;
|
|
|
|
|
|
let targetTabPage = null;
|
|
|
|
|
|
let panelIndex = -1;
|
|
|
|
|
|
let areaId = null;
|
|
|
|
|
|
|
|
|
|
|
|
for (const area of floatingAreas.value) {
|
|
|
|
|
|
if (area.children && area.children.type === 'TabPage') {
|
|
|
|
|
|
const tabPage = area.children;
|
|
|
|
|
|
if (tabPage.children) {
|
|
|
|
|
|
const childrenArray = Array.isArray(tabPage.children) ? tabPage.children : [tabPage.children];
|
|
|
|
|
|
const index = childrenArray.findIndex(child => child.id === panelId);
|
|
|
|
|
|
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
targetArea = area;
|
|
|
|
|
|
targetTabPage = tabPage;
|
|
|
|
|
|
panelIndex = index;
|
|
|
|
|
|
areaId = area.id;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!targetArea || !targetTabPage || !areaId) {
|
|
|
|
|
|
console.error(`❌ 找不到包含Panel ${panelId}的Area`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const tabPageId = targetTabPage.id || `tabPage-${areaId}`;
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`✅ 找到目标Area和TabPage:`, { areaId, tabPageId, panelId });
|
|
|
|
|
|
|
2026-01-08 14:51:40 +08:00
|
|
|
|
// 2. 调用PanelHandler的close方法回收Panel资源
|
|
|
|
|
|
panelActions.close(panelId, areaId);
|
|
|
|
|
|
console.log(`📌 调用PanelHandler回收Panel资源`);
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 调用TabPageActions处理关闭请求
|
2026-01-07 13:33:52 +08:00
|
|
|
|
await tabPageActions.requestClose(tabPageId, areaId);
|
|
|
|
|
|
|
2026-01-08 14:51:40 +08:00
|
|
|
|
// 4. 移除Panel
|
2026-01-07 13:33:52 +08:00
|
|
|
|
if (Array.isArray(targetTabPage.children)) {
|
|
|
|
|
|
targetTabPage.children.splice(panelIndex, 1);
|
|
|
|
|
|
console.log(`📌 从TabPage移除Panel后,剩余Panel数量: ${targetTabPage.children.length}`);
|
2026-01-13 16:56:27 +08:00
|
|
|
|
|
|
|
|
|
|
// 发送Panel移除事件,通知TabPage组件调整activeTabIndex
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.TABPAGE_PANEL_REMOVED, {
|
|
|
|
|
|
tabPageId,
|
|
|
|
|
|
removedPanelId: panelId,
|
|
|
|
|
|
removedIndex: panelIndex,
|
|
|
|
|
|
remainingPanelCount: targetTabPage.children.length
|
|
|
|
|
|
}, { componentId: 'dock-layout' });
|
2026-01-07 13:33:52 +08:00
|
|
|
|
} else {
|
2026-01-08 14:51:40 +08:00
|
|
|
|
// 当TabPage只有一个Panel时,我们将children设置为null
|
|
|
|
|
|
// 这样shouldShowTabs计算属性会返回false,不显示标签栏
|
|
|
|
|
|
// 但TabPage仍然存在
|
2026-01-07 13:33:52 +08:00
|
|
|
|
targetTabPage.children = null;
|
2026-01-08 14:51:40 +08:00
|
|
|
|
console.log(`📌 移除了唯一的Panel,TabPage不显示标签栏`);
|
2026-01-13 16:56:27 +08:00
|
|
|
|
|
|
|
|
|
|
// 发送Panel移除事件,通知TabPage组件调整activeTabIndex
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.TABPAGE_PANEL_REMOVED, {
|
|
|
|
|
|
tabPageId,
|
|
|
|
|
|
removedPanelId: panelId,
|
|
|
|
|
|
removedIndex: panelIndex,
|
|
|
|
|
|
remainingPanelCount: 0
|
|
|
|
|
|
}, { componentId: 'dock-layout' });
|
2026-01-07 13:33:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-08 14:51:40 +08:00
|
|
|
|
// 5. 检查TabPage是否还有子元素
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 当targetTabPage.children为null或undefined时,认为TabPage没有子元素
|
|
|
|
|
|
// 当targetTabPage.children为空数组时,也认为没有子元素
|
2026-01-08 14:51:40 +08:00
|
|
|
|
let hasTabPageChildren = true;
|
|
|
|
|
|
if (Array.isArray(targetTabPage.children)) {
|
|
|
|
|
|
hasTabPageChildren = targetTabPage.children.length > 0;
|
2026-01-09 13:45:34 +08:00
|
|
|
|
} else if (targetTabPage.children === null || targetTabPage.children === undefined) {
|
2026-01-08 14:51:40 +08:00
|
|
|
|
hasTabPageChildren = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 6. 只有当TabPage没有任何子元素时,才移除TabPage
|
|
|
|
|
|
if (!hasTabPageChildren) {
|
2026-01-07 13:33:52 +08:00
|
|
|
|
console.log(`📌 TabPage已无Panel,移除TabPage`);
|
2026-01-08 14:51:40 +08:00
|
|
|
|
|
|
|
|
|
|
// 7. 实际从Area的children中移除TabPage
|
|
|
|
|
|
if (Array.isArray(targetArea.children)) {
|
|
|
|
|
|
const tabPageIndex = targetArea.children.indexOf(targetTabPage);
|
|
|
|
|
|
if (tabPageIndex !== -1) {
|
|
|
|
|
|
targetArea.children.splice(tabPageIndex, 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果Area的children是单个TabPage,直接设为null
|
|
|
|
|
|
targetArea.children = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 8. 检查Area是否还有子元素
|
|
|
|
|
|
let hasAreaChildren = false;
|
|
|
|
|
|
if (Array.isArray(targetArea.children)) {
|
|
|
|
|
|
hasAreaChildren = targetArea.children.length > 0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
hasAreaChildren = !!targetArea.children;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 9. 只有当Area没有任何子元素时,才关闭整个Area
|
|
|
|
|
|
if (!hasAreaChildren) {
|
|
|
|
|
|
console.log(`📌 Area已无子元素,关闭整个Area`);
|
|
|
|
|
|
onCloseFloatingArea({ areaId });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-07 13:33:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-08 14:51:40 +08:00
|
|
|
|
// 10. 更新floatingAreas中的Area配置
|
2026-01-07 13:33:52 +08:00
|
|
|
|
const areaIndex = floatingAreas.value.findIndex(a => a.id === areaId);
|
|
|
|
|
|
if (areaIndex !== -1) {
|
|
|
|
|
|
floatingAreas.value[areaIndex] = { ...targetArea };
|
|
|
|
|
|
console.log(`📌 更新floatingAreas中的Area配置`);
|
|
|
|
|
|
|
2026-01-08 14:51:40 +08:00
|
|
|
|
// 11. 触发Area更新事件,确保状态同步
|
2026-01-07 13:33:52 +08:00
|
|
|
|
areaActions.updateState(areaId, { children: targetArea.children });
|
|
|
|
|
|
console.log(`📌 触发Area更新事件`);
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`✅ 成功移除标签页和回收Panel: areaId=${areaId}, panelId=${panelId}`);
|
|
|
|
|
|
}
|
2025-12-15 09:03:32 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Failed to handle tab close:', error);
|
|
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
const onTabAdd = async (data) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await tabPageActions.create(data.areaId, data.config);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Failed to handle tab add:', error);
|
|
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ResizeBar相关处理方法
|
|
|
|
|
|
const handleMainAreaResizeBar = (id, size) => {
|
|
|
|
|
|
areaActions.handleResize(id, size);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleMainAreaResizeBarStart = (id) => {
|
|
|
|
|
|
areaActions.handleResizeStart(id);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleMainAreaResizeBarEnd = (id) => {
|
|
|
|
|
|
areaActions.handleResizeEnd(id);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-26 17:12:36 +08:00
|
|
|
|
// 处理Area合并请求
|
|
|
|
|
|
const handleAreaMergeRequest = (data) => {
|
|
|
|
|
|
const { sourceArea, targetAreaId } = data;
|
|
|
|
|
|
|
|
|
|
|
|
// 查找目标Area
|
|
|
|
|
|
const targetArea = floatingAreas.value.find(area => area.id === targetAreaId);
|
|
|
|
|
|
if (!targetArea) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 直接修改目标Area的children配置
|
|
|
|
|
|
if (!targetArea.children) {
|
|
|
|
|
|
targetArea.children = [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理源Area的children
|
|
|
|
|
|
if (sourceArea.children) {
|
|
|
|
|
|
const childrenArray = Array.isArray(sourceArea.children) ? sourceArea.children : [sourceArea.children];
|
|
|
|
|
|
childrenArray.forEach(child => {
|
|
|
|
|
|
if (child.type === 'TabPage') {
|
|
|
|
|
|
// 添加到目标Area的children中
|
|
|
|
|
|
if (!Array.isArray(targetArea.children)) {
|
|
|
|
|
|
targetArea.children = [targetArea.children];
|
|
|
|
|
|
}
|
|
|
|
|
|
targetArea.children.push(child);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从floatingAreas中移除源Area
|
|
|
|
|
|
floatingAreas.value = floatingAreas.value.filter(area => area.id !== sourceArea.id);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
const getMainAreaResizeBarStyle = (resizeBar) => {
|
|
|
|
|
|
return areaActions.getResizeBarStyle(resizeBar);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 计算属性
|
|
|
|
|
|
const hideEdgeIndicators = computed(() => {
|
|
|
|
|
|
return !hasAreasInMainContent.value;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
// 设置事件总线监听器
|
2025-11-20 13:14:31 +08:00
|
|
|
|
const setupEventListeners = () => {
|
2025-12-25 13:53:52 +08:00
|
|
|
|
// 创建一个数组来保存所有的取消订阅函数
|
|
|
|
|
|
const unsubscribeFunctions = [];
|
|
|
|
|
|
|
2026-01-04 16:47:46 +08:00
|
|
|
|
// 上升事件处理 - 统一由handleRisingEvent处理所有上升事件
|
|
|
|
|
|
const risingEvents = [
|
|
|
|
|
|
// 面板拖拽事件
|
|
|
|
|
|
EVENT_TYPES.PANEL_DRAG_START,
|
|
|
|
|
|
EVENT_TYPES.PANEL_DRAG_MOVE,
|
|
|
|
|
|
EVENT_TYPES.PANEL_DRAG_END,
|
|
|
|
|
|
EVENT_TYPES.PANEL_DRAG_CANCEL,
|
|
|
|
|
|
// 面板调整大小事件
|
|
|
|
|
|
EVENT_TYPES.PANEL_RESIZE_START,
|
|
|
|
|
|
EVENT_TYPES.PANEL_RESIZE_MOVE,
|
|
|
|
|
|
EVENT_TYPES.PANEL_RESIZE_END,
|
|
|
|
|
|
// 区域拖拽事件
|
|
|
|
|
|
EVENT_TYPES.AREA_DRAG_START,
|
|
|
|
|
|
EVENT_TYPES.AREA_DRAG_MOVE,
|
|
|
|
|
|
EVENT_TYPES.AREA_DRAG_END,
|
|
|
|
|
|
EVENT_TYPES.AREA_DRAG_CANCEL,
|
|
|
|
|
|
// 区域调整大小事件
|
|
|
|
|
|
EVENT_TYPES.AREA_RESIZE_START,
|
|
|
|
|
|
EVENT_TYPES.AREA_RESIZE_MOVE,
|
|
|
|
|
|
EVENT_TYPES.AREA_RESIZE_END
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// 订阅所有上升事件,统一由handleRisingEvent处理
|
|
|
|
|
|
risingEvents.forEach(eventType => {
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(eventType, handleRisingEvent, { componentId: 'dock-layout' }));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
// Area相关事件
|
2025-12-31 10:51:47 +08:00
|
|
|
|
|
2025-12-26 13:09:35 +08:00
|
|
|
|
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' }));
|
2025-12-26 17:12:36 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_MERGE_REQUEST, handleAreaMergeRequest, { componentId: 'dock-layout' }));
|
2025-12-30 10:50:48 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_UPDATED, onAreaUpdated, { componentId: 'dock-layout' }));
|
2026-01-15 14:28:29 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_CLOSE_REQUEST, onAreaCloseRequest, { componentId: 'dock-layout' }));
|
2026-01-04 16:47:46 +08:00
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
2025-12-15 09:03:32 +08:00
|
|
|
|
// Tab相关事件
|
2025-12-26 13:09:35 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange, { componentId: 'dock-layout' }));
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CLOSE, onTabClose, { componentId: 'dock-layout' }));
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_ADD, onTabAdd, { componentId: 'dock-layout' }));
|
2025-12-15 09:03:32 +08:00
|
|
|
|
|
|
|
|
|
|
// Panel相关事件
|
2025-12-26 13:09:35 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_COLLAPSE, () => emit('toggleCollapse'), { componentId: 'dock-layout' }));
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE, onMaximize, { componentId: 'dock-layout' }));
|
2026-01-08 14:51:40 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE_REQUEST, onPanelClose, { componentId: 'dock-layout' }));
|
2026-01-09 13:45:34 +08:00
|
|
|
|
// 移除对PANEL_CLOSE事件的监听,避免重复执行关闭逻辑
|
|
|
|
|
|
// unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CLOSE, onPanelClose, { componentId: 'dock-layout' }));
|
2025-12-26 13:09:35 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_TOGGLE_TOOLBAR, () => emit('toggleToolbar'), { componentId: 'dock-layout' }));
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_MAXIMIZE_SYNC, onPanelMaximizeSync, { componentId: 'dock-layout' }));
|
2025-12-30 11:38:59 +08:00
|
|
|
|
// 单面板检测事件
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.PANEL_CHECK_SINGLE_PANEL, onCheckSinglePanel, { componentId: 'dock-layout' }));
|
2026-01-04 10:15:39 +08:00
|
|
|
|
// Area位置更新事件
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_POSITION_UPDATE, onAreaPositionUpdate, { componentId: 'dock-layout' }));
|
2026-01-05 13:29:28 +08:00
|
|
|
|
// Area z-index更新事件
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.Z_INDEX_UPDATE, onZIndexUpdate, { componentId: 'dock-layout' }));
|
2025-12-15 09:03:32 +08:00
|
|
|
|
|
|
|
|
|
|
// Resize相关事件
|
2025-12-26 13:09:35 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_START, () => emit('dragStart'), { componentId: 'dock-layout' }));
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_MOVE, () => emit('dragMove'), { componentId: 'dock-layout' }));
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.RESIZE_END, () => emit('dragEnd'), { componentId: 'dock-layout' }));
|
2025-12-15 09:03:32 +08:00
|
|
|
|
|
|
|
|
|
|
// Window相关事件
|
2025-12-25 13:53:52 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.WINDOW_STATE_CHANGE, (event) => {
|
2025-12-30 11:38:59 +08:00
|
|
|
|
const areaId = event.areaId;
|
|
|
|
|
|
const state = event.state;
|
|
|
|
|
|
const position = event.position;
|
|
|
|
|
|
|
|
|
|
|
|
const area = floatingAreas.value.find(a => a.id === areaId);
|
|
|
|
|
|
if (area) {
|
|
|
|
|
|
area.windowState = state;
|
|
|
|
|
|
if (position) {
|
|
|
|
|
|
area.left = position.left;
|
|
|
|
|
|
area.top = position.top;
|
|
|
|
|
|
area.width = position.width;
|
|
|
|
|
|
area.height = position.height;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-26 13:09:35 +08:00
|
|
|
|
}, { componentId: 'dock-layout' }));
|
2025-12-15 09:03:32 +08:00
|
|
|
|
|
|
|
|
|
|
// 自定义事件
|
2025-12-29 09:05:37 +08:00
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_MERGED, onAreaMerged, { componentId: 'dock-layout' }));
|
|
|
|
|
|
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.DOCK_ZONE_ACTIVE, (event) => onDockZoneActive(event.zoneId), { componentId: 'dock-layout' }));
|
2025-12-25 13:53:52 +08:00
|
|
|
|
|
|
|
|
|
|
return unsubscribeFunctions;
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-25 13:53:52 +08:00
|
|
|
|
// 保存取消订阅函数数组
|
|
|
|
|
|
const unsubscribeFunctions = ref([]);
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 清理函数
|
|
|
|
|
|
const cleanup = () => {
|
|
|
|
|
|
// 清理事件监听器和其他资源
|
2025-12-04 14:58:41 +08:00
|
|
|
|
console.log('🧹 开始清理DockLayout资源');
|
|
|
|
|
|
|
2025-12-29 09:05:37 +08:00
|
|
|
|
// 清理事件监听器
|
|
|
|
|
|
console.log('🔇 开始清理事件监听器');
|
|
|
|
|
|
unsubscribeFunctions.value.forEach(unsubscribe => unsubscribe());
|
|
|
|
|
|
unsubscribeFunctions.value = [];
|
|
|
|
|
|
|
2025-12-04 14:58:41 +08:00
|
|
|
|
// 清理浮动区域
|
|
|
|
|
|
floatingAreas.value = [];
|
|
|
|
|
|
|
|
|
|
|
|
// 清理隐藏区域
|
|
|
|
|
|
hiddenAreas.value = [];
|
|
|
|
|
|
|
|
|
|
|
|
// 清理主区域ResizeBar
|
|
|
|
|
|
mainAreaResizeBars.value = [];
|
|
|
|
|
|
|
|
|
|
|
|
// 清理停靠指示器状态
|
|
|
|
|
|
showDockIndicator.value = false;
|
|
|
|
|
|
currentMousePosition.value = { x: 0, y: 0 };
|
|
|
|
|
|
targetAreaRect.value = { left: 0, top: 0, width: 0, height: 0 };
|
|
|
|
|
|
activeDockZone.value = null;
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ DockLayout资源清理完成');
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 轻量级隐藏区域管理
|
|
|
|
|
|
const hiddenAreas = ref([]);
|
|
|
|
|
|
|
|
|
|
|
|
// 隐藏Area管理方法
|
2025-11-17 10:59:46 +08:00
|
|
|
|
// 将Area添加到隐藏列表
|
|
|
|
|
|
const addAreaToHiddenList = (area) => {
|
|
|
|
|
|
// 确保area有唯一标识符
|
|
|
|
|
|
if (!area.id) {
|
|
|
|
|
|
area.id = `hidden-area-${Date.now()}`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已经存在于隐藏列表中
|
|
|
|
|
|
const existingIndex = hiddenAreas.value.findIndex(h => h.id === area.id)
|
|
|
|
|
|
if (existingIndex === -1) {
|
|
|
|
|
|
// 添加到隐藏列表
|
|
|
|
|
|
hiddenAreas.value.push({
|
|
|
|
|
|
...area,
|
|
|
|
|
|
hiddenAt: new Date().toISOString()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 移除重复的详细实现函数 - 使用轻量级代理
|
2025-11-18 15:39:46 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 处理并排停靠逻辑
|
|
|
|
|
|
* 当主区域内已有Area时,压缩目标Area并创建并排布局
|
|
|
|
|
|
* @param {Object} sourceArea - 源Area对象
|
|
|
|
|
|
* @param {string} dockZone - 停靠方向
|
|
|
|
|
|
* @returns {Object} 处理结果 {success: boolean, message: string}
|
|
|
|
|
|
*/
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 轻量级并排停靠代理
|
|
|
|
|
|
const handleSideBySideDocking = () => '轻量级并排停靠代理'
|
|
|
|
|
|
|
|
|
|
|
|
// 轻量级ResizeBar添加代理
|
|
|
|
|
|
const addResizeBarForSideBySideLayout = () => '轻量级ResizeBar代理'
|
|
|
|
|
|
|
|
|
|
|
|
// 轻量级ResizeBar事件代理
|
|
|
|
|
|
const handleResizeBarResize = () => '轻量级ResizeBar调整代理'
|
|
|
|
|
|
|
|
|
|
|
|
// 轻量级ResizeBar尺寸调整代理
|
|
|
|
|
|
const handleResizeBarResizeStart = () => '轻量级ResizeBar调整开始代理'
|
|
|
|
|
|
const handleResizeBarResizeEnd = () => '轻量级ResizeBar调整结束代理'
|
|
|
|
|
|
|
|
|
|
|
|
// 轻量级尺寸调整代理
|
|
|
|
|
|
const handleHorizontalResize = () => '轻量级水平调整代理'
|
|
|
|
|
|
const handleVerticalResize = () => '轻量级垂直调整代理'
|
|
|
|
|
|
|
|
|
|
|
|
// 轻量级Area查找代理
|
|
|
|
|
|
const findFirstMainArea = () => '轻量级主区域查找代理'
|
|
|
|
|
|
const getOrCreateTargetArea = () => '轻量级目标区域获取代理'
|
|
|
|
|
|
|
|
|
|
|
|
// 轻量级并排布局代理
|
|
|
|
|
|
const createSideBySideLayout = () => '轻量级并排布局代理'
|
|
|
|
|
|
const compressTargetArea = () => '轻量级压缩目标区域代理'
|
|
|
|
|
|
const adjustSourceAreaForLayout = () => '轻量级布局调整代理'
|
|
|
|
|
|
|
|
|
|
|
|
// 添加浮动面板
|
|
|
|
|
|
const addFloatingPanel = (panel) => {
|
|
|
|
|
|
// 确保panel参数存在,否则使用默认面板对象
|
|
|
|
|
|
const safePanel = panel || {
|
|
|
|
|
|
id: `panel-${Date.now()}`,
|
|
|
|
|
|
title: '新建面板',
|
2025-12-04 14:58:41 +08:00
|
|
|
|
content: {
|
|
|
|
|
|
color: '#435d9c',
|
|
|
|
|
|
title: '默认面板内容',
|
|
|
|
|
|
type: 'default',
|
|
|
|
|
|
timestamp: new Date().toLocaleString(),
|
|
|
|
|
|
data: [
|
|
|
|
|
|
{ id: 1, label: '示例数据1', value: '123' },
|
|
|
|
|
|
{ id: 2, label: '示例数据2', value: '456' },
|
|
|
|
|
|
{ id: 3, label: '示例数据3', value: '789' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
2025-11-18 15:39:46 +08:00
|
|
|
|
|
2026-01-05 15:40:40 +08:00
|
|
|
|
// 生成唯一的areaId
|
|
|
|
|
|
const areaId = `area-${Date.now()}`;
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
const newArea = {
|
2026-01-05 15:40:40 +08:00
|
|
|
|
id: areaId,
|
2025-12-29 13:18:13 +08:00
|
|
|
|
type: 'floating', // 添加浮动类型标识
|
|
|
|
|
|
left: 100 + Math.random() * 200,
|
|
|
|
|
|
top: 100 + Math.random() * 200,
|
2025-11-20 13:14:31 +08:00
|
|
|
|
width: 300,
|
|
|
|
|
|
height: 200,
|
2026-01-05 15:40:40 +08:00
|
|
|
|
zIndex: zIndexManager.getFloatingAreaZIndex(areaId),
|
2025-12-04 14:58:41 +08:00
|
|
|
|
// 使用children结构以兼容Render组件的渲染逻辑
|
|
|
|
|
|
children: {
|
|
|
|
|
|
type: 'TabPage',
|
2026-01-13 16:56:27 +08:00
|
|
|
|
id: `tabPage-${areaId}`,
|
2026-01-08 16:46:00 +08:00
|
|
|
|
tabPosition: ['top', 'right', 'bottom', 'left'][Math.floor(Math.random() * 4)],
|
2026-01-05 16:01:16 +08:00
|
|
|
|
children: [
|
|
|
|
|
|
{
|
|
|
|
|
|
...safePanel,
|
|
|
|
|
|
id: `panel-${Date.now()}-1`,
|
|
|
|
|
|
title: panel?.title || '面板1',
|
|
|
|
|
|
type: 'Panel',
|
|
|
|
|
|
content: {
|
|
|
|
|
|
...safePanel.content,
|
|
|
|
|
|
title: '面板1内容',
|
|
|
|
|
|
data: [
|
|
|
|
|
|
{ id: 1, label: '面板1数据1', value: '数据1' },
|
|
|
|
|
|
{ id: 2, label: '面板1数据2', value: '数据2' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
...safePanel,
|
|
|
|
|
|
id: `panel-${Date.now()}-2`,
|
|
|
|
|
|
title: '面板2',
|
|
|
|
|
|
type: 'Panel',
|
|
|
|
|
|
content: {
|
|
|
|
|
|
...safePanel.content,
|
|
|
|
|
|
title: '面板2内容',
|
|
|
|
|
|
color: '#68217A',
|
|
|
|
|
|
data: [
|
|
|
|
|
|
{ id: 3, label: '面板2数据1', value: '数据3' },
|
|
|
|
|
|
{ id: 4, label: '面板2数据2', value: '数据4' }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2025-12-04 14:58:41 +08:00
|
|
|
|
}
|
2025-11-18 15:39:46 +08:00
|
|
|
|
}
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加到DockLayout的floatingAreas数组中用于渲染
|
2025-11-20 13:14:31 +08:00
|
|
|
|
floatingAreas.value.push(newArea)
|
2025-12-29 13:18:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 同时注册到AreaHandler的状态管理中,确保事件处理能正常进行
|
|
|
|
|
|
areaActions.createFloating(newArea)
|
|
|
|
|
|
|
2026-01-14 09:27:05 +08:00
|
|
|
|
// 初始化面板状态
|
|
|
|
|
|
const tabPage = newArea.children
|
|
|
|
|
|
if (tabPage.children) {
|
|
|
|
|
|
const childrenArray = Array.isArray(tabPage.children) ? tabPage.children : [tabPage.children]
|
|
|
|
|
|
for (const panel of childrenArray) {
|
|
|
|
|
|
if (panel.type === 'Panel' && panel.id) {
|
|
|
|
|
|
panelActions.initializePanelState(panel.id, areaId)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
return newArea.id
|
2025-11-18 15:39:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 查找或创建主区域TabPage
|
|
|
|
|
|
const findOrCreateMainAreaTabPage = () => {
|
|
|
|
|
|
// 返回主区域的tabPage信息
|
|
|
|
|
|
return {
|
|
|
|
|
|
id: 'main-area-tabpage',
|
|
|
|
|
|
title: '主区域',
|
2025-12-04 14:58:41 +08:00
|
|
|
|
items: []
|
2025-11-20 13:14:31 +08:00
|
|
|
|
};
|
2025-11-18 15:39:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 处理上升事件(用户触发的原始事件)- 从GlobalEventManager.js迁移
|
|
|
|
|
|
const handleRisingEvent = async (data, event) => {
|
|
|
|
|
|
// 从事件对象中获取事件类型
|
|
|
|
|
|
const eventType = event.type;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 总是输出日志,便于调试
|
|
|
|
|
|
console.log(`📈 收到上升事件: ${eventType}`, { data });
|
|
|
|
|
|
|
|
|
|
|
|
// 根据事件类型分发到不同的处理方法
|
|
|
|
|
|
switch (eventType) {
|
|
|
|
|
|
// 面板拖拽事件
|
|
|
|
|
|
case EVENT_TYPES.PANEL_DRAG_START:
|
|
|
|
|
|
await handlePanelDragStart(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.PANEL_DRAG_MOVE:
|
|
|
|
|
|
await handlePanelDragMove(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.PANEL_DRAG_END:
|
|
|
|
|
|
await handlePanelDragEnd(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.PANEL_DRAG_CANCEL:
|
|
|
|
|
|
await handlePanelDragCancel(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
// 面板resize事件
|
|
|
|
|
|
case EVENT_TYPES.PANEL_RESIZE_START:
|
|
|
|
|
|
await handlePanelResizeStart(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.PANEL_RESIZE_MOVE:
|
|
|
|
|
|
await handlePanelResizeMove(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.PANEL_RESIZE_END:
|
|
|
|
|
|
await handlePanelResizeEnd(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
// 区域拖拽事件
|
|
|
|
|
|
case EVENT_TYPES.AREA_DRAG_START:
|
|
|
|
|
|
await handleAreaDragStart(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.AREA_DRAG_MOVE:
|
|
|
|
|
|
await handleAreaDragMove(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.AREA_DRAG_END:
|
|
|
|
|
|
await handleAreaDragEnd(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.AREA_DRAG_CANCEL:
|
|
|
|
|
|
await handleAreaDragCancel(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
// 区域resize事件
|
|
|
|
|
|
case EVENT_TYPES.AREA_RESIZE_START:
|
|
|
|
|
|
await handleAreaResizeStart(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.AREA_RESIZE_MOVE:
|
|
|
|
|
|
await handleAreaResizeMove(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.AREA_RESIZE_END:
|
|
|
|
|
|
await handleAreaResizeEnd(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
// 标签页拖拽事件
|
|
|
|
|
|
case EVENT_TYPES.TABPAGE_DRAG_START:
|
|
|
|
|
|
await handleTabPageDragStart(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.TABPAGE_DRAG_MOVE:
|
|
|
|
|
|
await handleTabPageDragMove(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.TABPAGE_DRAG_END:
|
|
|
|
|
|
await handleTabPageDragEnd(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EVENT_TYPES.TABPAGE_DRAG_CANCEL:
|
|
|
|
|
|
await handleTabPageDragCancel(data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
// 默认处理
|
|
|
|
|
|
default:
|
|
|
|
|
|
console.log(`🌐 全局事件: ${eventType}`, data);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error(`❌ 上升事件处理错误 (${eventType}):`, error);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 面板拖拽开始处理
|
|
|
|
|
|
const handlePanelDragStart = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('👋 处理面板拖拽开始:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否应该操作区域而非面板,并缓存结果
|
|
|
|
|
|
const shouldOperateArea = shouldOperateAreaInsteadOfPanelFromData(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 缓存检测结果,用于后续的拖拽移动和结束事件
|
|
|
|
|
|
dragOperationCache.set(data.dragId, {
|
|
|
|
|
|
shouldOperateArea,
|
|
|
|
|
|
timestamp: Date.now()
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldOperateArea) {
|
|
|
|
|
|
// 转换为区域拖拽事件
|
|
|
|
|
|
const areaDragStartData = {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
eventType: 'area.drag.start',
|
|
|
|
|
|
dragId: data.dragId || `area_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽开始事件
|
|
|
|
|
|
eventBus.emit('area.drag.start', areaDragStartData);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 发送面板拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('panel.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'active'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 面板拖拽移动处理
|
|
|
|
|
|
const handlePanelDragMove = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理面板拖拽移动:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从缓存中获取单面板检测结果,避免重复检测
|
|
|
|
|
|
const cache = dragOperationCache.get(data.dragId);
|
|
|
|
|
|
const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(data);
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldOperateArea) {
|
|
|
|
|
|
// 转换为区域拖拽移动事件
|
|
|
|
|
|
const areaDragMoveData = {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
eventType: 'area.drag.move'
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽移动事件
|
|
|
|
|
|
eventBus.emit('area.drag.move', areaDragMoveData);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 发送面板拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('panel.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'moving'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 面板拖拽结束处理
|
|
|
|
|
|
const handlePanelDragEnd = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理面板拖拽结束:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从缓存中获取单面板检测结果
|
|
|
|
|
|
const cache = dragOperationCache.get(data.dragId);
|
|
|
|
|
|
const shouldOperateArea = cache ? cache.shouldOperateArea : shouldOperateAreaInsteadOfPanelFromData(data);
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldOperateArea) {
|
|
|
|
|
|
// 转换为区域拖拽结束事件
|
|
|
|
|
|
const areaDragEndData = {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
eventType: 'area.drag.end'
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽结束事件
|
|
|
|
|
|
eventBus.emit('area.drag.end', areaDragEndData);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 发送面板拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('panel.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'ended'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清理缓存
|
|
|
|
|
|
dragOperationCache.delete(data.dragId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 面板拖拽取消处理
|
|
|
|
|
|
const handlePanelDragCancel = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理面板拖拽取消:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送面板拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('panel.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'cancelled'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 清理缓存
|
|
|
|
|
|
dragOperationCache.delete(data.dragId);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 区域拖拽开始处理
|
|
|
|
|
|
const handleAreaDragStart = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('👋 处理区域拖拽开始:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('area.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'active'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 区域拖拽移动处理
|
|
|
|
|
|
const handleAreaDragMove = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理区域拖拽移动:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('area.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'moving'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域位置更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('area.position.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
position: data.position
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 区域拖拽结束处理
|
|
|
|
|
|
const handleAreaDragEnd = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理区域拖拽结束:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('area.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'ended'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 区域拖拽取消处理
|
|
|
|
|
|
const handleAreaDragCancel = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理区域拖拽取消:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送区域拖拽状态更新事件(下降事件)
|
|
|
|
|
|
eventBus.emit('area.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'cancelled'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 面板resize处理
|
|
|
|
|
|
const handlePanelResizeStart = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('👋 处理面板resize开始:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE_START, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'panel'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handlePanelResizeMove = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理面板resize移动:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'panel'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE_MOVE, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'panel'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handlePanelResizeEnd = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理面板resize结束:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE_END, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'panel'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 区域resize处理
|
|
|
|
|
|
const handleAreaResizeStart = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('👋 处理区域resize开始:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE_START, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'area'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleAreaResizeMove = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理区域resize移动:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'area'
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE_MOVE, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'area'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleAreaResizeEnd = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理区域resize结束:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.AREA_RESIZE_END, {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
resizeType: 'area'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 标签页拖拽处理
|
|
|
|
|
|
const handleTabPageDragStart = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('👋 处理标签页拖拽开始:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 标签页拖拽逻辑
|
|
|
|
|
|
eventBus.emit('tabpage.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'active'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleTabPageDragMove = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理标签页拖拽移动:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit('tabpage.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'moving'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleTabPageDragEnd = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理标签页拖拽结束:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit('tabpage.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'ended'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleTabPageDragCancel = async (data) => {
|
|
|
|
|
|
if (debugMode) {
|
|
|
|
|
|
console.log('✋ 处理标签页拖拽取消:', data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
eventBus.emit('tabpage.drag.state.update', {
|
|
|
|
|
|
...data,
|
|
|
|
|
|
status: 'cancelled'
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-30 11:38:59 +08:00
|
|
|
|
// 单面板检测处理函数
|
|
|
|
|
|
const onCheckSinglePanel = (event) => {
|
2025-12-31 10:51:47 +08:00
|
|
|
|
// 使用新的shouldOperateAreaInsteadOfPanelFromData函数检查是否为单面板
|
|
|
|
|
|
const isSinglePanel = shouldOperateAreaInsteadOfPanelFromData(event);
|
2025-12-30 11:38:59 +08:00
|
|
|
|
|
|
|
|
|
|
// 发送检测结果
|
|
|
|
|
|
eventBus.emit(EVENT_TYPES.PANEL_SINGLE_PANEL_RESULT, {
|
2025-12-31 10:51:47 +08:00
|
|
|
|
areaId: event.areaId,
|
|
|
|
|
|
panelId: event.panelId,
|
2025-12-30 11:38:59 +08:00
|
|
|
|
isSinglePanel
|
|
|
|
|
|
}, { componentId: 'dock-layout' });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Area resize事件处理函数
|
|
|
|
|
|
const onAreaResizeStart = (event) => {
|
|
|
|
|
|
const { areaId, direction, position } = event;
|
|
|
|
|
|
|
|
|
|
|
|
// AreaHandler已经监听了AREA_RESIZE_START事件,会自动处理
|
|
|
|
|
|
// 只需要更新本地floatingAreas中的状态
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const onAreaResizeMove = (event) => {
|
|
|
|
|
|
const { areaId, direction, size, position } = event;
|
|
|
|
|
|
|
|
|
|
|
|
const area = floatingAreas.value.find(a => a.id === areaId);
|
|
|
|
|
|
if (area) {
|
|
|
|
|
|
if (direction.includes('right') || direction.includes('left')) {
|
|
|
|
|
|
area.width = size.width;
|
|
|
|
|
|
if (direction.includes('left')) {
|
|
|
|
|
|
area.left = position.left;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (direction.includes('bottom') || direction.includes('top')) {
|
|
|
|
|
|
area.height = size.height;
|
|
|
|
|
|
if (direction.includes('top')) {
|
|
|
|
|
|
area.top = position.top;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-04 10:15:39 +08:00
|
|
|
|
// 处理Area位置更新事件
|
|
|
|
|
|
const onAreaPositionUpdate = (event) => {
|
|
|
|
|
|
const { areaId, left, top, width, height } = event;
|
|
|
|
|
|
|
|
|
|
|
|
const area = floatingAreas.value.find(a => a.id === areaId);
|
|
|
|
|
|
if (area) {
|
|
|
|
|
|
area.left = left;
|
|
|
|
|
|
area.top = top;
|
|
|
|
|
|
if (width !== undefined) {
|
|
|
|
|
|
area.width = width;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (height !== undefined) {
|
|
|
|
|
|
area.height = height;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-05 13:29:28 +08:00
|
|
|
|
// 处理Area z-index更新事件
|
|
|
|
|
|
const onZIndexUpdate = (event) => {
|
|
|
|
|
|
const { areaId, zIndex } = event;
|
|
|
|
|
|
|
|
|
|
|
|
const area = floatingAreas.value.find(a => a.id === areaId);
|
|
|
|
|
|
if (area) {
|
|
|
|
|
|
area.zIndex = zIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-30 11:38:59 +08:00
|
|
|
|
const onAreaResizeEnd = (event) => {
|
|
|
|
|
|
const { areaId, direction, finalPosition } = event;
|
|
|
|
|
|
|
|
|
|
|
|
// AreaHandler已经监听了AREA_RESIZE_END事件,会自动处理
|
|
|
|
|
|
// 只需要更新本地floatingAreas中的状态
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-14 09:27:05 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 初始化主区域的所有面板状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
const initializeMainAreaPanels = () => {
|
|
|
|
|
|
const mainTabPage = mainAreaConfig.value.children;
|
|
|
|
|
|
if (mainTabPage && mainTabPage.type === 'TabPage' && mainTabPage.children) {
|
|
|
|
|
|
const childrenArray = Array.isArray(mainTabPage.children)
|
|
|
|
|
|
? mainTabPage.children
|
|
|
|
|
|
: [mainTabPage.children];
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`[DockLayout] 初始化主区域面板,共 ${childrenArray.length} 个`);
|
|
|
|
|
|
|
|
|
|
|
|
for (const panel of childrenArray) {
|
|
|
|
|
|
if (panel.type === 'Panel' && panel.id) {
|
|
|
|
|
|
panelActions.initializePanelState(panel.id, mainAreaConfig.value.id);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 轻量级生命周期处理
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
// 初始化轻量级状态
|
|
|
|
|
|
console.log('DockLayout component mounted');
|
2025-12-25 13:53:52 +08:00
|
|
|
|
unsubscribeFunctions.value = setupEventListeners();
|
2026-01-14 09:27:05 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化主区域的面板状态
|
|
|
|
|
|
initializeMainAreaPanels();
|
2025-11-20 13:14:31 +08:00
|
|
|
|
})
|
2025-11-18 15:39:46 +08:00
|
|
|
|
|
2025-12-04 14:58:41 +08:00
|
|
|
|
// 组件卸载时清理资源
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
// 清理事件监听器和其他资源
|
|
|
|
|
|
console.log('DockLayout component unmounted');
|
|
|
|
|
|
cleanup();
|
2025-12-25 13:53:52 +08:00
|
|
|
|
// 逐个移除事件监听器
|
|
|
|
|
|
unsubscribeFunctions.value.forEach(unsubscribe => unsubscribe());
|
|
|
|
|
|
unsubscribeFunctions.value = [];
|
2025-12-04 14:58:41 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 暴露轻量级接口给父组件
|
2025-11-02 17:12:40 +07:00
|
|
|
|
defineExpose({
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 基础数据
|
2025-11-19 13:57:51 +08:00
|
|
|
|
floatingAreas,
|
|
|
|
|
|
hiddenAreas,
|
|
|
|
|
|
|
2025-11-20 13:14:31 +08:00
|
|
|
|
// 核心方法
|
2025-11-17 10:59:46 +08:00
|
|
|
|
addFloatingPanel,
|
2025-11-18 15:39:46 +08:00
|
|
|
|
findOrCreateMainAreaTabPage,
|
2025-11-20 13:14:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 轻量级代理方法(功能保留但简化)
|
|
|
|
|
|
handleDockingEnding: () => '轻量级停靠处理代理',
|
|
|
|
|
|
handleEdgeDocking: () => '轻量级边缘停靠代理',
|
|
|
|
|
|
handleSideBySideDocking: () => '轻量级并排停靠代理',
|
|
|
|
|
|
|
|
|
|
|
|
// ResizeBar轻量级代理
|
|
|
|
|
|
addResizeBarForSideBySideLayout: () => '轻量级ResizeBar代理',
|
|
|
|
|
|
handleResizeBarResize: () => '轻量级ResizeBar调整代理',
|
|
|
|
|
|
|
|
|
|
|
|
// 隐藏列表轻量级代理
|
|
|
|
|
|
getHiddenAreas: () => '轻量级隐藏列表代理',
|
|
|
|
|
|
restoreAreaFromHidden: () => '轻量级恢复代理',
|
|
|
|
|
|
removeFromHiddenList: () => '轻量级移除代理',
|
|
|
|
|
|
clearHiddenList: () => '轻量级清空代理',
|
2025-11-02 17:12:40 +07:00
|
|
|
|
})
|
2025-11-02 17:06:40 +07:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.dock-layout {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
2025-11-04 09:10:15 +08:00
|
|
|
|
overflow: visible;
|
2025-11-02 17:06:40 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 17:26:28 +08:00
|
|
|
|
/* 浮动区域样式已直接应用到Area组件 */
|
2025-11-02 17:19:53 +07:00
|
|
|
|
|
2025-11-02 17:06:40 +07:00
|
|
|
|
/* 添加浮动区域按钮样式 */
|
|
|
|
|
|
.add-floating-btn {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
user-select: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.add-floating-btn:active {
|
|
|
|
|
|
transform: scale(0.98);
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|