This commit is contained in:
xuziqiang
2024-05-15 17:29:42 +08:00
commit d0155dbe3c
7296 changed files with 1832517 additions and 0 deletions

View 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,
);
}
});
}

View 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);
}
}
}

View 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);
}

View 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
View 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);
}

View 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
View 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[];
}