feat(other): init

This commit is contained in:
2026-01-19 03:06:04 +08:00
commit 2b97d4ef6c
195 changed files with 30912 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
import { createPageLoadingGuard } from './page-loading-guard'
import { createPageTitleGuard } from './page-title-guard'
import { createPermissionGuard } from './permission-guard'
export function setupRouterGuard(router) {
createPageLoadingGuard(router)
createPermissionGuard(router)
createPageTitleGuard(router)
}

View File

@@ -0,0 +1,15 @@
export function createPageLoadingGuard(router) {
router.beforeEach(() => {
window.$loadingBar?.start()
})
router.afterEach(() => {
setTimeout(() => {
window.$loadingBar?.finish()
}, 200)
})
router.onError(() => {
window.$loadingBar?.error()
})
}

View File

@@ -0,0 +1,12 @@
const baseTitle = import.meta.env.VITE_TITLE
export function createPageTitleGuard(router) {
router.afterEach((to) => {
const pageTitle = to.meta?.title
if (pageTitle) {
document.title = `${pageTitle} | ${baseTitle}`
} else {
document.title = baseTitle
}
})
}

View File

@@ -0,0 +1,34 @@
import { getToken, isNullOrWhitespace } from '@/utils'
import { addDynamicRoutes } from '@/router'
const WHITE_LIST = ['/login', '/404']
export function createPermissionGuard(router) {
router.beforeEach(async (to) => {
const token = getToken()
/** 没有token的情况 */
if (isNullOrWhitespace(token)) {
if (WHITE_LIST.includes(to.path)) return true
return { path: 'login', query: { ...to.query, redirect: to.path } }
}
/** 有token的情况 */
if (to.path === '/login') return { path: '/' }
// 确保动态路由已加载
if (token && !router.hasRoute('Dashboard')) {
try {
await addDynamicRoutes()
// 如果当前路径不存在,重定向到工作台
if (to.path !== '/' && !router.hasRoute(to.name)) {
return { path: '/workbench' }
}
} catch (error) {
console.error('动态路由加载失败:', error)
return { path: '/login' }
}
}
return true
})
}

87
src/router/index.js Normal file
View File

@@ -0,0 +1,87 @@
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import { setupRouterGuard } from './guard'
import { basicRoutes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
import { getToken, isNullOrWhitespace } from '@/utils'
import { usePermissionStore } from '@/store'
const isHash = false
export const router = createRouter({
history: isHash ? createWebHashHistory('/') : createWebHistory('/'),
routes: basicRoutes,
scrollBehavior: () => ({ left: 0, top: 0 }),
})
export async function setupRouter(app) {
await addDynamicRoutes()
setupRouterGuard(router)
app.use(router)
}
export async function addDynamicRoutes() {
const token = getToken()
// 没有token情况
if (isNullOrWhitespace(token)) {
router.addRoute(EMPTY_ROUTE)
return
}
// 有token的情况
try {
const permissionStore = usePermissionStore()
const accessRoutes = permissionStore.generateRoutes()
// 确保路由按正确顺序添加
accessRoutes.forEach((route) => {
if (!router.hasRoute(route.name)) {
router.addRoute(route)
}
})
// 移除空路由添加404路由
if (router.hasRoute(EMPTY_ROUTE.name)) {
router.removeRoute(EMPTY_ROUTE.name)
}
router.addRoute(NOT_FOUND_ROUTE)
// 确保根路径重定向到工作台
// if (!router.hasRoute('workbench')) {
// const workbenchRoute = {
// name: 'workbench',
// path: '/',
// component: () => import('@/views/workbench/index.vue'),
// redirect: '/workbench',
// // children: [
// // {
// // name: 'Workbench',
// // path: 'workbench',
// // component: () => import('@/views/workbench/index.vue'),
// // meta: {
// // title: '工作台',
// // icon: 'mdi:index',
// // order: 0,
// // },
// // },
// // ],
// }
// router.addRoute(workbenchRoute)
// }
// console.log(router)
} catch (error) {
console.error(error)
throw error
}
}
export function getRouteNames(routes) {
return routes.map((route) => getRouteName(route)).flat(1)
}
function getRouteName(route) {
const names = [route.name]
if (route.subMenu && route.subMenu.length) {
names.push(...route.subMenu.map((item) => getRouteName(item)).flat(1))
}
return names
}

View File

@@ -0,0 +1,31 @@
export const basicRoutes = [
{
name: '404',
path: '/404',
component: () => import('@/views/error-page/404.vue'),
isHidden: true,
},
{
name: 'Login',
path: '/login',
component: () => import('@/views/login/index.vue'),
isHidden: true,
meta: {
title: '登录页',
},
},
]
export const NOT_FOUND_ROUTE = {
name: 'NotFound',
path: '/:pathMatch(.*)*',
redirect: '/404',
isHidden: true,
}
export const EMPTY_ROUTE = {
name: 'Empty',
path: '/:pathMatch(.*)*',
component: null,
}