增加了一些启动文件

This commit is contained in:
Xu Chang 2022-06-28 12:45:50 +08:00
parent 816aadd71f
commit 6659109f81
5 changed files with 1144 additions and 0 deletions

17
lib/page.common.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
/// <reference types="wechat-miniprogram" />
import { CommonAspectDict } from "oak-common-aspect";
import { Aspect, Context, EntityDict } from "oak-domain/lib/types";
import { BasicFeatures } from "./features";
import { ExceptionHandler } from "./types/ExceptionRoute";
import { Feature } from "./types/Feature";
import { OakCommonComponentMethods, OakComponentData, OakComponentProperties, OakHiddenComponentMethods, OakListComponentMethods, OakPageMethods, OakPageOption } from "./types/Page";
export declare type ComponentThisType<ED extends EntityDict, T extends keyof ED, FormedData extends WechatMiniprogram.Component.DataOption, IsList extends boolean, TData extends WechatMiniprogram.Component.DataOption = {}, TProperty extends WechatMiniprogram.Component.PropertyOption = {}, TMethod extends WechatMiniprogram.Component.MethodOption = {}> = ThisType<{
state: TData & FormedData & OakComponentData<ED, T>;
props: OakComponentProperties & WechatMiniprogram.Component.PropertyOptionToData<TProperty>;
setState: (data: any, callback?: () => void) => Promise<void>;
triggerEvent: <DetailType = any>(name: string, detail?: DetailType, options?: WechatMiniprogram.Component.TriggerEventOption) => void;
} & TMethod & OakCommonComponentMethods<ED, T> & OakHiddenComponentMethods & (IsList extends true ? OakListComponentMethods<ED, T> : {})>;
export declare function makeHiddenComponentMethods<ED extends EntityDict, T extends keyof ED, FormedData extends WechatMiniprogram.Component.DataOption, IsList extends boolean, TData extends WechatMiniprogram.Component.DataOption = {}, TProperty extends WechatMiniprogram.Component.PropertyOption = {}, TMethod extends WechatMiniprogram.Component.MethodOption = {}>(): OakHiddenComponentMethods & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod>;
export declare function makeCommonComponentMethods<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>>, FormedData extends WechatMiniprogram.Component.DataOption, Proj extends ED[T]['Selection']['data'], IsList extends boolean, TData extends WechatMiniprogram.Component.DataOption = {}, TProperty extends WechatMiniprogram.Component.PropertyOption = {}, TMethod extends WechatMiniprogram.Component.MethodOption = {}>(features: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> & FD, exceptionRouterDict: Record<string, ExceptionHandler>, formData: OakPageOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod>['formData']): Omit<OakCommonComponentMethods<ED, T>, 'navigateTo' | 'navigateBack' | 'resolveInput'> & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod>;
export declare function makeListComponentMethods<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>>, FormedData extends WechatMiniprogram.Component.DataOption, IsList extends boolean, TData extends WechatMiniprogram.Component.DataOption = {}, TProperty extends WechatMiniprogram.Component.PropertyOption = {}, TMethod extends WechatMiniprogram.Component.MethodOption = {}>(features: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> & FD): OakListComponentMethods<ED, T> & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod>;
export declare function makePageMethods<ED extends EntityDict, T extends keyof ED, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>>, FormedData extends WechatMiniprogram.Component.DataOption, Proj extends ED[T]['Selection']['data'], IsList extends boolean, TData extends WechatMiniprogram.Component.DataOption = {}, TProperty extends WechatMiniprogram.Component.PropertyOption = {}, TMethod extends WechatMiniprogram.Component.MethodOption = {}>(features: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> & FD, options: OakPageOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod>): OakPageMethods & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod>;

445
lib/page.common.js Normal file
View File

