From a378ca98f4fcd72ce090c52db5f67801eedbe7f7 Mon Sep 17 00:00:00 2001
From: Baobhan Sith <80159437+Heavrnl@users.noreply.github.com>
Date: Mon, 21 Apr 2025 21:39:26 +0800
Subject: [PATCH] update
---
.../src/components/LayoutConfigurator.vue | 330 ++++++++----------
.../src/components/LayoutRenderer.vue | 25 +-
packages/frontend/src/locales/zh.json | 2 +-
packages/frontend/src/stores/layout.store.ts | 130 +++----
4 files changed, 217 insertions(+), 270 deletions(-)
diff --git a/packages/frontend/src/components/LayoutConfigurator.vue b/packages/frontend/src/components/LayoutConfigurator.vue
index 52a2f0d..dee0d0b 100644
--- a/packages/frontend/src/components/LayoutConfigurator.vue
+++ b/packages/frontend/src/components/LayoutConfigurator.vue
@@ -1,5 +1,5 @@
@@ -404,7 +358,7 @@ const handleAvailablePaneDragEnd = (event: any) => {
@@ -526,8 +480,8 @@ const handleAvailablePaneDragEnd = (event: any) => {
diff --git a/packages/frontend/src/components/LayoutRenderer.vue b/packages/frontend/src/components/LayoutRenderer.vue
index 47ad2f1..eb8df03 100644
--- a/packages/frontend/src/components/LayoutRenderer.vue
+++ b/packages/frontend/src/components/LayoutRenderer.vue
@@ -546,9 +546,9 @@ const getIconClasses = (paneName: PaneName): string[] => {
@@ -559,16 +559,23 @@ const getIconClasses = (paneName: PaneName): string[] => {
文件管理器需要活动会话
+
+
+
+
diff --git a/packages/frontend/src/locales/zh.json b/packages/frontend/src/locales/zh.json
index f15465d..e5532ae 100644
--- a/packages/frontend/src/locales/zh.json
+++ b/packages/frontend/src/locales/zh.json
@@ -675,7 +675,7 @@
"remove": "移除"
},
"layoutConfigurator": {
- "title": "配置工作区布局",
+ "title": "布局管理器",
"availablePanes": "可用面板",
"layoutPreview": "主布局预览(拖拽到此处)",
"resetDefault": "恢复默认",
diff --git a/packages/frontend/src/stores/layout.store.ts b/packages/frontend/src/stores/layout.store.ts
index dc21740..1f03baf 100644
--- a/packages/frontend/src/stores/layout.store.ts
+++ b/packages/frontend/src/stores/layout.store.ts
@@ -257,35 +257,54 @@ export const useLayoutStore = defineStore('layout', () => {
}
}
+ // --- Helper for debounced persistence ---
+ // We still might want debounce if updates happen rapidly outside the configurator (e.g., pane resize)
+ let persistLayoutDebounceTimer: ReturnType | null = null;
+ const debouncedPersistLayout = () => {
+ if (persistLayoutDebounceTimer) clearTimeout(persistLayoutDebounceTimer);
+ persistLayoutDebounceTimer = setTimeout(async () => { // Make async
+ await persistLayoutTree(); // Await the async persist function
+ }, 1000);
+ };
+
// 更新整个布局树(通常由配置器保存时调用)
- function updateLayoutTree(newTree: LayoutNode | null) { // <-- Allow null
- // 可选:添加验证逻辑 (如果 newTree 不是 null)
+ async function updateLayoutTree(newTree: LayoutNode | null) { // Make async
+ // 可选:添加验证逻辑
if (newTree) {
- // TODO: Add validation for LayoutNode structure if needed
+ // TODO: Add validation
+ }
+ // Check if the tree actually changed before updating and persisting
+ if (JSON.stringify(newTree) !== JSON.stringify(layoutTree.value)) {
+ layoutTree.value = newTree;
+ console.log('[Layout Store] 布局树已更新。 New tree:', newTree);
+ // --- Directly call persist ---
+ await persistLayoutTree(); // Await persistence directly
+ } else {
+ console.log('[Layout Store] updateLayoutTree called but tree is unchanged.');
}
- layoutTree.value = newTree; // Assign null or the new tree
- console.log('[Layout Store] 布局树已更新。 New tree:', newTree);
- // 保存将在 watch 中自动触发
}
// 新增:更新侧栏配置
- function updateSidebarPanes(newPanes: { left: PaneName[], right: PaneName[] }) {
+ async function updateSidebarPanes(newPanes: { left: PaneName[], right: PaneName[] }) { // Make async
// --- Add Validation ---
if (newPanes &&
isValidPaneNameArray(newPanes.left, allPossiblePanes.value) &&
isValidPaneNameArray(newPanes.right, allPossiblePanes.value))
{
- sidebarPanes.value = newPanes as { left: PaneName[], right: PaneName[] }; // Assign validated data
- // Log the value immediately after update
- console.log('[Layout Store] 侧栏配置已通过验证并更新。 New sidebarPanes value:', JSON.parse(JSON.stringify(sidebarPanes.value)));
- // 保存将在 watch 中自动触发
+ // Check if panes actually changed
+ if (JSON.stringify(newPanes) !== JSON.stringify(sidebarPanes.value)) {
+ sidebarPanes.value = newPanes as { left: PaneName[], right: PaneName[] }; // Assign validated data
+ console.log('[Layout Store] 侧栏配置已通过验证并更新。 New sidebarPanes value:', JSON.parse(JSON.stringify(sidebarPanes.value)));
+ // --- Directly call persist ---
+ await persistSidebarPanes(); // Await persistence directly
+ } else {
+ console.log('[Layout Store] updateSidebarPanes called but panes are unchanged.');
+ }
} else {
console.error('[Layout Store] updateSidebarPanes 接收到无效的侧栏配置数据,未更新状态:', newPanes);
// 可选:抛出错误或通知用户
}
}
-
-
// 递归查找并更新节点大小
function findAndUpdateNodeSize(node: LayoutNode | null, nodeId: string, childrenSizes: { index: number; size: number }[]): LayoutNode | null {
if (!node) return null;
@@ -313,18 +332,18 @@ export const useLayoutStore = defineStore('layout', () => {
// 新增 Action: 更新特定容器节点的子节点大小
function updateNodeSizes(nodeId: string, childrenSizes: { index: number; size: number }[]) {
console.log(`[Layout Store] 请求更新节点 ${nodeId} 的子节点大小:`, childrenSizes);
+ const originalJson = JSON.stringify(layoutTree.value); // Store original state
const updatedTree = findAndUpdateNodeSize(layoutTree.value, nodeId, childrenSizes);
- if (updatedTree && updatedTree !== layoutTree.value) {
- // 只有在树实际发生变化时才更新 ref 以触发 watch
+
+ if (updatedTree && JSON.stringify(updatedTree) !== originalJson) { // Compare with original JSON
layoutTree.value = updatedTree;
- console.log(`[Layout Store] 节点 ${nodeId} 的子节点大小已更新。`);
- } else if (updatedTree === layoutTree.value) {
- console.log(`[Layout Store] 未找到节点 ${nodeId} 或大小未改变。`);
+ console.log(`[Layout Store] 节点 ${nodeId} 的子节点大小已更新,触发防抖保存。`);
+ // --- Use debounced persist for resize ---
+ debouncedPersistLayout();
} else {
- console.error(`[Layout Store] 更新节点 ${nodeId} 大小后得到无效的树结构。`);
+ console.log(`[Layout Store] 未找到节点 ${nodeId} 或大小未改变。`);
}
}
-
// 新增 Action: 切换布局(Header/Footer)的可见性
function toggleLayoutVisibility() {
isLayoutVisible.value = !isLayoutVisible.value;
@@ -383,27 +402,19 @@ export const useLayoutStore = defineStore('layout', () => {
}
// 新增 Action: 将当前主布局树持久化到后端和 localStorage
- async function persistLayoutTree() {
- if (!layoutTree.value) {
- console.warn('[Layout Store] persistLayoutTree: layoutTree is null, cannot persist.');
- // TODO: 考虑是否需要删除后端设置或发送空布局
- // await apiClient.put('/settings/layout', null); // 发送 null 或空对象
- localStorage.removeItem(LAYOUT_STORAGE_KEY);
- return;
- }
- const layoutToSave = JSON.stringify(layoutTree.value);
- // 1. 保存到后端
+ async function persistLayoutTree() { // Make async
+ // ... (existing try/catch logic for backend and localStorage) ...
+ // Ensure apiClient calls are awaited if they return promises
try {
console.log('[Layout Store] Attempting to save main layout to backend...');
- // Send the layoutTree value directly (which can be null)
- await apiClient.put('/settings/layout', layoutTree.value);
+ await apiClient.put('/settings/layout', layoutTree.value); // await
console.log('[Layout Store] 主布局已成功保存到后端 (sent value):', layoutTree.value);
} catch (error) {
console.error('[Layout Store] 保存主布局到后端失败:', error);
}
- // 2. 保存到 localStorage
+ // localStorage is synchronous
try {
- // If layoutTree.value is null, layoutToSave will be 'null'
+ const layoutToSave = JSON.stringify(layoutTree.value);
localStorage.setItem(LAYOUT_STORAGE_KEY, layoutToSave);
console.log('[Layout Store] 主布局已自动保存到 localStorage (saved value):', layoutToSave);
} catch (error) {
@@ -412,18 +423,18 @@ export const useLayoutStore = defineStore('layout', () => {
}
// 新增 Action: 将当前侧栏配置持久化到后端和 localStorage
- async function persistSidebarPanes() {
- const sidebarsToSave = JSON.stringify(sidebarPanes.value);
- // 1. 保存到后端 (假设 API 端点为 /settings/sidebar)
- try {
+ async function persistSidebarPanes() { // Make async
+ // ... (existing try/catch logic for backend and localStorage) ...
+ try {
console.log('[Layout Store] Attempting to save sidebar config to backend...');
- await apiClient.put('/settings/sidebar', sidebarPanes.value); // 新 API 端点
+ await apiClient.put('/settings/sidebar', sidebarPanes.value); // await
console.log('[Layout Store] 侧栏配置已成功保存到后端。');
} catch (error) {
console.error('[Layout Store] 保存侧栏配置到后端失败:', error);
}
- // 2. 保存到 localStorage
+ // localStorage is synchronous
try {
+ const sidebarsToSave = JSON.stringify(sidebarPanes.value);
localStorage.setItem(SIDEBAR_STORAGE_KEY, sidebarsToSave);
console.log('[Layout Store] 侧栏配置已自动保存到 localStorage。');
} catch (error) {
@@ -432,42 +443,9 @@ export const useLayoutStore = defineStore('layout', () => {
}
- // --- 持久化 Watchers ---
- let layoutDebounceTimer: ReturnType | null = null;
- let sidebarDebounceTimer: ReturnType | null = null;
-
- // 监听主布局树变化
- watch(
- layoutTree,
- (newTree, oldTree) => {
- if (oldTree === undefined) return; // 避免初始化触发
- if (JSON.stringify(newTree) !== JSON.stringify(oldTree)) {
- console.log('[Layout Store] Main layout tree changed, scheduling persistence...');
- if (layoutDebounceTimer) clearTimeout(layoutDebounceTimer);
- layoutDebounceTimer = setTimeout(() => {
- persistLayoutTree();
- }, 1000); // 1秒防抖
- }
- },
- { deep: true }
- );
-
- // 监听侧栏配置变化
- watch(
- sidebarPanes,
- (newPanes, oldPanes) => {
- if (oldPanes === undefined) return; // 避免初始化触发
- if (JSON.stringify(newPanes) !== JSON.stringify(oldPanes)) {
- console.log('[Layout Store] Sidebar panes changed, scheduling persistence...');
- if (sidebarDebounceTimer) clearTimeout(sidebarDebounceTimer);
- sidebarDebounceTimer = setTimeout(() => {
- persistSidebarPanes();
- }, 1000); // 1秒防抖
- }
- },
- { deep: true }
- );
-
+ // --- REMOVE the old watchers that called persist ---
+ // watch(layoutTree, ...); // REMOVE THIS
+ // watch(sidebarPanes, ...); // REMOVE THIS
// --- 初始化 ---
// Store 创建时自动初始化布局和侧栏
initializeLayout();