feat(admin-ui): implement RuoYi sidebar shell

This commit is contained in:
duanshuwen committed 2026-08-26 21:31:34 +08:00
1 parent 96612607e5
commit f6c5ad589f
3 files changed
+399

No files matched your search

@@ -0,0 +1,75 @@
<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">
<span 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>
</span>
</el-tooltip>
</template>
<SidebarItem
v-for="child in visibleChildren"
:key="child.id"
:menu="child"
:base-path="childBasePath"
:collapsed="collapsed"
: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">
<span 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>
</span>
</el-tooltip>
</el-menu-item>
</template>