修改内容区显示逻辑,改为配置驱动
This commit is contained in:
@@ -50,7 +50,7 @@
|
||||
@mousedown="onResizeStart('w', $event)"
|
||||
></div>
|
||||
<!-- 顶部标题栏 -->
|
||||
<div v-if="showTitleBar" class="vs-title-bar" :class="{ 'cursor-move': !isMaximized }" @mousedown="onDragStart">
|
||||
<div v-if="shouldShowTitleBar" class="vs-title-bar" :class="{ 'cursor-move': !isMaximized }" @mousedown="onDragStart">
|
||||
<div class="vs-title-left">
|
||||
<div class="vs-app-icon" aria-label="AppIcon">
|
||||
<svg class="vs-icon" viewBox="0 0 22.4 22.4" aria-hidden="true">
|
||||
@@ -99,41 +99,15 @@
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="vs-content">
|
||||
<!-- 优先显示receivedContent(停靠的外部内容) -->
|
||||
<template v-if="receivedContent && receivedContent.length > 0">
|
||||
<!-- 调试信息 -->
|
||||
<div v-if="false" style="position: absolute; top: 0; left: 0; background: red; color: white; padding: 5px; z-index: 9999;">
|
||||
DEBUG: receivedContent长度 = {{ receivedContent.length }}
|
||||
<div v-for="(item, index) in receivedContent" :key="`debug-${index}`">
|
||||
TabPage {{ index }}: {{ item.tabPage.id }} - {{ item.tabPage.title }} ({{ item.tabPage.panels.length }} panels)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TabPage
|
||||
v-for="(item, index) in receivedContent"
|
||||
:key="item.tabPage.id"
|
||||
:id="item.tabPage.id"
|
||||
:title="item.tabPage.title"
|
||||
:panels="item.tabPage.panels"
|
||||
:tabPosition="'bottom'"
|
||||
@tabDragStart="() => {}"
|
||||
@tabDragMove="() => {}"
|
||||
@tabDragEnd="() => {}"
|
||||
@maximize="onPanelMaximize"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 如果没有receivedContent但有slot内容,显示slot内容 -->
|
||||
<template v-else-if="$slots.default">
|
||||
<slot></slot>
|
||||
</template>
|
||||
<div class="vs-content">
|
||||
<!-- 直接渲染插槽内容,Render组件会自动处理children -->
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, computed, ref, onMounted, onUnmounted, watch, defineExpose } from 'vue'
|
||||
import { defineProps, computed, ref, onMounted, onUnmounted, watch, defineExpose, useSlots } from 'vue'
|
||||
import { emitEvent, EVENT_TYPES, globalEventListenerManager } from './eventBus'
|
||||
import TabPage from './TabPage.vue'
|
||||
import Panel from './Panel.vue'
|
||||
@@ -170,12 +144,44 @@ const originalPosition = ref({
|
||||
// 保存最大化前的位置和大小,用于还原
|
||||
const maximizedFromPosition = ref(null)
|
||||
|
||||
// 存储接收到的外部Area内容
|
||||
const receivedContent = ref([])
|
||||
// 不再需要存储接收到的外部Area内容,改为通过children配置管理
|
||||
|
||||
// 组件引用
|
||||
const areaRef = ref(null)
|
||||
|
||||
// 获取插槽
|
||||
const slots = useSlots();
|
||||
|
||||
// 计算属性:是否显示标题栏
|
||||
const shouldShowTitleBar = computed(() => {
|
||||
// 基础条件:props.showTitleBar为true
|
||||
if (!props.showTitleBar) return false;
|
||||
|
||||
// 获取插槽内容
|
||||
if (slots.default) {
|
||||
const slotChildren = slots.default();
|
||||
|
||||
// 如果没有插槽内容,显示标题栏
|
||||
if (slotChildren.length === 0) return true;
|
||||
|
||||
// 如果插槽内容不是TabPage,显示标题栏
|
||||
const firstChild = slotChildren[0];
|
||||
if (firstChild.type.name !== 'TabPage') return true;
|
||||
|
||||
// 获取TabPage的插槽内容
|
||||
const tabPageSlots = firstChild.children?.default ? firstChild.children.default() : [];
|
||||
|
||||
// 如果TabPage包含多个Panel,显示标题栏
|
||||
if (tabPageSlots.length !== 1) return true;
|
||||
|
||||
// 如果TabPage只包含一个Panel,不显示标题栏
|
||||
return false;
|
||||
}
|
||||
|
||||
// 默认显示标题栏
|
||||
return true;
|
||||
});
|
||||
|
||||
// 拖拽相关状态
|
||||
const isDragging = ref(false)
|
||||
const dragStartPos = ref({ x: 0, y: 0 })
|
||||
@@ -269,9 +275,20 @@ const onPanelMaximize = (panelId) => {
|
||||
// // console.log('🔸 Area接收最大化事件 - Panel ID:', panelId)
|
||||
|
||||
// 检查内容区是否只有一个Panel
|
||||
const panelChildren = $slots.default ? $slots.default() : []
|
||||
const isSinglePanel = panelChildren.length === 1
|
||||
// // console.log('🔸 检查是否单Panel模式:', { panelChildren: panelChildren.length, isSinglePanel })
|
||||
const slotChildren = slots.default ? slots.default() : []
|
||||
let isSinglePanel = false
|
||||
|
||||
// 查找TabPage组件
|
||||
const tabPages = slotChildren.filter(child => child.type.name === 'TabPage')
|
||||
|
||||
if (tabPages.length === 1) {
|
||||
// 获取TabPage的插槽内容
|
||||
const tabPageSlots = tabPages[0].children?.default ? tabPages[0].children.default() : []
|
||||
// 如果TabPage只有一个Panel,认为是单Panel模式
|
||||
isSinglePanel = tabPageSlots.length === 1
|
||||
}
|
||||
|
||||
// // console.log('🔸 检查是否单Panel模式:', { tabPages: tabPages.length, isSinglePanel })
|
||||
|
||||
if (isSinglePanel) {
|
||||
// // console.log('🔸 单Panel模式,切换Area最大化状态')
|
||||
@@ -659,132 +676,26 @@ const mergeAreaContent = (sourceArea) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const isEmpty = receivedContent.value.length === 0
|
||||
// 发送合并请求事件,让父组件处理配置修改
|
||||
emitEvent(EVENT_TYPES.AREA_MERGE_REQUEST, {
|
||||
sourceArea: sourceArea,
|
||||
targetAreaId: props.id
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
|
||||
if (isEmpty) {
|
||||
// 4.2.1 如果目标Area内容区为空,将源Area内容区的子组件添加到目标Area内容区
|
||||
// console.log('[Area] 目标Area为空,添加源Area的子组件')
|
||||
|
||||
// 处理源Area的所有tabPages(支持两种模式:tabPages和children)
|
||||
let tabPagesData = []
|
||||
|
||||
if (sourceArea.children) {
|
||||
// 统一处理children结构
|
||||
const childrenArray = Array.isArray(sourceArea.children) ? sourceArea.children : [sourceArea.children]
|
||||
for (const child of childrenArray) {
|
||||
if (child.type === 'TabPage' && child.children) {
|
||||
tabPagesData.push({
|
||||
id: child.id,
|
||||
title: child.title,
|
||||
panels: Array.isArray(child.children) ? child.children : (child.children.type === 'Panel' ? [child.children] : [])
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tabPagesData.length > 0) {
|
||||
tabPagesData.forEach((tabPage, tabIndex) => {
|
||||
// 保持原有的tabPage ID,确保Vue组件状态连续性
|
||||
const tabPageId = `merged-tabpage-${tabPage.id}`
|
||||
const newPanels = (tabPage.panels || []).map((panel, panelIndex) => {
|
||||
// 保持原有Panel ID不变,确保Vue响应式和状态稳定性
|
||||
// console.log(`[Area] 添加Panel: ${panel.id}`)
|
||||
return {
|
||||
...panel,
|
||||
maximized: true
|
||||
}
|
||||
})
|
||||
|
||||
receivedContent.value.push({
|
||||
id: `received-${tabPageId}`,
|
||||
title: tabPage.title || `标签页${tabIndex + 1}`,
|
||||
tabPage: {
|
||||
...tabPage,
|
||||
id: tabPageId,
|
||||
panels: newPanels
|
||||
},
|
||||
panels: newPanels
|
||||
})
|
||||
|
||||
// console.log(`[Area] 成功添加TabPage: ${tabPage.title} (${newPanels.length} 个Panel)`)
|
||||
})
|
||||
}
|
||||
|
||||
// 触发事件通知父组件将源Area保存到隐藏列表
|
||||
emitEvent(EVENT_TYPES.AREA_MERGED, {
|
||||
sourceArea: sourceArea,
|
||||
targetAreaId: props.id,
|
||||
targetAreaHasContent: false, // 目标Area为空
|
||||
operation: 'add-children',
|
||||
addedTabPages: receivedContent.value
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
|
||||
return true
|
||||
|
||||
} else {
|
||||
// 4.2.3 如果目标Area已有TabPage,合并TabPage标签页
|
||||
// console.log('[Area] 目标Area已有TabPage,合并TabPage标签页')
|
||||
|
||||
// 获取第一个现有的TabPage作为合并目标
|
||||
const existingTabPage = receivedContent.value[0]
|
||||
if (!existingTabPage) {
|
||||
// console.error('[Area] 现有TabPage不存在')
|
||||
return false
|
||||
}
|
||||
|
||||
// 处理源Area的所有children(统一使用children结构)
|
||||
let tabPagesData = []
|
||||
|
||||
if (sourceArea.children) {
|
||||
// 统一处理children结构
|
||||
const childrenArray = Array.isArray(sourceArea.children) ? sourceArea.children : [sourceArea.children]
|
||||
for (const child of childrenArray) {
|
||||
if (child.type === 'TabPage' && child.children) {
|
||||
tabPagesData.push({
|
||||
id: child.id,
|
||||
title: child.title,
|
||||
panels: Array.isArray(child.children) ? child.children : (child.children.type === 'Panel' ? [child.children] : [])
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tabPagesData.length > 0) {
|
||||
tabPagesData.forEach((sourceTabPage, tabIndex) => {
|
||||
if (sourceTabPage && sourceTabPage.panels) {
|
||||
// 保持原有Panel ID不变,避免Vue组件重新创建和状态丢失
|
||||
const newPanels = sourceTabPage.panels.map((panel, panelIndex) => {
|
||||
// // console.log(`[Area] 合并Panel到现有TabPage: ${panel.id}`)
|
||||
return {
|
||||
...panel,
|
||||
maximized: true
|
||||
}
|
||||
})
|
||||
|
||||
// 将新的Panel添加到现有TabPage,保持ID连续性
|
||||
existingTabPage.tabPage.panels.push(...newPanels)
|
||||
// existingTabPage.panels 是旧引用,保持结构一致性但避免重复添加
|
||||
// // console.log(`[Area] 成功合并 ${newPanels.length} 个Panel到现有TabPage`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 触发事件通知父组件将源Area及其TabPage组件保存到隐藏列表
|
||||
emitEvent(EVENT_TYPES.AREA_MERGED, {
|
||||
sourceArea: sourceArea,
|
||||
targetAreaId: props.id,
|
||||
targetAreaHasContent: true, // 目标Area已有内容
|
||||
operation: 'merge-tabpages',
|
||||
sourceTabPages: tabPagesData
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
// 更新完成
|
||||
// // console.log(`[Area] 合并完成,现有TabPage共有 ${existingTabPage.tabPage.panels.length} 个Panel`)
|
||||
return true
|
||||
}
|
||||
// 触发事件通知父组件将源Area保存到隐藏列表
|
||||
emitEvent(EVENT_TYPES.AREA_MERGED, {
|
||||
sourceArea: sourceArea,
|
||||
targetAreaId: props.id,
|
||||
targetAreaHasContent: false, // 简化处理,由父组件判断
|
||||
operation: 'merge-children',
|
||||
sourceTabPages: sourceArea.children ? [sourceArea.children] : []
|
||||
}, {
|
||||
source: { component: 'Area', areaId: props.id }
|
||||
})
|
||||
|
||||
return true
|
||||
|
||||
} catch (error) {
|
||||
// console.error('[Area] 合并Area内容时出错:', error)
|
||||
|
||||
@@ -225,6 +225,37 @@ const handleMainAreaResizeBarEnd = (id) => {
|
||||
areaActions.handleResizeEnd(id);
|
||||
};
|
||||
|
||||
// 处理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);
|
||||
};
|
||||
|
||||
const getMainAreaResizeBarStyle = (resizeBar) => {
|
||||
return areaActions.getResizeBarStyle(resizeBar);
|
||||
};
|
||||
@@ -243,6 +274,7 @@ const setupEventListeners = () => {
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.AREA_POSITION_UPDATE, onUpdatePosition, { 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_MERGE_REQUEST, handleAreaMergeRequest, { componentId: 'dock-layout' }));
|
||||
|
||||
// Tab相关事件
|
||||
unsubscribeFunctions.push(eventBus.on(EVENT_TYPES.TAB_CHANGE, onTabChange, { componentId: 'dock-layout' }));
|
||||
|
||||
@@ -397,22 +397,40 @@ const onDragStart = (e) => {
|
||||
|
||||
console.log(`[Panel:${props.id}] 开始拖拽, dragId: ${currentDragId}`)
|
||||
|
||||
// 2. 使用事件总线触发拖拽开始事件,包含统一的 dragId 和标准化数据格式
|
||||
const areaId = getCurrentAreaId();
|
||||
|
||||
// 2. 使用事件总线触发面板拖拽开始事件,包含统一的 dragId 和标准化数据格式
|
||||
emitEvent(EVENT_TYPES.PANEL_DRAG_START, {
|
||||
dragId: currentDragId,
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
areaId: areaId,
|
||||
position: { x: e.clientX, y: e.clientY },
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
|
||||
// 3. 防止文本选择和默认行为
|
||||
// 3. 同时触发Area拖拽开始事件,实现通过Panel标题栏拖拽Area
|
||||
emitEvent(EVENT_TYPES.AREA_DRAG_START, {
|
||||
dragId: currentDragId,
|
||||
areaId: areaId,
|
||||
event: e,
|
||||
element: null,
|
||||
position: { x: e.clientX, y: e.clientY },
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
startLeft: 0,
|
||||
startTop: 0,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
|
||||
// 4. 防止文本选择和默认行为
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
// 4. 添加Document事件监听器,使用一次性变量避免内存泄漏
|
||||
// 5. 添加Document事件监听器,使用一次性变量避免内存泄漏
|
||||
addDocumentDragListeners()
|
||||
}
|
||||
};
|
||||
@@ -424,16 +442,31 @@ const onDragMove = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
// 使用事件总线触发拖拽移动事件,包含 dragId
|
||||
const areaId = getCurrentAreaId();
|
||||
|
||||
// 1. 使用事件总线触发面板拖拽移动事件,包含 dragId
|
||||
emitEvent(EVENT_TYPES.PANEL_DRAG_MOVE, {
|
||||
dragId: currentDragId,
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
areaId: areaId,
|
||||
position: { x: e.clientX, y: e.clientY },
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
|
||||
// 2. 同时触发Area拖拽移动事件,实现通过Panel标题栏拖拽Area
|
||||
emitEvent(EVENT_TYPES.AREA_DRAG_MOVE, {
|
||||
dragId: currentDragId,
|
||||
areaId: areaId,
|
||||
event: e,
|
||||
position: { x: e.clientX, y: e.clientY },
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@@ -444,20 +477,33 @@ const onDragEnd = () => {
|
||||
|
||||
console.log(`[Panel:${props.id}] 结束拖拽, dragId: ${currentDragId}`)
|
||||
|
||||
// 使用事件总线触发拖拽结束事件,包含 dragId
|
||||
const areaId = getCurrentAreaId();
|
||||
|
||||
// 1. 使用事件总线触发面板拖拽结束事件,包含 dragId
|
||||
emitEvent(EVENT_TYPES.PANEL_DRAG_END, {
|
||||
dragId: currentDragId,
|
||||
panelId: props.id,
|
||||
areaId: getCurrentAreaId(),
|
||||
areaId: areaId,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
|
||||
// 使用统一的清理方法,确保一致性和完整性
|
||||
// 2. 同时触发Area拖拽结束事件,实现通过Panel标题栏拖拽Area
|
||||
emitEvent(EVENT_TYPES.AREA_DRAG_END, {
|
||||
dragId: currentDragId,
|
||||
areaId: areaId,
|
||||
event: null,
|
||||
position: null,
|
||||
timestamp: Date.now()
|
||||
}, {
|
||||
source: { component: 'Panel', panelId: props.id, dragId: currentDragId }
|
||||
})
|
||||
|
||||
// 3. 使用统一的清理方法,确保一致性和完整性
|
||||
cleanupDragEventListeners()
|
||||
|
||||
// 重置 dragId
|
||||
// 4. 重置 dragId
|
||||
currentDragId = null
|
||||
}
|
||||
};
|
||||
|
||||
@@ -87,10 +87,16 @@
|
||||
|
||||
<!-- Tab页内容区域 -->
|
||||
<div class="tab-content">
|
||||
<!-- 直接渲染插槽内容 -->
|
||||
<slot></slot>
|
||||
<!-- 使用Render组件渲染children配置 -->
|
||||
<div v-for="child in Array.isArray(children) ? children : [children]" :key="child.id" style="width: 100%; height: 100%;">
|
||||
<Render
|
||||
:type="child.type"
|
||||
:config="child"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 空状态提示 -->
|
||||
<div v-if="slotItems.length === 0" class="tab-empty">
|
||||
<div v-if="!children || (Array.isArray(children) && children.length === 0)" class="tab-empty">
|
||||
<span>没有可显示的内容</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -126,10 +132,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, ref, onMounted, onUnmounted, computed, useSlots } from 'vue'
|
||||
import { defineProps, ref, onMounted, onUnmounted, computed } from 'vue'
|
||||
import { emitEvent, EVENT_TYPES } from './eventBus'
|
||||
|
||||
const slots = useSlots()
|
||||
import Render from './Render.vue'
|
||||
|
||||
const props = defineProps({
|
||||
id: { type: String, required: true },
|
||||
@@ -157,33 +162,39 @@ let isDragging = false
|
||||
let dragIndex = -1
|
||||
let currentDragId = null
|
||||
|
||||
// 计算属性:获取插槽项的props
|
||||
// 计算属性:获取子组件项的props
|
||||
const slotItems = computed(() => {
|
||||
if (!slots.default) return []
|
||||
const slotChildren = slots.default()
|
||||
return slotChildren.map(child => child?.props || {})
|
||||
if (!props.children) return []
|
||||
const childrenArray = Array.isArray(props.children) ? props.children : [props.children]
|
||||
return childrenArray.map(child => child || {})
|
||||
})
|
||||
|
||||
// 计算属性:控制标签栏的显示
|
||||
const shouldShowTabs = computed(() => {
|
||||
// 显示标签栏的条件:showTabs为true,且有子组件
|
||||
return props.showTabs && slots.default && slots.default().length > 0
|
||||
// 显示标签栏的条件:showTabs为true,且有多个子组件
|
||||
if (!props.children) return false
|
||||
const childrenCount = Array.isArray(props.children) ? props.children.length : 1
|
||||
return props.showTabs && childrenCount > 1
|
||||
})
|
||||
|
||||
// 设置激活的标签页
|
||||
const setActiveTab = (index) => {
|
||||
const slotChildren = slots.default ? slots.default() : []
|
||||
if (index >= 0 && index < slotChildren.length) {
|
||||
if (!props.children) return
|
||||
|
||||
const childrenArray = Array.isArray(props.children) ? props.children : [props.children]
|
||||
if (index >= 0 && index < childrenArray.length) {
|
||||
activeTabIndex.value = index
|
||||
emitEvent(EVENT_TYPES.TAB_CHANGE, { index, tab: slotChildren[index] })
|
||||
emitEvent(EVENT_TYPES.TAB_CHANGE, { index, tab: childrenArray[index] })
|
||||
}
|
||||
}
|
||||
|
||||
// 组件挂载后,如果有子组件且没有激活的标签,默认激活第一个
|
||||
onMounted(() => {
|
||||
const slotChildren = slots.default ? slots.default() : []
|
||||
if (slotChildren.length > 0 && activeTabIndex.value === -1) {
|
||||
setActiveTab(0)
|
||||
if (props.children) {
|
||||
const childrenCount = Array.isArray(props.children) ? props.children.length : 1
|
||||
if (childrenCount > 0 && activeTabIndex.value === -1) {
|
||||
setActiveTab(0)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -202,13 +213,20 @@ const onTabDragStart = (index, event) => {
|
||||
// 生成统一的 dragId
|
||||
currentDragId = `tabpage_${props.id}_${index}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
|
||||
|
||||
// 获取tabId
|
||||
let tabId = null
|
||||
if (props.children) {
|
||||
const childrenArray = Array.isArray(props.children) ? props.children : [props.children]
|
||||
tabId = childrenArray[index]?.id || `tab-${index}`
|
||||
}
|
||||
|
||||
// 传递标签页索引和鼠标位置,包含 dragId
|
||||
emitEvent(EVENT_TYPES.TAB_DRAG_START, {
|
||||
dragId: currentDragId,
|
||||
clientX: event.clientX,
|
||||
clientY: event.clientY,
|
||||
tabIndex: index,
|
||||
tabId: $slots.default()[index]?.props?.id
|
||||
tabId: tabId
|
||||
}, {
|
||||
source: { component: 'TabPage', tabPageId: props.id, tabIndex: index, dragId: currentDragId }
|
||||
})
|
||||
|
||||
@@ -612,20 +612,6 @@ class DragStateManager {
|
||||
|
||||
console.log('🔍 _onDragEvent 接收到的数据:', { eventType, dragId, componentType, data });
|
||||
|
||||
// 从事件数据中提取 dragId,如果没有则根据组件类型推断
|
||||
let actualDragId = dragId;
|
||||
if (!actualDragId) {
|
||||
if (data.panelId) {
|
||||
actualDragId = `panel_${data.panelId}_${data.timestamp || Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
||||
} else if (data.tabIndex !== undefined) {
|
||||
actualDragId = `tabpage_${data.tabId}_${data.tabIndex}_${data.timestamp || Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
||||
} else if (data.areaId) {
|
||||
actualDragId = `area_${data.areaId}_${data.timestamp || Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔍 _onDragEvent 处理后的 dragId:', { originalDragId: dragId, actualDragId });
|
||||
|
||||
// 推断组件类型
|
||||
let actualComponentType = componentType;
|
||||
if (!actualComponentType) {
|
||||
@@ -638,6 +624,11 @@ class DragStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
// 从事件数据中提取 dragId,如果没有则使用统一的生成方法
|
||||
let actualDragId = dragId || this._generateDragId(actualComponentType);
|
||||
|
||||
console.log('🔍 _onDragEvent 处理后的 dragId:', { originalDragId: dragId, actualDragId });
|
||||
|
||||
// 准备标准化的拖拽数据
|
||||
const dragData = {
|
||||
...data,
|
||||
@@ -1799,15 +1790,20 @@ class DragStateManager {
|
||||
...options
|
||||
} = eventData;
|
||||
|
||||
// 使用传入的 dragId,如果没有则生成新的
|
||||
const dragId = incomingDragId || this._generateDragId(type);
|
||||
|
||||
// 检查是否已存在相同 dragId 的拖拽状态
|
||||
if (this.activeDrags.has(dragId)) {
|
||||
console.log(`⚠️ 拖拽状态已存在: ${dragId},跳过创建`);
|
||||
return dragId;
|
||||
}
|
||||
|
||||
// 检查是否有其他活跃拖拽
|
||||
if (this.activeDrags.size > 0) {
|
||||
console.warn('检测到其他活跃拖拽,跳过创建新拖拽状态');
|
||||
// 如果已经有活跃拖拽,直接返回现有拖拽的dragId
|
||||
return Array.from(this.activeDrags.keys())[0];
|
||||
console.warn('检测到其他活跃拖拽,暂停之前的拖拽');
|
||||
this.cancelAllDrags();
|
||||
}
|
||||
|
||||
// 使用传入的 dragId,如果没有则生成新的
|
||||
const dragId = incomingDragId || `area-${areaId}-${Date.now()}`;
|
||||
|
||||
// 创建拖拽状态
|
||||
const dragState = new DragState(dragId, DRAG_AREA_TYPES.AREA, element, {
|
||||
|
||||
Reference in New Issue
Block a user