task-2(壳层/路由): 冻结 /admin-vue/ base 与 History 路由契约为单一事实源

新增 src/config/app.ts(APP_BASE_PATH/ensureAppBasePath/joinAdminPath),
vite.config base、router createWebHistory、AdminLayout logo 路径统一消费常量,
禁止散落字面量;8 用例覆盖归一化/幂等/空段/单段/非法输入与字面量单源。
This commit is contained in:
2026-09-05 12:13:19 +08:00
parent ec7d56d566
commit 6f0357e41c
6 changed files with 338 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
import { createRouter, createWebHistory } from 'vue-router'
import type { AdminMenuNode } from '@/types/admin'
import AdminLayout from '@/layout/AdminLayout.vue'
import { useAdminSessionStore } from '@/stores/admin-session'
import { findFirstRoute } from './helpers'
import { APP_BASE_PATH } from '@/config/app'
const router = createRouter({
history: createWebHistory(APP_BASE_PATH),
routes: [
{
path: '/',
component: AdminLayout,
children: [
{ path: '', redirect: '/account/users' },
{ path: 'account/users', component: () => import('@/pages/account/UsersPage.vue'), meta: { menuKey: 'admin_users', title: '用户管理' } },
{ path: 'account/menus', component: () => import('@/pages/account/MenusPage.vue'), meta: { menuKey: 'admin_columns', title: '菜单管理' } },
{ path: 'account/groups', component: () => import('@/pages/account/GroupsPage.vue'), meta: { menuKey: 'admin_group_manage', title: '数据权限分组' } },
],
},
],
})
router.beforeEach(async (to) => {
const session = useAdminSessionStore()
if (!session.initialized) {
try {
await session.initialize()
} catch {
return false
}
}
if (to.path === '/') return findFirstRoute(session.menuTree)
const menuKey = to.meta.menuKey as string | undefined
if (menuKey && !session.isSuperAdmin && !hasMenu(session.menuTree, menuKey)) {
return findFirstRoute(session.menuTree)
}
return true
})
function hasMenu(nodes: AdminMenuNode[], key: string): boolean {
return nodes.some((node) => node.key === key || hasMenu(node.children || [], key))
}
export default router