Files
FastapiAdmin/frontend/src/layouts/components/Menu/BasicMenu.vue
T
zhangtao 7081850d46 feat(dependencies): update asyncmy and pandas versions for improved performance and compatibility
- Upgraded asyncmy from version 0.2.9 to 0.2.11 to leverage enhancements and bug fixes.
- Updated pandas from version 2.2.2 to 2.2.3 for better data processing capabilities.
- Added a new configuration option LOGIN_RESOLVE_IP_LOCATION to control IP location resolution during login.
- Enhanced login service to handle IP location resolution based on the new configuration.
- Improved validation logic in menu request handling to ensure proper redirection address for specific menu types.
- Adjusted CRUD template generation to dynamically use primary key column names for better flexibility.
- Updated Vue components to ensure proper handling of dynamic primary key references in menu items and forms.
2026-03-29 20:33:33 +08:00

127 lines
3.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 菜单组件 -->
<template>
<el-menu
ref="menuRef"
:default-active="activeMenuPath"
:collapse="!appStore.sidebar.opened"
:background-color="menuThemeProps.backgroundColor"
:text-color="menuThemeProps.textColor"
:active-text-color="menuThemeProps.activeTextColor"
:popper-effect="theme"
:unique-opened="false"
:collapse-transition="false"
:mode="menuMode"
>
<!-- 菜单项 -->
<MenuItem
v-for="route in data"
:key="route.path"
:item="route"
:base-path="menuParentBasePath"
/>
</el-menu>
</template>
<script lang="ts" setup>
import { nextTick } from "vue";
import type { MenuInstance } from "element-plus";
import { useRoute } from "vue-router";
import type { RouteRecordRaw } from "vue-router";
import { SidebarColor } from "@/enums/settings/theme.enum";
import { useSettingsStore, useAppStore } from "@/store";
import MenuItem from "./components/MenuItem.vue";
import variables from "@/styles/variables.module.scss";
const props = defineProps({
data: {
type: Array as PropType<RouteRecordRaw[]>,
default: () => [],
},
basePath: {
type: String,
required: true,
example: "/system",
},
menuMode: {
type: String as PropType<"vertical" | "horizontal">,
default: "vertical",
validator: (value: string) => ["vertical", "horizontal"].includes(value),
},
});
const settingsStore = useSettingsStore();
const appStore = useAppStore();
const currentRoute = useRoute();
const menuRef = ref<MenuInstance | null>(null);
// 获取主题
const theme = computed(() => settingsStore.theme);
// 获取浅色主题下的侧边栏配色方案
const sidebarColorScheme = computed(() => settingsStore.sidebarColorScheme);
// 菜单主题属性
const menuThemeProps = computed(() => {
const isDarkOrClassicBlue =
theme.value === "dark" || sidebarColorScheme.value === SidebarColor.CLASSIC_BLUE;
return {
backgroundColor: isDarkOrClassicBlue ? variables["menu-background"] : undefined,
textColor: isDarkOrClassicBlue ? variables["menu-text"] : undefined,
activeTextColor: isDarkOrClassicBlue ? variables["menu-active-text"] : undefined,
};
});
function normalizeMenuPath(p: string): string {
if (!p) return "";
if (/^https?:\/\//i.test(p) || p.startsWith("//")) return p;
const s = p.trim();
if (s === "/") return "/";
return s.replace(/\/+$/, "") || "/";
}
/**
* 与 MenuItem 叶子项 index 一致:叶子用 router.resolve 得到 path,与 route.path 相同;
* default-active 用当前 route.path(及 meta.activeMenu)即可对齐。
*/
const activeMenuPath = computed((): string => {
const r = currentRoute;
if (r.meta?.activeMenu && typeof r.meta.activeMenu === "string") {
return normalizeMenuPath(r.meta.activeMenu);
}
return normalizeMenuPath(r.path);
});
/**
* 侧栏树根前缀:左侧布局 base-path 为空时规范为 "/",再与每项 path 拼接。
* 勿用 resolveFullPath(route.path) 作为根 MenuItem 的 base-path,否则会与 item.path 再拼一次导致错位。
*/
const menuParentBasePath = computed(() => {
const b = props.basePath;
if (b === undefined || b === null || b === "") return "/";
const t = b.replace(/\/+$/, "");
return t || "/";
});
function syncMenuActive(val: string) {
menuRef.value?.updateActiveIndex(val);
}
watch(
activeMenuPath,
(val) => {
nextTick(() => {
syncMenuActive(val);
requestAnimationFrame(() => {
syncMenuActive(val);
setTimeout(() => syncMenuActive(val), 0);
setTimeout(() => syncMenuActive(val), 50);
});
});
},
{ immediate: true, flush: "post" }
);
// 父级激活样式由 Element Plus 在子项激活时为 el-sub-menu 添加 .is-activeMenuItem 内样式已覆盖标题颜色
</script>