2025-10-20 09:04:09 +08:00
|
|
|
|
import { defineStore } from 'pinia'
|
|
|
|
|
|
import { ref, computed } from 'vue'
|
|
|
|
|
|
import { LayoutCoordinator } from '../components/LayoutCoordinator.js'
|
|
|
|
|
|
|
|
|
|
|
|
// 生成唯一ID
|
|
|
|
|
|
export function generateUniqueId() {
|
|
|
|
|
|
return 'panel-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export const useDockPanelStore = defineStore('dockPanel', () => {
|
|
|
|
|
|
// 布局协调器实例
|
|
|
|
|
|
const minSizes = { panelWidth: 150, panelHeight: 100 }
|
|
|
|
|
|
const layoutCoordinator = new LayoutCoordinator(minSizes)
|
|
|
|
|
|
|
|
|
|
|
|
// 面板位置分组
|
|
|
|
|
|
const leftPanelArea = ref({
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
width: 300,
|
|
|
|
|
|
height: 0, // 将在updatePanelsSize中被正确设置
|
|
|
|
|
|
heightRatios: []
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const rightPanelArea = ref({
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
width: 250,
|
|
|
|
|
|
height: 0, // 将在updatePanelsSize中被正确设置
|
|
|
|
|
|
heightRatios: []
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const topPanelArea = ref({
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
height: 150,
|
|
|
|
|
|
width: 0, // 将在updatePanelsSize中被正确设置
|
|
|
|
|
|
widthRatios: []
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const bottomPanelArea = ref({
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
height: 200,
|
|
|
|
|
|
width: 0, // 将在updatePanelsSize中被正确设置
|
|
|
|
|
|
widthRatios: []
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const centerPanelArea = ref({
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
width: 0, // 将在updatePanelsSize中被正确设置
|
|
|
|
|
|
height: 0, // 将在updatePanelsSize中被正确设置
|
|
|
|
|
|
widthRatios: [],
|
|
|
|
|
|
heightRatios: []
|
|
|
|
|
|
})
|
|
|
|
|
|
const floatingWindows = ref([])
|
|
|
|
|
|
const minimizedWindows = ref([])
|
|
|
|
|
|
const closedPanelHistory = ref([]) // 关闭历史记录
|
|
|
|
|
|
|
|
|
|
|
|
// 激活的标签页
|
|
|
|
|
|
const activeCenterTab = ref(0)
|
|
|
|
|
|
|
|
|
|
|
|
// 计算属性
|
|
|
|
|
|
const leftPanels = computed(() => leftPanelArea.value.panels)
|
|
|
|
|
|
const rightPanels = computed(() => rightPanelArea.value.panels)
|
|
|
|
|
|
const topPanels = computed(() => topPanelArea.value.panels)
|
|
|
|
|
|
const bottomPanels = computed(() => bottomPanelArea.value.panels)
|
|
|
|
|
|
const centerPanels = computed(() => centerPanelArea.value.panels)
|
|
|
|
|
|
|
|
|
|
|
|
const leftPanelWidth = computed({
|
|
|
|
|
|
get: () => leftPanelArea.value.width,
|
|
|
|
|
|
set: (value) => leftPanelArea.value.width = value
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const rightPanelWidth = computed({
|
|
|
|
|
|
get: () => rightPanelArea.value.width,
|
|
|
|
|
|
set: (value) => rightPanelArea.value.width = value
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const topPanelHeight = computed({
|
|
|
|
|
|
get: () => topPanelArea.value.height,
|
|
|
|
|
|
set: (value) => topPanelArea.value.height = value
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const bottomPanelHeight = computed({
|
|
|
|
|
|
get: () => bottomPanelArea.value.height,
|
|
|
|
|
|
set: (value) => bottomPanelArea.value.height = value
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 调整大小状态
|
|
|
|
|
|
const isResizing = ref(false)
|
|
|
|
|
|
const resizeTarget = ref('')
|
|
|
|
|
|
const resizeStartPos = ref({ x: 0, y: 0 })
|
|
|
|
|
|
const resizeContext = ref(null)
|
|
|
|
|
|
|
|
|
|
|
|
// 拖拽状态
|
|
|
|
|
|
const dragState = ref({
|
|
|
|
|
|
active: false,
|
|
|
|
|
|
panelId: null,
|
|
|
|
|
|
startX: 0,
|
|
|
|
|
|
startY: 0,
|
|
|
|
|
|
originalPosition: null,
|
|
|
|
|
|
isPanelDrag: false
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 停靠预览
|
|
|
|
|
|
const dockPreview = ref({
|
|
|
|
|
|
visible: false,
|
|
|
|
|
|
position: { top: 0, left: 0, width: 0, height: 0 },
|
|
|
|
|
|
color: '#3b82f6',
|
|
|
|
|
|
targetPosition: ''
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 右键菜单
|
|
|
|
|
|
const contextMenu = ref({
|
|
|
|
|
|
visible: false,
|
|
|
|
|
|
position: { x: 0, y: 0 },
|
|
|
|
|
|
items: [],
|
|
|
|
|
|
panelId: null
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 面板大小影响关系
|
|
|
|
|
|
const panelSizeInfluence = {
|
|
|
|
|
|
influence: {
|
|
|
|
|
|
left: ref([]),
|
|
|
|
|
|
right: ref([]),
|
|
|
|
|
|
top: ref([]),
|
|
|
|
|
|
bottom: ref([]),
|
|
|
|
|
|
center: ref([])
|
|
|
|
|
|
},
|
|
|
|
|
|
influencedBy: {
|
|
|
|
|
|
left: ref([]),
|
|
|
|
|
|
right: ref([]),
|
|
|
|
|
|
top: ref([]),
|
|
|
|
|
|
bottom: ref([]),
|
|
|
|
|
|
center: ref([])
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据面板ID获取面板位置
|
|
|
|
|
|
function getPanelPositionById(panelId) {
|
|
|
|
|
|
// 检查左侧面板
|
|
|
|
|
|
for (let i = 0; i < leftPanels.value.length; i++) {
|
|
|
|
|
|
if (leftPanels.value[i].id === panelId) {
|
|
|
|
|
|
return { position: 'left', index: i }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查右侧面板
|
|
|
|
|
|
for (let i = 0; i < rightPanels.value.length; i++) {
|
|
|
|
|
|
if (rightPanels.value[i].id === panelId) {
|
|
|
|
|
|
return { position: 'right', index: i }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查顶部面板
|
|
|
|
|
|
for (let i = 0; i < topPanels.value.length; i++) {
|
|
|
|
|
|
if (topPanels.value[i].id === panelId) {
|
|
|
|
|
|
return { position: 'top', index: i }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查底部面板
|
|
|
|
|
|
for (let i = 0; i < bottomPanels.value.length; i++) {
|
|
|
|
|
|
if (bottomPanels.value[i].id === panelId) {
|
|
|
|
|
|
return { position: 'bottom', index: i }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查中心面板
|
|
|
|
|
|
for (let i = 0; i < centerPanelArea.value.panels.length; i++) {
|
|
|
|
|
|
if (centerPanelArea.value.panels[i].id === panelId) {
|
|
|
|
|
|
return { position: 'center', index: i }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加面板
|
|
|
|
|
|
function addPanel(panel, minSizes = { panelWidth: 150, panelHeight: 100 }) {
|
|
|
|
|
|
const panelData = {
|
|
|
|
|
|
...panel,
|
|
|
|
|
|
collapsed: panel.collapsed || false,
|
|
|
|
|
|
lastPosition: panel.position,
|
|
|
|
|
|
lastSize: panel.lastSize || {
|
|
|
|
|
|
width: panel.width || 300,
|
|
|
|
|
|
height: panel.height || 200
|
|
|
|
|
|
},
|
|
|
|
|
|
width: panel.width || 300
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取全局容器元素(只查询一次DOM)
|
|
|
|
|
|
const container = document.querySelector('.dock-panel-container');
|
|
|
|
|
|
|
|
|
|
|
|
switch (panel.position) {
|
|
|
|
|
|
case 'left':
|
|
|
|
|
|
const isLeftFirst = leftPanels.value.length === 0
|
|
|
|
|
|
leftPanelArea.value.panels.push(panelData)
|
|
|
|
|
|
resetPanelsSizeRatios('left')
|
|
|
|
|
|
// 使用全局容器元素更新面板尺寸
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
updatePanelsSize('left', leftPanelArea.value, container, minSizes);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isLeftFirst) {
|
|
|
|
|
|
// 触发左侧面板的尺寸影响处理,传入容器引用避免重复查询
|
|
|
|
|
|
handlePanelSizeInfluence('left', container)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
const isRightFirst = rightPanels.value.length === 0
|
|
|
|
|
|
rightPanelArea.value.panels.push(panelData)
|
|
|
|
|
|
resetPanelsSizeRatios('right')
|
|
|
|
|
|
// 使用全局容器元素更新面板尺寸
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
updatePanelsSize('right', rightPanelArea.value, container, minSizes);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isRightFirst) {
|
|
|
|
|
|
// 触发右侧面板的尺寸影响处理,传入容器引用避免重复查询
|
|
|
|
|
|
handlePanelSizeInfluence('right', container)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'top':
|
|
|
|
|
|
const isTopFirst = topPanels.value.length === 0
|
|
|
|
|
|
topPanelArea.value.panels.push(panelData)
|
|
|
|
|
|
resetPanelsSizeRatios('top')
|
|
|
|
|
|
// 使用全局容器元素更新面板尺寸
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
updatePanelsSize('top', topPanelArea.value, container, minSizes);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isTopFirst) {
|
|
|
|
|
|
// 触发顶部面板的尺寸影响处理,传入容器引用避免重复查询
|
|
|
|
|
|
handlePanelSizeInfluence('top', container)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'bottom':
|
|
|
|
|
|
const isBottomFirst = bottomPanels.value.length === 0
|
|
|
|
|
|
bottomPanelArea.value.panels.push(panelData)
|
|
|
|
|
|
resetPanelsSizeRatios('bottom')
|
|
|
|
|
|
// 使用全局容器元素更新面板尺寸
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
updatePanelsSize('bottom', bottomPanelArea.value, container, minSizes);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isBottomFirst) {
|
|
|
|
|
|
// 触发底部面板的尺寸影响处理,传入容器引用避免重复查询
|
|
|
|
|
|
handlePanelSizeInfluence('bottom', container)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'center':
|
|
|
|
|
|
default:
|
|
|
|
|
|
centerPanelArea.value.panels.push(panelData)
|
|
|
|
|
|
resetPanelsSizeRatios('center')
|
|
|
|
|
|
// 使用全局容器元素更新中心面板尺寸
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
updatePanelsSize('center', centerPanelArea.value, container, minSizes);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (centerPanelArea.value.panels.length === 1) {
|
|
|
|
|
|
activeCenterTab.value = 0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重置面板尺寸比例
|
|
|
|
|
|
function resetPanelsSizeRatios(position) {
|
|
|
|
|
|
let panelArea
|
|
|
|
|
|
|
|
|
|
|
|
switch (position) {
|
|
|
|
|
|
case 'top':
|
|
|
|
|
|
panelArea = topPanelArea.value
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'bottom':
|
|
|
|
|
|
panelArea = bottomPanelArea.value
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'left':
|
|
|
|
|
|
panelArea = leftPanelArea.value
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
panelArea = rightPanelArea.value
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'center':
|
|
|
|
|
|
panelArea = centerPanelArea.value
|
|
|
|
|
|
break
|
|
|
|
|
|
default:
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!panelArea.panels || panelArea.panels.length === 0) return
|
|
|
|
|
|
|
|
|
|
|
|
const panelCount = panelArea.panels.length
|
|
|
|
|
|
const ratios = Array(panelCount).fill(1 / panelCount)
|
|
|
|
|
|
|
|
|
|
|
|
if (position === 'top' || position === 'bottom') {
|
|
|
|
|
|
panelArea.widthRatios = ratios
|
|
|
|
|
|
} else if (position === 'left' || position === 'right') {
|
|
|
|
|
|
panelArea.heightRatios = ratios
|
|
|
|
|
|
} else if (position === 'center') {
|
|
|
|
|
|
// 中心面板通常是标签页形式,不需要宽高比例
|
|
|
|
|
|
panelArea.widthRatios = ratios
|
|
|
|
|
|
panelArea.heightRatios = ratios
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return ratios
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭面板
|
|
|
|
|
|
function closePanel(panelId, container = null) {
|
|
|
|
|
|
const panelPosition = getPanelPositionById(panelId)
|
|
|
|
|
|
if (!panelPosition) return
|
|
|
|
|
|
|
|
|
|
|
|
const { position, index } = panelPosition
|
|
|
|
|
|
let panel, panels
|
|
|
|
|
|
let panelArea = null
|
|
|
|
|
|
|
|
|
|
|
|
switch (position) {
|
|
|
|
|
|
case 'left':
|
|
|
|
|
|
panelArea = leftPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
panelArea = rightPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'top':
|
|
|
|
|
|
panelArea = topPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'bottom':
|
|
|
|
|
|
panelArea = bottomPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'center':
|
|
|
|
|
|
panelArea = centerPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
default:
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
panel = panels[index]
|
|
|
|
|
|
|
|
|
|
|
|
// 保存到历史记录
|
|
|
|
|
|
if (closedPanelHistory.value.length >= 20) {
|
|
|
|
|
|
closedPanelHistory.value.shift()
|
|
|
|
|
|
}
|
|
|
|
|
|
closedPanelHistory.value.push(panel)
|
|
|
|
|
|
|
|
|
|
|
|
// 从数组中移除面板
|
|
|
|
|
|
panels.splice(index, 1)
|
|
|
|
|
|
|
|
|
|
|
|
// 处理所有位置面板的通用逻辑
|
|
|
|
|
|
if (panels.length > 0) {
|
|
|
|
|
|
resetPanelsSizeRatios(position)
|
2025-10-20 10:59:56 +08:00
|
|
|
|
// 无论是否提供container参数,都应该更新面板区内的子面板尺寸
|
2025-10-20 09:04:09 +08:00
|
|
|
|
if (container) {
|
|
|
|
|
|
updatePanelsSize(position, panelArea, container, { panelWidth: 150, panelHeight: 100 });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果面板区域变为空,触发尺寸影响处理以更新其他区域
|
2025-10-20 10:59:56 +08:00
|
|
|
|
if (panels.length === 0) {
|
2025-10-20 09:04:09 +08:00
|
|
|
|
handlePanelSizeInfluence(position, container);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理中心面板的特殊逻辑
|
|
|
|
|
|
if (position === 'center') {
|
|
|
|
|
|
if (index === activeCenterTab.value && panels.length > 0) {
|
|
|
|
|
|
activeCenterTab.value = Math.min(index, panels.length - 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加浮动窗口
|
|
|
|
|
|
function addFloatingWindow(window) {
|
|
|
|
|
|
floatingWindows.value.push({
|
|
|
|
|
|
...window,
|
|
|
|
|
|
minimized: false,
|
|
|
|
|
|
maximized: false,
|
|
|
|
|
|
lastPosition: { x: window.x, y: window.y },
|
|
|
|
|
|
lastSize: { width: window.width, height: window.height }
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭浮动窗口
|
|
|
|
|
|
function closeFloatingWindow(windowId) {
|
|
|
|
|
|
const index = floatingWindows.value.findIndex(w => w.id === windowId)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
const minimizedIndex = minimizedWindows.value.findIndex(w => w.id === windowId)
|
|
|
|
|
|
if (minimizedIndex !== -1) {
|
|
|
|
|
|
minimizedWindows.value.splice(minimizedIndex, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
floatingWindows.value.splice(index, 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将面板转换为浮动窗口
|
|
|
|
|
|
function floatPanel(panelId) {
|
|
|
|
|
|
const panelPosition = getPanelPositionById(panelId)
|
|
|
|
|
|
if (!panelPosition) return
|
|
|
|
|
|
|
|
|
|
|
|
const { position, index } = panelPosition
|
|
|
|
|
|
let panel, panels, panelArea
|
|
|
|
|
|
|
|
|
|
|
|
switch (position) {
|
|
|
|
|
|
case 'left':
|
|
|
|
|
|
panelArea = leftPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
panelArea = rightPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'top':
|
|
|
|
|
|
panelArea = topPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'bottom':
|
|
|
|
|
|
panelArea = bottomPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'center':
|
|
|
|
|
|
panelArea = centerPanelArea.value
|
|
|
|
|
|
panels = panelArea.panels
|
|
|
|
|
|
break
|
|
|
|
|
|
default:
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
panel = panels[index]
|
|
|
|
|
|
|
|
|
|
|
|
// 从原位置移除
|
|
|
|
|
|
panels.splice(index, 1)
|
|
|
|
|
|
|
|
|
|
|
|
// 处理不同位置面板的特殊逻辑
|
|
|
|
|
|
if (position !== 'center') {
|
|
|
|
|
|
if (panelArea.panels.length > 0) {
|
|
|
|
|
|
resetPanelsSizeRatios(position)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (index === activeCenterTab.value && panels.length > 0) {
|
|
|
|
|
|
activeCenterTab.value = Math.min(index, panels.length - 1)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建浮动窗口
|
|
|
|
|
|
addFloatingWindow({
|
|
|
|
|
|
...panel,
|
|
|
|
|
|
x: 100,
|
|
|
|
|
|
y: 100,
|
|
|
|
|
|
width: 400,
|
|
|
|
|
|
height: 300,
|
|
|
|
|
|
floating: true
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 停靠面板
|
|
|
|
|
|
function dockPanel(panelId, position) {
|
|
|
|
|
|
const index = floatingWindows.value.findIndex(w => w.id === panelId)
|
|
|
|
|
|
if (index !== -1) {
|
|
|
|
|
|
const window = floatingWindows.value[index]
|
|
|
|
|
|
|
|
|
|
|
|
// 从浮动窗口移除
|
|
|
|
|
|
floatingWindows.value.splice(index, 1)
|
|
|
|
|
|
|
|
|
|
|
|
// 添加到新位置
|
|
|
|
|
|
addPanel({
|
|
|
|
|
|
...window,
|
|
|
|
|
|
position: position || window.lastPosition || 'center',
|
|
|
|
|
|
floating: false
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 最小化浮动窗口
|
|
|
|
|
|
function minimizeFloatingWindow(windowId) {
|
|
|
|
|
|
const window = floatingWindows.value.find(w => w.id === windowId)
|
|
|
|
|
|
if (window) {
|
|
|
|
|
|
window.minimized = true
|
|
|
|
|
|
minimizedWindows.value.push(window)
|
|
|
|
|
|
|
|
|
|
|
|
// 记录最小化前的状态
|
|
|
|
|
|
if (!window.maximized) {
|
|
|
|
|
|
window.lastPosition = { x: window.x, y: window.y }
|
|
|
|
|
|
window.lastSize = { width: window.width, height: window.height }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 恢复最小化窗口
|
|
|
|
|
|
function restoreMinimizedWindow(windowId) {
|
|
|
|
|
|
const windowIndex = floatingWindows.value.findIndex(w => w.id === windowId)
|
|
|
|
|
|
const minimizedIndex = minimizedWindows.value.findIndex(w => w.id === windowId)
|
|
|
|
|
|
|
|
|
|
|
|
if (windowIndex !== -1 && minimizedIndex !== -1) {
|
|
|
|
|
|
const window = floatingWindows.value[windowIndex]
|
|
|
|
|
|
|
|
|
|
|
|
// 移除最小化状态
|
|
|
|
|
|
window.minimized = false
|
|
|
|
|
|
|
|
|
|
|
|
// 从最小化窗口列表中移除
|
|
|
|
|
|
minimizedWindows.value.splice(minimizedIndex, 1)
|
|
|
|
|
|
|
|
|
|
|
|
// 如果窗口是最大化状态,则保持最大化
|
|
|
|
|
|
// 否则恢复到最小化前的位置和大小
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 最大化浮动窗口
|
|
|
|
|
|
function maximizeFloatingWindow(windowId) {
|
|
|
|
|
|
const window = floatingWindows.value.find(w => w.id === windowId)
|
|
|
|
|
|
if (window) {
|
|
|
|
|
|
if (window.maximized) {
|
|
|
|
|
|
// 还原
|
|
|
|
|
|
window.maximized = false
|
|
|
|
|
|
window.width = window.lastSize.width
|
|
|
|
|
|
window.height = window.lastSize.height
|
|
|
|
|
|
window.x = window.lastPosition.x
|
|
|
|
|
|
window.y = window.lastPosition.y
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 最大化
|
|
|
|
|
|
window.maximized = true
|
|
|
|
|
|
window.lastPosition = { x: window.x, y: window.y }
|
|
|
|
|
|
window.lastSize = { width: window.width, height: window.height }
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前窗口的尺寸逻辑
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 折叠/展开面板
|
|
|
|
|
|
function toggleCollapse(panelId, minSizes = { panelWidth: 150, panelHeight: 100 }) {
|
|
|
|
|
|
const panelPosition = getPanelPositionById(panelId)
|
|
|
|
|
|
if (!panelPosition) return
|
|
|
|
|
|
|
|
|
|
|
|
const { position, index } = panelPosition
|
|
|
|
|
|
let panel, panelArea
|
|
|
|
|
|
const isWidth = position === 'left' || position === 'right'
|
|
|
|
|
|
|
|
|
|
|
|
switch (position) {
|
|
|
|
|
|
case 'left':
|
|
|
|
|
|
panelArea = leftPanelArea.value
|
|
|
|
|
|
panel = panelArea.panels[index]
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
panelArea = rightPanelArea.value
|
|
|
|
|
|
panel = panelArea.panels[index]
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'top':
|
|
|
|
|
|
panelArea = topPanelArea.value
|
|
|
|
|
|
panel = panelArea.panels[index]
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'bottom':
|
|
|
|
|
|
panelArea = bottomPanelArea.value
|
|
|
|
|
|
panel = panelArea.panels[index]
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'center':
|
|
|
|
|
|
panelArea = centerPanelArea.value
|
|
|
|
|
|
panel = panelArea.panels[index]
|
|
|
|
|
|
panel.collapsed = !panel.collapsed
|
|
|
|
|
|
return
|
|
|
|
|
|
default:
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理非中心面板的折叠逻辑
|
|
|
|
|
|
if (position !== 'center') {
|
|
|
|
|
|
if (!panel.collapsed) {
|
|
|
|
|
|
// 保存原始尺寸
|
|
|
|
|
|
panel.originalSize = isWidth ? panelArea.width : panelArea.height
|
|
|
|
|
|
// 对于左右面板,设置为30px宽度
|
|
|
|
|
|
if (isWidth) {
|
|
|
|
|
|
panelArea.width = 30
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 恢复原始尺寸
|
|
|
|
|
|
if (panel.originalSize) {
|
|
|
|
|
|
if (isWidth) {
|
|
|
|
|
|
panelArea.width = Math.max(minSizes.panelWidth, panel.originalSize)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
panelArea.height = Math.max(minSizes.panelHeight, panel.originalSize)
|
|
|
|
|
|
}
|
|
|
|
|
|
delete panel.originalSize
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (isWidth) {
|
|
|
|
|
|
panelArea.width = minSizes.panelWidth
|
|
|
|
|
|
} else {
|
|
|
|
|
|
panelArea.height = minSizes.panelHeight
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换折叠状态
|
|
|
|
|
|
panel.collapsed = !panel.collapsed
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 隐藏右键菜单
|
|
|
|
|
|
function hideContextMenu() {
|
|
|
|
|
|
contextMenu.value.visible = false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化面板
|
|
|
|
|
|
function initializePanels(panels) {
|
|
|
|
|
|
panels.forEach(panel => {
|
|
|
|
|
|
if (panel.floating) {
|
|
|
|
|
|
addFloatingWindow({
|
|
|
|
|
|
...panel,
|
|
|
|
|
|
id: panel.id || generateUniqueId(),
|
|
|
|
|
|
width: panel.width || 400,
|
|
|
|
|
|
height: panel.height || 300,
|
|
|
|
|
|
x: panel.x || 100,
|
|
|
|
|
|
y: panel.y || 100
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
addPanel({
|
|
|
|
|
|
...panel,
|
|
|
|
|
|
id: panel.id || generateUniqueId(),
|
|
|
|
|
|
position: panel.position || 'center'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重置所有面板状态
|
|
|
|
|
|
function resetLayout() {
|
|
|
|
|
|
// 重置面板区对象,确保每个面板区域都包含width和height属性
|
|
|
|
|
|
leftPanelArea.value = {
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
width: 300,
|
|
|
|
|
|
height: 0, // 初始高度为0,将在updatePanelsSize中被正确设置
|
|
|
|
|
|
heightRatios: []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rightPanelArea.value = {
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
width: 250,
|
|
|
|
|
|
height: 0, // 初始高度为0,将在updatePanelsSize中被正确设置
|
|
|
|
|
|
heightRatios: []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
topPanelArea.value = {
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
height: 150,
|
|
|
|
|
|
width: 0, // 初始宽度为0,将在updatePanelsSize中被正确设置
|
|
|
|
|
|
widthRatios: []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bottomPanelArea.value = {
|
|
|
|
|
|
panels: [],
|
|
|
|
|
|
height: 200,
|
|
|
|
|
|
width: 0, // 初始宽度为0,将在updatePanelsSize中被正确设置
|
|
|
|
|
|
widthRatios: []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清空其他面板集合
|
|
|
|
|
|
centerPanelArea.value.panels = []
|
|
|
|
|
|
floatingWindows.value = []
|
|
|
|
|
|
minimizedWindows.value = []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-20 10:59:56 +08:00
|
|
|
|
// 刷新所有面板区域的大小信息
|
|
|
|
|
|
function refreshPanelSizes(container = null) {
|
|
|
|
|
|
// 对于每个面板区域,调用updatePanelsSize来刷新大小信息
|
|
|
|
|
|
// 只有当容器存在时才调用updatePanelsSize
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
updatePanelsSize('left', leftPanelArea.value, container);
|
|
|
|
|
|
updatePanelsSize('right', rightPanelArea.value, container);
|
|
|
|
|
|
updatePanelsSize('top', topPanelArea.value, container);
|
|
|
|
|
|
updatePanelsSize('bottom', bottomPanelArea.value, container);
|
|
|
|
|
|
updatePanelsSize('center', centerPanelArea.value, container);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 触发响应式更新
|
|
|
|
|
|
// 重新赋值整个对象来确保Vue能够检测到变化
|
|
|
|
|
|
leftPanelArea.value = { ...leftPanelArea.value };
|
|
|
|
|
|
rightPanelArea.value = { ...rightPanelArea.value };
|
|
|
|
|
|
topPanelArea.value = { ...topPanelArea.value };
|
|
|
|
|
|
bottomPanelArea.value = { ...bottomPanelArea.value };
|
|
|
|
|
|
centerPanelArea.value = { ...centerPanelArea.value };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-20 09:04:09 +08:00
|
|
|
|
// 初始化面板大小影响关系和受影响关系
|
|
|
|
|
|
function initializePanelSizeInfluence() {
|
|
|
|
|
|
// 初始化影响关系数据
|
|
|
|
|
|
['left', 'right', 'top', 'bottom','center'].forEach(position => {
|
|
|
|
|
|
panelSizeInfluence.influence[position].value = []
|
|
|
|
|
|
panelSizeInfluence.influencedBy[position].value = []
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 使用LayoutCoordinator初始化影响关系
|
|
|
|
|
|
const influenceData = layoutCoordinator.initializePanelSizeInfluence()
|
|
|
|
|
|
|
|
|
|
|
|
// 应用影响关系数据
|
|
|
|
|
|
if (influenceData && influenceData.influence) {
|
|
|
|
|
|
['left', 'right', 'top', 'bottom','center'].forEach(position => {
|
|
|
|
|
|
if (influenceData.influence[position]) {
|
|
|
|
|
|
panelSizeInfluence.influence[position].value = influenceData.influence[position]
|
|
|
|
|
|
}
|
|
|
|
|
|
if (influenceData.influencedBy && influenceData.influencedBy[position]) {
|
|
|
|
|
|
panelSizeInfluence.influencedBy[position].value = influenceData.influencedBy[position]
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理面板大小变化对其他面板的影响
|
|
|
|
|
|
function handlePanelSizeInfluence(position, externalContainer) {
|
|
|
|
|
|
// 确保position是有效的面板位置
|
|
|
|
|
|
if (!['left', 'right', 'top', 'bottom', 'center'].includes(position)) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 准备面板数据对象 - 包含所有位置的面板数据
|
|
|
|
|
|
const panelData = {
|
|
|
|
|
|
left: leftPanelArea.value,
|
|
|
|
|
|
right: rightPanelArea.value,
|
|
|
|
|
|
top: topPanelArea.value,
|
|
|
|
|
|
bottom: bottomPanelArea.value,
|
|
|
|
|
|
center: centerPanelArea.value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (!externalContainer) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 调用布局协调器处理面板大小影响
|
|
|
|
|
|
const updatedPanels = layoutCoordinator.handlePanelSizeInfluence(
|
|
|
|
|
|
position,
|
|
|
|
|
|
{
|
|
|
|
|
|
influence: panelSizeInfluence.influence,
|
|
|
|
|
|
influencedBy: panelSizeInfluence.influencedBy
|
|
|
|
|
|
},
|
|
|
|
|
|
panelData,
|
|
|
|
|
|
externalContainer
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新面板数据(包括面板区域本身的尺寸和内部的panels数组)
|
|
|
|
|
|
// 为每个位置定义对应的面板区域变量
|
|
|
|
|
|
const panelAreaMap = {
|
|
|
|
|
|
left: leftPanelArea.value,
|
|
|
|
|
|
right: rightPanelArea.value,
|
|
|
|
|
|
top: topPanelArea.value,
|
|
|
|
|
|
bottom: bottomPanelArea.value,
|
|
|
|
|
|
center: centerPanelArea.value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const positions = ['left', 'right', 'top', 'bottom', 'center'];
|
|
|
|
|
|
positions.forEach(pos => {
|
|
|
|
|
|
if (updatedPanels && updatedPanels[pos]) {
|
|
|
|
|
|
const panelArea = panelAreaMap[pos];
|
|
|
|
|
|
|
|
|
|
|
|
// 首先更新面板区域本身的宽高属性(如果有)
|
|
|
|
|
|
if (updatedPanels[pos].width !== undefined) {
|
|
|
|
|
|
panelArea.width = updatedPanels[pos].width;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (updatedPanels[pos].height !== undefined) {
|
|
|
|
|
|
panelArea.height = updatedPanels[pos].height;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新panels数组
|
|
|
|
|
|
if (updatedPanels[pos].panels) {
|
|
|
|
|
|
panelArea.panels = updatedPanels[pos].panels;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新比例数据
|
|
|
|
|
|
if (updatedPanels[pos].widthRatios) {
|
|
|
|
|
|
panelArea.widthRatios = updatedPanels[pos].widthRatios;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (updatedPanels[pos].heightRatios) {
|
|
|
|
|
|
panelArea.heightRatios = updatedPanels[pos].heightRatios;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 显式调用updatePanelsSize来更新所有面板区域的子面板尺寸,确保子面板大小随面板区域变化
|
|
|
|
|
|
if (leftPanelArea.value && leftPanelArea.value.panels && leftPanelArea.value.panels.length > 0) {
|
|
|
|
|
|
updatePanelsSize('left', leftPanelArea.value, externalContainer);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (rightPanelArea.value && rightPanelArea.value.panels && rightPanelArea.value.panels.length > 0) {
|
|
|
|
|
|
updatePanelsSize('right', rightPanelArea.value, externalContainer);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (topPanelArea.value && topPanelArea.value.panels && topPanelArea.value.panels.length > 0) {
|
|
|
|
|
|
updatePanelsSize('top', topPanelArea.value, externalContainer);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (bottomPanelArea.value && bottomPanelArea.value.panels && bottomPanelArea.value.panels.length > 0) {
|
|
|
|
|
|
updatePanelsSize('bottom', bottomPanelArea.value, externalContainer);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (centerPanelArea.value && centerPanelArea.value.panels && centerPanelArea.value.panels.length > 0) {
|
|
|
|
|
|
updatePanelsSize('center', centerPanelArea.value, externalContainer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新面板尺寸
|
|
|
|
|
|
function updatePanelsSize(position, panelArea, container, minSizes = { panelWidth: 150, panelHeight: 100 }) {
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保面板区域存在且有面板
|
|
|
|
|
|
if (!panelArea || !panelArea.panels || panelArea.panels.length === 0) return
|
|
|
|
|
|
|
|
|
|
|
|
// 获取容器尺寸
|
|
|
|
|
|
const containerWidth = container.clientWidth;
|
|
|
|
|
|
const containerHeight = container.clientHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// 准备面板区域数据,用于计算可用空间
|
|
|
|
|
|
const panelAreas = {
|
|
|
|
|
|
top: topPanelArea.value,
|
|
|
|
|
|
bottom: bottomPanelArea.value,
|
|
|
|
|
|
left: leftPanelArea.value,
|
|
|
|
|
|
right: rightPanelArea.value,
|
|
|
|
|
|
center: centerPanelArea.value
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 处理不同位置的面板尺寸更新
|
|
|
|
|
|
if (position === 'top' || position === 'bottom') {
|
|
|
|
|
|
// 顶部和底部面板 - 水平排列
|
|
|
|
|
|
// 更新面板区域的完整宽高信息
|
|
|
|
|
|
panelArea.width = layoutCoordinator.calculateAvailableWidth(
|
|
|
|
|
|
position,
|
|
|
|
|
|
panelSizeInfluence,
|
|
|
|
|
|
panelAreas,
|
|
|
|
|
|
containerWidth,
|
|
|
|
|
|
minSizes
|
|
|
|
|
|
);
|
|
|
|
|
|
// 使用当前面板区域的实际高度(已通过分割条调整后的高度)
|
|
|
|
|
|
panelArea.height = position === 'top' ? topPanelArea.value.height : bottomPanelArea.value.height;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保有宽度比例数组,并且长度与面板数量匹配
|
|
|
|
|
|
if (!panelArea.widthRatios || panelArea.widthRatios.length !== panelArea.panels.length) {
|
|
|
|
|
|
panelArea.widthRatios = resetPanelsSizeRatios(panelArea.panels.length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用面板宽度比例
|
|
|
|
|
|
panelArea.panels.forEach((panel, index) => {
|
|
|
|
|
|
// 计算面板宽度,确保不小于最小宽度
|
|
|
|
|
|
const calculatedWidth = panelArea.width * panelArea.widthRatios[index]
|
|
|
|
|
|
panel.width = Math.max(minSizes.panelWidth || 150, calculatedWidth)
|
|
|
|
|
|
panel.height = panelArea.height
|
|
|
|
|
|
})
|
|
|
|
|
|
} else if (position === 'left' || position === 'right') {
|
|
|
|
|
|
// 左侧和右侧面板 - 垂直排列
|
|
|
|
|
|
// 计算左侧/右侧面板区域的可用高度(考虑顶底面板占用的空间)
|
|
|
|
|
|
const availableHeight = layoutCoordinator.calculateAvailableHeight(
|
|
|
|
|
|
position,
|
|
|
|
|
|
panelSizeInfluence,
|
|
|
|
|
|
panelAreas,
|
|
|
|
|
|
containerHeight,
|
|
|
|
|
|
minSizes
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新面板区域的完整宽高信息
|
|
|
|
|
|
panelArea.height = availableHeight; // 设置面板区域高度为可用高度
|
|
|
|
|
|
panelArea.width = position === 'left' ? leftPanelArea.value.width : rightPanelArea.value.width; // 保持原有宽度
|
|
|
|
|
|
|
|
|
|
|
|
// 确保有高度比例数组,并且长度与面板数量匹配
|
|
|
|
|
|
if (!panelArea.heightRatios || panelArea.heightRatios.length !== panelArea.panels.length) {
|
|
|
|
|
|
panelArea.heightRatios = resetPanelsSizeRatios(panelArea.panels.length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用面板高度比例
|
|
|
|
|
|
panelArea.panels.forEach((panel, index) => {
|
|
|
|
|
|
// 计算面板高度,确保不小于最小高度
|
|
|
|
|
|
const calculatedHeight = panelArea.height * panelArea.heightRatios[index]
|
|
|
|
|
|
panel.height = Math.max(minSizes.panelHeight || 100, calculatedHeight)
|
|
|
|
|
|
panel.width = panelArea.width
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
// 新增中心面板的处理逻辑
|
|
|
|
|
|
else if (position === 'center') {
|
|
|
|
|
|
// 中心面板的尺寸计算(考虑其他面板占用的空间)
|
|
|
|
|
|
const availableWidth = layoutCoordinator.calculateAvailableWidth(
|
|
|
|
|
|
position,
|
|
|
|
|
|
panelSizeInfluence,
|
|
|
|
|
|
panelAreas,
|
|
|
|
|
|
containerWidth,
|
|
|
|
|
|
minSizes
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const availableHeight = layoutCoordinator.calculateAvailableHeight(
|
|
|
|
|
|
position,
|
|
|
|
|
|
panelSizeInfluence,
|
|
|
|
|
|
panelAreas,
|
|
|
|
|
|
containerHeight,
|
|
|
|
|
|
minSizes
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新面板区域的宽高信息
|
|
|
|
|
|
panelArea.width = availableWidth;
|
|
|
|
|
|
panelArea.height = availableHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保有宽高比例数组,并且长度与面板数量匹配
|
|
|
|
|
|
if (!panelArea.widthRatios || panelArea.widthRatios.length !== panelArea.panels.length) {
|
|
|
|
|
|
panelArea.widthRatios = resetPanelsSizeRatios(panelArea.panels.length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!panelArea.heightRatios || panelArea.heightRatios.length !== panelArea.panels.length) {
|
|
|
|
|
|
panelArea.heightRatios = resetPanelsSizeRatios(panelArea.panels.length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用面板宽高(中心面板通常是标签页形式,所有面板共享相同的宽高)
|
|
|
|
|
|
panelArea.panels.forEach((panel, index) => {
|
|
|
|
|
|
panel.width = panelArea.width;
|
|
|
|
|
|
panel.height = panelArea.height;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用更新后的面板数据,触发响应式更新
|
|
|
|
|
|
if (position === 'top') {
|
|
|
|
|
|
topPanelArea.value = { ...panelArea };
|
|
|
|
|
|
} else if (position === 'bottom') {
|
|
|
|
|
|
bottomPanelArea.value = { ...panelArea };
|
|
|
|
|
|
} else if (position === 'left') {
|
|
|
|
|
|
leftPanelArea.value = { ...panelArea };
|
|
|
|
|
|
} else if (position === 'right') {
|
|
|
|
|
|
rightPanelArea.value = { ...panelArea };
|
|
|
|
|
|
} else if (position === 'center') {
|
|
|
|
|
|
centerPanelArea.value = { ...panelArea };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 包装LayoutCoordinator的adjustAdjacentPanels方法
|
|
|
|
|
|
function adjustAdjacentPanels(position, panelIndex, delta, originalSizes, availableWidth) {
|
|
|
|
|
|
const panelArea = position === 'top' ? topPanelArea.value : bottomPanelArea.value
|
|
|
|
|
|
const panels = panelArea.panels
|
|
|
|
|
|
|
|
|
|
|
|
const updatedPanels = layoutCoordinator.adjustAdjacentPanels(
|
|
|
|
|
|
panels, panelIndex, delta, originalSizes, availableWidth
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if (updatedPanels !== panels) {
|
|
|
|
|
|
panelArea.panels = updatedPanels
|
|
|
|
|
|
return updatedPanels
|
|
|
|
|
|
}
|
|
|
|
|
|
return panels
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 包装LayoutCoordinator的adjustAdjacentPanelsVertical方法
|
|
|
|
|
|
function adjustAdjacentPanelsVertical(position, panelIndex, delta, originalSizes, availableHeight) {
|
|
|
|
|
|
const panelArea = position === 'left' ? leftPanelArea.value : rightPanelArea.value
|
|
|
|
|
|
const panels = panelArea.panels
|
|
|
|
|
|
|
|
|
|
|
|
const updatedPanels = layoutCoordinator.adjustAdjacentPanelsVertical(
|
|
|
|
|
|
panels, panelIndex, delta, originalSizes, availableHeight
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if (updatedPanels !== panels) {
|
|
|
|
|
|
panelArea.panels = updatedPanels
|
|
|
|
|
|
return updatedPanels
|
|
|
|
|
|
}
|
|
|
|
|
|
return panels
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 包装LayoutCoordinator的adjustRegionSize方法
|
|
|
|
|
|
function adjustRegionSize(target, delta, container = null) {
|
|
|
|
|
|
const panelAreas = {
|
|
|
|
|
|
top: topPanelArea.value,
|
|
|
|
|
|
bottom: bottomPanelArea.value,
|
|
|
|
|
|
left: leftPanelArea.value,
|
|
|
|
|
|
right: rightPanelArea.value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let containerHeight = null
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
containerHeight = container.clientHeight
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let newSize
|
|
|
|
|
|
switch (target) {
|
|
|
|
|
|
case 'left':
|
|
|
|
|
|
newSize = layoutCoordinator.adjustRegionSize('left', panelAreas.left.width, delta)
|
|
|
|
|
|
panelAreas.left.width = newSize
|
2025-10-20 11:06:42 +08:00
|
|
|
|
|
2025-10-20 09:04:09 +08:00
|
|
|
|
break
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
newSize = layoutCoordinator.adjustRegionSize('right', panelAreas.right.width, -delta)
|
|
|
|
|
|
panelAreas.right.width = newSize
|
|
|
|
|
|
break
|
|
|
|
|
|
case 'top':
|
|
|
|
|
|
newSize = layoutCoordinator.adjustRegionSize('top', panelAreas.top.height, delta, panelAreas, containerHeight)
|
|
|
|
|
|
panelAreas.top.height = newSize
|
2025-10-20 10:59:56 +08:00
|
|
|
|
|
2025-10-20 09:04:09 +08:00
|
|
|
|
break
|
|
|
|
|
|
case 'bottom':
|
|
|
|
|
|
newSize = layoutCoordinator.adjustRegionSize('bottom', panelAreas.bottom.height, -delta, panelAreas, containerHeight)
|
|
|
|
|
|
panelAreas.bottom.height = newSize
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
|
|
|
// 面板数据
|
|
|
|
|
|
leftPanelArea,
|
|
|
|
|
|
rightPanelArea,
|
|
|
|
|
|
topPanelArea,
|
|
|
|
|
|
bottomPanelArea,
|
|
|
|
|
|
centerPanelArea,
|
|
|
|
|
|
floatingWindows,
|
|
|
|
|
|
minimizedWindows,
|
|
|
|
|
|
closedPanelHistory,
|
|
|
|
|
|
|
|
|
|
|
|
// 计算属性
|
|
|
|
|
|
leftPanels,
|
|
|
|
|
|
rightPanels,
|
|
|
|
|
|
topPanels,
|
|
|
|
|
|
bottomPanels,
|
|
|
|
|
|
centerPanels,
|
|
|
|
|
|
leftPanelWidth,
|
|
|
|
|
|
rightPanelWidth,
|
|
|
|
|
|
topPanelHeight,
|
|
|
|
|
|
bottomPanelHeight,
|
|
|
|
|
|
|
|
|
|
|
|
// 状态
|
|
|
|
|
|
activeCenterTab,
|
|
|
|
|
|
isResizing,
|
|
|
|
|
|
resizeTarget,
|
|
|
|
|
|
resizeStartPos,
|
|
|
|
|
|
resizeContext,
|
|
|
|
|
|
dragState,
|
|
|
|
|
|
dockPreview,
|
|
|
|
|
|
contextMenu,
|
|
|
|
|
|
panelSizeInfluence,
|
|
|
|
|
|
|
|
|
|
|
|
// 方法
|
|
|
|
|
|
getPanelPositionById,
|
|
|
|
|
|
addPanel,
|
|
|
|
|
|
closePanel,
|
|
|
|
|
|
floatPanel,
|
|
|
|
|
|
dockPanel,
|
|
|
|
|
|
addFloatingWindow,
|
|
|
|
|
|
closeFloatingWindow,
|
|
|
|
|
|
minimizeFloatingWindow,
|
|
|
|
|
|
restoreMinimizedWindow,
|
|
|
|
|
|
maximizeFloatingWindow,
|
|
|
|
|
|
toggleCollapse,
|
|
|
|
|
|
hideContextMenu,
|
|
|
|
|
|
initializePanels,
|
|
|
|
|
|
resetLayout,
|
|
|
|
|
|
resetPanelsSizeRatios,
|
|
|
|
|
|
initializePanelSizeInfluence,
|
2025-10-20 10:59:56 +08:00
|
|
|
|
refreshPanelSizes,
|
2025-10-20 09:04:09 +08:00
|
|
|
|
updatePanelsSize,
|
|
|
|
|
|
handlePanelSizeInfluence,
|
|
|
|
|
|
adjustAdjacentPanels,
|
|
|
|
|
|
adjustAdjacentPanelsVertical,
|
|
|
|
|
|
adjustRegionSize
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|