fix:调试后端菜单数据问题
This commit is contained in:
@@ -35,7 +35,7 @@
|
|||||||
@menu-select="handleTopMenuSelect"
|
@menu-select="handleTopMenuSelect"
|
||||||
/>
|
/>
|
||||||
<!-- 右侧用户的内容 -->
|
<!-- 右侧用户的内容 -->
|
||||||
<rightMenuGroup />
|
<rightMenuGroup @on-stage-manage="onStageManage" />
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main>
|
<el-main>
|
||||||
<!-- <card-item :list="[1,2,3,4,5,6]"/> -->
|
<!-- <card-item :list="[1,2,3,4,5,6]"/> -->
|
||||||
@@ -98,9 +98,14 @@ const topLevelMenuList = computed(() => {
|
|||||||
return menuList.value.map((item) => {
|
return menuList.value.map((item) => {
|
||||||
const { children, ...rest } = item;
|
const { children, ...rest } = item;
|
||||||
return rest;
|
return rest;
|
||||||
});
|
}).filter(itv=>itv.name !== 'stage');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 后台管理点击获取列表
|
||||||
|
const onStageManage = () =>{
|
||||||
|
selectedTopMenu.value = '/stage';
|
||||||
|
}
|
||||||
|
|
||||||
const topTitle = computed(() => {
|
const topTitle = computed(() => {
|
||||||
return (
|
return (
|
||||||
topLevelMenuList.value.find((path) => path.path === selectedTopMenu.value)
|
topLevelMenuList.value.find((path) => path.path === selectedTopMenu.value)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="user-header-container">
|
<div class="user-header-container">
|
||||||
<div class="action-group">
|
<div class="action-group">
|
||||||
<div class="action-item">
|
<div class="action-item">
|
||||||
<el-icon :size="16"><Monitor /></el-icon>
|
<el-icon :size="16" @click="onStageManage"><Monitor /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="action-item">
|
<div class="action-item">
|
||||||
<el-badge is-dot class="notice-badge">
|
<el-badge is-dot class="notice-badge">
|
||||||
@@ -53,6 +53,8 @@ defineOptions({ name: "RightMenuGroup" });
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const tokenManager = TokenManager.getInstance();
|
const tokenManager = TokenManager.getInstance();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const emits = defineEmits(["on-stage-manage"]);
|
||||||
const handleCommand = (command: string) => {
|
const handleCommand = (command: string) => {
|
||||||
if (command === "logout") {
|
if (command === "logout") {
|
||||||
// 退出登录
|
// 退出登录
|
||||||
@@ -61,6 +63,11 @@ const handleCommand = (command: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const onStageManage = () =>{
|
||||||
|
emits('on-stage-manage')
|
||||||
|
}
|
||||||
|
|
||||||
// 获取当前的用户的数据信息
|
// 获取当前的用户的数据信息
|
||||||
const userInfo = computed(() => {
|
const userInfo = computed(() => {
|
||||||
return userStore.userInfo;
|
return userStore.userInfo;
|
||||||
|
|||||||
@@ -1,30 +1,34 @@
|
|||||||
import { createWebHistory, createRouter, type RouteRecordRaw } from 'vue-router'
|
import {
|
||||||
import { useUserStore } from '@/store'
|
createWebHistory,
|
||||||
import { getRouteMenus } from '@/api'
|
createRouter,
|
||||||
import TokenManager from '@/utils/storage';
|
type RouteRecordRaw,
|
||||||
|
} from "vue-router";
|
||||||
|
import { useUserStore } from "@/store";
|
||||||
|
import { getRouteMenus } from "@/api";
|
||||||
|
import TokenManager from "@/utils/storage";
|
||||||
|
|
||||||
import Login from '@/pages/Login/index.vue';
|
import Login from "@/pages/Login/index.vue";
|
||||||
import HomeView from '@/pages/Layout/index.vue';
|
import HomeView from "@/pages/Layout/index.vue";
|
||||||
|
|
||||||
const tokenManager = TokenManager.getInstance();
|
const tokenManager = TokenManager.getInstance();
|
||||||
// 基础路由(不需要权限验证)
|
// 基础路由(不需要权限验证)
|
||||||
const constantRoutes: RouteRecordRaw[] = [
|
const constantRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: "/login",
|
||||||
name: 'Login',
|
name: "Login",
|
||||||
component: Login,
|
component: Login,
|
||||||
meta: {
|
meta: {
|
||||||
title: '登录',
|
title: "登录",
|
||||||
requiresAuth: false
|
requiresAuth: false,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
]
|
},
|
||||||
|
];
|
||||||
|
|
||||||
// 动态路由(需要权限验证)
|
// 动态路由(需要权限验证)
|
||||||
const asyncRoutes: RouteRecordRaw[] = [
|
const asyncRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: "/",
|
||||||
name: 'Layout',
|
name: "Layout",
|
||||||
component: HomeView,
|
component: HomeView,
|
||||||
// redirect: '/home',
|
// redirect: '/home',
|
||||||
meta: {
|
meta: {
|
||||||
@@ -32,61 +36,81 @@ const asyncRoutes: RouteRecordRaw[] = [
|
|||||||
},
|
},
|
||||||
children: [] as RouteRecordRaw[],
|
children: [] as RouteRecordRaw[],
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
routes: [...constantRoutes, ...asyncRoutes],
|
routes: [...constantRoutes, ...asyncRoutes],
|
||||||
})
|
});
|
||||||
|
|
||||||
// 白名单路由(不需要登录即可访问)
|
// 白名单路由(不需要登录即可访问)
|
||||||
const whiteList = ['/login']
|
const whiteList = ["/login"];
|
||||||
|
|
||||||
// 1. 预先加载所有可能的页面组件
|
// 1. 预先加载所有可能的页面组件
|
||||||
// 这里的路径模式要覆盖到你所有的业务组件
|
// 这里的路径模式要覆盖到你所有的业务组件
|
||||||
const modules = import.meta.glob('@/pages/**/*.vue')
|
const modules = import.meta.glob("@/pages/**/*.vue");
|
||||||
|
|
||||||
const loadComponent = (componentPath: string) => {
|
const loadComponent = (componentPath: string) => {
|
||||||
if (!componentPath) return null
|
if (!componentPath) return null;
|
||||||
|
|
||||||
// 统一路径格式处理
|
// 统一路径格式处理
|
||||||
let fullPath = ''
|
let fullPath = "";
|
||||||
|
|
||||||
if (componentPath.startsWith('@/')) {
|
if (componentPath.startsWith("@/")) {
|
||||||
fullPath = componentPath
|
fullPath = componentPath;
|
||||||
} else if (componentPath.includes('/')) {
|
} else if (componentPath.includes("/")) {
|
||||||
// 补全路径,确保以 @/pages 开头
|
// 补全路径,确保以 @/pages 开头
|
||||||
fullPath = componentPath.startsWith('pages/') ? `@/${componentPath}` : `@/pages/${componentPath}/index.vue`
|
fullPath = componentPath.startsWith("pages/")
|
||||||
|
? `@/${componentPath}`
|
||||||
|
: `@/pages/${componentPath}/index.vue`;
|
||||||
} else {
|
} else {
|
||||||
// 补全 index.vue
|
// 补全 index.vue
|
||||||
fullPath = `@/pages/${componentPath}/index.vue`
|
fullPath = `@/pages/${componentPath}/index.vue`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重点:将 @/ 转换为 /src/,因为 glob 默认生成的 key 是相对于项目根目录的
|
// 重点:将 @/ 转换为 /src/,因为 glob 默认生成的 key 是相对于项目根目录的
|
||||||
const key = fullPath.replace('@/', '/src/')
|
const key = fullPath.replace("@/", "/src/");
|
||||||
|
|
||||||
// 从 modules 中查找对应的导入函数
|
// 从 modules 中查找对应的导入函数
|
||||||
if (modules[key]) {
|
if (modules[key]) {
|
||||||
return modules[key]
|
return modules[key];
|
||||||
} else {
|
} else {
|
||||||
console.error(`未找到组件文件: ${key}. 请检查路径或大小写。`)
|
console.error(`未找到组件文件: ${key}. 请检查路径或大小写。`);
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 将后端返回的路由数据转换为 Vue Router 路由
|
// 将后端返回的路由数据转换为 Vue Router 路由
|
||||||
const transformRoutes = (routes: any[], parentCode: string = ''): RouteRecordRaw[] => {
|
const transformRoutes = (
|
||||||
|
routes: any[],
|
||||||
|
parentCode: string = ""
|
||||||
|
): RouteRecordRaw[] => {
|
||||||
|
console.log("transformRoutes", routes);
|
||||||
return routes.flatMap((route) => {
|
return routes.flatMap((route) => {
|
||||||
const fullCode = parentCode ? `${parentCode}/${route.code}` : route.code;
|
const fullCode = parentCode ? `${parentCode}/${route.code}` : route.code;
|
||||||
|
|
||||||
// 如果当前路由有子路由,说明它是一个路由前缀,不需要组件
|
// 如果当前路由有子路由,说明它是一个路由前缀,不需要组件
|
||||||
if (route.children && route.children.length > 0) {
|
if (route.children && route.children.length > 0) {
|
||||||
// 将子路由的路径加上当前路由的前缀,然后递归处理
|
const childRoutes = transformRoutes(route.children, fullCode);
|
||||||
return transformRoutes(route.children, fullCode);
|
if (route.code) {
|
||||||
|
// 创建一个父路由,将子路由作为其 children
|
||||||
|
const parentRoute: RouteRecordRaw = {
|
||||||
|
path: `/${fullCode}`,
|
||||||
|
name: route.code,
|
||||||
|
meta: {
|
||||||
|
title: route.name,
|
||||||
|
icon: route.icon,
|
||||||
|
...route.meta,
|
||||||
|
},
|
||||||
|
children: childRoutes,
|
||||||
|
};
|
||||||
|
return parentRoute;
|
||||||
|
} else {
|
||||||
|
return childRoutes;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 叶子节点才需要组件和路由配置
|
// 叶子节点才需要组件和路由配置
|
||||||
const component = fullCode ? loadComponent(fullCode) : undefined;
|
const component = fullCode ? loadComponent(fullCode) : undefined;
|
||||||
|
|
||||||
const routeRecord: any = {
|
const routeRecord: any = {
|
||||||
path: route.code,
|
path: route.code,
|
||||||
name: route.code,
|
name: route.code,
|
||||||
@@ -95,7 +119,7 @@ const transformRoutes = (routes: any[], parentCode: string = ''): RouteRecordRaw
|
|||||||
icon: route.icon,
|
icon: route.icon,
|
||||||
...route.meta,
|
...route.meta,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
if (component) {
|
if (component) {
|
||||||
routeRecord.component = component;
|
routeRecord.component = component;
|
||||||
@@ -104,135 +128,117 @@ const transformRoutes = (routes: any[], parentCode: string = ''): RouteRecordRaw
|
|||||||
return routeRecord as RouteRecordRaw;
|
return routeRecord as RouteRecordRaw;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// 添加动态路由
|
// 添加动态路由
|
||||||
const addDynamicRoutes = async () => {
|
const addDynamicRoutes = async () => {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore();
|
||||||
|
|
||||||
// 如果路由已加载,直接返回
|
// 如果路由已加载,直接返回
|
||||||
if (userStore.isRoutesLoaded) {
|
if (userStore.isRoutesLoaded) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO:从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单)
|
// 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单)
|
||||||
let response:any;
|
let allRoutes:any[] = [];
|
||||||
if (userStore.isBackendUser) {
|
if (userStore.isBackendUser) {
|
||||||
const backendResponse = await getRouteMenus();
|
const backendResponse = await getRouteMenus();
|
||||||
response = [{
|
allRoutes = [
|
||||||
code: 'stage',
|
{
|
||||||
name: '后台管理',
|
code: "stage",
|
||||||
icon: '',
|
name: "后台管理",
|
||||||
|
icon: "",
|
||||||
children: backendResponse,
|
children: backendResponse,
|
||||||
}];
|
},
|
||||||
}else{
|
];
|
||||||
// response = await getUserMenus();
|
|
||||||
response = [];
|
|
||||||
}
|
|
||||||
if (response) {
|
|
||||||
const processRoutes = (routes: any[], prefix: string = ''): RouteRecordRaw[] => {
|
|
||||||
return routes.flatMap(route => {
|
|
||||||
const currentPath = prefix ? `${prefix}/${route.code}` : route.code;
|
|
||||||
|
|
||||||
if (route.children && route.children.length > 0) {
|
|
||||||
// 如果有子路由,递归处理并添加当前路径作为前缀
|
|
||||||
return processRoutes(route.children, currentPath);
|
|
||||||
} else {
|
} else {
|
||||||
// 叶子节点,创建路由记录
|
// TODO:获取用户端的数据信息
|
||||||
const component = loadComponent(currentPath);
|
// response = await getUserMenus();
|
||||||
return {
|
allRoutes = [];
|
||||||
path: route.code,
|
|
||||||
name: route.code,
|
|
||||||
component: component || HomeView, // 使用Layout的组件
|
|
||||||
meta: {
|
|
||||||
title: route.name,
|
|
||||||
icon: route.icon,
|
|
||||||
...route.meta,
|
|
||||||
}
|
}
|
||||||
} as RouteRecordRaw;
|
if (allRoutes) {
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// 转换路由数据
|
// 转换路由数据
|
||||||
// const dynamicRoutes = transformRoutes(Array.isArray(response) ? response : [response])
|
const dynamicRoutes = transformRoutes(
|
||||||
const dynamicRoutes = processRoutes(Array.isArray(response) ? response : [response])
|
Array.isArray(allRoutes) ? allRoutes : [allRoutes]
|
||||||
|
);
|
||||||
// 将动态路由添加到 Layout 的 children 中
|
// 将动态路由添加到 Layout 的 children 中
|
||||||
const layoutRoute = router.getRoutes().find(route => route.name === 'Layout')
|
const layoutRoute = router
|
||||||
|
.getRoutes()
|
||||||
|
.find((route) => route.name === "Layout");
|
||||||
|
|
||||||
if (layoutRoute) {
|
if (layoutRoute) {
|
||||||
dynamicRoutes.forEach(route => {
|
dynamicRoutes.forEach((route) => {
|
||||||
router.addRoute('Layout', route)
|
router.addRoute("Layout", route);
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
// 如果找不到 Layout 路由,直接添加到根路由
|
// 如果找不到 Layout 路由,直接添加到根路由
|
||||||
dynamicRoutes.forEach(route => {
|
dynamicRoutes.forEach((route) => {
|
||||||
router.addRoute(route)
|
router.addRoute(route);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
console.log('Layout route:', router.getRoutes())
|
|
||||||
// 保存路由数据到 store
|
// 保存路由数据到 store
|
||||||
userStore.setRoutes(response)
|
userStore.setRoutes(dynamicRoutes);
|
||||||
|
|
||||||
// 标记路由已加载
|
// 标记路由已加载
|
||||||
userStore.isRoutesLoaded = true
|
userStore.isRoutesLoaded = true;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 如果获取路由失败,清除用户数据并跳转到登录页
|
// 如果获取路由失败,清除用户数据并跳转到登录页
|
||||||
userStore.clearUserData()
|
userStore.clearUserData();
|
||||||
router.push('/login')
|
router.push("/login");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 路由导航守卫
|
// 路由导航守卫
|
||||||
router.beforeEach(async (to, _from, next) => {
|
router.beforeEach(async (to, _from, next) => {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore();
|
||||||
const accessToken = tokenManager.getToken('accessToken');
|
const accessToken = tokenManager.getToken("accessToken");
|
||||||
|
|
||||||
// 获取 token
|
// 获取 token
|
||||||
const token = accessToken || userStore.token
|
const token = accessToken || userStore.token;
|
||||||
|
|
||||||
// 如果已登录,更新 store 中的 token
|
// 如果已登录,更新 store 中的 token
|
||||||
if (token) {
|
if (token) {
|
||||||
userStore.setToken(token)
|
userStore.setToken(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否在白名单中
|
// 判断是否在白名单中
|
||||||
if (whiteList.includes(to.path)) {
|
if (whiteList.includes(to.path)) {
|
||||||
// 如果在白名单中且已登录,重定向到首页
|
// 如果在白名单中且已登录,重定向到首页
|
||||||
if (token) {
|
if (token) {
|
||||||
next('/')
|
next("/");
|
||||||
} else {
|
} else {
|
||||||
next()
|
next();
|
||||||
}
|
}
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 需要登录验证
|
// 需要登录验证
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// 未登录,重定向到登录页
|
// 未登录,重定向到登录页
|
||||||
next({
|
next({
|
||||||
path: '/login',
|
path: "/login",
|
||||||
query: { redirect: to.fullPath }, // 保存当前路径,登录后可以跳转回来
|
query: { redirect: to.fullPath }, // 保存当前路径,登录后可以跳转回来
|
||||||
})
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已登录,检查路由是否已加载
|
// 已登录,检查路由是否已加载
|
||||||
if (!userStore.isRoutesLoaded) {
|
if (!userStore.isRoutesLoaded) {
|
||||||
try {
|
try {
|
||||||
// 加载动态路由
|
// 加载动态路由
|
||||||
await addDynamicRoutes()
|
await addDynamicRoutes();
|
||||||
// 路由加载完成后,重新导航到目标路由
|
// 路由加载完成后,重新导航到目标路由
|
||||||
next({ ...to, replace: true })
|
next({ ...to, replace: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Route loading error:', error)
|
console.error("Route loading error:", error);
|
||||||
next('/login')
|
next("/login");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 路由已加载,直接放行
|
// 路由已加载,直接放行
|
||||||
next()
|
next();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
export default router
|
export default router;
|
||||||
|
|||||||
Reference in New Issue
Block a user