update
This commit is contained in:
@@ -333,12 +333,19 @@ const sidebarProps = computed(() => (paneName: PaneName | null, side: 'left' | '
|
||||
// --- Methods ---
|
||||
// 处理 Splitpanes 大小调整事件
|
||||
const handlePaneResize = (eventData: { panes: Array<{ size: number; [key: string]: any }> }) => {
|
||||
console.log('Splitpanes resized event object:', eventData); // 打印整个事件对象
|
||||
// +++ 添加更详细的日志 +++
|
||||
// +++ Log the entire layoutNode object if ID is undefined +++
|
||||
if (props.layoutNode && typeof props.layoutNode.id === 'undefined') {
|
||||
console.warn(`[LayoutRenderer DEBUG] handlePaneResize triggered but props.layoutNode.id is undefined. Full layoutNode prop:`, JSON.parse(JSON.stringify(props.layoutNode)));
|
||||
}
|
||||
console.log(`[LayoutRenderer DEBUG] handlePaneResize triggered for node ID: ${props.layoutNode?.id}, direction: ${props.layoutNode?.direction ?? 'N/A'}`); // Use optional chaining for safety
|
||||
console.log('[LayoutRenderer DEBUG] Splitpanes resized event object:', eventData);
|
||||
const paneSizes = eventData.panes; // 从事件对象中提取 panes 数组
|
||||
|
||||
console.log('Extracted paneSizes:', paneSizes); // 打印提取出的数组
|
||||
console.log('[LayoutRenderer DEBUG] Extracted paneSizes:', paneSizes); // 打印提取出的数组
|
||||
|
||||
if (props.layoutNode.type === 'container' && props.layoutNode.children) {
|
||||
// +++ Use optional chaining for safety +++
|
||||
if (props.layoutNode?.type === 'container' && props.layoutNode?.children) {
|
||||
// 确保 paneSizes 是一个数组
|
||||
if (!Array.isArray(paneSizes)) {
|
||||
console.error('[LayoutRenderer] handlePaneResize: 从事件对象提取的 panes 不是数组:', paneSizes);
|
||||
@@ -350,8 +357,12 @@ const handlePaneResize = (eventData: { panes: Array<{ size: number; [key: string
|
||||
size: paneInfo.size
|
||||
}));
|
||||
|
||||
// +++ 添加调用 store action 前的日志 +++
|
||||
console.log(`[LayoutRenderer DEBUG] Calling layoutStore.updateNodeSizes for node ID: ${props.layoutNode.id} with sizes:`, JSON.parse(JSON.stringify(childrenSizes)));
|
||||
// 调用 store action 来更新节点大小
|
||||
layoutStore.updateNodeSizes(props.layoutNode.id, childrenSizes);
|
||||
} else {
|
||||
console.log(`[LayoutRenderer DEBUG] handlePaneResize ignored for node ID: ${props.layoutNode.id} (type: ${props.layoutNode.type})`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -408,6 +419,11 @@ const getIconClasses = (paneName: PaneName): string[] => {
|
||||
|
||||
// --- Sidebar Resize Logic ---
|
||||
onMounted(() => {
|
||||
// +++ Log current layout tree from store on root mount +++
|
||||
if (props.isRootRenderer) {
|
||||
console.log('[LayoutRenderer DEBUG] Current layoutTree from store on mount:', JSON.stringify(layoutStore.layoutTree.value, null, 2));
|
||||
}
|
||||
|
||||
// Left Sidebar Resize
|
||||
useSidebarResize({
|
||||
sidebarRef: leftSidebarPanelRef,
|
||||
|
||||
@@ -184,132 +184,160 @@ export const useLayoutStore = defineStore('layout', () => {
|
||||
return allPossiblePanes.value.filter(pane => !used.has(pane));
|
||||
});
|
||||
|
||||
// +++ 新增:递归确保节点及其子节点都有 ID +++
|
||||
function ensureNodeIds(node: LayoutNode | null): LayoutNode | null {
|
||||
if (!node) return null;
|
||||
|
||||
// 确保当前节点有 ID
|
||||
if (!node.id) {
|
||||
console.warn('[Layout Store] Node is missing ID, generating one:', node);
|
||||
node.id = generateId();
|
||||
}
|
||||
|
||||
// 递归处理子节点
|
||||
if (node.type === 'container' && node.children) {
|
||||
node.children = node.children.map(child => ensureNodeIds(child)).filter(Boolean) as LayoutNode[];
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
// --- Actions ---
|
||||
// 初始化布局和侧栏配置
|
||||
async function initializeLayout() {
|
||||
// --- 移除之前的 DEBUG 日志 ---
|
||||
console.log('[Layout Store] Starting initializeLayout...'); // 保留起始日志
|
||||
layoutTree.value = null;
|
||||
sidebarPanes.value = getDefaultSidebarPanes();
|
||||
|
||||
let layoutLoadedFromBackend = false;
|
||||
let sidebarLoadedFromBackend = false;
|
||||
let loadedLayout: LayoutNode | null = null; // 临时存储加载的布局
|
||||
|
||||
// 1. 尝试从后端加载主布局
|
||||
try {
|
||||
console.log('[Layout Store] Attempting to load layout from backend...');
|
||||
const response = await apiClient.get<LayoutNode | null>('/settings/layout'); // 使用 apiClient
|
||||
console.log('[Layout Store] Step 1: Attempting to load layout from backend...');
|
||||
const response = await apiClient.get<LayoutNode | null>('/settings/layout');
|
||||
if (response.data) {
|
||||
// TODO: 在这里添加对 response.data 的结构验证,确保它符合 LayoutNode 接口
|
||||
layoutTree.value = response.data;
|
||||
console.log('[Layout Store] Step 1: Backend returned data.');
|
||||
// +++ 在赋值前确保 ID 存在 +++
|
||||
loadedLayout = ensureNodeIds(response.data);
|
||||
layoutLoadedFromBackend = true;
|
||||
console.log('[Layout Store] 主布局从后端加载成功。');
|
||||
// 更新 localStorage
|
||||
console.log('[Layout Store] Step 1: Layout processed with ensureNodeIds.');
|
||||
// 更新 localStorage (使用处理过的布局)
|
||||
try {
|
||||
localStorage.setItem(LAYOUT_STORAGE_KEY, JSON.stringify(response.data));
|
||||
localStorage.setItem(LAYOUT_STORAGE_KEY, JSON.stringify(loadedLayout));
|
||||
console.log('[Layout Store] Step 1: Saved processed layout to localStorage.');
|
||||
} catch (lsError) {
|
||||
console.error('[Layout Store] 保存后端主布局到 localStorage 失败:', lsError);
|
||||
console.error('[Layout Store] Step 1: Failed to save processed layout to localStorage:', lsError);
|
||||
}
|
||||
} else {
|
||||
console.log('[Layout Store] 后端未返回主布局数据。');
|
||||
console.log('[Layout Store] Step 1: Backend did not return layout data.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Layout Store] 从后端加载主布局失败:', error);
|
||||
console.error('[Layout Store] Step 1: Error loading layout from backend:', error);
|
||||
}
|
||||
|
||||
// 2. 尝试从后端加载侧栏配置 (假设 API 端点为 /settings/sidebar)
|
||||
// 2. 尝试从后端加载侧栏配置 (侧栏逻辑不变)
|
||||
try {
|
||||
console.log('[Layout Store] Attempting to load sidebar config from backend...');
|
||||
const response = await apiClient.get<{ left: any[], right: any[] } | null>('/settings/sidebar'); // Load as any[] first
|
||||
// --- Add Validation ---
|
||||
console.log('[Layout Store] Step 2: Attempting to load sidebar config from backend...');
|
||||
const response = await apiClient.get<{ left: any[], right: any[] } | null>('/settings/sidebar');
|
||||
if (response.data &&
|
||||
isValidPaneNameArray(response.data.left, allPossiblePanes.value) &&
|
||||
isValidPaneNameArray(response.data.right, allPossiblePanes.value))
|
||||
{
|
||||
sidebarPanes.value = response.data as { left: PaneName[], right: PaneName[] }; // Cast after validation
|
||||
sidebarPanes.value = response.data as { left: PaneName[], right: PaneName[] };
|
||||
sidebarLoadedFromBackend = true;
|
||||
console.log('[Layout Store] 侧栏配置从后端加载成功并通过验证。');
|
||||
// 更新 localStorage
|
||||
console.log('[Layout Store] Step 2: Sidebar config loaded from backend.');
|
||||
try {
|
||||
localStorage.setItem(SIDEBAR_STORAGE_KEY, JSON.stringify(response.data));
|
||||
} catch (lsError) {
|
||||
console.error('[Layout Store] 保存后端侧栏配置到 localStorage 失败:', lsError);
|
||||
}
|
||||
} else { // Handles the case where the 'if' at line 184 failed
|
||||
if (response.data) { // Check if data existed but failed validation
|
||||
console.log('[Layout Store] 后端返回的侧栏配置数据格式无效或包含无效/重复面板名称。');
|
||||
} else { // No data was returned from the backend
|
||||
console.log('[Layout Store] 后端未返回侧栏配置数据。');
|
||||
console.error('[Layout Store] Step 2: Failed to save backend sidebar config to localStorage:', lsError);
|
||||
}
|
||||
} else {
|
||||
console.log('[Layout Store] Step 2: Backend did not return valid sidebar data.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Layout Store] 从后端加载侧栏配置失败:', error);
|
||||
console.error('[Layout Store] Step 2: Error loading sidebar config from backend:', error);
|
||||
}
|
||||
|
||||
|
||||
// 3. 如果主布局后端未加载成功,尝试从 localStorage 加载
|
||||
if (!layoutLoadedFromBackend) {
|
||||
console.log('[Layout Store] Attempting to load main layout from localStorage...');
|
||||
console.log('[Layout Store] Step 3: Attempting localStorage for layout...');
|
||||
try {
|
||||
const savedLayout = localStorage.getItem(LAYOUT_STORAGE_KEY);
|
||||
if (savedLayout) {
|
||||
const parsedLayout = JSON.parse(savedLayout) as LayoutNode;
|
||||
// TODO: 添加验证逻辑
|
||||
layoutTree.value = parsedLayout;
|
||||
console.log('[Layout Store] 主布局从 localStorage 加载成功。');
|
||||
console.log('[Layout Store] Step 3: Parsed layout from localStorage.');
|
||||
// +++ 在赋值前确保 ID 存在 +++
|
||||
loadedLayout = ensureNodeIds(parsedLayout);
|
||||
console.log('[Layout Store] Step 3: Layout processed with ensureNodeIds.');
|
||||
} else {
|
||||
// 4. 如果 localStorage 也没有,使用默认主布局
|
||||
layoutTree.value = getDefaultLayout();
|
||||
console.log('[Layout Store] 未找到保存的主布局,使用默认布局。');
|
||||
console.log('[Layout Store] Step 4: No layout in localStorage. Applying default.');
|
||||
// +++ 确保默认布局也有 ID (虽然 getDefaultLayout 内部会生成) +++
|
||||
loadedLayout = ensureNodeIds(getDefaultLayout());
|
||||
console.log('[Layout Store] Step 4: Default layout processed with ensureNodeIds.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Layout Store] 从 localStorage 加载或解析主布局失败:', error);
|
||||
layoutTree.value = getDefaultLayout();
|
||||
console.error('[Layout Store] Step 3/4: Error loading/parsing layout from localStorage or applying default:', error);
|
||||
// Fallback to default if error and loadedLayout is still null
|
||||
if (!loadedLayout) {
|
||||
console.log('[Layout Store] Step 3/4: Applying default layout due to error.');
|
||||
loadedLayout = ensureNodeIds(getDefaultLayout());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 如果侧栏配置后端未加载成功,尝试从 localStorage 加载
|
||||
// 5. 如果侧栏配置后端未加载成功,尝试从 localStorage 加载 (侧栏逻辑不变)
|
||||
if (!sidebarLoadedFromBackend) {
|
||||
console.log('[Layout Store] Attempting to load sidebar config from localStorage...');
|
||||
console.log('[Layout Store] Step 5: Attempting localStorage for sidebars...');
|
||||
try {
|
||||
const savedSidebars = localStorage.getItem(SIDEBAR_STORAGE_KEY);
|
||||
if (savedSidebars) {
|
||||
const parsedSidebars = JSON.parse(savedSidebars) as { left: any[], right: any[] }; // Parse as any[] first
|
||||
// --- Add Validation ---
|
||||
const parsedSidebars = JSON.parse(savedSidebars) as { left: any[], right: any[] };
|
||||
if (parsedSidebars &&
|
||||
isValidPaneNameArray(parsedSidebars.left, allPossiblePanes.value) &&
|
||||
isValidPaneNameArray(parsedSidebars.right, allPossiblePanes.value))
|
||||
{
|
||||
sidebarPanes.value = parsedSidebars as { left: PaneName[], right: PaneName[] }; // Cast after validation
|
||||
console.log('[Layout Store] 侧栏配置从 localStorage 加载成功并通过验证。');
|
||||
sidebarPanes.value = parsedSidebars as { left: PaneName[], right: PaneName[] };
|
||||
console.log('[Layout Store] Step 5: Sidebar config loaded from localStorage.');
|
||||
} else {
|
||||
console.warn('[Layout Store] localStorage 中的侧栏配置格式无效或包含无效/重复面板名称,使用默认值。');
|
||||
console.warn('[Layout Store] Step 5: Invalid sidebar config in localStorage. Applying default.');
|
||||
sidebarPanes.value = getDefaultSidebarPanes();
|
||||
}
|
||||
} else {
|
||||
// 6. 如果 localStorage 也没有,使用默认侧栏配置
|
||||
console.log('[Layout Store] Step 6: No sidebar config in localStorage. Applying default.');
|
||||
sidebarPanes.value = getDefaultSidebarPanes();
|
||||
console.log('[Layout Store] 未找到保存的侧栏配置,使用默认配置。');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Layout Store] 从 localStorage 加载或解析侧栏配置失败:', error);
|
||||
sidebarPanes.value = getDefaultSidebarPanes();
|
||||
console.error('[Layout Store] Step 5/6: Error loading/parsing sidebar config from localStorage or applying default:', error);
|
||||
if (!sidebarPanes.value || !Array.isArray(sidebarPanes.value.left)) {
|
||||
sidebarPanes.value = getDefaultSidebarPanes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Final Check: Ensure defaults are applied if loading failed or resulted in null ---
|
||||
if (!layoutTree.value) {
|
||||
console.warn('[Layout Store] Layout tree is still null after all loading attempts. Applying default layout.');
|
||||
layoutTree.value = getDefaultLayout();
|
||||
// Optionally save the default to localStorage now?
|
||||
// try { localStorage.setItem(LAYOUT_STORAGE_KEY, JSON.stringify(layoutTree.value)); } catch(e) {}
|
||||
}
|
||||
// Basic check for sidebarPanes structure validity before potentially applying default
|
||||
if (!sidebarPanes.value || !Array.isArray(sidebarPanes.value.left) || !Array.isArray(sidebarPanes.value.right)) {
|
||||
console.warn('[Layout Store] Sidebar panes are null or invalid after all loading attempts. Applying default sidebar panes.');
|
||||
sidebarPanes.value = getDefaultSidebarPanes();
|
||||
// Optionally save the default to localStorage now?
|
||||
// try { localStorage.setItem(SIDEBAR_STORAGE_KEY, JSON.stringify(sidebarPanes.value)); } catch(e) {}
|
||||
}
|
||||
// --- Final Assignment and Check ---
|
||||
console.log('[Layout Store] Final Assignment: Assigning processed layout to layoutTree.value.');
|
||||
layoutTree.value = loadedLayout; // 将处理过的布局赋值给状态
|
||||
|
||||
// --- Log the final layout configuration after initialization ---
|
||||
// console.log('[Layout Store] Final Initialized Layout Tree:', JSON.stringify(layoutTree.value, null, 2));
|
||||
// console.log('[Layout Store] Final Initialized Sidebar Panes:', JSON.stringify(sidebarPanes.value, null, 2));
|
||||
// Final check (主要是为了调试,可以简化或移除)
|
||||
if (!layoutTree.value) {
|
||||
console.error('[Layout Store] FATAL: layoutTree is STILL null after all attempts! Applying default as last resort.');
|
||||
layoutTree.value = ensureNodeIds(getDefaultLayout());
|
||||
}
|
||||
if (!sidebarPanes.value || !Array.isArray(sidebarPanes.value.left) || !Array.isArray(sidebarPanes.value.right)) {
|
||||
console.warn('[Layout Store] Final Check: Sidebar panes invalid. Applying default.');
|
||||
sidebarPanes.value = getDefaultSidebarPanes();
|
||||
}
|
||||
|
||||
console.log('[Layout Store] initializeLayout finished.');
|
||||
// --- 移除最终状态的详细日志,避免冗余 ---
|
||||
// console.log('[Layout Store] Final layoutTree.value:', JSON.stringify(layoutTree.value, null, 2));
|
||||
// console.log('[Layout Store] Final sidebarPanes.value:', JSON.stringify(sidebarPanes.value, null, 2));
|
||||
}
|
||||
|
||||
// --- Helper for debounced persistence ---
|
||||
|
||||
Reference in New Issue
Block a user