oak-frontend-base/src/types/Page.ts

452 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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

import { Aspect, EntityDict, CheckerType, AggregationResult } from "oak-domain/lib/types";
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { CommonAspectDict } from 'oak-common-aspect';
import { Feature } from './Feature';
import { Pagination } from "./Pagination";
import { BasicFeatures } from "../features";
import { NamedFilterItem, NamedSorterItem } from './NamedCondition';
import { NotificationProps } from './Notification';
import { MessageProps } from './Message';
import { AsyncContext } from "oak-domain/lib/store/AsyncRowStore";
import { SyncContext } from "oak-domain/lib/store/SyncRowStore";
export type PropertyOption = Record<string, WechatMiniprogram.Component.AllProperty | FunctionConstructor>;
export type DataOption = WechatMiniprogram.Component.DataOption;
export type MethodOption = WechatMiniprogram.Component.MethodOption;
/**
* 微信的原声明中少写了FunctionConstructor只能抄一遍
*/
type PropertyType =
| FunctionConstructor
| StringConstructor
| NumberConstructor
| BooleanConstructor
| ArrayConstructor
| ObjectConstructor
| null
type ValueType<T extends PropertyType> = T extends null
? any
: T extends StringConstructor
? string
: T extends NumberConstructor
? number
: T extends BooleanConstructor
? boolean
: T extends ArrayConstructor
? any[]
: T extends ObjectConstructor
? AnyObject
: T extends FunctionConstructor
? Function
:never
type FullProperty<T extends PropertyType> = {
/** 属性类型 */
type: T
/** 属性初始值 */
value?: ValueType<T> | undefined
/** 属性值被更改时的响应函数 */
observer?:
| string
| ((
newVal: ValueType<T>,
oldVal: ValueType<T>,
changedPath: Array<string | number>
) => void) | undefined
/** 属性的类型(可以指定多个) */
optionalTypes?: ShortProperty[] | undefined
}
type AllFullProperty =
| FullProperty<StringConstructor>
| FullProperty<NumberConstructor>
| FullProperty<BooleanConstructor>
| FullProperty<ArrayConstructor>
| FullProperty<ObjectConstructor>
| FullProperty<null>
type ShortProperty =
| FunctionConstructor
| StringConstructor
| NumberConstructor
| BooleanConstructor
| ArrayConstructor
| ObjectConstructor
| null
type AllProperty = AllFullProperty | ShortProperty
type PropertyToData<T extends AllProperty> = T extends ShortProperty
? ValueType<T>
: FullPropertyToData<Exclude<T, ShortProperty>>
type FullPropertyToData<T extends AllFullProperty> = ValueType<T['type']>
type PropertyOptionToData<P extends PropertyOption> = {
[name in keyof P]: PropertyToData<P[name]>
};
interface ComponentOption<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends AsyncContext<ED>,
FrontCxt extends SyncContext<ED>,
AD extends Record<string, Aspect<ED, Cxt>>,
FD extends Record<string, Feature>,
FormedData extends Record<string, any>,
IsList extends boolean,
TData extends DataOption,
TProperty extends PropertyOption,
> {
entity?: T | ((this: ComponentPublicThisType<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty>) => T);
path?: string;
isList: IsList;
projection?: ED[T]['Selection']['data'] | ((this: ComponentPublicThisType<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty>) => ED[T]['Selection']['data']);
append?: boolean;
pagination?: Pagination;
filters?: Array<{
filter: ED[T]['Selection']['filter'] | ((this: ComponentPublicThisType<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty>) => ED[T]['Selection']['filter'] | undefined);
'#name'?: string;
}>;
sorters?: Array<{
sorter: NonNullable<ED[T]['Selection']['sorter']>[number] | ((this: ComponentPublicThisType<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty>) => NonNullable<ED[T]['Selection']['sorter']>[number]);
'#name'?: string;
}>;
formData?: (options: {
data: IsList extends true ? Partial<ED[T]['Schema']>[] : Partial<ED[T]['Schema']> | undefined;
features: BasicFeatures<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>> & FD;
props: Partial<PropertyOptionToData<TProperty>>;
legalActions: ED[T]['Action'][];
}) => FormedData & ThisType<ComponentPublicThisType<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList>>;
ns?: T | T[];
data?: ((this: ComponentPublicThisType<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty>) => TData) | TData;
properties?: TProperty;
};
export type MiniprogramStyleMethods = {
animate(
selector: string,
keyFrames: WechatMiniprogram.Component.KeyFrame[],
duration: number,
callback?: () => void
): void
clearAnimation(
selector: string,
options?: WechatMiniprogram.Component.ClearAnimationOptions,
callback?: () => void
): void;
triggerEvent: <DetailType = any>(
name: string,
detail?: DetailType,
options?: WechatMiniprogram.Component.TriggerEventOption
) => void;
}
export type ComponentProps<IsList extends boolean, TProperty extends PropertyOption> = IsList extends true ?
PropertyOptionToData<OakListComponentProperties & OakComponentProperties & TProperty> :
PropertyOptionToData<OakComponentProperties & TProperty>;
export type ComponentData<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
FormedData extends DataOption,
TData extends DataOption
> = TData & FormedData & OakComponentData<ED, T>;
export type ComponentPublicThisType<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends AsyncContext<ED>,
FrontCxt extends SyncContext<ED>,
AD extends Record<string, Aspect<ED, Cxt>>,
FD extends Record<string, Feature>,
FormedData extends Record<string, any>,
IsList extends boolean,
TData extends Record<string, any> = {},
TProperty extends PropertyOption = {},
TMethod extends MethodOption = {}
> = {
subscribed: Array<() => void>;
features: FD & BasicFeatures<ED, Cxt, FrontCxt, AD & CommonAspectDict<ED, Cxt>>;
state: ComponentData<ED, T, FormedData, TData>;
props: Readonly<ComponentProps<IsList, TProperty>>;
setState: (
data: Partial<ComponentData<ED, T, FormedData, TData>>,
callback?: () => void,
) => void;
triggerEvent: <DetailType = any>(
name: string,
detail?: DetailType,
options?: WechatMiniprogram.Component.TriggerEventOption
) => void;
} & TMethod & OakCommonComponentMethods<ED, T> & OakListComponentMethods<ED, T> & OakSingleComponentMethods<ED, T>;
export type ComponentFullThisType<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
IsList extends boolean,
Cxt extends AsyncContext<ED>,
FrontCxt extends SyncContext<ED>
> = {
subscribed: Array<() => void>;
features: BasicFeatures<ED, Cxt, FrontCxt, CommonAspectDict<ED, Cxt>>;
state: OakComponentData<ED, T>;
props: ComponentProps<true, {}>;
setState: (
data: Partial<OakComponentData<ED, T>>,
callback?: () => void,
) => void;
triggerEvent: <DetailType = any>(
name: string,
detail?: DetailType,
options?: WechatMiniprogram.Component.TriggerEventOption
) => void;
} & OakCommonComponentMethods<ED, T> & OakListComponentMethods<ED, T> & OakSingleComponentMethods<ED, T>;
export type OakComponentOption<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED,
Cxt extends AsyncContext<ED>,
FrontCxt extends SyncContext<ED>,
AD extends Record<string, Aspect<ED, Cxt>>,
FD extends Record<string, Feature>,
FormedData extends Record<string, any>,
IsList extends boolean,
TData extends Record<string, any>,
TProperty extends PropertyOption,
TMethod extends Record<string, Function>,
> = ComponentOption<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty> &
Partial<{
methods: TMethod;
lifetimes: {
created?(): void;
attached?(): void;
ready?(): void;
moved?(): void;
detached?(): void;
error?(err: Error): void;
show?(): void;
hide?(): void;
};
actions: ED[T]['Action'][] | ((this: ComponentPublicThisType<
ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty, TMethod
>) => ED[T]['Action'][]);
observers: Record<string, (...args: any[]) => any>;
}> &
Partial<{
wechatMp: {
externalClasses?: string[];
options?: Partial<WechatMiniprogram.Component.ComponentOptions> | undefined;
}
}> & ThisType<ComponentPublicThisType<ED, T, Cxt, FrontCxt, AD, FD, FormedData, IsList, TData, TProperty, TMethod>>;
export type OakComponentProperties = {
oakPath: StringConstructor;
oakId: StringConstructor;
oakProjection: ObjectConstructor;
oakFrom: StringConstructor;
oakParentEntity: StringConstructor;
oakDisablePulldownRefresh: BooleanConstructor;
oakAutoUnmount: BooleanConstructor;
oakActions: ArrayConstructor;
};
export type OakListComponentProperties = {
oakFilters: ObjectConstructor;
oakSorters: ObjectConstructor;
oakIsPicker: BooleanConstructor;
oakPagination: ObjectConstructor;
}
export type OakNavigateToParameters<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
oakId?: string;
oakEntity?: T;
oakPath?: string;
oakParent?: string;
oakProjection?: ED[T]['Selection']['data'],
oakSorters?: Array<NamedSorterItem<ED, T>>,
oakFilters?: Array<NamedFilterItem<ED, T>>;
oakIsPicker?: boolean;
[k: string]: any;
};
export type OakCommonComponentMethods<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED
> = {
setDisablePulldownRefresh: (able: boolean) => void;
sub: (type: string, callback: Function) => void;
unsub: (type: string, callback: Function) => void;
pub: (type: string, options?: any) => void;
unsubAll: (type: string) => void;
save: (key: string, item: any) => void;
load: (key: string) => any;
clear: () => void;
resolveInput: <K extends string>(
input: any,
keys?: K[]
) => { dataset?: Record<string, any>; value?: string } & {
[k in K]?: any;
};
setNotification: (data: NotificationProps) => void;
consumeNotification: () => NotificationProps | undefined;
setMessage: (data: MessageProps) => void;
consumeMessage: () => MessageProps | undefined;
reRender: (extra?: Record<string, any>) => void;
getFreshValue: (path?: string) =>
| Partial<ED[keyof ED]['Schema']>[]
| Partial<ED[keyof ED]['Schema']>
| undefined;
navigateTo: <T2 extends keyof ED>(
options: { url: string } & OakNavigateToParameters<ED, T2>,
state?: Record<string, any>,
disableNamespace?: boolean
) => Promise<void>;
navigateBack: (delta?: number) => Promise<void>;
redirectTo: <T2 extends keyof ED>(
options: Parameters<typeof wx.redirectTo>[0] &
OakNavigateToParameters<ED, T2>,
state?: Record<string, any>,
disableNamespace?: boolean
) => Promise<void>;
// setProps: (props: Record<string, any>, usingState?: true) => void;
clean: (path?: string) => void;
t(key: string, params?: object): string;
execute: (action?: ED[T]['Action'], messageProps?: boolean | MessageProps) => Promise<void>;
checkOperation: (
ntity: T,
action: ED[T]['Action'],
filter?: ED[T]['Update']['filter'],
checkerTypes?: CheckerType[]
) => boolean;
tryExecute: (path?: string) => boolean | Error;
getOperations: (
path?: string
) => { operation: ED[T]['Operation']; entity: T }[] | undefined;
refresh: () => Promise<void>;
aggregate: (aggregation: ED[T]['Aggregation']) => Promise<AggregationResult<ED[T]['Schema']>>;
};
export type OakSingleComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
setId: (id: string) => void;
unsetId: () => void;
getId: () => string | undefined;
// create: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>) => void;
update: (data: ED[T]['Update']['data'], action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) => void;
remove: (beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) => void;
isCreation: (path?: string) => boolean;
}
export type OakListComponentMethods<ED extends EntityDict & BaseEntityDict, T extends keyof ED> = {
loadMore: () => Promise<void>;
setFilters: (filters: NamedFilterItem<ED, T>[], path?: string) => void;
getFilters: (path?: string) => ED[T]['Selection']['filter'][] | undefined;
getFilterByName: (name: string, path?: string) => ED[T]['Selection']['filter'] | undefined;
addNamedFilter: (filter: NamedFilterItem<ED, T>, refresh?: boolean, path?: string) => void;
removeNamedFilter: (filter: NamedFilterItem<ED, T>, refresh?: boolean, path?: string) => void;
removeNamedFilterByName: (name: string, refresh?: boolean, path?: string) => void;
setNamedSorters: (sorters: NamedSorterItem<ED, T>[], path?: string) => void;
getSorters: (path?: string) => ED[T]['Selection']['sorter'] | undefined;
getSorterByName: (name: string, path?: string) => NonNullable<ED[T]['Selection']['sorter']>[number] | undefined;
addNamedSorter: (filter: NamedSorterItem<ED, T>, refresh?: boolean, path?: string) => void;
removeNamedSorter: (filter: NamedSorterItem<ED, T>, refresh?: boolean, path?: string) => void;
removeNamedSorterByName: (name: string, refresh?: boolean, path?: string) => void;
getPagination: (path?: string) => Pagination | undefined;
setPageSize: (pageSize: number, path?: string) => void;
setCurrentPage: (current: number, path?: string) => void;
addItem: (data: Omit<ED[T]['CreateSingle']['data'], 'id'>, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) => void;
removeItem: (id: string, beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) => void;
updateItem: (data: ED[T]['Update']['data'], id: string, action?: ED[T]['Action'], beforeExecute?: () => Promise<void>, afterExecute?: () => Promise<void>, path?: string) => void;
recoverItem: (id: string, path?: string) => void;
};
type ComponentOnPropsChangeOption = {
path?: string;
parent?: string;
}
export type OakComponentOnlyMethods = {
onPropsChanged: (options: ComponentOnPropsChangeOption) => void;
registerReRender: () => void;
setOakActions: () => void;
};
export type OakComponentData<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED
> = {
oakExecutable: boolean | Error;
oakExecuting: boolean;
oakFocused: {
attr: string;
message: string;
};
oakDirty: boolean;
oakLoading: boolean;
oakLoadingMore: boolean;
oakPullDownRefreshLoading: boolean;
oakEntity: T;
oakFullpath: string;
oakLegalActions?: ED[T]['Action'][];
oakDisablePulldownRefresh: boolean;
};
export type OakListComoponetData<
ED extends EntityDict & BaseEntityDict,
T extends keyof ED
> = {
oakFilters?: NonNullable<ED[T]['Selection']['filter']>[];
oakSorters?: NonNullable<ED[T]['Selection']['sorter']>[];
oakPagination?: Pagination;
}
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>
> = <
T extends keyof ED,
FormedData extends DataOption,
IsList extends boolean,
TData extends DataOption,
TProperty extends PropertyOption,
TMethod extends MethodOption
>(
options: OakComponentOption<
ED,
T,
Cxt,
FrontCxt,
AD,
FD,
FormedData,
IsList,
TData,
TProperty,
TMethod
>
) => React.ComponentType<any>;
// 暴露给组件的方法
export type WebComponentCommonMethodNames = 'setNotification' | 'setMessage' | 'navigateTo' | 'navigateBack' | 'redirectTo' | 'clean' | 't' | 'execute' | 'refresh' | 'setDisablePulldownRefresh' | 'aggregate' | 'checkOperation';
// 暴露给list组件的方法
export type WebComponentListMethodNames = 'loadMore' | 'setFilters' | 'addNamedFilter' | 'removeNamedFilter' | 'removeNamedFilterByName' | 'setNamedSorters'
| 'addNamedSorter' | 'removeNamedSorter' | 'removeNamedSorterByName' | 'setPageSize' | 'setCurrentPage' | 'addItem' | 'removeItem' | 'updateItem';
// 暴露给single组件的方法
export type WebComponentSingleMethodNames = 'update' | 'remove' | '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>;
data: TData & OakComponentData<ED, T> & (IsList extends true ? OakListComoponetData<ED, T> : {});
}