refactor: ♻️ 菜单路由优化
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "vue3-element-admin",
|
"name": "vue3-element-admin",
|
||||||
"description": "Vue3 + Vite + TypeScript + Element-Plus 的后台管理模板,vue-element-admin 的 Vue3 版本",
|
"description": "Vue3 + Vite + TypeScript + Element-Plus 的后台管理模板,vue-element-admin 的 Vue3 版本",
|
||||||
"version": "2.28.4",
|
"version": "2.29.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -78,10 +78,18 @@ appStore.activeTopMenu(activeTopMenuPath);
|
|||||||
*/
|
*/
|
||||||
const handleMenuSelect = (routePath: string) => {
|
const handleMenuSelect = (routePath: string) => {
|
||||||
appStore.activeTopMenu(routePath); // 设置激活的顶部菜单
|
appStore.activeTopMenu(routePath); // 设置激活的顶部菜单
|
||||||
permissionStore.setMixedLayoutLeftRoutes(routePath); // 更新左侧菜单
|
activateFirstLevelMenu(routePath); // 激活一级菜单并设置左侧二级菜单
|
||||||
navigateToFirstLeftMenu(permissionStore.mixedLayoutLeftRoutes); // 跳转到左侧第一个菜单
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 激活一级菜单并设置左侧二级菜单
|
||||||
|
* @param routePath 点击的菜单路径
|
||||||
|
*/
|
||||||
|
function activateFirstLevelMenu(routePath: string) {
|
||||||
|
permissionStore.updateSideMenu(routePath); // 更新左侧菜单
|
||||||
|
navigateToFirstLeftMenu(permissionStore.sideMenuRoutes); // 跳转到左侧第一个菜单
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跳转到左侧第一个可访问的菜单
|
* 跳转到左侧第一个可访问的菜单
|
||||||
* @param menus 左侧菜单列表
|
* @param menus 左侧菜单列表
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<!-- 左侧菜单栏 -->
|
<!-- 左侧菜单栏 -->
|
||||||
<div class="layout__sidebar--left">
|
<div class="layout__sidebar--left">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<SidebarMenu :data="mixedLayoutLeftRoutes" :base-path="activeTopMenuPath" />
|
<SidebarMenu :data="sideMenuRoutes" :base-path="activeTopMenuPath" />
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
<!-- 侧边栏切换按钮 -->
|
<!-- 侧边栏切换按钮 -->
|
||||||
<div class="layout__sidebar-toggle">
|
<div class="layout__sidebar-toggle">
|
||||||
@@ -72,13 +72,13 @@ const isSidebarOpen = computed(() => appStore.sidebar.opened); // 侧边栏是
|
|||||||
const isShowTagsView = computed(() => settingsStore.tagsView); // 是否显示标签视图
|
const isShowTagsView = computed(() => settingsStore.tagsView); // 是否显示标签视图
|
||||||
const layout = computed(() => settingsStore.layout); // 当前布局模式(left、top、mix)
|
const layout = computed(() => settingsStore.layout); // 当前布局模式(left、top、mix)
|
||||||
const activeTopMenuPath = computed(() => appStore.activeTopMenuPath); // 顶部菜单激活路径
|
const activeTopMenuPath = computed(() => appStore.activeTopMenuPath); // 顶部菜单激活路径
|
||||||
const mixedLayoutLeftRoutes = computed(() => permissionStore.mixedLayoutLeftRoutes); // 混合布局左侧菜单路由
|
const sideMenuRoutes = computed(() => permissionStore.sideMenuRoutes); // 混合布局左侧菜单路由
|
||||||
|
|
||||||
// 监听顶部菜单激活路径变化,更新混合布局左侧菜单路由
|
// 监听顶部菜单激活路径变化,更新混合布局左侧菜单路由
|
||||||
watch(
|
watch(
|
||||||
() => activeTopMenuPath.value,
|
() => activeTopMenuPath.value,
|
||||||
(newVal: string) => {
|
(newVal: string) => {
|
||||||
permissionStore.setMixedLayoutLeftRoutes(newVal);
|
permissionStore.updateSideMenu(newVal);
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true }
|
{ deep: true, immediate: true }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,12 +16,13 @@ export function setupPermission() {
|
|||||||
const isLogin = !!Storage.get(ACCESS_TOKEN_KEY, ""); // 判断是否登录
|
const isLogin = !!Storage.get(ACCESS_TOKEN_KEY, ""); // 判断是否登录
|
||||||
if (isLogin) {
|
if (isLogin) {
|
||||||
if (to.path === "/login") {
|
if (to.path === "/login") {
|
||||||
// 已登录,访问登录页,跳转到首页
|
// 已登录,跳转到首页
|
||||||
next({ path: "/" });
|
next({ path: "/" });
|
||||||
} else {
|
} else {
|
||||||
|
// 未登录
|
||||||
const permissionStore = usePermissionStore();
|
const permissionStore = usePermissionStore();
|
||||||
// 判断路由是否加载完成
|
// 判断路由是否加载完成
|
||||||
if (permissionStore.isRoutesLoaded) {
|
if (permissionStore.routesLoaded) {
|
||||||
if (to.matched.length === 0) {
|
if (to.matched.length === 0) {
|
||||||
// 路由未匹配,跳转到404
|
// 路由未匹配,跳转到404
|
||||||
next("/404");
|
next("/404");
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ const modules = import.meta.glob("../../views/**/**.vue");
|
|||||||
const Layout = () => import("@/layout/index.vue");
|
const Layout = () => import("@/layout/index.vue");
|
||||||
|
|
||||||
export const usePermissionStore = defineStore("permission", () => {
|
export const usePermissionStore = defineStore("permission", () => {
|
||||||
// 储所有路由,包括静态路由和动态路由
|
// 存储所有路由,包括静态路由和动态路由
|
||||||
const routes = ref<RouteRecordRaw[]>([]);
|
const routes = ref<RouteRecordRaw[]>([]);
|
||||||
// 混合模式左侧菜单路由
|
// 混合模式左侧菜单路由
|
||||||
const mixedLayoutLeftRoutes = ref<RouteRecordRaw[]>([]);
|
const sideMenuRoutes = ref<RouteRecordRaw[]>([]);
|
||||||
// 路由是否加载完成
|
// 路由是否加载完成
|
||||||
const isRoutesLoaded = ref(false);
|
const routesLoaded = ref(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取后台动态路由数据,解析并注册到全局路由
|
* 获取后台动态路由数据,解析并注册到全局路由
|
||||||
@@ -26,7 +26,7 @@ export const usePermissionStore = defineStore("permission", () => {
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
const dynamicRoutes = parseDynamicRoutes(data);
|
const dynamicRoutes = parseDynamicRoutes(data);
|
||||||
routes.value = [...constantRoutes, ...dynamicRoutes];
|
routes.value = [...constantRoutes, ...dynamicRoutes];
|
||||||
isRoutesLoaded.value = true;
|
routesLoaded.value = true;
|
||||||
resolve(dynamicRoutes);
|
resolve(dynamicRoutes);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -36,14 +36,14 @@ export const usePermissionStore = defineStore("permission", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据父菜单路径设置混合模式左侧菜单
|
* 根据父菜单路径设置侧边菜单
|
||||||
*
|
*
|
||||||
* @param parentPath 父菜单的路径,用于查找对应的菜单项
|
* @param parentPath 父菜单的路径,用于查找对应的菜单项
|
||||||
*/
|
*/
|
||||||
const setMixedLayoutLeftRoutes = (parentPath: string) => {
|
const updateSideMenu = (parentPath: string) => {
|
||||||
const matchedItem = routes.value.find((item) => item.path === parentPath);
|
const matchedItem = routes.value.find((item) => item.path === parentPath);
|
||||||
if (matchedItem && matchedItem.children) {
|
if (matchedItem && matchedItem.children) {
|
||||||
mixedLayoutLeftRoutes.value = matchedItem.children;
|
sideMenuRoutes.value = matchedItem.children;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -60,16 +60,16 @@ export const usePermissionStore = defineStore("permission", () => {
|
|||||||
|
|
||||||
// 清空本地存储的路由和菜单数据
|
// 清空本地存储的路由和菜单数据
|
||||||
routes.value = [];
|
routes.value = [];
|
||||||
mixedLayoutLeftRoutes.value = [];
|
sideMenuRoutes.value = [];
|
||||||
isRoutesLoaded.value = false;
|
routesLoaded.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
routes,
|
routes,
|
||||||
mixedLayoutLeftRoutes,
|
sideMenuRoutes,
|
||||||
isRoutesLoaded,
|
routesLoaded,
|
||||||
generateRoutes,
|
generateRoutes,
|
||||||
setMixedLayoutLeftRoutes,
|
updateSideMenu,
|
||||||
resetRouter,
|
resetRouter,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* WebSocket相关类型定义
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典WebSocket事件类型
|
|
||||||
*/
|
|
||||||
export interface DictWebSocketEvent {
|
|
||||||
/** 事件类型:更新或删除 */
|
|
||||||
type: "DICT_UPDATED" | "DICT_DELETED";
|
|
||||||
/** 字典编码 */
|
|
||||||
dictCode: string;
|
|
||||||
/** 时间戳 */
|
|
||||||
timestamp: number;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user