20260921231313

This commit is contained in:
oneao committed 2026-09-21 23:13:14 +08:00
1 parent ac710c1801
commit 583984c24f
81 files changed
+2523 -288

No files matched your search

+5 -5
View File
@@ -20,7 +20,7 @@ const router = createRouter({
})
// 登录守卫:未登录访问受保护页跳 /login?redirect=xxx;已登录访问 /login 跳 /dashboard
// 权限守卫:路由配置 meta.moduleId 时校验访问权限,无权限跳 /dashboard
// 权限守卫:路由配置 meta.moduleId 时校验访问权限,无权限跳 /403 缺省页
router.beforeEach(async (to) => {
NProgress.start()
const authStore = useAuthStore()
@@ -50,21 +50,21 @@ router.beforeEach(async (to) => {
const moduleId = to.meta.moduleId
if (moduleId && !permissionStore.canAccess(moduleId)) {
return '/dashboard'
return '/403'
}
// 菜单入口:路由命中 s_menu 里的页面菜单时,必须有该菜单的 menu.* 授权。
// 侧栏已按授权裁剪(stores/menus),这里兜住「手输地址直接访问」。
const menu = menuStore.findMenuByRoute(to.path)
if (menu && !permissionStore.canEnterMenu(menu.b_id)) {
return '/dashboard'
return '/403'
}
// 系统管理员专用页面(meta.adminOnly,当前为模块中心 /module/*):
// 非 g3soft 一律拦回工作台。按路由标记而非路径前缀判断,避免「菜单上看不见、
// 非 g3soft 一律拦到 403 页。按路由标记而非路径前缀判断,避免「菜单上看不见、
// 手输地址却能进」的越权;侧栏入口同样仅对 g3soft 渲染(AppSidebar)。
if (to.matched.some((r) => r.meta.adminOnly) && !permissionStore.isG3soft) {
return '/dashboard'
return '/403'
}
}
})
+34 -5
View File
@@ -22,8 +22,8 @@ import DefaultLayout from '@/layouts/DefaultLayout.vue'
* 切勿给分组节点配「内部再放一个 router-view」的容器组件:那样页面会下沉一层,
* 直接脱离 DefaultLayout 的 keep-alive,页面缓存失效。
* 分组节点不配 redirect:分组只是归类,不该自带「默认落地页」语义 —— 直接访问 /base、/module
* 这类裸前缀时交给表尾的 /:pathMatch(.*)* 兜到工作台,避免出现「菜单上没配、却能落在某个页面」
* 的第二入口(业务入口一律由 s_menu + 路由地址维护)。
* 这类裸前缀时交给表尾的 /:pathMatch(.*)* 渲染 404 缺省页,避免出现「菜单上没配、却能落在某个
* 页面」的第二入口(业务入口一律由 s_menu + 路由地址维护)。
* 子路由 path 写相对路径('module-management'),完整路径由父级拼接,
* 调整分组前缀时只需改父节点一处。
*/
@@ -213,16 +213,45 @@ export const routes = [
},
],
},
// 缺省页(应用内展示:保留侧栏 / 顶栏 / 页签,用户可直接切走或用侧栏导航):
// 403 由守卫跳转到达;500 供直接访问排查(渲染崩溃的兜底由 App 层
// ErrorBoundary 全屏渲染,不经过本路由)。
// componentName 不可省:布局的包装层按 name 缓存命名组件,无名页面会互相顶掉;
// 不设 meta.title:AppTabs 按 title 收录页签,缺省页不该出现在页签栏。
{
path: '/403',
name: 'fallback-403',
component: () => import('@/views/fallback/Forbidden.vue'),
meta: { componentName: 'Fallback403' },
},
{
path: '/500',
name: 'fallback-500',
component: () => import('@/views/fallback/ServerError.vue'),
meta: { componentName: 'Fallback500' },
},
],
},
// 404 兜住所有未知路径:独立布局(不挂 DefaultLayout)—— 未知路径与登录态无关,
// 未登录也要能看到;保留原地址不重定向,用户能看到自己输错的是什么。
// 不设 meta.title:AppTabs 按 title 收录页签,缺省页不该出现在页签栏。
{
path: '/:pathMatch(.*)*',
redirect: '/dashboard',
name: 'fallback-404',
component: () => import('@/views/fallback/FallbackPage.vue'),
props: { status: '404' },
},
]
/** 不作为菜单入口的路由:独立布局页(/login)与详情页(静态路径,无法靠动态段规则排除) */
const EXCLUDED_PATHS = new Set(['/login', '/base/othercompany/detail', '/base/contact/detail'])
/** 不作为菜单入口的路由:独立布局页(/login 与缺省页 /403 /500)与详情页(静态路径,
* 无法靠动态段规则排除)。catch-all 缺省路由含动态段,已被 collectMenuRoutes 的规则滤除 */
const EXCLUDED_PATHS = new Set([
'/login',
'/403',
'/500',
'/base/othercompany/detail',
'/base/contact/detail',
])
/**
* 收集可作为菜单入口的页面路由(递归展开布局容器与分组节点)。