diff --git a/src/App.vue b/src/App.vue
index 00d98e3..a6717f2 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,18 +1,43 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/src/AppMain.vue b/src/AppMain.vue
deleted file mode 100644
index 1a2dfc5..0000000
--- a/src/AppMain.vue
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main.ts b/src/main.ts
index 54ddfab..3980d9e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,5 +1,41 @@
+import type { App as AppType } from 'vue'
import App from './App.vue'
+import AppLoading from './components/common/AppLoading.vue'
+import { installPinia } from '@/store'
+import { installRouter } from '@/router'
-// 创建应用实例并挂载
-const app = createApp(App)
-app.mount('#app')
+async function bootstrap() {
+ // 显示加载动画
+ const loadingApp = createApp(AppLoading)
+ loadingApp.mount('#app')
+
+ try {
+ // 创建应用实例
+ const app = createApp(App)
+
+ // 注册模块 Pinia
+ await installPinia(app)
+
+ // 注册模块 Vue-router
+ await installRouter(app)
+
+ // 注册模块 指令/静态资源
+ const modules = import.meta.glob<{ install: (app: AppType) => void }>('./modules/*.ts', {
+ eager: true,
+ })
+
+ Object.values(modules).forEach(module => app.use(module))
+
+ // 卸载加载动画并挂载主应用
+ loadingApp.unmount()
+ app.mount('#app')
+ }
+ catch (error) {
+ // 如果初始化失败,卸载加载动画并显示错误
+ loadingApp.unmount()
+ console.error('Application initialization failed:', error)
+ throw error
+ }
+}
+
+bootstrap().catch(console.error)
diff --git a/src/router/guard.ts b/src/router/guard.ts
index ebbd98b..769d2a4 100644
--- a/src/router/guard.ts
+++ b/src/router/guard.ts
@@ -1,92 +1,142 @@
-import type { Router } from 'vue-router'
+import type { NavigationGuardNext, RouteLocationNormalized, Router } from 'vue-router'
import { useAppStore, useRouteStore, useTabStore } from '@/store'
import { local } from '@/utils'
const title = import.meta.env.VITE_APP_NAME
+// 路由上下文
+interface RouteContext {
+ appStore: ReturnType
+ routeStore: ReturnType
+ tabStore: ReturnType
+ isLogin: boolean
+}
+
+// 外链处理
+function handleExternalLink(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) {
+ if (to.meta.isLink) {
+ window.open(to.meta.linkPath as string)
+ next(false)
+ return true
+ }
+ return false
+}
+
+// 根路径重定向
+function handleRootPath(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext, context: RouteContext) {
+ if (to.path === '/') {
+ if (context.isLogin) {
+ next({ path: import.meta.env.VITE_HOME_PATH, replace: true })
+ }
+ else {
+ next({ path: '/login', replace: true })
+ }
+ return true
+ }
+ return false
+}
+
+// 登录页面访问处理
+function handleLoginPage(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext, context: RouteContext) {
+ if (to.name === 'login' && context.isLogin) {
+ next({ path: import.meta.env.VITE_HOME_PATH, replace: true })
+ return true
+ }
+ return false
+}
+
+// 认证检查
+function handleAuthentication(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext, context: RouteContext) {
+ if (!context.isLogin && to.name !== 'login' && to.meta?.requiresAuth !== false) {
+ const redirect = to.name === 'not-found' ? undefined : to.fullPath
+ next({ path: '/login', query: { redirect } })
+ return true
+ }
+ return false
+}
+
+// 路由初始化
+async function handleRouteInitialization(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext, context: RouteContext) {
+ if (context.isLogin && to.name !== 'login' && !context.routeStore.isInitAuthRoute) {
+ try {
+ await context.routeStore.initAuthRoute()
+
+ if (to.name === 'not-found') {
+ next({
+ path: to.fullPath,
+ replace: true,
+ query: to.query,
+ hash: to.hash,
+ })
+ return true
+ }
+ }
+ catch (error) {
+ console.error('Route initialization failed:', error)
+ local.remove('accessToken')
+ context.routeStore.resetRouteStore()
+ const redirect = to.fullPath !== '/' && to.fullPath !== '/login' ? to.fullPath : undefined
+ next({ path: '/login', query: redirect ? { redirect } : undefined, replace: true })
+ return true
+ }
+ }
+ return false
+}
+
+// 路由处理器列表
+const routeHandlers = [
+ handleExternalLink,
+ handleRootPath,
+ handleLoginPage,
+ handleAuthentication,
+ handleRouteInitialization,
+]
+
+// 处理路由
+async function processRoute(to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext, context: RouteContext) {
+ for (const handler of routeHandlers) {
+ const handled = await handler(to, from, next, context)
+ if (handled)
+ return
+ }
+
+ // 如果没有任何处理器处理该路由,则继续导航
+ next()
+}
+
export function setupRouterGuard(router: Router) {
const appStore = useAppStore()
const routeStore = useRouteStore()
const tabStore = useTabStore()
router.beforeEach(async (to, from, next) => {
- // 判断是否是外链,如果是直接打开网页并拦截跳转
- if (to.meta.isLink) {
- window.open(to.meta.linkPath)
- next(false) // 取消当前导航
- return
- }
// 开始 loadingBar
appStore.showProgress && window.$loadingBar?.start()
- // 判断有无TOKEN,登录鉴权
- const isLogin = Boolean(local.get('accessToken'))
-
- // 处理根路由重定向
- if (to.path === '/') {
- if (isLogin) {
- // 已登录,重定向到首页
- next({ path: import.meta.env.VITE_HOME_PATH, replace: true })
- }
- else {
- // 未登录,重定向到登录页
- next({ path: '/login', replace: true })
- }
- return
+ // 创建路由上下文
+ const context: RouteContext = {
+ appStore,
+ routeStore,
+ tabStore,
+ isLogin: Boolean(local.get('accessToken')),
}
- // 如果用户未登录,重定向到登录页
- if (!isLogin) {
- const redirect = to.name === 'not-found' ? undefined : to.fullPath
- next({ path: '/login', query: { redirect } })
- return
- }
-
- // 如果用户已登录且访问login页面,重定向到首页
- if (to.name === 'login' && isLogin) {
- next({ path: '/' })
- return
- }
-
- // 判断路由有无进行初始化
- if (!routeStore.isInitAuthRoute && to.name !== 'login') {
- try {
- await routeStore.initAuthRoute()
- // 动态路由加载完回到根路由
- if (to.name === 'not-found') {
- // 等待权限路由加载好了,回到之前的路由,否则404
- next({
- path: to.fullPath,
- replace: true,
- query: to.query,
- hash: to.hash,
- })
- return
- }
- }
- catch {
- // 如果路由初始化失败(比如 401 错误),重定向到登录页
- local.remove('accessToken')
- const redirect = to.fullPath !== '/' ? to.fullPath : undefined
- next({ path: '/login', query: redirect ? { redirect } : undefined })
- return
- }
- }
-
- next()
+ // 使用函数式处理路由
+ await processRoute(to, from, next, context)
})
+
router.beforeResolve((to) => {
// 设置菜单高亮
routeStore.setActiveMenu(to.meta.activePath ?? to.fullPath)
// 添加tabs
tabStore.addTab(to)
- // 设置高亮标签;
+ // 设置高亮标签
tabStore.setCurrentTab(to.fullPath as string)
})
router.afterEach((to) => {
// 修改网页标题
- document.title = `${to.meta.title} - ${title}`
+ document.title = `${to.meta.title || 'Nova Admin'} - ${title}`
// 结束 loadingBar
appStore.showProgress && window.$loadingBar?.finish()
})