diff --git a/src/composables/useStomp.ts b/src/composables/useStomp.ts index c2b8912b..c1c0b390 100644 --- a/src/composables/useStomp.ts +++ b/src/composables/useStomp.ts @@ -65,7 +65,7 @@ export function useStomp(options: UseStompOptions = {}) { // 检查WebSocket端点是否配置 if (!brokerURL.value) { - console.error("WebSocket连接失败: 未配置WebSocket端点URL"); + console.warn("WebSocket连接失败: 未配置WebSocket端点URL"); return; } @@ -74,7 +74,7 @@ export function useStomp(options: UseStompOptions = {}) { // 检查令牌是否为空,如果为空则不进行连接 if (!currentToken) { - console.error("WebSocket连接失败:授权令牌为空,请先登录"); + console.warn("WebSocket连接失败:授权令牌为空,请先登录"); return; } diff --git a/src/layouts/components/Menu/MixTopMenu.vue b/src/layouts/components/Menu/MixTopMenu.vue index 96b9eb00..4d40730c 100644 --- a/src/layouts/components/Menu/MixTopMenu.vue +++ b/src/layouts/components/Menu/MixTopMenu.vue @@ -85,47 +85,15 @@ const processedTopMenus = computed(() => { }); }); -const route = useRoute(); - -// 获取当前路由路径的顶部菜单路径 -const getActiveTopMenuPath = () => { - const pathSegments = route.path.split("/").filter(Boolean); - return pathSegments.length > 0 ? `/${pathSegments[0]}` : "/"; -}; - -// 监听路由变化,更新活跃的顶部菜单 -watch( - () => route.path, - () => { - const newActiveTopMenuPath = getActiveTopMenuPath(); - if (newActiveTopMenuPath !== appStore.activeTopMenuPath) { - appStore.activeTopMenu(newActiveTopMenuPath); - } - }, - { immediate: true } -); - /** * 处理菜单点击事件,切换顶部菜单并加载对应的左侧菜单 * @param routePath 点击的菜单路径 */ const handleMenuSelect = (routePath: string) => { appStore.activeTopMenu(routePath); // 设置激活的顶部菜单 - activateFirstLevelMenu(routePath); // 激活一级菜单并设置左侧二级菜单 -}; - -/** - * 激活一级菜单并设置左侧二级菜单 - * @param routePath 点击的菜单路径 - */ -function activateFirstLevelMenu(routePath: string) { permissionStore.updateSideMenu(routePath); // 更新左侧菜单 - - // 使用 nextTick 确保侧边菜单更新完成后再跳转 - nextTick(() => { - navigateToFirstLeftMenu(permissionStore.sideMenuRoutes); // 跳转到左侧第一个菜单 - }); -} + navigateToFirstLeftMenu(permissionStore.sideMenuRoutes); // 跳转到左侧第一个菜单 +}; /** * 跳转到左侧第一个可访问的菜单 @@ -134,43 +102,34 @@ function activateFirstLevelMenu(routePath: string) { const navigateToFirstLeftMenu = (menus: RouteRecordRaw[]) => { if (menus.length === 0) return; - // 查找第一个可访问的菜单项 - const findFirstAccessibleRoute = (routes: RouteRecordRaw[]): RouteRecordRaw | null => { - for (const route of routes) { - // 跳过隐藏的菜单项 - if (route.meta?.hidden) continue; + const [firstMenu] = menus; - // 如果有子菜单,递归查找 - if (route.children && route.children.length > 0) { - const childRoute = findFirstAccessibleRoute(route.children); - if (childRoute) return childRoute; - } else if (route.name && route.path) { - // 找到第一个有名称和路径的菜单项 - return route; - } - } - return null; - }; - - const firstRoute = findFirstAccessibleRoute(menus); - - if (firstRoute && firstRoute.name) { - console.log("🎯 Navigating to first menu:", firstRoute.name, firstRoute.path); + // 如果第一个菜单有子菜单,递归跳转到第一个子菜单 + if (firstMenu.children && firstMenu.children.length > 0) { + navigateToFirstLeftMenu(firstMenu.children as RouteRecordRaw[]); + } else if (firstMenu.name) { router.push({ - name: firstRoute.name, + name: firstMenu.name, query: - typeof firstRoute.meta?.params === "object" - ? (firstRoute.meta.params as LocationQueryRaw) + typeof firstMenu.meta?.params === "object" + ? (firstMenu.meta.params as LocationQueryRaw) : undefined, }); } }; -// 当前激活的顶部菜单路径 +// 获取当前路由路径的顶部菜单路径 const activeTopMenuPath = computed(() => appStore.activeTopMenuPath); onMounted(() => { topMenus.value = permissionStore.routes.filter((item) => !item.meta || !item.meta.hidden); + // 初始化顶部菜单 + const currentTopMenuPath = + useRoute().path.split("/").filter(Boolean).length > 1 + ? useRoute().path.match(/^\/[^/]+/)?.[0] || "/" + : "/"; + appStore.activeTopMenu(currentTopMenuPath); // 设置激活的顶部菜单 + permissionStore.updateSideMenu(currentTopMenuPath); // 更新左侧菜单 }); diff --git a/src/layouts/components/Settings/index.vue b/src/layouts/components/Settings/index.vue index 121ac8a0..2ebb6bb5 100644 --- a/src/layouts/components/Settings/index.vue +++ b/src/layouts/components/Settings/index.vue @@ -149,7 +149,7 @@ import { DocumentCopy, RefreshLeft, Check } from "@element-plus/icons-vue"; const { t } = useI18n(); import { LayoutMode, SidebarColor, ThemeMode } from "@/enums"; -import { useSettingsStore, usePermissionStore, useAppStore } from "@/store"; +import { useSettingsStore } from "@/store"; import { themeColorPresets } from "@/settings"; // 按钮图标 @@ -176,10 +176,7 @@ const layoutOptions: LayoutOption[] = [ // 使用统一的颜色预设配置 const colorPresets = themeColorPresets; -const route = useRoute(); -const appStore = useAppStore(); const settingsStore = useSettingsStore(); -const permissionStore = usePermissionStore(); const isDark = ref(settingsStore.theme === ThemeMode.DARK); const sidebarColor = ref(settingsStore.sidebarColorScheme); @@ -221,13 +218,6 @@ const handleLayoutChange = (layout: LayoutMode) => { if (settingsStore.layout === layout) return; settingsStore.updateLayout(layout); - - if (layout === LayoutMode.MIX && route.name) { - const topLevelRoute = findTopLevelRoute(permissionStore.routes, route.name as string); - if (appStore.activeTopMenuPath !== topLevelRoute.path) { - appStore.activeTopMenu(topLevelRoute.path); - } - } }; /** @@ -313,39 +303,6 @@ const generateSettingsCode = (): string => { };`; }; -/** - * 查找路由的顶层父路由 - * - * @param tree 树形数据 - * @param findName 查找的名称 - */ -function findTopLevelRoute(tree: any[], findName: string) { - const parentMap: any = {}; - - function buildParentMap(node: any, parent: any) { - parentMap[node.name] = parent; - - if (node.children) { - for (let i = 0; i < node.children.length; i++) { - buildParentMap(node.children[i], node); - } - } - } - - for (let i = 0; i < tree.length; i++) { - buildParentMap(tree[i], null); - } - - let currentNode = parentMap[findName]; - while (currentNode) { - if (!parentMap[currentNode.name]) { - return currentNode; - } - currentNode = parentMap[currentNode.name]; - } - return null; -} - /** * 关闭抽屉前的回调 */ diff --git a/src/layouts/components/TagsView/index.vue b/src/layouts/components/TagsView/index.vue index 7aca352e..8e5cf1af 100644 --- a/src/layouts/components/TagsView/index.vue +++ b/src/layouts/components/TagsView/index.vue @@ -58,16 +58,15 @@ import { useRoute, useRouter, type RouteRecordRaw } from "vue-router"; import { resolve } from "path-browserify"; import { translateRouteTitle } from "@/utils/i18n"; -import { usePermissionStore, useTagsViewStore, useSettingsStore, useAppStore } from "@/store"; +import { usePermissionStore, useTagsViewStore, useSettingsStore } from "@/store"; +import { LayoutMode } from "@/enums"; -// ========================= 类型定义 ========================= interface ContextMenu { visible: boolean; x: number; y: number; } -// ========================= 组合式 API ========================= const instance = getCurrentInstance(); const proxy = instance?.proxy; const router = useRouter(); @@ -77,9 +76,7 @@ const route = useRoute(); const permissionStore = usePermissionStore(); const tagsViewStore = useTagsViewStore(); const settingsStore = useSettingsStore(); -const appStore = useAppStore(); -// ========================= 响应式数据 ========================= const { visitedViews } = storeToRefs(tagsViewStore); const layout = computed(() => settingsStore.layout); @@ -96,7 +93,6 @@ const contextMenu = reactive({ // 滚动条引用 const scrollbarRef = ref(); -// ========================= 计算属性 ========================= // 路由映射缓存,提升查找性能 const routePathMap = computed(() => { const map = new Map(); @@ -121,7 +117,6 @@ const isLastView = computed(() => { return selectedTag.value.fullPath === visitedViews.value[visitedViews.value.length - 1]?.fullPath; }); -// ========================= 核心函数 ========================= /** * 递归提取固定标签 */ @@ -155,45 +150,6 @@ const extractAffixTags = (routes: RouteRecordRaw[], basePath = "/"): TagView[] = return affixTags; }; -/** - * 查找路由的顶级父节点 - */ -const findTopLevelParent = ( - routes: RouteRecordRaw[], - targetName: string -): RouteRecordRaw | null => { - // 构建父子关系映射 - const parentMap = new Map(); - - const buildMap = (routeList: RouteRecordRaw[], parent: RouteRecordRaw | null = null) => { - routeList.forEach((route) => { - if (parent) { - parentMap.set(route.name as string, parent); - } - - if (route.children?.length) { - buildMap(route.children, route); - } - }); - }; - - buildMap(routes); - - // 向上查找顶级父节点 - let current = parentMap.get(targetName); - let topLevel = current; - - while (current) { - const parent = parentMap.get(current.name as string); - if (!parent) break; - topLevel = current; - current = parent; - } - - return topLevel || null; -}; - -// ========================= 标签操作 ========================= /** * 初始化固定标签 */ @@ -225,7 +181,7 @@ const addCurrentTag = () => { }; /** - * 更新当前标签(优化版本) + * 更新当前标签 */ const updateCurrentTag = () => { nextTick(() => { @@ -245,7 +201,6 @@ const updateCurrentTag = () => { }); }; -// ========================= 事件处理 ========================= /** * 处理中键点击 */ @@ -270,7 +225,8 @@ const openContextMenu = (tag: TagView, event: MouseEvent) => { const leftPosition = event.clientX - offsetLeft + MENU_MARGIN; contextMenu.x = Math.min(leftPosition, maxLeft); - contextMenu.y = layout.value === "mix" ? event.clientY - 50 : event.clientY; + // 混合模式下,需要减去顶部菜单(fixed)的高度 + contextMenu.y = layout.value === LayoutMode.MIX ? event.clientY - 50 : event.clientY; contextMenu.visible = true; selectedTag.value = tag; @@ -301,7 +257,6 @@ const handleScroll = (event: WheelEvent) => { scrollbarRef.value.setScrollLeft(newScrollLeft); }; -// ========================= 标签管理 ========================= /** * 刷新标签 */ @@ -378,20 +333,7 @@ const closeAllTags = (tag: TagView | null) => { }); }; -// ========================= 混合布局处理 ========================= -/** - * 更新顶部菜单激活状态(混合布局) - */ -const updateTopMenuActive = (routeName: string) => { - if (layout.value !== "mix") return; - - const topParent = findTopLevelParent(permissionStore.routes, routeName); - if (topParent && appStore.activeTopMenuPath !== topParent.path) { - appStore.activeTopMenu(topParent.path); - } -}; - -// ========================= 组合式函数:右键菜单管理 ========================= +// 右键菜单管理 const useContextMenuManager = () => { const handleOutsideClick = () => { closeContextMenu(); @@ -411,7 +353,6 @@ const useContextMenuManager = () => { }); }; -// ========================= 监听器和生命周期 ========================= // 监听路由变化 watch( route, @@ -422,17 +363,6 @@ watch( { immediate: true } ); -// 监听路由名变化(混合布局) -watch( - () => route.name, - (newRouteName) => { - if (newRouteName) { - updateTopMenuActive(newRouteName as string); - } - }, - { deep: true } -); - // 初始化 onMounted(() => { initAffixTags(); diff --git a/src/layouts/composables/useLayoutMenu.ts b/src/layouts/composables/useLayoutMenu.ts index 68d35e9a..850c707c 100644 --- a/src/layouts/composables/useLayoutMenu.ts +++ b/src/layouts/composables/useLayoutMenu.ts @@ -31,28 +31,10 @@ export function useLayoutMenu() { return path; }); - // 监听顶部菜单路径变化,更新侧边菜单 - watch( - () => activeTopMenuPath.value, - (newPath) => { - permissionStore.updateSideMenu(newPath); - }, - { immediate: true } - ); - - /** - * 处理顶部菜单点击 - * @param path 菜单路径 - */ - function handleTopMenuClick(path: string) { - appStore.activeTopMenu(path); - } - return { routes, sideMenuRoutes, activeMenu, activeTopMenuPath, - handleTopMenuClick, }; } diff --git a/src/layouts/views/LeftLayout.vue b/src/layouts/views/LeftLayout.vue index b4ada9cb..aa62b317 100644 --- a/src/layouts/views/LeftLayout.vue +++ b/src/layouts/views/LeftLayout.vue @@ -38,14 +38,10 @@ import AppMain from "../components/AppMain/index.vue"; import BasicMenu from "../components/Menu/BasicMenu.vue"; // 布局相关参数 -const { isShowTagsView, isShowLogo, isSidebarOpen, isMobile } = useLayout(); +const { isShowTagsView, isShowLogo, isSidebarOpen } = useLayout(); // 菜单相关 const { routes } = useLayoutMenu(); - -// 添加调试日志 -console.log("🔍 LeftLayout - isSidebarOpen:", isSidebarOpen.value); -console.log("🔍 LeftLayout - isMobile:", isMobile.value);