feat: 事件动作类型增强, 能够根据actionType自动类型提示和校验, 同时修复AjaxAction里会将adaptor/requestAdaptor/responseAdaptor转换成对象的问题 #4189

This commit is contained in:
allanyu 2022-04-29 15:09:01 +08:00
parent 92a2208c82
commit f7fc6d011f
17 changed files with 196 additions and 132 deletions

View File

@ -1,11 +1,25 @@
import {RendererProps} from '../factory';
import {extendObject} from '../utils/helper';
import {RendererEvent} from '../utils/renderer-event';
import {evalExpression} from '../utils/tpl';
import {dataMapping} from '../utils/tpl-builtin';
import { RendererProps } from '../factory';
import { extendObject } from '../utils/helper';
import { RendererEvent } from '../utils/renderer-event';
import { evalExpression } from '../utils/tpl';
import { dataMapping } from '../utils/tpl-builtin';
import { IAjaxAction } from './AjaxAction';
import { IBreakAction } from './BreakAction';
import { IBroadcastAction } from './BroadcastAction';
import { ICmptAction } from './CmptAction';
import { IContinueAction } from './ContinueAction';
import { ICopyAction } from './CopyAction';
import { ICustomAction } from './CustomAction';
import { IAlertAction, IConfirmAction, IDialogAction, ICloseDialogAction } from './DialogAction';
import { IDrawerAction, ICloseDrawerAction } from './DrawerAction';
import { IEmailAction } from './EmailAction';
import { ILinkAction } from './LinkAction';
import { ILoopAction } from './LoopAction';
import { IPageGoAction } from './PageAction';
import { IParallelAction } from './ParallelAction';
import { ISwitchAction } from './SwitchAction';
import { IToastAction } from './ToastAction';
// 逻辑动作类型支持并行、排他switch、循环支持continue和break
type LogicActionType = 'parallel' | 'switch' | 'loop' | 'continue' | 'break';
// 循环动作执行状态
export enum LoopStatus {
@ -15,21 +29,48 @@ export enum LoopStatus {
}
// 监听器动作定义
export interface ListenerAction {
actionType: 'broadcast' | LogicActionType | 'custom' | string; // 动作类型 逻辑动作|自定义(脚本支撑)|reload|url|ajax|dialog|drawer 其他扩充的组件动作
export interface IListenerAction {
actionType: string; // 动作类型 逻辑动作|自定义(脚本支撑)|reload|url|ajax|dialog|drawer 其他扩充的组件动作
description?: string; // 事件描述actionType: broadcast
componentId?: string; // 组件ID用于直接执行指定组件的动作
args?: any; // 参数,可以配置数据映射
outputVar?: any; // 输出数据变量名
args?: Record<string, any>; // 参数,可以配置数据映射
outputVar?: string; // 输出数据变量名
preventDefault?: boolean; // 阻止原有组件的动作行为
stopPropagation?: boolean; // 阻止后续的事件处理器执行
expression?: string; // 执行条件
}
export interface LogicAction extends ListenerAction {
// 监听器动作联合类型
export type ListenerAction =
| IToastAction
| IBroadcastAction
| IAjaxAction
| ICmptAction
| ICopyAction
| ICustomAction
| IAlertAction
| IConfirmAction
| IDialogAction
| ICloseDialogAction
| IDrawerAction
| ICloseDrawerAction
| IEmailAction
| ILinkAction
| LogicAction
| IPageGoAction;
export interface ILogicAction extends IListenerAction {
children?: ListenerAction[]; // 子动作
}
// 逻辑动作类型支持并行、排他switch、循环支持continue和break
export type LogicAction =
| IParallelAction
| ISwitchAction
| ILoopAction
| IContinueAction
| IBreakAction;
export interface ListenerContext extends React.Component<RendererProps> {
[propName: string]: any;
}
@ -46,7 +87,7 @@ export interface RendererAction {
}
// 存储 Action 和类型的映射关系,用于后续查找
const ActionTypeMap: {[key: string]: RendererAction} = {};
const ActionTypeMap: { [key: string]: RendererAction } = {};
// 注册 Action
export const registerAction = (type: string, action: RendererAction) => {
@ -104,7 +145,7 @@ export const runAction = async (
event: any
) => {
// 用户可能需要用到事件数据和当前域的数据因此merge事件数据和当前渲染器数据
// 需要保持渲染器数据链完整
// 需要保持渲染器数据链完整
const mergeData = extendObject(renderer.props.data, {
event
});
@ -120,7 +161,7 @@ export const runAction = async (
let args = event.data;
if (actionConfig.args) {
args = dataMapping(actionConfig.args, mergeData);
args = dataMapping(actionConfig.args, mergeData, (key) => ['adaptor', 'responseAdaptor', 'requestAdaptor'].includes(key));
}
await actionInstrance.run(

View File

@ -1,24 +1,25 @@
import omit from 'lodash/omit';
import {Api} from '../types';
import {normalizeApiResponseData} from '../utils/api';
import {ServerError} from '../utils/errors';
import {createObject, isEmpty} from '../utils/helper';
import {RendererEvent} from '../utils/renderer-event';
import { Api } from '../types';
import { normalizeApiResponseData } from '../utils/api';
import { ServerError } from '../utils/errors';
import { createObject, isEmpty } from '../utils/helper';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
IListenerAction,
ListenerContext,
registerAction
} from './Action';
export interface IAjaxAction extends ListenerAction {
export interface IAjaxAction extends IListenerAction {
action: 'ajax';
args: {
api: Api;
messages: {
messages?: {
success: string;
failed: string;
};
options: object;
options?: Record<string, any>
[propName: string]: any;
};
}
@ -56,8 +57,8 @@ export class AjaxAction implements RendererAction {
event.data,
action.outputVar
? {
[`${action.outputVar}`]: responseData
}
[`${action.outputVar}`]: responseData
}
: responseData
)
);
@ -76,9 +77,9 @@ export class AjaxAction implements RendererAction {
msg,
result.msgTimeout !== undefined
? {
closeButton: true,
timeout: result.msgTimeout
}
closeButton: true,
timeout: result.msgTimeout
}
: undefined
);
}
@ -92,9 +93,9 @@ export class AjaxAction implements RendererAction {
e.message,
result.msgTimeout !== undefined
? {
closeButton: true,
timeout: result.msgTimeout
}
closeButton: true,
timeout: result.msgTimeout
}
: undefined
);
} else {

View File

@ -1,12 +1,16 @@
import {RendererEvent} from '../utils/renderer-event';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
ListenerContext,
LoopStatus,
registerAction
registerAction,
ILogicAction
} from './Action';
export interface IBreakAction extends ILogicAction {
actionType: 'break';
}
/**
* breach
*
@ -16,7 +20,7 @@ import {
*/
export class BreakAction implements RendererAction {
async run(
action: ListenerAction,
action: IBreakAction,
renderer: ListenerContext,
event: RendererEvent<any>
) {

View File

@ -1,14 +1,15 @@
import {RendererProps} from '../factory';
import {createObject} from '../utils/helper';
import {RendererEvent, dispatchEvent} from '../utils/renderer-event';
import { RendererProps } from '../factory';
import { createObject } from '../utils/helper';
import { RendererEvent, dispatchEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
IListenerAction,
ListenerContext,
registerAction
} from './Action';
export interface IBroadcastAction extends ListenerAction {
export interface IBroadcastAction extends IListenerAction {
actionType: 'broadcast';
eventName: string; // 事件名称actionType: broadcast
}

View File

@ -1,15 +1,16 @@
import {RendererEvent} from '../utils/renderer-event';
import {dataMapping} from '../utils/tpl-builtin';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
IListenerAction,
ListenerContext,
LoopStatus,
registerAction
} from './Action';
export interface ICmptAction extends ListenerAction {
value?: string | {[key: string]: string};
export interface ICmptAction extends IListenerAction {
actionType: 'setValue' | 'show' | 'hidden' | 'enabled' | 'disabled' | 'reload';
args: {
value?: string | { [key: string]: string };
}
}
/**

View File

@ -1,12 +1,16 @@
import {RendererEvent} from '../utils/renderer-event';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
ListenerContext,
LoopStatus,
registerAction
registerAction,
ILogicAction
} from './Action';
export interface IContinueAction extends ILogicAction {
actionType: 'continue';
}
/**
* continue
*
@ -16,7 +20,7 @@ import {
*/
export class ContinueAction implements RendererAction {
async run(
action: ListenerAction,
action: IContinueAction,
renderer: ListenerContext,
event: RendererEvent<any>
) {

View File

@ -1,13 +1,13 @@
import {RendererEvent} from '../utils/renderer-event';
import {filter} from '../utils/tpl';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
IListenerAction,
ListenerContext,
registerAction
} from './Action';
export interface ICopyAction extends ListenerAction {
export interface ICopyAction extends IListenerAction {
actionType: 'copy';
args: {
content: string;
copyFormat?: string;

View File

@ -1,14 +1,21 @@
import {RendererEvent} from '../utils/renderer-event';
import { Action } from '../types';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
IListenerAction,
ListenerContext,
LoopStatus,
registerAction
registerAction,
ListenerAction
} from './Action';
export interface ICustomAction extends ListenerAction {
script: string; // 自定义JSactionType: custom
export interface ICustomAction extends IListenerAction {
actionType: 'custom';
script: string | ((
renderer: any,
doAction: (action: Action, data: Record<string, any>) => void,
event: RendererEvent<any>,
action: ListenerAction,
) => void); // 自定义JSactionType: custom
}
/**
@ -42,7 +49,7 @@ export class CustomAction implements RendererAction {
null,
renderer,
renderer.props.onAction?.bind(renderer, event.context.nativeEvent) ||
renderer.doAction?.bind(renderer),
renderer.doAction?.bind(renderer),
event,
action
);

View File

@ -1,20 +1,23 @@
import {SchemaNode} from '../types';
import {RendererEvent} from '../utils/renderer-event';
import { SchemaNode } from '../types';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
IListenerAction,
ListenerContext,
registerAction
} from './Action';
export interface IAlertAction extends ListenerAction {
export interface IAlertAction extends IListenerAction {
actionType: 'alert';
args: {
msg: string;
[propName: string]: any;
};
}
export interface IConfirmAction extends ListenerAction {
export interface IConfirmAction extends IListenerAction {
actionType: 'confirm';
args: {
title: string;
msg: string;
@ -22,7 +25,8 @@ export interface IConfirmAction extends ListenerAction {
};
}
export interface IDialogAction extends ListenerAction {
export interface IDialogAction extends IListenerAction {
actionType: 'dialog';
dialog: SchemaNode;
}
@ -43,6 +47,10 @@ export class DialogAction implements RendererAction {
}
}
export interface ICloseDialogAction extends IListenerAction {
actionType: 'closeDialog';
}
/**
*
*

View File

@ -1,13 +1,15 @@
import {SchemaNode} from '../types';
import {RendererEvent} from '../utils/renderer-event';
import { SchemaNode } from '../types';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
IListenerAction,
ListenerAction,
ListenerContext,
registerAction
} from './Action';
export interface IDrawerAction extends ListenerAction {
export interface IDrawerAction extends IListenerAction {
actionType: 'drawer';
drawer: SchemaNode;
}
@ -28,6 +30,11 @@ export class DrawerAction implements RendererAction {
}
}
export interface ICloseDrawerAction extends IListenerAction {
actionType: 'closeDrawer';
}
/**
*
*

View File

@ -1,16 +1,15 @@
import {RendererEvent} from '../utils/renderer-event';
import {filter} from '../utils/tpl';
import { RendererEvent } from '../utils/renderer-event';
import pick from 'lodash/pick';
import mapValues from 'lodash/mapValues';
import qs from 'qs';
import {
RendererAction,
ListenerAction,
ListenerContext,
registerAction
registerAction,
IListenerAction
} from './Action';
export interface IEmailAction extends ListenerAction {
export interface IEmailAction extends IListenerAction {
actionType: 'email';
args: {
to: string;
cc: string;

View File

@ -1,19 +1,17 @@
import {Action} from '../types';
import {buildApi} from '../utils/api';
import {isEmpty, isObject, qsstringify} from '../utils/helper';
import {RendererEvent} from '../utils/renderer-event';
import {filter} from '../utils/tpl';
import { buildApi } from '../utils/api';
import { RendererEvent } from '../utils/renderer-event';
import omit from 'lodash/omit';
import {
RendererAction,
ListenerAction,
ListenerContext,
registerAction
registerAction,
IListenerAction
} from './Action';
export interface ILinkAction extends ListenerAction {
export interface ILinkAction extends IListenerAction {
actionType: 'link' | 'url' | 'jump';
args: {
link: string;
link?: string;
url?: never;
blank?: boolean;
params?: {
@ -23,18 +21,6 @@ export interface ILinkAction extends ListenerAction {
};
}
export interface IUrlAction extends ListenerAction {
args: {
url: string;
link?: never;
blank?: boolean;
params?: {
[key: string]: string;
};
[propName: string]: any;
};
}
/**
*
*
@ -44,7 +30,7 @@ export interface IUrlAction extends ListenerAction {
*/
export class LinkAction implements RendererAction {
async run(
action: ListenerAction,
action: ILinkAction,
renderer: ListenerContext,
event: RendererEvent<any>
) {
@ -71,6 +57,7 @@ export class LinkAction implements RendererAction {
urlObj.url,
{
actionType: action.actionType,
type: 'button',
...action.args
},
action.args

View File

@ -1,18 +1,17 @@
import {RendererEvent} from '../utils/renderer-event';
import {createObject} from '../utils/helper';
import { RendererEvent } from '../utils/renderer-event';
import { createObject } from '../utils/helper';
import {
RendererAction,
ListenerAction,
ListenerContext,
LogicAction,
LoopStatus,
registerAction,
runAction,
runActions
runActions,
ILogicAction
} from './Action';
import {resolveVariable} from '../utils/tpl-builtin';
import { resolveVariable } from '../utils/tpl-builtin';
export interface ILoopAction extends ListenerAction, LogicAction {
export interface ILoopAction extends ILogicAction {
actionType: 'loop';
args: {
loopName: string;
[propName: string]: any;

View File

@ -1,12 +1,13 @@
import {RendererEvent} from '../utils/renderer-event';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
IListenerAction,
ListenerContext,
registerAction
} from './Action';
export interface IPageGoAction extends ListenerAction {
export interface IPageGoAction extends IListenerAction {
actionType: 'goBack' | 'refresh' | 'goPage';
args: {
delta?: number;
[propName: string]: any;
@ -22,7 +23,7 @@ export interface IPageGoAction extends ListenerAction {
*/
export class PageGoBackAction implements RendererAction {
async run(
action: ListenerAction,
action: IPageGoAction,
renderer: ListenerContext,
event: RendererEvent<any>
) {
@ -56,7 +57,7 @@ export class PageGoAction implements RendererAction {
*/
export class PageRefreshAction implements RendererAction {
async run(
action: ListenerAction,
action: IPageGoAction,
renderer: ListenerContext,
event: RendererEvent<any>
) {

View File

@ -1,14 +1,16 @@
import {RendererEvent} from '../utils/renderer-event';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
ListenerContext,
ILogicAction,
LogicAction,
registerAction,
runActions
} from './Action';
export interface IParallelAction extends ListenerAction, LogicAction {}
export interface IParallelAction extends ILogicAction {
actionType: 'parallel';
}
export class ParallelAction implements RendererAction {
async run(

View File

@ -1,16 +1,16 @@
import {inflate} from 'zlib';
import {RendererEvent} from '../utils/renderer-event';
import {evalExpression} from '../utils/tpl';
import { RendererEvent } from '../utils/renderer-event';
import { evalExpression } from '../utils/tpl';
import {
RendererAction,
ListenerAction,
ListenerContext,
LogicAction,
registerAction,
runActions
runActions,
ILogicAction
} from './Action';
export interface ISwitchAction extends ListenerAction, LogicAction {}
export interface ISwitchAction extends ILogicAction {
actionType: 'switch';
}
/**
*

View File

@ -1,16 +1,17 @@
import {RendererEvent} from '../utils/renderer-event';
import { RendererEvent } from '../utils/renderer-event';
import {
RendererAction,
ListenerAction,
ListenerContext,
registerAction
registerAction,
IListenerAction
} from './Action';
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
export interface IToastAction extends ListenerAction {
msg: string;
msgType?: string;
position?:
export interface IToastAction extends IListenerAction {
actionType: 'toast';
args: {
msg: string;
msgType?: string;
position?:
| 'top-right'
| 'top-center'
| 'top-left'
@ -18,9 +19,10 @@ export interface IToastAction extends ListenerAction {
| 'bottom-left'
| 'bottom-right'
| 'center';
closeButton?: boolean;
showIcon?: boolean;
timeout?: number;
closeButton?: boolean;
showIcon?: boolean;
timeout?: number;
}
}
/**