feat: 前端搭建

This commit is contained in:
Gsh
2025-06-17 22:37:37 +08:00
parent 4830be6388
commit 0cd795f57a
1228 changed files with 23627 additions and 1 deletions

View File

@@ -0,0 +1,81 @@
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
import { useNProgress } from '@vueuse/integrations/useNProgress';
import { createRouter, createWebHistory } from 'vue-router';
import { ROUTER_WHITE_LIST } from '@/config';
import { errorRouter, layoutRouter, staticRouter } from '@/routers/modules/staticRouter';
import { useUserStore } from '@/stores';
const { start, done } = useNProgress(0, {
showSpinner: false,
trickleSpeed: 200,
minimum: 0.3,
easing: 'ease',
speed: 500,
});
const router = createRouter({
history: createWebHistory(),
routes: [...layoutRouter, ...staticRouter, ...errorRouter],
strict: false,
scrollBehavior: () => ({ left: 0, top: 0 }),
});
// 路由前置守卫
router.beforeEach(
async (
to: RouteLocationNormalized,
_from: RouteLocationNormalized,
next: NavigationGuardNext,
) => {
const userStore = useUserStore();
// 1、NProgress 开始
start();
// 2、标题
document.title = (to.meta.title as string) || (import.meta.env.VITE_WEB_TITLE as string);
// 3、权限 预留
// 3、判断是访问登陆页有Token访问当前页面token过期访问接口axios封装则自动跳转登录页面没有Token重置路由到登陆页。
// if (to.path.toLocaleLowerCase() === LOGIN_URL) {
// // 有Token访问当前页面
// if (userStore.token) {
// return next(from.fullPath);
// }
// else {
// ElMessage.error('账号身份已过期,请重新登录');
// }
// // 没有Token重置路由到登陆页。
// // resetRouter(); // 预留
// return next();
// }
// 4、判断访问页面是否在路由白名单地址[静态路由]中,如果存在直接放行。
if (ROUTER_WHITE_LIST.includes(to.path))
return next();
// 5、判断是否有 Token没有重定向到 login 页面。
if (!userStore.token)
userStore.logout();
// 其余逻辑 预留...
// 6、正常访问页面。
next();
},
);
// 路由跳转错误
router.onError((error) => {
// 结束全屏动画
done();
console.warn('路由错误', error.message);
});
// 后置路由
router.afterEach(() => {
// 结束全屏动画
done();
});
export default router;

View File

@@ -0,0 +1,39 @@
// 预留
import router from '@/routers/index';
import { useUserStore } from '@/stores';
import { useAuthStore } from '@/stores/modules/auth';
export async function initDynamicRouter() {
const userStore = useUserStore();
const authStore = useAuthStore();
try {
// 1、预留 获取菜单列表 || 按钮权限列表 || 递归菜单数据
await authStore.requestAuthMenuList();
// 2、判断当前用户是否拥有菜单权限
// console.log('authStore.authMenuList', authStore.authMenuList);
if (authStore.authMenuList == null || authStore.authMenuList.length === 0) {
userStore.logout();
return;
}
// 3、添加动态路由
authStore.authMenuList.forEach((item: any) => {
if (item.isFull === '0') {
// 如果是全屏的话,直接为整个页面
router.addRoute(item);
}
else {
router.addRoute('layout', item);
}
});
}
catch (error) {
console.log(error);
// 当菜单请求出错时,重定向到首页
userStore.logout();
return Promise.reject(error);
}
}

View File

@@ -0,0 +1,78 @@
import type { RouteRecordRaw } from 'vue-router';
import { HOME_URL } from '@/config';
// LayoutRouter[布局路由]
export const layoutRouter: RouteRecordRaw[] = [
{
path: '/',
redirect: HOME_URL,
component: () => import('@/layouts/index.vue'),
children: [
{
path: HOME_URL,
name: 'chat',
component: () => import('@/pages/chat/index.vue'),
meta: {
// title: '通用聊天页面',
isDefaultChat: true,
icon: 'HomeFilled',
// isHide: '1', // 是否在菜单中隐藏[0是1否] 预留
// isKeepAlive: '0', // 是否缓存路由数据[0是1否] 预留
// isFull: '1', // 是否全屏[0是1否] 预留
// enName: "Master Station", // 英文名称 预留
},
},
{
path: '/chat/:id',
name: 'chatWithId',
component: () => import('@/pages/chat/index.vue'),
meta: {
// title: '带 ID 的聊天页面',
isDefaultChat: false,
},
},
],
},
];
// staticRouter[静态路由] 预留
export const staticRouter: RouteRecordRaw[] = [];
// errorRouter (错误页面路由)
export const errorRouter = [
{
path: '/403',
name: '403',
component: () => import('@/pages/error/403.vue'),
meta: {
title: '403页面',
enName: '403 Page', // 英文名称
icon: 'QuestionFilled', // 菜单图标
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏1显示]
isLink: '1', // 是否外链[有值则是外链]
isKeepAlive: '0', // 是否缓存路由数据[0是1否]
isFull: '1', // 是否缓存全屏[0是1否]
isAffix: '1', // 是否缓存固定路由[0是1否]
},
},
{
path: '/404',
name: '404',
component: () => import('@/pages/error/404.vue'),
meta: {
title: '404页面',
enName: '404 Page', // 英文名称
icon: 'CircleCloseFilled', // 菜单图标
isHide: '1', // 代表路由在菜单中是否隐藏,是否隐藏[0隐藏1显示]
isLink: '1', // 是否外链[有值则是外链]
isKeepAlive: '0', // 是否缓存路由数据[0是1否]
isFull: '1', // 是否缓存全屏[0是1否]
isAffix: '1', // 是否缓存固定路由[0是1否]
},
},
// 找不到path将跳转404页面
{
path: '/:pathMatch(.*)*',
component: () => import('@/pages/error/404.vue'),
},
];

View File

@@ -0,0 +1,13 @@
import type {
_Awaitable,
NavigationGuardNext,
NavigationGuardReturn,
RouteLocationNormalized,
RouteLocationNormalizedLoaded,
} from 'vue-router';
export type NavigationGuard = (
to: RouteLocationNormalized,
from: RouteLocationNormalizedLoaded,
next: NavigationGuardNext,
) => _Awaitable<NavigationGuardReturn>;