增加重算列表

This commit is contained in:
JoyD
2025-10-27 22:03:58 +08:00
parent 88c90a3afc
commit ba9a9e99b7
4 changed files with 2654 additions and 19 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -303,6 +303,7 @@ const container = ref(null);
// 初始化Pinia store // 初始化Pinia store
const store = useDockPanelStore(); const store = useDockPanelStore();
// 基于 watch 的受影响重算已移除;改为在 store 的增删面板操作中按影响列表统一触发。
// 定义布局应用完成后的回调函数,用于刷新面板大小 // 定义布局应用完成后的回调函数,用于刷新面板大小
function handleLayoutApplied() { function handleLayoutApplied() {
// 确保容器存在后调用refreshPanelSizes并传递容器元素 // 确保容器存在后调用refreshPanelSizes并传递容器元素
@@ -742,8 +743,8 @@ function handleKeyDown(event) {
// 初始化 // 初始化
onMounted(() => { onMounted(() => {
// 初始化容器引用 // 初始化容器引用
const container = document.querySelector('.dock-panel-container'); container.value = document.querySelector('.dock-panel-container');
layoutManager.setContainer(container); layoutManager.setContainer(container.value);
// 检查URL参数是否有强制重置布局的标记 // 检查URL参数是否有强制重置布局的标记
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
@@ -778,6 +779,9 @@ onMounted(() => {
// 初始化面板大小影响关系 // 初始化面板大小影响关系
initializePanelSizeInfluence(); initializePanelSizeInfluence();
// 初始化边界(确保下区宽度按左右面板扣减)
store.handlePanelSizeInfluence('bottom', container.value);
// 添加事件监听 // 添加事件监听
document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp); document.addEventListener('mouseup', handleMouseUp);

View File

@@ -339,12 +339,32 @@ export class LayoutCoordinator {
} }
// 计算底部面板边界 - 底部面板通常位于最下方,只受容器高度限制 // 计算底部面板边界 - 底部面板通常位于最下方,只受容器高度限制
// 注意:为避免依赖未计算的左右宽度,这里的底部边界设置被延后至左右边界计算之后
if (panelAreas.bottom && panelAreas.bottom.panels && panelAreas.bottom.panels.length > 0) { if (panelAreas.bottom && panelAreas.bottom.panels && panelAreas.bottom.panels.length > 0) {
const bottomInfluencedBy = influenceData.influencedBy.bottom || [];
const bottomHeight = panelAreas.bottom.height || 200;
let bottomX = 0;
let bottomWidth = containerWidth;
bottomInfluencedBy.forEach(item => {
if (item.influence && item.property === 'width') {
const pos = item.position;
const area = panelAreas[pos];
const w = (this.panelBounds[pos]?.width ?? area?.width ?? 0);
if (w > 0) {
bottomWidth -= w;
if (pos === 'left') {
bottomX += w;
}
}
}
});
this.panelBounds.bottom = { this.panelBounds.bottom = {
x: 0, x: Math.max(0, bottomX),
y: containerHeight - (panelAreas.bottom.height || 200), y: containerHeight - bottomHeight,
width: containerWidth, width: Math.max(0, bottomWidth),
height: panelAreas.bottom.height || 200 height: bottomHeight
}; };
} }

View File

@@ -131,6 +131,8 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
center: ref([]) center: ref([])
} }
} }
// 全局:待重算的区域队列(去重)
const pendingRecompute = new Set();
// 根据面板ID获取面板位置 // 根据面板ID获取面板位置
function getPanelPositionById(panelId) { function getPanelPositionById(panelId) {
@@ -193,57 +195,102 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
// 获取全局容器元素只查询一次DOM // 获取全局容器元素只查询一次DOM
const container = document.querySelector('.dock-panel-container'); const container = document.querySelector('.dock-panel-container');
// 辅助:获取区域对象
function getAreaByPos(pos) {
return pos === 'left' ? leftPanelArea.value
: pos === 'right' ? rightPanelArea.value
: pos === 'top' ? topPanelArea.value
: pos === 'bottom' ? bottomPanelArea.value
: pos === 'center' ? centerPanelArea.value
: null;
}
// 辅助:获取受影响的区域列表
function impactedBy(position) {
const map = panelSizeInfluence.value?.influencedBy || {};
return Object.keys(map).filter(pos => {
const arr = map[pos] || [];
return arr.some(item => item.influence && item.position === position);
});
}
// 队列入列
function enqueueRecompute(...positions) {
positions.filter(Boolean).forEach(p => pendingRecompute.add(p));
}
// 处理队列
function processRecomputeQueue(externalContainer, sizes = minSizes) {
if (!externalContainer) return;
let guard = 0;
while (pendingRecompute.size > 0 && guard < 20) {
guard++;
const iterator = pendingRecompute.values();
const current = iterator.next().value;
pendingRecompute.delete(current);
// 先整体更新边界
handlePanelSizeInfluence(current, externalContainer);
// 更新当前区域的子面板尺寸
const currentArea = getAreaByPos(current);
if (currentArea) {
updatePanelsSize(current, currentArea, externalContainer, sizes);
}
// 将受影响区域入队并更新其子面板尺寸
const impacted = impactedBy(current);
impacted.forEach(pos => {
const area = getAreaByPos(pos);
if (area) {
updatePanelsSize(pos, area, externalContainer, sizes);
pendingRecompute.add(pos);
}
});
}
}
switch (panel.position) { switch (panel.position) {
case 'left': case 'left':
const isLeftFirst = leftPanels.value.length === 0 const isLeftFirst = leftPanels.value.length === 0
leftPanelArea.value.panels.push(panelData) leftPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('left') resetPanelsSizeRatios('left')
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) { if (container) {
updatePanelsSize('left', leftPanelArea.value, container, minSizes); updatePanelsSize('left', leftPanelArea.value, container, minSizes);
} }
if (isLeftFirst) { if (isLeftFirst) {
// 触发左侧面板的尺寸影响处理,传入容器引用避免重复查询 enqueueRecompute('left');
handlePanelSizeInfluence('left', container) processRecomputeQueue(container, minSizes);
} }
break break
case 'right': case 'right':
const isRightFirst = rightPanels.value.length === 0 const isRightFirst = rightPanels.value.length === 0
rightPanelArea.value.panels.push(panelData) rightPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('right') resetPanelsSizeRatios('right')
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) { if (container) {
updatePanelsSize('right', rightPanelArea.value, container, minSizes); updatePanelsSize('right', rightPanelArea.value, container, minSizes);
} }
if (isRightFirst) { if (isRightFirst) {
// 触发右侧面板的尺寸影响处理,传入容器引用避免重复查询 enqueueRecompute('right');
handlePanelSizeInfluence('right', container) processRecomputeQueue(container, minSizes);
} }
break break
case 'top': case 'top':
const isTopFirst = topPanels.value.length === 0 const isTopFirst = topPanels.value.length === 0
topPanelArea.value.panels.push(panelData) topPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('top') resetPanelsSizeRatios('top')
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) { if (container) {
updatePanelsSize('top', topPanelArea.value, container, minSizes); updatePanelsSize('top', topPanelArea.value, container, minSizes);
} }
if (isTopFirst) { if (isTopFirst) {
// 触发顶部面板的尺寸影响处理,传入容器引用避免重复查询 enqueueRecompute('top');
handlePanelSizeInfluence('top', container) processRecomputeQueue(container, minSizes);
} }
break break
case 'bottom': case 'bottom':
const isBottomFirst = bottomPanels.value.length === 0 const isBottomFirst = bottomPanels.value.length === 0
bottomPanelArea.value.panels.push(panelData) bottomPanelArea.value.panels.push(panelData)
resetPanelsSizeRatios('bottom') resetPanelsSizeRatios('bottom')
// 使用全局容器元素更新面板尺寸和绝对位置
if (container) { if (container) {
updatePanelsSize('bottom', bottomPanelArea.value, container, minSizes); updatePanelsSize('bottom', bottomPanelArea.value, container, minSizes);
} }
if (isBottomFirst) { if (isBottomFirst) {
// 触发底部面板的尺寸影响处理,传入容器引用避免重复查询 enqueueRecompute('bottom');
handlePanelSizeInfluence('bottom', container) processRecomputeQueue(container, minSizes);
} }
break break
case 'center': case 'center':
@@ -363,7 +410,9 @@ export const useDockPanelStore = defineStore('dockPanel', () => {
} }
// 如果面板区域变为空,触发尺寸影响处理以更新其他区域 // 如果面板区域变为空,触发尺寸影响处理以更新其他区域
if (panels.length === 0) { if (panels.length === 0) {
handlePanelSizeInfluence(position, container); // 入队并批量重算,直到队列为空
enqueueRecompute(position);
processRecomputeQueue(container, { panelWidth: 150, panelHeight: 100 });
} }
// 处理中心面板的特殊逻辑 // 处理中心面板的特殊逻辑