Files
WonderQ-Project/WonderQ-Admin-UI-Vue/src/components/layout/SidebarItem.vue
duanshuwen 68d2b88c04 fix(layout/sidebar-item): 修复侧边栏菜单项的两处显示问题
- 将侧边栏内容容器从span改为div,避免Tooltip触发器被误判为隐藏文本
- 折叠父菜单时子菜单强制不折叠以保留子项标题
- 新增对应单元测试覆盖修复场景
2026-08-27 15:33:35 +08:00

62 lines
2.6 KiB
Vue

<script setup lang="ts">
import { computed } from "vue";
import LayoutIcon from "@/components/layout/LayoutIcon.vue";
import { getMenuIconName, visibleNavigableMenus } from "@/lib/menu-display";
import type { NavigationType } from "@/lib/layout-settings";
import type { AdminMenu } from "@/types";
type SidebarMenu = AdminMenu & { isVisible?: boolean };
const props = withDefaults(defineProps<{
menu: SidebarMenu;
basePath?: string;
collapsed?: boolean;
navigationType?: NavigationType;
}>(), {
basePath: "",
collapsed: false,
navigationType: "left",
});
function resolveMenuPath(basePath: string, menuPath: string | null | undefined): string | undefined {
if (!menuPath) return undefined;
if (menuPath.startsWith("/")) return menuPath;
const normalizedBasePath = basePath.replace(/^\/+|\/+$/g, "");
const normalizedMenuPath = menuPath.trim().replace(/^\/+/, "");
if (!normalizedMenuPath) return normalizedBasePath ? `/${normalizedBasePath}` : undefined;
return `/${[normalizedBasePath, normalizedMenuPath].filter(Boolean).join("/")}`.replace(/\/{2,}/g, "/");
}
const resolvedPath = computed(() => resolveMenuPath(props.basePath, props.menu.path));
const visibleChildren = computed(() => visibleNavigableMenus(props.menu.children ?? []));
const childBasePath = computed(() => resolvedPath.value || props.basePath || "/");
</script>
<template>
<el-sub-menu v-if="menu.type === 'directory' && visibleChildren.length > 0" :index="resolvedPath || menu.id"
:aria-label="menu.name" :class="['sidebar-item', `sidebar-item--${navigationType}`]">
<template #title>
<el-tooltip :content="menu.name" :disabled="!collapsed" placement="right">
<div class="sidebar-item__content">
<LayoutIcon :name="getMenuIconName(menu)" :title="collapsed ? menu.name : undefined" size="18" />
<span v-if="!collapsed" class="sidebar-item__label">{{ menu.name }}</span>
</div>
</el-tooltip>
</template>
<SidebarItem v-for="child in visibleChildren" :key="child.id" :menu="child" :base-path="childBasePath"
:collapsed="false" :navigation-type="navigationType" />
</el-sub-menu>
<el-menu-item v-else-if="menu.type === 'page' && resolvedPath" :index="resolvedPath" :aria-label="menu.name"
:class="['sidebar-item', `sidebar-item--${navigationType}`]">
<el-tooltip :content="menu.name" :disabled="!collapsed" placement="right">
<div class="sidebar-item__content">
<LayoutIcon :name="getMenuIconName(menu)" :title="collapsed ? menu.name : undefined" size="18" />
<span v-if="!collapsed" class="sidebar-item__label">{{ menu.name }}</span>
</div>
</el-tooltip>
</el-menu-item>
</template>