前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题

This commit is contained in:
JEECG
2024-06-23 10:39:52 +08:00
parent bb918b742e
commit 0325e34dcb
1439 changed files with 171106 additions and 0 deletions

View File

@ -0,0 +1,147 @@
import type { Router, RouteLocationNormalized } from 'vue-router';
import { useAppStoreWithOut } from '/@/store/modules/app';
import { useUserStoreWithOut } from '/@/store/modules/user';
import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
import { Modal, notification } from 'ant-design-vue';
import { warn } from '/@/utils/log';
import { unref } from 'vue';
import { setRouteChange } from '/@/logics/mitt/routeChange';
import { createPermissionGuard } from './permissionGuard';
import { createStateGuard } from './stateGuard';
import nProgress from 'nprogress';
import projectSetting from '/@/settings/projectSetting';
import { createParamMenuGuard } from './paramMenuGuard';
// Don't change the order of creation
export function setupRouterGuard(router: Router) {
createPageGuard(router);
createPageLoadingGuard(router);
createHttpGuard(router);
createScrollGuard(router);
createMessageGuard(router);
createProgressGuard(router);
createPermissionGuard(router);
createParamMenuGuard(router); // must after createPermissionGuard (menu has been built.)
createStateGuard(router);
}
/**
* Hooks for handling page state
*/
function createPageGuard(router: Router) {
const loadedPageMap = new Map<string, boolean>();
router.beforeEach(async (to) => {
// The page has already been loaded, it will be faster to open it again, you dont need to do loading and other processing
to.meta.loaded = !!loadedPageMap.get(to.path);
// Notify routing changes
setRouteChange(to);
return true;
});
router.afterEach((to) => {
loadedPageMap.set(to.path, true);
});
}
// Used to handle page loading status
function createPageLoadingGuard(router: Router) {
const userStore = useUserStoreWithOut();
const appStore = useAppStoreWithOut();
const { getOpenPageLoading } = useTransitionSetting();
router.beforeEach(async (to) => {
if (!userStore.getToken) {
return true;
}
if (to.meta.loaded) {
return true;
}
if (unref(getOpenPageLoading)) {
appStore.setPageLoadingAction(true);
return true;
}
return true;
});
router.afterEach(async () => {
if (unref(getOpenPageLoading)) {
// TODO Looking for a better way
// The timer simulates the loading time to prevent flashing too fast,
setTimeout(() => {
appStore.setPageLoading(false);
}, 220);
}
return true;
});
}
/**
* The interface used to close the current page to complete the request when the route is switched
* @param router
*/
function createHttpGuard(router: Router) {
const { removeAllHttpPending } = projectSetting;
let axiosCanceler: Nullable<AxiosCanceler>;
if (removeAllHttpPending) {
axiosCanceler = new AxiosCanceler();
}
router.beforeEach(async () => {
// Switching the route will delete the previous request
axiosCanceler?.removeAllPending();
return true;
});
}
// Routing switch back to the top
function createScrollGuard(router: Router) {
const isHash = (href: string) => {
return /^#/.test(href);
};
const body = document.body;
router.afterEach(async (to) => {
// scroll top
isHash((to as RouteLocationNormalized & { href: string })?.href) && body.scrollTo(0, 0);
return true;
});
}
/**
* Used to close the message instance when the route is switched
* @param router
*/
export function createMessageGuard(router: Router) {
const { closeMessageOnSwitch } = projectSetting;
router.beforeEach(async () => {
try {
if (closeMessageOnSwitch) {
Modal.destroyAll();
notification.destroy();
}
} catch (error) {
warn('message guard error:' + error);
}
return true;
});
}
export function createProgressGuard(router: Router) {
const { getOpenNProgress } = useTransitionSetting();
router.beforeEach(async (to) => {
if (to.meta.loaded) {
return true;
}
unref(getOpenNProgress) && nProgress.start();
return true;
});
router.afterEach(async () => {
unref(getOpenNProgress) && nProgress.done();
return true;
});
}

View File

@ -0,0 +1,47 @@
import type { Router } from 'vue-router';
import { configureDynamicParamsMenu } from '../helper/menuHelper';
import { Menu } from '../types';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { useAppStoreWithOut } from '/@/store/modules/app';
import { usePermissionStoreWithOut } from '/@/store/modules/permission';
export function createParamMenuGuard(router: Router) {
const permissionStore = usePermissionStoreWithOut();
router.beforeEach(async (to, _, next) => {
// filter no name route
if (!to.name) {
next();
return;
}
// menu has been built.
if (!permissionStore.getIsDynamicAddedRoute) {
next();
return;
}
let menus: Menu[] = [];
if (isBackMode()) {
menus = permissionStore.getBackMenuList;
} else if (isRouteMappingMode()) {
menus = permissionStore.getFrontMenuList;
}
menus.forEach((item) => configureDynamicParamsMenu(item, to.params));
next();
});
}
const getPermissionMode = () => {
const appStore = useAppStoreWithOut();
return appStore.getProjectConfig.permissionMode;
};
const isBackMode = () => {
return getPermissionMode() === PermissionModeEnum.BACK;
};
const isRouteMappingMode = () => {
return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING;
};

