feat: Architecture initialization

This commit is contained in:
2026-07-14 10:31:17 +08:00
commit 6f37264047
59 changed files with 8752 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
import { createRouter, createWebHistory } from 'vue-router';
import { routes } from './routes';
import { auth } from '@/hooks/useAuth';
const router = createRouter({
history: createWebHistory(import.meta.env.VITE_BASE_URL || '/'),
routes,
scrollBehavior: () => ({ left: 0, top: 0 }),
});
// 路由守卫:登录鉴权 + 页面标题
router.beforeEach((to, _from, next) => {
const isLoggedIn = auth.isLoggedIn();
// 设置页面标题
const appTitle = import.meta.env.VITE_APP_TITLE || 'CPMS 运营平台';
document.title = to.meta.title ? `${to.meta.title} - ${appTitle}` : appTitle;
// 如果访问的是登录页
if (to.path === '/login') {
if (isLoggedIn) {
// 已登录则重定向到首页
next('/dashboard');
} else {
// 未登录则允许访问登录页
next();
}
} else {
// 访问其他页面
if (isLoggedIn) {
// 已登录则允许访问
next();
} else {
// 未登录则重定向到登录页
next('/login');
}
}
});
export default router;
+68
View File
@@ -0,0 +1,68 @@
import type { RouteRecordRaw } from 'vue-router';
import { createRoute } from './utils';
/**
* ====== 业务路由模块 ======
* 实际项目中按模块拆分,如 eventsRoutes、walletRoutes 等,
* 然后在下方 routes 数组的布局 children 中引入。
* 参考示例(嵌套路由):
*
* const eventsRoutes = {
* path: '/events',
* name: 'EventsModule',
* redirect: '/events/list',
* meta: { title: '我的赛事', activeMenu: '/events' },
* children: [
* createRoute('list', () => import('@/pages/events/list'), { title: '赛事列表' }),
* {
* path: 'bracket',
* name: 'BracketPage',
* component: () => import('@/pages/events/bracket'),
* meta: { title: '赛事详情' },
* children: [
* createRoute('player-management', () => import('@/pages/events/bracket/player-management'), { title: '选手管理' }),
* createRoute('match-result', () => import('@/pages/events/bracket/match-result'), { title: '比赛结果' }),
* ],
* },
* ],
* };
*/
export const routes: RouteRecordRaw[] = [
// ── 登录页(不经过布局)──
{
path: '/login',
name: 'Login',
component: () => import('@/pages/login'),
meta: { title: '登录' },
},
// ── 主布局(需要登录)──
{
path: '/',
component: () => import('@/layouts/BasicLayout'),
children: [
// 业务模块路由在此添加,例如:eventsRoutes, walletRoutes
createRoute('/dashboard', () => import('@/views/Dashboard'), {
title: '工作台',
icon: 'DashboardOutlined',
}),
createRoute('/about', () => import('@/views/About'), {
title: '关于',
icon: 'InfoCircleOutlined',
}),
// 默认重定向
{ path: '/', redirect: '/dashboard' },
],
},
// ── 404 ──
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/views/NotFound'),
meta: { title: '页面不存在' },
},
];
+40
View File
@@ -0,0 +1,40 @@
import type { RouteRecordRaw } from 'vue-router';
/** 路由 meta 类型 */
export type AppMeta = {
title: string;
icon?: string;
hideInMenu?: boolean;
activeMenu?: string;
};
/**
* 快速创建路由记录
* 根据路径自动生成 PascalCase 路由 name
*
* @example
* createRoute('list', () => import('@/pages/home'), { title: '赛事列表' })
* // => { path: 'list', name: 'List', meta: {...}, component: ... }
*/
export function createRoute(
path: string,
component: RouteRecordRaw['component'],
meta: AppMeta,
children: RouteRecordRaw[] = [],
): RouteRecordRaw {
const cleanPath = path.replace(/[:/]/g, '-');
const name = cleanPath
.split('-')
.filter(Boolean)
.map((p) => p.charAt(0).toUpperCase() + p.slice(1))
.join('');
return {
path,
name: name || undefined,
meta,
component,
children,
};
}