修改内容区显示逻辑,改为配置驱动

This commit is contained in:
zqm
2025-12-26 17:12:36 +08:00
parent e89d3254e8
commit 09e4076635
5 changed files with 213 additions and 210 deletions

View File

@@ -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)