push
This commit is contained in:
102
lib/saas/router/guard/permission-guard.ts
Normal file
102
lib/saas/router/guard/permission-guard.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
|
||||
|
||||
import type { Router } from 'vue-router';
|
||||
import { NsMessage } from '/nerv-lib/component/message';
|
||||
import { authorizationService } from '/nerv-base/store/modules/authorization-service';
|
||||
import { appConfigStore } from '/nerv-base/store/modules/app-config';
|
||||
import { Cookies } from '/nerv-lib/util/cookie';
|
||||
import { setRouteChange } from '/nerv-lib/util/routeChange';
|
||||
export function createPermissionGuard(router: Router, whiteNameList: string[]) {
|
||||
const authorizationStore = authorizationService();
|
||||
const appConfig = appConfigStore();
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if (!appConfig.userCustomRouterGuard) {
|
||||
setRouteChange(to);
|
||||
if (to?.query?.nervsid) {
|
||||
if (to?.query?.nervsid !== Cookies.get('nervsid')) {
|
||||
Cookies.set('nervsid', to?.query?.nervsid);
|
||||
try {
|
||||
const info = await appConfig.userInfo();
|
||||
await authorizationStore.initUserResource();
|
||||
authorizationStore.initMenuResource();
|
||||
appConfig.setUserInfo(info.data);
|
||||
info.success
|
||||
? window.sessionStorage.setItem('userInfo', JSON.stringify(info.data))
|
||||
: '';
|
||||
} catch (err) {
|
||||
Cookies.remove('nervsid');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
!Cookies.get('nervsid') &&
|
||||
to.fullPath !== '/login' &&
|
||||
to.name &&
|
||||
!whiteNameList.includes(to.name as string)
|
||||
) {
|
||||
NsMessage.error('登陆信息已过期,请重新登录!', 1);
|
||||
next({ name: 'login' });
|
||||
} else {
|
||||
// 存储用户信息
|
||||
|
||||
if (to.fullPath !== '/login') {
|
||||
const initUserInfo = window.sessionStorage['userInfo'];
|
||||
if (!initUserInfo && Cookies.get('nervsid')) {
|
||||
try {
|
||||
const info = await appConfig.userInfo();
|
||||
info.success
|
||||
? window.sessionStorage.setItem('userInfo', JSON.stringify(info.data))
|
||||
: '';
|
||||
} catch (err) {
|
||||
Cookies.remove('nervsid');
|
||||
}
|
||||
} else {
|
||||
if (initUserInfo) {
|
||||
const userInfo = JSON.parse(initUserInfo);
|
||||
authorizationStore.setEnterpriseName(
|
||||
!userInfo.organizationalName ? '' : userInfo.organizationalName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (to.name && !whiteNameList.includes(to.name as string)) {
|
||||
if (appConfig.enablePermissions !== undefined && appConfig.enablePermissions) {
|
||||
if (authorizationStore.getInitRouterList.length === 0) {
|
||||
await authorizationStore.initUserResource();
|
||||
}
|
||||
|
||||
if (
|
||||
authorizationStore.checkPermissionRouter(
|
||||
to.meta?.bindView ? to.meta?.bindView : to.name,
|
||||
)
|
||||
) {
|
||||
next();
|
||||
} else {
|
||||
if (to.path === '/') {
|
||||
next({ name: authorizationStore.getInitRouterList[0] });
|
||||
} else {
|
||||
// console.log(authorizationStore.getInitRouterList);
|
||||
NsMessage.error('无该页面权限!');
|
||||
next({ name: 'error403' });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await appConfig.userCustomRouterGuard(
|
||||
to,
|
||||
from,
|
||||
next,
|
||||
whiteNameList,
|
||||
authorizationStore,
|
||||
appConfig,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
143
lib/saas/router/helper/menu-helper.ts
Normal file
143
lib/saas/router/helper/menu-helper.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { dynamicImportRoute, getComponent } from '/nerv-base/router/helper/view-helper';
|
||||
import { routeModule } from '/nerv-base/router/routes';
|
||||
|
||||
export interface RouteMenu {
|
||||
code: string; //组件名
|
||||
name?: string;
|
||||
label: string;
|
||||
sort: number;
|
||||
parentCode?: string;
|
||||
backApi?: Recordable[]; //组件内所使用的Api
|
||||
route?: RouteRecordRaw;
|
||||
menus?: RouteMenu[];
|
||||
type?: string; //三种类型 menus菜单 noChildrenMenu不渲染该菜单下的子菜单 op操作
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换权限菜单到路由
|
||||
* @param menu
|
||||
* @param parentCode
|
||||
*/
|
||||
export function transformMenuToRoute(menu: RouteMenu, parentCode = '') {
|
||||
const { route, menus } = menu;
|
||||
if (route.component) {
|
||||
route.component = dynamicImportRoute(route.component);
|
||||
}
|
||||
|
||||
const _route: RouteRecordRaw = {
|
||||
...route,
|
||||
};
|
||||
if (menus) {
|
||||
_route.children = transformMenus(menus);
|
||||
}
|
||||
return _route;
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换权限菜单列表到路由列表
|
||||
* @param menus
|
||||
*/
|
||||
export function transformMenus(menus: RouteMenu[]): RouteRecordRaw[] {
|
||||
const list = [];
|
||||
for (let i = 0, l = menus.length; i < l; i++) {
|
||||
list.push(transformMenuToRoute(menus[i]));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
export function sortMenu(menus: RouteMenu[]) {
|
||||
menus.sort((a: RouteMenu, b: RouteMenu) => {
|
||||
return a.sort - b.sort;
|
||||
});
|
||||
return menus;
|
||||
}
|
||||
|
||||
export function dropMenu(menus, info) {
|
||||
const { dragNode: menu, node: target, dropToGap, dropPosition } = info;
|
||||
if (
|
||||
(target.parentCode !== menu.parentCode && target.code !== menu.parentCode) ||
|
||||
(target.parentCode !== '' && dropToGap === false)
|
||||
) {
|
||||
return {
|
||||
success: false,
|
||||
msg: '只在栏目内移动',
|
||||
};
|
||||
}
|
||||
const list = getMenusArray(menus, menu);
|
||||
// 移到当前栏目最顶部
|
||||
if (target.code === menu.parentCode) {
|
||||
}
|
||||
|
||||
moveMenuItem(list, menu.code, dropPosition, dropToGap);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
menus,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得移动的最终数组对象
|
||||
* @param menus
|
||||
* @param menu
|
||||
*/
|
||||
export function getMenusArray(menus, menu) {
|
||||
let list: RouteMenu[] = [];
|
||||
const index = -1;
|
||||
|
||||
function _getMenuArray(menus, menu) {
|
||||
for (let i = 0, l = menus.length; i < l; i++) {
|
||||
if (menus[i].code === menu.parentCode) {
|
||||
list = menus[i];
|
||||
return;
|
||||
} else if (menus[i].menus) {
|
||||
_getMenuArray(menus[i].menus, menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (menu.parentCode === '') {
|
||||
return menus;
|
||||
}
|
||||
_getMenuArray(menus, menu);
|
||||
|
||||
return list.menus;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组内移动
|
||||
* @param menus
|
||||
* @param dragNodeCode
|
||||
* @param dropPosition
|
||||
* @param dropToGap
|
||||
*/
|
||||
function moveMenuItem(menus, dragNodeCode, dropPosition, dropToGap) {
|
||||
const index = menus.findIndex((item) => dragNodeCode === item.code);
|
||||
const _menus = menus.splice(index, 1);
|
||||
if (dropToGap === false) {
|
||||
menus.unshift(_menus[0]);
|
||||
} else {
|
||||
if (index < dropPosition) {
|
||||
dropPosition--;
|
||||
}
|
||||
if (dropPosition === -1) dropPosition = 0;
|
||||
menus.splice(dropPosition, 0, _menus[0]);
|
||||
}
|
||||
for (let i = 0, l = menus.length; i < l; i++) {
|
||||
menus[i].sort = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
export function editMenuLabel(menus: RouteMenu[], code: string, newLabel: string) {
|
||||
for (let i = 0, l = menus.length; i < l; i++) {
|
||||
if (menus[i].code === code) {
|
||||
menus[i].label = newLabel;
|
||||
// menus[i].route.meta.title = newLabel;
|
||||
return;
|
||||
}
|
||||
if (menus[i].menus) {
|
||||
editMenuLabel(menus[i].menus as RouteMenu[], code, newLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
lib/saas/router/helper/route-helper.ts
Normal file
82
lib/saas/router/helper/route-helper.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { getComponent } from '/nerv-base/router/helper/view-helper';
|
||||
import { ModuleMenu } from '/nerv-base/router/types';
|
||||
import { RouteMenu, sortMenu } from '/nerv-base/router/helper/menu-helper';
|
||||
import { isNumber } from 'lodash-es';
|
||||
|
||||
export function transformRouteToMenu(route: RouteRecordRaw, parentCode = '') {
|
||||
const { children, ...extend } = route;
|
||||
if (extend.component) {
|
||||
const component = getComponent(extend.component.toString());
|
||||
component && (extend.component = component as any);
|
||||
}
|
||||
const code: any = route.meta?.code || route.name || '';
|
||||
if (!extend.meta) extend.meta = {};
|
||||
if (extend.meta.index === undefined || !isNumber(extend.meta.index)) {
|
||||
extend.meta.index = 999;
|
||||
}
|
||||
|
||||
const _menu: ModuleMenu = {
|
||||
code,
|
||||
icon: (route.meta?.icon || ' ') as string,
|
||||
sort: (route.meta?.index || 999) as number,
|
||||
label: (route.meta?.title || ' ') as string,
|
||||
type: (route.meta?.type || 'menus') as string,
|
||||
// name: dealOp(route) as string,
|
||||
backApi: dealBackApi(route) as Recordable[],
|
||||
parentCode,
|
||||
extend: {
|
||||
keepAlive: (route.meta?.keepAlive || false) as boolean,
|
||||
// itemList: route.meta?.itemList || null,
|
||||
},
|
||||
route: extend,
|
||||
};
|
||||
if (children) {
|
||||
_menu.menus = transformRoutes(children, code);
|
||||
}
|
||||
return _menu;
|
||||
}
|
||||
function dealBackApi(e: any) {
|
||||
if (e.meta?.hideChildren) {
|
||||
if (e.children !== undefined) {
|
||||
return e.children[0].meta?.backApi || [];
|
||||
} else {
|
||||
return e.meta?.backApi ? e.meta?.backApi : [];
|
||||
}
|
||||
}
|
||||
return e.meta?.backApi || [];
|
||||
}
|
||||
|
||||
function dealOp(e: any) {
|
||||
if (e.meta?.type === 'op') {
|
||||
return e.name;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function transformRoutes(routes: RouteRecordRaw[], parentCode = '') {
|
||||
const list = [];
|
||||
for (let i = 0, l = routes.length; i < l; i++) {
|
||||
if (routes[i].meta?.operates && !routes[i].meta?.hideResource) {
|
||||
routes[i].meta?.operates.forEach((item) => {
|
||||
const info = {
|
||||
sort: 999,
|
||||
type: 'op',
|
||||
code: item.code,
|
||||
name: '',
|
||||
label: item.title,
|
||||
backApi: item.backApi,
|
||||
parentCode: parentCode,
|
||||
};
|
||||
list.push(info);
|
||||
});
|
||||
}
|
||||
if (routes[i].name !== `${parentCode}Index` && !routes[i].meta?.hideResource) {
|
||||
list.push(transformRouteToMenu(routes[i], parentCode));
|
||||
}
|
||||
}
|
||||
return sortMenu(list);
|
||||
}
|
||||
33
lib/saas/router/helper/view-helper.ts
Normal file
33
lib/saas/router/helper/view-helper.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
const viewsModules: Recordable<() => Promise<Recordable>> = import.meta.glob(
|
||||
'/src/view/**/*.{vue,tsx}'
|
||||
);
|
||||
viewsModules['/saas/view/system/application.vue'] = () =>
|
||||
import('/nerv-lib/saas/view/system/application.vue');
|
||||
|
||||
viewsModules['/saas/view/system/layout/content.vue'] = () =>
|
||||
import('/nerv-lib/saas/view/system/layout/content.vue');
|
||||
|
||||
viewsModules['/saas/view/menuManage/index.vue'] = () =>
|
||||
import('/nerv-lib/saas/view/menuManage/index.vue');
|
||||
|
||||
const viewsModulesKeys = Object.keys(viewsModules);
|
||||
|
||||
function getComponent(component: string): string | undefined {
|
||||
const key = viewsModulesKeys.find((key) => {
|
||||
return component.includes(key);
|
||||
});
|
||||
// !key && console.log('key', component);
|
||||
return key;
|
||||
}
|
||||
|
||||
function dynamicImportRoute(component: string) {
|
||||
const dynamicComponent = viewsModules[component];
|
||||
if (dynamicComponent) {
|
||||
return dynamicComponent;
|
||||
} else {
|
||||
console.error(`can't find ${component}`);
|
||||
return viewsModules['/saas/view/system/layout/content.vue'];
|
||||
}
|
||||
}
|
||||
|
||||
export { viewsModules, getComponent, dynamicImportRoute };
|
||||
33
lib/saas/router/index.ts
Normal file
33
lib/saas/router/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { App } from 'vue';
|
||||
import type { RouteRecord } from 'vue-router';
|
||||
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { routes, ALLRoute, WHITE_NAME_LIST } from './routes';
|
||||
import { useRouteStore } from '/nerv-base/store/modules/route';
|
||||
import { createPermissionGuard } from '/nerv-lib/saas/router/guard/permission-guard';
|
||||
|
||||
// app router
|
||||
export const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.VITE_PUBLIC_PATH as string),
|
||||
routes: ALLRoute,
|
||||
strict: true,
|
||||
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||
});
|
||||
|
||||
// reset router
|
||||
export function resetRouter() {
|
||||
router.getRoutes().forEach((route: RouteRecord) => {
|
||||
const { name } = route;
|
||||
if (name && !WHITE_NAME_LIST.includes(name as string)) {
|
||||
router.hasRoute(name) && router.removeRoute(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// config router
|
||||
export function setupRouter(app: App<Element>) {
|
||||
app.use(router);
|
||||
const routeStore = useRouteStore();
|
||||
routeStore.setRoute(routes);
|
||||
createPermissionGuard(router, WHITE_NAME_LIST);
|
||||
}
|
||||
78
lib/saas/router/routes/index.ts
Normal file
78
lib/saas/router/routes/index.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
|
||||
import { log } from '/nerv-lib/util';
|
||||
import { appConfigStore } from '/nerv-lib/saas/store/modules/app-config';
|
||||
let modules = import.meta.globEager('/src/router/**/*.ts');
|
||||
const modulesOP = import.meta.globEager('/src/router-op/**/*.ts');
|
||||
|
||||
const modulesCloud = import.meta.globEager('/src/router-cloud/**/*.ts');
|
||||
import { appConfig } from '/@/config/app.config.ts';
|
||||
if (__APP_INFO__.platform?.toLowerCase() === 'op') {
|
||||
// log.info('The operating platform is op.');
|
||||
modules = modulesOP;
|
||||
} else if (__APP_INFO__.platform?.toLowerCase() === 'cloud') {
|
||||
// log.info('The operating platform is cloud.');
|
||||
modules = modulesCloud;
|
||||
} else {
|
||||
// appConfig = initAppConfig;
|
||||
}
|
||||
// const test = appConfigStore();
|
||||
// console.log(test);
|
||||
const routes: any[] = [];
|
||||
Object.keys(modules).forEach((key) => {
|
||||
const mod = modules[key].default || {};
|
||||
const modList = Array.isArray(mod) ? [...mod] : [mod];
|
||||
if (modList[0].children && !modList[0].component) {
|
||||
if (appConfig['customApplication'] && appConfig['customApplication'] === 'v2') {
|
||||
modList[0].component = () => import('/nerv-lib/saas/view/system/customApplication.vue');
|
||||
} else {
|
||||
modList[0].component = () => import('/nerv-lib/saas/view/system/application.vue');
|
||||
}
|
||||
}
|
||||
modList[0].path && routes.push(...modList);
|
||||
});
|
||||
|
||||
export { routes };
|
||||
|
||||
export const LoginRoute = {
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: appConfig.customLogin
|
||||
? appConfig.customLogin
|
||||
: () => import('/nerv-lib/saas/view/system/login.vue'),
|
||||
meta: {
|
||||
title: '登录',
|
||||
},
|
||||
};
|
||||
export const Error403Route = {
|
||||
path: '/403',
|
||||
name: 'error403',
|
||||
component: () => import('/nerv-lib/saas/view/service/error-403.vue'),
|
||||
};
|
||||
export const updatePassWord = {
|
||||
path: '/updatePassWord',
|
||||
name: 'UpdatePassWord',
|
||||
component: appConfig.customUpdatePwd
|
||||
? appConfig.customUpdatePwd
|
||||
: () => import('/nerv-lib/saas/view/service/updatePassWord.vue'),
|
||||
};
|
||||
|
||||
export const DefaultRoute = {
|
||||
path: '/:pathMatch(.*)',
|
||||
name: 'default',
|
||||
redirect: { name: 'root' },
|
||||
};
|
||||
const outControlPageName: any[] = [];
|
||||
Object.keys(modules).forEach((key) => {
|
||||
const mod = modules[key].default || {};
|
||||
if (mod.name && mod.outContrl) {
|
||||
outControlPageName.push(mod.name);
|
||||
}
|
||||
});
|
||||
export const WHITE_NAME_LIST = [
|
||||
Error403Route.name,
|
||||
updatePassWord.name,
|
||||
LoginRoute.name,
|
||||
...outControlPageName,
|
||||
];
|
||||
export const ALLRoute = [LoginRoute, DefaultRoute, updatePassWord, Error403Route, ...routes];
|
||||
13
lib/saas/router/types.ts
Normal file
13
lib/saas/router/types.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
export interface ModuleMenu {
|
||||
code: string;
|
||||
sort: number; //排序
|
||||
label: string; //路由名字
|
||||
type: string; //路由类型默认为menus,op为操作
|
||||
name: string; //路由name
|
||||
parentCode: string;
|
||||
backApi?: Recordable[]; //界面对应的操作
|
||||
route: RouteRecordRaw;
|
||||
menus?: ModuleMenu[];
|
||||
}
|
||||
Reference in New Issue
Block a user