Merge branch 'dev' of codeup.aliyun.com:61c14a7efa282c88e103c23f/oak-frontend-base into dev

This commit is contained in:
Xu Chang 2024-02-29 08:37:58 +08:00
commit 514c0ca0f6
22 changed files with 429 additions and 142 deletions

View File

@ -99,7 +99,7 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
mergeSelectResult<T extends keyof ED>(entity: T, rows: Partial<ED[T]['Schema']>[], sr: Record<string, any>): void;
get<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], allowMiss?: boolean, sr?: Record<string, any>): Partial<ED[T]["Schema"]>[];
getById<T extends keyof ED>(entity: T, projection: ED[T]['Selection']['data'], id: string, allowMiss?: boolean): Partial<ED[T]["Schema"]>[];
judgeRelation(entity: keyof ED, attr: string): string | 0 | 1 | string[] | 2;
judgeRelation(entity: keyof ED, attr: string): string | 0 | 1 | string[] | 2 | -1;
bindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
unbindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
getCachedData(): { [T in keyof ED]?: ED[T]["OpSchema"][] | undefined; };

View File

@ -47,7 +47,7 @@ declare abstract class Node<ED extends EntityDict & BaseEntityDict, T extends ke
getParent(): SingleNode<ED, keyof ED, Cxt, FrontCxt, AD> | ListNode<ED, keyof ED, Cxt, FrontCxt, AD> | VirtualNode<ED, Cxt, FrontCxt, AD> | undefined;
protected getProjection(): ED[T]['Selection']['data'] | undefined;
setProjection(projection: ED[T]['Selection']['data']): void;
protected judgeRelation(attr: string): string | 0 | 1 | string[] | 2;
protected judgeRelation(attr: string): string | 0 | 1 | string[] | 2 | -1;
}
declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends CommonAspectDict<ED, Cxt>> extends Node<ED, T, Cxt, FrontCxt, AD> {
private updates;
@ -95,11 +95,19 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
removeNamedSorter(sorter: NamedSorterItem<ED, T>, refresh?: boolean): void;
removeNamedSorterByName(name: string, refresh: boolean): void;
getFreshValue(): Array<Partial<ED[T]['Schema']>>;
private addItemInner;
addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}): string;
addItems(items: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}>): string[];
private removeItemInner;
removeItem(id: string): void;
removeItems(ids: string[]): void;
private recoverItemInner;
recoverItem(id: string): void;
recoverItems(ids: string[]): void;
resetItem(id: string): void;
/**
* itemId进行更新
@ -243,9 +251,14 @@ export declare class RunningTree<ED extends EntityDict & BaseEntityDict, Cxt ext
addItem<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}): string;
addItems<T extends keyof ED>(path: string, data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}>): string[];
removeItem(path: string, id: string): void;
removeItems(path: string, ids: string[]): void;
updateItem<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action']): void;
recoverItem(path: string, id: string): void;
recoverItems(path: string, ids: string[]): void;
resetItem(path: string, id: string): void;
create<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'>): void;
update<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], action?: ED[T]['Action']): void;

View File

@ -485,7 +485,7 @@ class ListNode extends Node {
}, true, this.sr);
return result;
}
addItem(item) {
addItemInner(item) {
// 如果数据键值是一个空字符串则更新成null
for (const k in item) {
if (item[k] === '') {
@ -502,12 +502,20 @@ class ListNode extends Node {
data: Object.assign(item, { id }),
};
this.sr[id] = {};
return id;
}
addItem(item) {
const id = this.addItemInner(item);
this.setDirty();
return id;
}
removeItem(id) {
if (this.updates[id] &&
this.updates[id].action === 'create') {
addItems(items) {
const ids = items.map((item) => this.addItemInner(item));
this.setDirty();
return ids;
}
removeItemInner(id) {
if (this.updates[id] && this.updates[id].action === 'create') {
// 如果是新增项,在这里抵消
unset(this.updates, id);
unset(this.sr, id);
@ -522,12 +530,26 @@ class ListNode extends Node {
},
};
}
}
removeItem(id) {
this.removeItemInner(id);
this.setDirty();
}
recoverItem(id) {
removeItems(ids) {
ids.forEach((id) => this.removeItemInner(id));
this.setDirty();
}
recoverItemInner(id) {
const operation = this.updates[id];
assert(operation?.action === 'remove');
unset(this.updates, id);
}
recoverItem(id) {
this.recoverItemInner(id);
this.setDirty();
}
recoverItems(ids) {
ids.forEach((id) => this.recoverItemInner(id));
this.setDirty();
}
resetItem(id) {
@ -1643,11 +1665,21 @@ export class RunningTree extends Feature {
assert(node instanceof ListNode);
return node.addItem(data);
}
addItems(path, data) {
const node = this.findNode(path);
assert(node instanceof ListNode);
return node.addItems(data);
}
removeItem(path, id) {
const node = this.findNode(path);
assert(node instanceof ListNode);
node.removeItem(id);
}
removeItems(path, ids) {
const node = this.findNode(path);
assert(node instanceof ListNode);
node.removeItems(ids);
}
updateItem(path, data, id, action) {
const node = this.findNode(path);
assert(node instanceof ListNode);
@ -1658,6 +1690,11 @@ export class RunningTree extends Feature {
assert(node instanceof ListNode);
node.recoverItem(id);
}
recoverItems(path, ids) {
const node = this.findNode(path);
assert(node instanceof ListNode);
node.recoverItems(ids);
}
resetItem(path, id) {
const node = this.findNode(path);
assert(node instanceof ListNode);

View File

@ -367,6 +367,12 @@ const oakBehavior = Behavior({
: this.state.oakFullpath;
return this.features.runningTree.addItem(path2, data);
},
addItems(data, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.addItems(path2, data);
},
updateItem(data, id, action, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -379,12 +385,24 @@ const oakBehavior = Behavior({
: this.state.oakFullpath;
return this.features.runningTree.removeItem(path2, id);
},
removeItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.removeItems(path2, ids);
},
recoverItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.recoverItem(path2, id);
},
recoverItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.recoverItems(path2, ids);
},
resetItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`

13
es/page.react.d.ts vendored
View File

@ -56,12 +56,17 @@ export declare function createComponent<IsList extends boolean, ED extends Entit
addItem<T extends keyof ED>(data: Omit<ED[T]["CreateSingle"]["data"], "id"> & {
id?: string | undefined;
}, path?: string | undefined): string;
addItems<T_1 extends keyof ED>(data: (Omit<ED[T_1]["CreateSingle"]["data"], "id"> & {
id?: string | undefined;
})[], path?: string | undefined): string[];
removeItem(id: string, path?: string | undefined): void;
updateItem<T_1 extends keyof ED>(data: ED[T_1]["Update"]["data"], id: string, action?: ED[T_1]["Action"] | undefined, path?: string | undefined): void;
removeItems(ids: string[], path?: string | undefined): void;
updateItem<T_2 extends keyof ED>(data: ED[T_2]["Update"]["data"], id: string, action?: ED[T_2]["Action"] | undefined, path?: string | undefined): void;
recoverItem(id: string, path?: string | undefined): void;
recoverItems(ids: string[], path?: string | undefined): void;
resetItem(id: string, path?: string | undefined): void;
update<T_2 extends keyof ED>(data: ED[T_2]["Update"]["data"], action?: ED[T_2]["Action"] | undefined, path?: string | undefined): void;
create<T_3 extends keyof ED>(data: Omit<ED[T_3]["CreateSingle"]["data"], "id">, path?: string | undefined): void;
update<T_3 extends keyof ED>(data: ED[T_3]["Update"]["data"], action?: ED[T_3]["Action"] | undefined, path?: string | undefined): void;
create<T_4 extends keyof ED>(data: Omit<ED[T_4]["CreateSingle"]["data"], "id">, path?: string | undefined): void;
remove(path?: string | undefined): void;
isCreation(path?: string | undefined): boolean;
clean(path?: string | undefined): void;
@ -74,7 +79,7 @@ export declare function createComponent<IsList extends boolean, ED extends Entit
getFreshValue(path?: string | undefined): Partial<ED[keyof ED]["Schema"]> | Partial<ED[keyof ED]["Schema"]>[] | undefined;
checkOperation(entity: T, action: ED[T]["Action"], data?: ED[T]["Update"]["data"] | undefined, filter?: ED[T]["Update"]["filter"] | undefined, checkerTypes?: CheckerType[] | undefined): boolean;
tryExecute(path?: string | undefined): boolean | Error;
getOperations<T_4 extends keyof ED>(path?: string | undefined): {
getOperations<T_5 extends keyof ED>(path?: string | undefined): {
entity: keyof ED;
operation: ED[keyof ED]["Operation"];
}[] | undefined;

View File

@ -87,12 +87,24 @@ class OakComponentBase extends React.PureComponent {
: this.state.oakFullpath;
return this.features.runningTree.addItem(path2, data);
}
addItems(data, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.addItems(path2, data);
}
removeItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.removeItem(path2, id);
}
removeItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.removeItems(path2, ids);
}
updateItem(data, id, action, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -105,6 +117,12 @@ class OakComponentBase extends React.PureComponent {
: this.state.oakFullpath;
this.features.runningTree.recoverItem(path2, id);
}
recoverItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.recoverItems(path2, ids);
}
resetItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -426,9 +444,15 @@ export function createComponent(option, features) {
addItem: (data, path) => {
return this.addItem(data, path);
},
addItems: (data, path) => {
return this.addItems(data, path);
},
removeItem: (id, path) => {
return this.removeItem(id, path);
},
removeItems: (ids, path) => {
return this.removeItems(ids, path);
},
updateItem: (data, id, action, path) => {
return this.updateItem(data, id, action, path);
},
@ -471,6 +495,9 @@ export function createComponent(option, features) {
recoverItem: (id, path) => {
return this.recoverItem(id, path);
},
recoverItems: (ids, path) => {
return this.recoverItems(ids, path);
},
resetItem: (id, path) => {
return this.resetItem(id, path);
},

7
es/types/Page.d.ts vendored
View File

@ -206,9 +206,14 @@ export type OakListComponentMethods<ED extends EntityDict & BaseEntityDict, T ex
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}, path?: string) => string;
addItems: (data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}>, path?: string) => string[];
removeItem: (id: string, path?: string) => void;
removeItems: (ids: string[], path?: string) => void;
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], path?: string) => void;
recoverItem: (id: string, path?: string) => void;
recoverItems: (ids: string[], path?: string) => void;
resetItem: (id: string, path?: string) => void;
};
type ComponentOnPropsChangeOption = {
@ -244,7 +249,7 @@ type OakListComoponetData<ED extends EntityDict & BaseEntityDict, T extends keyo
};
export type MakeOakComponent<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature>> = <IsList extends boolean, T extends keyof ED, FormedData extends DataOption, TData extends DataOption, TProperty extends DataOption, TMethod extends MethodOption>(options: OakComponentOption<IsList, ED, T, Cxt, FrontCxt, AD, FD, FormedData, TData, TProperty, TMethod>) => (props: ReactComponentProps<ED, T, IsList, TProperty>) => React.ReactElement;
export type WebComponentCommonMethodNames = 'setNotification' | 'setMessage' | 'navigateTo' | 'navigateBack' | 'redirectTo' | 'clean' | 't' | 'execute' | 'refresh' | 'aggregate' | 'checkOperation' | 'isDirty';
export type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters' | 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'removeItem' | 'updateItem' | 'resetItem' | 'recoverItem';
export type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters' | 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'addItems' | 'removeItem' | 'removeItems' | 'updateItem' | 'resetItem' | 'recoverItem' | 'recoverItems';
export type WebComponentSingleMethodNames = 'update' | 'remove' | 'create' | 'isCreation';
export type WebComponentProps<ED extends EntityDict & BaseEntityDict, T extends keyof ED, IsList extends boolean, TData extends DataOption = {}, TMethod extends MethodOption = {}> = {
methods: TMethod & OakCommonComponentMethods<ED, T> & OakListComponentMethods<ED, T> & OakSingleComponentMethods<ED, T>;

View File

@ -45,44 +45,31 @@ export function resolvePath(dataSchema, entity, path) {
idx++;
continue;
}
try {
const relation = judgeRelation(dataSchema, _entity, attr);
if (relation === 1) {
const attributes = getAttributes(dataSchema[_entity].attributes);
attribute = attributes[attr];
attrType = attribute.type;
if (attr === 'id') {
attrType = 'ref';
}
else {
if (attrType === 'ref') {
attr = attribute.ref;
}
const relation = judgeRelation(dataSchema, _entity, attr, true);
if (relation === 1) {
const attributes = getAttributes(dataSchema[_entity].attributes);
attribute = attributes[attr];
attrType = attribute.type;
if (attr === 'id') {
attrType = 'ref';
}
else {
if (attrType === 'ref') {
attr = attribute.ref;
}
}
else if (relation === 2) {
// entity entityId
if (attr === 'entityId') {
attrType = 'ref';
}
_entity = attr;
}
else if (typeof relation === 'string') {
_entity = relation;
}
idx++;
}
catch (err) {
if (process.env.NODE_ENV === 'development') {
console.warn(`存在非「${_entity}」schema属性: ${path}`);
else if (relation === 2) {
// entity entityId
if (attr === 'entityId') {
attrType = 'ref';
}
return {
entity: 'notExist',
attr: path,
attrType: undefined,
attribute,
};
_entity = attr;
}
else if (typeof relation === 'string') {
_entity = relation;
}
idx++;
}
return {
entity: _entity,
@ -123,11 +110,15 @@ export function getLabel(attribute, entity, attr, t) {
}
if (attr === '$$createAt$$' ||
attr === '$$updateAt$$' ||
attr === '$$deleteAt$$') {
attr === '$$deleteAt$$' ||
attr === '$$seq$$') {
return t(`common::${attr}`, {
'#oakModule': 'oak-frontend-base',
});
}
if (attr === 'id') {
return 'id';
}
return t(`${entity}:attr.${attr}`, {});
}
// 目前width属性可以是undefined只有特殊type或用户自定义才有值这样其余attr属性可以自适应

View File

@ -99,7 +99,7 @@ export declare class Cache<ED extends EntityDict & BaseEntityDict, Cxt extends A
mergeSelectResult<T extends keyof ED>(entity: T, rows: Partial<ED[T]['Schema']>[], sr: Record<string, any>): void;
get<T extends keyof ED>(entity: T, selection: ED[T]['Selection'], allowMiss?: boolean, sr?: Record<string, any>): Partial<ED[T]["Schema"]>[];
getById<T extends keyof ED>(entity: T, projection: ED[T]['Selection']['data'], id: string, allowMiss?: boolean): Partial<ED[T]["Schema"]>[];
judgeRelation(entity: keyof ED, attr: string): string | 0 | 1 | string[] | 2;
judgeRelation(entity: keyof ED, attr: string): string | 0 | 1 | string[] | 2 | -1;
bindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
unbindOnSync(callback: (opRecords: OpRecord<ED>[]) => void): void;
getCachedData(): { [T in keyof ED]?: ED[T]["OpSchema"][] | undefined; };

View File

@ -47,7 +47,7 @@ declare abstract class Node<ED extends EntityDict & BaseEntityDict, T extends ke
getParent(): SingleNode<ED, keyof ED, Cxt, FrontCxt, AD> | ListNode<ED, keyof ED, Cxt, FrontCxt, AD> | VirtualNode<ED, Cxt, FrontCxt, AD> | undefined;
protected getProjection(): ED[T]['Selection']['data'] | undefined;
setProjection(projection: ED[T]['Selection']['data']): void;
protected judgeRelation(attr: string): string | 0 | 1 | string[] | 2;
protected judgeRelation(attr: string): string | 0 | 1 | string[] | 2 | -1;
}
declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends CommonAspectDict<ED, Cxt>> extends Node<ED, T, Cxt, FrontCxt, AD> {
private updates;
@ -95,11 +95,19 @@ declare class ListNode<ED extends EntityDict & BaseEntityDict, T extends keyof E
removeNamedSorter(sorter: NamedSorterItem<ED, T>, refresh?: boolean): void;
removeNamedSorterByName(name: string, refresh: boolean): void;
getFreshValue(): Array<Partial<ED[T]['Schema']>>;
private addItemInner;
addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}): string;
addItems(items: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}>): string[];
private removeItemInner;
removeItem(id: string): void;
removeItems(ids: string[]): void;
private recoverItemInner;
recoverItem(id: string): void;
recoverItems(ids: string[]): void;
resetItem(id: string): void;
/**
* itemId进行更新
@ -243,9 +251,14 @@ export declare class RunningTree<ED extends EntityDict & BaseEntityDict, Cxt ext
addItem<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}): string;
addItems<T extends keyof ED>(path: string, data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}>): string[];
removeItem(path: string, id: string): void;
removeItems(path: string, ids: string[]): void;
updateItem<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action']): void;
recoverItem(path: string, id: string): void;
recoverItems(path: string, ids: string[]): void;
resetItem(path: string, id: string): void;
create<T extends keyof ED>(path: string, data: Omit<ED[T]['CreateSingle']['data'], 'id'>): void;
update<T extends keyof ED>(path: string, data: ED[T]['Update']['data'], action?: ED[T]['Action']): void;

View File

@ -488,7 +488,7 @@ class ListNode extends Node {
}, true, this.sr);
return result;
}
addItem(item) {
addItemInner(item) {
// 如果数据键值是一个空字符串则更新成null
for (const k in item) {
if (item[k] === '') {
@ -505,12 +505,20 @@ class ListNode extends Node {
data: Object.assign(item, { id }),
};
this.sr[id] = {};
return id;
}
addItem(item) {
const id = this.addItemInner(item);
this.setDirty();
return id;
}
removeItem(id) {
if (this.updates[id] &&
this.updates[id].action === 'create') {
addItems(items) {
const ids = items.map((item) => this.addItemInner(item));
this.setDirty();
return ids;
}
removeItemInner(id) {
if (this.updates[id] && this.updates[id].action === 'create') {
// 如果是新增项,在这里抵消
(0, lodash_1.unset)(this.updates, id);
(0, lodash_1.unset)(this.sr, id);
@ -525,12 +533,26 @@ class ListNode extends Node {
},
};
}
}
removeItem(id) {
this.removeItemInner(id);
this.setDirty();
}
recoverItem(id) {
removeItems(ids) {
ids.forEach((id) => this.removeItemInner(id));
this.setDirty();
}
recoverItemInner(id) {
const operation = this.updates[id];
(0, assert_1.assert)(operation?.action === 'remove');
(0, lodash_1.unset)(this.updates, id);
}
recoverItem(id) {
this.recoverItemInner(id);
this.setDirty();
}
recoverItems(ids) {
ids.forEach((id) => this.recoverItemInner(id));
this.setDirty();
}
resetItem(id) {
@ -1646,11 +1668,21 @@ class RunningTree extends Feature_1.Feature {
(0, assert_1.assert)(node instanceof ListNode);
return node.addItem(data);
}
addItems(path, data) {
const node = this.findNode(path);
(0, assert_1.assert)(node instanceof ListNode);
return node.addItems(data);
}
removeItem(path, id) {
const node = this.findNode(path);
(0, assert_1.assert)(node instanceof ListNode);
node.removeItem(id);
}
removeItems(path, ids) {
const node = this.findNode(path);
(0, assert_1.assert)(node instanceof ListNode);
node.removeItems(ids);
}
updateItem(path, data, id, action) {
const node = this.findNode(path);
(0, assert_1.assert)(node instanceof ListNode);
@ -1661,6 +1693,11 @@ class RunningTree extends Feature_1.Feature {
(0, assert_1.assert)(node instanceof ListNode);
node.recoverItem(id);
}
recoverItems(path, ids) {
const node = this.findNode(path);
(0, assert_1.assert)(node instanceof ListNode);
node.recoverItems(ids);
}
resetItem(path, id) {
const node = this.findNode(path);
(0, assert_1.assert)(node instanceof ListNode);

View File

@ -370,6 +370,12 @@ const oakBehavior = Behavior({
: this.state.oakFullpath;
return this.features.runningTree.addItem(path2, data);
},
addItems(data, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.addItems(path2, data);
},
updateItem(data, id, action, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -382,12 +388,24 @@ const oakBehavior = Behavior({
: this.state.oakFullpath;
return this.features.runningTree.removeItem(path2, id);
},
removeItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.removeItems(path2, ids);
},
recoverItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.recoverItem(path2, id);
},
recoverItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.recoverItems(path2, ids);
},
resetItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`

13
lib/page.react.d.ts vendored
View File

@ -56,12 +56,17 @@ export declare function createComponent<IsList extends boolean, ED extends Entit
addItem<T extends keyof ED>(data: Omit<ED[T]["CreateSingle"]["data"], "id"> & {
id?: string | undefined;
}, path?: string | undefined): string;
addItems<T_1 extends keyof ED>(data: (Omit<ED[T_1]["CreateSingle"]["data"], "id"> & {
id?: string | undefined;
})[], path?: string | undefined): string[];
removeItem(id: string, path?: string | undefined): void;
updateItem<T_1 extends keyof ED>(data: ED[T_1]["Update"]["data"], id: string, action?: ED[T_1]["Action"] | undefined, path?: string | undefined): void;
removeItems(ids: string[], path?: string | undefined): void;
updateItem<T_2 extends keyof ED>(data: ED[T_2]["Update"]["data"], id: string, action?: ED[T_2]["Action"] | undefined, path?: string | undefined): void;
recoverItem(id: string, path?: string | undefined): void;
recoverItems(ids: string[], path?: string | undefined): void;
resetItem(id: string, path?: string | undefined): void;
update<T_2 extends keyof ED>(data: ED[T_2]["Update"]["data"], action?: ED[T_2]["Action"] | undefined, path?: string | undefined): void;
create<T_3 extends keyof ED>(data: Omit<ED[T_3]["CreateSingle"]["data"], "id">, path?: string | undefined): void;
update<T_3 extends keyof ED>(data: ED[T_3]["Update"]["data"], action?: ED[T_3]["Action"] | undefined, path?: string | undefined): void;
create<T_4 extends keyof ED>(data: Omit<ED[T_4]["CreateSingle"]["data"], "id">, path?: string | undefined): void;
remove(path?: string | undefined): void;
isCreation(path?: string | undefined): boolean;
clean(path?: string | undefined): void;
@ -74,7 +79,7 @@ export declare function createComponent<IsList extends boolean, ED extends Entit
getFreshValue(path?: string | undefined): Partial<ED[keyof ED]["Schema"]> | Partial<ED[keyof ED]["Schema"]>[] | undefined;
checkOperation(entity: T, action: ED[T]["Action"], data?: ED[T]["Update"]["data"] | undefined, filter?: ED[T]["Update"]["filter"] | undefined, checkerTypes?: CheckerType[] | undefined): boolean;
tryExecute(path?: string | undefined): boolean | Error;
getOperations<T_4 extends keyof ED>(path?: string | undefined): {
getOperations<T_5 extends keyof ED>(path?: string | undefined): {
entity: keyof ED;
operation: ED[keyof ED]["Operation"];
}[] | undefined;

View File

@ -92,12 +92,24 @@ class OakComponentBase extends react_1.default.PureComponent {
: this.state.oakFullpath;
return this.features.runningTree.addItem(path2, data);
}
addItems(data, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.addItems(path2, data);
}
removeItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.removeItem(path2, id);
}
removeItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.removeItems(path2, ids);
}
updateItem(data, id, action, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -110,6 +122,12 @@ class OakComponentBase extends react_1.default.PureComponent {
: this.state.oakFullpath;
this.features.runningTree.recoverItem(path2, id);
}
recoverItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.recoverItems(path2, ids);
}
resetItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -431,9 +449,15 @@ function createComponent(option, features) {
addItem: (data, path) => {
return this.addItem(data, path);
},
addItems: (data, path) => {
return this.addItems(data, path);
},
removeItem: (id, path) => {
return this.removeItem(id, path);
},
removeItems: (ids, path) => {
return this.removeItems(ids, path);
},
updateItem: (data, id, action, path) => {
return this.updateItem(data, id, action, path);
},
@ -476,6 +500,9 @@ function createComponent(option, features) {
recoverItem: (id, path) => {
return this.recoverItem(id, path);
},
recoverItems: (ids, path) => {
return this.recoverItems(ids, path);
},
resetItem: (id, path) => {
return this.resetItem(id, path);
},

7
lib/types/Page.d.ts vendored
View File

@ -206,9 +206,14 @@ export type OakListComponentMethods<ED extends EntityDict & BaseEntityDict, T ex
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}, path?: string) => string;
addItems: (data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & {
id?: string;
}>, path?: string) => string[];
removeItem: (id: string, path?: string) => void;
removeItems: (ids: string[], path?: string) => void;
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], path?: string) => void;
recoverItem: (id: string, path?: string) => void;
recoverItems: (ids: string[], path?: string) => void;
resetItem: (id: string, path?: string) => void;
};
type ComponentOnPropsChangeOption = {
@ -244,7 +249,7 @@ type OakListComoponetData<ED extends EntityDict & BaseEntityDict, T extends keyo
};
export type MakeOakComponent<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>, FrontCxt extends SyncContext<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature>> = <IsList extends boolean, T extends keyof ED, FormedData extends DataOption, TData extends DataOption, TProperty extends DataOption, TMethod extends MethodOption>(options: OakComponentOption<IsList, ED, T, Cxt, FrontCxt, AD, FD, FormedData, TData, TProperty, TMethod>) => (props: ReactComponentProps<ED, T, IsList, TProperty>) => React.ReactElement;
export type WebComponentCommonMethodNames = 'setNotification' | 'setMessage' | 'navigateTo' | 'navigateBack' | 'redirectTo' | 'clean' | 't' | 'execute' | 'refresh' | 'aggregate' | 'checkOperation' | 'isDirty';
export type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters' | 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'removeItem' | 'updateItem' | 'resetItem' | 'recoverItem';
export type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters' | 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'addItems' | 'removeItem' | 'removeItems' | 'updateItem' | 'resetItem' | 'recoverItem' | 'recoverItems';
export type WebComponentSingleMethodNames = 'update' | 'remove' | 'create' | 'isCreation';
export type WebComponentProps<ED extends EntityDict & BaseEntityDict, T extends keyof ED, IsList extends boolean, TData extends DataOption = {}, TMethod extends MethodOption = {}> = {
methods: TMethod & OakCommonComponentMethods<ED, T> & OakListComponentMethods<ED, T> & OakSingleComponentMethods<ED, T>;

View File

@ -50,44 +50,31 @@ function resolvePath(dataSchema, entity, path) {
idx++;
continue;
}
try {
const relation = (0, relation_1.judgeRelation)(dataSchema, _entity, attr);
if (relation === 1) {
const attributes = getAttributes(dataSchema[_entity].attributes);
attribute = attributes[attr];
attrType = attribute.type;
if (attr === 'id') {
attrType = 'ref';
}
else {
if (attrType === 'ref') {
attr = attribute.ref;
}
const relation = (0, relation_1.judgeRelation)(dataSchema, _entity, attr, true);
if (relation === 1) {
const attributes = getAttributes(dataSchema[_entity].attributes);
attribute = attributes[attr];
attrType = attribute.type;
if (attr === 'id') {
attrType = 'ref';
}
else {
if (attrType === 'ref') {
attr = attribute.ref;
}
}
else if (relation === 2) {
// entity entityId
if (attr === 'entityId') {
attrType = 'ref';
}
_entity = attr;
}
else if (typeof relation === 'string') {
_entity = relation;
}
idx++;
}
catch (err) {
if (process.env.NODE_ENV === 'development') {
console.warn(`存在非「${_entity}」schema属性: ${path}`);
else if (relation === 2) {
// entity entityId
if (attr === 'entityId') {
attrType = 'ref';
}
return {
entity: 'notExist',
attr: path,
attrType: undefined,
attribute,
};
_entity = attr;
}
else if (typeof relation === 'string') {
_entity = relation;
}
idx++;
}
return {
entity: _entity,
@ -131,11 +118,15 @@ function getLabel(attribute, entity, attr, t) {
}
if (attr === '$$createAt$$' ||
attr === '$$updateAt$$' ||
attr === '$$deleteAt$$') {
attr === '$$deleteAt$$' ||
attr === '$$seq$$') {
return t(`common::${attr}`, {
'#oakModule': 'oak-frontend-base',
});
}
if (attr === 'id') {
return 'id';
}
return t(`${entity}:attr.${attr}`, {});
}
exports.getLabel = getLabel;

View File

@ -1,6 +1,6 @@
{
"name": "oak-frontend-base",
"version": "4.2.2",
"version": "4.2.4",
"description": "oak框架中前端与业务逻辑无关的平台部分",
"author": {
"name": "XuChang"
@ -31,7 +31,8 @@
"react-responsive": "^9.0.2",
"rmc-pull-to-refresh": "^1.0.13",
"socket.io-client": "^4.7.2",
"uuid": "^8.3.2"
"uuid": "^8.3.2",
"weapp.socket.io": "^2.2.1"
},
"peerDependencies": {
"@ant-design/icons": ">=5.2.6",
@ -93,4 +94,4 @@
"module": "es/index",
"types": "es/index.d.ts",
"typings": "es/index.d.ts"
}
}

View File

@ -615,7 +615,7 @@ class ListNode<
return result;
}
addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }) {
private addItemInner(item: Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }) {
// 如果数据键值是一个空字符串则更新成null
for (const k in item) {
if (item[k] === '') {
@ -632,15 +632,25 @@ class ListNode<
data: Object.assign(item, { id }),
};
this.sr[id] = {};
return id;
}
addItem(item: Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }) {
const id = this.addItemInner(item);
this.setDirty();
return id;
}
removeItem(id: string) {
if (
this.updates[id] &&
this.updates[id].action === 'create'
) {
addItems(items: Array< Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }>) {
const ids = items.map(
(item) => this.addItemInner(item)
);
this.setDirty();
return ids;
}
private removeItemInner(id: string) {
if (this.updates[id] && this.updates[id].action === 'create') {
// 如果是新增项,在这里抵消
unset(this.updates, id);
unset(this.sr, id);
@ -654,13 +664,35 @@ class ListNode<
},
};
}
}
removeItem(id: string) {
this.removeItemInner(id);
this.setDirty();
}
recoverItem(id: string) {
removeItems(ids: string[]) {
ids.forEach(
(id) => this.removeItemInner(id)
);
this.setDirty();
}
private recoverItemInner(id: string) {
const operation = this.updates[id];
assert(operation?.action === 'remove');
unset(this.updates, id);
}
recoverItem(id: string) {
this.recoverItemInner(id);
this.setDirty();
}
recoverItems(ids: string[]) {
ids.forEach(
(id) => this.recoverItemInner(id)
);
this.setDirty();
}
@ -1995,15 +2027,24 @@ export class RunningTree<
return node.addItem(data);
}
removeItem(
path: string,
id: string
) {
addItems<T extends keyof ED>(path: string, data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }>) {
const node = this.findNode(path);
assert(node instanceof ListNode);
return node.addItems(data);
}
removeItem(path: string, id: string) {
const node = this.findNode(path);
assert(node instanceof ListNode);
node.removeItem(id);
}
removeItems(path: string, ids: string[]) {
const node = this.findNode(path);
assert(node instanceof ListNode);
node.removeItems(ids);
}
updateItem<T extends keyof ED>(
path: string,
data: ED[T]['Update']['data'],
@ -2021,6 +2062,12 @@ export class RunningTree<
node.recoverItem(id);
}
recoverItems(path: string, ids: string[]) {
const node = this.findNode(path);
assert(node instanceof ListNode);
node.recoverItems(ids);
}
resetItem(path: string, id: string) {
const node = this.findNode(path);
assert(node instanceof ListNode);

View File

@ -578,6 +578,12 @@ const oakBehavior = Behavior<
: this.state.oakFullpath;
return this.features.runningTree.addItem(path2, data);
},
addItems(data, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.addItems(path2, data);
},
updateItem(data, id, action, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -595,12 +601,24 @@ const oakBehavior = Behavior<
: this.state.oakFullpath;
return this.features.runningTree.removeItem(path2, id);
},
removeItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.removeItems(path2, ids);
},
recoverItem(id, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.recoverItem(path2, id);
},
recoverItems(ids, path) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.recoverItems(path2, ids);
},
resetItem(id: string, path?: string) {
const path2 = path
? `${this.state.oakFullpath}.${path}`

View File

@ -197,10 +197,20 @@ abstract class OakComponentBase<
);
}
removeItem(
id: string,
addItems<T extends keyof ED>(
data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }>,
path?: string
) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
return this.features.runningTree.addItems(
path2,
data
);
}
removeItem(id: string, path?: string) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
@ -210,6 +220,13 @@ abstract class OakComponentBase<
);
}
removeItems(ids: string[], path?: string) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.removeItems(path2, ids);
}
updateItem<T extends keyof ED>(
data: ED[T]['Update']['data'],
id: string,
@ -234,6 +251,13 @@ abstract class OakComponentBase<
this.features.runningTree.recoverItem(path2, id);
}
recoverItems(ids: string[], path?: string) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
: this.state.oakFullpath;
this.features.runningTree.recoverItems(path2, ids);
}
resetItem(id: string, path?: string) {
const path2 = path
? `${this.state.oakFullpath}.${path}`
@ -741,9 +765,15 @@ export function createComponent<
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }, path?: string) => {
return this.addItem(data, path);
},
addItems: (data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'>> & { id?: string }, path?: string) => {
return this.addItems(data, path);
},
removeItem: (id: string, path?: string) => {
return this.removeItem(id, path);
},
removeItems: (ids: string[], path?: string) => {
return this.removeItems(ids, path);
},
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], path?: string) => {
return this.updateItem(data, id, action, path);
},
@ -786,6 +816,9 @@ export function createComponent<
recoverItem: (id: string, path?: string) => {
return this.recoverItem(id, path);
},
recoverItems: (ids: string[], path?: string) => {
return this.recoverItems(ids, path);
},
resetItem: (id: string, path?: string) => {
return this.resetItem(id, path);
},

View File

@ -439,9 +439,12 @@ export type OakListComponentMethods<ED extends EntityDict & BaseEntityDict, T ex
setCurrentPage: (current: number, path?: string) => void;
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }, path?: string) => string;
addItems: (data: Array<Omit<ED[T]['CreateSingle']['data'], 'id'> & { id?: string }>, path?: string) => string[];
removeItem: (id: string, path?: string) => void;
removeItems: (ids: string[], path?: string) => void;
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], path?: string) => void;
recoverItem: (id: string, path?: string) => void;
recoverItems: (ids: string[], path?: string) => void;
resetItem: (id: string, path?: string) => void;
};
@ -522,7 +525,8 @@ export type WebComponentCommonMethodNames = 'setNotification' | 'setMessage' | '
// 暴露给list组件的方法
export type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters'
| 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'removeItem' | 'updateItem' | 'resetItem' | 'recoverItem';
| 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage'
| 'addItem' | 'addItems' | 'removeItem' | 'removeItems' | 'updateItem' | 'resetItem' | 'recoverItem' | 'recoverItems';
// 暴露给single组件的方法
export type WebComponentSingleMethodNames = 'update' | 'remove' | 'create' | 'isCreation';

View File

@ -85,42 +85,30 @@ export function resolvePath<ED extends EntityDict & BaseEntityDict>(
idx++;
continue;
}
try {
const relation = judgeRelation(dataSchema, _entity, attr);
if (relation === 1) {
const attributes = getAttributes(
dataSchema[_entity].attributes
);
attribute = attributes[attr];
attrType = attribute.type;
if (attr === 'id') {
attrType = 'ref';
} else {
if (attrType === 'ref') {
attr = attribute.ref as string;
}
const relation = judgeRelation(dataSchema, _entity, attr, true);
if (relation === 1) {
const attributes = getAttributes(
dataSchema[_entity].attributes
);
attribute = attributes[attr];
attrType = attribute.type;
if (attr === 'id') {
attrType = 'ref';
} else {
if (attrType === 'ref') {
attr = attribute.ref as string;
}
} else if (relation === 2) {
// entity entityId
if (attr === 'entityId') {
attrType = 'ref';
}
_entity = attr as keyof ED;
} else if (typeof relation === 'string') {
_entity = relation as keyof ED;
}
idx++;
} catch (err) {
if (process.env.NODE_ENV === 'development') {
console.warn(`存在非「${_entity as string}」schema属性: ${path}`);
} else if (relation === 2) {
// entity entityId
if (attr === 'entityId') {
attrType = 'ref';
}
return {
entity: 'notExist',
attr: path,
attrType: undefined,
attribute,
};
_entity = attr as keyof ED;
} else if (typeof relation === 'string') {
_entity = relation as keyof ED;
}
idx++;
}
return {
entity: _entity,
@ -174,12 +162,16 @@ export function getLabel<ED extends EntityDict & BaseEntityDict>(
if (
attr === '$$createAt$$' ||
attr === '$$updateAt$$' ||
attr === '$$deleteAt$$'
attr === '$$deleteAt$$' ||
attr === '$$seq$$'
) {
return t(`common::${attr}`, {
'#oakModule': 'oak-frontend-base',
});
}
if (attr === 'id') {
return 'id';
}
return t(`${entity as string}:attr.${attr}`, {});
}