/** * 事件动作的类型定义 * 因为core里有文件依赖了它, 所以要讲类型提升至这里, 不能放到amis-actions包里 */ import type { ModelMessage } from 'ai'; import type { Api, AsyncFuncString, BaseOpenAICompletionsRestParams, IScopedContext, OpenAIClientConfig, RendererEnv, RendererProps, Schema, SchemaBoolean, SchemaExpression, ScopedComponentType, ToastLevel, fetchOptions } from '../types'; import type { CookieAttr } from '../utils/cookie'; export type EventListenerAction = EventListenerActionTradition | ActionObject | ActionObject[]; export interface EventListenerActionTradition { weight?: number; actions: ActionObject | ActionObject[]; } /** * 事件动作属性 */ export type OnEventProps = Partial>; export interface RendererEventListener { renderer: ScopedComponentType; type: string; weight: number; actions: ActionObject | ActionObject[]; } export interface RendererEvent { type: string; context: TCTX; /** * 阻止原有动作执行 */ prevented?: boolean; /** * 阻止后续动作执行 */ stoped?: boolean; data?: TDATA; preventDefault: (prevented?: boolean) => void; stopPropagation: (stopped?: boolean) => void; setData: (data: TDATA) => void; } export interface RendererEventContext { env: RendererEnv; nativeEvent?: string | React.SyntheticEvent | ActionObject; scoped: IScopedContext; data: Record; [propName: string]: any; } /** * 如下是兼容form里老的ajax配置 */ export interface IFormActionExt { type?: 'reset' | 'submit' | 'button'; mergeData?: boolean; target?: string; redirect?: string; blank?: boolean; api?: Api; asyncApi?: Api; /** 指定要reload的目标组件的componentId */ reload?: string; /** * 是否要reload目标对象的开关, 因为历史原因, 只有在 reloadFlag: false 时才是明确禁用reload */ reloadFlag?: boolean; close?: string | boolean; from?: string; __from?: string; messages?: { success?: string; failed?: string; }; feedback?: { skipRestOnCancel?: boolean; skipRestOnConfirm?: boolean; [key: string]: any; }; countDown?: number; /** * 指定哪些属性名是必填的 * form使用 */ required?: string[]; } /** * 组件定制的属性 */ export interface ICmptActionExt { ignoreConfirm?: boolean; confirmText?: string; requireSelected?: boolean; onClick?: (event: any, props: any, data: any) => void; /** InputTable里用到 */ payload?: boolean; /** Table */ hiddenOnHover?: boolean; /** combo */ index?: number; } export interface IListenerAction = Record> extends IFormActionExt, ICmptActionExt, ICmptActionBase { /** 动作类型 逻辑动作|自定义(脚本支撑)|reload|url|ajax|dialog|drawer 其他扩充的组件动作 */ actionType: T | (string & {}); /** * 事件描述,actionType: broadcast */ description?: string; /** * 组件链路, 有弹窗dialog/drawer的场景下需要透传当前组件的$path过去, 否则会导致 * componentClosest和componentSelector找不到 * @inner 内部使用 */ __$path?: string; componentId?: string; /** * 组件名称 */ componentName?: string; /** * args参数的原始定义, 因为args都会被变量解析掉 */ argsRaw?: Record; /** * args参数中的变量解析黑名单, 名单内的属性不会解析变量 * 适用于如title, body等动态schema需要延迟解析的场景 */ argsResolveDenyList?: string[]; /** * 输出数据变量名, 默认是`${actionType}Result` */ outputVar?: string; /** * 阻止原有组件的动作行为 */ preventDefault?: SchemaBoolean; /** * 阻止后续的事件处理器执行 */ stopPropagation?: SchemaBoolean; /** * 执行条件 */ expression?: SchemaBoolean; /** * 执行条件,1.9.0废弃 * @deprecated 使用expression */ execOn?: string; /** * 后续动作 */ then?: ActionObject | ActionObject[]; /** * 是否执行后续动作 */ thenOn?: SchemaBoolean; /** * 当`thenOn`判断为 false 时执行的动作 */ thenElse?: ActionObject | ActionObject[]; /** * @deprecated 兼容旧逻辑 */ mergeData?: boolean; /** 权重 */ weight?: number; /** * 延迟多少毫秒执行 */ execDelay?: number; /** 是否显示debug日志 */ debug?: boolean; args?: Arg; } /** * @deprecated 请使用`ScopedComponentType`来替代, 兼容使用了hooks的FC renderer */ export interface ListenerContext extends React.Component { /** * 注册了scope的renderer都会有mounted标识, 说明是否渲染在屏幕中 */ mounted?: boolean; [propName: string]: any; } export interface RendererAction { /** * 运行这个 Action,每个类型的 Action 都只有一个实例,run 函数是个可重入的函数 */ run: (action: ActionObject, renderer: ScopedComponentType, event: RendererEvent, /** * 有些Action内部需要通过上下文数据处理专有逻辑,这里的数据是事件数据+组件数据 */ mergeData: Record) => Promise; } export interface ICopyAction extends IListenerAction { actionType: 'copy'; args: { content: string; message?: string; }; /** * @deprecated 兼容旧的, 在RootRenderer.ts中使用 */ content?: string; /** * @deprecated 兼容旧的, 在RootRenderer.ts中使用 */ copy?: string; /** * @deprecated 兼容旧的, 在RootRenderer.ts中使用 */ copyFormat?: string; } /** * 兼容新旧action的ajax动作 * TODO 现在无法直接用在IFormAction中, 因为那里的类型没有要求使用actionType来区分 */ export interface IAjaxAction extends IListenerAction, IFormActionExt { actionType: 'ajax' | 'download'; /** * * @deprecated 兼容老的逻辑, 请使用`args.api` */ api?: Api; reload?: string; args?: { api: Api; messages?: { success: string; failed: string; }; options?: Pick; [propName: string]: any; }; } export interface IBroadcastAction extends IListenerAction { actionType: 'broadcast'; /** 广播事件名 */ eventName: string; args?: Record; } export interface ISetValueAction extends IListenerAction, ICmptActionBase { actionType: 'setValue'; args?: { value?: string | { [key: string]: any; }; /** * 是否使用value替换掉原来的props.value, 默认是替换, 如果只想更新部分, 可以通过设置replace=false来指定 * 在combo下有用 */ replace?: boolean; index?: number; }; } export interface IReloadAction extends IListenerAction { actionType: 'reload'; args?: Record; /** * 目标组件name, 兼容逻辑 * @deprecated 使用compnentId替换 */ target?: string; } export interface IVisiableAction extends IListenerAction { actionType: 'show' | 'hidden' | 'enabled' | 'disabled'; args?: Record; } export interface ICmptActionBase { /** * 查找最近的祖先元素类型, 如`page,form,crud...` */ componentClosest?: string; /** * 组件查询表达式, 如`form[title=123,className='abc,def']`, 功能类似`document.querySelector` */ componentSelector?: string; } export type ICmptAction = IReloadAction | IVisiableAction | ICmptCustomAction | ISetValueAction; export interface ICustomAction extends IListenerAction { actionType: 'custom'; /** * 如果用的是自定义的js, 里面用到了异步的方法, 特别是doAction, 一定记得return * 否则action不会等待它执行完就去下一步了 */ script: AsyncFuncString | ((renderer: ScopedComponentType & { event: RendererEvent; action: ICustomAction; doAction: (action: IListenerAction) => Promise; }, doAction: (action: ActionObject, data?: Record) => void, event: RendererEvent, action: ListenerAction) => void); args?: Record; } export interface IAlertAction extends IListenerAction { actionType: 'alert'; args: { msg: string; [propName: string]: any; }; } /** * 弹出确认弹框, 或者触发dialog的confirm行为(当有componentId参数时) */ export interface IConfirmAction extends IListenerAction { actionType: 'confirm' | 'confirmDialog'; args?: { title?: string; msg?: string; [propName: string]: any; }; /** * @deprecated 兼容代码 */ target?: string; } export interface IDialogAction extends IListenerAction { actionType: 'dialog'; dialog: Partial; args?: Record; /** * 确认操作 * @deprecated 过期用法, 应该用event-action来组织 */ onConfirm?: (values: object[], action: ActionObject, ...args: Array) => boolean; } export interface ICloseDialogAction extends IListenerAction { actionType: 'closeDialog'; args?: Record; } export interface IDrawerAction extends IListenerAction { actionType: 'drawer'; drawer: Partial; args?: Record; } export interface ICloseDrawerAction extends IListenerAction { actionType: 'closeDrawer'; args?: Record; } export interface IEmailAction extends IListenerAction { actionType: 'email'; args: { to: string; subject: string; body: string; cc?: string; bcc?: string; [propName: string]: any; }; to?: string; cc?: string; bcc?: string; subject?: string; body?: string; } export interface ILinkAction extends IListenerAction { actionType: 'link' | 'url' | 'jump'; args?: { link?: string; url?: string; blank?: boolean; params?: { [key: string]: string; }; [propName: string]: any; }; /** 兼容旧的动作定义, 在RootRenderer.tsx中使用 */ to?: string; url?: string; link?: string; type?: 'button'; blank?: boolean; } export interface ILogAction extends IListenerAction { actionType: 'log'; args?: Record; } export interface IPageGoAction extends IListenerAction { actionType: 'goBack' | 'refresh' | 'goPage'; args?: { delta?: number; [propName: string]: any; }; } export interface IToastAction extends IListenerAction { actionType: 'toast'; args: { msg: string; msgType?: ToastLevel; position?: 'top-right' | 'top-center' | 'top-left' | 'bottom-center' | 'bottom-left' | 'bottom-right' | 'center'; closeButton?: boolean; showIcon?: boolean; timeout?: number; }; /** * @deprecated 兼容旧的逻辑, 在RootRenderer.ts里用到 */ toast?: { /** 兼容老旧的写法, 不推荐了 */ items?: { level?: ToastLevel; body?: any; title?: any; }[]; } & Partial; } export interface IDeleteLocalAction extends IListenerAction { actionType: 'deleteLocal'; args: { /** * 本地存储类型, 默认是`local` */ localType?: 'local' | 'session' | 'cookie'; /** * 存储的key */ key: string; }; } export interface ISaveLocalAction extends IListenerAction { actionType: 'saveLocal'; args: { /** * 本地存储类型, 默认是`local` */ localType?: 'local' | 'session' | 'cookie'; /** * 存储的key */ key: SchemaExpression; /** * 存储的值 */ value: string | number | Record; /** * 当localType=cookie时, 附加设置 */ cookieAttrs?: CookieAttr; /** * 值如果是对象, 是否替换, 默认是合并而不替换; 如果是其他类型比如数组, 都是直接替换 */ replace?: boolean; }; } export interface ISaveAsAction extends IListenerAction { actionType: 'saveAs'; args?: { /** * 文件名, 默认是data.txt */ fileName?: string; }; /** * 文件名, 默认是data.txt */ fileName?: string; } export interface ICmptCustomAction extends IListenerAction, ICmptActionBase { actionType: 'add' | 'addOrActiveTab' | 'addTab' | 'blur' | 'cancel' | 'cancel' | 'change' | 'changeTabKey' | 'clear-and-submit' | 'clear' | 'clearValueAndOptions' | 'click-item' | 'click' | 'close' | 'closeTab' | 'collapse' | 'deferLoad' | 'delete' | 'deleteSuccess' | 'edit' | 'expand' | 'focus' | 'goto-image' | 'goto-step' | 'goto-step' | 'hotKey' | 'loaded' | 'next' | 'next' | 'open' | 'prev' | 'prev' | 'rebuild' | 'reloadOptions' | 'remove' | 'reset-and-submit' | 'reset' | 'routerBeforeEnter' | 'routerChange' | 'routerQueryChange' | 'search' | 'selectAll' | 'selectedChange' | 'setOptions' | 'sort-asc' | 'sort-desc' | 'step-submit' | 'step-submit' | 'submit' | 'toggleFolded' | 'togglePopOver' | 'toggleLoading' | 'validate' | 'dispatchEvent' | `add${string}` | `create${string}` | `delete${string}` | `update${string}` | `clear${string}` | `edit${string}` | `remove${string}` | `before${string}` | `after${string}` /** 激活xxx */ | `active${string}` /** 加载xxx */ | `load${string}` /** AI 聊天相关事件 */ | `chat${string}` | `send${string}` | `stop${string}` | `refresh${string}` | `uploadFiles`; args?: Record; } export interface ILogicAction extends IListenerAction { children?: ListenerAction[]; args?: Record; } export interface ISpinnerAction extends IListenerAction { actionType: 'spinner' | 'closeSpinner'; args?: { tip?: string; /** 多少毫秒后自动关闭 */ closeAfter?: number; }; } /** * 等待动作 */ export interface IWaitAction extends IListenerAction { actionType: 'wait'; args: { /** * 等待毫秒数 */ millsecond: number; }; } export interface ICountDownAction extends IListenerAction { actionType: 'countDown'; args: { /** 倒计时多少秒 */ total: number | SchemaExpression; /** 每步间隔, 单位是秒, 不设置表示没有步骤*/ step?: number | SchemaExpression; /** 每步执行的动作 */ stepAction?: ActionObject | ActionObject[]; }; } export type ListenerAction = IToastAction | IBroadcastAction | IAjaxAction | ICmptAction | ICopyAction | ICustomAction | IAlertAction | IConfirmAction | IDialogAction | ICloseDialogAction | IDrawerAction | ICloseDrawerAction | IEmailAction | ILinkAction | LogicAction | IPageGoAction | ILogAction | ISaveAsAction | ISpinnerAction | IWaitAction | ISaveLocalAction | IDeleteLocalAction | ISendChatCompletionsAction | ICountDownAction; export interface IBreakAction extends ILogicAction { actionType: 'break'; args?: Record; } export interface IContinueAction extends ILogicAction { actionType: 'continue'; args?: Record; } export interface IParallelAction extends ILogicAction { actionType: 'parallel'; args?: Record; } export interface ISwitchAction extends ILogicAction { actionType: 'switch'; args?: Record; } export interface ILoopAction extends ILogicAction { actionType: 'loop'; args?: { loopName: string; [propName: string]: any; }; } export type LogicAction = IParallelAction | ISwitchAction | ILoopAction | IContinueAction | IBreakAction; export type ActionObject = ListenerAction | ICmptCustomAction; export type FetchEvents = 'fetchSuccess' | 'fetchFailed' | 'fetchError'; export interface ISendChatCompletionsActionArgs extends Omit, Pick { apiKey?: SchemaExpression | (() => string); question: SchemaExpression | SchemaExpression[]; /** * 流式每块的后续动作 */ onChunk?: ActionObject | ActionObject[]; /** * 流式输出时提前断开连接表达式 */ abortExpression?: SchemaExpression; } export interface ISendChatCompletionsAction extends IListenerAction { actionType: 'sendChatCompletions'; args: ISendChatCompletionsActionArgs; } export type OpenAIRequestMessage = ModelMessage;