feat: 项目结构重构优化

This commit is contained in:
Ray.Hao
2025-12-26 12:35:37 +08:00
parent 65ad4fe59f
commit aa374dd2ba
164 changed files with 11305 additions and 3103 deletions

View File

@@ -0,0 +1,245 @@
<!-- 闖懷黒扈<EFBFBD>サカ -->
<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"
@open="onMenuOpen"
@close="onMenuClose"
>
<!-- 闖懷黒鬘?-->
<LayoutSidebarItem
v-for="route in data"
:key="route.path"
:item="route"
:base-path="resolveFullPath(route.path)"
/>
</el-menu>
</template>
<script lang="ts" setup>
import { useRoute } from "vue-router";
import path from "path-browserify";
import type { MenuInstance } from "element-plus";
import type { RouteRecordRaw } from "vue-router";
import { SidebarColor } from "@/enums/settings";
import { useSettingsStore, useAppStore } from "@/store";
import { isExternal } from "@/utils/index";
import LayoutSidebarItem from "./LayoutSidebarItem.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 menuRef = ref<MenuInstance>();
const settingsStore = useSettingsStore();
const appStore = useAppStore();
const currentRoute = useRoute();
// 蟄伜お蟾イ螻募シ€<C280>除蜊暮。ケ邏「蠑<EFBDA2>
const expandedMenuIndexes = ref<string[]>([]);
// 闔キ蜿紋クサ鬚<EFBDBB>
const theme = computed(() => settingsStore.theme);
// 闔キ蜿匁オ<E58C81>牡荳サ鬚倅ク狗噪萓ァ霎ケ譬城<E8ADAC>濶イ譁ケ譯?
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,
};
});
// 隶。邂怜ス灘燕豼€豢サ逧<EFBDBB>除蜊暮。?
const activeMenuPath = computed((): string => {
const { meta, path } = currentRoute;
// 螯よ棡霍ッ逕アmeta荳ュ隶セ鄂ョ莠<EFBDAE>ctiveMenu<6E><EFBFBD>菴ソ逕ィ螳<EFBDA8>シ育畑莠主、<E4B8BB>炊荳€莠帷音谿頑ュ蜀オ<E89C80>悟ヲりッヲ諠<EFBDA6>。オ<EFBDA1>?
if (meta?.activeMenu && typeof meta.activeMenu === "string") {
return meta.activeMenu;
}
// 蜷ヲ蛻吩スソ逕ィ蠖灘燕霍ッ逕ア霍ッ蠕<EFBDAF>
return path;
});
/**
* 闔キ蜿門ョ梧紛霍ッ蠕<EFBDAF>
*
* @param routePath 蠖灘燕霍ッ逕ア逧<EFBDB1>嶌蟇ケ霍ッ蠕? /user
* @returns 螳梧紛逧<E7B49B>サ晏ッケ霍ッ蠕?D://vue3-element-admin/system/user
*/
function resolveFullPath(routePath: string) {
if (isExternal(routePath)) {
return routePath;
}
if (isExternal(props.basePath)) {
return props.basePath;
}
// 螯よ棡 basePath 荳コ遨コ<E981A8>磯。カ驛ィ蟶<EFBDA8>€<EFBDB1>会シ檎峩謗・霑泌屓 routePath
if (!props.basePath || props.basePath === "") {
return routePath;
}
// 隗」譫占キッ蠕<EFBDAF>シ檎函謌仙ョ梧紛逧<E7B49B>サ晏ッケ霍ッ蠕<EFBDAF>
return path.resolve(props.basePath, routePath);
}
/**
* 謇灘シ€闖懷黒
*
* @param index 蠖灘燕螻募シ€<C280>除蜊暮。ケ邏「蠑<EFBDA2>
*/
const onMenuOpen = (index: string) => {
expandedMenuIndexes.value.push(index);
};
/**
* 蜈ウ髣ュ闖懷黒
*
* @param index 蠖灘燕謾カ襍キ逧<EFBDB7>除蜊暮。ケ邏「蠑<EFBDA2>
*/
const onMenuClose = (index: string) => {
expandedMenuIndexes.value = expandedMenuIndexes.value.filter((item) => item !== index);
};
/**
* 逶大成螻募シ€<C280>除蜊暮。ケ蜿伜喧<E4BC9C>梧峩譁ー辷カ闖懷黒譬キ蠑<EFBDB7>
*/
watch(
() => expandedMenuIndexes.value,
() => {
updateParentMenuStyles();
}
);
/**
* 逶大成闖懷黒讓。蠑丞序蛹厄シ壼ス楢除蜊墓ィ。蠑丞<E8A091>謐「荳コ豌エ蟷ウ讓。蠑乗慮<E4B997><EFBFBD>髣ュ謇€譛牙ア募シ€<C280>除蜊暮。ケ<EFBDA1>?
* 驕ソ蜈榊惠豌エ蟷ウ讓。蠑丈ク玖除蜊暮。ケ譏セ遉コ髞吩ス阪€?
*/
watch(
() => props.menuMode,
(newMode) => {
if (newMode === "horizontal" && menuRef.value) {
expandedMenuIndexes.value.forEach((item) => menuRef.value!.close(item));
}
}
);
/**
* 逶大成豼€豢サ闖懷黒蜿伜喧<E4BC9C>御クコ蛹<EFBDBA>性豼€豢サ蟄占除蜊慕噪辷カ闖懷黒豺サ蜉<EFBDBB>譬キ蠑冗ア?
*/
watch(
() => activeMenuPath.value,
() => {
nextTick(() => {
updateParentMenuStyles();
});
},
{ immediate: true }
);
/**
* 逶大成霍ッ逕ア蜿伜喧<E4BC9C>檎。ョ菫晁除蜊戊<E89C8A>髫週agsView蛻<77>困閠梧ュ」遑ョ豼€豢?
*/
watch(
() => currentRoute.path,
() => {
nextTick(() => {
updateParentMenuStyles();
});
}
);
/**
* 譖エ譁ー辷カ闖懷黒譬キ蠑?- 荳コ蛹<EFBDBA>性豼€豢サ蟄占除蜊慕噪辷カ闖懷黒豺サ蜉<EFBDBB> has-active-child 邀?
*/
function updateParentMenuStyles() {
if (!menuRef.value?.$el) return;
nextTick(() => {
try {
const menuEl = menuRef.value?.$el as HTMLElement;
if (!menuEl) return;
// 遘サ髯、謇€譛臥鴫譛臥噪 has-active-child 邀?
const allSubMenus = menuEl.querySelectorAll(".el-sub-menu");
allSubMenus.forEach((subMenu) => {
subMenu.classList.remove("has-active-child");
});
// 譟・謇セ蠖灘燕豼€豢サ逧<EFBDBB>除蜊暮。?
const activeMenuItem = menuEl.querySelector(".el-menu-item.is-active");
if (activeMenuItem) {
// 蜷台ク頑衍謇セ辷カ郤ァ el-sub-menu 蜈<><EFBFBD>
let parent = activeMenuItem.parentElement;
while (parent && parent !== menuEl) {
if (parent.classList.contains("el-sub-menu")) {
parent.classList.add("has-active-child");
}
parent = parent.parentElement;
}
} else {
// 豌エ蟷ウ讓。蠑丈ク句庄閭ス髴€隕∫音谿雁、<E99B81><EFBDA4>?
if (props.menuMode === "horizontal") {
// 蟇ケ莠取ーエ蟷ウ闖懷黒<E687B7>御スソ逕ィ霍ッ蠕<EFBDAF>源驟肴擂謇セ蛻ー辷カ闖懷<E99796>?
const currentPath = activeMenuPath.value;
// 譟・謇セ謇€譛臥宛闖懷黒鬘ケ<E9AC98>梧」€譟・蜩ェ荳ェ蛹<EFBDAA>性蠖灘燕霍ッ蠕?
allSubMenus.forEach((subMenu) => {
const subMenuEl = subMenu as HTMLElement;
const subMenuPath =
subMenuEl.getAttribute("data-path") ||
subMenuEl.querySelector(".el-sub-menu__title")?.getAttribute("data-path");
// 螯よ棡謇セ蛻ー蛹<EFBDB0>性蠖灘燕霍ッ蠕<EFBDAF>噪辷カ闖懷黒<E687B7><EFBFBD>豺サ蜉<EFBDBB>€豢サ邀サ
if (subMenuPath && currentPath.startsWith(subMenuPath)) {
subMenuEl.classList.add("has-active-child");
}
});
}
}
} catch (error) {
console.error("Error updating parent menu styles:", error);
}
});
}
/**
* 扈<>サカ謖りスス蜷守ォ句叉譖エ譁ー辷カ闖懷黒譬キ蠑<EFBDB7>
*/
onMounted(() => {
// 遑ョ菫晏惠扈<E683A0>サカ謖りスス蜷取峩譁ー譬キ蠑擾シ御ク堺セ晁オ紋コ主シよュ・謫堺ス?
updateParentMenuStyles();
});
</script>