@ -0,0 +1,445 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makePageMethods = exports.makeListComponentMethods = exports.makeCommonComponentMethods = exports.makeHiddenComponentMethods = void 0;
const assert_1 = __importDefault(require("assert"));
const lodash_1 = require("lodash");
const types_1 = require("oak-domain/lib/types");
const Feature_1 = require("./types/Feature");
function makeHiddenComponentMethods() {
return {
subscribe() {
if (!this.subscribed) {
this.subscribed = (0, Feature_1.subscribe)(() => this.reRender());
}
},
unsubscribe() {
if (this.subscribed) {
this.subscribed();
this.subscribed = undefined;
}
},
};
}
exports.makeHiddenComponentMethods = makeHiddenComponentMethods;
function makeCommonComponentMethods(features, exceptionRouterDict, formData) {
return {
t(key, params) {
return 'not implemented';
},
async reRender(extra) {
if (this.state.oakFullpath) {
const rows = features.runningTree.getFreshValue(this.state.oakFullpath);
const dirty = features.runningTree.isDirty(this.state.oakFullpath);
const oakLegalActions = [];
if (this.state.newOakActions) {
for (const action of this.state.newOakActions) {
try {
await features.runningTree.testAction(this.state.oakFullpath, action);
oakLegalActions.push(action);
}
catch (e) {
if (e instanceof types_1.OakInputIllegalException) {
oakLegalActions.push(action);
}
}
}
}
const data = await formData.call(this, {
data: rows,
features,
params: this.state,
legalActions: oakLegalActions,
});
for (const k in data) {
if (data[k] === undefined) {
(0, lodash_1.assign)(data, {
[k]: null,
});
}
}
(0, lodash_1.assign)(data, { oakDirty: dirty });
if (extra) {
(0, lodash_1.assign)(data, extra);
}
(0, lodash_1.assign)(data, {
oakLegalActions,
});
this.setState(data);
}
},
callPicker(attr, params) {
if (this.state.oakExecuting) {
return;
}
const relation = features.cache.judgeRelation(this.state.oakEntity, attr);
let subEntity;
if (relation === 2) {
subEntity = attr;
}
else {
(0, assert_1.default)(typeof relation === 'string');
subEntity = relation;
}
let url = `/pages/pickers/${subEntity}/index?oakIsPicker=true&oakParentEntity=${this.state.oakEntity}&oakParent=${this.state.oakFullpath}&oakPath=${attr}`;
for (const k in params) {
url += `&${k}=${JSON.stringify(params[k])}`;
}
this.navigateTo({
url,
});
},
setForeignKey(id, goBackDelta = -1) {
if (this.state.oakExecuting) {
return;
}
const { oakIsPicker, oakParent, oakPath } = this.state;
(0, assert_1.default)(oakIsPicker);
features.runningTree.setForeignKey(oakParent, oakPath, id);
if (goBackDelta !== 0) {
this.navigateBack({
delta: goBackDelta,
});
}
},
addForeignKeys(ids, goBackDelta = -1) {
if (this.state.oakExecuting) {
return;
}
const { oakIsPicker, oakParent, oakPath } = this.state;
(0, assert_1.default)(oakIsPicker);
features.runningTree.addForeignKeys(oakParent, oakPath, ids);
if (goBackDelta !== 0) {
this.navigateBack({
delta: goBackDelta,
});
}
},
setUniqueForeignKeys(ids, goBackDelta = -1) {
if (this.state.oakExecuting) {
return;
}
const { oakIsPicker, oakParent, oakPath } = this.state;
(0, assert_1.default)(oakIsPicker);
features.runningTree.setUniqueForeignKeys(oakParent, oakPath, ids);
if (goBackDelta !== 0) {
this.navigateBack({
delta: goBackDelta,
});
}
},
async execute(action, legalExceptions) {
if (this.state.oakExecuting) {
return;
}
this.setState({
oakExecuting: true,
oakFocused: {},
});
try {
const result = await features.runningTree.execute(this.state.oakFullpath, action);
this.setState({ oakExecuting: false });
this.setState({
oakError: {
type: 'success',
msg: '操作成功',
},
});
return result;
}
catch (err) {
if (err instanceof types_1.OakException) {
if (err instanceof types_1.OakInputIllegalException) {
const attr = err.getAttributes()[0];
this.setState({
oakFocused: {
[attr]: true,
},
oakExecuting: false,
oakError: {
type: 'warning',
msg: err.message,
},
});
}
else {
const { name } = err.constructor;
const handler = exceptionRouterDict[name];
if (legalExceptions && legalExceptions.includes(name)) {
// 如果调用时就知道有异常,直接抛出
this.setState({
oakExecuting: false,
});
throw err;
}
else if (handler) {
const { hidden, level, handler: fn, router } = handler;
if (!hidden) {
this.setState({
oakExecuting: false,
oakError: {
type: level,
msg: err.message,
},
});
}
else {
this.setState({
oakExecuting: false,
});
}
if (fn) {
fn(err);
return;
}
else if (router) {
this.setState({
oakExecuting: false,
});
this.navigateTo({
url: router,
});
}
}
else {
this.setState({
oakExecuting: false,
oakError: {
type: 'warning',
msg: err.message,
},
});
}
}
}
else {
this.setState({
oakExecuting: false,
oakError: {
type: 'error',
msg: err.message,
},
});
}
throw err;
}
},
resetUpdateData() {
return features.runningTree.resetUpdateData(this.state.oakFullpath);
},
setUpdateData(attr, value) {
if (this.state.oakExecuting) {
return;
}
return features.runningTree.setUpdateData(this.state.oakFullpath, attr, value);
},
};
}
exports.makeCommonComponentMethods = makeCommonComponentMethods;
function makeListComponentMethods(features) {
return {
pushNode(path, options) {
const path2 = path ? `${this.state.oakFullpath}.${path}` : this.state.oakFullpath;
features.runningTree.pushNode(path2, options || {});
},
removeNode(parent, path) {
features.runningTree.removeNode(parent, path);
},
async getFilters() {
const namedFilters = features.runningTree.getNamedFilters(this.state.oakFullpath);
const filters = await Promise.all(namedFilters.map(({ filter }) => {
if (typeof filter === 'function') {
return filter();
}
return filter;
}));
return filters;
},
async getFilterByName(name) {
const filter = features.runningTree.getNamedFilterByName(this.state.oakFullpath, name);
if (filter?.filter) {
if (typeof filter.filter === 'function') {
return filter.filter();
}
return filter.filter;
}
return;
},
addNamedFilter(namedFilter, refresh = false) {
return features.runningTree.addNamedFilter(this.state.oakFullpath, namedFilter, refresh);
},
removeNamedFilter(namedFilter, refresh = false) {
return features.runningTree.removeNamedFilter(this.state.oakFullpath, namedFilter, refresh);
},
removeNamedFilterByName(name, refresh = false) {
return features.runningTree.removeNamedFilterByName(this.state.oakFullpath, name, refresh);
},
setNamedSorters(namedSorters) {
return features.runningTree.setNamedSorters(this.state.oakFullpath, namedSorters);
},
async getSorters() {
const namedSorters = features.runningTree.getNamedSorters(this.state.oakFullpath);
const sorters = (await Promise.all(namedSorters.map(({ sorter }) => {
if (typeof sorter === 'function') {
return sorter();
}
return sorter;
}))).filter(ele => !!ele);
return sorters;
},
async getSorterByName(name) {
const sorter = features.runningTree.getNamedSorterByName(this.state.oakFullpath, name);
if (sorter?.sorter) {
if (typeof sorter.sorter === 'function') {
return sorter.sorter();
}
return sorter.sorter;
}
return;
},
addNamedSorter(namedSorter, refresh = false) {
return features.runningTree.addNamedSorter(this.state.oakFullpath, namedSorter, refresh);
},
removeNamedSorter(namedSorter, refresh = false) {
return features.runningTree.removeNamedSorter(this.state.oakFullpath, namedSorter, refresh);
},
removeNamedSorterByName(name, refresh = false) {
return features.runningTree.removeNamedSorterByName(this.state.oakFullpath, name, refresh);
},
setFilters(filters) {
return features.runningTree.setNamedFilters(this.state.oakFullpath, filters);
},
};
}
exports.makeListComponentMethods = makeListComponentMethods;
function makePageMethods(features, options) {
return {
async refresh() {
if (options.projection && this.state.oakFullpath) {
this.setState({
oakLoading: true,
});
try {
await features.runningTree.refresh(this.state.oakFullpath);
this.setState({
oakLoading: false,
});
}
catch (err) {
this.setState({
oakLoading: false,
oakError: {
type: 'error',
msg: err.message,
},
});
}
;
}
},
async onPullDownRefresh() {
if (options.projection) {
await this.refresh();
}
},
async onReachBottom() {
if (options.isList && options.append && options.projection) {
this.setState({
oakMoreLoading: true,
});
try {
await features.runningTree.loadMore(this.state.oakFullpath);
this.setState({
oakMoreLoading: false,
});
}
catch (err) {
this.setState({
oakMoreLoading: false,
oakError: {
type: 'error',
msg: err.message,
},
});
}
}
},
async onLoad(pageOption) {
const { oakId, oakEntity, oakPath, oakProjection, oakParent, oakSorters, oakFilters, oakIsPicker, oakFrom, oakActions, ...rest } = this.state;
(0, assert_1.default)(!(options.isList && oakId));
const filters = [];
if (oakFilters?.length > 0) {
// 这里在跳页面的时候用this.navigate应该可以限制传过来的filter的格式
const oakFilters2 = JSON.parse(oakFilters);
filters.push(...oakFilters2);
}
else if (options.filters) {
for (const ele of options.filters) {
const { filter, "#name": name } = ele;
filters.push({
filter: typeof filter === 'function' ? await filter({
features,
rest,
onLoadOptions: pageOption,
}) : filter,
['#name']: name,
});
}
}
let proj = oakProjection && JSON.parse(oakProjection);
if (!proj && options.projection) {
const { projection } = options;
proj = typeof projection === 'function' ? () => projection({
features,
rest,
onLoadOptions: pageOption,
}) : projection;
}
let sorters = [];
if (oakSorters?.length > 0) {
// 这里在跳页面的时候用this.navigate应该可以限制传过来的sorter的格式
const oakSorters2 = JSON.parse(oakSorters);
sorters.push(...oakSorters2);
}
else if (options.sorters) {
for (const ele of options.sorters) {
const { sorter, "#name": name } = ele;
sorters.push({
sorter: typeof sorter === 'function' ? await sorter({
features,
rest,
onLoadOptions: pageOption,
}) : sorter,
['#name']: name,
});
}
}
const path2 = oakParent ? `${oakParent}:${oakPath || options.path}` : oakPath || options.path;
const node = await features.runningTree.createNode({
path: path2,
entity: (oakEntity || options.entity),
isList: options.isList,
isPicker: oakIsPicker,
projection: proj,
pagination: options.pagination,
filters,
sorters,
id: oakId,
});
// const oakFullpath = oakParent ? `${oakParent}.${oakPath || options.path}` : oakPath || options.path;
this.setState({
oakEntity: node.getEntity(),
oakFullpath: path2,
oakFrom,
newOakActions: oakActions && JSON.parse(oakActions).length > 0
? JSON.parse(oakActions)
: options.actions || [],
}, () => {
this.refresh();
});
},
};
}
exports.makePageMethods = makePageMethods;