View File

@ -0,0 +1,206 @@
import type { Router, RouteRecordRaw } from 'vue-router';
import { usePermissionStoreWithOut } from '/@/store/modules/permission';
import { PageEnum } from '/@/enums/pageEnum';
import { useUserStoreWithOut } from '/@/store/modules/user';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { RootRoute } from '/@/router/routes';
import { isOAuth2AppEnv } from '/@/views/sys/login/useLogin';
import { OAUTH2_THIRD_LOGIN_TENANT_ID } from "/@/enums/cacheEnum";
import { setAuthCache } from "/@/utils/auth";
const LOGIN_PATH = PageEnum.BASE_LOGIN;
//auth2登录路由
const OAUTH2_LOGIN_PAGE_PATH = PageEnum.OAUTH2_LOGIN_PAGE_PATH;
//分享免登录路由
const SYS_FILES_PATH = PageEnum.SYS_FILES_PATH;
// 邮件中的跳转地址,对应此路由,携带token免登录直接去办理页面
const TOKEN_LOGIN = PageEnum.TOKEN_LOGIN;
const ROOT_PATH = RootRoute.path;
//update-begin---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3不支持auth2登录------------
//update-begin---author:wangshuai ---date:20221111 for: [VUEN-2472]分享免登录------------
const whitePathList: PageEnum[] = [LOGIN_PATH, OAUTH2_LOGIN_PAGE_PATH,SYS_FILES_PATH, TOKEN_LOGIN ];
//update-end---author:wangshuai ---date:20221111 for: [VUEN-2472]分享免登录------------
//update-end---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3不支持auth2登录------------
export function createPermissionGuard(router: Router) {
const userStore = useUserStoreWithOut();
const permissionStore = usePermissionStoreWithOut();
router.beforeEach(async (to, from, next) => {
if (
from.path === ROOT_PATH &&
to.path === PageEnum.BASE_HOME &&
userStore.getUserInfo.homePath &&
userStore.getUserInfo.homePath !== PageEnum.BASE_HOME
) {
next(userStore.getUserInfo.homePath);
return;
}
const token = userStore.getToken;
// Whitelist can be directly entered
if (whitePathList.includes(to.path as PageEnum)) {
if (to.path === LOGIN_PATH && token) {
const isSessionTimeout = userStore.getSessionTimeout;
//update-begin---author:scott ---date:2023-04-24 for【QQYUN-4713】登录代码调整逻辑有问题改造待观察--
//TODO vben默认写法暂时不知目的有问题暂时先注释掉
//await userStore.afterLoginAction();
//update-end---author:scott ---date::2023-04-24 for【QQYUN-4713】登录代码调整逻辑有问题改造待观察--
try {
if (!isSessionTimeout) {
next((to.query?.redirect as string) || '/');
return;
}
} catch {}
//update-begin---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3不支持auth2登录------------
} else if (to.path === LOGIN_PATH && isOAuth2AppEnv() && !token) {
//退出登录进入此逻辑
//如果进入的页面是login页面并且当前是OAuth2app环境并且token为空就进入OAuth2登录页面
//update-begin---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
if(to.query.tenantId){
setAuthCache(OAUTH2_THIRD_LOGIN_TENANT_ID,to.query.tenantId)
}
next({ path: OAUTH2_LOGIN_PAGE_PATH });
//update-end---author:wangshuai ---date:20230224 for[QQYUN-3440]新建企业微信和钉钉配置表,通过租户模式隔离------------
return;
//update-end---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3不支持auth2登录------------
}
next();
return;
}
// token does not exist
if (!token) {
// You can access without permission. You need to set the routing meta.ignoreAuth to true
if (to.meta.ignoreAuth) {
next();
return;
}
//update-begin---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3 Auth2未实现------------
let path = LOGIN_PATH;
if (whitePathList.includes(to.path as PageEnum)) {
// 在免登录白名单如果进入的页面是login页面并且当前是OAuth2app环境就进入OAuth2登录页面
if (to.path === LOGIN_PATH && isOAuth2AppEnv()) {
next({ path: OAUTH2_LOGIN_PAGE_PATH });
} else {
//在免登录白名单,直接进入
next();
}
} else {
//update-begin---author:wangshuai ---date:20230302 for只有首次登陆并且是企业微信或者钉钉的情况下才会调用------------
//----------【首次登陆并且是企业微信或者钉钉的情况下才会调用】-----------------------------------------------
//只有首次登陆并且是企业微信或者钉钉的情况下才会调用
let href = window.location.href;
//判断当前是auth2页面并且是钉钉/企业微信并且包含tenantId参数
if(isOAuth2AppEnv() && href.indexOf("/tenantId/")!= -1){
let params = to.params;
if(params && params.path && params.path.length>0){
//直接获取参数最后一位
setAuthCache(OAUTH2_THIRD_LOGIN_TENANT_ID,params.path[params.path.length-1])
}
}
//---------【首次登陆并且是企业微信或者钉钉的情况下才会调用】------------------------------------------------
//update-end---author:wangshuai ---date:20230302 for只有首次登陆并且是企业微信或者钉钉的情况下才会调用------------
// 如果当前是在OAuth2APP环境就跳转到OAuth2登录页面否则跳转到登录页面
path = isOAuth2AppEnv() ? OAUTH2_LOGIN_PAGE_PATH : LOGIN_PATH;
}
//update-end---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3 Auth2未实现------------
// redirect login page
const redirectData: { path: string; replace: boolean; query?: Recordable<string> } = {
//update-begin---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3 Auth2未实现------------
path: path,
//update-end---author:wangshuai ---date:20220629 for[issues/I5BG1I]vue3 Auth2未实现------------
replace: true,
};
//update-begin---author:scott ---date:2023-04-24 for【QQYUN-4713】登录代码调整逻辑有问题改造待观察--
if (to.fullPath) {
console.log("to.fullPath 1",to.fullPath)
console.log("to.path 2",to.path)
let getFullPath = to.fullPath;
if(getFullPath=='/' || getFullPath=='/500' || getFullPath=='/400' || getFullPath=='/login?redirect=/' || getFullPath=='/login?redirect=/login?redirect=/'){
return;
}
//update-end---author:scott ---date:2023-04-24 for【QQYUN-4713】登录代码调整逻辑有问题改造待观察--
redirectData.query = {
...redirectData.query,
// update-begin-author:sunjianlei date:20230306 for: 修复登录成功后,没有正确重定向的问题
redirect: to.fullPath,
// update-end-author:sunjianlei date:20230306 for: 修复登录成功后,没有正确重定向的问题
};
}
next(redirectData);
return;
}
//==============================【首次登录并且是企业微信或者钉钉的情况下才会调用】==================
//判断是免登录页面,如果页面包含/tenantId/,那么就直接前往主页
if(isOAuth2AppEnv() && to.path.indexOf("/tenantId/") != -1){
next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
return;
}
//==============================【首次登录并且是企业微信或者钉钉的情况下才会调用】==================
// Jump to the 404 page after processing the login
if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_ROUTE.name && to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME)) {
next(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);
return;
}
//update-begin---author:scott ---date:2024-02-21 for【QQYUN-8326】刷新首页不需要重新获取用户信息---
// // get userinfo while last fetch time is empty
// if (userStore.getLastUpdateTime === 0) {
// try {
// console.log("--LastUpdateTime---getUserInfoAction-----")
// await userStore.getUserInfoAction();
// } catch (err) {
// console.info(err);
// next();
// }
// }
//update-end---author:scott ---date::2024-02-21 for【QQYUN-8326】刷新首页不需要重新获获取用户信息---
// update-begin--author:liaozhiyang---date:20240321---for【QQYUN-8572】表格行选择卡顿问题customRender中字典引起的
if (userStore.getLastUpdateTime === 0) {
userStore.setAllDictItemsByLocal();
}
// update-end--author:liaozhiyang---date:20240321---for【QQYUN-8572】表格行选择卡顿问题customRender中字典引起的
if (permissionStore.getIsDynamicAddedRoute) {
next();
return;
}
// 构建后台菜单路由
const routes = await permissionStore.buildRoutesAction();
routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw);
});
router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
permissionStore.setDynamicAddedRoute(true);
if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
// 动态添加路由后此处应当重定向到fullPath否则会加载404页面内容
next({ path: to.fullPath, replace: true, query: to.query });
} else {
const redirectPath = (from.query.redirect || to.path) as string;
const redirect = decodeURIComponent(redirectPath);
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect };
next(nextData);
}
});
}

View File

@ -0,0 +1,24 @@
import type { Router } from 'vue-router';
import { useAppStore } from '/@/store/modules/app';
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
import { useUserStore } from '/@/store/modules/user';
import { usePermissionStore } from '/@/store/modules/permission';
import { PageEnum } from '/@/enums/pageEnum';
import { removeTabChangeListener } from '/@/logics/mitt/routeChange';
export function createStateGuard(router: Router) {
router.afterEach((to) => {
// Just enter the login page and clear the authentication information
if (to.path === PageEnum.BASE_LOGIN) {
const tabStore = useMultipleTabStore();
const userStore = useUserStore();
const appStore = useAppStore();
const permissionStore = usePermissionStore();
appStore.resetAllState();
permissionStore.resetState();
tabStore.resetState();
userStore.resetState();
removeTabChangeListener();
}
});
}