增加重算列表
This commit is contained in:
2562
AutoRobot/Windows/Robot/Web/package-lock.json
generated
Normal file
2562
AutoRobot/Windows/Robot/Web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理中心面板的特殊逻辑
|
// 处理中心面板的特殊逻辑
|
||||||
|
|||||||
Reference in New Issue
Block a user