oak-frontend-base/es/features/console.js

244 lines
8.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Feature } from '../types/Feature';
import { assert } from 'oak-domain/lib/utils/assert';
import { intersection } from 'oak-domain/lib/utils/lodash';
import { LOCAL_STORAGE_KEYS } from '../constant/constant';
import { judgeRelation } from 'oak-domain/lib/store/relation';
;
;
;
export default class Console extends Feature {
cache;
localStorage;
user;
userId;
isRoot;
consoleContext;
availMenus;
unsubFns;
initialize() {
this.unsubFns.push(this.user.subscribe(() => this.onUserChanged()));
}
saveContext(context) {
if (this.consoleContext !== context) {
this.consoleContext = context;
if (context) {
this.localStorage.save(LOCAL_STORAGE_KEYS.consoleContext, context);
}
else {
this.localStorage.remove(LOCAL_STORAGE_KEYS.consoleContext);
}
this.checkAvailMenus();
}
}
async onUserChanged() {
this.isRoot = this.user.isRoot();
const userId = this.user.getUserId(true);
if (userId !== this.userId) {
this.userId = userId;
}
if (this.userId && !this.isRoot) {
await this.cache.exec('loadRelations', {
entities: this.entities,
});
}
else if (!this.userId) {
this.saveContext(undefined);
return;
}
this.checkAvailMenus();
}
initAvailMenus() {
const schema = this.cache.getSchema();
this.availMenus = this.menus.map((menu) => {
const { destEntity, path, ...rest } = menu;
if (destEntity) {
let sourceEntity = destEntity;
if (path) {
const paths = path.split('.');
paths.forEach((ele) => {
const rel = judgeRelation(schema, sourceEntity, ele);
if (rel === 2) {
sourceEntity = ele;
}
else if (typeof rel === 'string') {
sourceEntity = rel;
}
else {
assert(rel instanceof Array);
sourceEntity = rel[0];
}
});
return {
destEntity,
path,
sourceEntity,
available: null,
...rest,
};
}
else {
return {
destEntity,
path,
sourceEntity,
available: null,
...rest,
};
}
}
return {
...menu,
available: null,
};
});
}
checkAvailMenus() {
if (this.consoleContext && this.userId) {
const { entity, entityId } = this.consoleContext;
// 这个不能放在constructor里面因为this.menus是后初始化的
if (this.availMenus.length < this.menus.length) {
this.initAvailMenus();
}
const actionAuths = this.userId && !this.isRoot && this.cache.get('actionAuth', {
data: {
id: 1,
path: {
destEntity: 1,
sourceEntity: 1,
value: 1,
},
deActions: 1,
},
filter: {
relation: {
entity: entity,
$or: [
{
entityId,
},
{
entityId: {
$exists: false,
},
}
],
userRelation$relation: {
userId: this.userId
}
},
}
});
this.availMenus.forEach((menu) => {
let { destEntity, path, actions, sourceEntity } = menu;
let available = false;
switch (destEntity) {
// 如果是空字符串,表示对任何用户可见
case '': {
available = true;
break;
}
case 'userRelation': {
available = !!this.cache.checkOperation(destEntity, {
action: 'create',
data: {
entity: entity,
entityId
},
}, [
'relation'
]);
break;
}
case undefined: {
available = !!this.isRoot;
break;
}
default: {
assert(actions?.length);
assert(typeof path === 'string');
if (sourceEntity === entity) {
if (this.isRoot) {
available = true;
}
else if (this.userId) {
assert(actionAuths);
available = !!actionAuths.find(actionAuth => intersection(actionAuth.deActions, actions).length > 0 && actionAuth.path.destEntity === destEntity && path === actionAuth.path.value);
}
}
else {
available = null;
}
}
}
menu.available = available;
});
}
else {
this.availMenus.forEach(ele => ele.available = null);
}
this.publish();
}
constructor(cache, localStorage, user, getEntityProjection) {
super();
this.cache = cache;
this.localStorage = localStorage;
this.user = user;
this.availMenus = [];
this.unsubFns = [];
this.initialize();
this.loadContext(getEntityProjection);
}
async loadContext(getEntityProjection) {
const context = await this.localStorage.load(LOCAL_STORAGE_KEYS.consoleContext);
this.consoleContext = context;
if (this.consoleContext) {
const { entity, entityId } = this.consoleContext;
await this.cache.refresh(entity, {
data: getEntityProjection(entity),
filter: {
id: entityId,
},
});
this.checkAvailMenus();
}
}
setContext(entity, entityId) {
assert(this.entities.includes(entity));
if (entity !== this.consoleContext?.entity || entityId !== this.consoleContext.entityId) {
this.saveContext({
entity,
entityId,
});
}
}
getContext() {
return this.consoleContext;
}
getAvailMenus() {
return this.availMenus.filter(ele => ele.available === true);
}
/**
* 检查当前url是否可以访问
* @param url
* @returns
* true: 可以访问
* false: 无权访问
* null: 上下文不匹配
* undefined: menu中没有此url
*/
checkUrlAvailable(url) {
let result = undefined;
for (const menu of this.availMenus) {
if (menu.url === url) {
if (menu.available) {
return true;
}
else {
result = menu.available;
}
}
}
return result;
}
}