100
src/initialize-dev.ts Normal file
View File

@ -0,0 +1,100 @@
import { Aspect, AspectWrapper, Checker, Trigger, StorageSchema, Context, RowStore, OakRowInconsistencyException, Watcher } from "oak-domain/lib/types";
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { Feature } from './types/Feature';
import { createDebugStore } from './debugStore';
import { initialize as createBasicFeatures, BasicFeatures } from './features';
import { assign, intersection, keys } from 'lodash';
import commonAspectDict from 'oak-common-aspect';
import { ActionDictOfEntityDict } from "oak-domain/lib/types/Action";
import { analyzeActionDefDict } from "oak-domain/lib/store/actionDef";
import { CommonAspectDict } from "oak-common-aspect";
import { CacheStore } from "./cacheStore/CacheStore";
/**
* dev模式下使Cxt
* @param storageSchema
* @param createFeatures
* @param contextBuilder
* @param context
* @param triggers
* @param checkers
* @param watchers
* @param aspectDict
* @param initialData
* @param actionDict
* @returns
*/
export function initialize<ED extends EntityDict, Cxt extends Context<ED>, AD extends Record<string, Aspect<ED, Cxt>>, FD extends Record<string, Feature<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>>>(
storageSchema: StorageSchema<ED>,
createFeatures: (aspectWrapper: AspectWrapper<ED, Cxt, AD>, basicFeatures: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>, context: Cxt) => FD,
contextBuilder: (cxtString?: string) => (store: RowStore<ED, Cxt>) => Cxt,
aspectDict: AD,
triggers?: Array<Trigger<ED, keyof ED, Cxt>>,
checkers?: Array<Checker<ED, keyof ED, Cxt>>,
watchers?: Array<Watcher<ED, keyof ED, Cxt>>,
initialData?: {
[T in keyof ED]?: Array<ED[T]['OpSchema']>;
},
actionDict?: ActionDictOfEntityDict<ED>) {
let intersect = intersection(keys(commonAspectDict), keys(aspectDict));
if (intersect.length > 0) {
throw new Error(`用户定义的aspect中不能和系统aspect同名${intersect.join(',')}`);
}
const aspectDict2 = assign({}, commonAspectDict, aspectDict);
const debugStore = createDebugStore(storageSchema, contextBuilder, triggers || [], checkers || [], watchers || [], initialData, actionDict);
const cacheStore = new CacheStore(storageSchema, contextBuilder);
if (checkers) {
checkers.forEach(
(checker) => cacheStore.registerChecker(checker)
);
}
if (actionDict) {
const { checkers: adCheckers } = analyzeActionDefDict(storageSchema, actionDict);
adCheckers.forEach(
(checker) => cacheStore.registerChecker(checker)
);
}
const context = contextBuilder()(cacheStore);
const wrapper: AspectWrapper<ED, Cxt, typeof aspectDict2> = {
exec: async (name, params) => {
const str = await context.toString();
const contextBackend = contextBuilder(str)(debugStore);
await contextBackend.begin();
let result;
try {
result = await aspectDict2[name](params, contextBackend);
await contextBackend.commit();
}
catch (err) {
await contextBackend.rollback();
throw err;
}
return {
result,
opRecords: contextBackend.opRecords,
};
}
};
const basicFeatures = createBasicFeatures<ED, Cxt, typeof aspectDict2>(wrapper, storageSchema, context, cacheStore);
// basicFeatures.runningNode.setStorageSchema(storageSchema);
const userDefinedfeatures = createFeatures(wrapper, basicFeatures, context);
intersect = intersection(keys(basicFeatures), keys(userDefinedfeatures));
if (intersect.length > 0) {
throw new Error(`用户定义的feature中不能和系统feature同名${intersect.join(',')}`);
}
const features = assign(basicFeatures, userDefinedfeatures);
return {
features,
context,
};
}

