You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
547 lines
20 KiB
547 lines
20 KiB
7 months ago
|
|
||
|
|
||
|
import { defineStore } from 'pinia';
|
||
|
import { http } from '/nerv-lib/util/http';
|
||
|
import { stringUtil } from '/nerv-lib/util/string-util';
|
||
|
import { cloneDeep } from 'lodash-es';
|
||
|
import { toRaw } from 'vue';
|
||
|
import { log } from '/nerv-lib/util/log';
|
||
|
|
||
|
export const authorizationService = defineStore({
|
||
|
id: 'authorizationService',
|
||
|
/**
|
||
|
* token 测试用
|
||
|
* userinfo 用户信息
|
||
|
* itemMap 权限树
|
||
|
* @returns
|
||
|
*/
|
||
|
state(): {
|
||
|
token: boolean;
|
||
|
userInfo: any;
|
||
|
itemMap: any;
|
||
|
defaultRegion: { value: string; label: string; isDefault: any };
|
||
|
currentRegion: { value: string; label: string; isDefault: any };
|
||
|
regionArray: Array<any>;
|
||
|
ModulesRes: Array<any>;
|
||
|
permissionMap: Recordable;
|
||
|
switches: Recordable;
|
||
|
} {
|
||
|
return {
|
||
|
token: false,
|
||
|
userInfo: {},
|
||
|
itemMap: {},
|
||
|
defaultRegion: { label: '', value: '', isDefault: '' },
|
||
|
currentRegion: { label: '', value: '', isDefault: '' },
|
||
|
regionArray: [],
|
||
|
ModulesRes: [],
|
||
|
permissionMap: {},
|
||
|
switches: {},
|
||
|
};
|
||
|
},
|
||
|
actions: {
|
||
|
login() {},
|
||
|
logout() {
|
||
|
window.location.href = '/login';
|
||
|
},
|
||
|
loadAuthorization() {
|
||
|
return http.post('/api/passport/passport/objs/Authorization/CheckAuthorization');
|
||
|
},
|
||
|
loadModules() {
|
||
|
return http.get('/api/webui/webui/objs/GetModules');
|
||
|
},
|
||
|
loadRegion() {
|
||
|
return http.get('/api/passport/objs/GetRegionsInfo');
|
||
|
},
|
||
|
loadSwitch() {
|
||
|
return http.get('/api/webui/webui/objs/GetSwitchs');
|
||
|
},
|
||
|
getAuthMap() {
|
||
|
const requestArr = [
|
||
|
this.loadAuthorization(),
|
||
|
this.loadModules(),
|
||
|
this.loadRegion(),
|
||
|
this.loadSwitch(),
|
||
|
];
|
||
|
return Promise.all(requestArr).then((result) => {
|
||
|
if (result && result.length >= 2) {
|
||
|
log.info('权限加载完成');
|
||
|
const authResponse = result[0];
|
||
|
const menusResponse = result[1];
|
||
|
this.ModulesRes = cloneDeep(result[1]);
|
||
|
result[2] ? this.setRegionInfo(result[2]) : '';
|
||
|
this.itemMap = this.convertResponse2ItemMap(authResponse, menusResponse);
|
||
|
this.permissionMap = this.getPermissionMap(authResponse, menusResponse);
|
||
|
this.switches = result[3]?.switchs;
|
||
|
|
||
|
log.info('生成权限树', toRaw(this.permissionMap));
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 是否有权限
|
||
|
*
|
||
|
* @param moduleName 模块名
|
||
|
*
|
||
|
* @param subModuleName 子模块名
|
||
|
*
|
||
|
* @param operationName 操作名
|
||
|
*
|
||
|
* @returns {boolean} true: 有权限, false: 没有权限
|
||
|
*/
|
||
|
exists(moduleName: string, subModuleName?: string, operationName?: string): boolean {
|
||
|
/**(1)访问主模块*/
|
||
|
let key = moduleName;
|
||
|
if (subModuleName) {
|
||
|
/**(2)访问子模块*/
|
||
|
key = key + '_' + subModuleName;
|
||
|
}
|
||
|
/**(3)某个具体操作*/
|
||
|
if (operationName) {
|
||
|
key = key + '_' + operationName;
|
||
|
}
|
||
|
// this.checkAuthMap()
|
||
|
return this.itemMap[key] != null || this.isAdmin();
|
||
|
},
|
||
|
|
||
|
// 递归遍历权限树方法
|
||
|
traverseMenus(menusItem: any, subMenus: any, itemMap: any, module: any) {
|
||
|
if (menusItem['submenus'] && menusItem['submenus'].length > 0) {
|
||
|
menusItem['submenus'].forEach((subMenu: any) => {
|
||
|
if (subMenu['isGlobalDisplay']) {
|
||
|
if (!subMenu['isOperation']) {
|
||
|
// 如果是自定义资源且是操作,就不用按照菜单权限写入
|
||
|
if (subMenu['operation'] && subMenu['operation']['resource']) {
|
||
|
const subMenusName = subMenu['operation']['resource'];
|
||
|
subMenus.push(subMenusName);
|
||
|
itemMap[module['name'] + '_' + subMenusName] = true;
|
||
|
if (subMenu['operations'] && subMenu['operations'].length) {
|
||
|
subMenu['operations'].forEach((op: any) => {
|
||
|
itemMap[module['name'] + '_' + subMenusName + '__' + op['name']] = true;
|
||
|
itemMap[
|
||
|
module['name'] + '_' + subMenusName + stringUtil.firstToUpper(op['name'])
|
||
|
] = true; //操作对应的页面权限
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
// 如果是自定义资源且是操作,如【管理】按钮,将它写入父节点的操作里
|
||
|
const opName = subMenu?.operation.resource;
|
||
|
itemMap[module['name'] + '_' + menusItem['name'] + '__' + opName] = true; // xxApp_xxMenus__xxOpName
|
||
|
itemMap[module['name'] + '_' + menusItem['name'] + stringUtil.firstToUpper(opName)] =
|
||
|
true; //操作对应的页面权限,如:xxApp_xxMenusXxOpName
|
||
|
}
|
||
|
this.traverseMenus(subMenu, subMenus, itemMap, module);
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
},
|
||
|
//处理权限树
|
||
|
convertResponse2ItemMap(authResponse: any, menusResponse: any) {
|
||
|
const itemMap: any = {};
|
||
|
/** 如果是具有admin权限用户*/
|
||
|
if (authResponse['accountname'] == 'admin' || authResponse['isAdmin']) {
|
||
|
itemMap['*'] = '';
|
||
|
return itemMap;
|
||
|
}
|
||
|
/***默认显示的模块或者菜单 如:监控下面的指标监控
|
||
|
* 先处理默认显示的模块权限,再处理授权的权限,注意顺序
|
||
|
*/
|
||
|
if (menusResponse instanceof Array) {
|
||
|
menusResponse.forEach((module) => {
|
||
|
if (module['isGlobalDisplay']) {
|
||
|
let menus: Array<any> = [];
|
||
|
if (itemMap[module['name']] == null) {
|
||
|
itemMap[module['name']] = ''; //保留上个项目中该模块的菜单信息
|
||
|
}
|
||
|
itemMap[module['name']] = '';
|
||
|
if (module['menus'] && module['menus'].length > 0) {
|
||
|
module['menus'].forEach((menusItem: any) => {
|
||
|
if (menusItem['isGlobalDisplay']) {
|
||
|
if (menusItem['isGlobal']) {
|
||
|
// 1. 全局开放模块又是独立模块
|
||
|
itemMap[menusItem['name']] = '';
|
||
|
const globalMenus: Array<any> = [];
|
||
|
if (menusItem['submenus'] && menusItem['submenus'].length > 0) {
|
||
|
menusItem['submenus'].forEach((subMenu: any) => {
|
||
|
if (subMenu['isGlobalDisplay']) {
|
||
|
if (subMenu['operation'] && subMenu['operation']['resource']) {
|
||
|
const globalMenuName = subMenu['operation']['resource'];
|
||
|
globalMenus.push(globalMenuName);
|
||
|
itemMap[menusItem['name'] + '_' + globalMenuName] = '';
|
||
|
if (subMenu['operations'] && subMenu['operations'].length) {
|
||
|
subMenu['operations'].forEach((op: any) => {
|
||
|
itemMap[
|
||
|
menusItem['name'] + '_' + globalMenuName + '_' + op['name']
|
||
|
] = '';
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (menusItem['isDir']) {
|
||
|
itemMap[module['name'] + '_' + subMenu['name']] = true;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
itemMap[menusItem['name']] = globalMenus;
|
||
|
}
|
||
|
} else if (menusItem['isDir']) {
|
||
|
// 2. 文件夹下的模块
|
||
|
const subMenus: Array<any> = [];
|
||
|
this.traverseMenus(menusItem, subMenus, itemMap, module);
|
||
|
menus = [...menus, ...subMenus];
|
||
|
} else {
|
||
|
//3. 普通全局开放模块
|
||
|
menus.push(menusItem['name']);
|
||
|
itemMap[module['name'] + '_' + menusItem['name']] = '';
|
||
|
if (menusItem.operations && menusItem.operations.length) {
|
||
|
menusItem.operations.forEach((op: any) => {
|
||
|
itemMap[module['name'] + '_' + menusItem['name'] + '_' + op['name']] = '';
|
||
|
});
|
||
|
}
|
||
|
// 处理下层菜单
|
||
|
const subMenus: Array<any> = [];
|
||
|
this.traverseMenus(menusItem, subMenus, itemMap, module);
|
||
|
menus = [...menus, ...subMenus];
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
itemMap[module['name']] = menus;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
if (!authResponse) {
|
||
|
return itemMap;
|
||
|
}
|
||
|
const projects = authResponse['projects'];
|
||
|
if (!projects.length) {
|
||
|
return itemMap;
|
||
|
}
|
||
|
projects.forEach((project: any) => {
|
||
|
// if (project['projectname'] == 'systemProject') {
|
||
|
const modules = project['modules'];
|
||
|
if (!modules.length) {
|
||
|
return;
|
||
|
}
|
||
|
modules.forEach((module: any) => {
|
||
|
let menus = [];
|
||
|
if (itemMap[module['name']] == null) {
|
||
|
itemMap[module['name']] = ''; //保留上个项目中该模块的菜单信息
|
||
|
}
|
||
|
if (!module['resources'].length) {
|
||
|
return;
|
||
|
}
|
||
|
module['resources'].forEach((subModule: any) => {
|
||
|
menus.push(subModule['name']);
|
||
|
itemMap[module['name'] + '_' + subModule['name']] = ''; //当该资源在系统项目下,即受角色管理
|
||
|
itemMap[module['name'] + '_' + subModule['name'] + '_' + project['projectname']] = '';
|
||
|
if (!subModule['operations'].length) {
|
||
|
return;
|
||
|
}
|
||
|
const ops: Array<any> = [];
|
||
|
subModule['operations'].forEach((op: any) => {
|
||
|
/**权限合并修改:
|
||
|
* 1.后端注册权限将查看(detail)和列表(list)权限合并为查看(list)权限后,
|
||
|
* 2.前端:用户勾选查看(list),即表示有查看列表和详情权限。
|
||
|
*/
|
||
|
if (op['name'] == subModule['name'] + '_list') {
|
||
|
op['name'] = subModule['name'] + '_detail';
|
||
|
}
|
||
|
itemMap[module['name'] + '_' + subModule['name'] + '_' + op['name']] = '';
|
||
|
itemMap[
|
||
|
module['name'] +
|
||
|
'_' +
|
||
|
subModule['name'] +
|
||
|
'_' +
|
||
|
project['projectname'] +
|
||
|
'_' +
|
||
|
op['name']
|
||
|
] = '';
|
||
|
ops.push(op['name']);
|
||
|
});
|
||
|
itemMap[module['name'] + '_' + subModule['name'] + '_' + project['projectname']] =
|
||
|
ops.join(',');
|
||
|
});
|
||
|
if (itemMap[module['name']] && itemMap[module['name']] instanceof Array) {
|
||
|
//如果上个项目在该模块有菜单
|
||
|
menus.push(...itemMap[module['name']]); //合并
|
||
|
menus = Array.from(new Set(menus)); //去重
|
||
|
}
|
||
|
itemMap[module['name']] = menus;
|
||
|
});
|
||
|
// }
|
||
|
});
|
||
|
return itemMap;
|
||
|
},
|
||
|
|
||
|
//判断是否在当前项目内
|
||
|
isCurrentApp(app: string) {
|
||
|
const url = window.location.href;
|
||
|
const reg = /[http|https]+:\/\/.+?\/([^/]+)/gi;
|
||
|
let currentApp;
|
||
|
const result = reg.exec(url);
|
||
|
if (result != null) {
|
||
|
currentApp = result[1];
|
||
|
}
|
||
|
return currentApp === app;
|
||
|
},
|
||
|
|
||
|
getValidFirstMenuName(moduleName: string | number) {
|
||
|
if (!this.itemMap) {
|
||
|
return [];
|
||
|
}
|
||
|
// let menuName = null;
|
||
|
const menus: any[] = this.itemMap[moduleName];
|
||
|
// if(!menus||menus.length==0)return;
|
||
|
// menuName = menus[0];
|
||
|
return menus;
|
||
|
},
|
||
|
|
||
|
isAdmin() {
|
||
|
return this.itemMap['*'] != null;
|
||
|
},
|
||
|
|
||
|
//设置region信息
|
||
|
setRegionInfo(response: any) {
|
||
|
if (response) {
|
||
|
const item: { label: any; value: any; isDefault: any }[] = [];
|
||
|
const regions = response['regions'];
|
||
|
regions.forEach((region: { isDefault: any; name: any; label: any }) => {
|
||
|
region.isDefault
|
||
|
? (this.defaultRegion = {
|
||
|
label: region.label,
|
||
|
value: region.name,
|
||
|
isDefault: region.isDefault,
|
||
|
})
|
||
|
: '';
|
||
|
item.push({
|
||
|
label: region.label,
|
||
|
value: region.name,
|
||
|
isDefault: region.isDefault,
|
||
|
});
|
||
|
});
|
||
|
this.regionArray = item;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
setCurrentRegion(currentRegion: { value: string; label: string; isDefault: any }) {
|
||
|
this.currentRegion = currentRegion;
|
||
|
},
|
||
|
|
||
|
getApp() {
|
||
|
return ((import.meta.env.VITE_PUBLIC_PATH || '') as string).replace(/\//g, '');
|
||
|
},
|
||
|
|
||
|
getPermissionMap(authResponse: any, menusResponse: any) {
|
||
|
const itemMap: any = {};
|
||
|
// itemMap['*'] = true;
|
||
|
// return itemMap;
|
||
|
/** 如果是具有admin权限用户*/
|
||
|
if (authResponse['accountname'] == 'admin' || authResponse['isAdmin']) {
|
||
|
itemMap['*'] = true;
|
||
|
return itemMap;
|
||
|
}
|
||
|
|
||
|
/***默认显示的模块或者菜单 如:监控下面的指标监控
|
||
|
* 先处理默认显示的模块权限,再处理授权的权限,注意顺序
|
||
|
*/
|
||
|
if (menusResponse instanceof Array) {
|
||
|
menusResponse.forEach((module) => {
|
||
|
if (module['isGlobalDisplay']) {
|
||
|
let menus: Array<any> = [];
|
||
|
if (itemMap[module['name']] == null) {
|
||
|
itemMap[module['name']] = ''; //保留上个项目中该模块的菜单信息
|
||
|
}
|
||
|
itemMap[module['name']] = '';
|
||
|
if (module['menus'] && module['menus'].length > 0) {
|
||
|
module['menus'].forEach((menusItem: any) => {
|
||
|
if (menusItem['isGlobalDisplay']) {
|
||
|
if (menusItem['isGlobal']) {
|
||
|
//全局开放模块又是独立模块
|
||
|
itemMap[menusItem['name']] = '';
|
||
|
const globalMenus: Array<any> = [];
|
||
|
if (menusItem['submenus'] && menusItem['submenus'].length > 0) {
|
||
|
menusItem['submenus'].forEach((subMenu: any) => {
|
||
|
if (subMenu['isGlobalDisplay']) {
|
||
|
if (subMenu['operation'] && subMenu['operation']['resource']) {
|
||
|
const globalMenuName = subMenu['operation']['resource'];
|
||
|
globalMenus.push(globalMenuName);
|
||
|
itemMap[menusItem['name'] + '_' + globalMenuName] = true;
|
||
|
if (subMenu['operations'] && subMenu['operations'].length) {
|
||
|
subMenu['operations'].forEach((op: any) => {
|
||
|
itemMap[
|
||
|
menusItem['name'] + '_' + globalMenuName + '__' + op['name']
|
||
|
] = true;
|
||
|
itemMap[
|
||
|
menusItem['name'] +
|
||
|
'_' +
|
||
|
globalMenuName +
|
||
|
stringUtil.firstToUpper(op['name'])
|
||
|
] = true; //权限对应页面
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
itemMap[menusItem['name']] = globalMenus;
|
||
|
}
|
||
|
} else if (menusItem['isDir']) {
|
||
|
// 2. 文件夹下的模块
|
||
|
const subMenus: Array<any> = [];
|
||
|
this.traverseMenus(menusItem, subMenus, itemMap, module);
|
||
|
menus = [...menus, ...subMenus];
|
||
|
} else {
|
||
|
//3. 普通全局开放模块
|
||
|
menus.push(menusItem['name']);
|
||
|
itemMap[module['name'] + '_' + menusItem['name']] = true;
|
||
|
if (menusItem.operations && menusItem.operations.length) {
|
||
|
menusItem.operations.forEach((op: any) => {
|
||
|
itemMap[module['name'] + '_' + menusItem['name'] + '__' + op['name']] =
|
||
|
true;
|
||
|
itemMap[
|
||
|
module['name'] +
|
||
|
'_' +
|
||
|
menusItem['name'] +
|
||
|
stringUtil.firstToUpper(op['name'])
|
||
|
] = true; //权限对应页面
|
||
|
});
|
||
|
}
|
||
|
// 处理下层菜单
|
||
|
const subMenus: Array<any> = [];
|
||
|
this.traverseMenus(menusItem, subMenus, itemMap, module);
|
||
|
menus = [...menus, ...subMenus];
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
itemMap[module['name']] = menus;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (!authResponse) {
|
||
|
return itemMap;
|
||
|
}
|
||
|
const projects = authResponse['projects'];
|
||
|
if (!projects.length) {
|
||
|
return itemMap;
|
||
|
}
|
||
|
projects.forEach((project: any) => {
|
||
|
const modules = project['modules'];
|
||
|
if (!modules.length) {
|
||
|
return;
|
||
|
}
|
||
|
modules.forEach((module: any) => {
|
||
|
let menus = [];
|
||
|
if (itemMap[module['name']] == null) {
|
||
|
itemMap[module['name']] = ''; //保留上个项目中该模块的菜单信息
|
||
|
}
|
||
|
if (!module['resources'].length) {
|
||
|
return;
|
||
|
}
|
||
|
module['resources'].forEach((subModule: any) => {
|
||
|
menus.push(subModule['name']);
|
||
|
if (project['projectname'] === 'systemProject') {
|
||
|
itemMap[module['name'] + '_' + subModule['name']] = 'systemProject'; //当该资源在系统项目下,即受角色管理
|
||
|
} else {
|
||
|
itemMap[module['name'] + '_' + subModule['name']] = true; //当该资源在系统项目下,即受角色管理
|
||
|
itemMap[module['name'] + '_' + subModule['name'] + '_' + project['projectname']] =
|
||
|
true;
|
||
|
}
|
||
|
if (!subModule['operations'].length) {
|
||
|
return;
|
||
|
}
|
||
|
const ops: Array<any> = [];
|
||
|
subModule['operations'].forEach((op: any) => {
|
||
|
/**权限合并修改:
|
||
|
* 1.后端注册权限将查看(detail)和列表(list)权限合并为查看(list)权限后,
|
||
|
* 2.前端:用户勾选查看(list),即表示有查看列表和详情权限。
|
||
|
*/
|
||
|
if (op['name'] == 'list') {
|
||
|
op['name'] = 'detail';
|
||
|
}
|
||
|
itemMap[module['name'] + '_' + subModule['name'] + '__' + op['name']] = true;
|
||
|
itemMap[
|
||
|
module['name'] + '_' + subModule['name'] + stringUtil.firstToUpper(op['name'])
|
||
|
] = true; //权限对应页面
|
||
|
if (project['projectname'] !== 'systemProject') {
|
||
|
itemMap[
|
||
|
module['name'] +
|
||
|
'_' +
|
||
|
subModule['name'] +
|
||
|
'_' +
|
||
|
project['projectname'] +
|
||
|
'__' +
|
||
|
op['name']
|
||
|
] = true;
|
||
|
}
|
||
|
ops.push(op['name']);
|
||
|
});
|
||
|
if (project['projectname'] !== 'systemProject') {
|
||
|
itemMap[module['name'] + '_' + subModule['name'] + '_' + project['projectname']] =
|
||
|
ops.join(',');
|
||
|
}
|
||
|
});
|
||
|
if (itemMap[module['name']] && itemMap[module['name']] instanceof Array) {
|
||
|
//如果上个项目在该模块有菜单
|
||
|
menus.push(...itemMap[module['name']]); //合并
|
||
|
menus = Array.from(new Set(menus)); //去重
|
||
|
}
|
||
|
itemMap[module['name']] = menus;
|
||
|
});
|
||
|
// }
|
||
|
});
|
||
|
return itemMap;
|
||
|
},
|
||
|
async checkAuthMap() {
|
||
|
if (this.ModulesRes.length === 0) {
|
||
|
await this.getAuthMap();
|
||
|
}
|
||
|
},
|
||
|
checkPermission(
|
||
|
moduleName: string,
|
||
|
subModuleName?: string | undefined,
|
||
|
operationName?: string | undefined,
|
||
|
projectName?: string | undefined,
|
||
|
): boolean {
|
||
|
if (this.permissionMap['*']) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
let key = moduleName;
|
||
|
if (!subModuleName) {
|
||
|
// console.log(1, key);
|
||
|
return !!this.permissionMap[key];
|
||
|
}
|
||
|
key = `${key}_${subModuleName}`;
|
||
|
|
||
|
if (!projectName) {
|
||
|
if (operationName) {
|
||
|
key = `${key}__${operationName}`;
|
||
|
}
|
||
|
|
||
|
|
||
|
return !!this.permissionMap[key];
|
||
|
}
|
||
|
if (this.permissionMap[key] === 'systemProject') {
|
||
|
if (operationName) {
|
||
|
key = `${key}__${operationName}`;
|
||
|
}
|
||
|
// console.log(3, key, operationName);
|
||
|
|
||
|
return !!this.permissionMap[key];
|
||
|
} else {
|
||
|
key = `${key}_${projectName}`;
|
||
|
if (operationName) {
|
||
|
key = `${key}__${operationName}`;
|
||
|
}
|
||
|
|
||
|
return !!this.permissionMap[key];
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
});
|