From 96b81d1a1683a666adbf5df56f1a34f519488081 Mon Sep 17 00:00:00 2001 From: Cano1997 <1978141412@qq.com> Date: Wed, 11 Jun 2025 17:49:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/src/interface/util/index.ts | 1 + .../util/script/i-script-function.ts | 32 ++++ packages/runtime/src/utils/index.ts | 1 + packages/runtime/src/utils/script/index.ts | 2 + .../src/utils/script/script-factory.ts | 80 +++++++++ .../src/utils/script/script-function.ts | 158 ++++++++++++++++++ 6 files changed, 274 insertions(+) create mode 100644 packages/runtime/src/interface/util/script/i-script-function.ts create mode 100644 packages/runtime/src/utils/script/index.ts create mode 100644 packages/runtime/src/utils/script/script-factory.ts create mode 100644 packages/runtime/src/utils/script/script-function.ts diff --git a/packages/runtime/src/interface/util/index.ts b/packages/runtime/src/interface/util/index.ts index 29db1486493..7bf8f83bdbc 100644 --- a/packages/runtime/src/interface/util/index.ts +++ b/packages/runtime/src/interface/util/index.ts @@ -9,3 +9,4 @@ export { IOpenViewUtil } from './i-open-view-util/i-open-view-util'; export { IOverlayContainer } from './i-overlay-container/i-overlay-container'; export { IOverlayController } from './i-overlay-controller/i-overlay-controller'; export { IOverlayPopoverContainer } from './i-overlay-popover-container/i-overlay-popover-container'; +export type { IScriptFunctionOpts } from './script/i-script-function'; diff --git a/packages/runtime/src/interface/util/script/i-script-function.ts b/packages/runtime/src/interface/util/script/i-script-function.ts new file mode 100644 index 00000000000..b37545714a7 --- /dev/null +++ b/packages/runtime/src/interface/util/script/i-script-function.ts @@ -0,0 +1,32 @@ +/** + * 脚本函数构造选项 + * @author lxm + * @date 2023-07-25 10:47:08 + * @export + * @interface IScriptFunctionOpts + */ +export interface IScriptFunctionOpts { + /** + * 是否是单行脚本,并把表达式结果return + * @author lxm + * @date 2023-07-25 10:46:18 + * @type {boolean} + */ + singleRowReturn?: boolean; + + /** + * 预置参数 + * @author lxm + * @date 2023-07-25 11:37:40 + * @type {IParams} + */ + presetParams?: IParams; + + /** + * 是否是异步函数脚本 + * @author lxm + * @date 2023-08-21 03:15:43 + * @type {boolean} + */ + isAsync?: boolean; +} diff --git a/packages/runtime/src/utils/index.ts b/packages/runtime/src/utils/index.ts index a299966f89e..ebb82dc5808 100644 --- a/packages/runtime/src/utils/index.ts +++ b/packages/runtime/src/utils/index.ts @@ -8,3 +8,4 @@ export { export * from './wf-helper/wf-helper'; export { TextUtil } from './text-util/text-util'; export { RawValueUtil } from './raw-value-util/raw-value-util'; +export * from './script/index'; diff --git a/packages/runtime/src/utils/script/index.ts b/packages/runtime/src/utils/script/index.ts new file mode 100644 index 00000000000..bfe72ac2147 --- /dev/null +++ b/packages/runtime/src/utils/script/index.ts @@ -0,0 +1,2 @@ +export * from './script-factory'; +export * from './script-function'; diff --git a/packages/runtime/src/utils/script/script-factory.ts b/packages/runtime/src/utils/script/script-factory.ts new file mode 100644 index 00000000000..257b507603c --- /dev/null +++ b/packages/runtime/src/utils/script/script-factory.ts @@ -0,0 +1,80 @@ +import { IScriptFunctionOpts } from '../../interface'; +import { ScriptFunction } from './script-function'; + +export class ScriptFactory { + /** + * 创建脚本方法 + * @author lxm + * @date 2023-07-25 11:47:48 + * @param {string[]} argKeys 参数列表 + * @param {string} scriptCode 脚本代码 + * @param {IScriptFunctionOpts} options 选项 + * @return {*} {ScriptFunction} + */ + static createScriptFn( + argKeys: string[], + scriptCode: string, + options?: IScriptFunctionOpts, + ): ScriptFunction { + return new ScriptFunction(argKeys, scriptCode, options); + } + + /** + * 直接创建并执行脚本 + * @author lxm + * @date 2023-07-25 02:21:28 + * @static + * @param {IParams} args 脚本参数 + * @param {string} scriptCode 脚本代码 + * @param {IScriptFunctionOpts} options 选项 + * @return {*} + */ + static execScriptFn( + args: IParams, + scriptCode: string, + options?: IScriptFunctionOpts, + ): unknown { + return this.createScriptFn(Object.keys(args), scriptCode, options).exec( + args, + ); + } + + /** + * 直接创建并同步执行脚本 + * + * @author tony001 + * @date 2024-06-25 14:06:25 + * @static + * @param {IParams} args + * @param {string} scriptCode + * @param {IScriptFunctionOpts} [options={}] + * @return {*} {Promise} + */ + static async asyncExecScriptFn( + args: IParams, + scriptCode: string, + options: IScriptFunctionOpts = {}, + ): Promise { + const result = await this.createScriptFn(Object.keys(args), scriptCode, { + ...options, + isAsync: true, + }).exec(args); + return result; + } + + /** + * 执行单行脚本 + * @author lxm + * @date 2023-10-20 03:20:56 + * @static + * @param {string} scriptCode 脚本字符串 + * @param {IParams} [args={}] 作用域变量参数对象 + * @return {*} {unknown} + */ + static execSingleLine(scriptCode: string, args: IParams = {}): unknown { + return this.execScriptFn(args, scriptCode, { + singleRowReturn: true, + isAsync: false, + }); + } +} diff --git a/packages/runtime/src/utils/script/script-function.ts b/packages/runtime/src/utils/script/script-function.ts new file mode 100644 index 00000000000..b0b211235f4 --- /dev/null +++ b/packages/runtime/src/utils/script/script-function.ts @@ -0,0 +1,158 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable no-new-func */ +/* eslint-disable @typescript-eslint/ban-types */ +import { mergeRight } from 'ramda'; +import { IScriptFunctionOpts } from '../../interface'; + +/** 默认选项 */ +const DefaultOptions: IScriptFunctionOpts = { + /** 是否是单行脚本,并把表达式结果return */ + singleRowReturn: false, + isAsync: true, +}; + +export class ScriptFunction { + protected scriptFn: Function; + + protected argKeys: string[] = []; + + protected options: IScriptFunctionOpts; + + constructor( + argKeys: string[], + scriptCode: string, + options: IScriptFunctionOpts = DefaultOptions, + ) { + this.options = options; + const code = this.formatCode(scriptCode, options); + this.calcArgKeys(argKeys, options); + const fn = new Function(...this.argKeys, code); + this.scriptFn = function callBack(...args: unknown[]): unknown { + try { + return fn.apply({}, args); + } catch (error) { + ibiz.log.error('报错脚本', code); + throw error; + } + }; + } + + /** + * 格式化脚本 + * @author lxm + * @date 2023-07-25 11:02:33 + * @protected + * @param {string} scriptCode + * @param {IScriptFunctionOpts} options + * @return {*} {string} + */ + protected formatCode( + scriptCode: string, + options: IScriptFunctionOpts, + ): string { + let code = scriptCode; + if (options.singleRowReturn) { + code = `return (${code})`; + } + if (options.isAsync) { + code = `return (async function() { ${code}} )();`; + } + return code; + } + + /** + * 计算参数名称集合 + * @author lxm + * @date 2023-07-25 11:42:37 + * @protected + * @param {string[]} argKeys + * @param {IScriptFunctionOpts} options + */ + protected calcArgKeys(argKeys: string[], options: IScriptFunctionOpts): void { + const keys = options.presetParams ? Object.keys(options.presetParams) : []; + keys.push(...argKeys); + // 预置提供的参数 + const presetArgsKeys = [ + 'document', + 'el', + 'selector', + 'env', + 'context', + 'viewParam', + 'data', + 'util', + ]; + keys.push(...presetArgsKeys); + // 除重 + this.argKeys = Array.from(new Set(keys)); + } + + /** + * 转换参数,把exec的对象参数转换成数组 + * @author lxm + * @date 2023-07-25 11:22:03 + * @protected + * @param {IParams} params + * @return {*} {any[]} + */ + protected convertArgs(params: IParams): any[] { + const { presetParams } = this.options; + // 合并执行参数和预置参数 + const _params = presetParams ? mergeRight(presetParams, params) : params; + + // 预置的元素查询参数 + _params.document = document; + _params.selector = (className: string): HTMLCollectionOf => { + return document.getElementsByClassName(className); + }; + + // 对象参数转数组 + const result: any[] = []; + this.argKeys.forEach(key => { + if (_params[key] === undefined) { + this.fillDefaultParams(key, _params); + } + result.push(_params[key]); + }); + + return result; + } + + /** + * 填充预置参数 + * @author lxm + * @date 2023-08-21 04:07:50 + * @protected + * @param {string} key + * @param {IParams} param + */ + protected fillDefaultParams(key: string, param: IParams): void { + switch (key) { + case 'util': // 工具类 + param.util = { + message: ibiz.message, + notification: ibiz.notification, + modal: ibiz.modal, + openView: ibiz.openView, + }; + break; + case 'env': // 全局环境变量 + param.env = ibiz.env; + break; + default: + break; + } + } + + /** + * 执行脚本代码 + * @author lxm + * @date 2023-07-25 11:21:44 + * @param {IParams} params + * @return {*} + */ + exec(params: IParams): unknown { + const scriptArgs = this.convertArgs(params); + return this.scriptFn(...scriptArgs); + } +} -- Gitee