565
src/page.common.ts Normal file
View File

@ -0,0 +1,565 @@
import assert from "assert";
import { assign, omit } from "lodash";
import { CommonAspectDict } from "oak-common-aspect";
import { Aspect, Context, DeduceSorterItem, EntityDict, OakException, OakInputIllegalException } from "oak-domain/lib/types";
import { BasicFeatures } from "./features";
import { ExceptionHandler } from "./types/ExceptionRoute";
import { Feature, subscribe } from "./types/Feature";
import { NamedFilterItem, NamedSorterItem } from "./types/NamedCondition";
import { OakCommonComponentMethods, OakComponentData, OakComponentOption, OakComponentProperties, OakHiddenComponentMethods, OakListComponentMethods, OakPageMethods, OakPageOption } from "./types/Page";
export type ComponentThisType<ED extends EntityDict,
T extends keyof ED,
FormedData extends WechatMiniprogram.Component.DataOption,
IsList extends boolean,
TData extends WechatMiniprogram.Component.DataOption = {},
TProperty extends WechatMiniprogram.Component.PropertyOption = {},
TMethod extends WechatMiniprogram.Component.MethodOption = {}> = ThisType<{
state: TData & FormedData & OakComponentData<ED, T>;
props: OakComponentProperties & WechatMiniprogram.Component.PropertyOptionToData<TProperty>;
setState: (
data: any,
callback?: () => void,
) => Promise<void>;
triggerEvent: <DetailType = any>(
name: string,
detail?: DetailType,
options?: WechatMiniprogram.Component.TriggerEventOption
) => void
} &
TMethod &
OakCommonComponentMethods<ED, T> &
OakHiddenComponentMethods &
(IsList extends true ? OakListComponentMethods<ED, T> : {})
>;
export function makeHiddenComponentMethods<ED extends EntityDict,
T extends keyof ED,
FormedData extends WechatMiniprogram.Component.DataOption,
IsList extends boolean,
TData extends WechatMiniprogram.Component.DataOption = {},
TProperty extends WechatMiniprogram.Component.PropertyOption = {},
TMethod extends WechatMiniprogram.Component.MethodOption = {}>(): OakHiddenComponentMethods & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod> {
return {
subscribe() {
if (!this.subscribed) {
this.subscribed = subscribe(
() => this.reRender()
);
}
},
unsubscribe() {
if (this.subscribed) {
this.subscribed();
this.subscribed = undefined;
}
},
};
}
export function makeCommonComponentMethods<ED extends EntityDict,
T extends keyof ED,
Cxt extends Context<ED>,
AD extends Record<string, Aspect<ED, Cxt>>,
FD extends Record<string, Feature<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>>,
FormedData extends WechatMiniprogram.Component.DataOption,
Proj extends ED[T]['Selection']['data'],
IsList extends boolean,
TData extends WechatMiniprogram.Component.DataOption = {},
TProperty extends WechatMiniprogram.Component.PropertyOption = {},
TMethod extends WechatMiniprogram.Component.MethodOption = {}>(
features: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> & FD,
exceptionRouterDict: Record<string, ExceptionHandler>,
formData: OakPageOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod>['formData']
): Omit<OakCommonComponentMethods<ED, T>, 'navigateTo' | 'navigateBack' | 'resolveInput'> & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod> {
return {
t(key: string, params?: object) {
return 'not implemented';
},
async reRender(extra) {
if (this.state.oakFullpath) {
const rows = features.runningTree.getFreshValue(this.state.oakFullpath);
const dirty = features.runningTree.isDirty(this.state.oakFullpath);
const oakLegalActions = [];
if (this.state.newOakActions) {
for (const action of this.state.newOakActions) {
try {
await features.runningTree.testAction(this.state.oakFullpath, action);
oakLegalActions.push(action);
}
catch (e) {
if (e instanceof OakInputIllegalException) {
oakLegalActions.push(action);
}
}
}
}
const data = await formData.call(this, {
data: rows as any,
features,
params: this.state,
legalActions: oakLegalActions,
});
for (const k in data) {
if (data[k] === undefined) {
assign(data, {
[k]: null,
})
}
}
assign(data, { oakDirty: dirty });
if (extra) {
assign(data, extra);
}
assign(data, {
oakLegalActions,
});
this.setState(data);
}
},
callPicker(attr: string, params: Record<string, any>) {
if (this.state.oakExecuting) {
return;
}
const relation = features.cache.judgeRelation(this.state.oakEntity, attr);
let subEntity: string;
if (relation === 2) {
subEntity = attr;
}
else {
assert(typeof relation === 'string');
subEntity = relation;
}
let url = `/pages/pickers/${subEntity}/index?oakIsPicker=true&oakParentEntity=${this.state.oakEntity}&oakParent=${this.state.oakFullpath}&oakPath=${attr}`;
for (const k in params) {
url += `&${k}=${JSON.stringify(params[k])}`;
}
this.navigateTo({
url,
});
},
setForeignKey(id: string, goBackDelta: number = -1) {
if (this.state.oakExecuting) {
return;
}
const { oakIsPicker, oakParent, oakPath } = this.state;
assert(oakIsPicker);
features.runningTree.setForeignKey(oakParent, oakPath, id);
if (goBackDelta !== 0) {
this.navigateBack({
delta: goBackDelta,
});
}
},
addForeignKeys(ids: string[], goBackDelta: number = -1) {
if (this.state.oakExecuting) {
return;
}
const { oakIsPicker, oakParent, oakPath } = this.state;
assert(oakIsPicker);
features.runningTree.addForeignKeys(oakParent, oakPath, ids);
if (goBackDelta !== 0) {
this.navigateBack({
delta: goBackDelta,
});
}
},
setUniqueForeignKeys(ids: string[], goBackDelta: number = -1) {
if (this.state.oakExecuting) {
return;
}
const { oakIsPicker, oakParent, oakPath } = this.state;
assert(oakIsPicker);
features.runningTree.setUniqueForeignKeys(oakParent, oakPath, ids);
if (goBackDelta !== 0) {
this.navigateBack({
delta: goBackDelta,
});
}
},
async execute(action, legalExceptions) {
if (this.state.oakExecuting) {
return;
}
this.setState({
oakExecuting: true,
oakFocused: {},
});
try {
const result = await features.runningTree.execute(this.state.oakFullpath, action);
this.setState({ oakExecuting: false });
this.setState({
oakError: {
type: 'success',
msg: '操作成功',
},
});
return result;
}
catch (err) {
if (err instanceof OakException) {
if (err instanceof OakInputIllegalException) {
const attr = err.getAttributes()[0];
this.setState({
oakFocused: {
[attr]: true,
},
oakExecuting: false,
oakError: {
type: 'warning',
msg: err.message,
},
});
}
else {
const { name } = err.constructor;
const handler = exceptionRouterDict[name];
if (legalExceptions && legalExceptions.includes(name)) {
// 如果调用时就知道有异常,直接抛出
this.setState({
oakExecuting: false,
});
throw err;
}
else if (handler) {
const { hidden, level, handler: fn, router } = handler;
if (!hidden) {
this.setState({
oakExecuting: false,
oakError: {
type: level!,
msg: err.message,
},
});
}
else {
this.setState({
oakExecuting: false,
});
}
if (fn) {
fn(err);
return;
}
else if (router) {
this.setState({
oakExecuting: false,
});
this.navigateTo({
url: router,
});
}
}
else {
this.setState({
oakExecuting: false,
oakError: {
type: 'warning',
msg: err.message,
},
});
}
}
}
else {
this.setState({
oakExecuting: false,
oakError: {
type: 'error',
msg: (err as Error).message,
},
});
}
throw err;
}
},
resetUpdateData() {
return features.runningTree.resetUpdateData(this.state.oakFullpath);
},
setUpdateData(attr, value) {
if (this.state.oakExecuting) {
return;
}
return features.runningTree.setUpdateData(this.state.oakFullpath, attr, value);
},
};
}
export
function makeListComponentMethods<ED extends EntityDict,
T extends keyof ED,
Cxt extends Context<ED>,
AD extends Record<string, Aspect<ED, Cxt>>,
FD extends Record<string, Feature<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>>,
FormedData extends WechatMiniprogram.Component.DataOption,
IsList extends boolean,
TData extends WechatMiniprogram.Component.DataOption = {},
TProperty extends WechatMiniprogram.Component.PropertyOption = {},
TMethod extends WechatMiniprogram.Component.MethodOption = {}>(
features: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> & FD
): OakListComponentMethods<ED, T> & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod> {
return {
pushNode(path, options) {
const path2 = path ? `${this.state.oakFullpath}.${path}` : this.state.oakFullpath;
features.runningTree.pushNode(path2, options || {});
},
removeNode(parent, path) {
features.runningTree.removeNode(parent, path);
},
async getFilters() {
const namedFilters = features.runningTree.getNamedFilters(this.state.oakFullpath);
const filters = await Promise.all(
namedFilters.map(
({ filter }) => {
if (typeof filter === 'function') {
return filter();
}
return filter;
}
)
);
return filters;
},
async getFilterByName(name) {
const filter = features.runningTree.getNamedFilterByName(this.state.oakFullpath, name);
if (filter?.filter) {
if (typeof filter.filter === 'function') {
return filter.filter();
}
return filter.filter;
}
return;
},
addNamedFilter(namedFilter, refresh = false) {
return features.runningTree.addNamedFilter(this.state.oakFullpath, namedFilter, refresh);
},
removeNamedFilter(namedFilter, refresh = false) {
return features.runningTree.removeNamedFilter(this.state.oakFullpath, namedFilter, refresh);
},
removeNamedFilterByName(name, refresh = false) {
return features.runningTree.removeNamedFilterByName(this.state.oakFullpath, name, refresh);
},
setNamedSorters(namedSorters) {
return features.runningTree.setNamedSorters(this.state.oakFullpath, namedSorters);
},
async getSorters() {
const namedSorters = features.runningTree.getNamedSorters(this.state.oakFullpath);
const sorters = (await Promise.all(
namedSorters.map(
({ sorter }) => {
if (typeof sorter === 'function') {
return sorter();
}
return sorter;
}
)
)).filter(ele => !!ele) as DeduceSorterItem<ED[T]['Schema']>[];
return sorters;
},
async getSorterByName(name) {
const sorter = features.runningTree.getNamedSorterByName(this.state.oakFullpath, name);
if (sorter?.sorter) {
if (typeof sorter.sorter === 'function') {
return sorter.sorter();
}
return sorter.sorter;
}
return;
},
addNamedSorter(namedSorter, refresh = false) {
return features.runningTree.addNamedSorter(this.state.oakFullpath, namedSorter, refresh);
},
removeNamedSorter(namedSorter, refresh = false) {
return features.runningTree.removeNamedSorter(this.state.oakFullpath, namedSorter, refresh);
},
removeNamedSorterByName(name, refresh = false) {
return features.runningTree.removeNamedSorterByName(this.state.oakFullpath, name, refresh);
},
setFilters(filters) {
return features.runningTree.setNamedFilters(this.state.oakFullpath, filters);
},
};
}
export function makePageMethods<ED extends EntityDict,
T extends keyof ED,
Cxt extends Context<ED>,
AD extends Record<string, Aspect<ED, Cxt>>,
FD extends Record<string, Feature<ED, Cxt, AD & CommonAspectDict<ED, Cxt>>>,
FormedData extends WechatMiniprogram.Component.DataOption,
Proj extends ED[T]['Selection']['data'],
IsList extends boolean,
TData extends WechatMiniprogram.Component.DataOption = {},
TProperty extends WechatMiniprogram.Component.PropertyOption = {},
TMethod extends WechatMiniprogram.Component.MethodOption = {}>(
features: BasicFeatures<ED, Cxt, AD & CommonAspectDict<ED, Cxt>> & FD,
options: OakPageOption<ED, T, Cxt, AD, FD, Proj, FormedData, IsList, TData, TProperty, TMethod>
): OakPageMethods & ComponentThisType<ED, T, FormedData, IsList, TData, TProperty, TMethod> {
return {
async refresh() {
if (options.projection && this.state.oakFullpath) {
this.setState({
oakLoading: true,
});
try {
await features.runningTree.refresh(this.state.oakFullpath);
this.setState({
oakLoading: false,
});
}
catch (err) {
this.setState({
oakLoading: false,
oakError: {
type: 'error',
msg: (err as Error).message,
},
});
};
}
},
async onPullDownRefresh() {
if (options.projection) {
await this.refresh();
}
},
async onReachBottom() {
if (options.isList && options.append && options.projection) {
this.setState({
oakMoreLoading: true,
});
try {
await features.runningTree.loadMore(this.state.oakFullpath);
this.setState({
oakMoreLoading: false,
});
}
catch (err) {
this.setState({
oakMoreLoading: false,
oakError: {
type: 'error',
msg: (err as Error).message,
},
});
}
}
},
async onLoad(pageOption) {
const { oakId, oakEntity, oakPath, oakProjection, oakParent,
oakSorters, oakFilters, oakIsPicker, oakFrom, oakActions, ...rest } = this.props;
assert(!(options.isList && oakId));
const filters: NamedFilterItem<ED, T>[] = [];
if (oakFilters?.length > 0) {
// 这里在跳页面的时候用this.navigate应该可以限制传过来的filter的格式
const oakFilters2 = JSON.parse(oakFilters);
filters.push(...oakFilters2);
}
else if (options.filters) {
for (const ele of options.filters) {
const { filter, "#name": name } = ele;
filters.push({
filter: typeof filter === 'function' ? await filter({
features,
rest,
onLoadOptions: pageOption,
}) : filter,
['#name']: name,
});
}
}
let proj = oakProjection && JSON.parse(oakProjection);
if (!proj && options.projection) {
const { projection } = options;
proj = typeof projection === 'function' ? () => projection({
features,
rest,
onLoadOptions: pageOption,
}) : projection;
}
let sorters: NamedSorterItem<ED, T>[] = [];
if (oakSorters?.length > 0) {
// 这里在跳页面的时候用this.navigate应该可以限制传过来的sorter的格式
const oakSorters2 = JSON.parse(oakSorters);
sorters.push(...oakSorters2);
}
else if (options.sorters) {
for (const ele of options.sorters) {
const { sorter, "#name": name } = ele;
sorters.push({
sorter: typeof sorter === 'function' ? await sorter({
features,
rest,
onLoadOptions: pageOption,
}) : sorter,
['#name']: name,
});
}
}
const path2 = oakParent ? `${oakParent}:${oakPath || options.path}` : oakPath || options.path;
const node = await features.runningTree.createNode({
path: path2,
entity: (oakEntity || options.entity) as T,
isList: options.isList,
isPicker: oakIsPicker,
projection: proj,
pagination: options.pagination,
filters,
sorters,
id: oakId,
});
// const oakFullpath = oakParent ? `${oakParent}.${oakPath || options.path}` : oakPath || options.path;
this.setState(
{
oakEntity: node.getEntity(),
oakFullpath: path2,
oakFrom,
newOakActions:
oakActions && JSON.parse(oakActions).length > 0
? JSON.parse(oakActions)
: options.actions || [],
},
() => {
this.refresh();
}
);
},
};
}

17
src/utils/wx.polyfill.ts Normal file
View File

@ -0,0 +1,17 @@
Object.assign(global, {
Array: Array,
Date: Date,
Error: Error,
Function: Function,
Math: Math,
Object: Object,
RegExp: RegExp,
String: String,
TypeError: TypeError,
setTimeout: setTimeout,
clearTimeout: clearTimeout,
setInterval: setInterval,
clearInterval: clearInterval,
process: {},
});
export {}