diff --git a/src/components/MobileBottomNav/index.vue b/src/components/MobileBottomNav/index.vue
index fdb95dd..f49919a 100644
--- a/src/components/MobileBottomNav/index.vue
+++ b/src/components/MobileBottomNav/index.vue
@@ -34,130 +34,68 @@ export default {
default: true
}
},
- data() {
- return {
- navItemsCache: null
- }
- },
computed: {
...mapGetters(['device', 'sidebarRouters']),
isMobile() {
return this.device === 'mobile' || window.innerWidth < 768
},
navItems() {
- // 如果提供了自定义items,直接使用
+ // 如果提供了自定义 items,直接使用
if (this.items && this.items.length > 0) {
return this.items
}
-
- // 使用缓存,避免重复计算
- if (this.navItemsCache) {
- return this.navItemsCache
- }
-
- // 从侧边栏路由中获取可用的路由
+ // 始终从 store 的 sidebarRouters 计算,保证与接口返回、路由注册一致,避免移动端菜单/跳转错乱
const routes = this.sidebarRouters || []
-
- // 扁平化路由,获取所有叶子节点路由
- const flattenRoutes = (routes, parentPath = '') => {
- let result = []
- if (!routes || !Array.isArray(routes)) {
- return result
- }
-
- routes.forEach(route => {
- if (route.hidden) return
-
- // 处理路径 - 确保路径正确
- let fullPath = route.path || ''
- if (parentPath) {
- if (fullPath.startsWith('/')) {
- fullPath = fullPath
- } else {
- // 合并路径
- const basePath = parentPath.endsWith('/') ? parentPath.slice(0, -1) : parentPath
- fullPath = `${basePath}/${fullPath}`.replace(/\/+/g, '/')
- }
- }
-
- // 确保路径以/开头
- if (fullPath && !fullPath.startsWith('/')) {
- fullPath = '/' + fullPath
- }
-
- // 如果有子路由,递归处理
- if (route.children && route.children.length > 0) {
- result = result.concat(flattenRoutes(route.children, fullPath))
- } else {
- // 叶子节点路由,且有meta信息
- if (route.meta && route.meta.title && fullPath) {
- result.push({
- path: fullPath,
- label: route.meta.title,
- icon: route.meta.icon || 'el-icon-menu',
- iconClass: route.meta.icon,
- route: route
- })
- }
- }
- })
- return result
- }
-
- const flatRoutes = flattenRoutes(routes)
-
- // 过滤并获取所有主要路由(不限制数量,显示所有)
- const mainRoutes = flatRoutes
- .filter(route => {
- // 过滤掉一些特殊路由
- const excludePaths = ['/redirect', '/login', '/register', '/404', '/401', '/user/profile']
- const path = route.path || ''
- return path &&
- path !== '/' &&
- !excludePaths.some(exclude => path.includes(exclude)) &&
- !path.startsWith('/user/')
- })
- // 不限制数量,显示所有可用路由
-
- // 缓存结果
+ const flatRoutes = this.flattenRoutes(routes)
+ const mainRoutes = flatRoutes.filter(route => {
+ const excludePaths = ['/redirect', '/login', '/register', '/404', '/401', '/user/profile']
+ const path = route.path || ''
+ return path &&
+ path !== '/' &&
+ !excludePaths.some(exclude => path.includes(exclude)) &&
+ !path.startsWith('/user/')
+ })
if (mainRoutes.length > 0) {
- this.navItemsCache = mainRoutes
return mainRoutes
}
-
- // 如果没有找到路由,返回默认导航
- const defaultRoutes = [
- {
- path: '/sloworder/index',
- label: '首页',
- icon: 'el-icon-s-home'
- }
+ return [
+ { path: '/sloworder/index', label: '首页', icon: 'el-icon-s-home' }
]
-
- this.navItemsCache = defaultRoutes
- return defaultRoutes
}
},
- watch: {
- sidebarRouters: {
- handler() {
- // 路由变化时清除缓存
- this.navItemsCache = null
- },
- deep: true
- }
- },
- mounted() {
- // 等待路由加载完成
- this.$nextTick(() => {
- // 延迟一下,确保路由已经加载
- setTimeout(() => {
- this.navItemsCache = null
- this.$forceUpdate()
- }, 500)
- })
- },
methods: {
+ /** 扁平化路由为叶子节点,路径与 Vue Router 注册的完整 path 一致 */
+ flattenRoutes(routes, parentPath = '') {
+ if (!routes || !Array.isArray(routes)) return []
+ const result = []
+ routes.forEach(route => {
+ if (route.hidden) return
+ let fullPath = (route.path || '').trim()
+ if (parentPath) {
+ if (fullPath.startsWith('/')) {
+ // 已是绝对路径,直接使用
+ } else {
+ const base = parentPath.endsWith('/') ? parentPath.slice(0, -1) : parentPath
+ fullPath = `${base}/${fullPath}`.replace(/\/+/g, '/')
+ }
+ }
+ if (fullPath && !fullPath.startsWith('/')) {
+ fullPath = '/' + fullPath
+ }
+ if (route.children && route.children.length > 0) {
+ result.push(...this.flattenRoutes(route.children, fullPath))
+ } else if (route.meta && route.meta.title && fullPath) {
+ result.push({
+ path: fullPath,
+ label: route.meta.title,
+ icon: route.meta.icon || 'el-icon-menu',
+ iconClass: route.meta.icon,
+ route
+ })
+ }
+ })
+ return result
+ },
isActive(path) {
if (!path) return false
const currentPath = this.$route.path
diff --git a/src/layout/index.vue b/src/layout/index.vue
index af4a49e..1b5777c 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -10,9 +10,10 @@
-
+
@@ -46,6 +47,13 @@ export default {
fixedHeader: state => state.settings.fixedHeader
}),
...mapGetters(['sidebarRouters']),
+ /** 接口路由更新后变化,使底部导航重新渲染并拉取最新菜单,避免点击跳错页 */
+ mobileNavKey() {
+ const routes = this.sidebarRouters || []
+ const len = routes.length
+ const firstPath = (len && routes[0]) ? (routes[0].path || '') : ''
+ return `${len}-${firstPath}`
+ },
mobileNavItems() {
// 如果返回空数组,组件会使用默认逻辑从路由中自动获取所有可用路由
return []