diff --git a/erm.frontend/package.json b/erm.frontend/package.json index fc0c94cf..bc9e4fea 100644 --- a/erm.frontend/package.json +++ b/erm.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.245", + "platform-core": "8.1.246", "quasar": "2.15.3", "tailwindcss": "3.4.3", "vue": "3.4.24", diff --git a/gradle.properties b/gradle.properties index 461ba7da..3f53bb12 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,7 +38,7 @@ application_version=1.0.0 platform_group=io.sc platform_version=8.1.44 platform_plugin_version=8.1.44 -platform_core_frontend_version=8.1.245 +platform_core_frontend_version=8.1.246 ########################################################### # dependencies version diff --git a/io.sc.engine.mv.frontend/package.json b/io.sc.engine.mv.frontend/package.json index adde1af3..9cffb4ea 100644 --- a/io.sc.engine.mv.frontend/package.json +++ b/io.sc.engine.mv.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.245", + "platform-core": "8.1.246", "quasar": "2.15.3", "tailwindcss": "3.4.3", "vue": "3.4.24", diff --git a/io.sc.engine.rule.client.spring/src/main/resources/META-INF/platform/plugins/messages.json b/io.sc.engine.rule.client.spring/src/main/resources/META-INF/platform/plugins/messages.json new file mode 100644 index 00000000..e585b2a0 --- /dev/null +++ b/io.sc.engine.rule.client.spring/src/main/resources/META-INF/platform/plugins/messages.json @@ -0,0 +1,16 @@ +/* + * 国际化消息源插件配置 + * 功能: 该插件配置为框架提供国际化消息资源 + * 使用说明: + * includes: 包含国际化消息资源列表 + * excludes: 排除国际化消息资源列表 + * 注意: 当一个包名同时存在于 includes 和 excludes 中, excludes 优先, 即该包不会被自动扫描 + */ + + +{ + "includes":[ + "io/sc/engine/rule/client/spring/i18n/parameters" + ], + "excludes":[] +} diff --git a/io.sc.engine.rule.client.spring/src/main/resources/META-INF/platform/plugins/parameters.json b/io.sc.engine.rule.client.spring/src/main/resources/META-INF/platform/plugins/parameters.json new file mode 100644 index 00000000..9f33d4db --- /dev/null +++ b/io.sc.engine.rule.client.spring/src/main/resources/META-INF/platform/plugins/parameters.json @@ -0,0 +1,61 @@ +/* + * 系统参数贡献项配置示例 + * 功能说明: 为系统提供参数配置 + * 使用说明: + * id: 参数唯一标识 + * parentId: 父唯一标识,用于进行参数分类 + * code: 参数代码,应用可通过该代码获取参数值 + * defaultValue: 默认值 + * order: 排序 + */ + +[ + //模型引擎客户端 + {"id":"parameter.re.client","order":1010}, + //模型引擎客户端/执行器执行模式 + { + "id" :"parameter.re.client.executorMode", + "parentId" :"parameter.re.client", + "code" :"parameter.re.client.executorMode", + "defaultValue" :"Local", + "order" : 0, + "options" :{ + "Local" : "parameter.re.client.executorMode.Local", + "Remote" : "parameter.re.client.executorMode.Remote" + } + }, + //模型引擎客户端/模型定义加载器执行模式 + { + "id" :"parameter.re.client.loaderMode", + "parentId" :"parameter.re.client", + "code" :"parameter.re.client.loaderMode", + "defaultValue" :"Local", + "order" : 10, + "options" :{ + "Local" : "parameter.re.client.loaderMode.Local", + "Remote" : "parameter.re.client.loaderMode.Remote" + } + }, + //模型引擎客户端/远程模型引擎 API URL + { + "id" :"parameter.re.client.remoteApiUrl", + "parentId" :"parameter.re.client", + "code" :"parameter.re.client.remoteApiUrl", + "defaultValue" :"http://localhost:8080/api/re/resource", + "order" : 20 + }, + //模型引擎客户端/系统启动时自动编译模式 + { + "id" :"parameter.re.client.autoCompile", + "parentId" :"parameter.re.client", + "code" :"parameter.re.client.autoCompile", + "defaultValue" :"none", + "order" : 30, + "options" :{ + "none" : "parameter.re.client.autoCompile.none", /* 系统启动时不自动编译资源 */ + "deployed" : "parameter.re.client.autoCompile.deployed", /* 系统启动时自动编译[已发布]的资源 */ + "last" : "parameter.re.client.autoCompile.last", /* 系统启动时自动编译[最新版本]的资源 */ + "deployed-and-last" : "parameter.re.client.autoCompile.deployed_and_last" /* 系统启动时自动编译[已发布和最新版本]的资源 */ + } + } +] diff --git a/io.sc.engine.rule.client.spring/src/main/resources/io/sc/engine/rule/client/spring/i18n/parameters.properties b/io.sc.engine.rule.client.spring/src/main/resources/io/sc/engine/rule/client/spring/i18n/parameters.properties new file mode 100644 index 00000000..81c412af --- /dev/null +++ b/io.sc.engine.rule.client.spring/src/main/resources/io/sc/engine/rule/client/spring/i18n/parameters.properties @@ -0,0 +1,17 @@ +parameter.re.client=Rule Engine(Client) + +parameter.re.client.executorMode=Executor Mode +parameter.re.client.executorMode.Local=Local +parameter.re.client.executorMode.Remote=Remote + +parameter.re.client.loaderMode=Loader Mode +parameter.re.client.loaderMode.Local=Local +parameter.re.client.loaderMode.Remote=Remote + +parameter.re.client.remoteApiUrl=Remote Server API URL + +parameter.re.client.autoCompile=Auto Compile Resource Model after System Launched +parameter.re.client.autoCompile.none=None +parameter.re.client.autoCompile.deployed=Deployed +parameter.re.client.autoCompile.last=Last +parameter.re.client.autoCompile.deployed_and_last=Deployed And Last diff --git a/io.sc.engine.rule.client.spring/src/main/resources/io/sc/engine/rule/client/spring/i18n/parameters_zh_CN.properties b/io.sc.engine.rule.client.spring/src/main/resources/io/sc/engine/rule/client/spring/i18n/parameters_zh_CN.properties new file mode 100644 index 00000000..f19d301b --- /dev/null +++ b/io.sc.engine.rule.client.spring/src/main/resources/io/sc/engine/rule/client/spring/i18n/parameters_zh_CN.properties @@ -0,0 +1,17 @@ +parameter.re.client=\u51b3\u7b56\u5f15\u64ce(\u5ba2\u6237\u7aef) + +parameter.re.client.executorMode=\u6267\u884c\u5668\u6267\u884c\u6a21\u5f0f +parameter.re.client.executorMode.Local=\u672c\u5730 +parameter.re.client.executorMode.Remote=\u8fdc\u7a0b + +parameter.re.client.loaderMode=\u8d44\u6e90\u5b9a\u4e49\u52a0\u8f7d\u5668\u6267\u884c\u6a21\u5f0f +parameter.re.client.loaderMode.Local=\u672c\u5730 +parameter.re.client.loaderMode.Remote=\u8fdc\u7a0b + +parameter.re.client.remoteApiUrl=\u8fdc\u7a0b\u51b3\u7b56\u5f15\u64ce API URL\u5730\u5740 + +parameter.re.client.autoCompile=\u7cfb\u7edf\u542f\u52a8\u65f6\u81ea\u52a8\u7f16\u8bd1\u6a21\u5f0f +parameter.re.client.autoCompile.none=\u4e0d\u81ea\u52a8\u7f16\u8bd1 +parameter.re.client.autoCompile.deployed=\u81ea\u52a8\u7f16\u8bd1[\u5df2\u53d1\u5e03]\u7684\u8d44\u6e90 +parameter.re.client.autoCompile.last=\u81ea\u52a8\u7f16\u8bd1[\u6700\u65b0\u7248\u672c]\u7684\u8d44\u6e90 +parameter.re.client.autoCompile.deployed_and_last=\u81ea\u52a8\u7f16\u8bd1[\u5df2\u53d1\u5e03\u548c\u6700\u65b0\u7248\u672c]\u7684\u8d44\u6e90 diff --git a/io.sc.engine.rule.client/src/main/java/io/sc/engine/rule/client/remote/RemoteLoader.java b/io.sc.engine.rule.client/src/main/java/io/sc/engine/rule/client/remote/RemoteLoader.java index feceabb4..98e21ba7 100644 --- a/io.sc.engine.rule.client/src/main/java/io/sc/engine/rule/client/remote/RemoteLoader.java +++ b/io.sc.engine.rule.client/src/main/java/io/sc/engine/rule/client/remote/RemoteLoader.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import io.sc.platform.core.response.ResponseWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.sc.engine.rule.client.Loader; diff --git a/io.sc.engine.rule.client/src/test/java/io/sc/engine/rule/client/test/Test.java b/io.sc.engine.rule.client/src/test/java/io/sc/engine/rule/client/test/Test.java new file mode 100644 index 00000000..06998ed2 --- /dev/null +++ b/io.sc.engine.rule.client/src/test/java/io/sc/engine/rule/client/test/Test.java @@ -0,0 +1,73 @@ +package io.sc.engine.rule.client.test; + +import io.sc.engine.rule.client.Executor; +import io.sc.engine.rule.client.ExecutorBuilder; +import io.sc.engine.rule.client.ExecutorFactory; +import io.sc.engine.rule.client.enums.ExecutorMode; +import io.sc.engine.rule.client.enums.LoaderMode; +import io.sc.engine.rule.core.code.impl.support.ParameterResult; +import io.sc.engine.rule.core.code.impl.support.ResourceResult; +import io.sc.engine.rule.core.util.TimeTracer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Test { + private static final String MODEL_API_URL ="http://localhost:8080/api/re/resource"; //远程模型引擎 API URL 地址 + private static final String EXECUTOR_NAME ="executor"; //执行器名称 + private static final String MODEL_CODE ="M1628257024598"; //需要执行的模型代码 + private static final Integer MODEL_VERSION =null; //需要执行的模型版本 + private static final int COUNT =1; //需要执行的次数 + + private static TimeTracer tracer =TimeTracer.getInstance("tracer"); //创建一个时间跟踪器,用于跟踪执行时间,在生产环境中不要这样做 + + public static void main(String[] args) throws Exception{ + init(); + testLocalExecutorRemoteLoader_map(); + } + + public static void init() throws Exception{ + //创建执行器(本地执行,远程获取模型定义) + Executor executor =new ExecutorBuilder().build(ExecutorMode.LOCAL, LoaderMode.REMOTE, MODEL_API_URL); + + //注册执行器,便于之后获取,如果每次都构建一个新的执行器,将显著影响性能 + ExecutorFactory.register(EXECUTOR_NAME, executor); + + //第一次执行,消除缓存对性能对比测试的影响 + //executor.executeByCode(MODEL_CODE, MODEL_VERSION,JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(prepareData())); + ResourceResult result =executor.executeByCode(MODEL_CODE, MODEL_VERSION,prepareData()); + List parameters =result.getData(); + for(ParameterResult parameter : parameters) { + System.out.println(parameter); + } + //tracer.log("初始化完毕===================================="); + + } + + /** + * 测试本地执行器,远程模型定义加载器,输入参数为 map 对象 + * @throws Exception 违例 + */ + public static void testLocalExecutorRemoteLoader_map() throws Exception{ + //从注册器中获取执行器 + Executor executor =ExecutorFactory.getExecutor(EXECUTOR_NAME); + tracer.log("开始执行(采用 map 对象作为参数)===================================="); + for(int i=0;i data =prepareData(); + //executor.getLoader().getResourceByCode(MODEL_CODE, MODEL_VERSION); + executor.executeByCode(MODEL_CODE, MODEL_VERSION,data); + } + tracer.log("执行完毕(采用 map 对象作为参数)"); + tracer.log("采用 map 对象作为输入参数将执行效率提高 20+ 倍!!!"); + } + + + private static Map prepareData() throws Exception{ + Map map =new HashMap(); + map.put("P1628257063367", 10);//得分,整数 + return map; + } + +} diff --git a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/GroovySourceCodeGenerator.java b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/GroovySourceCodeGenerator.java index a0c66ce8..0f67895c 100644 --- a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/GroovySourceCodeGenerator.java +++ b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/GroovySourceCodeGenerator.java @@ -56,8 +56,8 @@ public class GroovySourceCodeGenerator implements CodeGenerator{ } private SourceCode _generateSourceCode(ResourceWrapper wrapper) throws Exception{ - Configuration cfg = new Configuration(Configuration.VERSION_2_3_28); - cfg.setTemplateLoader(new ClassTemplateLoader(GroovySourceCodeGenerator.class,"/org/wsp/engine/rule/core/code/template/groovy")); + Configuration cfg = new Configuration(Configuration.VERSION_2_3_32); + cfg.setTemplateLoader(new ClassTemplateLoader(GroovySourceCodeGenerator.class,"/io/sc/engine/rule/core/code/template/groovy")); cfg.setDefaultEncoding("UTF-8"); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); cfg.setLogTemplateExceptions(false); diff --git a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/enums/ProcessorType.java b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/enums/ProcessorType.java index 4a65b96a..90de7174 100644 --- a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/enums/ProcessorType.java +++ b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/enums/ProcessorType.java @@ -6,6 +6,7 @@ package io.sc.engine.rule.core.enums; public enum ProcessorType { EMPTY, //空操作 OPTION_VALUE, //选项值 + MATH_FORMULA, //数学公式 ARITHMETIC, //算数运算 TERNARY, //三元操作 WHEN_THEN, //When then 运算 diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/dictionary/dictionary.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/dictionary/dictionary.ftl new file mode 100644 index 00000000..44f0b77e --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/dictionary/dictionary.ftl @@ -0,0 +1,33 @@ +<#assign dictionaries=($wrapper.dictionaries)!> +<#list (dictionaries)! as dictionary> +/** + * 数据字典类 + * @author auto generated by engine + */ +@JsonIgnoreProperties(ignoreUnknown=true) +class ${CodeReplacer.className(dictionary.code)}_V${dictionary.version}{ +<#list (dictionary.getFields())! as field> + <#if field.defaultValue??> + <#if "java.lang.String"==(field.valueType)!> + String ${CodeReplacer.fieldName(field.code)} ="${field.defaultValue}";//${field.name} + <#else> + ${ValueType.getSimpleJavaType(field.valueType)} ${CodeReplacer.fieldName(field.code)} =${field.defaultValue};//${field.name} + + <#else> + <#if (field.valueTypeIsList)!> + List<${ValueType.getSimpleJavaType(field.valueType)}> ${CodeReplacer.fieldName(field.code)};//${field.name} + <#else> + ${ValueType.getSimpleJavaType(field.valueType)} ${CodeReplacer.fieldName(field.code)};//${field.name} + + + + + public void init(){ +<#list (dictionary.getFields())! as field> + <#if field?? && field.valueCalculation?? && field.valueCalculation!=""> + ${CodeReplacer.fieldName(field.code)} =(${ExpressionReplacer.groovyWithNoArgumentName(field.valueCalculation,null)}); + + + } +} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/groovy.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/groovy.ftl new file mode 100644 index 00000000..9e078125 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/groovy.ftl @@ -0,0 +1,99 @@ +<#ftl strip_whitespace=true> +package io.sc.engine.rule.core.code; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.type.TypeReference; + +import groovy.transform.Canonical; + +import java.math.*; + +import java.util.Random; +import java.util.Map; + +import io.sc.engine.rule.core.classes.RuleResult; +import io.sc.engine.rule.core.classes.SingleRuleResult; +import io.sc.engine.rule.core.classes.ResourceAbstract; + +import io.sc.engine.rule.core.code.impl.support.ResourceResult; +import io.sc.engine.rule.core.code.impl.support.ParameterResult; +import io.sc.engine.rule.core.code.impl.support.FieldValidator; +import io.sc.engine.rule.core.code.impl.support.ValidateResult; +import io.sc.engine.rule.core.enums.ParameterType; +import io.sc.engine.rule.core.enums.RuntimeInputParameterType; +import io.sc.engine.rule.core.util.DateUtil; +import io.sc.engine.rule.core.util.DataTypeConvertor; +import io.sc.engine.rule.core.util.ESql; +import io.sc.engine.rule.core.util.JacksonObjectMapper; +import io.sc.engine.rule.core.util.CodeReplacer; +import io.sc.engine.rule.core.util.Strings; + +import io.sc.engine.rule.client.Executor; + +import static java.lang.Math.PI; +import static java.lang.Math.E; +import static java.lang.Math.abs; +import static java.lang.Math.acos; +import static java.lang.Math.asin; +import static java.lang.Math.atan; +import static java.lang.Math.atan2; +import static java.lang.Math.cbrt; +import static java.lang.Math.ceil; +import static java.lang.Math.cos; +import static java.lang.Math.cosh; +import static java.lang.Math.exp; +import static java.lang.Math.expm1; +import static java.lang.Math.floor; +import static java.lang.Math.IEEEremainder; +import static java.lang.Math.log; +import static java.lang.Math.pow; +import static java.lang.Math.random; +import static java.lang.Math.rint; +import static java.lang.Math.round; +import static java.lang.Math.sin; +import static java.lang.Math.sinh; +import static java.lang.Math.sqrt; +import static java.lang.Math.tan; +import static java.lang.Math.tanh; +import static java.lang.Math.toDegrees; +import static java.lang.Math.toRadians; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.sc.engine.rule.core.function.JpmmlEvaluator; +import static io.sc.engine.rule.core.function.ArithmeticFunction.randomInt; +import static io.sc.engine.rule.core.function.ArithmeticFunction.max; +import static io.sc.engine.rule.core.function.ArithmeticFunction.min; +import static io.sc.engine.rule.core.function.ArithmeticFunction.sum; +import static io.sc.engine.rule.core.function.ArithmeticFunction.transformSequencing; +import static io.sc.engine.rule.core.function.DateFunction.now; +import static io.sc.engine.rule.core.function.DateFunction.yyyyMMdd; +import static io.sc.engine.rule.core.function.DateFunction.yyyy_MM_dd; +import static io.sc.engine.rule.core.function.StringFunction.join; +import static io.sc.engine.rule.core.function.NormalDistributionFunction.normalDistributioin; +import static io.sc.engine.rule.core.function.NormalDistributionFunction.inverseNormalDistributioin; + +import static io.sc.engine.rule.core.util.NumberFormater.decimal; +import static io.sc.engine.rule.core.util.NumberFormater.decimal1; +import static io.sc.engine.rule.core.util.NumberFormater.decimal2; +import static io.sc.engine.rule.core.util.NumberFormater.decimal3; +import static io.sc.engine.rule.core.util.NumberFormater.decimal4; +import static io.sc.engine.rule.core.util.NumberFormater.decimal5; +import static io.sc.engine.rule.core.util.NumberFormater.decimal6; + +import static io.sc.engine.rule.core.util.NumberFormater.money; +import static io.sc.engine.rule.core.util.NumberFormater.money2; + +import static io.sc.engine.rule.core.util.NumberFormater.rmb; +import static io.sc.engine.rule.core.util.NumberFormater.rmb2; + +import static io.sc.engine.rule.core.util.NumberFormater.percent; +import static io.sc.engine.rule.core.util.NumberFormater.percent2; + + +<#if $wrapper.type=="RESOURCE"> + <#include "/resource_groovy.ftl"/> +<#elseif $wrapper.type=="LIB"> + <#include "/lib_groovy.ftl"/> + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib/lib.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib/lib.ftl new file mode 100644 index 00000000..574cb102 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib/lib.ftl @@ -0,0 +1,111 @@ +<#assign libs=($wrapper.libs)!> +<#list (libs)! as lib> +/** + * 库类 + * @author auto generated by engine + */ +@JsonIgnoreProperties(ignoreUnknown=true) +class ${CodeReplacer.className(lib.code,lib.version)}{ + private static final Logger log =LoggerFactory.getLogger(${CodeReplacer.className(lib.code,lib.version)}.class); +<#list (lib.indicators)! as indicator> + ${indicator.forArgumentField($wrapper)} + + + //通过输入参数构建指标库对象 + public void convertArgument(Map map){ + Object obj =null; + <#list (lib.indicators)! as indicator> + ${indicator.forConvertArgumentFromMap($wrapper,"this")} + + } + + public void convertArgument(String json){ + ${CodeReplacer.className(lib.code)}_V${lib.version} result =JacksonObjectMapper.getDefaultObjectMapper().readValue(json, ${CodeReplacer.className(lib.code,lib.version)}.class); + <#list (lib.indicators)! as indicator> + <#if "INTERFACE"==(indicator.type)!> + this.${CodeReplacer.fieldName(indicator.code)} =result.${CodeReplacer.fieldName(indicator.code)}; + <#if ValueType.isBaseType(indicator.valueType)> + <#else> + this.${CodeReplacer.fieldName(indicator.code)}.init(); + + + + } + + public void execute() throws Exception{ + <#-- 处理指标值 --> + <#list (lib.indicators)! as indicator> + <#if "INDICATOR"==(indicator.type)!> + ${CodeReplacer.fieldName(indicator.code)}();//${indicator.name},${indicator.type} + + + } + + public void validate(ValidateResult result) { +<#list (lib.indicators)! as indicator> + <#list (indicator.validators)! as validator> + <#if "EMPTY"==(validator.type)!> + FieldValidator.empty("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "NOT_EMPTY"==(validator.type)!> + FieldValidator.notEmpty("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "TRUE"==(validator.type)!> + FieldValidator.trueValue("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "FALSE"==(validator.type)!> + FieldValidator.falseValue("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "INTEGER_RANGE"==(validator.type)!> + FieldValidator.integerRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>${validator.minValue}<#else>null,<#if validator.maxValue??>${validator.maxValue}<#else>null,result); + <#elseif "DECIMAL_RANGE"==(validator.type)!> + FieldValidator.decimalRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>new Double(${validator.minValue})<#else>null,<#if validator.maxValue??>new Double(${validator.maxValue})<#else>null,result); + <#elseif "LENGTH_RANGE"==(validator.type)!> + FieldValidator.lengthRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>${validator.minValue}<#else>null,<#if validator.maxValue??>${validator.maxValue}<#else>null,result); + <#elseif "DATE_RANGE"==(validator.type)!> + FieldValidator.dateRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>DateUtil.parseDate("${validator.minValue?string("yyyy-MM-dd HH:mm:ss")}")<#else>null,<#if validator.maxValue??>DateUtil.parseDate("${validator.maxValue?string("yyyy-MM-dd HH:mm:ss")}")<#else>null,result); + <#elseif "EMAIL"==(validator.type)!> + FieldValidator.mail("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "PATTERN"==(validator.type)!> + FieldValidator.pattern("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},"${validator.pattern}",result); + + + + } + +<#list (lib.indicators)! as indicator> + <#if "INDICATOR"==(indicator.type)!> + <#assign parameter=indicator> + public void ${CodeReplacer.fieldName(indicator.code)}(){ + ${CodeReplacer.className(lib.code)}_V${lib.version} arg =this; + <#list (indicator.processors)! as processor> + if(log.isDebugEnabled()){log.debug(" {}","${parameter.name}(${parameter.type})");} + <#if "OPTION_VALUE"==(processor.type)!> + <#include "/processor/OPTION_VALUE.ftl"/> + <#elseif "ARITHMETIC"==(processor.type)!> + <#include "/processor/ARITHMETIC.ftl"/> + <#elseif "TERNARY"==(processor.type)!> + <#include "/processor/TERNARY.ftl"/> + <#elseif "WHEN_THEN"==(processor.type)!> + <#include "/processor/WHEN_THEN.ftl"/> + <#elseif "NUMBER_RANGE"==(processor.type)!> + <#include "/processor/NUMBER_RANGE.ftl"/> + <#elseif "CONDITION_RANGE"==(processor.type)!> + <#include "/processor/CONDITION_RANGE.ftl"/> + <#elseif "DECISION_TABLE_2C"==(processor.type)!> + <#include "/processor/DECISION_TABLE_2C.ftl"/> + <#elseif "DECISION_TABLE"==(processor.type)!> + <#include "/processor/DECISION_TABLE.ftl"/> + <#elseif "DECISION_TREE"==(processor.type)!> + <#include "/processor/DECISION_TREE.ftl"/> + <#elseif "EXECUTION_FLOW"==(processor.type)!> + <#include "/processor/EXECUTION_FLOW.ftl"/> + <#elseif "PMML"==(processor.type)!> + <#include "/processor/PMML.ftl"/> + <#elseif "GROOVY_SCRIPT"==(processor.type)!> + <#include "/processor/GROOVY_SCRIPT.ftl"/> + <#elseif "SQL"==(processor.type)!> + <#include "/processor/SQL.ftl"/> + + + } + + +} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib_groovy.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib_groovy.ftl new file mode 100644 index 00000000..ac79d5d4 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib_groovy.ftl @@ -0,0 +1,197 @@ +<#assign lib=$wrapper.lib> +/** + * 指标库类(name:${lib.name}, code:${lib.code}, version:${lib.version}) + * ${(lib.description)!} + * @author auto generated by engine + */ +class ${CodeReplacer.className(lib.code,lib.version)}{ + private static final Logger log =LoggerFactory.getLogger(${CodeReplacer.className(lib.code,lib.version)}.class); + + /** + * 执行方法(Map作为输入参数,该 Map 封装了调用模型的参数) + * @param map 输入参数封装器 + * @return 执行结果 + */ + public static ResourceResult execute(Map map) throws Exception{ + return execute(map["executor"],map["subModelCode"],map["argument"]); + } + + <#-- 执行方法(Map作为输入参数) --> + /** + * 执行方法 + * @param executor 执行器对象 + * @param subModelCode 子模型代码 + * @param data 输入参数 + * @return 执行结果 + */ + public static ResourceResult execute(Executor executor,String subModelCode,Object data) throws Exception{ + if(log.isDebugEnabled()){log.debug("开始执行指标库 : ${CodeReplacer.className(lib.code,lib.version)}");} + if(data instanceof Map){ + if(log.isDebugEnabled()){log.debug("显示输入参数(Map)=================================================\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(data));} + }else if(data instanceof String){ + if(log.isDebugEnabled()){log.debug("显示输入参数(Json字符串)=================================================\n{}",data);} + } + //初始化模型参数 + if(log.isDebugEnabled()){log.debug("初始化指标库参数");} + Argument argument =Argument.convertArgument(data); + + //输入参数合法性检查(指标库) + ValidateResult validateResult =new ValidateResult(); + + //输入参数合法性检查(模型) + if(log.isDebugEnabled()){log.debug("开始检查指标库输入参数数据合法性");} + argument.validate(validateResult); + if(validateResult.hasError()){ + if(log.isDebugEnabled()){log.debug("\t检查结果: 失败!");} + ResourceResult result =new ResourceResult(); + result.setValidateResult(validateResult); + return result; + } + if(log.isDebugEnabled()){log.debug("\t检查结果: 成功!");} + + //执行指标库中的所有指标 + <#list (lib.indicators)! as indicator> + <#if "INDICATOR"==(indicator.type)!> + ${CodeReplacer.methodName(indicator.code)}(executor,argument);//${indicator.name},${indicator.type} + + + + //返回结果 + ResourceResult result =argument.toResult(); + if(log.isDebugEnabled()){log.debug("指标库调用成功,返回结果:\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(result));} + return result; + } + +<#list (lib.indicators)! as indicator> + <#if "INDICATOR"==(indicator.type)!> + public static void ${CodeReplacer.methodName(indicator.code)}(Executor executor,Argument arg){ + <#list (indicator.processors)! as processor> + <#assign parameter=indicator> + if(log.isDebugEnabled()){log.debug(" {}","${parameter.name}(${parameter.type})");} + <#if "OPTION_VALUE"==(processor.type)!> + <#include "/processor/OPTION_VALUE.ftl"/> + <#elseif "ARITHMETIC"==(processor.type)!> + <#include "/processor/ARITHMETIC.ftl"/> + <#elseif "TERNARY"==(processor.type)!> + <#include "/processor/TERNARY.ftl"/> + <#elseif "WHEN_THEN"==(processor.type)!> + <#include "/processor/WHEN_THEN.ftl"/> + <#elseif "NUMBER_RANGE"==(processor.type)!> + <#include "/processor/NUMBER_RANGE.ftl"/> + <#elseif "CONDITION_RANGE"==(processor.type)!> + <#include "/processor/CONDITION_RANGE.ftl"/> + <#elseif "DECISION_TABLE_2C"==(processor.type)!> + <#include "/processor/DECISION_TABLE_2C.ftl"/> + <#elseif "DECISION_TABLE"==(processor.type)!> + <#include "/processor/DECISION_TABLE.ftl"/> + <#elseif "DECISION_TREE"==(processor.type)!> + <#include "/processor/DECISION_TREE.ftl"/> + <#elseif "EXECUTION_FLOW"==(processor.type)!> + <#include "/processor/EXECUTION_FLOW.ftl"/> + <#elseif "PMML"==(processor.type)!> + <#include "/processor/PMML.ftl"/> + <#elseif "GROOVY_SCRIPT"==(processor.type)!> + <#include "/processor/GROOVY_SCRIPT.ftl"/> + <#elseif "SQL"==(processor.type)!> + <#include "/processor/SQL.ftl"/> + + + } + + +} + +/** + * 模型参数类 + * @author auto generated by engine + */ +@JsonIgnoreProperties(ignoreUnknown=true) +class Argument{ +<#list (lib.indicators)! as indicator> + ${indicator.forArgumentField($wrapper)} + + + <#-- 参数转换 --> + public static Argument convertArgument(Map map){ + if(map!=null){ + Argument argument =new Argument(); + Object obj =null; + + <#list (lib.indicators)! as indicator> + ${indicator.forConvertArgumentFromMap($wrapper,"argument")} + + + return argument; + } + return null; + } + + <#-- 参数转换 --> + public static Argument convertArgument(String json){ + if(json!=null && !"".equals(json.trim())){ + Argument argument =JacksonObjectMapper.getDefaultObjectMapper().readValue(json, Argument.class); + + <#list (lib.indicators)! as indicator> + ${indicator.forConvertArgumentFromJson($wrapper,"argument")} + + + return argument; + } + return null; + } + + public void validate(ValidateResult result) { +<#list (lib.indicators)! as indicator> + <#list (indicator.validators)! as validator> + <#if "EMPTY"==(validator.type)!> + FieldValidator.empty("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "NOT_EMPTY"==(validator.type)!> + FieldValidator.notEmpty("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "TRUE"==(validator.type)!> + FieldValidator.trueValue("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "FALSE"==(validator.type)!> + FieldValidator.falseValue("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "INTEGER_RANGE"==(validator.type)!> + FieldValidator.integerRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>${validator.minValue}<#else>null,<#if validator.maxValue??>${validator.maxValue}<#else>null,result); + <#elseif "DECIMAL_RANGE"==(validator.type)!> + FieldValidator.decimalRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>new Double(${validator.minValue})<#else>null,<#if validator.maxValue??>new Double(${validator.maxValue})<#else>null,result); + <#elseif "LENGTH_RANGE"==(validator.type)!> + FieldValidator.lengthRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>${validator.minValue}<#else>null,<#if validator.maxValue??>${validator.maxValue}<#else>null,result); + <#elseif "DATE_RANGE"==(validator.type)!> + FieldValidator.dateRange("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},<#if validator.minValue??>DateUtil.parseDate("${validator.minValue?string("yyyy-MM-dd HH:mm:ss")}")<#else>null,<#if validator.maxValue??>DateUtil.parseDate("${validator.maxValue?string("yyyy-MM-dd HH:mm:ss")}")<#else>null,result); + <#elseif "EMAIL"==(validator.type)!> + FieldValidator.mail("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},result); + <#elseif "PATTERN"==(validator.type)!> + FieldValidator.pattern("${indicator.code}",'''${indicator.name}''',this.${CodeReplacer.fieldName(indicator.code)},"${validator.pattern}",result); + + + + } + + public ResourceResult toResult(){ + ResourceResult result =new ResourceResult(); +<#list (lib.indicators)! as indicator> + <#if "INDICATOR"==(indicator.type)!> + <#if indicator.valueType==ValueType.Decimal.getJavaType()> + result.addParameterResult(new ParameterResult("${indicator.code}","${indicator.name}",ParameterType.${indicator.type},"${indicator.valueType}",${indicator.valueScale!"8"},RoundingMode.${indicator.valueRoundingMode!"HALF_UP"},this.${CodeReplacer.fieldName(indicator.code)}==null?null:${CodeReplacer.fieldName(indicator.code)}.setScale(${indicator.valueScale!"8"},RoundingMode.${indicator.valueRoundingMode!"HALF_UP"}).toString())); + <#elseif + indicator.valueType==ValueType.Boolean.getJavaType() + || indicator.valueType==ValueType.Long.getJavaType() + || indicator.valueType==ValueType.String.getJavaType() + || indicator.valueType==ValueType.Date.getJavaType() + > + result.addParameterResult(new ParameterResult("${indicator.code}","""${indicator.name}""",ParameterType.${indicator.type},"${indicator.valueType}",${indicator.valueScale!"null"},<#if indicator.valueRoundingMode??>RoundingMode.${indicator.valueRoundingMode}<#else>null,this.${CodeReplacer.fieldName(indicator.code)}==null?null:this.${CodeReplacer.fieldName(indicator.code)}.toString())); + <#else> + result.addParameterResult(new ParameterResult("${indicator.code}","""${indicator.name}""",ParameterType.${indicator.type},"${indicator.valueType}",${indicator.valueScale!"null"},<#if indicator.valueRoundingMode??>RoundingMode.${indicator.valueRoundingMode}<#else>null,this.${CodeReplacer.fieldName(indicator.code)}==null?null:JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(this.${CodeReplacer.fieldName(indicator.code)}))); + + + + return result; + } +} + +<#-- 数据字典类 --> +<#include "/dictionary/dictionary.ftl"/> + +//执行并返回 +${CodeReplacer.className(lib.code)}_V${lib.version}.execute(INPUT_PARAMETER); diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/argument.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/argument.ftl new file mode 100644 index 00000000..9f257887 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/argument.ftl @@ -0,0 +1,153 @@ +/** + * 模型参数类 + * @author auto generated by engine + */ +@JsonIgnoreProperties(ignoreUnknown=true) +class Argument{ +<#list (model.getAllParameters())! as parameter> + ${parameter.forArgumentField($wrapper)} + + +<#-- 参数转换 --> + public static Argument convertArgument(Map map){ + if(map!=null){ + Argument argument =new Argument(); + + Object obj =null; + + <#list (model.getAllParameters())! as parameter> + ${parameter.forConvertArgumentFromMap($wrapper,"argument")} + + + return argument; + } + return null; + } + + <#-- 参数转换 --> + public static Argument convertArgument(String json){ + if(json!=null && !"".equals(json.trim())){ + Argument argument =JacksonObjectMapper.getDefaultObjectMapper().readValue(json, Argument.class); + + <#list (model.getAllParameters())! as parameter> + ${parameter.forConvertArgumentFromJson($wrapper,"argument")} + + + return argument; + } + return null; + } + + public void validate(ValidateResult result) { +<#list (model.getAllParameters())! as parameter> + <#list (parameter.getValidators())! as validator> + ${validator.type!} + <#if "EMPTY"==(validator.type)!> + FieldValidator.empty("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},result); + <#elseif "NOT_EMPTY"==(validator.type)!> + FieldValidator.notEmpty("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},result); + <#elseif "TRUE"==(validator.type)!> + FieldValidator.trueValue("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},result); + <#elseif "FALSE"==(validator.type)!> + FieldValidator.falseValue("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},result); + <#elseif "INTEGER_RANGE"==(validator.type)!> + FieldValidator.integerRange("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},<#if validator.minValue??>${validator.minValue}<#else>null,<#if validator.maxValue??>${validator.maxValue}<#else>null,result); + <#elseif "DECIMAL_RANGE"==(validator.type)!> + FieldValidator.decimalRange("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},<#if validator.minValue??>new Double(${validator.minValue})<#else>null,<#if validator.maxValue??>new Double(${validator.maxValue})<#else>null,result); + <#elseif "LENGTH_RANGE"==(validator.type)!> + FieldValidator.lengthRange("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},<#if validator.minValue??>${validator.minValue}<#else>null,<#if validator.maxValue??>${validator.maxValue}<#else>null,result); + <#elseif "DATE_RANGE"==(validator.type)!> + FieldValidator.dateRange("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},<#if validator.minValue??>DateUtil.parseDate("${validator.minValue?string("yyyy-MM-dd HH:mm:ss")}")<#else>null,<#if validator.maxValue??>DateUtil.parseDate("${validator.maxValue?string("yyyy-MM-dd HH:mm:ss")}")<#else>null,result); + <#elseif "EMAIL"==(validator.type)!> + FieldValidator.mail("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},result); + <#elseif "PATTERN"==(validator.type)!> + FieldValidator.pattern("${parameter.code}",'''${parameter.name}''',this.${CodeReplacer.fieldName(parameter.code)},"${validator.pattern}",result); + + + + } + + public void mergeParameterValueFromIndicatorLib(Map libs){ + <#list (model.getAllParameters())! as parameter> + <#if "INDICATOR"==(parameter.type)!> + <#-- 如果直接给模型参数(类型为指标)设置过非空值,则直接采用设置过的值,否则采用指标库计算结果值 --> + <#if $wrapper.isExecuteTestCase> + if(this.${CodeReplacer.fieldName(parameter.code)}==null){this.${CodeReplacer.fieldName(parameter.code)} =libs.get("${CodeReplacer.varName(parameter.libCode,parameter.libVersion)}").${CodeReplacer.fieldName(parameter.indicatorCode)};}//${parameter.name} + <#else> + this.${CodeReplacer.fieldName(parameter.code)} =libs.get("${CodeReplacer.varName(parameter.libCode,parameter.libVersion)}").${CodeReplacer.fieldName(parameter.indicatorCode)};//${parameter.name} + + + + } + + public ResourceResult toResult(){ + ResourceResult result =new ResourceResult(); +<#list model.getAllParameters() as parameter> + <#if 'OUT'==(parameter.type)! || 'INTERMEDIATE'==(parameter.type)!> + <#if parameter.valueType==ValueType.Decimal.getJavaType()> + result.addParameterResult(new ParameterResult("${parameter.code}","${parameter.name}",ParameterType.${parameter.type},"${parameter.valueType}",${parameter.valueScale!"8"},RoundingMode.${parameter.valueRoundingMode!"HALF_UP"},this.${CodeReplacer.fieldName(parameter.code)}==null?null:${CodeReplacer.fieldName(parameter.code)}.setScale(${parameter.valueScale!"8"},RoundingMode.${parameter.valueRoundingMode!"HALF_UP"}).toString())); + <#elseif + parameter.valueType==ValueType.Boolean.getJavaType() + || parameter.valueType==ValueType.Long.getJavaType() + || parameter.valueType==ValueType.String.getJavaType() + || parameter.valueType==ValueType.Date.getJavaType() + > + result.addParameterResult(new ParameterResult("${parameter.code}","${parameter.name}",ParameterType.${parameter.type},"${parameter.valueType}",null,null,this.${CodeReplacer.fieldName(parameter.code)}==null?null:this.${CodeReplacer.fieldName(parameter.code)}.toString())); + <#else> + result.addParameterResult(new ParameterResult("${parameter.code}","${parameter.name}",ParameterType.${parameter.type},"${parameter.valueType}",null,null,this.${CodeReplacer.fieldName(parameter.code)}==null?null:JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(this.${CodeReplacer.fieldName(parameter.code)}))); + + <#elseif 'INDICATOR'==(parameter.type)!> + <#assign indicator=LibUtil.findIndicator($wrapper.libs,parameter.libCode,parameter.libVersion,parameter.indicatorCode)> + <#if "INDICATOR"==(indicator.type)!> + <#if parameter.valueType==ValueType.Decimal.getJavaType()> + result.addParameterResult(new ParameterResult("${indicator.code}","${indicator.name}",ParameterType.${parameter.type},"${parameter.valueType}",${parameter.valueScale!"8"},RoundingMode.${parameter.valueRoundingMode!"HALF_UP"},this.${CodeReplacer.fieldName(parameter.code)}==null?null:${CodeReplacer.fieldName(parameter.code)}.setScale(${parameter.valueScale!"8"},RoundingMode.${parameter.valueRoundingMode!"HALF_UP"}).toString())); + <#elseif + parameter.valueType==ValueType.Boolean.getJavaType() + || parameter.valueType==ValueType.Long.getJavaType() + || parameter.valueType==ValueType.String.getJavaType() + || parameter.valueType==ValueType.Date.getJavaType() + > + result.addParameterResult(new ParameterResult("${indicator.code}","${indicator.name}",ParameterType.${parameter.type},"${parameter.valueType}",null,null,this.${CodeReplacer.fieldName(parameter.code)}==null?null:this.${CodeReplacer.fieldName(parameter.code)}.toString())); + <#else> + result.addParameterResult(new ParameterResult("${indicator.code}","${indicator.name}",ParameterType.${parameter.type},"${parameter.valueType}",null,null,this.${CodeReplacer.fieldName(parameter.code)}==null?null:JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(this.${CodeReplacer.fieldName(parameter.code)}))); + + + <#elseif 'RULE_RESULT'==(parameter.type)!> + result.addParameterResult(new ParameterResult("${parameter.code}","${parameter.name}",ParameterType.${parameter.type},this.${CodeReplacer.fieldName(parameter.code)})); + <#elseif 'SINGLE_RULE_RESULT'==(parameter.type)!> + result.addParameterResult(new ParameterResult("${parameter.code}","${parameter.name}",ParameterType.${parameter.type},this.${CodeReplacer.fieldName(parameter.code)})); + + + return result; + } + + public Map toMap(){ + Map map =new HashMap(); + <#list model.getAllParameters() as parameter> + map.put("${parameter.code}",this.${CodeReplacer.fieldName(parameter.code)});//${parameter.type}, ${parameter.name} + + return map; + } + + public void mergeResult(ResourceResult result){ + if(result!=null){ +<#list model.getAllParameters() as parameter> + <#if + parameter.valueType==ValueType.Boolean.getJavaType() + || parameter.valueType==ValueType.Long.getJavaType() + || parameter.valueType==ValueType.Decimal.getJavaType() + || parameter.valueType==ValueType.String.getJavaType() + || parameter.valueType==ValueType.Date.getJavaType() + > + if(result.exists("${parameter.code}")){ + this.${CodeReplacer.fieldName(parameter.code)} =DataTypeConvertor.convert(result.getValueByParameterCode("${parameter.code}"),${ValueType.getSimpleJavaType(parameter.valueType)}.class); + } + <#else> + if(result.exists("${parameter.code}")){ + this.${CodeReplacer.fieldName(parameter.code)} =result.getValueByParameterCode("${parameter.code}"); + } + + + } + } +} \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/model.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/model.ftl new file mode 100644 index 00000000..dc78107b --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/model.ftl @@ -0,0 +1,224 @@ +<#assign model=resource.model> +/** + * 资源类(name:${resource.name}, code:${resource.code}, version:${resource.version}) + * @author auto generated by engine + */ +class ${CodeReplacer.className(resource.code,resource.version)} { + private static final Logger log =LoggerFactory.getLogger(${CodeReplacer.className(resource.code,resource.version)}.class); + + /** + * 执行方法(Map作为输入参数,该 Map 封装了调用模型的参数) + * @param map 输入参数封装器 + * @return 执行结果 + */ + public static ResourceResult execute(Map map) throws Exception{ + return execute(map["executor"],map["subModelCode"],map["argument"]); + } + + <#-- 执行方法(Map作为输入参数) --> + /** + * 执行方法 + * @param executor 执行器对象 + * @param subModelCode 子模型代码 + * @param data 输入参数 + * @return 执行结果 + */ + public static ResourceResult execute(Executor executor,String subModelCode,Object data) throws Exception{ + if(log.isDebugEnabled()){log.debug("开始执行模型 : ${CodeReplacer.className(resource.code,resource.version)}");} + if(data instanceof Map){ + if(log.isDebugEnabled()){log.debug("显示输入参数(Map)=================================================\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(data));} + }else if(data instanceof String){ + if(log.isDebugEnabled()){log.debug("显示输入参数(Json字符串)=================================================\n{}",data);} + } + + <#if $wrapper.isExecuteTestCase> + <#else> + <#list ($wrapper.libs)! as lib> + if(log.isDebugEnabled()){log.debug("初始化指标库 : ${lib.name}_V${lib.version}");} + ${CodeReplacer.className(lib.code,lib.version)} ${CodeReplacer.varName(lib.code,lib.version)} =new ${CodeReplacer.className(lib.code,lib.version)}(); + ${CodeReplacer.varName(lib.code,lib.version)}.convertArgument(data); + + + + //初始化模型参数 + if(log.isDebugEnabled()){log.debug("从 {} 初始化模型参数","java.lang.String"==data.class?"Json":"Map");} + Argument argument =Argument.convertArgument(data); + + //输入参数合法性检查 + ValidateResult validateResult =new ValidateResult(); + + <#if $wrapper.isExecuteTestCase> + <#else> + //输入参数合法性检查(指标库) + <#list ($wrapper.libs)! as lib> + if(log.isDebugEnabled()){log.debug("开始检查输入参数数据合法性(指标库: ${lib.name}_V${lib.version})");} + ${CodeReplacer.varName(lib.code,lib.version)}.validate(validateResult); + if(validateResult.hasError()){ + if(log.isDebugEnabled()){log.debug("\t检查结果: 失败!");} + ResourceResult result =new ResourceResult(); + result.setValidateResult(validateResult); + return result; + } + if(log.isDebugEnabled()){log.debug("\t检查结果: 成功!");} + + + //输入参数合法性检查(模型) + if(log.isDebugEnabled()){log.debug("开始检查模型输入参数数据合法性");} + argument.validate(validateResult); + if(validateResult.hasError()){ + if(log.isDebugEnabled()){log.debug("\t检查结果: 失败!");} + ResourceResult result =new ResourceResult(); + result.setValidateResult(validateResult); + return result; + } + if(log.isDebugEnabled()){log.debug("\t检查结果: 成功!");} + + <#if $wrapper.isExecuteTestCase> + <#else> + //执行指标库 + <#list ($wrapper.libs)! as lib> + if(log.isDebugEnabled()){log.debug("开始执行指标库: ${lib.name}_V${lib.version}");} + ${CodeReplacer.varName(lib.code,lib.version)}.execute(); + + + + <#if $wrapper.isExecuteTestCase> + <#else> + //合并指标库指标 + if(log.isDebugEnabled()){log.debug("开始合并指标库指标");} + Map indicatorLibs =new HashMap(); + <#list ($wrapper.libs)! as lib> + indicatorLibs.put("${CodeReplacer.varName(lib.code,lib.version)}",${CodeReplacer.varName(lib.code,lib.version)}); + + argument.mergeParameterValueFromIndicatorLib(indicatorLibs); + if(log.isDebugEnabled()){log.debug("显示合并后输入参数:\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(argument));} + + + //执行模型 + if(subModelCode){ + subModelCode =CodeReplacer.methodName(subModelCode); + "${r'${subModelCode}'}"(executor,argument);//调用子模型 + }else{ + ${CodeReplacer.methodName(model.code)}(executor,argument);//调用顶级模型(${model.name}) + } + + //返回结果 + ResourceResult result =argument.toResult(); + if(log.isDebugEnabled()){log.debug("模型调用成功,返回结果:\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(result));} + return result; + } + + //顶级模型(${model.fullName}) + private static void ${CodeReplacer.methodName(model.code)}(Executor executor,Argument argument){ + if(log.isDebugEnabled()){log.debug("开始调用顶级模型: {}","${model.name}");} + <#if (model.enable)!> + <#else> + if(log.isDebugEnabled()){log.debug("开始调用顶级模型: enable==false");} + return; + + <#if "DOWN_TOP"==(model.executeMode)!> + <#-- 模型的执行模式为:自下而上,首先执行子模型 --> + <#list (model.children)! as subModel> + ${CodeReplacer.methodName(subModel.code)}(executor,argument);//${subModel.name} + + + <#-- 处理顶级模型的中间值和结果值 --> + <#list (model.parameters)! as parameter> + <#if "INTERMEDIATE"==(parameter.type)! || "OUT"==(parameter.type)! || "RULE_RESULT"==(parameter.type)! || "SINGLE_RULE_RESULT"==(parameter.type)!> + ${CodeReplacer.methodName(parameter.code)}(executor,argument);//${parameter.name},${parameter.type} + + + } + + <#-- 递归生成所有子模型执行方法 --> + <#list (model.children)! as subModel> + //子模型(${subModel.fullName}) + private static void ${CodeReplacer.methodName(subModel.code)}(Executor executor,Argument argument){ + if(log.isDebugEnabled()){log.debug("开始调用子模型: {}","${subModel.fullName}");} + <#if (subModel.enable)!> + <#else> + if(log.isDebugEnabled()){log.debug("开始调用子模型: enable==false");} + return; + + <#if "DOWN_TOP"==(subModel.executeMode)!> + <#-- 子模型的执行模式为:自下而上,首先执行子模型的子模型 --> + <#list (subModel.children)! as _subModel> + ${CodeReplacer.methodName(_subModel.code)}(executor,argument);//${_subModel.name} + + + <#-- 处理子模型的中间值和结果值 --> + <#list (subModel.getParameters())! as parameter> + <#if "INTERMEDIATE"==(parameter.type)! || "OUT"==(parameter.type)! || "RULE_RESULT"==(parameter.type)! || "SINGLE_RULE_RESULT"==(parameter.type)!> + ${CodeReplacer.methodName(parameter.code)}(executor,argument);//${parameter.name},${parameter.type} + + + } + + <#include "/model/sub-model.ftl"/> + + <#-- 生成所有参数处理器方法 --> + + <#list (model.getAllParameters())! as parameter><#-- 循环将每个参数处理生成一个方法 --> + <#if ("INTERMEDIATE"==(parameter.type)! || "OUT"==(parameter.type)! || "RULE_RESULT"==(parameter.type)! || "SINGLE_RULE_RESULT"==(parameter.type)!)> + //参数处理器, ${parameter.name}(${parameter.type}) + private static void ${CodeReplacer.methodName(parameter.code)}(Executor executor,Argument ${ExpressionReplacer.ARGUMENT_NAME}){ + if(log.isDebugEnabled()){log.debug(" {}","${parameter.name}(${parameter.type})");} + <#list (parameter.processors)! as processor><#-- 循环将每个处理器转换成 java 语句 --> + <#if (processor.enable)!> + <#if "OPTION_VALUE"==(processor.type)!> + <#include "/processor/OPTION_VALUE.ftl"/> + <#elseif "ARITHMETIC"==(processor.type)!> + <#include "/processor/ARITHMETIC.ftl"/> + <#elseif "TERNARY"==(processor.type)!> + <#include "/processor/TERNARY.ftl"/> + <#elseif "WHEN_THEN"==(processor.type)!> + <#include "/processor/WHEN_THEN.ftl"/> + <#elseif "RULE"==(processor.type)!> + <#include "/processor/RULE.ftl"/> + <#elseif "SINGLE_RULE"==(processor.type)!> + <#include "/processor/SINGLE_RULE.ftl"/> + <#elseif "NUMBER_RANGE"==(processor.type)!> + <#include "/processor/NUMBER_RANGE.ftl"/> + <#elseif "CONDITION_RANGE"==(processor.type)!> + <#include "/processor/CONDITION_RANGE.ftl"/> + <#elseif "DECISION_TABLE_2C"==(processor.type)!> + <#include "/processor/DECISION_TABLE_2C.ftl"/> + <#elseif "DECISION_TABLE"==(processor.type)!> + <#include "/processor/DECISION_TABLE.ftl"/> + <#elseif "DECISION_TREE"==(processor.type)!> + <#include "/processor/DECISION_TREE.ftl"/> + <#elseif "EXECUTION_FLOW"==(processor.type)!> + <#include "/processor/EXECUTION_FLOW.ftl"/> + <#elseif "PMML"==(processor.type)!> + <#include "/processor/PMML.ftl"/> + <#elseif "GROOVY_SCRIPT"==(processor.type)!> + <#include "/processor/GROOVY_SCRIPT.ftl"/> + <#elseif "SQL"==(processor.type)!> + <#include "/processor/SQL.ftl"/> + + + + if(log.isDebugEnabled()){log.debug(" 参数结果值 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + } + + + + + <#-- 决策树函数 --> + <#include "/processor/DECISION_TREE_FUNCTION.ftl"/> + + <#-- 执行流函数 --> + <#include "/processor/EXECUTION_FLOW_FUNCTION.ftl"/> +} + +<#-- 参数类 --> +<#include "/model/argument.ftl"/> + +<#-- 库类 --> +<#include "/lib/lib.ftl"/> + +<#-- 数据字典类 --> +<#include "/dictionary/dictionary.ftl"/> + +//执行并返回 +${CodeReplacer.className(resource.code)}_V${resource.version}.execute(INPUT_PARAMETER); diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/sub-model.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/sub-model.ftl new file mode 100644 index 00000000..81b31995 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/sub-model.ftl @@ -0,0 +1,25 @@ +<#list (subModel.children)! as subModel> + //子模型(${subModel.fullName}) + private static void ${subModel.code}(Executor executor,Argument argument){ + if(log.isDebugEnabled()){log.debug("开始调用子模型: {}","${subModel.fullName}");} + <#if (subModel.enable)!> + <#else> + if(log.isDebugEnabled()){log.debug("开始调用子模型: enable==false");} + return; + + <#if "DOWN_TOP"==(subModel.executeMode)!> + <#-- 子模型的执行模式为:自下而上,首先执行子模型的子模型 --> + <#list (subModel.children)! as _subModel> + ${_subModel.code}(executor,argument);//${_subModel.name} + + + <#-- 处理子模型的中间值和结果值 --> + <#list (subModel.getParameters())! as parameter> + <#if "INTERMEDIATE"==(parameter.type)! || "OUT"==(parameter.type)! || "RULE_RESULT"==(parameter.type)! || "SINGLE_RULE_RESULT"==(parameter.type)!> + ${parameter.code}(executor,argument);//${parameter.name},${parameter.type} + + + } + + <#include "/model/sub-model.ftl"/> + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/ARITHMETIC.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/ARITHMETIC.ftl new file mode 100644 index 00000000..b187a71b --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/ARITHMETIC.ftl @@ -0,0 +1,4 @@ + //算数运算 + ${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)} =${ExpressionReplacer.groovy(processor.arithmetic,parameter.valueType<#-- 算数运算,需要进行相关逻辑处理,即使参数类型为字符串也需要执行算数运算表达式 -->)};//${parameter.type}, ${parameter.name} + if(log.isDebugEnabled()){log.debug(" 算数运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/CONDITION_RANGE.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/CONDITION_RANGE.ftl new file mode 100644 index 00000000..d61b9e78 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/CONDITION_RANGE.ftl @@ -0,0 +1,4 @@ + //条件分段函数 + ${ConditionRange.generateGroovyCode(parameter,processor)} + if(log.isDebugEnabled()){log.debug(" 条件分段函数运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TABLE.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TABLE.ftl new file mode 100644 index 00000000..afd56363 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TABLE.ftl @@ -0,0 +1,4 @@ + //决策表 + ${DecisionTable.generateGroovyCode(parameter,processor)} + if(log.isDebugEnabled()){log.debug(" 决策表运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TABLE_2C.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TABLE_2C.ftl new file mode 100644 index 00000000..ac42970b --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TABLE_2C.ftl @@ -0,0 +1,4 @@ + //简单决策表 + ${DecisionTable2C.generateGroovyCode(parameter,processor)} + if(log.isDebugEnabled()){log.debug(" 简单决策表运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TREE.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TREE.ftl new file mode 100644 index 00000000..6a873b76 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TREE.ftl @@ -0,0 +1,4 @@ + //决策树(此处只是入口,真正的决策树计算逻辑在后面通过一系列方法完成) + ${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)} =Tree_${CodeReplacer.fieldName(parameter.code)}_${DecisionTree.parse(processor.decisionTree).id}(executor,${ExpressionReplacer.ARGUMENT_NAME}); + if(log.isDebugEnabled()){log.debug(" 决策树运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TREE_FUNCTION.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TREE_FUNCTION.ftl new file mode 100644 index 00000000..cc765d79 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/DECISION_TREE_FUNCTION.ftl @@ -0,0 +1,13 @@ + /*-------------------------------------------------------------------------------* + * 决策树函数 * + *-------------------------------------------------------------------------------*/ +<#list (model.getAllParameters())! as parameter><#-- 循环将每个参数处理生成一个方法 --> + <#if ("INTERMEDIATE"==parameter.type || "OUT"==parameter.type)> + <#list (parameter.processors)! as processor> + <#if "DECISION_TREE"==processor.type> + //${parameter.name}(${parameter.type}) +${DecisionTree.generateGroovyCode(parameter,processor)} + + + + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/EXECUTION_FLOW.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/EXECUTION_FLOW.ftl new file mode 100644 index 00000000..70f67752 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/EXECUTION_FLOW.ftl @@ -0,0 +1,4 @@ + //执行流(此处只是入口,真正的执行流计算逻辑在后面通过一系列方法完成) + Flow_${CodeReplacer.fieldName(parameter.code)}_${ExecutionFlow.parse(processor.executionFlow).id}(executor,${ExpressionReplacer.ARGUMENT_NAME}); + if(log.isDebugEnabled()){log.debug(" 执行流运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/EXECUTION_FLOW_FUNCTION.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/EXECUTION_FLOW_FUNCTION.ftl new file mode 100644 index 00000000..70cbd867 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/EXECUTION_FLOW_FUNCTION.ftl @@ -0,0 +1,13 @@ + /*-------------------------------------------------------------------------------* + * 执行流函数 * + *-------------------------------------------------------------------------------*/ +<#list (model.getAllParameters())! as parameter><#-- 循环将每个参数处理生成一个方法 --> + <#if ("INTERMEDIATE"==parameter.type || "OUT"==parameter.type)> + <#list (parameter.processors)! as processor> + <#if "EXECUTION_FLOW"==processor.type> + //${parameter.name}(${parameter.type}) +${ExecutionFlow.generateGroovyCode(parameter,processor)} + + + + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/GROOVY_SCRIPT.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/GROOVY_SCRIPT.ftl new file mode 100644 index 00000000..62637aa0 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/GROOVY_SCRIPT.ftl @@ -0,0 +1,3 @@ +<#if processor.groovyScript??> +${ExpressionReplacer.groovy(processor.groovyScript,null)} + diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/NUMBER_RANGE.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/NUMBER_RANGE.ftl new file mode 100644 index 00000000..02b92a41 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/NUMBER_RANGE.ftl @@ -0,0 +1,4 @@ + //数值分段函数 + ${NumberRange.generateGroovyCode(parameter,processor)} + if(log.isDebugEnabled()){log.debug(" 数值分段函数运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/OPTION_VALUE.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/OPTION_VALUE.ftl new file mode 100644 index 00000000..15e866e2 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/OPTION_VALUE.ftl @@ -0,0 +1,34 @@ + //选项值运算 +<#assign optionParameter=model.getParameterByOptionParameterCode(processor.optionCode)> +<#if optionParameter??> + if(${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(optionParameter.code)}!=null){ + <#list model.getParameterOptionsByOptionParameterCode(processor.optionCode) as option> + <#if option_index==0> + <#if optionParameter.valueType=='java.lang.String'> + if(${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(optionParameter.code)}=="""${option.inputValue}"""){ + <#else> + if(${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(optionParameter.code)}==${option.inputValue}){ + + <#else> + <#if optionParameter.valueType=='java.lang.String'> + }else if(${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(optionParameter.code)}=="""${option.inputValue}"""){ + <#else> + }else if(${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(optionParameter.code)}==${option.inputValue}){ + + + <#if parameter.valueType=='java.lang.String'> + ${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)} ="""${option.value}"""; + if(log.isDebugEnabled()){log.debug(" 选项运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + <#else> + ${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)} =${option.value}; + if(log.isDebugEnabled()){log.debug(" 选项运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + + + }else{ + if(log.isDebugEnabled()){log.debug(" !!!未匹配到选项列表,选项运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + } + }else{ + if(log.isDebugEnabled()){log.debug(" !!!未提供选项输入值,选项运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + } + + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/PMML.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/PMML.ftl new file mode 100644 index 00000000..f60f6669 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/PMML.ftl @@ -0,0 +1,3 @@ +<#if processor.pmml??> + arg.${CodeReplacer.fieldName(parameter.code)} =JpmmlEvaluator.evaluate('${parameter.id}_${processor.id}','''${processor.pmml}''',arg.toMap()); + diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/RULE.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/RULE.ftl new file mode 100644 index 00000000..c91b7048 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/RULE.ftl @@ -0,0 +1,4 @@ + //规则运算 +${Rule.generateGroovyCode(parameter,processor)} + if(log.isDebugEnabled()){log.debug(" 算数运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/SINGLE_RULE.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/SINGLE_RULE.ftl new file mode 100644 index 00000000..e0e1b549 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/SINGLE_RULE.ftl @@ -0,0 +1,4 @@ + //单规则运算 +${SingleRule.generateGroovyCode(parameter,processor)} + if(log.isDebugEnabled()){log.debug(" 算数运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/SQL.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/SQL.ftl new file mode 100644 index 00000000..f454710e --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/SQL.ftl @@ -0,0 +1,17 @@ + //SQL 运算 +<#if processor.sqlDatasourceName??> + javax.sql.DataSource ds =io.sc.engine.rule.client.spring.util.EngineSpringApplicationContextUtil.getDataSource('${processor.sqlDatasourceName}'); +<#else> + javax.sql.DataSource ds =io.sc.engine.rule.client.spring.util.EngineSpringApplicationContextUtil.getDefaultDataSource(); + + String sql =${ExpressionReplacer.groovy("\n"+processor.sql,"java.lang.String")}; +<#if processor.sql??> + ESql.withInstance(ds){ db-> + db.query(sql) { rs -> + if (rs.next()) { +${SqlFieldMapping.generateGroovyCode(parameter,processor)} + } + } + } + + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/TERNARY.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/TERNARY.ftl new file mode 100644 index 00000000..1e46ea04 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/TERNARY.ftl @@ -0,0 +1,4 @@ + //三元运算 + ${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)} =(${ExpressionReplacer.groovy(processor.ternaryCondition,null)}) ? (${ExpressionReplacer.groovy(processor.ternaryTrue,parameter.valueType)}) : (${ExpressionReplacer.groovy(processor.ternaryFalse,parameter.valueType)}); + if(log.isDebugEnabled()){log.debug(" 三元运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/WHEN_THEN.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/WHEN_THEN.ftl new file mode 100644 index 00000000..3938e50a --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/WHEN_THEN.ftl @@ -0,0 +1,12 @@ + //WhenThen 运算 + if(${ExpressionReplacer.groovy(processor.when,null)}){ + ${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)} =${ExpressionReplacer.groovy(processor.then,parameter.valueType)}; + if(log.isDebugEnabled()){log.debug(" WhenThen 运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + <#-- 如果是短路操作,直接结束处理 --> + <#if processor.isWhenThenShorted> + if(log.isDebugEnabled()){log.debug(" WhenThen 短路!!!");} + if(log.isDebugEnabled()){log.debug(" 参数结果值 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});} + return; + + } + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/resource_groovy.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/resource_groovy.ftl new file mode 100644 index 00000000..e8dd5c4d --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/resource_groovy.ftl @@ -0,0 +1,11 @@ +<#assign resource=$wrapper.resource> +//外部引入------------------------------------------------------- +<#if resource.imports??> +${resource.imports} + + +<#if resource.type=="MODEL"> + <#include "/model/model.ftl"/> +<#elseif resource.type=="SCORE_CARD"> + <#include "/scorecard/score_card.ftl"/> + \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/scorecard/argument.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/scorecard/argument.ftl new file mode 100644 index 00000000..d7b5baa6 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/scorecard/argument.ftl @@ -0,0 +1,89 @@ +/********************************************************************************** + * 评分卡参数类 * + **********************************************************************************/ +@JsonIgnoreProperties(ignoreUnknown=true) +class Argument{ +<#list (resource.scoreCardVars)! as scoreCardVar> + <#if 'NUMBER_RANGE'==(scoreCardVar.type)! || 'INDICATOR_NUMBER_RANGE'==(scoreCardVar.type)! || 'INDICATOR_VALUE'==(scoreCardVar.type)!> + BigDecimal ${CodeReplacer.fieldName(scoreCardVar.code)};//${scoreCardVar.name}, ${scoreCardVar.type} + <#elseif 'OPTION'==(scoreCardVar.type)! || 'INDICATOR_OPTION'==(scoreCardVar.type)!> + String ${CodeReplacer.fieldName(scoreCardVar.code)};//${scoreCardVar.name}, ${scoreCardVar.type} + + + +<#list (resource.scoreCardVars)! as scoreCardVar> + BigDecimal R_${scoreCardVar.code};//${scoreCardVar.name}得分, OUT + + + /* 最终得分 -------------------------------*/ + BigDecimal _SCORE_;//最终得分 + + <#-- 参数转换(Map) --> + public static Argument convertArgument(Map map){ + if(map!=null){ + Argument argument =new Argument(); + + Object obj =null; + <#list (resource.scoreCardVars)! as scoreCardVar> + <#if 'NUMBER_RANGE'==(scoreCardVar.type)! || 'INDICATOR_NUMBER_RANGE'==(scoreCardVar.type)! || 'INDICATOR_VALUE'==(scoreCardVar.type)!> + obj =DataTypeConvertor.convert(map.get("${scoreCardVar.code}"),BigDecimal.class);if(obj!=null){argument.${CodeReplacer.fieldName(scoreCardVar.code)} =obj;}//${scoreCardVar.name} + <#elseif 'OPTION'==(scoreCardVar.type)! || 'INDICATOR_OPTION'==(scoreCardVar.type)!> + obj =DataTypeConvertor.convert(map.get("${scoreCardVar.code}"),String.class);if(obj!=null){argument.${CodeReplacer.fieldName(scoreCardVar.code)} =obj;}//${scoreCardVar.name} + + + return argument; + } + return null; + } + + <#-- 参数转换(json) --> + public static Argument convertArgument(String json){ + if(json!=null && !"".equals(json.trim())){ + return JacksonObjectMapper.getDefaultObjectMapper().readValue(json, Argument.class); + } + return null; + } + + public void validate(ValidateResult result) { + + } + + public void mergeParameterValueFromIndicatorLib(Map libs){ + <#list (resource.scoreCardVars)! as scoreCardVar> + <#if 'INDICATOR_OPTION'==(scoreCardVar.type)! || 'INDICATOR_NUMBER_RANGE'==(scoreCardVar.type)! || 'INDICATOR_VALUE'==(scoreCardVar.type)!> + <#-- 如果直接给模型参数(类型为指标)设置过非空值,则直接采用设置过的值,否则采用指标库计算结果值 --> + <#if $wrapper.isExecuteTestCase> + if(this.${CodeReplacer.fieldName(scoreCardVar.code)}==null){this.${CodeReplacer.fieldName(scoreCardVar.code)} =libs.get("${scoreCardVar.libCode}_${scoreCardVar.libVersion}").${CodeReplacer.fieldName(scoreCardVar.indicatorCode)};}//${scoreCardVar.name} + <#else> + this.${CodeReplacer.fieldName(scoreCardVar.code)} =libs.get("${scoreCardVar.libCode}_${scoreCardVar.libVersion}").${CodeReplacer.fieldName(scoreCardVar.indicatorCode)};//${scoreCardVar.name} + + + + } + + public ResourceResult toResult(){ + ResourceResult resourceResult =new ResourceResult(); + + <#list (resource.scoreCardVars)! as scoreCardVar> + resourceResult.addParameterResult(new ParameterResult("R_${scoreCardVar.code}","""${scoreCardVar.name}""",ParameterType.OUT,"java.math.BigDecimal",this.R_${scoreCardVar.code}==null?null:this.R_${scoreCardVar.code}.toString())); + + + resourceResult.addParameterResult(new ParameterResult("_SCORE_","最终得分",ParameterType.OUT,"java.math.BigDecimal",this._SCORE_==null?null:this._SCORE_.toString())); + return resourceResult; + } + + public Map toMap(){ + Map map =new HashMap(); + + <#list (resource.scoreCardVars)! as scoreCardVar> + map.put("${scoreCardVar.code}",this.${scoreCardVar.code}); + + + <#list (resource.scoreCardVars)! as scoreCardVar> + map.put("R_${scoreCardVar.code}",this.R_${scoreCardVar.code}); + + + map.put("_SCORE_",this._SCORE_); + return map; + } +} \ No newline at end of file diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/scorecard/score_card.ftl b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/scorecard/score_card.ftl new file mode 100644 index 00000000..8d9c8cc0 --- /dev/null +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/scorecard/score_card.ftl @@ -0,0 +1,147 @@ +/** + * 资源类(name:${resource.name}, code:${resource.code}, version:${resource.version}) + * ${(resource.description)!} + * @author auto generated by engine + */ +class ${CodeReplacer.className(resource.code)}_V${resource.version}{ + private static final Logger log =LoggerFactory.getLogger(${CodeReplacer.className(resource.code)}_V${resource.version}.class); + + /** + * 执行方法(Map作为输入参数,该 Map 封装了调用模型的参数) + * @param map 输入参数封装器 + * @return 执行结果 + */ + public static ResourceResult execute(Map map) throws Exception{ + return execute(map["executor"],map["subModelCode"],map["argument"]); + } + + <#-- 执行方法(Map作为输入参数) --> + /** + * 执行方法 + * @param executor 执行器对象 + * @param subModelCode 子模型代码 + * @param data 输入参数 + * @return 执行结果 + */ + public static ResourceResult execute(Executor executor,String subModelCode,Object data) throws Exception{ + if(log.isDebugEnabled()){log.debug("开始执行评分卡 : ${resource.name}_${resource.version}");} + if(data instanceof Map){ + if(log.isDebugEnabled()){log.debug("显示输入参数(Map)=================================================\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(data));} + }else if(data instanceof String){ + if(log.isDebugEnabled()){log.debug("显示输入参数(Json字符串)=================================================\n{}",data);} + } + + <#list ($wrapper.libs)! as lib> + //初始化指标库[name:${lib.name}, code:${lib.code}, version:${lib.version}] + if(log.isDebugEnabled()){log.debug("初始化指标库 : ${lib.name}_${lib.version}");} + ${CodeReplacer.className(lib.code,lib.version)} ${CodeReplacer.varName(lib.code,lib.version)} =new ${CodeReplacer.className(lib.code,lib.version)}(); + ${CodeReplacer.varName(lib.code,lib.version)}.convertArgument(data); + + + //初始化评分卡变量 + if(log.isDebugEnabled()){log.debug("初始化评分卡变量");} + Argument argument =Argument.convertArgument(data); + + //输入参数合法性检查(指标库) + ValidateResult validateResult =new ValidateResult(); + <#list ($wrapper.libs)! as lib> + if(log.isDebugEnabled()){log.debug("开始检查输入参数数据合法性(指标库: ${lib.name}_${lib.version})");} + ${CodeReplacer.varName(lib.code,lib.version)}.validate(validateResult); + if(validateResult.hasError()){ + if(log.isDebugEnabled()){log.debug("\t检查结果: 失败!");} + ResourceResult result =new ResourceResult(); + result.setValidateResult(validateResult); + return result; + } + if(log.isDebugEnabled()){log.debug("\t检查结果: 成功!");} + + + //输入参数合法性检查(评分卡) + if(log.isDebugEnabled()){log.debug("开始检查评分卡输入参数数据合法性");} + argument.validate(validateResult); + if(validateResult.hasError()){ + if(log.isDebugEnabled()){log.debug("\t检查结果: 失败!");} + ResourceResult result =new ResourceResult(); + result.setValidateResult(validateResult); + return result; + } + if(log.isDebugEnabled()){log.debug("\t检查结果: 成功!");} + + //执行指标库 + <#if $wrapper.isExecuteTestCase> + <#else> + <#list ($wrapper.libs)! as lib> + if(log.isDebugEnabled()){log.debug("开始执行指标库: ${lib.name}_${lib.version}");} + ${CodeReplacer.varName(lib.code,lib.version)}.execute(); + + + + //合并指标库指标 + if(log.isDebugEnabled()){log.debug("开始合并指标库指标");} + Map indicatorLibs =new HashMap(); + <#list ($wrapper.libs)! as lib> + indicatorLibs.put("${lib.code}_${lib.version}",${CodeReplacer.varName(lib.code,lib.version)}); + + argument.mergeParameterValueFromIndicatorLib(indicatorLibs); + if(log.isDebugEnabled()){log.debug("显示合并后输入参数:\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(argument));} + + //调用评分卡 + ${CodeReplacer.fieldName(resource.code)}(executor,argument);//调用评分卡(${resource.name}) + + //返回结果 + ResourceResult result =argument.toResult(); + if(log.isDebugEnabled()){log.debug("评分卡调用成功,返回结果:\n{}",JacksonObjectMapper.getDefaultObjectMapper().writeValueAsString(result));} + return result; + } + + //${resource.name} + public static void ${CodeReplacer.fieldName(resource.code)}(Executor executor,Argument ${ExpressionReplacer.ARGUMENT_NAME}){ + if(log.isDebugEnabled()){log.debug("开始调用评分卡: {}","${resource.name}");} + <#list (resource.scoreCardVars)! as scoreCardVar> + //${scoreCardVar.name} + ${CodeReplacer.fieldName(scoreCardVar.code)}(executor,${ExpressionReplacer.ARGUMENT_NAME}); + + + //计算最终得分 + ${ExpressionReplacer.ARGUMENT_NAME}._SCORE_ =0; + <#list (resource.scoreCardVars)! as scoreCardVar> + ${ExpressionReplacer.ARGUMENT_NAME}._SCORE_ +=${ExpressionReplacer.ARGUMENT_NAME}.R_${scoreCardVar.code}==null?0:${ExpressionReplacer.ARGUMENT_NAME}.R_${scoreCardVar.code}; + + if(log.isDebugEnabled()){log.debug("评分卡结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}._SCORE_);} + } + + <#list (resource.scoreCardVars)! as scoreCardVar> + //计算评分卡变量得分(${scoreCardVar.name}) + public static void ${CodeReplacer.fieldName(scoreCardVar.code)}(Executor executor,Argument arg){ + <#if "OPTION"==(scoreCardVar.type)! || "INDICATOR_OPTION"==(scoreCardVar.type)!> + //选项 + if(log.isDebugEnabled()){log.debug(" {}","${scoreCardVar.name}(OUT)");} + ${Option.generateGroovyCode(scoreCardVar)} + if(log.isDebugEnabled()){log.debug(" 选项运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.R_${scoreCardVar.code});} + <#elseif "NUMBER_RANGE"==(scoreCardVar.type)! || "INDICATOR_NUMBER_RANGE"==(scoreCardVar.type)!> + //数值分段函数 + if(log.isDebugEnabled()){log.debug(" {}","${scoreCardVar.name}(OUT)");} + ${NumberRange.generateGroovyCode(scoreCardVar)} + if(log.isDebugEnabled()){log.debug(" 数值分段函数运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.R_${scoreCardVar.code});} + <#elseif "INDICATOR_VALUE"==(scoreCardVar.type)!> + //指标值 + if(log.isDebugEnabled()){log.debug(" {}","${scoreCardVar.name}(OUT)");} + ${ExpressionReplacer.ARGUMENT_NAME}.R_${CodeReplacer.fieldName(scoreCardVar.code)} =${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(scoreCardVar.code)}; + if(log.isDebugEnabled()){log.debug(" 指标值运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.R_${CodeReplacer.fieldName(scoreCardVar.code)});} + + } + + +} + +<#-- 参数类 --> +<#include "/scorecard/argument.ftl"/> + +<#-- 库类 --> +<#include "/lib/lib.ftl"/> + +<#-- 数据字典类 --> +<#include "/dictionary/dictionary.ftl"/> + +//执行并返回 +${CodeReplacer.className(resource.code)}_V${resource.version}.execute(INPUT_PARAMETER); diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums.properties b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums.properties index 6a36f537..17e38544 100644 --- a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums.properties +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums.properties @@ -48,6 +48,7 @@ io.sc.engine.rule.core.enums.ParameterType.CONSTANT=Constant #================================================ io.sc.engine.rule.core.enums.ProcessorType.EMPTY=Empty io.sc.engine.rule.core.enums.ProcessorType.OPTION_VALUE=Option Value +io.sc.engine.rule.core.enums.ProcessorType.MATH_FORMULA=Math Formula io.sc.engine.rule.core.enums.ProcessorType.ARITHMETIC=Arithmetic io.sc.engine.rule.core.enums.ProcessorType.TERNARY=Ternary io.sc.engine.rule.core.enums.ProcessorType.WHEN_THEN=When-Then @@ -88,6 +89,7 @@ io.sc.engine.rule.core.enums.HttpAuthorizationType.BEARER=Bearer Token # \u53C2\u6570\u5904\u7406\u5668\u7C7B\u578B\u679A\u4E3E #================================================ io.sc.engine.rule.core.enums.ParameterProcessorType.optionParameterCode=Option Value +io.sc.engine.rule.core.enums.ParameterProcessorType.MATH_FORMULA=Math Formula io.sc.engine.rule.core.enums.ParameterProcessorType.ARITHMETIC=Arithmetic io.sc.engine.rule.core.enums.ParameterProcessorType.TERNARY=Ternary io.sc.engine.rule.core.enums.ParameterProcessorType.WHEN_THEN=When-Then diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_tw_CN.properties b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_tw_CN.properties index 63b9c127..af197559 100644 --- a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_tw_CN.properties +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_tw_CN.properties @@ -48,6 +48,7 @@ io.sc.engine.rule.core.enums.ParameterType.CONSTANT=\u5E38\u91CF #================================================ io.sc.engine.rule.core.enums.ProcessorType.EMPTY=\u7A7A io.sc.engine.rule.core.enums.ProcessorType.OPTION_VALUE=\u9078\u9805\u503C +io.sc.engine.rule.core.enums.ProcessorType.MATH_FORMULA=\u6578\u5B78\u516C\u5F0F io.sc.engine.rule.core.enums.ProcessorType.ARITHMETIC=\u7B97\u6578\u904B\u7B97 io.sc.engine.rule.core.enums.ProcessorType.TERNARY=\u4E09\u5143\u64CD\u4F5C io.sc.engine.rule.core.enums.ProcessorType.WHEN_THEN=When Then \u904B\u7B97 @@ -88,6 +89,7 @@ io.sc.engine.rule.core.enums.HttpAuthorizationType.BEARER=Bearer Token # \u53C2\u6570\u5904\u7406\u5668\u7C7B\u578B\u679A\u4E3E #================================================ io.sc.engine.rule.core.enums.ParameterProcessorType.OPTION_VALUE=\u9078\u9805\u503C +io.sc.engine.rule.core.enums.ParameterProcessorType.MATH_FORMULA=\u6578\u5B78\u516C\u5F0F io.sc.engine.rule.core.enums.ParameterProcessorType.ARITHMETIC=\u7B97\u6578\u904B\u7B97 io.sc.engine.rule.core.enums.ParameterProcessorType.TERNARY=\u4E09\u5143\u64CD\u4F5C io.sc.engine.rule.core.enums.ParameterProcessorType.WHEN_THEN=When Then \u904B\u7B97 diff --git a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_zh_CN.properties b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_zh_CN.properties index 95fc12d5..3e674820 100644 --- a/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_zh_CN.properties +++ b/io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_zh_CN.properties @@ -48,6 +48,7 @@ io.sc.engine.rule.core.enums.ParameterType.CONSTANT=\u5E38\u91CF #================================================ io.sc.engine.rule.core.enums.ProcessorType.EMPTY=\u7A7A io.sc.engine.rule.core.enums.ProcessorType.OPTION_VALUE=\u9009\u9879\u503C +io.sc.engine.rule.core.enums.ProcessorType.MATH_FORMULA=\u6570\u5B66\u516C\u5F0F io.sc.engine.rule.core.enums.ProcessorType.ARITHMETIC=\u7B97\u6570\u8FD0\u7B97 io.sc.engine.rule.core.enums.ProcessorType.TERNARY=\u4E09\u5143\u64CD\u4F5C io.sc.engine.rule.core.enums.ProcessorType.WHEN_THEN=When Then \u8FD0\u7B97 @@ -88,6 +89,7 @@ io.sc.engine.rule.core.enums.HttpAuthorizationType.BEARER=Bearer Token # \u53C2\u6570\u5904\u7406\u5668\u7C7B\u578B\u679A\u4E3E #================================================ io.sc.engine.rule.core.enums.ParameterProcessorType.OPTION_VALUE=\u9009\u9879\u503C +io.sc.engine.rule.core.enums.ParameterProcessorType.MATH_FORMULA=\u6570\u5B66\u516C\u5F0F io.sc.engine.rule.core.enums.ParameterProcessorType.ARITHMETIC=\u7B97\u6570\u8FD0\u7B97 io.sc.engine.rule.core.enums.ParameterProcessorType.TERNARY=\u4E09\u5143\u64CD\u4F5C io.sc.engine.rule.core.enums.ParameterProcessorType.WHEN_THEN=When Then \u8FD0\u7B97 diff --git a/io.sc.engine.rule.frontend/package.json b/io.sc.engine.rule.frontend/package.json index 7ff4026a..03a2a184 100644 --- a/io.sc.engine.rule.frontend/package.json +++ b/io.sc.engine.rule.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.245", + "platform-core": "8.1.248", "quasar": "2.15.3", "tailwindcss": "3.4.3", "vue": "3.4.24", diff --git a/io.sc.engine.rule.frontend/src/components/index.ts b/io.sc.engine.rule.frontend/src/components/index.ts index aaa5a5c6..5392c01b 100644 --- a/io.sc.engine.rule.frontend/src/components/index.ts +++ b/io.sc.engine.rule.frontend/src/components/index.ts @@ -3,6 +3,7 @@ */ import component_engine_rule_resources from '@/views/resources/Resources.vue'; +import component_engine_rule_designer from '@/views/resources/designer/Designer.vue'; import component_engine_rule_authorization from '@/views/authorization/Authorization.vue'; import component_engine_rule_workflow from '@/views/workflow/Workflow.vue'; import component_engine_rule_dictionary from '@/views/dictionary/Dictionary.vue'; @@ -12,6 +13,7 @@ import component_engine_rule_migration from '@/views/migration/Migration.vue'; const localComponents = { 'component.engine.rule.resources': component_engine_rule_resources, + 'component.engine.rule.designer': component_engine_rule_designer, 'component.engine.rule.authorization': component_engine_rule_authorization, 'component.engine.rule.workflow': component_engine_rule_workflow, 'component.engine.rule.dictionary': component_engine_rule_dictionary, diff --git a/io.sc.engine.rule.frontend/src/i18n/messages.json b/io.sc.engine.rule.frontend/src/i18n/messages.json index 144c7616..556d376f 100644 --- a/io.sc.engine.rule.frontend/src/i18n/messages.json +++ b/io.sc.engine.rule.frontend/src/i18n/messages.json @@ -1,20 +1,20 @@ { "menu.engine.rule":"Rule Engine", - "menu.engine.rule.resources": "Resources Manager", + "menu.engine.rule.resources": "Model Manager", "menu.engine.rule.authorization": "Authorization Manager", "menu.engine.rule.workflow": "Workflow", "menu.engine.rule.dictionary": "Meta Data Manager", "menu.engine.rule.lib": "Feature Library Manager", "menu.engine.rule.testcase": "Test Case Manager", - "menu.engine.rule.migration": "Migration", + "menu.engine.rule.migration": "Data Back and Migration", - "re.resources.grid.title": "Resources", + "re.resources.grid.title": "Model", "re.resources.grid.toolbar.addTop": "Top Folder", "re.resources.grid.toolbar.addChild": "Child Folder", "re.resources.grid.toolbar.addModel": "Model", "re.resources.grid.toolbar.addScoreCard": "Score Card", "re.resources.grid.toolbar.deepClone.tip": "Are you sure to deep clone the resource?", - "re.resources.grid.toolbar.deepCloneNew": "Deep Clone(New Resource)", + "re.resources.grid.toolbar.deepCloneNew": "Deep Clone(new)", "re.resources.grid.toolbar.deepCloneNew.tip": "Are you sure to deep clone the resource as new resource?", "re.resources.grid.toolbar.design": "View/Design", "re.resources.grid.toolbar.deploy.online":"Online", @@ -33,10 +33,11 @@ "re.resources.dialog.attachment.grid.entity.file": "Please select a file", "re.resources.designer.dialog.title": "Model Designer - {name} ({status},V{version})", - "re.resources.designer.model.grid.title": "Model Tree", + "re.resources.designer.model.grid.title": "Model Structure", "re.resources.designer.model.grid.toolbar.addChild": "Add Child Model", - "re.resources.designer.model.grid.toolbar.generateGroovySourceCode": "Generate Groovy Source Code", - "re.resources.designer.model.grid.toolbar.generateGroovySourceCode4TestCase": "Generate Groovy Source Code(Test Case)", + "re.resources.designer.model.grid.toolbar.deepClone.tip": "Are you sure to deep clone the model?", + "re.resources.designer.model.grid.toolbar.generateGroovySourceCode": "Generate Script Code", + "re.resources.designer.model.grid.toolbar.generateGroovySourceCode4TestCase": "Generate Script Code(Test Case)", "re.resources.designer.model.grid.entity.executeMode": "Execute Mode", "re.resources.designer.parameter.tab.title": "Parameter", @@ -56,6 +57,7 @@ "re.resources.designer.parameter.grid.toolbar.add.ruleResult": "Rule Output", "re.resources.designer.parameter.grid.toolbar.add.singleRuleResult": "Single Rule Output", "re.resources.designer.parameter.grid.toolbar.add.importPmml": "Import PMML", + "re.resources.designer.parameter.grid.toolbar.deepClone.tip": "Are you sure to deep clone the parameter?", "re.resources.designer.parameter.grid.entity.valueType": "Value Type", "re.resources.designer.parameter.grid.entity.valueTypeVersion": "Value Type Version", "re.resources.designer.parameter.grid.entity.valueScale": "Value Scale", @@ -91,7 +93,7 @@ "re.resources.designer.processor.grid.entity.pmml": "PMML", "re.resources.designer.processor.grid.entity.decisionTable2C": "Simple Decision Table", "re.resources.designer.processor.grid.entity.decisionTable": "Decision Table", - "re.resources.designer.processor.grid.entity.groovyScript": "Groovy Script", + "re.resources.designer.processor.grid.entity.groovyScript": "Script", "re.resources.designer.processor.grid.entity.sqlDatasourceName": "Datasource Name", "re.resources.designer.processor.grid.entity.sql": "SQL", "re.resources.designer.processor.grid.entity.sqlParameterValues": "Parameter Values", @@ -102,11 +104,14 @@ "re.resources.designer.processor.dialog.decisionTree.title": "Decision Tree Designer", "re.resources.designer.processor.dialog.executionFlow.title": "Execution Flow Designer", - "re.resources.designer.testCase.grid.title": "Test Case List", + "re.resources.designer.testCase.grid.title": "Test Cases", "re.resources.designer.testCase.grid.entity.testResult": "Result", "re.resources.designer.testCase.grid.entity.lastTestDate": "Test Date", + "re.resources.designer.testCase.grid.entity.ownerCode": "Resource Code", + "re.resources.designer.testCase.grid.entity.ownerName": "Resource Name", + "re.resources.designer.testCase.grid.entity.ownerVersion": "Resource Version", - "re.resources.designer.testCaseParameter.grid.title": "Test Case Parameter List", + "re.resources.designer.testCaseParameter.grid.title": "Parameter List", "re.resources.designer.testCaseParameter.grid.entity.inputValue": "Input Value", "re.resources.designer.testCaseParameter.grid.entity.expectValue": "Expect Value", "re.resources.designer.testCaseParameter.grid.entity.resultValue": "Result Value", @@ -120,7 +125,7 @@ "re.resources.importSample.grid.toolbar.import": "Import Sample", "re.resources.importSample.grid.toolbar.import.tip": "Are you sure to import the samples?", - "re.dictionary.grid.title": "Meta Data Tree", + "re.dictionary.grid.title": "Meta Data", "re.dictionary.grid.toolbar.addGroup": "Add New", "re.dictionary.grid.toolbar.addTop": "Top Folder", "re.dictionary.grid.toolbar.addChild": "Child Folder", @@ -130,7 +135,7 @@ "re.dictionary.grid.toolbar.cloneGroup": "Clone", "re.dictionary.grid.toolbar.deepClone": "Deep Clone", "re.dictionary.grid.toolbar.deepClone.tip": "Are you sure to deep clone the meta data?", - "re.dictionary.grid.toolbar.deepCloneNew": "Deep Clone (New Meta Data)", + "re.dictionary.grid.toolbar.deepCloneNew": "Deep Clone (new)", "re.dictionary.grid.toolbar.deepCloneNew.tip": "Are you sure to deep clone the meta data as a new meta data?", "re.dictionary.grid.toolbar.generateJson": "Generate JSON", "re.dictionary.grid.toolbar.deploy": "Deploy", @@ -165,9 +170,9 @@ "re.lib.grid.toolbar.cloneGroup": "Clone", "re.lib.grid.toolbar.deepClone": "Deep Clone", "re.lib.grid.toolbar.deepClone.tip": "Are you sure to clone the Feature Library?", - "re.lib.grid.toolbar.deepCloneNew": "Deep Clone (New Feature Library)", + "re.lib.grid.toolbar.deepCloneNew": "Deep Clone (new)", "re.lib.grid.toolbar.deepCloneNew.tip": "Are you sure to clone the feature library as a new feature library?", - "re.lib.grid.toolbar.generateGroovy": "Generate Groovy Code", + "re.lib.grid.toolbar.generateGroovy": "Generate Script Code", "re.lib.grid.toolbar.deploy": "Deploy", "re.lib.grid.toolbar.deploy.tip": "Are you sure to deploy the Feature Library?", "re.lib.grid.toolbar.importGroup": "Import", @@ -177,6 +182,9 @@ "re.lib.tab.indicator.title": "Feature", "re.lib.tab.testcase.title": "Test Case", + "re.indicator.grid.toolbar.addInterface": "Interface", + "re.indicator.grid.toolbar.addIndicator": "Indicator", + "re.migration.import.title":"Import ( From The File Uploaded )", "re.migration.import.subTitle":"", "re.migration.import.action":"Import", diff --git a/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json b/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json index ec1c61e1..4bc539fa 100644 --- a/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json +++ b/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json @@ -1,20 +1,20 @@ { "menu.engine.rule":"規則引擎", - "menu.engine.rule.resources": "資源管理", + "menu.engine.rule.resources": "模型管理", "menu.engine.rule.authorization": "權限管理", "menu.engine.rule.workflow": "流程審批", "menu.engine.rule.dictionary": "元數據管理", "menu.engine.rule.lib": "特征庫管理", - "menu.engine.rule.testcase": "測試用例", - "menu.engine.rule.migration": "數據遷移", + "menu.engine.rule.testcase": "試算用例", + "menu.engine.rule.migration": "數據備份和遷移", - "re.resources.grid.title": "資源樹", + "re.resources.grid.title": "模型", "re.resources.grid.toolbar.addTop": "頂級文件夾", "re.resources.grid.toolbar.addChild": "子文件夾", "re.resources.grid.toolbar.addModel": "模型", "re.resources.grid.toolbar.addScoreCard": "評分卡", "re.resources.grid.toolbar.deepClone.tip": "您確定要深度複製資源嗎?", - "re.resources.grid.toolbar.deepCloneNew": "深度複製(新資源)", + "re.resources.grid.toolbar.deepCloneNew": "深度複製(新)", "re.resources.grid.toolbar.deepCloneNew.tip": "您確定要深度複製資源成一個新的資源嗎?", "re.resources.grid.toolbar.design": "查看/設計", "re.resources.grid.toolbar.deploy.online":"上線", @@ -33,16 +33,17 @@ "re.resources.dialog.attachment.grid.entity.file": "請選擇一個文件", "re.resources.designer.dialog.title": "模型設計 - {name} ({status},V{version})", - "re.resources.designer.model.grid.title": "模型結構樹", + "re.resources.designer.model.grid.title": "模型結構", "re.resources.designer.model.grid.toolbar.addChild": "添加子模型", - "re.resources.designer.model.grid.toolbar.generateGroovySourceCode": "生成 Groovy 代碼", - "re.resources.designer.model.grid.toolbar.generateGroovySourceCode4TestCase": "生成 Groovy 代碼(測試用例)", + "re.resources.designer.model.grid.toolbar.deepClone.tip": "您確定要深度複製模型嗎?", + "re.resources.designer.model.grid.toolbar.generateGroovySourceCode": "生成腳本代碼", + "re.resources.designer.model.grid.toolbar.generateGroovySourceCode4TestCase": "生成腳本代碼(測試用例)", "re.resources.designer.model.grid.entity.executeMode": "執行模式", "re.resources.designer.parameter.tab.title": "參數", "re.resources.designer.testcase.tab.title": "測試用例", "re.resources.designer.validator.tab.title": "驗證器", - "re.resources.designer.processor.tab.title": "處理器", + "re.resources.designer.processor.tab.title": "處理邏輯", "re.resources.designer.option.tab.title": "選項", "re.resources.designer.parameter.grid.title": "參數列表", @@ -56,6 +57,7 @@ "re.resources.designer.parameter.grid.toolbar.add.ruleResult": "規則結果值", "re.resources.designer.parameter.grid.toolbar.add.singleRuleResult": "單規則結果值", "re.resources.designer.parameter.grid.toolbar.add.importPmml": "導入 PMML", + "re.resources.designer.parameter.grid.toolbar.deepClone.tip": "您確定要深度複製參數嗎?", "re.resources.designer.parameter.grid.entity.valueType": "值類型", "re.resources.designer.parameter.grid.entity.valueTypeVersion": "值類型版本", "re.resources.designer.parameter.grid.entity.valueScale": "值精度", @@ -74,7 +76,7 @@ "re.resources.designer.option.grid.entity.value": "計算值", "re.resources.designer.option.grid.entity.title": "顯示文本", - "re.resources.designer.processor.grid.title": "處理器", + "re.resources.designer.processor.grid.title": "處理邏輯", "re.resources.designer.processor.grid.entity.content": "內容", "re.resources.designer.processor.grid.entity.optionCode": "選項", "re.resources.designer.processor.grid.entity.arithmetic": "算數表達式", @@ -83,7 +85,7 @@ "re.resources.designer.processor.grid.entity.ternaryFalse": "條件不滿足時", "re.resources.designer.processor.grid.entity.when": "When 表達式", "re.resources.designer.processor.grid.entity.then": "Then 表達式", - "re.resources.designer.processor.grid.entity.isWhenThenShorted": "短路操作", + "re.resources.designer.processor.grid.entity.isWhenThenShorted": "跳過後續操作", "re.resources.designer.processor.grid.entity.numberRangeVar": "數值分段表達式", "re.resources.designer.processor.grid.entity.numberRange": "數值分段", "re.resources.designer.processor.grid.entity.conditionRangeVar": "條件分段", @@ -102,16 +104,19 @@ "re.resources.designer.processor.dialog.decisionTree.title": "決策樹設計器", "re.resources.designer.processor.dialog.executionFlow.title": "執行流設計器", - "re.resources.designer.testCase.grid.title": "測試用例列表", - "re.resources.designer.testCase.grid.entity.testResult": "測試結果", + "re.resources.designer.testCase.grid.title": "試算用例", + "re.resources.designer.testCase.grid.entity.testResult": "結果", "re.resources.designer.testCase.grid.entity.lastTestDate": "測試日期", + "re.resources.designer.testCase.grid.entity.ownerCode": "資源代碼", + "re.resources.designer.testCase.grid.entity.ownerName": "資源名稱", + "re.resources.designer.testCase.grid.entity.ownerVersion": "資源版本", - "re.resources.designer.testCaseParameter.grid.title": "測試用例參數列表", + "re.resources.designer.testCaseParameter.grid.title": "參數列表", "re.resources.designer.testCaseParameter.grid.entity.inputValue": "輸入值", "re.resources.designer.testCaseParameter.grid.entity.expectValue": "期望值", "re.resources.designer.testCaseParameter.grid.entity.resultValue": "結果值", "re.resources.designer.testCaseParameter.grid.entity.skipCheck": "跳過檢查", - "re.resources.designer.testCaseParameter.grid.entity.testResult": "測試結果", + "re.resources.designer.testCaseParameter.grid.entity.testResult": "結果", "re.resources.import.dialog.title": "導入資源", @@ -120,7 +125,7 @@ "re.resources.importSample.grid.toolbar.import": "導入示例", "re.resources.importSample.grid.toolbar.import.tip": "您確定要導入示例資源嗎?", - "re.dictionary.grid.title": "元數據樹", + "re.dictionary.grid.title": "元數據", "re.dictionary.grid.toolbar.addGroup": "新增", "re.dictionary.grid.toolbar.addTop": "頂級文件夾", "re.dictionary.grid.toolbar.addChild": "子文件夾", @@ -130,7 +135,7 @@ "re.dictionary.grid.toolbar.cloneGroup": "複製", "re.dictionary.grid.toolbar.deepClone": "深度複製", "re.dictionary.grid.toolbar.deepClone.tip": "您確定要深度複製元數據嗎?", - "re.dictionary.grid.toolbar.deepCloneNew": "深度復製(新元數據)", + "re.dictionary.grid.toolbar.deepCloneNew": "深度復製(新)", "re.dictionary.grid.toolbar.deepCloneNew.tip": "您確定要深度複製元數據成一個新的元數據嗎?", "re.dictionary.grid.toolbar.generateJson": "生成示例 JSON", "re.dictionary.grid.toolbar.deploy": "發佈", @@ -141,7 +146,7 @@ "re.dictionary.grid.entity.javaClassName": "Java 類全路徑名稱", - "re.dictionary.field.grid.title": "字段列表", + "re.dictionary.field.grid.title": "字段集", "re.dictionary.field.grid.entity.valueType": "值類型", "re.dictionary.field.grid.entity.valueTypeIsList": "是否列表", "re.dictionary.field.grid.entity.valueCalculation": "值計算公式", @@ -157,7 +162,7 @@ "re.dictionary.importSample.grid.toolbar.import": "導入示例", "re.dictionary.importSample.grid.toolbar.import.tip": "您確定要導入示例元數據嗎?", - "re.lib.grid.title": "特征庫樹", + "re.lib.grid.title": "特征庫", "re.lib.grid.toolbar.addGroup": "新增", "re.lib.grid.toolbar.addTop": "頂級文件夾", "re.lib.grid.toolbar.addChild": "子文件夾", @@ -165,9 +170,9 @@ "re.lib.grid.toolbar.cloneGroup": "複製", "re.lib.grid.toolbar.deepClone": "深度複製", "re.lib.grid.toolbar.deepClone.tip": "您確定要深度複製特征庫嗎?", - "re.lib.grid.toolbar.deepCloneNew": "深度複製(新特征庫)", + "re.lib.grid.toolbar.deepCloneNew": "深度複製(新)", "re.lib.grid.toolbar.deepCloneNew.tip": "您確定要深度複製特征庫成一個新的特征庫嗎?", - "re.lib.grid.toolbar.generateGroovy": "生成 Groovy 源代碼", + "re.lib.grid.toolbar.generateGroovy": "生成腳本源代碼", "re.lib.grid.toolbar.deploy": "發佈", "re.lib.grid.toolbar.deploy.tip": "您確定要發佈特征庫嗎?", "re.lib.grid.toolbar.importGroup": "導入", @@ -177,6 +182,9 @@ "re.lib.tab.indicator.title": "特征", "re.lib.tab.testcase.title": "測試用例", + "re.indicator.grid.toolbar.addInterface": "接口", + "re.indicator.grid.toolbar.addIndicator": "指標", + "re.migration.import.title":"導入數據 (通過上傳文件導入)", "re.migration.import.subTitle":"", "re.migration.import.action":"導入數據", diff --git a/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json b/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json index 6469dfb6..b1a9a61a 100644 --- a/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json +++ b/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json @@ -1,20 +1,20 @@ { "menu.engine.rule":"规则引擎", - "menu.engine.rule.resources": "资源管理", + "menu.engine.rule.resources": "模型管理", "menu.engine.rule.authorization": "权限管理", "menu.engine.rule.workflow": "流程审批", "menu.engine.rule.dictionary": "元数据管理", "menu.engine.rule.lib": "特征库管理", - "menu.engine.rule.testcase": "测试用例管理", - "menu.engine.rule.migration": "数据迁移", + "menu.engine.rule.testcase": "试算用例管理", + "menu.engine.rule.migration": "数据备份和迁移", - "re.resources.grid.title": "资源树", + "re.resources.grid.title": "模型", "re.resources.grid.toolbar.addTop": "顶级文件夹", "re.resources.grid.toolbar.addChild": "子文件夹", "re.resources.grid.toolbar.addModel": "模型", "re.resources.grid.toolbar.addScoreCard": "评分卡", "re.resources.grid.toolbar.deepClone.tip": "您确定要深度复制资源吗?", - "re.resources.grid.toolbar.deepCloneNew": "深度复制(新资源)", + "re.resources.grid.toolbar.deepCloneNew": "深度复制(新)", "re.resources.grid.toolbar.deepCloneNew.tip": "您确定要深度复制资源成一个新的资源吗?", "re.resources.grid.toolbar.design": "查看/设计", "re.resources.grid.toolbar.deploy.online":"上线", @@ -33,16 +33,17 @@ "re.resources.dialog.attachment.grid.entity.file": "请选择一个文件", "re.resources.designer.dialog.title": "模型设计 - {name} ({status},V{version})", - "re.resources.designer.model.grid.title": "模型结构树", + "re.resources.designer.model.grid.title": "模型结构", "re.resources.designer.model.grid.toolbar.addChild": "添加子模型", - "re.resources.designer.model.grid.toolbar.generateGroovySourceCode": "生成 Groovy 代码", - "re.resources.designer.model.grid.toolbar.generateGroovySourceCode4TestCase": "生成 Groovy 代码(测试用例)", + "re.resources.designer.model.grid.toolbar.deepClone.tip": "您确定要深度复制模型吗?", + "re.resources.designer.model.grid.toolbar.generateGroovySourceCode": "生成脚本代码", + "re.resources.designer.model.grid.toolbar.generateGroovySourceCode4TestCase": "生成脚本代码(测试用例)", "re.resources.designer.model.grid.entity.executeMode": "执行模式", "re.resources.designer.parameter.tab.title": "参数", "re.resources.designer.testcase.tab.title": "测试用例", "re.resources.designer.validator.tab.title": "验证器", - "re.resources.designer.processor.tab.title": "处理器", + "re.resources.designer.processor.tab.title": "处理逻辑", "re.resources.designer.option.tab.title": "选项", "re.resources.designer.parameter.grid.title": "参数列表", @@ -56,6 +57,7 @@ "re.resources.designer.parameter.grid.toolbar.add.ruleResult": "规则结果值", "re.resources.designer.parameter.grid.toolbar.add.singleRuleResult": "单规则结果值", "re.resources.designer.parameter.grid.toolbar.add.importPmml": "导入 PMML", + "re.resources.designer.parameter.grid.toolbar.deepClone.tip": "您确定要深度复制参数吗?", "re.resources.designer.parameter.grid.entity.valueType": "值类型", "re.resources.designer.parameter.grid.entity.valueTypeVersion": "值类型版本", "re.resources.designer.parameter.grid.entity.valueScale": "值精度", @@ -74,7 +76,7 @@ "re.resources.designer.option.grid.entity.value": "计算值", "re.resources.designer.option.grid.entity.title": "显示文本", - "re.resources.designer.processor.grid.title": "处理器", + "re.resources.designer.processor.grid.title": "处理逻辑", "re.resources.designer.processor.grid.entity.content": "内容", "re.resources.designer.processor.grid.entity.optionCode": "选项", "re.resources.designer.processor.grid.entity.arithmetic": "算数表达式", @@ -83,7 +85,7 @@ "re.resources.designer.processor.grid.entity.ternaryFalse": "条件不满足时", "re.resources.designer.processor.grid.entity.when": "When 表达式", "re.resources.designer.processor.grid.entity.then": "Then 表达式", - "re.resources.designer.processor.grid.entity.isWhenThenShorted": "短路操作", + "re.resources.designer.processor.grid.entity.isWhenThenShorted": "跳过后续操作", "re.resources.designer.processor.grid.entity.numberRangeVar": "数值分段表达式", "re.resources.designer.processor.grid.entity.numberRange": "数值分段", "re.resources.designer.processor.grid.entity.conditionRangeVar": "条件分段", @@ -102,16 +104,19 @@ "re.resources.designer.processor.dialog.decisionTree.title": "决策树设计器", "re.resources.designer.processor.dialog.executionFlow.title": "执行流设计器", - "re.resources.designer.testCase.grid.title": "测试用例列表", - "re.resources.designer.testCase.grid.entity.testResult": "测试结果", + "re.resources.designer.testCase.grid.title": "试算用例", + "re.resources.designer.testCase.grid.entity.testResult": "结果", "re.resources.designer.testCase.grid.entity.lastTestDate": "测试日期", + "re.resources.designer.testCase.grid.entity.ownerCode": "资源代码", + "re.resources.designer.testCase.grid.entity.ownerName": "资源名称", + "re.resources.designer.testCase.grid.entity.ownerVersion": "资源版本", - "re.resources.designer.testCaseParameter.grid.title": "测试用例参数列表", + "re.resources.designer.testCaseParameter.grid.title": "参数列表", "re.resources.designer.testCaseParameter.grid.entity.inputValue": "输入值", "re.resources.designer.testCaseParameter.grid.entity.expectValue": "期望值", "re.resources.designer.testCaseParameter.grid.entity.resultValue": "结果值", "re.resources.designer.testCaseParameter.grid.entity.skipCheck": "跳过检查", - "re.resources.designer.testCaseParameter.grid.entity.testResult": "测试结果", + "re.resources.designer.testCaseParameter.grid.entity.testResult": "结果", "re.resources.import.dialog.title": "导入资源", @@ -120,7 +125,7 @@ "re.resources.importSample.grid.toolbar.import": "导入示例", "re.resources.importSample.grid.toolbar.import.tip": "您确定要导入示例资源吗?", - "re.dictionary.grid.title": "元数据树", + "re.dictionary.grid.title": "元数据", "re.dictionary.grid.toolbar.addGroup": "新增", "re.dictionary.grid.toolbar.addTop": "顶级文件夹", "re.dictionary.grid.toolbar.addChild": "子文件夹", @@ -130,7 +135,7 @@ "re.dictionary.grid.toolbar.cloneGroup": "复制", "re.dictionary.grid.toolbar.deepClone": "深度复制", "re.dictionary.grid.toolbar.deepClone.tip": "您确定要深度复制元数据吗?", - "re.dictionary.grid.toolbar.deepCloneNew": "深度复制(新元數據)", + "re.dictionary.grid.toolbar.deepCloneNew": "深度复制(新)", "re.dictionary.grid.toolbar.deepCloneNew.tip": "您确定要深度复制元数据成一个新的元数据吗?", "re.dictionary.grid.toolbar.generateJson": "生成示例 JSON", "re.dictionary.grid.toolbar.deploy": "发布", @@ -141,7 +146,7 @@ "re.dictionary.grid.entity.javaClassName": "Java 类全路径名称", - "re.dictionary.field.grid.title": "字段列表", + "re.dictionary.field.grid.title": "字段集", "re.dictionary.field.grid.entity.valueType": "值类型", "re.dictionary.field.grid.entity.valueTypeIsList": "是否列表", "re.dictionary.field.grid.entity.valueCalculation": "值计算公式", @@ -157,7 +162,7 @@ "re.dictionary.importSample.grid.toolbar.import": "导入示例", "re.dictionary.importSample.grid.toolbar.import.tip": "您确定要导入示例元数据吗?", - "re.lib.grid.title": "特征库树", + "re.lib.grid.title": "特征库", "re.lib.grid.toolbar.addGroup": "新增", "re.lib.grid.toolbar.addTop": "顶级文件夹", "re.lib.grid.toolbar.addChild": "子文件夹", @@ -165,9 +170,9 @@ "re.lib.grid.toolbar.cloneGroup": "复制", "re.lib.grid.toolbar.deepClone": "深度复制", "re.lib.grid.toolbar.deepClone.tip": "您确定要深度复制特征库吗?", - "re.lib.grid.toolbar.deepCloneNew": "深度复制(新特征库)", + "re.lib.grid.toolbar.deepCloneNew": "深度复制(新)", "re.lib.grid.toolbar.deepCloneNew.tip": "您确定要深度复制特征库成一个新的特征库吗?", - "re.lib.grid.toolbar.generateGroovy": "生成 Groovy 源代码", + "re.lib.grid.toolbar.generateGroovy": "生成脚本源代码", "re.lib.grid.toolbar.deploy": "发布", "re.lib.grid.toolbar.deploy.tip": "您确定要发布特征库吗?", "re.lib.grid.toolbar.importGroup": "导入", @@ -177,6 +182,9 @@ "re.lib.tab.indicator.title": "特征", "re.lib.tab.testcase.title": "测试用例", + "re.indicator.grid.toolbar.addInterface": "接口", + "re.indicator.grid.toolbar.addIndicator": "指标", + "re.migration.import.title":"导入数据 (通过上传文件导入)", "re.migration.import.subTitle":"", "re.migration.import.action":"导入数据", diff --git a/io.sc.engine.rule.frontend/src/routes/routes.json b/io.sc.engine.rule.frontend/src/routes/routes.json index c54ae39e..687bbe26 100644 --- a/io.sc.engine.rule.frontend/src/routes/routes.json +++ b/io.sc.engine.rule.frontend/src/routes/routes.json @@ -14,6 +14,22 @@ ] } }, + { + "force": true, + "name": "route.engine.rule.designer", + "path": "re/designer", + "parent": "/", + "priority": 0, + "module": "io.sc.engine.rule.frontend", + "component": "component.engine.rule.designer", + "componentPath": "@/views/resources/designer/Designer.vue", + "redirect": null, + "meta": { + "permissions": [ + "/re/resources/**/*" + ] + } + }, { "name": "route.engine.rule.authorization", "path": "re/authorization", diff --git a/io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue b/io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue index 54d9039f..826b6e33 100644 --- a/io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue +++ b/io.sc.engine.rule.frontend/src/views/authorization/Authorization.vue @@ -110,9 +110,20 @@ :columns="[ { width: '100%', name: 'name', label: $t('name') }, { width: 80, name: 'type', label: $t('type'), format: Formater.enum(Enums.ResourceType) }, - { width: 100, name: 'code', label: $t('code') }, + { width: 150, name: 'code', label: $t('code') }, { width: 60, name: 'version', label: $t('version') }, - { width: 60, name: 'status', label: $t('status'), format: Formater.enum(Enums.DeployStatus) }, + { + width: 80, + name: 'status', + label: $t('status'), + align: 'center', + format: (value, row) => { + return { + componentType: ResourceDeployStatusTag, + attrs: { status: value }, + }; + }, + }, ]" > @@ -122,6 +133,7 @@ diff --git a/io.sc.engine.rule.frontend/src/views/lib/LibGrid.vue b/io.sc.engine.rule.frontend/src/views/lib/LibGrid.vue index 64da93bc..05a2159e 100644 --- a/io.sc.engine.rule.frontend/src/views/lib/LibGrid.vue +++ b/io.sc.engine.rule.frontend/src/views/lib/LibGrid.vue @@ -138,7 +138,7 @@ }, click: (arg) => { DialogManager.confirm($t('re.lib.grid.toolbar.deploy.tip'), () => { - axios.post(Environment.apiContextPath('/api/re/lib/deploy/' + arg.selected.id)).then(() => { + axios.post(Environment.apiContextPath('/api/re/lib/deploy/' + arg.selected.id)).then((response) => { treeGridRef.refresh(); }); }); @@ -187,11 +187,13 @@ width: '100%', name: 'name', label: $t('name'), + sortable: false, }, { width: 80, name: 'type', label: $t('type'), + sortable: false, format: (value) => { if (value !== 'FOLDER') { return Formater.enum(Enums.LibType)(value); @@ -199,7 +201,19 @@ }, }, { width: 60, name: 'version', label: $t('version') }, - { width: 60, name: 'status', label: $t('status'), format: Formater.enum(Enums.DeployStatus) }, + { + width: 60, + name: 'status', + label: $t('status'), + align: 'center', + sortable: false, + format: (value, row) => { + return { + componentType: ResourceDeployStatusTag, + attrs: { status: value }, + }; + }, + }, ]" :editor="{ dialog: { @@ -228,19 +242,19 @@ panel: { columnNum: 1, fields: [ - { name: 'type', label: $t('type') }, + { name: 'order', label: $t('order') }, { name: 'id', label: $t('id') }, + { name: 'parent', label: $t('parent') }, + { name: 'type', label: $t('type') }, { name: 'code', label: $t('code') }, { name: 'name', label: $t('name') }, { name: 'description', label: $t('description') }, - { name: 'order', label: $t('order') }, { name: 'dataComeFrom', label: $t('dataComeFrom') }, { name: 'creator', label: $t('creator') }, { name: 'createDate', label: $t('createDate') }, { name: 'lastModifier', label: $t('lastModifier') }, { name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() }, - { name: 'corporationCode', label: $t('corporationCode') }, ], }, }" @@ -251,13 +265,16 @@ diff --git a/io.sc.engine.rule.frontend/src/views/resources/designer/Option.vue b/io.sc.engine.rule.frontend/src/views/resources/designer/Option.vue index d981738e..3094345c 100644 --- a/io.sc.engine.rule.frontend/src/views/resources/designer/Option.vue +++ b/io.sc.engine.rule.frontend/src/views/resources/designer/Option.vue @@ -7,13 +7,38 @@ hide-bottom :config-button="false" selection="multiple" - :checkbox-selection="false" + :checkbox-selection="true" :tree="false" :fetch-data-url="Environment.apiContextPath('/api/re/model/parameter/option/findByParameterId?parameterId=' + parameter.id)" :data-url="Environment.apiContextPath('/api/re/model/parameter/option')" :pageable="false" :toolbar-configure="{ noIcon: false }" - :toolbar-actions="['refresh', 'separator', 'add', 'edit', 'remove', 'separator', 'view', 'separator', 'export']" + :toolbar-actions="[ + 'refresh', + 'separator', + { + extend: 'add', + enableIf: (arg) => { + return !readOnly; + }, + }, + { + extend: 'edit', + enableIf: (arg) => { + return !readOnly && arg.selected; + }, + }, + { + extend: 'remove', + enableIf: (arg) => { + return !readOnly && arg.selected; + }, + }, + 'separator', + 'view', + 'separator', + 'export', + ]" :columns="[ { width: 60, name: 'order', label: $t('order'), sortable: false, align: 'right' }, { width: 100, name: 'inputValue', label: $t('re.resources.designer.option.grid.entity.inputValue'), sortable: false }, @@ -85,6 +110,7 @@ const props = defineProps({ fetchDataUrl: { type: String, default: '' }, dataUrl: { type: String, default: '' }, parameter: { type: Object, default: undefined }, + readOnly: { type: Boolean, default: false }, }); const emit = defineEmits<{ diff --git a/io.sc.engine.rule.frontend/src/views/resources/designer/Parameter.vue b/io.sc.engine.rule.frontend/src/views/resources/designer/Parameter.vue index 01bdecb4..44a2c33a 100644 --- a/io.sc.engine.rule.frontend/src/views/resources/designer/Parameter.vue +++ b/io.sc.engine.rule.frontend/src/views/resources/designer/Parameter.vue @@ -8,7 +8,7 @@ hide-bottom :config-button="false" selection="multiple" - :checkbox-selection="false" + :checkbox-selection="true" :tree="false" :fetch-data-url="Environment.apiContextPath('/api/re/model/parameter/findByModelId?modelId=' + model.id)" :data-url="Environment.apiContextPath('/api/re/model/parameter')" @@ -17,15 +17,13 @@ :toolbar-actions="[ 'refresh', 'separator', - { - name: 'move', - label: $t('re.resources.designer.parameter.grid.toolbar.move'), - icon: 'bi-share-fill', - }, [ { extend: 'add', click: undefined, + enableIf: (arg) => { + return !readOnly; + }, }, { extend: 'add', @@ -60,8 +58,8 @@ name: 'indicator', label: $t('re.resources.designer.parameter.grid.toolbar.add.indicator'), icon: 'bi-link', - afterClick: (arg) => { - arg.grid.getEditorForm().setFieldValue('type', 'INDICATOR'); + click: (arg) => { + selectIndicatorDialogRef.open(); }, }, 'separator', @@ -113,7 +111,7 @@ { extend: 'clone', enableIf: (arg) => { - return arg.selected && arg.selected.parent; + return !readOnly && arg.selected; }, }, { @@ -122,12 +120,40 @@ label: $t('deepClone'), icon: 'bi-copy', enableIf: (arg) => { - return arg.selected && arg.selected.parent; + return !readOnly && arg.selected; + }, + click: (arg) => { + DialogManager.confirm($t('re.resources.designer.parameter.grid.toolbar.deepClone.tip'), () => { + axios.post(Environment.apiContextPath('/api/re/model/parameter/deepClone/' + arg.selected.id)).then(() => { + gridRef.refresh(); + }); + }); + }, + }, + { + extend: 'edit', + enableIf: (arg) => { + return !readOnly && arg.selected; + }, + }, + { + extend: 'remove', + enableIf: (arg) => { + return !readOnly && arg.selected; + }, + }, + 'separator', + { + name: 'move', + label: $t('re.resources.designer.parameter.grid.toolbar.move'), + icon: 'bi-share-fill', + enableIf: (arg) => { + return !readOnly && arg.selected; + }, + click: (arg) => { + moveParameterDialogRef.open(); }, - click: (arg) => {}, }, - 'edit', - 'remove', 'separator', 'view', 'separator', @@ -137,14 +163,30 @@ { width: 60, name: 'order', label: $t('order'), sortable: false, align: 'right' }, { width: '100%', name: 'name', label: $t('name'), sortable: false }, { width: 150, name: 'code', label: $t('code'), sortable: false }, - { width: 100, name: 'type', label: $t('type'), sortable: false, format: Formater.enum(Enums.ParameterType) }, + { width: 110, name: 'type', label: $t('type'), sortable: false, format: Formater.enum(Enums.ParameterType) }, { - width: 150, + width: 180, name: 'valueType', label: $t('re.resources.designer.parameter.grid.entity.valueType'), sortable: false, - format: (value) => { - return ValueTypeMap[value]; + format: (value, row) => { + if (row.valueTypeVersion) { + return ValueTypeMap[value] + ' (V' + row.valueTypeVersion + ')'; + } + if (row.valueType == 'java.math.BigDecimal') { + if (row.valueRoundingMode == 'HALF_UP') { + return ValueTypeMap[value] + '(' + row.valueScale + ')'; + } else { + return ValueTypeMap[value] + '(' + row.valueScale + ',' + Formater.enum(Enums.RoundingMode)(row.valueRoundingMode) + ')'; + } + } + var result = ValueTypeMap[value]; + result = result || row.valueType; + if (result) { + result = result.replace('<', '<'); + result = result.replace('>', '>'); + } + return result; }, }, { @@ -159,7 +201,6 @@ :editor="{ dialog: { width: '600px', - height: '550px', }, form: { colsNum: 1, @@ -173,24 +214,34 @@ name: 'libCode', label: $t('re.resources.designer.parameter.grid.entity.libCode'), type: 'select', + options: libCodeOptionsRef, showIf: (arg) => { const type = arg.form.getFieldValue('type'); return type === 'INDICATOR'; }, + 'onUpdate:modelValue': (value) => { + libVersionOptionsRef = IndicatorManager.getLibVersionMap(value); + }, }, { name: 'libVersion', label: $t('re.resources.designer.parameter.grid.entity.libVersion'), type: 'select', + options: libVersionOptionsRef, showIf: (arg) => { const type = arg.form.getFieldValue('type'); return type === 'INDICATOR'; }, + 'onUpdate:modelValue': (value) => { + const libCode = gridRef.getEditorForm().getFieldValue('libCode'); + indicatorCodeOptionsRef = IndicatorManager.getIndicatorMap(libCode, value); + }, }, { name: 'indicatorCode', label: $t('re.resources.designer.parameter.grid.entity.indicatorCode'), type: 'select', + options: indicatorCodeOptionsRef, showIf: (arg) => { const type = arg.form.getFieldValue('type'); return type === 'INDICATOR'; @@ -305,6 +356,7 @@ fields: [ { name: 'order', label: $t('order') }, { name: 'id', label: $t('id') }, + { name: 'model', label: $t('model') }, { name: 'code', label: $t('code') }, { name: 'name', label: $t('name') }, { name: 'description', label: $t('description') }, @@ -324,7 +376,6 @@ { name: 'createDate', label: $t('createDate') }, { name: 'lastModifier', label: $t('lastModifier') }, { name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() }, - { name: 'corporationCode', label: $t('corporationCode') }, ], }, }" @@ -338,15 +389,35 @@ emit('beforeRequestData'); } " + @after-editor-open=" + (row) => { + console.log(row); + if (row.type === 'INDICATOR') { + axios.get(Environment.apiContextPath('/api/re/lib/isc/getLibInformationWrapper')).then((response) => { + IndicatorManager.setWrapper(response.data); + libCodeOptionsRef = IndicatorManager.getLibMap(); + libVersionOptionsRef = IndicatorManager.getLibVersionMap(row.libCode); + indicatorCodeOptionsRef = IndicatorManager.getIndicatorMap(row.libCode, row.libVersion); + }); + } + } + " > + + diff --git a/io.sc.engine.rule.frontend/src/views/shared/SelectIndicatorDialog.vue b/io.sc.engine.rule.frontend/src/views/shared/SelectIndicatorDialog.vue new file mode 100644 index 00000000..b34a072b --- /dev/null +++ b/io.sc.engine.rule.frontend/src/views/shared/SelectIndicatorDialog.vue @@ -0,0 +1,184 @@ + + diff --git a/io.sc.engine.rule.frontend/src/views/testcase/Testcase.vue b/io.sc.engine.rule.frontend/src/views/testcase/Testcase.vue index 2fefa7cd..73486beb 100644 --- a/io.sc.engine.rule.frontend/src/views/testcase/Testcase.vue +++ b/io.sc.engine.rule.frontend/src/views/testcase/Testcase.vue @@ -1,41 +1,46 @@