Merge branch 'dev' into release
This commit is contained in:
commit
1cb3f9a210
|
|
@ -9,12 +9,12 @@ interface UserFeature extends Feature {
|
|||
}
|
||||
/**
|
||||
* 1、destEntity如果不写,只对root可见
|
||||
* 2、destEntity为一些特殊的Entity时,action/path可以不写
|
||||
* 2、destEntity为一些特殊的Entity时,actions/path可以不写
|
||||
* 当前只支持userRelation,对此entity可以授权的用户可见
|
||||
*/
|
||||
export interface Menu<ED extends EntityDict & BaseEntityDict> {
|
||||
destEntity?: keyof ED;
|
||||
action?: string;
|
||||
export interface Menu<ED extends EntityDict & BaseEntityDict, T extends keyof ED> {
|
||||
destEntity?: T;
|
||||
actions?: Array<ED[T]['Action']>;
|
||||
path?: string;
|
||||
url: string;
|
||||
}
|
||||
|
|
@ -22,18 +22,17 @@ export interface ConsoleContext<ED extends EntityDict & BaseEntityDict> {
|
|||
entity: keyof ED;
|
||||
entityId: string;
|
||||
}
|
||||
export default abstract class Console<ED extends EntityDict & BaseEntityDict, OMenu extends Menu<ED>> extends Feature {
|
||||
private cache;
|
||||
private localStorage;
|
||||
export default abstract class Console<ED extends EntityDict & BaseEntityDict, OMenu extends Menu<ED, keyof ED>> extends Feature {
|
||||
protected cache: Cache<ED>;
|
||||
protected localStorage: LocalStorage;
|
||||
protected abstract entities: (keyof ED)[];
|
||||
protected abstract menus: OMenu[];
|
||||
private user;
|
||||
private userId?;
|
||||
private isRoot?;
|
||||
private consoleContext?;
|
||||
protected user: UserFeature;
|
||||
protected userId?: string;
|
||||
protected isRoot?: boolean;
|
||||
protected consoleContext?: ConsoleContext<ED>;
|
||||
private availMenus;
|
||||
private unsubFns;
|
||||
private urlDict;
|
||||
private initialize;
|
||||
private saveContext;
|
||||
private onUserChanged;
|
||||
|
|
@ -43,7 +42,19 @@ export default abstract class Console<ED extends EntityDict & BaseEntityDict, OM
|
|||
private loadContext;
|
||||
setContext(entity: keyof ED, entityId: string): void;
|
||||
getContext(): ConsoleContext<ED> | undefined;
|
||||
getAvailMenus(): OMenu[];
|
||||
isUrlAvailable(url: string): boolean;
|
||||
getAvailMenus(): (OMenu & {
|
||||
sourceEntity?: keyof ED | undefined;
|
||||
available: boolean | null;
|
||||
})[];
|
||||
/**
|
||||
* 检查当前url是否可以访问
|
||||
* @param url
|
||||
* @returns
|
||||
* true: 可以访问
|
||||
* false: 无权访问
|
||||
* null: 上下文不匹配
|
||||
* undefined: menu中没有此url
|
||||
*/
|
||||
checkUrlAvailable(url: string): boolean | null | undefined;
|
||||
}
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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';
|
||||
;
|
||||
|
|
@ -14,7 +15,6 @@ export default class Console extends Feature {
|
|||
consoleContext;
|
||||
availMenus;
|
||||
unsubFns;
|
||||
urlDict = {};
|
||||
initialize() {
|
||||
this.unsubFns.push(this.user.subscribe(() => this.onUserChanged()));
|
||||
}
|
||||
|
|
@ -51,33 +51,44 @@ export default class Console extends Feature {
|
|||
const schema = this.cache.getSchema();
|
||||
this.availMenus = this.menus.map((menu) => {
|
||||
const { destEntity, path, ...rest } = menu;
|
||||
if (path && destEntity) {
|
||||
const paths = path.split('.');
|
||||
if (destEntity) {
|
||||
let sourceEntity = destEntity;
|
||||
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: false,
|
||||
...rest,
|
||||
};
|
||||
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: false,
|
||||
available: null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
@ -118,41 +129,7 @@ export default class Console extends Feature {
|
|||
}
|
||||
}, { accurate: true });
|
||||
this.availMenus.forEach((menu) => {
|
||||
const { destEntity, path, action, sourceEntity } = menu;
|
||||
switch (destEntity) {
|
||||
case 'userRelation': {
|
||||
return this.cache.checkOperation(destEntity, {
|
||||
action: 'create',
|
||||
data: {
|
||||
entity: entity,
|
||||
entityId
|
||||
},
|
||||
}, [
|
||||
'relation'
|
||||
]);
|
||||
}
|
||||
case undefined: {
|
||||
return !!this.isRoot;
|
||||
}
|
||||
default: {
|
||||
assert(action);
|
||||
assert(typeof path === 'string');
|
||||
if (sourceEntity === entity) {
|
||||
if (this.isRoot) {
|
||||
return true;
|
||||
}
|
||||
else if (this.userId) {
|
||||
assert(actionAuths);
|
||||
return !!actionAuths.find(actionAuth => actionAuth.deActions?.includes(action) && actionAuth.path.destEntity === destEntity && path === actionAuth.path.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.urlDict = {};
|
||||
this.availMenus.forEach((menu) => {
|
||||
let { destEntity, path, action, sourceEntity } = menu;
|
||||
let { destEntity, path, actions, sourceEntity } = menu;
|
||||
let available = false;
|
||||
switch (destEntity) {
|
||||
case 'userRelation': {
|
||||
|
|
@ -172,7 +149,7 @@ export default class Console extends Feature {
|
|||
break;
|
||||
}
|
||||
default: {
|
||||
assert(action);
|
||||
assert(actions?.length);
|
||||
assert(typeof path === 'string');
|
||||
if (sourceEntity === entity) {
|
||||
if (this.isRoot) {
|
||||
|
|
@ -180,21 +157,19 @@ export default class Console extends Feature {
|
|||
}
|
||||
else if (this.userId) {
|
||||
assert(actionAuths);
|
||||
available = !!actionAuths.find(actionAuth => actionAuth.deActions?.includes(action) && actionAuth.path.destEntity === destEntity && path === actionAuth.path.value);
|
||||
available = !!actionAuths.find(actionAuth => intersection(actionAuth.deActions, actions).length > 0 && actionAuth.path.destEntity === destEntity && path === actionAuth.path.value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
available = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
menu.available = available;
|
||||
if (available) {
|
||||
assert(!this.urlDict[menu.url]);
|
||||
this.urlDict[menu.url] = menu;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.availMenus.forEach(ele => ele.available = false);
|
||||
this.urlDict = {};
|
||||
this.availMenus.forEach(ele => ele.available = null);
|
||||
}
|
||||
this.publish();
|
||||
}
|
||||
|
|
@ -235,9 +210,29 @@ export default class Console extends Feature {
|
|||
return this.consoleContext;
|
||||
}
|
||||
getAvailMenus() {
|
||||
return Object.values(this.urlDict);
|
||||
return this.availMenus.filter(ele => ele.available === true);
|
||||
}
|
||||
isUrlAvailable(url) {
|
||||
return this.urlDict.hasOwnProperty(url);
|
||||
/**
|
||||
* 检查当前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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ type Location = {
|
|||
key: string;
|
||||
namespace: string;
|
||||
search: string;
|
||||
url: string;
|
||||
};
|
||||
export declare class Navigator extends CommonNavigator {
|
||||
history: WechatMiniprogram.Wx;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ export class Navigator extends CommonNavigator {
|
|||
//初始化的时候
|
||||
const pages = getCurrentPages(); //获取加载的页面
|
||||
const currentPage = pages[pages.length - 1]; //获取当前页面的对象
|
||||
const url = currentPage?.route; //当前页面url
|
||||
const route = currentPage?.route; //当前页面url
|
||||
const options = currentPage?.options; //如果要获取url中所带的参数可以查看options
|
||||
const pathname = url ? url
|
||||
const pathname = route ? route
|
||||
.replace('/pages', '')
|
||||
.replace('pages', '')
|
||||
.replace('/index', '') : '';
|
||||
|
|
@ -23,12 +23,14 @@ export class Navigator extends CommonNavigator {
|
|||
}
|
||||
search += `${k}=${typeof options[k] === 'string' ? options[k] : JSON.stringify(options[k])}`;
|
||||
}
|
||||
const url = pathname.replace(this.namespace, '');
|
||||
return {
|
||||
pathname: pathname,
|
||||
state: options,
|
||||
key: `${pages.length - 1}`,
|
||||
namespace: this.namespace,
|
||||
search,
|
||||
url: url || '/',
|
||||
};
|
||||
}
|
||||
getState() {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export declare class Navigator extends CommonNavigator {
|
|||
setHistory(history: BrowserHistory): void;
|
||||
getLocation(): {
|
||||
namespace: string;
|
||||
url: string;
|
||||
state: unknown;
|
||||
key: string;
|
||||
pathname: string;
|
||||
|
|
|
|||
|
|
@ -14,9 +14,12 @@ export class Navigator extends CommonNavigator {
|
|||
this.history = history;
|
||||
}
|
||||
getLocation() {
|
||||
const { pathname } = this.history.location;
|
||||
const url = pathname.replace(this.namespace, '');
|
||||
return {
|
||||
...this.history.location,
|
||||
namespace: this.namespace,
|
||||
url: url || '/',
|
||||
};
|
||||
}
|
||||
getState() {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ interface UserFeature extends Feature {
|
|||
}
|
||||
/**
|
||||
* 1、destEntity如果不写,只对root可见
|
||||
* 2、destEntity为一些特殊的Entity时,action/path可以不写
|
||||
* 2、destEntity为一些特殊的Entity时,actions/path可以不写
|
||||
* 当前只支持userRelation,对此entity可以授权的用户可见
|
||||
*/
|
||||
export interface Menu<ED extends EntityDict & BaseEntityDict> {
|
||||
destEntity?: keyof ED;
|
||||
action?: string;
|
||||
export interface Menu<ED extends EntityDict & BaseEntityDict, T extends keyof ED> {
|
||||
destEntity?: T;
|
||||
actions?: Array<ED[T]['Action']>;
|
||||
path?: string;
|
||||
url: string;
|
||||
}
|
||||
|
|
@ -22,18 +22,17 @@ export interface ConsoleContext<ED extends EntityDict & BaseEntityDict> {
|
|||
entity: keyof ED;
|
||||
entityId: string;
|
||||
}
|
||||
export default abstract class Console<ED extends EntityDict & BaseEntityDict, OMenu extends Menu<ED>> extends Feature {
|
||||
private cache;
|
||||
private localStorage;
|
||||
export default abstract class Console<ED extends EntityDict & BaseEntityDict, OMenu extends Menu<ED, keyof ED>> extends Feature {
|
||||
protected cache: Cache<ED>;
|
||||
protected localStorage: LocalStorage;
|
||||
protected abstract entities: (keyof ED)[];
|
||||
protected abstract menus: OMenu[];
|
||||
private user;
|
||||
private userId?;
|
||||
private isRoot?;
|
||||
private consoleContext?;
|
||||
protected user: UserFeature;
|
||||
protected userId?: string;
|
||||
protected isRoot?: boolean;
|
||||
protected consoleContext?: ConsoleContext<ED>;
|
||||
private availMenus;
|
||||
private unsubFns;
|
||||
private urlDict;
|
||||
private initialize;
|
||||
private saveContext;
|
||||
private onUserChanged;
|
||||
|
|
@ -43,7 +42,19 @@ export default abstract class Console<ED extends EntityDict & BaseEntityDict, OM
|
|||
private loadContext;
|
||||
setContext(entity: keyof ED, entityId: string): void;
|
||||
getContext(): ConsoleContext<ED> | undefined;
|
||||
getAvailMenus(): OMenu[];
|
||||
isUrlAvailable(url: string): boolean;
|
||||
getAvailMenus(): (OMenu & {
|
||||
sourceEntity?: keyof ED | undefined;
|
||||
available: boolean | null;
|
||||
})[];
|
||||
/**
|
||||
* 检查当前url是否可以访问
|
||||
* @param url
|
||||
* @returns
|
||||
* true: 可以访问
|
||||
* false: 无权访问
|
||||
* null: 上下文不匹配
|
||||
* undefined: menu中没有此url
|
||||
*/
|
||||
checkUrlAvailable(url: string): boolean | null | undefined;
|
||||
}
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const Feature_1 = require("../types/Feature");
|
||||
const assert_1 = require("oak-domain/lib/utils/assert");
|
||||
const lodash_1 = require("oak-domain/lib/utils/lodash");
|
||||
const constant_1 = require("../constant/constant");
|
||||
const relation_1 = require("oak-domain/lib/store/relation");
|
||||
;
|
||||
|
|
@ -16,7 +17,6 @@ class Console extends Feature_1.Feature {
|
|||
consoleContext;
|
||||
availMenus;
|
||||
unsubFns;
|
||||
urlDict = {};
|
||||
initialize() {
|
||||
this.unsubFns.push(this.user.subscribe(() => this.onUserChanged()));
|
||||
}
|
||||
|
|
@ -53,33 +53,44 @@ class Console extends Feature_1.Feature {
|
|||
const schema = this.cache.getSchema();
|
||||
this.availMenus = this.menus.map((menu) => {
|
||||
const { destEntity, path, ...rest } = menu;
|
||||
if (path && destEntity) {
|
||||
const paths = path.split('.');
|
||||
if (destEntity) {
|
||||
let sourceEntity = destEntity;
|
||||
paths.forEach((ele) => {
|
||||
const rel = (0, relation_1.judgeRelation)(schema, sourceEntity, ele);
|
||||
if (rel === 2) {
|
||||
sourceEntity = ele;
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
sourceEntity = rel;
|
||||
}
|
||||
else {
|
||||
(0, assert_1.assert)(rel instanceof Array);
|
||||
sourceEntity = rel[0];
|
||||
}
|
||||
});
|
||||
return {
|
||||
destEntity,
|
||||
path,
|
||||
sourceEntity,
|
||||
available: false,
|
||||
...rest,
|
||||
};
|
||||
if (path) {
|
||||
const paths = path.split('.');
|
||||
paths.forEach((ele) => {
|
||||
const rel = (0, relation_1.judgeRelation)(schema, sourceEntity, ele);
|
||||
if (rel === 2) {
|
||||
sourceEntity = ele;
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
sourceEntity = rel;
|
||||
}
|
||||
else {
|
||||
(0, assert_1.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: false,
|
||||
available: null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
@ -120,41 +131,7 @@ class Console extends Feature_1.Feature {
|
|||
}
|
||||
}, { accurate: true });
|
||||
this.availMenus.forEach((menu) => {
|
||||
const { destEntity, path, action, sourceEntity } = menu;
|
||||
switch (destEntity) {
|
||||
case 'userRelation': {
|
||||
return this.cache.checkOperation(destEntity, {
|
||||
action: 'create',
|
||||
data: {
|
||||
entity: entity,
|
||||
entityId
|
||||
},
|
||||
}, [
|
||||
'relation'
|
||||
]);
|
||||
}
|
||||
case undefined: {
|
||||
return !!this.isRoot;
|
||||
}
|
||||
default: {
|
||||
(0, assert_1.assert)(action);
|
||||
(0, assert_1.assert)(typeof path === 'string');
|
||||
if (sourceEntity === entity) {
|
||||
if (this.isRoot) {
|
||||
return true;
|
||||
}
|
||||
else if (this.userId) {
|
||||
(0, assert_1.assert)(actionAuths);
|
||||
return !!actionAuths.find(actionAuth => actionAuth.deActions?.includes(action) && actionAuth.path.destEntity === destEntity && path === actionAuth.path.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.urlDict = {};
|
||||
this.availMenus.forEach((menu) => {
|
||||
let { destEntity, path, action, sourceEntity } = menu;
|
||||
let { destEntity, path, actions, sourceEntity } = menu;
|
||||
let available = false;
|
||||
switch (destEntity) {
|
||||
case 'userRelation': {
|
||||
|
|
@ -174,7 +151,7 @@ class Console extends Feature_1.Feature {
|
|||
break;
|
||||
}
|
||||
default: {
|
||||
(0, assert_1.assert)(action);
|
||||
(0, assert_1.assert)(actions?.length);
|
||||
(0, assert_1.assert)(typeof path === 'string');
|
||||
if (sourceEntity === entity) {
|
||||
if (this.isRoot) {
|
||||
|
|
@ -182,21 +159,19 @@ class Console extends Feature_1.Feature {
|
|||
}
|
||||
else if (this.userId) {
|
||||
(0, assert_1.assert)(actionAuths);
|
||||
available = !!actionAuths.find(actionAuth => actionAuth.deActions?.includes(action) && actionAuth.path.destEntity === destEntity && path === actionAuth.path.value);
|
||||
available = !!actionAuths.find(actionAuth => (0, lodash_1.intersection)(actionAuth.deActions, actions).length > 0 && actionAuth.path.destEntity === destEntity && path === actionAuth.path.value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
available = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
menu.available = available;
|
||||
if (available) {
|
||||
(0, assert_1.assert)(!this.urlDict[menu.url]);
|
||||
this.urlDict[menu.url] = menu;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.availMenus.forEach(ele => ele.available = false);
|
||||
this.urlDict = {};
|
||||
this.availMenus.forEach(ele => ele.available = null);
|
||||
}
|
||||
this.publish();
|
||||
}
|
||||
|
|
@ -237,10 +212,30 @@ class Console extends Feature_1.Feature {
|
|||
return this.consoleContext;
|
||||
}
|
||||
getAvailMenus() {
|
||||
return Object.values(this.urlDict);
|
||||
return this.availMenus.filter(ele => ele.available === true);
|
||||
}
|
||||
isUrlAvailable(url) {
|
||||
return this.urlDict.hasOwnProperty(url);
|
||||
/**
|
||||
* 检查当前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;
|
||||
}
|
||||
}
|
||||
exports.default = Console;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ type Location = {
|
|||
key: string;
|
||||
namespace: string;
|
||||
search: string;
|
||||
url: string;
|
||||
};
|
||||
export declare class Navigator extends CommonNavigator {
|
||||
history: WechatMiniprogram.Wx;
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ class Navigator extends navigator_common_1.Navigator {
|
|||
//初始化的时候
|
||||
const pages = getCurrentPages(); //获取加载的页面
|
||||
const currentPage = pages[pages.length - 1]; //获取当前页面的对象
|
||||
const url = currentPage?.route; //当前页面url
|
||||
const route = currentPage?.route; //当前页面url
|
||||
const options = currentPage?.options; //如果要获取url中所带的参数可以查看options
|
||||
const pathname = url ? url
|
||||
const pathname = route ? route
|
||||
.replace('/pages', '')
|
||||
.replace('pages', '')
|
||||
.replace('/index', '') : '';
|
||||
|
|
@ -26,12 +26,14 @@ class Navigator extends navigator_common_1.Navigator {
|
|||
}
|
||||
search += `${k}=${typeof options[k] === 'string' ? options[k] : JSON.stringify(options[k])}`;
|
||||
}
|
||||
const url = pathname.replace(this.namespace, '');
|
||||
return {
|
||||
pathname: pathname,
|
||||
state: options,
|
||||
key: `${pages.length - 1}`,
|
||||
namespace: this.namespace,
|
||||
search,
|
||||
url: url || '/',
|
||||
};
|
||||
}
|
||||
getState() {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export declare class Navigator extends CommonNavigator {
|
|||
setHistory(history: BrowserHistory): void;
|
||||
getLocation(): {
|
||||
namespace: string;
|
||||
url: string;
|
||||
state: unknown;
|
||||
key: string;
|
||||
pathname: string;
|
||||
|
|
|
|||
|
|
@ -17,9 +17,12 @@ class Navigator extends navigator_common_1.Navigator {
|
|||
this.history = history;
|
||||
}
|
||||
getLocation() {
|
||||
const { pathname } = this.history.location;
|
||||
const url = pathname.replace(this.namespace, '');
|
||||
return {
|
||||
...this.history.location,
|
||||
namespace: this.namespace,
|
||||
url: url || '/',
|
||||
};
|
||||
}
|
||||
getState() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "oak-frontend-base",
|
||||
"version": "5.3.13",
|
||||
"version": "5.3.14",
|
||||
"description": "oak框架中前端与业务逻辑无关的平台部分",
|
||||
"author": {
|
||||
"name": "XuChang"
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
"node-schedule": "^2.1.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"oak-common-aspect": "^3.0.2",
|
||||
"oak-domain": "^5.1.5",
|
||||
"oak-domain": "^5.1.6",
|
||||
"oak-memory-tree-store": "^3.3.6",
|
||||
"ol": "^7.3.0",
|
||||
"react-activation": "^0.12.4",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
|
|||
import { Cache } from './cache';
|
||||
import { LocalStorage } from './localStorage';
|
||||
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';
|
||||
|
|
@ -15,12 +16,12 @@ interface UserFeature extends Feature {
|
|||
|
||||
/**
|
||||
* 1、destEntity如果不写,只对root可见
|
||||
* 2、destEntity为一些特殊的Entity时,action/path可以不写
|
||||
* 2、destEntity为一些特殊的Entity时,actions/path可以不写
|
||||
* 当前只支持userRelation,对此entity可以授权的用户可见
|
||||
*/
|
||||
export interface Menu<ED extends EntityDict & BaseEntityDict> {
|
||||
destEntity?: keyof ED;
|
||||
action?: string;
|
||||
export interface Menu<ED extends EntityDict & BaseEntityDict, T extends keyof ED> {
|
||||
destEntity?: T;
|
||||
actions?: Array<ED[T]['Action']>;
|
||||
path?: string;
|
||||
url: string;
|
||||
};
|
||||
|
|
@ -31,23 +32,21 @@ export interface ConsoleContext<ED extends EntityDict & BaseEntityDict> {
|
|||
};
|
||||
|
||||
|
||||
export default abstract class Console<ED extends EntityDict & BaseEntityDict, OMenu extends Menu<ED>> extends Feature {
|
||||
private cache: Cache<ED>;
|
||||
private localStorage: LocalStorage;
|
||||
export default abstract class Console<ED extends EntityDict & BaseEntityDict, OMenu extends Menu<ED, keyof ED>> extends Feature {
|
||||
protected cache: Cache<ED>;
|
||||
protected localStorage: LocalStorage;
|
||||
protected abstract entities: (keyof ED)[];
|
||||
protected abstract menus: OMenu[];
|
||||
private user: UserFeature;
|
||||
private userId?: string;
|
||||
private isRoot?: boolean;
|
||||
private consoleContext?: ConsoleContext<ED>;
|
||||
protected user: UserFeature;
|
||||
protected userId?: string;
|
||||
protected isRoot?: boolean;
|
||||
protected consoleContext?: ConsoleContext<ED>;
|
||||
private availMenus: (OMenu & {
|
||||
sourceEntity?: keyof ED;
|
||||
available: boolean;
|
||||
available: boolean | null; // null表示上下文不匹配
|
||||
})[];
|
||||
private unsubFns: Array<() => void>;
|
||||
|
||||
private urlDict: Record<string, OMenu> = {};
|
||||
|
||||
private initialize() {
|
||||
this.unsubFns.push(
|
||||
this.user.subscribe(
|
||||
|
|
@ -92,46 +91,60 @@ export default abstract class Console<ED extends EntityDict & BaseEntityDict, OM
|
|||
this.checkAvailMenus();
|
||||
}
|
||||
|
||||
private initAvailMenus() {
|
||||
private initAvailMenus() {
|
||||
const schema = this.cache.getSchema();
|
||||
this.availMenus = this.menus.map(
|
||||
(menu) => {
|
||||
const { destEntity, path, ...rest } = menu;
|
||||
|
||||
if (path && destEntity) {
|
||||
const paths = path.split('.');
|
||||
|
||||
if (destEntity) {
|
||||
let sourceEntity = destEntity;
|
||||
paths.forEach(
|
||||
(ele) => {
|
||||
const rel = judgeRelation(schema, sourceEntity, ele);
|
||||
if (rel === 2) {
|
||||
sourceEntity = ele as keyof ED;
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
sourceEntity = rel as keyof ED;
|
||||
}
|
||||
else {
|
||||
assert(rel instanceof Array);
|
||||
sourceEntity = rel[0] as keyof ED;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
destEntity,
|
||||
path,
|
||||
sourceEntity,
|
||||
available: false,
|
||||
...rest,
|
||||
} as OMenu & {
|
||||
sourceEntity?: keyof ED;
|
||||
available: boolean;
|
||||
};
|
||||
if (path) {
|
||||
const paths = path.split('.');
|
||||
|
||||
paths.forEach(
|
||||
(ele) => {
|
||||
const rel = judgeRelation(schema, sourceEntity, ele);
|
||||
if (rel === 2) {
|
||||
sourceEntity = ele as keyof ED;
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
sourceEntity = rel as keyof ED;
|
||||
}
|
||||
else {
|
||||
assert(rel instanceof Array);
|
||||
sourceEntity = rel[0] as keyof ED;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
destEntity,
|
||||
path,
|
||||
sourceEntity,
|
||||
available: null,
|
||||
...rest,
|
||||
} as OMenu & {
|
||||
sourceEntity?: keyof ED;
|
||||
available: boolean | null;
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
destEntity,
|
||||
path,
|
||||
sourceEntity,
|
||||
available: null,
|
||||
...rest,
|
||||
} as OMenu & {
|
||||
sourceEntity?: keyof ED;
|
||||
available: boolean | null;
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
...menu,
|
||||
available: false,
|
||||
available: null,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
|
@ -178,52 +191,8 @@ export default abstract class Console<ED extends EntityDict & BaseEntityDict, OM
|
|||
|
||||
this.availMenus.forEach(
|
||||
(menu) => {
|
||||
const { destEntity, path, action, sourceEntity } = menu;
|
||||
switch (destEntity) {
|
||||
case 'userRelation': {
|
||||
return this.cache.checkOperation(
|
||||
destEntity,
|
||||
{
|
||||
action: 'create',
|
||||
data: {
|
||||
entity: entity as string,
|
||||
entityId
|
||||
},
|
||||
},
|
||||
[
|
||||
'relation'
|
||||
]
|
||||
)
|
||||
}
|
||||
case undefined: {
|
||||
return !!this.isRoot;
|
||||
}
|
||||
default: {
|
||||
assert(action);
|
||||
assert(typeof path === 'string');
|
||||
if (sourceEntity === entity) {
|
||||
if (this.isRoot) {
|
||||
return true;
|
||||
}
|
||||
else if (this.userId) {
|
||||
assert(actionAuths);
|
||||
return !!actionAuths.find(
|
||||
actionAuth => actionAuth.deActions?.includes(action) && actionAuth.path!.destEntity === destEntity && path === actionAuth.path!.value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
this.urlDict = {};
|
||||
this.availMenus.forEach(
|
||||
(menu) => {
|
||||
let { destEntity, path, action, sourceEntity } = menu;
|
||||
let available = false;
|
||||
let { destEntity, path, actions, sourceEntity } = menu;
|
||||
let available: boolean | null = false;
|
||||
switch (destEntity) {
|
||||
case 'userRelation': {
|
||||
available = !!this.cache.checkOperation(
|
||||
|
|
@ -246,9 +215,9 @@ export default abstract class Console<ED extends EntityDict & BaseEntityDict, OM
|
|||
break;
|
||||
}
|
||||
default: {
|
||||
assert(action);
|
||||
assert(actions?.length);
|
||||
assert(typeof path === 'string');
|
||||
|
||||
|
||||
if (sourceEntity === entity) {
|
||||
if (this.isRoot) {
|
||||
available = true;
|
||||
|
|
@ -256,26 +225,24 @@ export default abstract class Console<ED extends EntityDict & BaseEntityDict, OM
|
|||
else if (this.userId) {
|
||||
assert(actionAuths);
|
||||
available = !!actionAuths.find(
|
||||
actionAuth => actionAuth.deActions?.includes(action) && actionAuth.path!.destEntity === destEntity && path === actionAuth.path!.value
|
||||
actionAuth => intersection(actionAuth.deActions, actions).length > 0 && actionAuth.path!.destEntity === destEntity && path === actionAuth.path!.value
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
available = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu.available = available;
|
||||
if (available) {
|
||||
assert(!this.urlDict[menu.url]);
|
||||
this.urlDict[menu.url] = menu;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.availMenus.forEach(
|
||||
ele => ele.available = false
|
||||
ele => ele.available = null
|
||||
);
|
||||
this.urlDict = {};
|
||||
}
|
||||
this.publish();
|
||||
}
|
||||
|
|
@ -323,10 +290,33 @@ export default abstract class Console<ED extends EntityDict & BaseEntityDict, OM
|
|||
}
|
||||
|
||||
getAvailMenus() {
|
||||
return Object.values(this.urlDict);
|
||||
return this.availMenus.filter(
|
||||
ele => ele.available === true
|
||||
);
|
||||
}
|
||||
|
||||
isUrlAvailable(url: string) {
|
||||
return this.urlDict.hasOwnProperty(url);
|
||||
/**
|
||||
* 检查当前url是否可以访问
|
||||
* @param url
|
||||
* @returns
|
||||
* true: 可以访问
|
||||
* false: 无权访问
|
||||
* null: 上下文不匹配
|
||||
* undefined: menu中没有此url
|
||||
*/
|
||||
checkUrlAvailable(url: string) {
|
||||
let result: boolean | null | undefined = undefined;
|
||||
for (const menu of this.availMenus) {
|
||||
if (menu.url === url) {
|
||||
if (menu.available) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
result = menu.available;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ type Location = {
|
|||
key: string;
|
||||
namespace: string;
|
||||
search: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export class Navigator extends CommonNavigator {
|
||||
|
|
@ -24,9 +25,9 @@ export class Navigator extends CommonNavigator {
|
|||
//初始化的时候
|
||||
const pages = getCurrentPages(); //获取加载的页面
|
||||
const currentPage = pages[pages.length - 1]; //获取当前页面的对象
|
||||
const url = currentPage?.route; //当前页面url
|
||||
const route = currentPage?.route; //当前页面url
|
||||
const options = currentPage?.options; //如果要获取url中所带的参数可以查看options
|
||||
const pathname = url ? url
|
||||
const pathname = route ? route
|
||||
.replace('/pages', '')
|
||||
.replace('pages', '')
|
||||
.replace('/index', '') : '';
|
||||
|
|
@ -37,12 +38,14 @@ export class Navigator extends CommonNavigator {
|
|||
}
|
||||
search += `${k}=${ typeof options[k] === 'string' ? options[k] : JSON.stringify(options[k])}`;
|
||||
}
|
||||
const url = pathname.replace(this.namespace, '');
|
||||
return {
|
||||
pathname: pathname,
|
||||
state: options,
|
||||
key: `${pages.length - 1}`,
|
||||
namespace: this.namespace,
|
||||
search,
|
||||
url: url || '/',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,9 +25,12 @@ export class Navigator extends CommonNavigator {
|
|||
}
|
||||
|
||||
getLocation() {
|
||||
const { pathname } = this.history.location;
|
||||
const url = pathname.replace(this.namespace, '');
|
||||
return {
|
||||
...this.history.location,
|
||||
namespace: this.namespace,
|
||||
url: url || '/',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue