From 484c116c4a019fa757ebba05bab8f033fb09b90f Mon Sep 17 00:00:00 2001 From: jingrow Date: Sun, 15 Mar 2026 23:10:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dget=5Fworkspace=5Fsidebar=5Fi?= =?UTF-8?q?tems=E9=87=8D=E5=A4=8D=E6=89=A7=E8=A1=8C=E5=A4=9A=E6=AC=A1?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/src/app/layouts/AppSidebar.vue | 4 +- .../frontend/src/shared/stores/menu.ts | 71 +++++++++++++------ .../src/views/workspace/WorkspacePage.vue | 17 ++--- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/apps/jingrow/frontend/src/app/layouts/AppSidebar.vue b/apps/jingrow/frontend/src/app/layouts/AppSidebar.vue index fb95f2a..48c315c 100644 --- a/apps/jingrow/frontend/src/app/layouts/AppSidebar.vue +++ b/apps/jingrow/frontend/src/app/layouts/AppSidebar.vue @@ -122,9 +122,7 @@ const parentWorkspaceOptions = computed(() => { }) onMounted(async () => { - if (!menuStore.loadedFromBackend) { - await menuStore.loadFromBackend() - } + await menuStore.loadFromBackend() syncEditableWorkspaces() }) diff --git a/apps/jingrow/frontend/src/shared/stores/menu.ts b/apps/jingrow/frontend/src/shared/stores/menu.ts index a402f9e..d3ceaae 100644 --- a/apps/jingrow/frontend/src/shared/stores/menu.ts +++ b/apps/jingrow/frontend/src/shared/stores/menu.ts @@ -54,10 +54,17 @@ function getDefaultMenus(): AppMenuItem[] { export const useMenuStore = defineStore('menu', () => { // 标记是否已从后端加载过 const loadedFromBackend = ref(false) - + + // Loading promise to prevent duplicate calls + let loadingPromise: Promise | null = null + // Workspace dictionary for quick lookup (like jingrow.workspaces in old frontend) // Key: slug(workspace.name), Value: workspace data const workspaces = ref>({}) + + // Access flags from backend + const hasWorkspaceAccess = ref(false) + const hasCreateWorkspaceAccess = ref(false) // 正确初始化为数组,而不是函数 const initItems = () => { @@ -155,29 +162,44 @@ export const useMenuStore = defineStore('menu', () => { * 菜单完全由后端数据驱动 */ async function loadFromBackend() { - try { - const response = await getWorkspaceSidebarItems() - const workspaceMenuItems = transformWorkspacePages(response.pages) - - // Build workspace dictionary (key: slug(workspace.name)) - const dict: Record = {} - for (const page of response.pages) { - const slugKey = pageTypeToSlug(page.name) - dict[slugKey] = page + // Return existing promise if already loading (prevent duplicate calls) + if (loadingPromise) return loadingPromise + // Already loaded + if (loadedFromBackend.value) return { success: true, count: items.value.length } + + loadingPromise = (async () => { + try { + const response = await getWorkspaceSidebarItems() + const workspaceMenuItems = transformWorkspacePages(response.pages) + + // Build workspace dictionary (key: slug(workspace.name)) + const dict: Record = {} + for (const page of response.pages) { + const slugKey = pageTypeToSlug(page.name) + dict[slugKey] = page + } + workspaces.value = dict + + // Store access flags + hasWorkspaceAccess.value = response.has_access || false + hasCreateWorkspaceAccess.value = response.has_create_access || false + + // 直接使用后端返回的菜单数据 + items.value = workspaceMenuItems + persist() + + loadedFromBackend.value = true + + return { success: true, count: workspaceMenuItems.length } + } catch (error: any) { + console.error('Failed to load menu from backend:', error) + return { success: false, error: error.message } + } finally { + loadingPromise = null } - workspaces.value = dict - - // 直接使用后端返回的菜单数据 - items.value = workspaceMenuItems - persist() - - loadedFromBackend.value = true - - return { success: true, count: workspaceMenuItems.length } - } catch (error: any) { - console.error('Failed to load menu from backend:', error) - return { success: false, error: error.message } - } + })() + + return loadingPromise } /** @@ -185,6 +207,7 @@ export const useMenuStore = defineStore('menu', () => { */ async function reloadFromBackend() { loadedFromBackend.value = false + loadingPromise = null return loadFromBackend() } @@ -212,6 +235,8 @@ export const useMenuStore = defineStore('menu', () => { visibleItems, loadedFromBackend, workspaces, + hasWorkspaceAccess, + hasCreateWorkspaceAccess, addMenu, updateMenu, removeMenu, diff --git a/apps/jingrow/frontend/src/views/workspace/WorkspacePage.vue b/apps/jingrow/frontend/src/views/workspace/WorkspacePage.vue index 6a7dd04..74913de 100644 --- a/apps/jingrow/frontend/src/views/workspace/WorkspacePage.vue +++ b/apps/jingrow/frontend/src/views/workspace/WorkspacePage.vue @@ -259,7 +259,7 @@ import { usePermissionStore } from '@/shared/stores/permissions' import { useAuthStore } from '@/shared/stores/auth' import { useMenuStore } from '@/shared/stores/menu' import { useWorkspaceEditStore } from '@/shared/stores/workspaceEdit' -import { getWorkspaceSidebarItems, getDesktopPage } from '@/shared/api/workspace' +import { getDesktopPage } from '@/shared/api/workspace' import draggable from 'vuedraggable' import IconPicker from '@/core/components/IconPicker.vue' import OnboardingBlock from '@/core/features/workspace_builder/blocks/OnboardingBlock.vue' @@ -376,8 +376,8 @@ function handleAddBlock(key: string) { async function loadWorkspaceSidebarMeta(force = false) { if (workspaceSidebarMeta.value.loaded && !force) return try { - const resp = await getWorkspaceSidebarItems() - const pages = Array.isArray(resp.pages) ? resp.pages : [] + await menuStore.loadFromBackend() + const pages = Object.values(menuStore.workspaces) const uniq = (arr: string[]) => Array.from(new Set(arr.filter(Boolean))) const publicParents = uniq( @@ -393,8 +393,8 @@ async function loadWorkspaceSidebarMeta(force = false) { workspaceSidebarMeta.value = { loaded: true, - has_access: Boolean(resp.has_access), - has_create_access: Boolean(resp.has_create_access), + has_access: menuStore.hasWorkspaceAccess, + has_create_access: menuStore.hasCreateWorkspaceAccess, publicParents, privateParents } @@ -405,11 +405,8 @@ async function loadWorkspaceSidebarMeta(force = false) { } async function load() { - // Ensure menu is loaded first - if (!menuStore.loadedFromBackend) { - await menuStore.loadFromBackend() - } - + await menuStore.loadFromBackend() + // If workspace not found in dictionary, it doesn't exist if (!workspaceName.value) { message.error(t('Workspace not found'))