From 5ec4f9e649291dd32b57acf1557ef396e8f288ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Thu, 13 Apr 2023 09:32:20 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../formlua/core/AttendanceQlExpress.java | 316 + .../salary/formlua/core/QLExpressContext.java | 19 + .../formlua/core/exception/ErrorType.java | 69 + .../core/exception/ExcelRunTimeException.java | 24 + .../formlua/data/ExpressDataService.java | 85 + .../formlua/data/ExpressDataServiceImpl.java | 662 ++ .../salary/formlua/data/func/EqOperator.java | 117 + .../formlua/data/func/LessMoreOperator.java | 115 + .../salary/formlua/data/func/LogicFunc.java | 99 + .../formlua/data/func/NotEqOperator.java | 112 + .../formlua/data/func/QLExpressContext.java | 47 + .../formlua/data/func/QlExpressUtil.java | 148 + .../entity/parameter/DateAndString.java | 5 + .../formlua/entity/parameter/ExcelFunc.java | 138 + .../formlua/entity/parameter/ExcelFuncs.java | 495 ++ .../entity/parameter/FormulaContext.java | 35 + .../entity/parameter/FuncDescUtil.java | 132 + .../formlua/entity/parameter/FuncNames.java | 20 + .../formlua/entity/parameter/IllegalList.java | 19 + .../entity/parameter/ParamContext.java | 30 + .../entity/parameter/ParamFactory.java | 127 + .../formlua/entity/parameter/ParamType.java | 15 + .../formlua/entity/parameter/ReturnType.java | 13 + .../entity/parameter/ThreadLocalData.java | 59 + .../formlua/entity/standard/AggFunc.java | 8 + .../entity/standard/ExcelModuleFixField.java | 34 + .../formlua/entity/standard/ExcelPage.java | 56 + .../formlua/entity/standard/ExcelResult.java | 87 + .../entity/standard/FormulaCategory.java | 58 + .../entity/standard/FormulaDataSource.java | 37 + .../entity/standard/FormulaFilterData.java | 303 + .../standard/FormulaModuleCategory.java | 34 + .../formlua/func/compare/CommonOper.java | 71 + .../formlua/func/compare/Compareutils.java | 310 + .../formlua/func/compare/EqOperator.java | 243 + .../func/compare/GreaterEqOperator.java | 104 + .../formlua/func/compare/GreaterOperator.java | 105 + .../formlua/func/compare/InOperator.java | 97 + .../formlua/func/compare/LessEqOperator.java | 103 + .../formlua/func/compare/LessOperator.java | 104 + .../formlua/func/compare/NotEqueOperator.java | 102 + .../formlua/func/compare/OperatorInTest.java | 38 + .../formlua/func/compare/WOperatorAdd.java | 60 + .../formlua/func/compare/WOperatorDiv.java | 66 + .../formlua/func/compare/WOperatorMulti.java | 55 + .../formlua/func/compare/WOperatorReduce.java | 59 + .../formlua/func/date/DateTimeService.java | 92 + .../func/date/DateTimeServiceImpl.java | 1324 +++ .../func/date/DateTimeTestServiceImpl.java | 1208 +++ .../formlua/func/finance/FinanceService.java | 15 + .../func/finance/FinanceServiceImpl.java | 119 + .../func/finance/FinanceServiceTestImpl.java | 45 + .../formlua/func/find/FindFuncsService.java | 31 + .../func/find/FindFuncsServiceImpl.java | 193 + .../func/find/FindFuncsTestServiceImpl.java | 166 + .../salary/formlua/func/logic/IfOperator.java | 97 + .../formlua/func/logic/LogicService.java | 17 + .../formlua/func/logic/LogicServiceImpl.java | 495 ++ .../salary/formlua/func/logic/LogicUtils.java | 110 + .../formlua/func/math/MathFuncsService.java | 79 + .../func/math/MathFuncsServiceImpl.java | 468 ++ .../func/math/MathFuncsServiceTestImpl.java | 486 ++ .../formlua/func/string/ExtractType.java | 7 + .../func/string/StringFormulaService.java | 186 + .../func/string/StringFormulaServiceImpl.java | 820 ++ .../string/StringFormulaServiceTestImpl.java | 555 ++ .../salary/formlua/util/CompareUtil.java | 24 + .../engine/salary/formlua/util/DateUtil.java | 212 + .../engine/salary/formlua/util/ErrorUtil.java | 33 + .../salary/formlua/util/ExcelParamUtil.java | 1104 +++ .../salary/formlua/util/ExcelResult.java | 36 + .../formlua/util/ExcelStandardUtil.java | 492 ++ .../salary/formlua/util/ExecuteTest.java | 47 + .../formlua/util/ExpressRegularUtil.java | 227 + .../salary/formlua/util/IgnoreFilter.java | 21 + .../formlua/util/IgnoreParamFilter.java | 769 ++ .../salary/formlua/util/NativePlace.java | 7162 +++++++++++++++++ .../salary/formlua/util/RegularUtil.java | 241 + .../engine/salary/formlua/util/SortUtil.java | 49 + .../engine/salary/formlua/util/TestUtil.java | 403 + .../formlua/util/standard/ExcelDataType.java | 8 + .../formlua/util/standard/ExcelTransUtil.java | 320 + 82 files changed, 22696 insertions(+) create mode 100644 src/com/engine/salary/formlua/core/AttendanceQlExpress.java create mode 100644 src/com/engine/salary/formlua/core/QLExpressContext.java create mode 100644 src/com/engine/salary/formlua/core/exception/ErrorType.java create mode 100644 src/com/engine/salary/formlua/core/exception/ExcelRunTimeException.java create mode 100644 src/com/engine/salary/formlua/data/ExpressDataService.java create mode 100644 src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java create mode 100644 src/com/engine/salary/formlua/data/func/EqOperator.java create mode 100644 src/com/engine/salary/formlua/data/func/LessMoreOperator.java create mode 100644 src/com/engine/salary/formlua/data/func/LogicFunc.java create mode 100644 src/com/engine/salary/formlua/data/func/NotEqOperator.java create mode 100644 src/com/engine/salary/formlua/data/func/QLExpressContext.java create mode 100644 src/com/engine/salary/formlua/data/func/QlExpressUtil.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/DateAndString.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/ExcelFunc.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/FormulaContext.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/FuncNames.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/IllegalList.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/ParamContext.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/ParamFactory.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/ParamType.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/ReturnType.java create mode 100644 src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java create mode 100644 src/com/engine/salary/formlua/entity/standard/AggFunc.java create mode 100644 src/com/engine/salary/formlua/entity/standard/ExcelModuleFixField.java create mode 100644 src/com/engine/salary/formlua/entity/standard/ExcelPage.java create mode 100644 src/com/engine/salary/formlua/entity/standard/ExcelResult.java create mode 100644 src/com/engine/salary/formlua/entity/standard/FormulaCategory.java create mode 100644 src/com/engine/salary/formlua/entity/standard/FormulaDataSource.java create mode 100644 src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java create mode 100644 src/com/engine/salary/formlua/entity/standard/FormulaModuleCategory.java create mode 100644 src/com/engine/salary/formlua/func/compare/CommonOper.java create mode 100644 src/com/engine/salary/formlua/func/compare/Compareutils.java create mode 100644 src/com/engine/salary/formlua/func/compare/EqOperator.java create mode 100644 src/com/engine/salary/formlua/func/compare/GreaterEqOperator.java create mode 100644 src/com/engine/salary/formlua/func/compare/GreaterOperator.java create mode 100644 src/com/engine/salary/formlua/func/compare/InOperator.java create mode 100644 src/com/engine/salary/formlua/func/compare/LessEqOperator.java create mode 100644 src/com/engine/salary/formlua/func/compare/LessOperator.java create mode 100644 src/com/engine/salary/formlua/func/compare/NotEqueOperator.java create mode 100644 src/com/engine/salary/formlua/func/compare/OperatorInTest.java create mode 100644 src/com/engine/salary/formlua/func/compare/WOperatorAdd.java create mode 100644 src/com/engine/salary/formlua/func/compare/WOperatorDiv.java create mode 100644 src/com/engine/salary/formlua/func/compare/WOperatorMulti.java create mode 100644 src/com/engine/salary/formlua/func/compare/WOperatorReduce.java create mode 100644 src/com/engine/salary/formlua/func/date/DateTimeService.java create mode 100644 src/com/engine/salary/formlua/func/date/DateTimeServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/finance/FinanceService.java create mode 100644 src/com/engine/salary/formlua/func/finance/FinanceServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java create mode 100644 src/com/engine/salary/formlua/func/find/FindFuncsService.java create mode 100644 src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/logic/IfOperator.java create mode 100644 src/com/engine/salary/formlua/func/logic/LogicService.java create mode 100644 src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/logic/LogicUtils.java create mode 100644 src/com/engine/salary/formlua/func/math/MathFuncsService.java create mode 100644 src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/math/MathFuncsServiceTestImpl.java create mode 100644 src/com/engine/salary/formlua/func/string/ExtractType.java create mode 100644 src/com/engine/salary/formlua/func/string/StringFormulaService.java create mode 100644 src/com/engine/salary/formlua/func/string/StringFormulaServiceImpl.java create mode 100644 src/com/engine/salary/formlua/func/string/StringFormulaServiceTestImpl.java create mode 100644 src/com/engine/salary/formlua/util/CompareUtil.java create mode 100644 src/com/engine/salary/formlua/util/DateUtil.java create mode 100644 src/com/engine/salary/formlua/util/ErrorUtil.java create mode 100644 src/com/engine/salary/formlua/util/ExcelParamUtil.java create mode 100644 src/com/engine/salary/formlua/util/ExcelResult.java create mode 100644 src/com/engine/salary/formlua/util/ExcelStandardUtil.java create mode 100644 src/com/engine/salary/formlua/util/ExecuteTest.java create mode 100644 src/com/engine/salary/formlua/util/ExpressRegularUtil.java create mode 100644 src/com/engine/salary/formlua/util/IgnoreFilter.java create mode 100644 src/com/engine/salary/formlua/util/IgnoreParamFilter.java create mode 100644 src/com/engine/salary/formlua/util/NativePlace.java create mode 100644 src/com/engine/salary/formlua/util/RegularUtil.java create mode 100644 src/com/engine/salary/formlua/util/SortUtil.java create mode 100644 src/com/engine/salary/formlua/util/TestUtil.java create mode 100644 src/com/engine/salary/formlua/util/standard/ExcelDataType.java create mode 100644 src/com/engine/salary/formlua/util/standard/ExcelTransUtil.java diff --git a/src/com/engine/salary/formlua/core/AttendanceQlExpress.java b/src/com/engine/salary/formlua/core/AttendanceQlExpress.java new file mode 100644 index 000000000..4b7f07d34 --- /dev/null +++ b/src/com/engine/salary/formlua/core/AttendanceQlExpress.java @@ -0,0 +1,316 @@ +package com.engine.salary.formlua.core; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.entity.parameter.FuncNames; +import com.engine.salary.formlua.func.compare.*; +import com.engine.salary.formlua.func.date.DateTimeService; +import com.engine.salary.formlua.func.finance.FinanceService; +import com.engine.salary.formlua.func.find.FindFuncsService; +import com.engine.salary.formlua.func.logic.LogicService; +import com.engine.salary.formlua.func.math.MathFuncsService; +import com.engine.salary.formlua.func.string.StringFormulaService; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.engine.salary.formlua.util.ExpressRegularUtil; +import com.ql.util.express.DynamicParamsUtil; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.regex.PatternSyntaxException; + +/** + * 考勤执行业务类 + */ +public class AttendanceQlExpress { + + public static ExpressRunner runner; + + static { + runner = new ExpressRunner(true, false); + } + + private static boolean isInitialRunner = false; + + +// AggregationFunc aggregationFunc; + + LogicService logicService; + + DateTimeService dateTimeService; + + StringFormulaService stringFormulaService; + + MathFuncsService mathFuncsService; + + FindFuncsService findFuncsService; + +// private ExcelFuncs excelFuncs; +// +// private HrmDbService hrmDbService; + + private FinanceService financeService; +// private RemoteExcelformulaService remoteExcelformulaService; + private String errorInfo; + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + + /** + * @param statement 执行语句 + * @param context 上下文 + * @throws Exception + */ + public Object execute(String statement, Map context) + throws Exception { + String expressSql = statement; + initRunner(runner); + DynamicParamsUtil.supportDynamicParams = true; + //初步的语法的格式校验 + IExpressContext expressContext = new QLExpressContext(context); +// ThreadLocalData threadLocalData=new ThreadLocalData(); +// threadLocalData.setExpressContext(context); +// ParamContext.get().setValue("formulaParam",threadLocalData); +// ParamContext.get().setValue("currentUser",simpleEmployee); + Object obj = null; + try { + ExpressRegularUtil.checkFuncExpress(expressSql); + expressSql = expressSql.replaceAll("\\{", ""); + expressSql = expressSql.replaceAll("\\}", ""); + obj = runner.execute(expressSql, expressContext, null, true, false); + JSONObject resultObj = new JSONObject(); + if (obj != null) { + resultObj.put("excute", true); + if (obj instanceof DataType) { + DataType dataType = (DataType) obj; + resultObj.put("data", dataType.getContent()); + resultObj.put("boolData", dataType.getContent()); + } else { + resultObj.put("data", obj); + resultObj.put("boolData", obj); + } + } else { + resultObj.put("excute", false); + } + return resultObj; + } catch (Exception e) { + logger.error("err", e); + String jsonError = e.getMessage(); + if (e instanceof PatternSyntaxException) { + PatternSyntaxException patternSyntaxException = (PatternSyntaxException) e; + jsonError = patternSyntaxException.getDescription(); + } else { + if (null != e.getCause()) { + jsonError = e.getCause().getMessage(); + if (e.getCause() instanceof InvocationTargetException) { + InvocationTargetException invocationTargetException = (InvocationTargetException) e.getCause(); + jsonError = invocationTargetException.getTargetException().getMessage(); + } + } + } + JSONObject errorJSON = new JSONObject(); + if (null == jsonError) { + errorJSON.put("error", "参数为空"); + obj = errorJSON; + + JSONObject resultObj = new JSONObject(); + resultObj.put("data", ""); + resultObj.put("excute", true); + return resultObj; + } + try { + errorJSON = JSON.parseObject(jsonError); + } catch (Exception ex) { + errorJSON.put("error", "参数为空"); + obj = errorJSON; + + JSONObject resultObj = new JSONObject(); + resultObj.put("data", ""); + resultObj.put("excute", true); + return resultObj; + } + if (!(e instanceof PatternSyntaxException)) { + String func = errorJSON.getString("func"); + int funcIdx = errorJSON.getInteger("errorFunc"); + String[] funcSplit = statement.split(func); + int startError = 1; + int loopLength = funcSplit.length - funcIdx; + for (int i = 0; i < loopLength; i++) { + if (loopLength > 1 && i == 0) { + startError += funcSplit[i].length() + func.length(); + } else { + startError += funcSplit[i].length(); + } + } + int startIdx = startError; + int endIdx = startError + func.length() - 1; + Map replaceMap = ExcelParamUtil.replaceErrorPlace(startIdx, endIdx, func, expressSql, context); + errorJSON.put("errorIdx", replaceMap.get("startIdx")); + errorJSON.put("errorEndIdx", replaceMap.get("endIdx")); + + } + if (errorJSON.containsKey("error") && null != errorJSON.getString("msg") && !ExpressRegularUtil.isContainChinese(errorJSON.getString("msg"))) { + errorJSON.put("error", "校验失败或参数错误"); + } + + errorJSON.remove("errorFunc"); + errorJSON.remove("formula"); + errorJSON.remove("func"); + errorJSON.remove("errorData"); + obj = errorJSON; + } + return obj; + } + + private void initRunner(ExpressRunner runner) { + if (isInitialRunner) { + return; + } + synchronized (runner) { + if (isInitialRunner) { + return; + } + try { + //比较函数 + runner.replaceOperator("=", new EqOperator("=")); + runner.replaceOperator("==", new EqOperator("=")); + runner.replaceOperator("!=", new NotEqueOperator("!=")); + + runner.replaceOperator(">", new GreaterOperator(">")); + runner.replaceOperator("<", new LessOperator("<")); + runner.replaceOperator(">=", new GreaterEqOperator(">=")); + runner.replaceOperator("<=", new LessEqOperator("<=")); + + runner.replaceOperator("+", new WOperatorAdd("+")); + runner.replaceOperator("-", new WOperatorReduce("-")); + runner.replaceOperator("*", new WOperatorMulti("*")); + runner.replaceOperator("/", new WOperatorDiv("/")); + //逻辑函数 + runner.replaceOperator("IN", new InOperator("in")); + runner.replaceOperator("IF", new InOperator("IF")); + runner.addFunctionOfServiceMethod(FuncNames.AND.toString(), logicService, FuncNames.AND.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.OR.toString(), logicService, FuncNames.OR.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.LIKE.toString(), logicService, FuncNames.LIKE.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.TRUE.toString(), logicService, FuncNames.TRUE.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.FALSE.toString(), logicService, FuncNames.FALSE.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.ISEMPTY.toString(), logicService, FuncNames.ISEMPTY.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.NOT.toString(), logicService, FuncNames.NOT.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.IFS.toString(), logicService, FuncNames.IFS.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.FIND.toString(), logicService, FuncNames.FIND.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.SWITCH.toString(), logicService, FuncNames.SWITCH.getName(), new Class[]{Object[].class}, ""); + + //日期函数 + runner.addFunctionOfServiceMethod("DATEDIFF", dateTimeService, "dateDiff", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("DATEADD", dateTimeService, "dateAdd", new Class[]{Object[].class}, errorInfo); + runner.addFunctionOfServiceMethod("YEAR", dateTimeService, "year", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("MONTH", dateTimeService, "month", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("DAY", dateTimeService, "day", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("HOUR", dateTimeService, "hour", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("MINUTE", dateTimeService, "minute", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("SECOND", dateTimeService, "seconds", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("WEEKNUM", dateTimeService, "weekNum", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("WEEKDAY", dateTimeService, "weekDay", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("NOW", dateTimeService, "now", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("TODAY", dateTimeService, "today", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("DATEFORMAT", dateTimeService, "dateFormat", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("DAYOFMONTH", dateTimeService, "dayOfMonth", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("EOMONTH", dateTimeService, "eoMonth", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("NETWORKDAYSPI", dateTimeService, "workdayIntl", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("CURRYEAR", dateTimeService, "currYear", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("CURRMONTH", dateTimeService, "currMonth", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("CURRDAY", dateTimeService, "currDay", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("CURRWEEK", dateTimeService, "currWeek", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("CURRHOUR", dateTimeService, "currHour", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("CURRMINUTE", dateTimeService, "currMinute", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("CURRSECOND", dateTimeService, "currSecond", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("MAXDATE", dateTimeService, "maxDate", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("MINDATE", dateTimeService, "minDate", new Class[]{Object[].class}, ""); + + //聚合函数 +// runner.addFunctionOfServiceMethod("COUNT", aggregationFunc, "counts", new Class[]{Object[].class}, "COUNT参数错误"); +// runner.addFunctionOfServiceMethod("AVG", aggregationFunc, "avgs", new Class[]{Object[].class}, "AVG参数错误"); +// runner.addFunctionOfServiceMethod("SUM", aggregationFunc, "sumNumber", new Class[]{Object[].class}, "SUM参数错误"); +// runner.addFunctionOfServiceMethod("MAX", aggregationFunc, "maxNumber", new Class[]{Object[].class}, "MAX参数错误"); +// runner.addFunctionOfServiceMethod("MIN", aggregationFunc, "minNumber", new Class[]{Object[].class}, "MIN参数错误"); + + //字符串函数 + runner.addFunctionOfServiceMethod("CONCAT", stringFormulaService, "concatString", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("SEARCH", stringFormulaService, "search", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("TEXT", stringFormulaService, "text", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("PAD", stringFormulaService, "pad", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("REPLACE", stringFormulaService, "replace", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("VALUE", stringFormulaService, "value", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("LEN", stringFormulaService, "len", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("LEFT", stringFormulaService, "left", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("RIGHT", stringFormulaService, "right", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("MID", stringFormulaService, "mid", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("REPT", stringFormulaService, "repeat", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("TRIM", stringFormulaService, "trim", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("SCORE", stringFormulaService, "score", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("IDCARD", stringFormulaService, "idCard", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.ISSTRING.toString(), stringFormulaService, FuncNames.ISSTRING.getName(), new Class[]{Object[].class}, ""); + + //数学函数 + runner.addFunctionOfServiceMethod("ROUNDUP", mathFuncsService, "roundUp", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("ROUNDDOWN", mathFuncsService, "roundDown", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("ROUND", mathFuncsService, "round", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.AGGREGATION.toString(), mathFuncsService, FuncNames.AGGREGATION.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.MOD.toString(), mathFuncsService, FuncNames.MOD.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.TRUNC.toString(), mathFuncsService, FuncNames.TRUNC.getName(), new Class[]{Object.class, Object.class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.ISINT.toString(), mathFuncsService, FuncNames.ISINT.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.ISNUMBER.toString(), mathFuncsService, FuncNames.ISNUMBER.getName(), new Class[]{Object[].class}, ""); + + //查找函数 + runner.addFunctionOfServiceMethod(FuncNames.CHOOSE.toString(), findFuncsService, "chooseOne", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.MATCH.toString(), findFuncsService, "match", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.VLOOKUPS.toString(), findFuncsService, "vlookups", new Class[]{Object[].class}, ""); + + //数据库函数-hrm +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMNAME.toString(), hrmDbService, FuncNames.GETHRMNAME.getName(), new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMMOBILE.toString(), hrmDbService, FuncNames.GETHRMMOBILE.getName(), new Class[]{Object[].class}, ""); + + //财务函数 + runner.addFunctionOfServiceMethod(FuncNames.GETMONEY.toString(), financeService, FuncNames.GETMONEY.getName(), new Class[]{Object[].class}, ""); + + //数据库函数-hrm +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMLOGINID.toString(), hrmDbService, "getHrmLoginId", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMWORKCODE.toString(), hrmDbService, "getHrmWorkcode", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMMANAGER.toString(), hrmDbService, "getHrmManager", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMALLMANAGER.toString(), hrmDbService, "getHrmAllManager", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMDEPARTMENT.toString(), hrmDbService, "getHrmDepartment", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETHRMSUBCOMPANY.toString(), hrmDbService, "getHrmSubcompany", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETDEPARTMENTNAME.toString(), hrmDbService, "getDepartmentName", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETDEPARTMENTCODE.toString(), hrmDbService, "getDepartmentCode", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETSUPERDEPARTMENT.toString(), hrmDbService, "getSuperDepartment", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETALLSUPERDEPARTMENT.toString(), hrmDbService, "getAllSuperDepartment", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETSUBCOMPANYNAME.toString(), hrmDbService, "getSubcompanyName", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETSUBCOMPANYCODE.toString(), hrmDbService, "getSubcompanyCode", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETSUPERSUBCOMPANY.toString(), hrmDbService, "getSuperSubcompany", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.GETALLSUPERSUBCOMPANY.toString(), hrmDbService, "getAllSuperSubcompany", new Class[]{Object[].class}, ""); + + //加载模块自定义函数 +// try { +// List otherFuncList=excelFuncs.getOtherFuncs(); +// if(otherFuncList!=null && otherFuncList.size()>0){ +// //为每个方法实例化一个ExcelExtendFuncService +// for (ExcelFunc excelFunc:otherFuncList){ +// //每个接口调度类实例化时指定模块和函数名 +// ExcelExtendFuncService excelExtendFuncService=new ExcelExtendFuncServiceImpl(excelFunc.getModule(),excelFunc.getName()); +// //将自定义函数放入context上下文中 +// runner.addFunctionOfServiceMethod(excelFunc.getName(),excelExtendFuncService, RpcMethod.execute.toString(),new Class[]{Object[].class},""); +// } +// } +// } catch (Exception e) { +// logger.error("err",e); +// } + } catch (Exception e) { + logger.error("err", e); + throw new RuntimeException("初始化失败表达式"); + } + } + isInitialRunner = true; + } +} diff --git a/src/com/engine/salary/formlua/core/QLExpressContext.java b/src/com/engine/salary/formlua/core/QLExpressContext.java new file mode 100644 index 000000000..d9db4a6ff --- /dev/null +++ b/src/com/engine/salary/formlua/core/QLExpressContext.java @@ -0,0 +1,19 @@ +package com.engine.salary.formlua.core; + +import com.ql.util.express.IExpressContext; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("serial") +public class QLExpressContext extends HashMap implements + IExpressContext { + + + + public QLExpressContext(Map aProperties) { + super(aProperties); + } + + +} diff --git a/src/com/engine/salary/formlua/core/exception/ErrorType.java b/src/com/engine/salary/formlua/core/exception/ErrorType.java new file mode 100644 index 000000000..58f97671a --- /dev/null +++ b/src/com/engine/salary/formlua/core/exception/ErrorType.java @@ -0,0 +1,69 @@ +package com.engine.salary.formlua.core.exception; + +import com.engine.salary.util.SalaryI18nUtil; + +public enum ErrorType { + /** + *函数参数不能为空 + */ + NOT_NULL(SalaryI18nUtil.getI18nLabel(91326,"函数参数不能为空")), + /** + * 参数不能为空 + */ + VAR_NOT_NULL(SalaryI18nUtil.getI18nLabel(32804,"参数不能为空")), + /** + *函数参数错误,参数类型需为数字字段 + */ + MUST_NUM(SalaryI18nUtil.getI18nLabel(91327,"函数参数错误,参数类型需为数字字段")), + /** + *函数参数类型错误,参数需为表格 + */ + MUST_FORM(SalaryI18nUtil.getI18nLabel(91330,"函数参数类型错误,参数需为表格")), + /** + * + */ + MUST_FORM_FIELD(SalaryI18nUtil.getI18nLabel(91331,"函数参数错误,参数类型需为表格字段")), + CANT_FORM_FIELD(SalaryI18nUtil.getI18nLabel(91427,"比较操作符参数不能是表格字段")), + /** + * + */ + CND_NOT_NULL(SalaryI18nUtil.getI18nLabel(11575,"条件不能为空")), + /** + * + */ + MIN_VAR_COUNT(SalaryI18nUtil.getI18nLabel(91332,"函数的最少参数个数")), + /** + * + */ + MAX_VAR_COUNT(SalaryI18nUtil.getI18nLabel(91333,"函数的最多参数个数")), + /** + * + */ + CANNOT_HAVE_VAR(SalaryI18nUtil.getI18nLabel(91334,"函数不能有参数")), + /** + * + */ + RETURN_TYPE_DIFF(SalaryI18nUtil.getI18nLabel(91335,"函数多个条件的返回值必须一致")), + /** + * + */ + VAR_COUNT_MUST_Odd(SalaryI18nUtil.getI18nLabel(91336,"函数最后一个参数需为默认返回值")), + /** + * + */ + VAR_TYPE_WRONG(SalaryI18nUtil.getI18nLabel(91337,"函数参数类型错误")), + /** + * + */ + VAR_MUST_HAVE_DATE(SalaryI18nUtil.getI18nLabel(91338,"函数日期参数必须包含年月日")), + /** + * + */ + VAR_TYPE_MUST_BE(SalaryI18nUtil.getI18nLabel(91339,"函数参数类型错误,参数类型需为")), + /** + * + */ + CANNOT_FIND_TEN(SalaryI18nUtil.getI18nLabel(91361,"函数未能获取到租户")); + ErrorType(String name) { + } +} diff --git a/src/com/engine/salary/formlua/core/exception/ExcelRunTimeException.java b/src/com/engine/salary/formlua/core/exception/ExcelRunTimeException.java new file mode 100644 index 000000000..cd4a7736f --- /dev/null +++ b/src/com/engine/salary/formlua/core/exception/ExcelRunTimeException.java @@ -0,0 +1,24 @@ +package com.engine.salary.formlua.core.exception; + + + +public class ExcelRunTimeException extends Exception{ + private String info; + + public ExcelRunTimeException(String info) { + super(info,new Exception(info)); + this.info = info; + } + + public ExcelRunTimeException() { + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } + +} diff --git a/src/com/engine/salary/formlua/data/ExpressDataService.java b/src/com/engine/salary/formlua/data/ExpressDataService.java new file mode 100644 index 000000000..239974af7 --- /dev/null +++ b/src/com/engine/salary/formlua/data/ExpressDataService.java @@ -0,0 +1,85 @@ +package com.engine.salary.formlua.data; + +import com.weaver.common.form.data.FormData; +import com.weaver.excel.formula.api.entity.ExpressFormula; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.teams.domain.user.SimpleEmployee; + +import java.util.List; +import java.util.Map; + +/** + * 公式数据交互service + * @author Failymiss + * + */ +public interface ExpressDataService { + + public Map buildCndFilter(Long formId, Long fieldId, String express, Map params, String module, SimpleEmployee employee); + + /** + * 统计函数条件校验 + * @param formId + * @param fieldId + * @param funcName + * @param express + * @param params + * @param module + * @param employee + * @return + * @throws Exception + */ + public Double getAggregateDataTest(Long formId, Long fieldId, String funcName,String module,Map params,SimpleEmployee employee) throws Exception; + + /** + * @param formId + * @param fieldId + * @param funcName + * @param express + * @param params + * @param module + * @param employee + * @return + */ + public Double getAggregateData(Long formId, Long fieldId, String funcName, String express, Map params, String module, SimpleEmployee employee); + + public Double getCommonAggregateData(Long formId,Long fieldId,String funcName,List cndDataType,String moduleSource,SimpleEmployee employee); + + /** + * formdata封装成函数需要的数据结构 + * @param fieldIds 字段id + * @param dataId 当前数据id(上报id,审批id) + * @param module 当前数据module + * @param employee 操作人 + * @return + */ +// public Map bulidDataType(List fieldIds, Long dataId, ModuleSource module, SimpleEmployee employee); + + /** + * @param fieldIds + * @param formData + * @param module + * @param employee + * @return + */ + public Map bulidDataType(List fieldIds, FormData formData, String module,SimpleEmployee employee); + + /** + * 测试统计筛选条件 + */ + public void testFunc(SimpleEmployee employee); + + String getDataType(String componentKey); + + /** + * 给规则库更新时构建筛选条件的一个接口 + * @param formula + * @param targetFormId + * @param employee + * @param formData + * @param module + * @return + */ + Map buildFilterParam(ExpressFormula formula, Long targetFormId, SimpleEmployee employee, FormData formData, String module); + +} diff --git a/src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java b/src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java new file mode 100644 index 000000000..5d6991b5f --- /dev/null +++ b/src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java @@ -0,0 +1,662 @@ +package com.engine.salary.formlua.data; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Maps; +import com.weaver.common.base.entity.result.WeaResult; +import com.weaver.common.form.FreeFormAssistService; +import com.weaver.common.form.FreeFormService; +import com.weaver.common.form.FreeStatAssistService; +import com.weaver.common.form.component.base.ComponentConfig; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.common.form.constant.FormGroup; +import com.weaver.common.form.data.FormData; +import com.weaver.common.form.data.FormDataStatus; +import com.weaver.common.form.data.detail.FormDataDetail; +import com.weaver.common.form.data.option.FormDataOption; +import com.weaver.common.form.data.text.FormDataText; +import com.weaver.common.form.metadata.ModuleSource; +import com.weaver.common.form.metadata.field.FormField; +import com.weaver.common.form.remoteService.RemoteFreeStatService; +import com.weaver.common.form.stat.FilterFormData; +import com.weaver.common.form.stat.domain.search.FilterFormDataParam; +import com.weaver.common.form.stat.service.serarch.FilterFormDataSearchService; +import com.weaver.context.WeaverSentinelContext; +import com.weaver.excel.formula.api.entity.ExpressFormula; +import com.weaver.excel.formula.api.entity.FormulaVar; +import com.weaver.excel.formula.core.rpc.ExcelDubboInvoker; +import com.weaver.excel.formula.core.rpc.RemoteExcelService; +import com.weaver.excel.formula.data.func.QlExpressUtil; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.FormulaContext; +import com.weaver.excel.formula.entity.parameter.standard.AggFunc; +import com.weaver.excel.formula.entity.parameter.standard.ExcelResult; +import com.weaver.excel.formula.entity.parameter.standard.FormulaFilterData; +import com.weaver.excel.formula.util.ExcelParamUtil; +import com.weaver.excel.formula.util.standard.ExcelTransUtil; +import com.weaver.framework.rpc.annotation.RpcReference; +import com.weaver.teams.core.orm.mybatis.Page; +import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.formreport.remote.RemoteFormReportService; +import com.weaver.utils.WeaverDubboSentinelUtil; +import com.weaver.workflow.common.entity.list.requestlist.RequestListDataVoEntity; +import com.weaver.workflow.common.entity.list.requestlist.RequestListSearchConditionEntity; +import com.weaver.workflow.list.api.rest.publicapi.WflRequestListFormRest; +import com.weaver.workflow.list.api.rest.publicapi.WflSearchConditionRest; +import com.weaver.workflow.report.api.rest.reportstat.WfcReportStatRest; +import org.apache.dubbo.rpc.RpcException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; +import java.util.*; + +@Service +@SuppressWarnings("unused") +public class ExpressDataServiceImpl implements ExpressDataService { + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + @Autowired + protected FreeFormAssistService freeFormAssistService; + @RpcReference(group = FormGroup.WORKFLOW) + protected RemoteFreeStatService remoteFlowFreeStatService; + @Autowired + private FreeStatAssistService freeStatAssistService; + @RpcReference(group = "biaoge") + protected RemoteExcelService remoteExcelService; + @RpcReference(group = FormGroup.FORMREPORT) + protected RemoteFreeStatService remoteReportFreeStatService; + @Autowired + private QlExpressUtil qlExpressUtil; + @RpcReference + RemoteFormReportService remoteFormReportService; +// @RpcReference +// private WfcSearchConditionRest wfcSearchConditionRest; + @RpcReference(group = "workflow") + private WflSearchConditionRest wflSearchConditionRest; +// @RpcReference(group = "workflow",timeout = 300000) +// private WfcRequestListFormRest wfcRequestListFormRpc; + @RpcReference(group = "workflow") + private WflRequestListFormRest wflRequestListFormRest; + @Autowired + private ExcelDubboInvoker excelDubboInvoker; + @Autowired + private ExcelTransUtil excelTransUtil; +// @RpcReference(group = "workflow") +// private WfcRequestListFormRest wfcRequestListFormRest; + @RpcReference(group = "hrmsalary") + private RemoteExcelService remoteExcelServiceHrmSalary; + @RpcReference(group = "workflow") + private WfcReportStatRest wfcReportStatRest; + @Autowired + private FilterFormDataSearchService filterFormDataSearchService; + @Override + public void testFunc(SimpleEmployee employee) { + + try { + Map params = new HashMap(); + List formFields = bulidFreeFormService(ModuleSource.biaoge).getFormFieldListByStatus(2598433966837708893L, null, employee); + if(formFields != null && formFields.size() > 0) { + for(FormField formField:formFields) { + params.put("fieldId_"+formField.getId(), formField); + } + } + + String str = "2=5"; + + //测试= ==方法 + logger.info("测试=,==方法"); + + String str2 = "fieldId_2598434392040299458=5"; + + String str3 = "fieldId_3419471597648354446=5"; + logger.info("数字控件:"+JSON.toJSONString(qlExpressUtil.execute(str3, params))); + + String str4 = "fieldId_2598434963895899468='2020-07-14'"; + logger.info("日期控件:"+JSON.toJSONString(qlExpressUtil.execute(str4, params))); + + String str5 = "fieldId_3419471597648354447=5"; + logger.info("选项控件:"+JSON.toJSONString(qlExpressUtil.execute(str5, params))); + + //测试= ==方法 + logger.info("测试 >= <= > < 方法"); + + String str7 = "fieldId_3419471597648354446=5"; + logger.info("数字控件:"+JSON.toJSONString(qlExpressUtil.execute(str3, params))); + + String str8 = "fieldId_2598434963895899468='2020-07-14'"; + logger.info("日期控件:"+JSON.toJSONString(qlExpressUtil.execute(str4, params))); + + logger.info("测试 >= =< !=方法"); + } catch (Exception e) { + logger.error("err",e); + } + } + + @Override + public Double getAggregateDataTest(Long formId, Long fieldId, String funcName,String module,Map params,SimpleEmployee employee) throws Exception { + Double value = 0d; + return 1d; + } + + @SuppressWarnings("unchecked") + @Override + public Map buildCndFilter(Long formId, Long fieldId, String express, Map params, String module, SimpleEmployee employee) { + Map paramMap=new HashMap<>(); + List filterFormDatas = new ArrayList(); + if(express != null) { + if(params == null) { + params = new HashMap(); + } + List formFields = bulidFreeFormService(ModuleSource.valueOf(module)).getFormFieldListByStatus(formId, null, employee); + if(formFields != null && formFields.size() > 0) { + for(FormField formField:formFields) { + params.put("field"+formField.getId(), formField); + } + } + try { + Object object = qlExpressUtil.execute(express, params); + if(object instanceof FilterFormData) { + filterFormDatas.add((FilterFormData) object); + }else if((object instanceof List) && (((List) object).get(0) instanceof FilterFormData)) { + filterFormDatas.addAll((List)object); + } + } catch (Exception e) { + logger.error("err",e); + } + } + Map param = assemblyParam(formId, employee); + if(filterFormDatas != null && filterFormDatas.size() > 0) { + param.put("condition", filterFormDatas.get(0).getCondition()); + } + paramMap.put("param",param); + paramMap.put("filterFormDatas",filterFormDatas); + return paramMap; + } + + @Override + @SuppressWarnings("unchecked") + public Double getAggregateData(Long formId, Long fieldId, String funcName,String express, Map params, String module, SimpleEmployee employee) { + Double value = 0d; + List filterFormDatas = new ArrayList(); + if(express != null) { + if(params == null) { + params = new HashMap(); + } + + List formFields = bulidFreeFormService(ModuleSource.valueOf(module)).getFormFieldListByStatus(formId, null, employee); + if(formFields != null && formFields.size() > 0) { + for(FormField formField:formFields) { + boolean isput=false; + Iterator keysets=params.keySet().iterator(); + while (keysets.hasNext()){ + String key=keysets.next(); + Object obj=params.get(key); + logger.info("聚合函数匹配表单控件:"+key+"-->"+formField.getId()); + if(obj instanceof DataType){ + DataType dataType=(DataType)obj; + if(null!=dataType.getFieldId()&&Long.parseLong(dataType.getFieldId())==formField.getId() && !dataType.getName().equals("当前数据")){ + params.put(key, formField); + }else if(key.indexOf(formField.getId()+"")>0){ + params.put(key, formField); + } + }else if(key.indexOf(formField.getId()+"")>0){ + params.put(key, formField); + } + } + if(!isput){ + params.put("field"+formField.getId(), formField); + } + } + } + logger.info(formId+"aggregate express:"+express); + try { + Object object = qlExpressUtil.execute(express, params); + if(object instanceof FilterFormData) { + filterFormDatas.add((FilterFormData) object); + }else if((object instanceof List) && (((List) object).get(0) instanceof FilterFormData)) { + filterFormDatas.addAll((List)object); + } + } catch (Exception e) { + logger.error("err",e); + } + } + Map param = assemblyParam(formId, employee); + if(filterFormDatas != null && filterFormDatas.size() > 0) { + logger.info(filterFormDatas.get(0).getCondition()); + param.put("condition", StringUtils.isEmpty(filterFormDatas.get(0).getCondition())?"AND":filterFormDatas.get(0).getCondition()); + } +// logger.info(formId+"param聚合参数:"+(param!=null?JSON.toJSONString(param):"NULL")); +// logger.info(formId+"filterFormDatas聚合参数:"+(filterFormDatas!=null?JSON.toJSONString(filterFormDatas):"NULL")); +// logger.info(formId+"fieldId聚合参数:"+fieldId); + if("count".equalsIgnoreCase(funcName)) { + if(module.equalsIgnoreCase(ModuleSource.biaoge.toString())){ + value=Double.valueOf(remoteFormReportService.countStatFormDatasForReportNum(param, filterFormDatas, null, employee)); + } else if(module.equalsIgnoreCase(ModuleSource.workflow.toString())){ +// value=Double.valueOf(remoteFlowDataStatQueryService.countStatFormDatasForFlowNum(param, filterFormDatas, employee)); + value = getFlowData(param, filterFormDatas, employee, formId); + } + }else { + if (module.equalsIgnoreCase(ModuleSource.workflow.toString())) { + value = remoteFlowFreeStatService.findFieldStatByField(param, filterFormDatas, + fieldId, funcName,employee); + } else if(module.equalsIgnoreCase(ModuleSource.biaoge.toString())){ + value = remoteReportFreeStatService.findFieldStatByField(param, filterFormDatas, + fieldId, funcName,employee); + } + } + logger.info(funcName+"聚合结果:"+value); + return value; + } + + @Override + public Double getCommonAggregateData(Long formId, Long fieldId, String funcName, List cndDataType, String moduleSource, SimpleEmployee employee) { + Double value=0d; + funcName=funcName.toLowerCase(); + List filterFormDatas=null; + List formulaFilterDataList=new ArrayList<>(); + for (int i=1;i paramFilterList=paramObj.getFormulaFilterDataList(); +// logger.info(JSON.toJSONString(paramFilterList)); + formulaFilterDataList.addAll(paramFilterList); + } + } + + //审批、上报使用老条件 + if(moduleSource.equalsIgnoreCase(ModuleSource.workflow.toString()) || moduleSource.equalsIgnoreCase(ModuleSource.biaoge.toString())){ + JSONArray jsonArray=JSON.parseArray(JSON.toJSONString(formulaFilterDataList)); + filterFormDatas=jsonArray.toJavaList(FilterFormData.class); +// logger.info("函数条件新转老结果:"+(JSON.toJSONString(filterFormDatas))); + } + logger.info("条件参数:"+JSON.toJSONString(filterFormDatas)); + Map param = assemblyParam(formId, employee); + if(filterFormDatas != null && filterFormDatas.size() > 0) { + param.put("condition", StringUtils.isEmpty(filterFormDatas.get(0).getCondition())?"AND":filterFormDatas.get(0).getCondition()); + } + if(formulaFilterDataList !=null && formulaFilterDataList.size()>0){ + param.put("condition", StringUtils.isEmpty(formulaFilterDataList.get(0).getCondition())?"AND":formulaFilterDataList.get(0).getCondition()); + } + + + if(moduleSource.equalsIgnoreCase(ModuleSource.workflow.toString())){ + if("count".equalsIgnoreCase(funcName)) { + value = getFlowData(param, filterFormDatas, employee, formId); + }else { +// value = freeStatAssistService.buildFreeStatService("workflow").findFieldStatByField(param, filterFormDatas, +// fieldId, funcName,employee); + List filterFormDataParamList=filterFormDataSearchService.conversionOldFilterFormDataToNew(filterFormDatas,employee); + logger.info("conversionOldFilterFormDataToNew函数统计转换条件:"+JSON.toJSONString(filterFormDataParamList)); + Map aggResultMap= null; + try { + WeaverSentinelContext.setDowngradeType(false); + aggResultMap = wfcReportStatRest.findFieldCalculateByCondition(formId,fieldId,filterFormDataParamList,funcName,employee); + } catch (RpcException e) { + logger.error("err",e); + if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { + //降级逻辑编写 + logger.error("审批服务不可用"); + } + } + logger.info("审批新统计结果:"+JSON.toJSONString(aggResultMap)); + Object aggResultObject=aggResultMap.get(funcName.toLowerCase()); + if(aggResultObject!=null){ + BigDecimal bigDecimal=new BigDecimal(aggResultObject+""); + value=bigDecimal.doubleValue(); + } + } + logger.info("审批聚合结果:"+value); + }else if(moduleSource.equalsIgnoreCase(ModuleSource.biaoge.toString())){ + ExcelResult excelResult= null; + try { + WeaverSentinelContext.setDowngradeType(false); + excelResult = remoteExcelService.aggregation(AggFunc.valueOf(funcName.toLowerCase()),formId+"",fieldId+"",formulaFilterDataList,null,employee); + } catch (IllegalArgumentException e) { + logger.error("err",e); + }catch (RpcException e){ + logger.error("err",e); + if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { + //降级逻辑编写 + logger.error("上报服务不可用"); + } + } + try { + value=Double.parseDouble(excelResult.getData()+""); + } catch (NumberFormatException e) { + logger.error("err",e); + } + logger.info("上报聚合结果:"+JSON.toJSONString(excelResult)); + }else if(moduleSource.equalsIgnoreCase("hrmsalary")){ + ExcelResult excelResult= null; + try { + excelResult = remoteExcelServiceHrmSalary.aggregation(AggFunc.valueOf(funcName.toLowerCase()),formId+"",fieldId+"",formulaFilterDataList,null,employee); + } catch (IllegalArgumentException e) { + logger.error("err",e); + }catch (RpcException e){ + logger.error("err",e); + if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { + //降级逻辑编写 + logger.error("薪酬服务不可用"); + } + } + try { + value=Double.parseDouble(excelResult.getData()+""); + } catch (NumberFormatException e) { + logger.error("err",e); + } + logger.info("薪酬聚合结果:"+JSON.toJSONString(excelResult)); + } + return value; + } + + /** + * 根据表单参数查询审批数据量 + * @param paramMap + * @param filterFormDatas + * @param employee + * @return + */ + private Double getFlowData(Map paramMap, List filterFormDatas, SimpleEmployee employee, Long formId) { + List datas =null; + FormDataOption formDataOption=new FormDataOption(); + Page pageDatas=new Page(); + + JSONObject filter=new JSONObject(); + JSONArray filterArray=JSON.parseArray(JSON.toJSONString(filterFormDatas)); + + for(int i=0;i weaResult= null; + try { + WeaverSentinelContext.setDowngradeType(false); + weaResult = wflSearchConditionRest.convertCondition(cndString); +// weaResult = wfcSearchConditionRest.convertCondition(cndString); + } catch (RpcException e) { + if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { + //降级逻辑编写 + logger.error("审批服务不可用"); + logger.error("err",e); + } + } + JSONObject flowJson=JSON.parseObject(weaResult.getData()); + JSONObject formDatas=new JSONObject(); + formDatas.put("formDatas",flowJson); + cndString=formDatas.toJSONString(); + logger.error("转换审批条件后:"+cndString); + RequestListSearchConditionEntity listSearchCondition =new RequestListSearchConditionEntity(); + JSONObject newFlowCndJson=JSON.parseObject(cndString); + if(paramMap != null) listSearchCondition = newFlowCndJson.toJavaObject(RequestListSearchConditionEntity.class); + if(paramMap.get("condition")!=null){ + listSearchCondition.setType(paramMap.get("condition")+""); + } + logger.info("JSON转换成审批条件对象:"+(listSearchCondition!=null?JSON.toJSONString(listSearchCondition):"NULL")); + //listSearchCondition.setType(paramMap.get("condition")!=null?paramMap.get("condition")+"":"AND"); + com.weaver.common.component.table.page.Page page = new com.weaver.common.component.table.page.Page(1, 10); + page.setSize(Integer.MAX_VALUE); + paramMap.put("isAdmin",true); + paramMap.remove("filterFormDatas"); + logger.error("函数执行条件paramMap:"+JSON.toJSONString(paramMap)); + Long flowCount = wflRequestListFormRest.getFormFilterRequestCount(paramMap, formId, listSearchCondition, employee); + if(flowCount==null){ + flowCount=0L; + } + return flowCount.doubleValue(); +// List tempDatas=wfcRequestListFormRest.getFormFilterRequestDatasByWfId(paramMap,formId,listSearchCondition,page,employee); +// List tempDatas=wfcRequestListFormRpc.getFormFilterRequestDatas(paramMap,formId,listSearchCondition,page,employee); +// return new Double(tempDatas.size()); + } + + // 封装高级搜索参数 + private Map assemblyParam(Long formId, SimpleEmployee employee) { + Map param = new HashMap(); + + param.put("employeeId", employee.getUserId()); + param.put("formId", formId); // 表单id + param.put("isAdmin", true); // 统计默认有管理元权限 + param.put("status", FormDataStatus.submit.toString()); // 统计默认有管理元权限 + + return param; + } + + + public FreeFormService bulidFreeFormService(ModuleSource module) { + return freeFormAssistService.buildFreeFormService(module.toString()); + } + + @Override + public Map bulidDataType(List fieldIds, FormData formData, String module, + SimpleEmployee employee) { + Map dataMap = new HashMap(); + if(fieldIds != null && fieldIds.size() > 0 && formData != null) { + List dataDetails = formData.getDataDetails(); + Map> dataDetailMap = new HashMap>(); + if(dataDetails != null && dataDetails.size() > 0) { + for(FormDataDetail dataDetail : dataDetails) { + if(dataDetailMap.containsKey(dataDetail.getFormField().getId())) { + dataDetailMap.get(dataDetail.getFormField().getId()).add(dataDetail); + }else { + List values = new ArrayList(); + values.add(dataDetail); + dataDetailMap.put(dataDetail.getFormField().getId(), values); + } + + } + } + Map fieldMap = bulidFreeFormService(ModuleSource.valueOf(module)).getFieldMapByFormId(formData.getForm().getId(), employee); + for(String field : fieldIds) { + Long fieldId = Long.parseLong(field); + FormField formField = fieldMap.get(fieldId); + if(formField != null) { + DataType dataType = new DataType(); + dataType.setFieldId(field); + dataType.setDataType(getDataType(formField.getComponentKey())); + if(dataDetailMap.containsKey(fieldId)) { + dataType.setContent(getDetailValue(dataDetailMap.get(fieldId))); + dataType.setText(getDetailContent(dataDetailMap.get(fieldId))); + if( ComponentType.RadioBox.toString().equals(formField.getComponentKey()) + || ComponentType.CheckBox.toString().equals(formField.getComponentKey()) + || ComponentType.Select.toString().equals(formField.getComponentKey())) { + dataType.setScore(getDetailScore(dataDetailMap.get(fieldId),ModuleSource.valueOf(module),formData.getFormLayout().getId(),employee)); + } + }else { + dataType.setContent(""); + dataType.setText(""); + } + dataMap.put(field, dataType); + } + } + } + return dataMap; + } + + private Double getDetailScore(List dataDetails, ModuleSource module,Long layoutId,SimpleEmployee employee) { + Double score =0d; + for (FormDataDetail formDataDetail :dataDetails){ + score=excelTransUtil.getDetailScore(formDataDetail,module,layoutId,employee); + } +// if(dataDetails != null && dataDetails.size() > 0) { +// FormDataDetail dataDetail = dataDetails.get(0); +// if(dataDetail != null) { +// score = bulidFreeFormService(module).getOptionScore(dataDetail.getFormField().getId()+"", layoutId, dataDetail, employee).doubleValue(); +// } +// } + return score; + } + + private String getDetailValue(List dataDetails) { + String content =""; + if(dataDetails != null && dataDetails.size() > 0) { + FormDataDetail dataDetail = dataDetails.get(0); + if(dataDetail != null) { + content = dataDetail.getContent() == null ? "" : dataDetail.getContent(); // 字段新数据 + FormDataText formDataText = dataDetail.getDataText(); + if (formDataText != null) { // 如果是多行文本框 + content = formDataText.getContent(); + } + List optDetails = dataDetail.getDataOptions(); // 填写选项明细 + if ((optDetails != null) && (optDetails.size() > 0)) {// 如果是选项类型控件 + for (FormDataOption formDataOption : optDetails) { + content += formDataOption.getOptionId()+","; + } + if ((content != null) && (content.length() > 0)) { + content = content.substring(0, content.length() - 1); // 去掉最后一个逗号 + } + } + } + } + return content; + } + + private String getDetailContent(List dataDetails) { + String content =""; + if(dataDetails != null && dataDetails.size() > 0) { + FormDataDetail dataDetail = dataDetails.get(0); + if(dataDetail != null) { + content = dataDetail.getContent() == null ? "" : dataDetail.getContent(); // 字段新数据 + FormDataText formDataText = dataDetail.getDataText(); + if (formDataText != null) { // 如果是多行文本框 + content = formDataText.getContent(); + } + List optDetails = dataDetail.getDataOptions(); // 填写选项明细 + if ((optDetails != null) && (optDetails.size() > 0)) {// 如果是选项类型控件 + for (FormDataOption formDataOption : optDetails) { + content += formDataOption.getContent() + ","; + } + if ((content != null) && (content.length() > 0)) { + content = content.substring(0, content.length() - 1); // 去掉最后一个逗号 + } + } + } + } + return content; + } + + /** + * 检查控件类型 + * @param componentKey + * @return + */ + @Override + public String getDataType(String componentKey){ + DataType dataType = new DataType(); + if(ComponentConfig.isNumberComponent(componentKey)) { + return DataType.NUMBER; + }else if(ComponentConfig.isOptionComponent(componentKey)) { + return DataType.OPTION; + }else if(componentKey.equals(ComponentType.DateComponent.toString())) { + return DataType.STRING; + }else { + return DataType.STRING; + } + } + + @Override + public Map buildFilterParam(ExpressFormula dataExpressFormula, Long targetFormId, SimpleEmployee employee, FormData formData, String module) { + String moduleStr=module.toString(); + FormulaContext.get().setValue(moduleStr); + + Map expressMap=new HashMap<>(); + Map paramMap = Maps.newHashMap(); + if(dataExpressFormula==null) throw new RuntimeException("公式不存在"); + + try { + JSONObject paramJson= JSON.parseObject(dataExpressFormula.getParameter()); + List varList=null; + if(dataExpressFormula.getParameter()!=null){ + JSONArray paramArray=paramJson.getJSONArray("formulavars"); + varList=paramArray.toJavaList(FormulaVar.class); + List fieldIds=new ArrayList<>(); + for(FormulaVar formulaVar:varList){ + if(formulaVar.getFieldId()!=null&&formulaVar.getOptionId()==null&&!formulaVar.getFormId().equalsIgnoreCase(targetFormId.toString())){ + fieldIds.add(formulaVar.getFieldId().toString()); + } + } + + Map dataTypeMap=bulidDataType(fieldIds,formData,module,employee); + for(FormulaVar formulaVar:varList){ + if(formulaVar.getFieldId()!=null&&dataTypeMap.containsKey(formulaVar.getFieldId().toString())){ + DataType dataType=dataTypeMap.get(formulaVar.getFieldId().toString()); + if(formulaVar.getFormId()!=null){ + dataType.setFormId(Long.parseLong(formulaVar.getFormId())); + } + + try { + dataType.setModule(formulaVar.getModule()); + } catch (IllegalArgumentException e) { + logger.error("err",e); + dataType.setModule(formulaVar.getModule()); + } + dataType.setEmployee(employee); + if(formulaVar.getName()!=null){ + if(dataType.getContent()==null){ + dataType.setContent(formulaVar.getOptionId()); + } + if(dataType.getText()==null){ + dataType.setText(formulaVar.getName()); + } + } + expressMap.put(formulaVar.getKey(),dataType); + }else{ + DataType dataType=new DataType(); + + if(formulaVar.getKey().equals("current_operator")){ + dataType.setContent(employee.getId()); + dataType.setText(employee.getUsername()); + dataType.setDataType(DataType.OPTION); + expressMap.put(formulaVar.getKey(),dataType); + }else if(formulaVar.getOptionId()!=null){ + dataType.setDataType(DataType.OPTION); + dataType.setContent(formulaVar.getOptionId()); + dataType.setText(formulaVar.getName()); + expressMap.put(formulaVar.getKey(),dataType); + }else { + dataType.setContent(formulaVar.getFormId()); + try { + dataType.setModule(formulaVar.getModule()); + } catch (IllegalArgumentException e) { + logger.error("err",e); + dataType.setModule(formulaVar.getModule()); + } + dataType.setEmployee(employee); + } + dataType.setFormId(formulaVar.getFormId()!=null?Long.parseLong(formulaVar.getFormId()):null); + expressMap.put(formulaVar.getKey(),dataType); + } + } + + List paramDatas=paramJson.getJSONArray("formulavars").toJavaList(FormulaVar.class); + String filterGenFormula= ExcelParamUtil.replaceAllParam(dataExpressFormula.getFormula(),paramDatas); + filterGenFormula= ExcelParamUtil.spliteSql(filterGenFormula,expressMap); + filterGenFormula=filterGenFormula.replaceAll("\\{",""); + filterGenFormula=filterGenFormula.replaceAll("\\}",""); + paramMap=this.buildCndFilter(targetFormId,null,filterGenFormula,expressMap,module,employee); + } + } catch (Exception e) { + logger.error("err",e); + } + return paramMap; + } + +} diff --git a/src/com/engine/salary/formlua/data/func/EqOperator.java b/src/com/engine/salary/formlua/data/func/EqOperator.java new file mode 100644 index 000000000..83ef15e15 --- /dev/null +++ b/src/com/engine/salary/formlua/data/func/EqOperator.java @@ -0,0 +1,117 @@ +package com.engine.salary.formlua.data.func; + +import com.ql.util.express.Operator; +import com.weaver.common.form.component.base.ComponentConfig; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.common.form.excel.validator.Validator; +import com.weaver.common.form.metadata.field.FormField; +import com.weaver.common.form.stat.FilterFormData; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.teams.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; + + +/** + * equals转成筛选条件 + * @author Failymiss + */ +public class EqOperator extends Operator { + + private static final long serialVersionUID = -6647187680280498682L; + + + public Object executeInner(Object[] list) throws Exception { + Object obj=executeInner(list[0], list[1]); + return obj; + } + + public Object executeInner(Object obj1,Object obj2) throws Exception { + FilterFormData filterFormData = null; + String content = null; + FormField field = null; + if(checkParam(obj1, obj2)) { + field = (FormField) obj1; + if(obj2 instanceof DataType) { + content = ((DataType) obj2).getContent()+""; + }else { + content = obj2+""; + } + } + if (field != null && content != null) { + String componentKey = field.getComponentKey(); + filterFormData = new FilterFormData(); + filterFormData.setFieldId(field.getId()+""); + if(field.getSubForm() != null) { + filterFormData.setSubFormId(field.getSubForm().getId()+""); + } + filterFormData.setComponentKey(componentKey); + if(StringUtils.isEmpty(content)) { + filterFormData.setTerm(FilterFormData.TERM_NULL); + }else{ + filterFormData.setTerm(FilterFormData.TERM_EQ); + //数字类型 + if(ComponentConfig.isNumberComponent(componentKey) + || componentKey.equals(ComponentType.DateComponent.toString()) + || componentKey.equals(ComponentType.TimeComponent.toString())) { + filterFormData.setContent(content); + //选项控件 + }else if(ComponentConfig.isOptionComponent(componentKey)) { + List ids = new ArrayList<>(); + String[] idsArray = content.split(","); + for(String idStr : idsArray) { + if(StringUtils.isNotBlank(idStr)) { + ids.add(idStr); + } + } + filterFormData.setIds(ids); + //文本型 + }else { + filterFormData.setContent(content); + } + } + } + return filterFormData; + } + + private boolean checkParam(Object obj1,Object obj2) { + if(obj1 instanceof FormField) { + String componentKey = ((FormField) obj1).getComponentKey(); + if(ComponentConfig.isNumberComponent(componentKey)) { + if(obj2 instanceof DataType) { + if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)){ + return true; + }else { + throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); + } + }else if(StringUtils.isEmpty(obj2+"") || Validator.isFloat(obj2+"") ){ + return true; + }else { + throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); + } + }else if(ComponentConfig.isOptionComponent(componentKey)){ + if(StringUtils.isEmpty(obj2+"") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { + return true; + }else { + throw new RuntimeException("筛选条件[=]:选项控件右边必须是选项"); + } + } else { + if(StringUtils.isEmpty(obj2+"") || obj2 instanceof String || obj2 instanceof Character) { + return true; + }else if(obj2 instanceof DataType){ + if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ + return true; + }else if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ + return true; + }else { + throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); + } + }else { + throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); + } + } + } + throw new RuntimeException("筛选条件[=]:左边必须是表单控件"); + } +} \ No newline at end of file diff --git a/src/com/engine/salary/formlua/data/func/LessMoreOperator.java b/src/com/engine/salary/formlua/data/func/LessMoreOperator.java new file mode 100644 index 000000000..35cf47591 --- /dev/null +++ b/src/com/engine/salary/formlua/data/func/LessMoreOperator.java @@ -0,0 +1,115 @@ +package com.engine.salary.formlua.data.func; + +import com.alibaba.fastjson.JSON; +import com.ql.util.express.Operator; +import com.weaver.common.form.component.base.ComponentConfig; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.common.form.excel.validator.Validator; +import com.weaver.common.form.metadata.field.FormField; +import com.weaver.common.form.stat.FilterFormData; +import com.weaver.excel.formula.entity.parameter.DataType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * >= <= > < 转成筛选条件 + * @author Failymiss + */ +public class LessMoreOperator extends Operator{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final long serialVersionUID = -1001332992613137814L; + + public LessMoreOperator(String aName) { + this.name = aName; + } + + @Override + public Object executeInner(Object[] list) throws Exception { + + return executeInner(list[0], list[1]); + } + + private Object executeInner(Object obj1, Object obj2) { + FilterFormData filterFormData = null; + FormField field = null; + String content = null; + if(checkParam(obj1, obj2)) { + field = (FormField) obj1; + if(obj2 instanceof DataType) { + content = ((DataType) obj2).getContent()+""; + }else { + content = obj2+""; + } + } + if (field != null && content != null) { + String componentKey = field.getComponentKey(); + if(ComponentConfig.isNumberComponent(componentKey) + || componentKey.equals(ComponentType.DateComponent.toString()) + || componentKey.equals(ComponentType.TimeComponent.toString())) { + + filterFormData = new FilterFormData(); + filterFormData.setFieldId(field.getId()+""); + if(field.getSubForm() != null) { + filterFormData.setSubFormId(field.getSubForm().getId()+""); + } + filterFormData.setComponentKey(componentKey); + switch (this.name) { + case ">=": + filterFormData.setTerm(FilterFormData.TERM_GE); + break; + case ">": + filterFormData.setTerm(FilterFormData.TERM_GT); + break; + case "<=": + filterFormData.setTerm(FilterFormData.TERM_LE); + break; + case "<": + filterFormData.setTerm(FilterFormData.TERM_LT); + break; + default: + break; + } + filterFormData.setContent(content); + } + } + return filterFormData; + } + + private boolean checkParam(Object obj1,Object obj2) { + logger.info("聚合函数校验,第一个参数:"+ JSON.toJSONString(obj1)); + logger.info("聚合函数校验,第二个参数:"+ JSON.toJSONString(obj2)); + if(obj1 instanceof FormField) { + String componentKey = ((FormField) obj1).getComponentKey(); + if(ComponentConfig.isNumberComponent(componentKey)) { + if(obj2 instanceof Number) { + return true; + }else if(obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)){ + return true; + }else { + throw new RuntimeException("筛选条件["+this.name+"]:数字控件右边必须是数字"); + } + } + if(componentKey.equals(ComponentType.DateComponent.toString())) { + if(obj2 instanceof String && Validator.isDate((String)obj2)) { + return true; + }else if(obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ + return true; + }else { + throw new RuntimeException("筛选条件["+this.name+"]:日期控件右边必须是日期字符串"); + } + + } + if(componentKey.equals(ComponentType.TimeComponent.toString())) { + if(obj2 instanceof String && Validator.isTime((String)obj2)) { + return true; + }else if(obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING) ){ + return true; + }else { + throw new RuntimeException("筛选条件["+this.name+"]:时间控件右边必须是时间字符串"); + } + } + } + throw new RuntimeException("筛选条件["+this.name+"]:左边必须是数字控件或时间控件"); + } + +} diff --git a/src/com/engine/salary/formlua/data/func/LogicFunc.java b/src/com/engine/salary/formlua/data/func/LogicFunc.java new file mode 100644 index 000000000..655aaf249 --- /dev/null +++ b/src/com/engine/salary/formlua/data/func/LogicFunc.java @@ -0,0 +1,99 @@ +package com.engine.salary.formlua.data.func; + +import com.weaver.common.form.component.base.ComponentConfig; +import com.weaver.common.form.metadata.field.FormField; +import com.weaver.common.form.stat.FilterFormData; +import com.weaver.excel.formula.entity.parameter.DataType; + +import java.util.ArrayList; +import java.util.List; + +public class LogicFunc { + + public static List and(Object... objs){ + List filterFormDatas = new ArrayList<>(); + if(objs != null && objs.length > 0) { + for(int i=0;i,>=,<,<=,LIKE,AND,OR'条件公式"); + } + } + } + return filterFormDatas; + } + + /** + * + * @param objs + * @return + */ + public static List or(Object... objs){ + List filterFormDatas = new ArrayList<>(); + if(objs != null && objs.length > 0) { + for(int i=0;i,>=,<,<=,LIKE,AND,OR'条件公式"); + } + } + } + return filterFormDatas; + } + + /** + * 支持文本、数字、日期 + * @param formField + * @param strs + * @return + */ + public static FilterFormData like(FormField formField,Object[] strs){ + if(formField != null && strs.length > 0) { + if(ComponentConfig.isOptionComponent(formField.getComponentKey())) { + throw new RuntimeException("筛选条件函数[LIKE]:第一个参数不能是选项控件"); + } + FilterFormData filterFormData = new FilterFormData(); + List contents = new ArrayList(); + for(Object str : strs) { + contents.add(str+""); + } + filterFormData.setContents(contents); + filterFormData.setTerm(FilterFormData.TERM_LIKE); + filterFormData.setFieldId(formField.getId()+""); + return filterFormData; + }else { + throw new RuntimeException("筛选条件函数[LIKE]:参数异常"); + } + } + + /** + * 仅支持选项型控件 + * @param formField + * @param options + * @return + */ + public static FilterFormData in(FormField formField,DataType[] options){ + if(formField != null && options.length > 0) { + if(!ComponentConfig.isOptionComponent(formField.getComponentKey())) { + throw new RuntimeException("筛选条件函数[IN]:第一个参数必须选项控件"); + } + FilterFormData filterFormData = new FilterFormData(); + List ids = new ArrayList(); + for(DataType option : options) { + ids.add(option.getContent()+""); + } + filterFormData.setIds(ids); + filterFormData.setFieldId(formField.getId()+""); + filterFormData.setTerm(FilterFormData.TERM_EQ); + return filterFormData; + }else { + throw new RuntimeException("筛选条件函数[IN]:参数异常"); + } + } +} diff --git a/src/com/engine/salary/formlua/data/func/NotEqOperator.java b/src/com/engine/salary/formlua/data/func/NotEqOperator.java new file mode 100644 index 000000000..494e291a8 --- /dev/null +++ b/src/com/engine/salary/formlua/data/func/NotEqOperator.java @@ -0,0 +1,112 @@ +package com.engine.salary.formlua.data.func; + +import com.ql.util.express.Operator; +import com.weaver.common.form.component.base.ComponentConfig; +import com.weaver.common.form.excel.validator.Validator; +import com.weaver.common.form.metadata.field.FormField; +import com.weaver.common.form.stat.FilterFormData; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.teams.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; + + +/** + * equals转成筛选条件 + * @author Failymiss + */ +public class NotEqOperator extends Operator { + + private static final long serialVersionUID = -6647187680280498682L; + + public Object executeInner(Object[] list) throws Exception { + return executeInner(list[0], list[1]); + } + + public Object executeInner(Object obj1,Object obj2) throws Exception { + FilterFormData filterFormData = null; + String content = null; + FormField field = null; + if(checkParam(obj1, obj2)) { + field = (FormField) obj1; + if(obj2 instanceof DataType) { + content = ((DataType) obj2).getContent()+""; + }else { + content = obj2+""; + } + } + if (field != null && content != null) { + String componentKey = field.getComponentKey(); + filterFormData = new FilterFormData(); + filterFormData.setFieldId(field.getId()+""); + if(field.getSubForm() != null) { + filterFormData.setSubFormId(field.getSubForm().getId()+""); + } + filterFormData.setComponentKey(componentKey); + if(StringUtils.isEmpty(content)) { + filterFormData.setTerm(FilterFormData.TERM_NOT_NULL); + }else{ + //选项控件 + if(ComponentConfig.isOptionComponent(componentKey)) { + filterFormData.setTerm(FilterFormData.TERM_NOT_EQ); + List ids = new ArrayList<>(); + String[] idsArray = content.split(","); + for(String idStr : idsArray) { + if(StringUtils.isNotBlank(idStr)) { + ids.add(idStr); + } + } + filterFormData.setIds(ids); + //其他 + }else { + filterFormData.setTerm(FilterFormData.TERM_NOT_EQ); + filterFormData.setContent(content); + } + } + } + return filterFormData; + } + + private boolean checkParam(Object obj1,Object obj2) { + if(obj1 instanceof FormField) { + String componentKey = ((FormField) obj1).getComponentKey(); + if(ComponentConfig.isNumberComponent(componentKey)) { + if(obj2 instanceof DataType) { + if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)){ + return true; + }else { + throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); + } + }else if(StringUtils.isEmpty(obj2+"") || Validator.isFloat(obj2+"") ){ + return true; + }else { + throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); + } + }else if(ComponentConfig.isOptionComponent(componentKey)){ + if(StringUtils.isEmpty(obj2+"") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { + return true; + }else { + throw new RuntimeException("筛选条件[!=]:选项控件右边必须是选项"); + } + } else { + if(StringUtils.isEmpty(obj2+"") || obj2 instanceof String || obj2 instanceof Character) { + return true; + }else if(obj2 instanceof DataType){ + if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING) ){ + return true; + }else if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ + return true; + }else if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ + return true; + }else { + throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); + } + }else { + throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); + } + } + } + throw new RuntimeException("筛选条件[!=]:左边必须是表单控件"); + } +} diff --git a/src/com/engine/salary/formlua/data/func/QLExpressContext.java b/src/com/engine/salary/formlua/data/func/QLExpressContext.java new file mode 100644 index 000000000..86cf3d8af --- /dev/null +++ b/src/com/engine/salary/formlua/data/func/QLExpressContext.java @@ -0,0 +1,47 @@ +package com.engine.salary.formlua.data.func; + + +import com.ql.util.express.IExpressContext; +import org.springframework.context.ApplicationContext; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("serial") +public class QLExpressContext extends HashMap implements + IExpressContext { + + private ApplicationContext context; + + public QLExpressContext(ApplicationContext aContext) { + this.context = aContext; + } + + public QLExpressContext(Map aProperties,ApplicationContext aContext) { + super(aProperties); + this.context = aContext; + } + + /** + * 抽象方法:根据名称从属性列表中提取属性值 + */ + public Object get(Object name) { + Object result = null; + result = super.get(name); + try { + if (result == null && this.context != null + && this.context.containsBean((String) name)) { + // 如果在Spring容器中包含bean,则返回String的Bean + result = this.context.getBean((String) name); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + return result; + } + + public Object put(String name, Object object) { + return super.put(name, object); + } + +} \ No newline at end of file diff --git a/src/com/engine/salary/formlua/data/func/QlExpressUtil.java b/src/com/engine/salary/formlua/data/func/QlExpressUtil.java new file mode 100644 index 000000000..8f254735d --- /dev/null +++ b/src/com/engine/salary/formlua/data/func/QlExpressUtil.java @@ -0,0 +1,148 @@ +package com.engine.salary.formlua.data.func; + +import com.ql.util.express.DynamicParamsUtil; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.weaver.common.form.metadata.field.FormField; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.FuncNames; +import com.weaver.excel.formula.func.aggregate.AggregationFunc; +import com.weaver.excel.formula.func.compare.WOperatorAdd; +import com.weaver.excel.formula.func.compare.WOperatorDiv; +import com.weaver.excel.formula.func.compare.WOperatorMulti; +import com.weaver.excel.formula.func.compare.WOperatorReduce; +import com.weaver.excel.formula.func.date.DateTimeService; +import com.weaver.excel.formula.func.logic.IfOperator; +import com.weaver.excel.formula.func.logic.LogicService; +import com.weaver.excel.formula.func.math.MathFuncsService; +import com.weaver.excel.formula.func.string.StringFormulaService; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 函数转换筛选条件类 + * @author Failymiss + */ +@Component +public class QlExpressUtil { + @Autowired + AggregationFunc aggregationFunc; + @Autowired + LogicService logicService; + @Autowired + DateTimeService dateTimeService; + @Autowired + StringFormulaService stringFormulaService; + @Autowired + MathFuncsService mathFuncsService; + + + private static ExpressRunner runner; + static { + runner = new ExpressRunner(true,false); + } + private static boolean isInitialRunner = false; + private ApplicationContext applicationContext;// spring上下文 + + /** + * + * @param statement + * 执行语句 + * @param context + * 上下文 + * @throws Exception + */ + public Object execute(String statement, Map context) + throws Exception { + DynamicParamsUtil.supportDynamicParams = true; + initRunner(runner); + IExpressContext expressContext = new QLExpressContext(context, + applicationContext); + return runner.execute(statement, expressContext, null, true, false); + } + + private void initRunner(ExpressRunner runner) { + if (isInitialRunner == true) { + return; + } + synchronized (runner) { + if (isInitialRunner == true) { + return; + } + try { + runner.replaceOperator("=",new EqOperator()); + runner.replaceOperator("==",new EqOperator()); + runner.replaceOperator("!=",new NotEqOperator()); + runner.replaceOperator(">=",new LessMoreOperator(">=")); + runner.replaceOperator(">",new LessMoreOperator(">")); + runner.replaceOperator("<=",new LessMoreOperator("<=")); + runner.replaceOperator("<",new LessMoreOperator("<")); + runner.addFunctionOfClassMethod("LIKE",LogicFunc.class.getName(),"like", new Class[] {FormField.class, Object[].class},""); + runner.addFunctionOfClassMethod("IN",LogicFunc.class.getName(),"in",new Class[] {FormField.class, DataType[].class},""); + runner.addFunctionOfClassMethod("AND",LogicFunc.class.getName(),"and",new Class[]{Object[].class},""); + runner.addFunctionOfClassMethod("OR",LogicFunc.class.getName(),"or",new Class[]{Object[].class},""); + + /**********************一下函数引入后不会构建成高级搜索条件***********************/ + + //字符串函数 + runner.addFunctionOfServiceMethod("CONCAT",stringFormulaService,"concatString",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("SEARCH",stringFormulaService,"search",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("TEXT",stringFormulaService,"text",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("PAD",stringFormulaService,"pad",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("REPLACE",stringFormulaService,"replace",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("VALUE",stringFormulaService,"value",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("LEN",stringFormulaService,"len",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("LEFT",stringFormulaService,"left",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("RIGHT",stringFormulaService,"right",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("MID",stringFormulaService,"mid",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("REPT",stringFormulaService,"repeat",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("TRIM",stringFormulaService,"trim",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("SCORE",stringFormulaService,"score",new Class[]{Object[].class},""); + + //数学函数 + runner.addFunctionOfServiceMethod("ROUNDUP",mathFuncsService,"roundUp",new Class[]{Object.class},""); + runner.addFunctionOfServiceMethod("ROUNDDOWN",mathFuncsService,"roundDown",new Class[]{Object.class},""); + + //日期函数 + runner.addFunctionOfServiceMethod( "DATEDIFF",dateTimeService,"dateDiff",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "DATEADD",dateTimeService,"dateAdd",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "YEAR",dateTimeService,"year",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "MONTH",dateTimeService,"month",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "DAY",dateTimeService,"day",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "HOUR",dateTimeService,"hour",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "MINUTE",dateTimeService,"minute",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "SECOND",dateTimeService,"seconds",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "WEEKNUM",dateTimeService,"weekNum",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "WEEKDAY",dateTimeService,"weekDay",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "NOW",dateTimeService,"now",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "TODAY",dateTimeService,"today",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod("DATEFORMAT",dateTimeService,"dateFormat",new Class[]{Object[].class},""); + + //逻辑函数 + runner.replaceOperator("IF",new IfOperator("IF")); + runner.addFunctionOfServiceMethod(FuncNames.TRUE.toString(),logicService,FuncNames.TRUE.getName(),new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod(FuncNames.FALSE.toString(),logicService,FuncNames.FALSE.getName(),new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod(FuncNames.ISEMPTY.toString(),logicService,FuncNames.ISEMPTY.getName(),new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod(FuncNames.NOT.toString(),logicService,FuncNames.NOT.getName(),new Class[]{Object[].class},""); + + runner.replaceOperator("+",new WOperatorAdd("+")); + runner.replaceOperator("-",new WOperatorReduce("-")); + runner.replaceOperator("*",new WOperatorMulti("*")); + runner.replaceOperator("/",new WOperatorDiv("/")); + + } catch (Exception e) { + throw new RuntimeException("初始化失败表达式"); + } + } + isInitialRunner = true; + } + + public void setApplicationContext(ApplicationContext aContext) + throws BeansException { + applicationContext = aContext; + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/DateAndString.java b/src/com/engine/salary/formlua/entity/parameter/DateAndString.java new file mode 100644 index 000000000..4e660c0af --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/DateAndString.java @@ -0,0 +1,5 @@ +package com.engine.salary.formlua.entity.parameter; + + +public class DateAndString { +} diff --git a/src/com/engine/salary/formlua/entity/parameter/ExcelFunc.java b/src/com/engine/salary/formlua/entity/parameter/ExcelFunc.java new file mode 100644 index 000000000..83d23af7f --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/ExcelFunc.java @@ -0,0 +1,138 @@ +package com.engine.salary.formlua.entity.parameter; + +import com.alibaba.fastjson.JSONObject; + + +public class ExcelFunc { + + private String name;//函数名称 + private String chineseName;//中文 + private String description;//函数描述 + private String formatString;//函数格式 + private String[] paramArray;//函数参数列表 + private String[] paramData;//参数默认数据 + private String returnType;//返回类型 + private String type="function";// + private String validForm;//有效的表单类型 current用户当前表单、all 用户所有表单 + private JSONObject jsonFormat; + private String module; + public ExcelFunc(){} + + /** + * + * @param name 名称 + * @param description 描述 + * @param formatString 格式 + * @param paramArray 参数列表 + * @param returnType 返回类型 + */ + public ExcelFunc(String name,String chineseName, String description, String formatString, String[] paramArray,String[] paramData, String returnType,JSONObject jsonFormat,String validForm) { + this.name = name; + this.chineseName=chineseName; + this.description = description; + this.formatString = formatString; + this.paramArray = paramArray; + this.returnType = returnType; + this.jsonFormat=jsonFormat; + this.paramData=paramData; + this.validForm=validForm; + } + public ExcelFunc(String name,String chineseName, String description, String formatString, String[] paramArray,String[] paramData, String returnType,String validForm) { + this.name = name; + this.chineseName=chineseName; + this.description = description; + this.formatString = formatString; + this.paramArray = paramArray; + this.returnType = returnType; + this.paramData=paramData; + this.validForm=validForm; + } + + public String getModule() { + return module; + } + + public void setModule(String module) { + this.module = module; + } + + public String getValidForm() { + return validForm; + } + + public void setValidForm(String validForm) { + this.validForm = validForm; + } + + public String getChineseName() { + return chineseName; + } + + public void setChineseName(String chineseName) { + this.chineseName = chineseName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getFormatString() { + return formatString; + } + + public void setFormatString(String formatString) { + this.formatString = formatString; + } + + public String[] getParamArray() { + return paramArray; + } + + public void setParamArray(String[] paramArray) { + this.paramArray = paramArray; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public JSONObject getJsonFormat() { + return jsonFormat; + } + + public void setJsonFormat(JSONObject jsonFormat) { + this.jsonFormat = jsonFormat; + } + + public String[] getParamData() { + return paramData; + } + + public void setParamData(String[] paramData) { + this.paramData = paramData; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java b/src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java new file mode 100644 index 000000000..92ddf028d --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java @@ -0,0 +1,495 @@ +package com.engine.salary.formlua.entity.parameter; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.weaver.common.i18n.label.SystemEnv; +import com.weaver.excel.formula.core.rpc.ExcelDubboInvoker; +import com.weaver.excel.formula.core.rpc.RemoteExcelExtendFuncService; +import com.weaver.excel.formula.core.rpc.RpcMethod; +import org.apache.commons.compress.utils.Lists; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + + +@Component +public class ExcelFuncs { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + final static private String ALLFORM="all"; + final static private String CURRENTDATA="current_data"; + static String normalStr="{\"key\":\"\",\"fieldId\":\"\",\"componentKey\":\"\",\"term\":\"\",\"formId\":\"\",\"content\":\"\",\"fieldType\":\"\"}"; + static public JSONObject normalJson= JSON.parseObject(normalStr); + static private String[] nullParamDatas=new String[]{}; + static private String[] paramDatas=new String[]{}; + static private String[] allParamDatas=new String[]{"{}","[]"}; + static private String[] moduleList=new String[]{"biaoge","workflow"}; + @Autowired + ExcelDubboInvoker excelDubboInvoker; + + @Autowired + private FuncDescUtil funcDescUtil; + public List getCompList(){ + //比较操作符 + List compList=new LinkedList<>(); + ExcelFunc excelFunc=null; + String [] paramArray=new String[]{}; + excelFunc=new ExcelFunc(">",SystemEnv.getHtmlLabelName(12132,"大于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + compList.add(excelFunc); + + excelFunc=new ExcelFunc(">=",SystemEnv.getHtmlLabelName(27694,"大于等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + compList.add(excelFunc); + + excelFunc=new ExcelFunc("<",SystemEnv.getHtmlLabelName(20009,"小于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + compList.add(excelFunc); + + excelFunc=new ExcelFunc("<=",SystemEnv.getHtmlLabelName(15251,"小于等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + compList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("=",SystemEnv.getHtmlLabelName(15112,"等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + compList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("!=",SystemEnv.getHtmlLabelName(14897,"不等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + compList.add(excelFunc); + + return compList; + } + + /** + * 日期函数的列表 + * @return + */ + public List getDateList(){ + //日期函数 + List dateList=new LinkedList<>(); + ExcelFunc excelFunc=null; + String [] paramArray=new String[]{}; + excelFunc=new ExcelFunc("TODAY",SystemEnv.getHtmlLabelName(94924,"当前日期"), funcDescUtil.get("TODAY"),"TODAY()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("NOW",SystemEnv.getHtmlLabelName(94925,"当前日期时间"), funcDescUtil.get("NOW"),"NOW()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("DATEADD",SystemEnv.getHtmlLabelName(94926,"对日期加减年、月、日"), funcDescUtil.get("DATEADD"),"DATEADD(日期, 数值, ['单位'])",nullParamDatas,paramArray,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("DATEDIFF",SystemEnv.getHtmlLabelName(94927,"返回两个日期的差值"), funcDescUtil.get("DATEDIFF"),"DATEDIFF(日期1, 日期2, ['单位'])",nullParamDatas,paramArray,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("DATEFORMAT",SystemEnv.getHtmlLabelName(94928,"返回指定格式的日期"), funcDescUtil.get("DATEFORMAT"),"DATEFORMAT(日期, '可选格式')",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("YEAR",SystemEnv.getHtmlLabelName(94929,"返回日期中的年"), funcDescUtil.get("YEAR"),"YEAR(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{"String"}; + excelFunc=new ExcelFunc("MONTH",SystemEnv.getHtmlLabelName(94930,"返回日期中的月"), funcDescUtil.get("MONTH"),"MONTH(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("DAY",SystemEnv.getHtmlLabelName(94931,"返回日期中的日"), funcDescUtil.get("DAY"),"DAY(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("HOUR",SystemEnv.getHtmlLabelName(94932,"返回日期中的小时"), funcDescUtil.get("HOUR"),"HOUR(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("MINUTE",SystemEnv.getHtmlLabelName(94933,"返回日期中的分钟"), funcDescUtil.get("MINUTE"),"MINUTE(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("SECOND",SystemEnv.getHtmlLabelName(94934,"返回日期中的秒"), funcDescUtil.get("SECOND"),"SECOND(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("WEEKNUM",SystemEnv.getHtmlLabelName(94936,"返回日期为第几周"), funcDescUtil.get("WEEKNUM"),"WEEKNUM(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("WEEKDAY",SystemEnv.getHtmlLabelName(94937,"返回日期为星期几"), funcDescUtil.get("WEEKDAY"),"WEEKDAY(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("NETWORKDAYSPI",SystemEnv.getHtmlLabelName(94938,"返回指定日期之间包含的工作日天数(仅限的过去时间)"), funcDescUtil.get("NETWORKDAYSPI"),"NETWORKDAYSPI(日期1, 日期2, 成员)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("EOMONTH",SystemEnv.getHtmlLabelName(94939,"返回某月最后一天日期"), funcDescUtil.get("EOMONTH"),"EOMONTH(日期,指定日期之前或之后的月数)",paramArray,nullParamDatas,"Number",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("CURRYEAR",SystemEnv.getHtmlLabelName(101059,"返回当前年份"), funcDescUtil.get("CURRYEAR"),"CURRYEAR()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("CURRMONTH",SystemEnv.getHtmlLabelName(101060,"返回当前月份"), funcDescUtil.get("CURRMONTH"),"CURRMONTH()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("CURRDAY",SystemEnv.getHtmlLabelName(101061,"返回当前第几日(当月)"), funcDescUtil.get("CURRDAY"),"CURRDAY()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("CURRWEEK",SystemEnv.getHtmlLabelName(101062,"返回当前是周几"), funcDescUtil.get("CURRWEEK"),"CURRWEEK()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("CURRHOUR",SystemEnv.getHtmlLabelName(101063,"返回当前小时"), funcDescUtil.get("CURRHOUR"),"CURRHOUR()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("CURRMINUTE",SystemEnv.getHtmlLabelName(101064,"返回当前分"), funcDescUtil.get("CURRMINUTE"),"CURRMINUTE()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("CURRSECOND",SystemEnv.getHtmlLabelName(101065,"返回当前秒"), funcDescUtil.get("CURRSECOND"),"CURRSECOND()",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + paramArray=new String[]{}; + excelFunc=new ExcelFunc("MAXDATE",SystemEnv.getHtmlLabelName(100803,"返回一组日期中的最大值"), funcDescUtil.get("MAXDATE"),"MAXDATE(日期1,日期2,……)",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("MINDATE",SystemEnv.getHtmlLabelName(100805,"返回一组日期中的最小值"), funcDescUtil.get("MINDATE"),"MINDATE(日期1,日期2,……)",paramArray,nullParamDatas,"String",CURRENTDATA); + dateList.add(excelFunc); + return dateList; + } + + /** + * 逻辑函数的列表 + * @return + */ + public List getLogicList(){ + //逻辑函数 + List logicList=new LinkedList<>(); + ExcelFunc excelFunc=null; + String [] paramArray=new String[]{}; + excelFunc=new ExcelFunc("IF",SystemEnv.getHtmlLabelName(94940,"如果条件为真,则...否则..."), funcDescUtil.get("IF"),"IF(条件, 表达式1, 表达式2)",paramArray,nullParamDatas,"Object",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("AND",SystemEnv.getHtmlLabelName(51100,"且"), funcDescUtil.get("AND"),"AND(条件1, 条件2, [条件3, …])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("OR",SystemEnv.getHtmlLabelName(35824,"或"), funcDescUtil.get("OR"),"OR(条件1, 条件2, [条件3, …])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("NOT",SystemEnv.getHtmlLabelName(94942,"反转真假结果"), funcDescUtil.get("NOT"),"NOT(逻辑结果)",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("IN",SystemEnv.getHtmlLabelName(94943,"变量是否包含在一组结果中"), funcDescUtil.get("IN"),"IN(变量, [变量1, 变量2, …])",paramArray,allParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("LIKE",SystemEnv.getHtmlLabelName(94944,"文本是否包含任意一个关键字"), funcDescUtil.get("LIKE"),"LIKE(文本, [文本1, 文本2, …])",paramArray,allParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("ISEMPTY",SystemEnv.getHtmlLabelName(94945,"是否为空"), funcDescUtil.get("ISEMPTY"),"ISEMPTY(变量)",paramArray,paramDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("TRUE",SystemEnv.getHtmlLabelName(94946,"返回真"), funcDescUtil.get("TRUE"),"TRUE()",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("FALSE",SystemEnv.getHtmlLabelName(94947,"返回假"), funcDescUtil.get("FALSE"),"FALSE()",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("IFS",SystemEnv.getHtmlLabelName(94948,"多条件"), funcDescUtil.get("IFS"),"IFS({条件1},{结果1},{条件2},{结果2}...{默认结果})",paramArray,nullParamDatas,"Object",CURRENTDATA); + logicList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("FIND",SystemEnv.getHtmlLabelName(31835,"查找"), funcDescUtil.get("FIND"),"FIND([{查找值1},{查找值2}...{查找值N}],[{查找目标1},{查找目标2}...{查找目标N}])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + logicList.add(excelFunc); + return logicList; + } + + /** + * 字符函数的列表 + * @return + */ + public List getStringList(){ + //字符函数 + List stringList=new LinkedList<>(); + ExcelFunc excelFunc=null; + String [] paramArray=new String[]{}; + excelFunc=new ExcelFunc("CONCAT",SystemEnv.getHtmlLabelName(94949,"链接多个文本"), funcDescUtil.get("CONCAT"),"CONCAT(文本1, 文本2, [文本3, …])",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("TEXT",SystemEnv.getHtmlLabelName(94950,"将变量转为文本"), funcDescUtil.get("TEXT"),"TEXT(变量)",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("VALUE",SystemEnv.getHtmlLabelName(94951,"将文本转为数字"), funcDescUtil.get("VALUE"),"VALUE(文本)",paramArray,nullParamDatas,"Number",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("LEN",SystemEnv.getHtmlLabelName(94952,"返回文本长度"), funcDescUtil.get("LEN"),"LEN(文本)",paramArray,nullParamDatas,"Number",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("SEARCH",SystemEnv.getHtmlLabelName(94953,"在文本中查找关键字"), funcDescUtil.get("SEARCH"),"SEARCH(关键字, 文本, [搜索开始位置])",paramArray,nullParamDatas,"Number",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("REPLACE",SystemEnv.getHtmlLabelName(94954,"替换文本中的字"), funcDescUtil.get("REPLACE"),"REPLACE(原文本, 替换开始位置, 替换字符数, 新文本)",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("REPT",SystemEnv.getHtmlLabelName(94955,"将文本重复指定次数"), funcDescUtil.get("REPT"),"REPT(文本, 重复次数)",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("PAD",SystemEnv.getHtmlLabelName(94956,"将文本填充至指定长度"), funcDescUtil.get("PAD"),"PAD(原文本, 长度, 填充用的文本, ['填充位置'])",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("TRIM",SystemEnv.getHtmlLabelName(94957,"清除前后空格"), funcDescUtil.get("TRIM"),"TRIM(文本)",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("LEFT",SystemEnv.getHtmlLabelName(94958,"返回文本左侧开始的文字"), funcDescUtil.get("LEFT"),"LEFT(文本, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("RIGHT",SystemEnv.getHtmlLabelName(94959,"返回文本右侧开始的文字"), funcDescUtil.get("RIGHT"),"RIGHT(文本, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("MID",SystemEnv.getHtmlLabelName(94960,"返回文本指定位置开始的文字"), funcDescUtil.get("MID"),"MID(文本, 指定位置, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("SCORE",SystemEnv.getHtmlLabelName(94961,"获取选项型控件分数"), funcDescUtil.get("SCORE"),"SCORE({选项型控件})",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("IDCARD",SystemEnv.getHtmlLabelName(94962,"身份证函数"), funcDescUtil.get("IDCARD"),"IDCARD({身份证号码}, {查找类型})",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + + + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("ISSTRING",SystemEnv.getHtmlLabelName(0,"是否是字符串"), funcDescUtil.get("ISSTRING"),"ISSTRING({任意控件})",paramArray,nullParamDatas,"String",CURRENTDATA); + stringList.add(excelFunc); + +// paramArray=new String[]{}; +// excelFunc=new ExcelFunc("SUBSTRING",SystemEnv.getHtmlLabelName(97524,"字符截取函数"), funcDescUtil.get("SUBSTRING"),"SUBSTRING({源字符}, {截取开始位置},{截取结束位置})",paramArray,nullParamDatas,"String",CURRENTDATA); +// stringList.add(excelFunc); +// paramArray=new String[]{}; +// excelFunc=new ExcelFunc("SUBSTITUE",SystemEnv.getHtmlLabelName(97525,"字符查找替换函数"), funcDescUtil.get("SUBSTITUE"),"SUBSTITUE({源字符}, {被替换字符},{新字符})",paramArray,nullParamDatas,"String",CURRENTDATA); +// stringList.add(excelFunc); +// paramArray=new String[]{}; +// excelFunc=new ExcelFunc("LOWER",SystemEnv.getHtmlLabelName(97526,"字符转小写函数"), funcDescUtil.get("LOWER"),"LOWER({源字符})",paramArray,nullParamDatas,"String",CURRENTDATA); +// stringList.add(excelFunc); +// paramArray=new String[]{}; +// excelFunc=new ExcelFunc("UPPER",SystemEnv.getHtmlLabelName(97527,"字符转大写函数"), funcDescUtil.get("UPPER"),"UPPER({源字符})",paramArray,nullParamDatas,"String",CURRENTDATA); +// stringList.add(excelFunc); +// paramArray=new String[]{}; +// excelFunc=new ExcelFunc("EXACT",SystemEnv.getHtmlLabelName(97528,"字符比较函数"), funcDescUtil.get("EXACT"),"EXACT({字符1}, {字符2})",paramArray,nullParamDatas,"String",CURRENTDATA); +// stringList.add(excelFunc); + return stringList; + } + + /** + * 数学函数的列表 + * @return + */ + public List getMathList(){ + List mathList=new LinkedList<>(); + ExcelFunc excelFunc=null; + String [] paramArray=new String[]{}; + excelFunc=new ExcelFunc("ROUNDUP",SystemEnv.getHtmlLabelName(94963,"向上舍入"), funcDescUtil.get("ROUNDUP"),"ROUNDUP(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); + mathList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("ROUND",SystemEnv.getHtmlLabelName(17392,"四舍五入"), funcDescUtil.get("ROUND"),"ROUND(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); + mathList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("ROUNDDOWN",SystemEnv.getHtmlLabelName(94964,"向下舍入"), funcDescUtil.get("ROUNDDOWN"),"ROUNDDOWN(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); + mathList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("AGGREGATION",SystemEnv.getHtmlLabelName(94965,"聚合运算"), funcDescUtil.get("AGGREGATION"),"AGGREGATION({数字}...,{聚合运算类型})",paramArray,nullParamDatas,"Number",CURRENTDATA); + mathList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("MOD",SystemEnv.getHtmlLabelName(94966,"求余"), funcDescUtil.get("MOD"),"ROUNDDOWN({数字},{数字})",paramArray,nullParamDatas,"Number",CURRENTDATA); + mathList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("TRUNC",SystemEnv.getHtmlLabelName(94967,"数字格式化"), funcDescUtil.get("TRUNC"),"ROUNDDOWN({数字},{精度})",paramArray,nullParamDatas,"Number",CURRENTDATA); + mathList.add(excelFunc); + + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("ISINT",SystemEnv.getHtmlLabelName(0,"字符内容是否是整数"), funcDescUtil.get("ISINT"),"ISINT({字符})",paramArray,nullParamDatas,"String",CURRENTDATA); + mathList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("ISNUMBER",SystemEnv.getHtmlLabelName(0,"字符内容是否是数字"), funcDescUtil.get("ISNUMBER"),"ISNUMBER({字符})",paramArray,nullParamDatas,"String",CURRENTDATA); + mathList.add(excelFunc); + + return mathList; + + } + + /** + * 查找函数的列表 + * @return + */ + public List getFindList(){ + List findList=new LinkedList<>(); + ExcelFunc excelFunc=null; + String [] paramArray=new String[]{}; + excelFunc=new ExcelFunc("CHOOSE",SystemEnv.getHtmlLabelName(94968,"返回索引范围内指定的值"), funcDescUtil.get("CHOOSE"),"CHOOSE(数据源,[条件])",paramArray,nullParamDatas,"Array",CURRENTDATA); + findList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("VLOOKUPS",SystemEnv.getHtmlLabelName(94969,"按列查找,返回所需值"), funcDescUtil.get("VLOOKUPS"),"VLOOKUPS(表,[条件],[返回参数])",paramArray,nullParamDatas,"Array",CURRENTDATA); + findList.add(excelFunc); + + paramArray=new String[]{}; + excelFunc=new ExcelFunc("MATCH",SystemEnv.getHtmlLabelName(94970,"返回指定数值在指定数组区域中的位置"), funcDescUtil.get("MATCH"),"MATCH(值,[数组])",paramArray,nullParamDatas,"Number",CURRENTDATA); + findList.add(excelFunc); + return findList; + } + + /** + * 聚合函数 COUNT(表格, [统计条件]) + * @return + */ + public List getAggList(){ + List aggList=new LinkedList<>(); + ExcelFunc excelFunc=null; + + String [] paramArray=new String[]{"Form","Number","Boolean"}; + excelFunc=new ExcelFunc("COUNT", SystemEnv.getHtmlLabelName(16654,"计数"), funcDescUtil.get("COUNT"),"COUNT(表格)",paramArray,paramDatas,"Number",ALLFORM); + aggList.add(excelFunc); + + paramArray=new String[]{"Number","Number","Boolean"}; + excelFunc=new ExcelFunc("SUM",SystemEnv.getHtmlLabelName(95012,"求和") , funcDescUtil.get("SUM"),"SUM(数字字段)",paramArray,paramDatas,"Number",ALLFORM); + aggList.add(excelFunc); + + paramArray=new String[]{"Number","Number","Boolean"}; + excelFunc=new ExcelFunc("AVG",SystemEnv.getHtmlLabelName(19550,"平均值"), funcDescUtil.get("AVG"),"AVG(数字字段)",paramArray,paramDatas,"Number",ALLFORM); + aggList.add(excelFunc); + + paramArray=new String[]{"Number","Number","Boolean"}; + excelFunc=new ExcelFunc("MIN",SystemEnv.getHtmlLabelName(12318,"最小值"), funcDescUtil.get("MIN"),"MIN(表格)",paramArray,paramDatas,"Number",ALLFORM); + aggList.add(excelFunc); + + paramArray=new String[]{"Number","Number","Boolean"}; + excelFunc=new ExcelFunc("MAX",SystemEnv.getHtmlLabelName(66750,"最大值"), funcDescUtil.get("MAX"),"MAX(表格)",paramArray,paramDatas,"Number",ALLFORM); + aggList.add(excelFunc); + return aggList; + } + + /** + * 财务类函数列表 + * @return + */ + public Object getFinanceList(){ + ExcelFunc excelFunc = null; + List funcs = Lists.newArrayList(); + excelFunc = new ExcelFunc("GETMONEY",SystemEnv.getHtmlLabelName(0,"获取锁给定数字的金额大写"), funcDescUtil.get("GETMONEY"),"GETMONEY({数字})",null,nullParamDatas,"",CURRENTDATA); + funcs.add(excelFunc); + + return funcs; + } + /** + * 数据库函数列表 + * @return + */ + public Object getDataBaseList() { + ExcelFunc excelFunc = null; + List funcs = Lists.newArrayList(); + +// excelFunc = new ExcelFunc("GETHRMLOGINID",SystemEnv.getHtmlLabelName(100807,"返回指定人员系统账号"), funcDescUtil.get("GETHRMLOGINID"),"GETHRMLOGINID({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETHRMWORKCODE",SystemEnv.getHtmlLabelName(100809,"返回指定人员编号"), funcDescUtil.get("GETHRMWORKCODE"),"GETHRMWORKCODE({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETHRMMANAGER",SystemEnv.getHtmlLabelName(100811,"返回指定人员直接上级"), funcDescUtil.get("GETHRMMANAGER"),"GETHRMMANAGER({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETHRMALLMANAGER",SystemEnv.getHtmlLabelName(100813,"返回指定人员所有上级"), funcDescUtil.get("GETHRMALLMANAGER"),"GETHRMALLMANAGER({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETHRMDEPARTMENT",SystemEnv.getHtmlLabelName(100815,"返回指定人员部门"), funcDescUtil.get("GETHRMDEPARTMENT"),"GETHRMDEPARTMENT({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETHRMSUBCOMPANY",SystemEnv.getHtmlLabelName(100817,"返回指定人员分部"), funcDescUtil.get("GETHRMSUBCOMPANY"),"GETHRMSUBCOMPANY({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETDEPARTMENTNAME",SystemEnv.getHtmlLabelName(100819,"返回指定部门名称"), funcDescUtil.get("GETDEPARTMENTNAME"),"GETDEPARTMENTNAME({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETDEPARTMENTCODE",SystemEnv.getHtmlLabelName(100821,"返回指定部门编号"), funcDescUtil.get("GETDEPARTMENTCODE"),"GETDEPARTMENTCODE({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETSUPERDEPARTMENT",SystemEnv.getHtmlLabelName(100823,"返回指定部门直接上级部门"), funcDescUtil.get("GETSUPERDEPARTMENT"),"GETSUPERDEPARTMENT({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETALLSUPERDEPARTMENT",SystemEnv.getHtmlLabelName(100825,"返回指定部门所有上级部门"), funcDescUtil.get("GETALLSUPERDEPARTMENT"),"GETALLSUPERDEPARTMENT({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETSUBCOMPANYNAME",SystemEnv.getHtmlLabelName(100827,"返回指定分部名称"), funcDescUtil.get("GETSUBCOMPANYNAME"),"GETSUBCOMPANYNAME({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETSUBCOMPANYCODE",SystemEnv.getHtmlLabelName(100829,"返回指定分部编号"), funcDescUtil.get("GETSUBCOMPANYCODE"),"GETSUBCOMPANYCODE({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETSUPERSUBCOMPANY",SystemEnv.getHtmlLabelName(100831,"返回指定分部直接上级分部"), funcDescUtil.get("GETSUPERSUBCOMPANY"),"GETSUPERSUBCOMPANY({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); +// +// excelFunc = new ExcelFunc("GETALLSUPERSUBCOMPANY",SystemEnv.getHtmlLabelName(100833,"返回指定分部所有上级分部"), funcDescUtil.get("GETALLSUPERSUBCOMPANY"),"GETALLSUPERSUBCOMPANY({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// funcs.add(excelFunc); + + excelFunc = new ExcelFunc("GETHRMNAME",SystemEnv.getHtmlLabelName(100833,"获取人员名称"), funcDescUtil.get("GETHRMNAME"),"GETHRMNAME({人员})",null,nullParamDatas,"",CURRENTDATA); + funcs.add(excelFunc); + + excelFunc = new ExcelFunc("GETHRMMOBILE",SystemEnv.getHtmlLabelName(100833,"获取人员手机号码"), funcDescUtil.get("GETHRMMOBILE"),"GETHRMMOBILE({人员})",null,nullParamDatas,"",CURRENTDATA); + funcs.add(excelFunc); + + return funcs; + } + + public List getOtherFuncs(){ + List otherFuncs=new ArrayList<>(); + for(int i=0;i moduleFuncs=(List)result; + if(moduleFuncs.size()>0){ + otherFuncs.addAll(moduleFuncs); + } + } + } catch (Exception e) { + logger.error("err",e); + } + } + return otherFuncs; + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/FormulaContext.java b/src/com/engine/salary/formlua/entity/parameter/FormulaContext.java new file mode 100644 index 000000000..d51715e23 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/FormulaContext.java @@ -0,0 +1,35 @@ +package com.engine.salary.formlua.entity.parameter; + +import com.alibaba.fastjson.JSONObject; + + +public class FormulaContext { + public static ThreadLocal fmCtx=new ThreadLocal(); + + private JSONObject formulaJson=new JSONObject(); + + public static FormulaContext get(){ + if(null==fmCtx.get()){ + fmCtx.set(new FormulaContext()); + } + return fmCtx.get(); + } + + public JSONObject getFormulaJson() { + return formulaJson; + } + public void setValue(String func){ + if(formulaJson.getInteger(func)!=null){ + int i=formulaJson.getInteger(func)+1; + formulaJson.put(func,i); + }else { + formulaJson.put(func,1); + } + } + public Integer getValue(String func){ + return formulaJson.getInteger(func); + } + public void removeContext(){ + fmCtx.remove(); + } +} \ No newline at end of file diff --git a/src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java b/src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java new file mode 100644 index 000000000..1b0ea6889 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java @@ -0,0 +1,132 @@ +package com.engine.salary.formlua.entity.parameter; + +import com.weaver.common.i18n.label.SystemEnv; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + + +@Component +public class FuncDescUtil { + protected final Logger logger = LoggerFactory.getLogger(FuncDescUtil.class); + Map funcMap=new HashMap(); + public void initData(){ + //聚合函数 + funcMap.put("COUNT",SystemEnv.getHtmlLabelName(94986,"返回指定表格中满足条件的数据条数。示例:COUNT({员工表})")); + funcMap.put("SUM",SystemEnv.getHtmlLabelName(94987,"返回指定表格中满足条件的数据,其指定数字字段值的总和。统计条件中不可嵌套使用统计函数。示例:SUM({员工表.工资})")); + funcMap.put("AVG",SystemEnv.getHtmlLabelName(94988,"返回指定表格中满足条件的数据,其指定数字字段值的平均值。统计条件中不可嵌套使用统计函数。示例:AVG({员工表.工资})")); + funcMap.put("MIN",SystemEnv.getHtmlLabelName(94989,"返回指定表格中满足条件的数据,其指定数字字段值的最小值。统计条件中不可嵌套使用统计函数。示例:MIN({员工表.工资})")); + funcMap.put("MAX",SystemEnv.getHtmlLabelName(94990,"返回指定表格中满足条件的数据,其指定数字字段值的最大值。统计条件中不可嵌套使用统计函数。示例:MAX({员工表.工资})")); + //日期函数 + funcMap.put("TODAY",SystemEnv.getHtmlLabelName(97678,"返回当天日期。示例:TODAY() 结果: '2020-01-01'")); + funcMap.put("NOW",SystemEnv.getHtmlLabelName(97689,"返回当天日期+时间。示例:NOW() 结果: '2016-12-24 12:05:38'")); + funcMap.put("DATEADD",SystemEnv.getHtmlLabelName(97691,"对日期加减按照单位加减。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。示例:
DATEADD('2016-12-21', 3) 结果: '2016-12-24'
DATEADD('2016-12-24 20:00:00', 3, 'H') 结果: '2016-12-24 23:00:00'")); + funcMap.put("DATEDIFF",SystemEnv.getHtmlLabelName(97692,"根据指定的单位,返回日期2减去日期1的差值。当日期2小于日期1时,差值为负值。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。
示例:
DATEDIF('2016-12-21', '2016-12-24') 结果: 3
DATEDIF('2016-12-24 20:00:00', '2016-12-25 20:00:00', 'H') 结果: 24")); + funcMap.put("DATEFORMAT",SystemEnv.getHtmlLabelName(97693,"将日期转为指定格式返回。 示例:
DATEFORMAT('2016-12-24', 'YY年MM月DD日') 结果: 2016年12月24日
yyyy 将年份显示为1900-9999
yy 将年份显示为00-99
mm 将月份显示为 01–12
dd 将日期显示为 01–31")); + funcMap.put("YEAR",SystemEnv.getHtmlLabelName(97694,"返回指定日期中的年。示例:
YEAR('2016-12-24') 结果: 2016")); + funcMap.put("MONTH",SystemEnv.getHtmlLabelName(97695,"返回指定日期中的月。示例:
MONTH('2016-12-24') 结果: 12")); + funcMap.put("DAY",SystemEnv.getHtmlLabelName(97696,"返回指定日期中的日。示例:
DAY('2016-12-24') 结果: 24")); + funcMap.put("HOUR",SystemEnv.getHtmlLabelName(97697,"返回指定日期中的小时。示例:
HOUR('2016-12-24 20:30:56') 结果: 20")); + funcMap.put("MINUTE",SystemEnv.getHtmlLabelName(97698,"返回指定日期中的分钟。示例:
MINUTE('2016-12-24 20:30:56') 结果: 30")); + funcMap.put("SECOND",SystemEnv.getHtmlLabelName(97699,"返回指定日期中的秒钟。示例:
SECOND('2016-12-24 20:30:56') 结果: 56")); + funcMap.put("WEEKNUM",SystemEnv.getHtmlLabelName(97700,"返回指定日期为第几周,从每年第1天开始算第1周。示例:
WEEKNUM('2016-12-24') 结果: 52")); + funcMap.put("WEEKDAY",SystemEnv.getHtmlLabelName(97701,"返回指定日期为星期几。返回值为0~6,代表周日~周六。示例:
WEEKDAY('2016-12-24') 结果: 6")); + funcMap.put("EOMONTH",SystemEnv.getHtmlLabelName(97702,"将某月最后一天日期返回。日期可以为指定日期也可以是日期参数,之前的月数用负数表示,之后的月数用正数表示。所输入月数需为整数。
示例:EOMONTH('2021-11-07', -2)
结果:2021-09-30")); + funcMap.put("NETWORKDAYSPI",SystemEnv.getHtmlLabelName(97703,"将指定日期(仅限的过去时间,最大支持跨度为365天)之间包含的工作日天数返回。注意:此函数只能选择过去的时间才可使用,跨度不能超过365天。当日期2小于日期1时,差值为负值。单位默认为日。
示例:想知道李四在2021-11-07和2021-11-12之间的工作日天数。
NETWORKDAYSPI('2021-11-07', '2021-11-12','李四')
结果:5")); + funcMap.put("MAXDATE", SystemEnv.getHtmlLabelName(100804, "取一组日期中的最大值。示例:
MAXDATE('2016-12-24', '2022-12-24') 结果: 2022-12-24")); + funcMap.put("MINDATE", SystemEnv.getHtmlLabelName(100806, "取一组日期中的最小值。示例:
MINDATE('2016-12-24', '2022-12-24') 结果: 2016-12-24")); + //日期中的当前时间操作 + funcMap.put("CURRYEAR", SystemEnv.getHtmlLabelName(101066, "取当前日期的年份。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRYEAR() 结果: 2022")); + funcMap.put("CURRMONTH", SystemEnv.getHtmlLabelName(101067, "取当前日期的月份。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRMONTH() 结果: 2")); + funcMap.put("CURRDAY", SystemEnv.getHtmlLabelName(101068, "取当前日期的天。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRDAY() 结果: 17")); + funcMap.put("CURRWEEK", SystemEnv.getHtmlLabelName(101069, "取当前日期是周几。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRWEEK() 结果: 4")); + funcMap.put("CURRHOUR", SystemEnv.getHtmlLabelName(101070, "取当前日期的小时。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRHOUR() 结果: 11")); + funcMap.put("CURRMINUTE", SystemEnv.getHtmlLabelName(101071, "取当前日期的分钟。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRMINUTE() 结果: 20")); + funcMap.put("CURRSECOND", SystemEnv.getHtmlLabelName(101072, "取当前日期的秒钟。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRSECOND() 结果: 30")); + + //逻辑函数 + funcMap.put("IF",SystemEnv.getHtmlLabelName(97704,"如果条件为真,则执行表达式1,为假则执行表达式2。条件中不可嵌套使用IF函数。示例:
IF({员工表.年龄} > 60, '退休', '在职')、IF({员工表.年龄} > 60, IF({员工表.性别} = {员工表.性别.女}, '退休', '在职'), '在职')")); + funcMap.put("AND",SystemEnv.getHtmlLabelName(97705,"所有条件均为真,则返回真,否则返回假。逻辑操作AND的函数模式。示例:
AND(2 = 2, 2 < 2)")); + funcMap.put("OR",SystemEnv.getHtmlLabelName(97706,"任意一个条件为真,则返回真,否则返回假。逻辑操作OR的函数模式。示例:
OR(2 = 2, 2 > 3)")); + funcMap.put("NOT",SystemEnv.getHtmlLabelName(97707,"对逻辑结果取反。示例:
NOT(2 > 3)")); + funcMap.put("IN",SystemEnv.getHtmlLabelName(97708,"任意类型的变量或常量等于一组同类型变量或常量结果中的任意一个,则返回真。示例:
IN(2, [2, 3, 4])")); + funcMap.put("LIKE",SystemEnv.getHtmlLabelName(97709,"文本类型的变量或常量包含一组文本类型变量或常量结果中的任意一个,则返回真。逻辑操作LIKE的函数模式。示例:
LIKE('大家好', ['大家', '好'])")); + funcMap.put("TRUE",SystemEnv.getHtmlLabelName(97710,"返回真。示例:TRUE()")); + funcMap.put("FALSE",SystemEnv.getHtmlLabelName(97712,"返回假。示例:FALSE()")); + funcMap.put("IFS",SystemEnv.getHtmlLabelName(97713,"多个条件判断,位于单数位置的参数设置为条件,位于双数位置的参数设置为结果,最后一个参数为默认返回值,当所有条件都不满足的时候返回默认参数。示例:IFS(1>1,1,1=1,2,0),结果:2")); + funcMap.put("FIND",SystemEnv.getHtmlLabelName(97714,"用指定参数去另一个参数列表中查找匹配项,指定参数时,填写1则去第一个参数列表中查找,2则是第二个参数列表里匹配查找第一个参数,成功则返回true,失败返回false。示例:FIND([1,2,3],[1,2,3,4],1),结果:true")); + + //文本函数 + funcMap.put("CONCAT",SystemEnv.getHtmlLabelName(97730,"可用于连接多个任意类型的文本、日期、数字变量或常量。示例:
CONCAT({总价}/10000, '万元')")); + funcMap.put("TEXT",SystemEnv.getHtmlLabelName(97731,"将变量转为文本。示例:
TEXT({当前数据.性别}) 结果: '男'")); + funcMap.put("VALUE",SystemEnv.getHtmlLabelName(97732,"将文本转为数字。示例:
VALUE('23') 结果: 23")); + funcMap.put("LEN",SystemEnv.getHtmlLabelName(97733,"返回文本的长度,中文、英文都算1个字符。示例:
LEN('大家好dajiahao') 结果: 12")); + funcMap.put("SEARCH",SystemEnv.getHtmlLabelName(97734,"在指定文本中查找关键字,返回第一次出现关键字的字符位置,文本的第一个字记为1。未找到,返回0。搜索开始位置,表示从文本的第几个字符开始搜索,默认为1。示例:
SEARCH('大家', '大家好大家好', 3) 结果: 4")); + funcMap.put("REPLACE",SystemEnv.getHtmlLabelName(97735,"在原文本中,从替换位置开始,往后数指定的替换字符数,将这段文本替换为新文本。示例:
REPLACE('大家好大家好', 2, 3, 'dajia') 结果: '大dajia家好'")); + funcMap.put("REPT",SystemEnv.getHtmlLabelName(97736,"将文本重复指定次数。示例:
REPT('大家', 2) 结果: '大家大家'")); + funcMap.put("PAD",SystemEnv.getHtmlLabelName(97737,"将原文本填充到指定长度,如果文本长度大于设置的长度,则不做任何操作。填充位置可用参数:'LEFT'、'RIGHT'。示例:
PAD('你好', 4, '你', 'LEFT') 结果: '你你你好'")); + funcMap.put("TRIM",SystemEnv.getHtmlLabelName(97738,"删除文本首尾的空格。示例:
TRIM(' 大家好 ') 结果: '大家好'")); + funcMap.put("LEFT",SystemEnv.getHtmlLabelName(97739,"从文本左侧开始,返回指定字符数的文字。示例:
LEFT('大家好', 2) 结果: '大家'")); + funcMap.put("RIGHT",SystemEnv.getHtmlLabelName(97740,"从文本右侧开始,返回指定字符数的文字。示例:
RIGHT('大家好', 2) 结果: '家好'")); + funcMap.put("MID",SystemEnv.getHtmlLabelName(97741,"从文本指定位置之后开始,返回指定字符数的文字。示例:
MID('大家好', 2, 1) 结果: '家'")); + funcMap.put("ISEMPTY",SystemEnv.getHtmlLabelName(97742,"变量为空或未填写,则返回真。示例:
ISEMPTY({员工表.电话})")); + funcMap.put("IDCARD",SystemEnv.getHtmlLabelName(97743,"从身份证号码中获取相关信息,比如:生日(BD)、年龄(AGE)、籍贯(NA)、性别(GENDER)。示例:
IDCARD( ‘43070319980706334X’ , ‘BD’ ) 结果: '1998-07-06'")); + funcMap.put("SCORE",SystemEnv.getHtmlLabelName(97744,"获取选项型控件(单选框、复选框、下拉菜单)分数。示例:SCORE({当前数据.单选框}) 结果:选项分数
注:未设置选项分数时,结果为0")); + funcMap.put("SUBSTRING", SystemEnv.getHtmlLabelName(97745,"字符截取函数,用于按起始位置截取字符。
示例:SUBSTRING('abcdefg',2,3)
结果:bc")); + funcMap.put("SUBSTITUE", SystemEnv.getHtmlLabelName(97746,"字符查找替换函数,替换字符中的所有关键词为新字符。
示例:SUBSTITUE('泛微移动办公','泛微','eteams')
结果:eteams移动办公")); + funcMap.put("LOWER", SystemEnv.getHtmlLabelName(97747,"将字符中的字母转为小写。
示例:LOWER('abc')
结果:ABC")); + funcMap.put("UPPER", SystemEnv.getHtmlLabelName(97748,"将字符中的字母转为大写。
示例:LOWER('ABC')
结果:abc")); + funcMap.put("EXACT", SystemEnv.getHtmlLabelName(97749,"比较两个字符是否相等,区分字母的大小写。
示例:EXACT('泛微Eteams','泛微eteams')
结果:false")); + funcMap.put("ISSTRING", SystemEnv.getHtmlLabelName(0,"判断是否是字符。
示例:ISSTRING('泛微Eteams')
结果:true")); + + //数学函数 + funcMap.put("ROUND",SystemEnv.getHtmlLabelName(97750,"根据设置的小数位精确度,返回对数值四舍五入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,针对小数点后的数据进行四舍五入;如果小数位精确度等于 0,返回最接近数值的整数;如果小数位精确度为负整数,针对小数点前的数据进行四舍五入,被舍掉的数据用0占位。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。
示例:ROUND(123.456,2),ROUND(123.456,0),ROUND(123.456,-2)
结果:依次为123.46,123,100")); + funcMap.put("ROUNDUP",SystemEnv.getHtmlLabelName(97751,"根据设置的小数位精确度,返回对数值向上舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向上舍入到指定的小数位。如果小数位精确度等于 0,则向上舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向上进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。示例:ROUNDDOWN(76.9,0)结果:77")); + funcMap.put("ROUNDDOWN",SystemEnv.getHtmlLabelName(97752,"根据设置的小数位精确度,返回对数值向下舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向下舍入到指定的小数位。如果小数位精确度等于 0,则向下舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向下进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。
示例:ROUNDDOWN(76.9,0)
结果:76")); + funcMap.put("AGGREGATION",SystemEnv.getHtmlLabelName(97753,"将一组数据进行统计计算,支持最大值(MAX)、最小值(MIN)、平均值(AVG)。示例:AGGREGATION(1 , 2,3,'AVG'),结果:2")); + funcMap.put("MOD",SystemEnv.getHtmlLabelName(97754,"将两个参数进行除法运算然后得出余数返回。示例:MOD( 7 , 3 ),结果:1")); + funcMap.put("TRUNC",SystemEnv.getHtmlLabelName(97755,"将小数点格式化成指定位数。示例:TRUNC( 2.123 , 2 ),结果:2.12")); + funcMap.put("ISINT",SystemEnv.getHtmlLabelName(0,"判断字符内容是否是整数。示例:ISINT( 2.123 ),结果:false")); + funcMap.put("ISNUMBER",SystemEnv.getHtmlLabelName(0,"判断字符内容是否是数字。示例:ISNUMBER('2.123'),结果:true")); + + //查找函数 + funcMap.put("CHOOSE",SystemEnv.getHtmlLabelName(97756,"根据条件获取指定数据源中的全部数据。数据源支持选表单、表单中的字段。
示例:想知道税表中,收入大于15000的数值
CHOOSE({税表}, {税表.收入}>15000)
结果:返回税表中收入大于15000的集合")); + funcMap.put("MATCH",SystemEnv.getHtmlLabelName(97757,"将指定数值在指定数组区域中的位置返回。若数组中无指定值,返回null。
示例:MATCH(15000, [1000, 15000, 2000])
结果:1")); + funcMap.put("VLOOKUPS", SystemEnv.getHtmlLabelName(97758,"按列查找,返回所需值。常用于薪酬模块。根据条件获取查询参数所在列的返回参数的值。返回参数可填写多个,用英文逗号隔开。若查询不到返回null。
示例:VLOOKUPS({税表},{税表.收入},AND({税表.收入}>{税表.应纳税所得额下限},{税表.收入}<{税表.应纳税所得额上限}),[{税表.税率},{税表.速算扣除数}])
结果:按列查找返回税表中收入所在的收入区间所对应的税率和速算扣除数的数值")); + + //数据库函数 + funcMap.put("GETHRMLOGINID", SystemEnv.getHtmlLabelName(100808, "获取指定人员系统账号。
示例:GETHRMLOGINID({表单.张三})
结果:zhangsan@qq.com")); + funcMap.put("GETHRMWORKCODE", SystemEnv.getHtmlLabelName(100810, "获取指定人员编号。
示例:GETHRMWORKCODE({表单.张三})
结果:A001")); + funcMap.put("GETHRMMANAGER", SystemEnv.getHtmlLabelName(100812, "获取指定人员直接上级。
示例:GETHRMMANAGER({表单.张三})
结果:返回张三的直接上级")); + funcMap.put("GETHRMALLMANAGER", SystemEnv.getHtmlLabelName(100814, "获取指定人员所有上级。
示例:GETHRMMANAGER({表单.张三})
结果:返回张三的所有上级形成的数组")); + funcMap.put("GETHRMDEPARTMENT", SystemEnv.getHtmlLabelName(100816, "获取指定人员部门。
示例:GETHRMDEPARTMENT({表单.张三})
结果:返回张三的部门")); + funcMap.put("GETHRMSUBCOMPANY", SystemEnv.getHtmlLabelName(100818, "获取指定人员分部。
示例:GETHRMSUBCOMPANY({表单.张三})
结果:返回张三的分部")); + funcMap.put("GETDEPARTMENTNAME", SystemEnv.getHtmlLabelName(100820, "获取指定部门名称。
示例:GETDEPARTMENTNAME({表单.A部门})
结果:A部门")); + funcMap.put("GETDEPARTMENTCODE", SystemEnv.getHtmlLabelName(100822, "获取指定部门编号。
示例:GETDEPARTMENTCODE({表单.A部门})
结果:A001")); + funcMap.put("GETSUPERDEPARTMENT", SystemEnv.getHtmlLabelName(100824, "获取指定部门直接上级部门。
示例:GETDEPARTMENTCODE({表单.A部门})
结果:A部门的直接上级部门")); + funcMap.put("GETALLSUPERDEPARTMENT", SystemEnv.getHtmlLabelName(100826, "获取指定部门所有上级部门。
示例:GETALLSUPERDEPARTMENT({表单.A部门})
结果:A部门的所有上级部门形成的数组")); + funcMap.put("GETSUBCOMPANYNAME", SystemEnv.getHtmlLabelName(100828, "获取指定分部名称。
示例:GETSUBCOMPANYNAME({表单.A分部})
结果:A分部")); + funcMap.put("GETSUBCOMPANYCODE", SystemEnv.getHtmlLabelName(100830, "获取指定分部编号。
示例:GETSUBCOMPANYCODE({表单.A分部})
结果:B001")); + funcMap.put("GETSUPERSUBCOMPANY", SystemEnv.getHtmlLabelName(100832, "获取指定分部直接上级分部。
示例:GETSUPERSUBCOMPANY({表单.A分部})
结果:A分部的直接上级分部")); + funcMap.put("GETALLSUPERSUBCOMPANY", SystemEnv.getHtmlLabelName(100834, "获取指定分部所有上级分部。
示例:GETALLSUPERSUBCOMPANY({表单.A分部})
结果:A分部的所有上级分部形成的数组")); + funcMap.put("GETHRMNAME", SystemEnv.getHtmlLabelName(100834, "获取指定人员的姓名。
示例:GETHRMNAME({U:张三})
结果:张三")); + funcMap.put("GETHRMMOBILE", SystemEnv.getHtmlLabelName(100834, "获取指定人员的手机号码。
示例:GETHRMMOBILE({U:张三})
结果:13123232323")); + + //财务函数 + funcMap.put("GETMONEY", SystemEnv.getHtmlLabelName(0, "将金额转换成中文金额大写。
示例:GETMONEY({1234})
结果:壹仟贰佰叁拾肆元整")); + + } + public String get(String key){ + if(funcMap.size()>0){ +// logger.info("描述数据存在:"+funcMap.size()); + }else { + logger.info("初始化函数描述数据"); + initData(); + } + + return funcMap.get(key); + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/FuncNames.java b/src/com/engine/salary/formlua/entity/parameter/FuncNames.java new file mode 100644 index 000000000..b70235490 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/FuncNames.java @@ -0,0 +1,20 @@ +package com.engine.salary.formlua.entity.parameter; + + +public enum FuncNames { + AND("and"), OR("or"), IF("ifF"), LIKE("likeFunc"), DATEDIFF("dateDiff"), DATEADD("dateAdd"), NOW("now"), DATEFORMAT("dateFormat"), COUNT("counts"), SUM("sumNumber"), MAX("maxNumber"), MIN("minNumber"), CONCAT("concatString"), SEARCH("search"), TEXT("text"), PAD("pad"), REPLACE("replace"), VALUE("value"), LEN("len"), LEFT("left"), RIGHT("right"), MID("mid"), TRUE("isTrue"), FALSE("isFalse"), NOT("not"), ISEMPTY("isEmpty"), TODAY("today"), IFS("ifs"), AGGREGATION("aggregation"), MOD("mod"), FIND("find"), SWITCH("switchs"), TRUNC("Trunc"), IDCARD("idCard"), + RANDOMNUMBER("randomNumber"), ROUNDUP("roundUp"), ROUNDDOWN("roundDown"), ROUND("round"), ADDRESS("addressAnalysis"), EOMONTH("eoMonth"), NETWORKDAYSPI("networkdaysPastIntl"), + CHOOSE("choose"), MATCH("match"), VLOOKUPS("vlookups"), GETHRMLOGINID("getHrmLoginId"), GETHRMWORKCODE("getHrmWorkcode"), GETHRMMANAGER("getHrmManager"), GETHRMALLMANAGER("getHrmAllManager"), + GETHRMDEPARTMENT("getHrmDepartment"), GETHRMSUBCOMPANY("getHrmSubcompany"), GETDEPARTMENTNAME("getDepartmentName"), GETDEPARTMENTCODE("getDepartmentCode"), GETSUPERDEPARTMENT("getSuperDepartment"), + GETALLSUPERDEPARTMENT("getAllSuperDepartment"), GETSUBCOMPANYNAME("getSubcompanyName"), GETSUBCOMPANYCODE("getSubcompanyCode"), GETSUPERSUBCOMPANY("getSuperSubcompany"), GETALLSUPERSUBCOMPANY("getAllSuperSubcompany"), + ISINT("isInt"), ISNUMBER("isNumber"), ISSTRING("isString"), GETMONEY("getMoney"), GETHRMNAME("getHrmName"), GETHRMMOBILE("getHrmMobile"); + String name; + + FuncNames(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/IllegalList.java b/src/com/engine/salary/formlua/entity/parameter/IllegalList.java new file mode 100644 index 000000000..5ed75febf --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/IllegalList.java @@ -0,0 +1,19 @@ +package com.engine.salary.formlua.entity.parameter; + + + +public class IllegalList { + private final String[] operArray=new String[]{"<",">","+","-","*","/","{","}","[","]","(",")","=","!=","'","\"","!",".",">=","<="}; + private final String[] nameIllegalArray=new String[]{"<",">","+","-","*","/","{","}","[","]","(",")","=","!=","'","\"","!",".", + "LIKE","like",">=","<=","IN","IF","AND","OR","TRUE","FALSE","NOW","DATEDIFF","DATEADD","Y","M","D","H","I","S","WEEKNUM", + "WEEKDAY","TODAY","DATEFORMAT","COUNT","SUM","MAX","MIN","CONCAT","SEARCH","TEXT","PAD","REPLACE","VALUE","LEN","LEFT","RIGHT","MID"}; + private IllegalList(){} + private static IllegalList illegalList=new IllegalList(); + public static IllegalList getInstance(){return illegalList;} + public String[] getNameIllegalArray() { + return nameIllegalArray; + } + public String[] getOperArray() { + return operArray; + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/ParamContext.java b/src/com/engine/salary/formlua/entity/parameter/ParamContext.java new file mode 100644 index 000000000..afc1b65e5 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/ParamContext.java @@ -0,0 +1,30 @@ +package com.engine.salary.formlua.entity.parameter; + +import com.alibaba.fastjson.JSONObject; + +/** + * @className: + * @Description:本地线程存储的Excel函数变量context,线程结束后会清空释放当前线程的变量context + * @Author: + * @date: + */ +public class ParamContext { + public static ThreadLocal fmCtx=new ThreadLocal(); + private JSONObject jsonObject=new JSONObject(); + + public static ParamContext get(){ + if(null==fmCtx.get()){ + fmCtx.set(new ParamContext()); + } + return fmCtx.get(); + } + public void setValue(String func,Object value){ + jsonObject.put(func,value); + } + public Object getValue(String func){ + return jsonObject.get(func); + } + public void removeContext(){ + fmCtx.remove(); + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/ParamFactory.java b/src/com/engine/salary/formlua/entity/parameter/ParamFactory.java new file mode 100644 index 000000000..b0cbab51e --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/ParamFactory.java @@ -0,0 +1,127 @@ +package com.engine.salary.formlua.entity.parameter; + +/** + * @className:默认本地参数 + * @Description:注释 + * @Author: + * @date: + */ +public class ParamFactory { + private String charValue; + private Double doubleValue; + private Integer integerValue; + private Long longValue; + private Float floatValue; + private Boolean boolValue; + private String dateTimeValue; + private String selectValue; + private String timeValue; + private String textValue; + private ParamFactory(){} + + private ParamFactory(String charValue, Double doubleValue, Integer integerValue, Long longValue, Float floatValue, Boolean boolValue,String dateTimeValue,String selectValue,String timeValue,String textValue) { + this.charValue = charValue; + this.doubleValue = doubleValue; + this.integerValue = integerValue; + this.longValue = longValue; + this.floatValue = floatValue; + this.boolValue = boolValue; + this.dateTimeValue=dateTimeValue; + this.selectValue=selectValue; + this.timeValue=timeValue; + this.textValue=textValue; + } + + private static ParamFactory paramFactory=new ParamFactory("2020-01-12 12:23:33",5.2,2020,100L,new Float(20.4),true,"2020-01-12 12:23:33","8428149709910469289","12:12:30","abcd"); + public static ParamFactory getInstance(){ + return paramFactory; + } + + public String getTimeValue() { + return timeValue; + } + + public void setTimeValue(String timeValue) { + this.timeValue = timeValue; + } + + public String getSelectValue() { + return selectValue; + } + + public void setSelectValue(String selectValue) { + this.selectValue = selectValue; + } + + public String getCharValue() { + return charValue; + } + + public void setCharValue(String charValue) { + this.charValue = charValue; + } + + public Double getDoubleValue() { + return doubleValue; + } + + public String getDateTimeValue() { + return dateTimeValue; + } + + public void setDateTimeValue(String dateTimeValue) { + this.dateTimeValue = dateTimeValue; + } + + public void setDoubleValue(Double doubleValue) { + this.doubleValue = doubleValue; + } + + public Integer getIntegerValue() { + return integerValue; + } + + public void setIntegerValue(Integer integerValue) { + this.integerValue = integerValue; + } + + public Long getLongValue() { + return longValue; + } + + public void setLongValue(Long longValue) { + this.longValue = longValue; + } + + public Float getFloatValue() { + return floatValue; + } + + public void setFloatValue(Float floatValue) { + this.floatValue = floatValue; + } + + public Boolean getBoolValue() { + return boolValue; + } + + public void setBoolValue(Boolean boolValue) { + this.boolValue = boolValue; + } + + public static ParamFactory getParamFactory() { + return paramFactory; + } + + public static void setParamFactory(ParamFactory paramFactory) { + ParamFactory.paramFactory = paramFactory; + } + + public String getTextValue() { + return textValue; + } + + public void setTextValue(String textValue) { + this.textValue = textValue; + } +} diff --git a/src/com/engine/salary/formlua/entity/parameter/ParamType.java b/src/com/engine/salary/formlua/entity/parameter/ParamType.java new file mode 100644 index 000000000..f11a1ceca --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/ParamType.java @@ -0,0 +1,15 @@ +package com.engine.salary.formlua.entity.parameter; + + +public enum ParamType { + STRING("String"),INTEGER("Integer"),DOUBLE("Double"),LONG("Long"),SHORT("Short"),JSONOBJECT("JSONObject"),FLOAT("Float"),BOOLEAN("Boolean"); + String name; + ParamType(String name) { + this.name=name; + } + + public String getName() { + return name; + } + +} diff --git a/src/com/engine/salary/formlua/entity/parameter/ReturnType.java b/src/com/engine/salary/formlua/entity/parameter/ReturnType.java new file mode 100644 index 000000000..601a097cb --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/ReturnType.java @@ -0,0 +1,13 @@ +package com.engine.salary.formlua.entity.parameter; + + +public class ReturnType { + public final static int BOOLEAN_VALUE=0; + public final static int NUMBER_VALUE=1; + public final static int STRING_VALUE=2; + public final static String[] NUMBER_TYPE=new String[]{"NumberComponent","Money","Raty","score","Monitor"}; + public final static String[] DATETIME_TYPE=new String[]{"DateComponent","DateInterval"}; + public final static String[] CHECK_TYPE=new String[]{"RadioBox","CheckBox","Select","ComboSelect"}; + public final static String[] DROPDOWN_LIST=new String[]{"Select","ComboSelect"}; + public final static String[]CHECKBOX_LIST=new String[]{"RadioBox","CheckBox"}; +} diff --git a/src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java b/src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java new file mode 100644 index 000000000..4a06cc07e --- /dev/null +++ b/src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java @@ -0,0 +1,59 @@ +package com.engine.salary.formlua.entity.parameter; + +import com.weaver.common.form.metadata.ModuleSource; +import com.weaver.teams.domain.user.SimpleEmployee; + +import java.util.Iterator; +import java.util.Map; + + +public class ThreadLocalData { + private Map expressContext; + private ModuleSource moduleSource; + + private SimpleEmployee employee; + + public ModuleSource getModuleSource() { + return moduleSource; + } + + public void setModuleSource(ModuleSource moduleSource) { + this.moduleSource = moduleSource; + } + + public SimpleEmployee getEmployee() { + return employee; + } + + public void setEmployee(SimpleEmployee employee) { + this.employee = employee; + } + + public Map getExpressContext() { + return expressContext; + } + + public void setExpressContext(Map expressContext) { + transMap(expressContext); + this.expressContext = expressContext; + } + + private void transMap(Map expressContext){ + Iterator iterator=expressContext.keySet().iterator(); + while (iterator.hasNext()){ + String key=iterator.next(); + Object obj=expressContext.get(key); + if(obj instanceof DataType){ + DataType dataType=(DataType)obj; + if(dataType.getFieldId()!=null){ + int idx=key.indexOf(dataType.getFieldId().toString()); + if(idx>=0){ + String localKey=key.substring(0,idx+dataType.getFieldId().toString().length()); + dataType.setAggCndKey(localKey); + } + } + + } + } + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/AggFunc.java b/src/com/engine/salary/formlua/entity/standard/AggFunc.java new file mode 100644 index 000000000..34215605c --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/AggFunc.java @@ -0,0 +1,8 @@ +package com.engine.salary.formlua.entity.standard; + +public enum AggFunc { + count("计数"),avg("平均数"),min("最小数"),max("最大数"),sum("合计数"); + + AggFunc(String name) { + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/ExcelModuleFixField.java b/src/com/engine/salary/formlua/entity/standard/ExcelModuleFixField.java new file mode 100644 index 000000000..92e05d744 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/ExcelModuleFixField.java @@ -0,0 +1,34 @@ +package com.engine.salary.formlua.entity.standard; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ExcelModuleFixField { + /** + * 审批发起人 + */ + public static String FLOW_CREATOR="creator"; + /** + * 审批请求ID + */ + public static String FLOW_REQUEST_ID="requestid"; + /** + * 审批发起人所属部门 + */ + public static String FLOW_CREATOR_DEPT="creator_depart"; + /** + * 上报收集人 + */ + public static String REPORT_CREATOR="creator"; + /** + * 上报名称 + */ + public static String REPORT_NAME="name"; + /** + * 上报提交人 + */ + public static String REPORT_REPORTER="reporter"; + + public static List ALLFIXFIELD = new ArrayList<>(Arrays.asList(FLOW_CREATOR,FLOW_CREATOR_DEPT,FLOW_REQUEST_ID,REPORT_CREATOR,REPORT_NAME,REPORT_REPORTER)); +} diff --git a/src/com/engine/salary/formlua/entity/standard/ExcelPage.java b/src/com/engine/salary/formlua/entity/standard/ExcelPage.java new file mode 100644 index 000000000..dddf2300c --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/ExcelPage.java @@ -0,0 +1,56 @@ +package com.engine.salary.formlua.entity.standard; + +import java.io.Serializable; +import java.util.List; + +/** + * @author + */ +public class ExcelPage implements Serializable { + private static final long serialVersionUID = -3149769813337109956L; + private int pageNo; + private int pageSize; + private int count; + private String keywords; + private List pageResult; + + public String getKeywords() { + return keywords; + } + + public void setKeywords(String keywords) { + this.keywords = keywords; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public int getPageNo() { + return pageNo; + } + + public void setPageNo(int pageNo) { + this.pageNo = pageNo; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public List getPageResult() { + return pageResult; + } + + public void setPageResult(List pageResult) { + this.pageResult = pageResult; + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/ExcelResult.java b/src/com/engine/salary/formlua/entity/standard/ExcelResult.java new file mode 100644 index 000000000..f504acc33 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/ExcelResult.java @@ -0,0 +1,87 @@ +package com.engine.salary.formlua.entity.standard; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author roy + */ +public class ExcelResult implements Serializable { + private static final long serialVersionUID = 4578033427466119428L; + /** + * 文本、数字、日期从这里取值 + */ + private Object data; + /** + * 布尔值从这里取值 + */ + private boolean boolData; + private String stringData; + private BigDecimal numberData; + /** + * 执行状态,true为执行成功,false为执行失败 + */ + private boolean status; + private String errorMsg; + private String formulaId; + + public String getFormulaId() { + return formulaId; + } + + public void setFormulaId(String formulaId) { + this.formulaId = formulaId; + } + + public boolean isBoolData() { + return boolData; + } + + public String getStringData() { + return stringData; + } + + public void setStringData(String stringData) { + this.stringData = stringData; + } + + public BigDecimal getNumberData() { + return numberData; + } + + public void setNumberData(BigDecimal numberData) { + this.numberData = numberData; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } + + public boolean getBoolData() { + return boolData; + } + + public void setBoolData(boolean boolData) { + this.boolData = boolData; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public boolean isStatus() { + return status; + } + + public void setStatus(boolean status) { + this.status = status; + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/FormulaCategory.java b/src/com/engine/salary/formlua/entity/standard/FormulaCategory.java new file mode 100644 index 000000000..fbc482888 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/FormulaCategory.java @@ -0,0 +1,58 @@ +package com.engine.salary.formlua.entity.standard; + +import java.io.Serializable; + +/** + * @author roy + */ +public class FormulaCategory implements Serializable { + private static final long serialVersionUID = 376155360889274784L; + /** + * 分类ID + */ + private String id; + /** + * 分类名称 + */ + private String name; + /** + * 所属模块 + */ + private String module; + /** + * 类别,和module保持一致即可,为兼容老数据的保留字段 + */ + private String type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getModule() { + return module; + } + + public void setModule(String module) { + this.module = module; + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/FormulaDataSource.java b/src/com/engine/salary/formlua/entity/standard/FormulaDataSource.java new file mode 100644 index 000000000..83bdbcf52 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/FormulaDataSource.java @@ -0,0 +1,37 @@ +package com.engine.salary.formlua.entity.standard; + +import java.io.Serializable; + +/** + * @author roy + */ +public class FormulaDataSource implements Serializable { + private static final long serialVersionUID = 8657467498740290598L; + private String dataId; + private String title; + private String module; + + public String getDataId() { + return dataId; + } + + public void setDataId(String dataId) { + this.dataId = dataId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getModule() { + return module; + } + + public void setModule(String module) { + this.module = module; + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java b/src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java new file mode 100644 index 000000000..06531e13f --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java @@ -0,0 +1,303 @@ +package com.engine.salary.formlua.entity.standard; + +import com.weaver.common.form.stat.FilterFormData; +import com.weaver.common.form.stat.domain.search.FilterFormDataIds; +import com.weaver.teams.domain.entity.BaseEntity; + +import java.io.Serializable; +import java.util.List; + +/** + * @author roy + */ +public class FormulaFilterData implements Serializable { + public static final String CONDITION_AND = "and"; + public static final String CONDITION_OR = "or"; + public static final String TERM_EQ = "eq"; + public static final String TERM_NOT_EQ = "neq"; + public static final String TERM_NULL = "null"; + public static final String TERM_NOT_NULL = "notnull"; + public static final String TERM_LIKE = "like"; + public static final String TERM_GT = "gt"; + public static final String TERM_GE = "ge"; + public static final String TERM_LE = "le"; + public static final String TERM_LT = "lt"; + public static final String TERM_BEQ = "beq"; + public static final String TERM_SEQ = "seq"; + public static final String SOURCE_TYPE_CONSTANT = "constant"; + public static final String SOURCE_TYPE_VARIABLE = "variable"; + private static final long serialVersionUID = 2902385161856666369L; + /** + * 字段ID + */ + private String fieldId; + /** + * 明细子表ID + */ + private String subFormId; + /** + * 控件名称 + */ + private String componentKey; + /** + * 操作符,具体符号在上面的静态变量中 + */ + private String term; + private String tremStr; + /** + * 条件的值 + */ + private String content; + /** + * 范围条件的截止范围 + */ + private String endContent; + /** + * 选项条件的值 + */ + private List ids; + private List children; + private List contents; + private List idObjects; + private String dateType; + private List allUserIds; + private List allDeptIds; + private String operateId; + private String departmentId; + private List deptFieldIds; + private String subDept; + private List pIds; + private String sourceType; + private String sourceFile; + private String idsStr; + private String sortStr; + private String condition = "and"; + private List selectIds; + private String format; + private boolean isFixed; + private List filterFormDataIdsList; + + public String getFieldId() { + return fieldId; + } + + public void setFieldId(String fieldId) { + this.fieldId = fieldId; + } + + public String getSubFormId() { + return subFormId; + } + + public void setSubFormId(String subFormId) { + this.subFormId = subFormId; + } + + public String getComponentKey() { + return componentKey; + } + + public void setComponentKey(String componentKey) { + this.componentKey = componentKey; + } + + public String getTerm() { + return term; + } + + public void setTerm(String term) { + this.term = term; + } + + public String getTremStr() { + return tremStr; + } + + public void setTremStr(String tremStr) { + this.tremStr = tremStr; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getEndContent() { + return endContent; + } + + public void setEndContent(String endContent) { + this.endContent = endContent; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + +// public List getChildren() { +// return children; +// } +// +// public void setChildren(List children) { +// this.children = children; +// } + + public List getContents() { + return contents; + } + + public void setContents(List contents) { + this.contents = contents; + } + + public List getIdObjects() { + return idObjects; + } + + public void setIdObjects(List idObjects) { + this.idObjects = idObjects; + } + + public String getDateType() { + return dateType; + } + + public void setDateType(String dateType) { + this.dateType = dateType; + } + + public List getAllUserIds() { + return allUserIds; + } + + public void setAllUserIds(List allUserIds) { + this.allUserIds = allUserIds; + } + + public List getAllDeptIds() { + return allDeptIds; + } + + public void setAllDeptIds(List allDeptIds) { + this.allDeptIds = allDeptIds; + } + + public String getOperateId() { + return operateId; + } + + public void setOperateId(String operateId) { + this.operateId = operateId; + } + + public String getDepartmentId() { + return departmentId; + } + + public void setDepartmentId(String departmentId) { + this.departmentId = departmentId; + } + + public List getDeptFieldIds() { + return deptFieldIds; + } + + public void setDeptFieldIds(List deptFieldIds) { + this.deptFieldIds = deptFieldIds; + } + + public String getSubDept() { + return subDept; + } + + public void setSubDept(String subDept) { + this.subDept = subDept; + } + + public List getpIds() { + return pIds; + } + + public void setpIds(List pIds) { + this.pIds = pIds; + } + + public String getSourceType() { + return sourceType; + } + + public void setSourceType(String sourceType) { + this.sourceType = sourceType; + } + + public String getSourceFile() { + return sourceFile; + } + + public void setSourceFile(String sourceFile) { + this.sourceFile = sourceFile; + } + + public String getIdsStr() { + return idsStr; + } + + public void setIdsStr(String idsStr) { + this.idsStr = idsStr; + } + + public String getSortStr() { + return sortStr; + } + + public void setSortStr(String sortStr) { + this.sortStr = sortStr; + } + + public String getCondition() { + return condition; + } + + public void setCondition(String condition) { + this.condition = condition; + } + + public List getSelectIds() { + return selectIds; + } + + public void setSelectIds(List selectIds) { + this.selectIds = selectIds; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public boolean isFixed() { + return isFixed; + } + + public void setFixed(boolean fixed) { + isFixed = fixed; + } + +// public List getFilterFormDataIdsList() { +// return filterFormDataIdsList; +// } +// +// public void setFilterFormDataIdsList(List filterFormDataIdsList) { +// this.filterFormDataIdsList = filterFormDataIdsList; +// } +} diff --git a/src/com/engine/salary/formlua/entity/standard/FormulaModuleCategory.java b/src/com/engine/salary/formlua/entity/standard/FormulaModuleCategory.java new file mode 100644 index 000000000..50dc2a8fa --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/FormulaModuleCategory.java @@ -0,0 +1,34 @@ +package com.engine.salary.formlua.entity.standard; + +import java.io.Serializable; + +/** + * @author + */ +public class FormulaModuleCategory implements Serializable { + private static final long serialVersionUID = 561339364277864462L; + /** + * 分类名称 + */ + private String content; + /** + * 分类ID + */ + private String id; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/src/com/engine/salary/formlua/func/compare/CommonOper.java b/src/com/engine/salary/formlua/func/compare/CommonOper.java new file mode 100644 index 000000000..ad7921ee2 --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/CommonOper.java @@ -0,0 +1,71 @@ +package com.engine.salary.formlua.func.compare; + + +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.ExcelParamUtil; + +import java.util.ArrayList; +import java.util.List; + +public class CommonOper { + + public static List operDivMultiList(Object obj1,Object obj2,String oper){ + List resultList=new ArrayList<>(); + if( (obj1 instanceof Object[] && !(obj2 instanceof Object[])) || (obj2 instanceof Object[] && !(obj1 instanceof Object[])) ){ + Object[] arrayParam; + Object param; + boolean firstArray=false; + if(obj1 instanceof Object[]){ + arrayParam=(Object[])obj1; + param=obj2; + firstArray=true; + }else { + arrayParam=(Object[])obj2; + param=obj1; + } + for (int i=0;i operAddReduceList(Object obj1,Object obj2){ + List resultList=new ArrayList<>(); + Object[] param1=(Object[])obj1; + Object[] param2=(Object[])obj2; + if(param1.length!=param2.length){ + throw new RuntimeException("参数列表长度不一致"); + } + for (int i=0;i filterFormDataList = new ArrayList<>(); + FormulaFilterData filterData = new FormulaFilterData(); + String content = null; + try { + if (obj1 instanceof DataType) { + DataType dataType1 = (DataType) obj1; + if (StringUtils.isEmpty(dataType1.getComponentKey())) { + dataType1.setComponentKey(dataType1.getDataType()); + } + if (obj2 instanceof DataType) { +// content = ((DataType) obj2).getContent()+""; + DataType paramDataType = (DataType) obj2; + if (paramDataType == null || paramDataType.getContent() == null) { + content = ""; + } else { + content = paramDataType.getContent() + ""; + } + } else { + content = obj2 + ""; + } + if (content != null) { + String componentKey = dataType1.getComponentKey(); + filterData.setFieldId(dataType1.getFieldId()); + if (dataType1.getSubFormId() != null) { + filterData.setSubFormId(dataType1.getSubFormId() + ""); + } + filterData.setComponentKey(componentKey); + if (StringUtils.isEmpty(content)) { +// filterData.setTerm(FilterFormData.TERM_NOT_NULL); + } else { +// //选项控件 +// if (ComponentConfig.isOptionComponent(componentKey)) { +// filterData.setTerm(FilterFormData.TERM_NOT_EQ); +// List ids = new ArrayList<>(); +// String[] idsArray = content.split(","); +// for (String idStr : idsArray) { +// if (StringUtils.isNotBlank(idStr)) { +// ids.add(idStr); +// } +// } +// filterData.setIds(ids); +// //其他 +// } else { +// filterData.setTerm(FilterFormData.TERM_NOT_EQ); +// filterData.setContent(content); +//// if(ComponentConfig.isNumberComponent(dataType1.getComponentKey()) || dataType1.getComponentKey().equalsIgnoreCase(DataType.NUMBER)){ +//// if(StringUtils.isEmpty(content)){ +//// filterData.setContent("0"); +//// } +//// } +// } + } + } + filterFormDataList.add(filterData); +// dataType.setFormulaFilterDataList(filterFormDataList); + dataType.setComponentKey(dataType1.getComponentKey()); + dataType.setSubFormId(dataType1.getSubFormId()); + } + } catch (Exception e) { + logger.error("err", e); + } + + } + + /** + * 构建大于、小于、大于等于、小于等于的搜索条件 + * + * @param dataType + * @param name + * @param obj1 + * @param obj2 + */ + public static void buildLessMoreFilterParam(DataType dataType, String name, Object obj1, Object obj2) { + List filterFormDataList = new ArrayList<>(); + FormulaFilterData filterData = new FormulaFilterData(); + try { + logger.info(name + "执行结果:" + JSON.toJSONString(dataType)); + if (obj1 instanceof DataType) { + DataType dataType1 = (DataType) obj1; + if (StringUtils.isEmpty(dataType1.getComponentKey())) { + dataType1.setComponentKey(dataType1.getDataType()); + } + String content = null; + if (obj2 instanceof DataType) { +// content = ((DataType) obj2).getContent()+""; + DataType paramDataType = (DataType) obj2; + if (paramDataType == null || paramDataType.getContent() == null) { + content = ""; + } else { + content = paramDataType.getContent() + ""; + } + } else { + content = obj2 + ""; + } + if (content != null) { + String componentKey = dataType1.getComponentKey(); + if (ComponentConfig.isNumberComponent(componentKey) + || componentKey.equals(ComponentType.DateComponent.toString()) + || componentKey.equals(ComponentType.TimeComponent.toString()) + || dataType1.getComponentKey().equalsIgnoreCase(DataType.STRING) + || dataType1.getComponentKey().equalsIgnoreCase(DataType.NUMBER) + || dataType1.getComponentKey().equalsIgnoreCase(DataType.STRING) + || dataType1.getComponentKey().equalsIgnoreCase(DataType.BOOL)) { + + filterData.setFieldId(dataType1.getFieldId() + ""); + if (dataType1.getSubFormId() != null) { + filterData.setSubFormId(dataType1.getSubFormId() + ""); + } + filterData.setComponentKey(componentKey); + switch (name) { + case ">=": + filterData.setTerm(FilterFormData.TERM_GE); + break; + case ">": + filterData.setTerm(FilterFormData.TERM_GT); + break; + case "<=": + filterData.setTerm(FilterFormData.TERM_LE); + break; + case "<": + filterData.setTerm(FilterFormData.TERM_LT); + break; + default: + break; + } + filterData.setContent(content); + } + } + filterFormDataList.add(filterData); + dataType.setFormulaFilterDataList(filterFormDataList); + dataType.setComponentKey(dataType1.getComponentKey()); + dataType.setSubFormId(dataType1.getSubFormId()); + } + } catch (Exception e) { + logger.error("err", e); + } + + } + + /** + * 校验大于、小于、小于等于、大于等于操作符的入参 + * + * @param name + * @param obj1 + * @param obj2 + * @return + */ + public static boolean checkLessMoreParam(String name, Object obj1, Object obj2) { + if (obj1 instanceof FormField) { + String componentKey = ((FormField) obj1).getComponentKey(); + if (ComponentConfig.isNumberComponent(componentKey)) { + if (obj2 instanceof Number) { + return true; + } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { + return true; + } else { + throw new RuntimeException("筛选条件[" + name + "]:数字控件右边必须是数字"); + } + } + if (componentKey.equals(ComponentType.DateComponent.toString())) { + if (obj2 instanceof String && Validator.isDate((String) obj2)) { + return true; + } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { + return true; + } else { + throw new RuntimeException("筛选条件[" + name + "]:日期控件右边必须是日期字符串"); + } + + } + if (componentKey.equals(ComponentType.TimeComponent.toString())) { + if (obj2 instanceof String && Validator.isTime((String) obj2)) { + return true; + } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { + return true; + } else { + throw new RuntimeException("筛选条件[" + name + "]:时间控件右边必须是时间字符串"); + } + } + } + throw new RuntimeException("筛选条件[" + name + "]:左边必须是数字控件或时间控件"); + } + + /** + * 校验等于号的入参 + * + * @param obj1 + * @param obj2 + * @return + */ + public static boolean checkEqParam(Object obj1, Object obj2) { + if (obj1 instanceof DataType) { + String componentKey = ((FormField) obj1).getComponentKey(); + if (ComponentConfig.isNumberComponent(componentKey)) { + if (obj2 instanceof DataType) { + if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { + return true; + } else { + throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); + } + } else if (StringUtils.isEmpty(obj2 + "") || Validator.isFloat(obj2 + "")) { + return true; + } else { + throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); + } + } else if (ComponentConfig.isOptionComponent(componentKey)) { + if (StringUtils.isEmpty(obj2 + "") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { + return true; + } else { + throw new RuntimeException("筛选条件[=]:选项控件右边必须是选项"); + } + } else { + if (StringUtils.isEmpty(obj2 + "") || obj2 instanceof String || obj2 instanceof Character) { + return true; + } else if (obj2 instanceof DataType) { + if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { + return true; + } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { + return true; + } else { + throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); + } + } else { + throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); + } + } + } + throw new RuntimeException("筛选条件[=]:左边必须是表单控件"); + } + + /** + * 校验不等于号的入参 + * + * @param obj1 + * @param obj2 + * @return + */ + public static boolean checkNotEqParam(Object obj1, Object obj2) { + if (obj1 instanceof FormField) { + String componentKey = ((FormField) obj1).getComponentKey(); + if (ComponentConfig.isNumberComponent(componentKey)) { + if (obj2 instanceof DataType) { + if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { + return true; + } else { + throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); + } + } else if (StringUtils.isEmpty(obj2 + "") || Validator.isFloat(obj2 + "")) { + return true; + } else { + throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); + } + } else if (ComponentConfig.isOptionComponent(componentKey)) { + if (StringUtils.isEmpty(obj2 + "") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { + return true; + } else { + throw new RuntimeException("筛选条件[!=]:选项控件右边必须是选项"); + } + } else { + if (StringUtils.isEmpty(obj2 + "") || obj2 instanceof String || obj2 instanceof Character) { + return true; + } else if (obj2 instanceof DataType) { + if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { + return true; + } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { + return true; + } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { + return true; + } else { + throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); + } + } else { + throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); + } + } + } + throw new RuntimeException("筛选条件[!=]:左边必须是表单控件"); + } +} diff --git a/src/com/engine/salary/formlua/func/compare/EqOperator.java b/src/com/engine/salary/formlua/func/compare/EqOperator.java new file mode 100644 index 000000000..81aeef54a --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/EqOperator.java @@ -0,0 +1,243 @@ +package com.engine.salary.formlua.func.compare; + +import com.alibaba.fastjson.JSON; +import com.engine.salary.formlua.core.exception.ErrorType; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.CompareUtil; +import com.engine.salary.formlua.util.DateUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.ql.util.express.ArraySwap; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.instruction.op.OperatorEqualsLessMore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + + +public class EqOperator extends OperatorEqualsLessMore { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + public EqOperator(String aName) { + super(aName); + } + + public EqOperator(String aAliasName, String aName, String aErrorInfo) { + super(aAliasName, aName, aErrorInfo); + } + + @Override + public OperateData executeInner(InstructionSetContext context, ArraySwap list) throws Exception { + return super.executeInner(context, list); + } + + @Override + public Object executeInner(Object... list) throws Exception { + DataType result=new DataType(); + result.setDataType(DataType.BOOL); + logger.info("等于号参数:"+JSON.toJSONString(list)); + String oper="="; + if(list.length!=2){ + throw new RuntimeException("[=]"+ ErrorType.MAX_VAR_COUNT.name()); + } + Object op1=list[0]; + Object op2=list[1]; + //校验参数类型 + String datatype= ExcelParamUtil.checkParamType(op1); + String dataType2=ExcelParamUtil.checkParamType(op2); + if(op2 instanceof Object[]){ + Object[] objectParams=(Object[])op2; + if(objectParams[0] instanceof DataType){ + DataType paramDataType=(DataType)objectParams[0]; + dataType2=paramDataType.getDataType(); + }else{ + dataType2=ExcelParamUtil.checkParamType(objectParams[0]); + } + } + + if(datatype.equals(DataType.OPTION)||dataType2.equals(DataType.OPTION)){ + //对option的特殊处理,获取option的字符串后根据逗号分割,然后排序数组,数组长度不一致返回false,一致则循环对比直到同样下标的数据不一致返回false,否则为true + try { + String[] firstOptions=new String[]{}; + String[] secondOptions=new String[]{}; + result.setContent(true); + firstOptions= CompareUtil.genArray(op1,"option"); + secondOptions=CompareUtil.genArray(op2,"option"); + Arrays.sort(firstOptions); + Arrays.sort(secondOptions); + +// logger.info("比较选项:"+JSON.toJSONString(firstOptions)+"-->"+JSON.toJSONString(secondOptions)); + if(firstOptions.length!=secondOptions.length){ + result.setContent(false); + }else{ + int i=0; + for (;i dataList=ExcelParamUtil.converParamValue(op1,op2); + if(ExcelParamUtil.getParamType(op1).toLowerCase().equals("double")||ExcelParamUtil.getParamType(op2).toLowerCase().equals("double")){ + boolean r=OperatorEqualsLessMore.executeInner("=",ExcelParamUtil.convertParamValToNumber(dataList.get(0)),ExcelParamUtil.convertParamValToNumber(dataList.get(1))); + result.setContent(r); + }else if(op1 instanceof DataType && op2 instanceof DataType && DateUtil.isDateComponent(op1) && DateUtil.isDateComponent(op2)){ + + + Object dateStringOne=null; + if(op1 instanceof DataType){ + DataType dataTypeOne=(DataType)op1; + dateStringOne=dataTypeOne.getContent(); + }else{ + dateStringOne=op1; + } + + Object dateStringTwo=null; + if(op2 instanceof DataType){ + DataType dataTypeTwo=(DataType)op2; + dateStringTwo=dataTypeTwo.getContent(); + }else{ + dateStringTwo=op2; + } + boolean dateResult=false; + Date firstDate=DateUtil.buildDateByDateChar(dateStringOne==null?"":dateStringOne+""); + Date secondDate= DateUtil.buildDateByDateChar(dateStringTwo==null?"":dateStringTwo+""); + if (firstDate == null && secondDate == null){ + dateResult= true; + }else if(firstDate==null || secondDate ==null){ + dateResult= false; + }else{ + dateResult= firstDate.getTime()==secondDate.getTime(); + } + result.setContent(dateResult); + }else { + Object firstParam=ExcelParamUtil.getParamContent(dataList.get(0),""); + Object secondParam=ExcelParamUtil.getParamContent(dataList.get(1),""); + logger.info("等于号比较:"+firstParam+"-->"+secondParam); + if((firstParam instanceof String || firstParam instanceof Character) && (secondParam instanceof String || secondParam instanceof Character)){ + if(firstParam.toString().length()==1&&secondParam.toString().length()==1){ + boolean r=firstParam.toString().equals(secondParam.toString()); + result.setContent(r); + return result; + } + } + boolean r=OperatorEqualsLessMore.executeInner("=",firstParam,secondParam); + result.setContent(r); + } + } catch (Exception e) { + logger.error("err",e); + } + } +// buildFilterParam(result,op1,op2); + return result; + } + + /** + * 构建搜索条件参数 + * @param dataType + * @param obj1 + * @param obj2 + */ +// private void buildFilterParam(DataType dataType,Object obj1,Object obj2){ +// List filterFormDataList=new ArrayList<>(); +// FormulaFilterData filterData=new FormulaFilterData(); +// String content = null; +// try { +// if(obj1!=null && (obj1 instanceof DataType)){ +// DataType dataType1=(DataType)obj1; +// if(StringUtils.isEmpty(dataType1.getComponentKey())){ +// dataType1.setComponentKey(dataType1.getDataType()); +// } +// if(obj2 instanceof DataType) { +//// content = ((DataType) obj2).getContent()+""; +// DataType paramDataType=(DataType) obj2; +// if(paramDataType==null || paramDataType.getContent() == null){ +// content = ""; +// }else{ +// content = paramDataType.getContent()+""; +// } +// }else { +// content = obj2+""; +// } +// if ( content != null) { +// filterData.setFieldId(dataType1.getFieldId()); +// if(dataType1.getSubFormId() != null) { +// filterData.setSubFormId(dataType1.getSubFormId()+""); +// } +// +// filterData.setComponentKey(dataType1.getComponentKey()); +// if(StringUtils.isEmpty(content)) { +// filterData.setTerm(FilterFormData.TERM_NULL); +// }else{ +// filterData.setTerm(FilterFormData.TERM_EQ); +// if(StringUtils.isNotEmpty(dataType1.getComponentKey())){ +// //数字类型 +// if(ComponentConfig.isNumberComponent(dataType1.getComponentKey()) +// || dataType1.getComponentKey().equals(ComponentType.DateComponent.toString()) +// || dataType1.getComponentKey().equals(ComponentType.TimeComponent.toString()) +// || dataType1.getComponentKey().equalsIgnoreCase(DataType.STRING) +// || dataType1.getComponentKey().equalsIgnoreCase(DataType.NUMBER)|| +// dataType1.getComponentKey().equalsIgnoreCase(DataType.DATE) +// || dataType1.getComponentKey().equalsIgnoreCase(DataType.BOOL) +// ) { +// filterData.setContent(content); +// //选项控件 +// }else if(ComponentConfig.isOptionComponent(dataType1.getComponentKey())) { +// List ids = new ArrayList<>(); +// String[] idsArray = content.split(","); +// for(String idStr : idsArray) { +// if(StringUtils.isNotBlank(idStr)) { +// ids.add(idStr); +// } +// } +// filterData.setIds(ids); +// //文本型 +// }else { +// filterData.setContent(content); +// } +// } +// +// } +// } +// if(filterData!=null){ +// filterFormDataList.add(filterData); +// } +// +// logger.info("=号构建过滤参数:"+(filterFormDataList!=null? JSON.toJSONString(filterFormDataList):"NULL")); +// dataType.setFormulaFilterDataList(filterFormDataList); +// dataType.setComponentKey(dataType1.getComponentKey()); +// dataType.setSubFormId(dataType1.getSubFormId()); +// } +// } catch (Exception e) { +// logger.error("err",e); +// } +// +// } + + +} diff --git a/src/com/engine/salary/formlua/func/compare/GreaterEqOperator.java b/src/com/engine/salary/formlua/func/compare/GreaterEqOperator.java new file mode 100644 index 000000000..7e9a27055 --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/GreaterEqOperator.java @@ -0,0 +1,104 @@ +package com.engine.salary.formlua.func.compare; + +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.CompareUtil; +import com.engine.salary.formlua.util.DateUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.ql.util.express.instruction.op.OperatorEqualsLessMore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + + +public class GreaterEqOperator extends OperatorEqualsLessMore { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public Object executeInner(Object op1, Object op2) throws Exception { + DataType result = new DataType(); + result.setDataType(DataType.BOOL); + String datatype = ExcelParamUtil.checkParamType(op1); + //对option的特殊处理,获取option的字符串后根据逗号分割,然后排序数组,数组长度不一致返回false,一致则循环对比直到同样下标的数据不一致返回false,否则为true + try { + if (datatype.equals(DataType.OPTION)) { + result.setContent(true); + String[] firstOptions = new String[]{}; + String[] secondOptions = new String[]{}; + firstOptions = CompareUtil.genArray(op1, "option"); + secondOptions = CompareUtil.genArray(op2, "option"); + Arrays.sort(firstOptions); + Arrays.sort(secondOptions); + if (firstOptions.length != secondOptions.length) { + result.setContent(false); + } else { + int i = 0; + for (; i < firstOptions.length; i++) { + boolean loopresult = OperatorEqualsLessMore.executeInner(">=", firstOptions[i], secondOptions[i]); + if (!loopresult) { + result.setContent(false); + break; + } + } + } + } else if (op1 instanceof DataType && op2 instanceof DataType && DateUtil.isDateComponent(op1) && DateUtil.isDateComponent(op2)) { + + + Object dateStringOne = null; + if (op1 instanceof DataType) { + DataType dataTypeOne = (DataType) op1; + dateStringOne = dataTypeOne.getContent(); + } else { + dateStringOne = op1; + } + + Object dateStringTwo = null; + if (op2 instanceof DataType) { + DataType dataTypeTwo = (DataType) op2; + dateStringTwo = dataTypeTwo.getContent(); + } else { + dateStringTwo = op2; + } + boolean dateResult = false; + Date firstDate = DateUtil.buildDateByDateChar(dateStringOne == null ? "" : dateStringOne + ""); + Date secondDate = DateUtil.buildDateByDateChar(dateStringTwo == null ? "" : dateStringTwo + ""); + if (firstDate == null && secondDate == null) { + dateResult = true; + } else if (firstDate == null && secondDate != null) { + dateResult = false; + } else if (firstDate != null && secondDate == null) { + dateResult = true; + } else { + dateResult = firstDate.getTime() >= secondDate.getTime(); + } + result.setContent(dateResult); + } else { + List dataList = ExcelParamUtil.converParamValue(op1, op2); + boolean r; + if (ExcelParamUtil.getParamType(op1).toLowerCase().equals("double") || ExcelParamUtil.getParamType(op2).toLowerCase().equals("double")) { + r = OperatorEqualsLessMore.executeInner(">=", ExcelParamUtil.convertParamValToNumber(dataList.get(0)), ExcelParamUtil.convertParamValToNumber(dataList.get(1))); + } else { + r = OperatorEqualsLessMore.executeInner(">=", ExcelParamUtil.getParamContent(dataList.get(0), ""), ExcelParamUtil.getParamContent(dataList.get(1), "")); + } + result.setContent(r); + } + } catch (Exception e) { + logger.error("err", e); + result.setContent(false); + } +// Compareutils.buildLessMoreFilterParam(result,this.name,op1,op2); + return result; + } + + public GreaterEqOperator(String aAliasName, String aName, String aErrorInfo) { + super(aAliasName, aName, aErrorInfo); + } + + public GreaterEqOperator(String aName) { + super(aName); + } + + +} diff --git a/src/com/engine/salary/formlua/func/compare/GreaterOperator.java b/src/com/engine/salary/formlua/func/compare/GreaterOperator.java new file mode 100644 index 000000000..ba9f3050b --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/GreaterOperator.java @@ -0,0 +1,105 @@ +package com.engine.salary.formlua.func.compare; + +import com.alibaba.fastjson.JSON; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.CompareUtil; +import com.engine.salary.formlua.util.DateUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.ql.util.express.instruction.op.OperatorEqualsLessMore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Date; + + +public class GreaterOperator extends OperatorEqualsLessMore { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + public Object executeInner(Object op1, Object op2) throws Exception { + DataType result = new DataType(); + result.setDataType(DataType.BOOL); +// IgnoreParamFilter.filterCompareFunc(op1,op2,">"); + String datatype = ExcelParamUtil.checkParamType(op1); + logger.info("大于号比较:" + JSON.toJSONString(op1) + "-->" + JSON.toJSONString(op2)); + //对option的特殊处理,获取option的字符串后根据逗号分割,然后排序数组,数组长度不一致返回false,一致则循环对比直到同样下标的数据不一致返回false,否则为true + try { + if (datatype.equals(DataType.OPTION)) { + result.setContent(true); + String[] firstOptions = new String[]{}; + String[] secondOptions = new String[]{}; + firstOptions = CompareUtil.genArray(op1, "option"); + secondOptions = CompareUtil.genArray(op2, "option"); + Arrays.sort(firstOptions); + Arrays.sort(secondOptions); + if (firstOptions.length != secondOptions.length) { + result.setContent(false); + } else { + int i = 0; + for (; i < firstOptions.length; i++) { + boolean loopresult = OperatorEqualsLessMore.executeInner(">", firstOptions[i], secondOptions[i]); + if (!loopresult) { + result.setContent(false); + break; + } + } + } + } else if (op1 instanceof DataType && op2 instanceof DataType && DateUtil.isDateComponent(op1) && DateUtil.isDateComponent(op2)) { + + + Object dateStringOne = null; + if (op1 instanceof DataType) { + DataType dataTypeOne = (DataType) op1; + dateStringOne = dataTypeOne.getContent(); + } else { + dateStringOne = op1; + } + + Object dateStringTwo = null; + if (op2 instanceof DataType) { + DataType dataTypeTwo = (DataType) op2; + dateStringTwo = dataTypeTwo.getContent(); + } else { + dateStringTwo = op2; + } + boolean dateResult = false; + Date firstDate = DateUtil.buildDateByDateChar(dateStringOne == null ? "" : dateStringOne + ""); + Date secondDate = DateUtil.buildDateByDateChar(dateStringTwo == null ? "" : dateStringTwo + ""); + if (firstDate == null && secondDate == null) { + dateResult = false; + } else if (firstDate == null && secondDate != null) { + dateResult = false; + } else if (firstDate != null && secondDate == null) { + dateResult = true; + } else { + dateResult = firstDate.getTime() > secondDate.getTime(); + } + result.setContent(dateResult); + } else { + logger.info("参数1:" + ExcelParamUtil.convertParamValToNumber(op1) + ""); + logger.info("参数2:" + ExcelParamUtil.convertParamValToNumber(op2) + ""); + boolean r; + if (ExcelParamUtil.getParamType(op1).toLowerCase().equals("double") || ExcelParamUtil.getParamType(op2).toLowerCase().equals("double")) { + r = OperatorEqualsLessMore.executeInner(">", ExcelParamUtil.convertParamValToNumber(op1), ExcelParamUtil.convertParamValToNumber(op2)); + } else { + r = OperatorEqualsLessMore.executeInner(">", ExcelParamUtil.getParamContent(op1, ""), ExcelParamUtil.getParamContent(op2, "")); + } + result.setContent(r); + } + } catch (Exception e) { + logger.error("err", e); + result.setContent(false); + } + Compareutils.buildLessMoreFilterParam(result, this.name, op1, op2); + return result; + } + + public GreaterOperator(String aName) { + super(aName); + } + + public GreaterOperator(String aAliasName, String aName, String aErrorInfo) { + super(aAliasName, aName, aErrorInfo); + } +} diff --git a/src/com/engine/salary/formlua/func/compare/InOperator.java b/src/com/engine/salary/formlua/func/compare/InOperator.java new file mode 100644 index 000000000..22d7dcf6f --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/InOperator.java @@ -0,0 +1,97 @@ +package com.engine.salary.formlua.func.compare; + +import com.alibaba.fastjson.JSON; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.func.logic.LogicUtils; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.engine.salary.formlua.util.IgnoreParamFilter; +import com.ql.util.express.instruction.op.OperatorIn; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + + +public class InOperator extends OperatorIn { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Override + public Object executeInner(Object[] list) throws Exception { + DataType result=new DataType(); + result.setDataType(DataType.BOOL); + if(list.length<1||list[1]==null){ + Integer number= IgnoreParamFilter.getSetFuncNumber("IN"); + } + List paramList=new ArrayList<>(); + paramList.add(list[0]); + Object[] objectArray=(Object[])list[1]; + for (int i=0;i(); + paramList.add(null); + List dataArray=new ArrayList<>(); + if(list[0] instanceof DataType){ + DataType dataType=(DataType)list[0]; + if(dataType.getDataType().equals(DataType.OPTION)){ + if(dataType.getContent()!=null){ + String[] arrys=dataType.getContent().toString().split(","); + for (int i=0;i dataList=ExcelParamUtil.converParamValue(op1,op2); + boolean r; + if(ExcelParamUtil.getParamType(op1).toLowerCase().equals("double")||ExcelParamUtil.getParamType(op2).toLowerCase().equals("double")){ + r=OperatorEqualsLessMore.executeInner("<=",ExcelParamUtil.convertParamValToNumber(dataList.get(0)),ExcelParamUtil.convertParamValToNumber(dataList.get(1))); + }else { + r=OperatorEqualsLessMore.executeInner("<=",ExcelParamUtil.getParamContent(dataList.get(0),""),ExcelParamUtil.getParamContent(dataList.get(1),"")); + } + result.setContent(r); + } + } catch (Exception e) { + logger.error("err",e); + result.setContent(false); + } + Compareutils.buildLessMoreFilterParam(result,this.name,op1,op2); + return result; + } + + public LessEqOperator(String aName) { + super(aName); + } + + public LessEqOperator(String aAliasName, String aName, String aErrorInfo) { + super(aAliasName, aName, aErrorInfo); + } +} diff --git a/src/com/engine/salary/formlua/func/compare/LessOperator.java b/src/com/engine/salary/formlua/func/compare/LessOperator.java new file mode 100644 index 000000000..5d5348889 --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/LessOperator.java @@ -0,0 +1,104 @@ +package com.engine.salary.formlua.func.compare; + +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.CompareUtil; +import com.engine.salary.formlua.util.DateUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.ql.util.express.instruction.op.OperatorEqualsLessMore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + + +public class LessOperator extends OperatorEqualsLessMore { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Override + public Object executeInner(Object op1, Object op2) throws Exception { + DataType result=new DataType(); + result.setDataType(DataType.BOOL); +// IgnoreParamFilter.filterCompareFunc(op1,op2,"<"); + String datatype= ExcelParamUtil.checkParamType(op1); + + //对option的特殊处理,获取option的字符串后根据逗号分割,然后排序数组,数组长度不一致返回false,一致则循环对比直到同样下标的数据不一致返回false,否则为true + try { + if(datatype.equals(DataType.OPTION)){ + result.setContent(true); + String[] firstOptions=new String[]{}; + String[] secondOptions=new String[]{}; + firstOptions= CompareUtil.genArray(op1,"option"); + secondOptions=CompareUtil.genArray(op2,"option"); + Arrays.sort(firstOptions); + Arrays.sort(secondOptions); + if(firstOptions.length!=secondOptions.length){ + result.setContent(false); + }else{ + int i=0; + for (;i dataList=ExcelParamUtil.converParamValue(op1,op2); + boolean r; + if(ExcelParamUtil.getParamType(op1).toLowerCase().equals("double")||ExcelParamUtil.getParamType(op2).toLowerCase().equals("double")){ + r=OperatorEqualsLessMore.executeInner("<",ExcelParamUtil.convertParamValToNumber(dataList.get(0)),ExcelParamUtil.convertParamValToNumber(dataList.get(1))); + }else { + r=OperatorEqualsLessMore.executeInner("<",ExcelParamUtil.getParamContent(dataList.get(0),""),ExcelParamUtil.getParamContent(dataList.get(1),"")); + } + result.setContent(r); + } + } catch (Exception e) { + logger.error("err",e); + result.setContent(false); + } + Compareutils.buildLessMoreFilterParam(result,this.name,op1,op2); + return result; + } + + public LessOperator(String aName) { + super(aName); + } + + public LessOperator(String aAliasName, String aName, String aErrorInfo) { + super(aAliasName, aName, aErrorInfo); + } + +} diff --git a/src/com/engine/salary/formlua/func/compare/NotEqueOperator.java b/src/com/engine/salary/formlua/func/compare/NotEqueOperator.java new file mode 100644 index 000000000..5b34a14bf --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/NotEqueOperator.java @@ -0,0 +1,102 @@ +package com.engine.salary.formlua.func.compare; + +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.CompareUtil; +import com.engine.salary.formlua.util.DateUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.ql.util.express.instruction.op.OperatorEqualsLessMore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.List; + +public class NotEqueOperator extends OperatorEqualsLessMore { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public Object executeInner(Object op1, Object op2) throws Exception { + DataType result = new DataType(); + result.setDataType(DataType.BOOL); +// IgnoreParamFilter.filterCompareFunc(op1,op2,"!="); + String datatype = ExcelParamUtil.checkParamType(op1); + + //对option的特殊处理,获取option的字符串后根据逗号分割,然后排序数组,数组长度不一致返回false,一致则循环对比直到同样下标的数据不一致返回false,否则为true + try { + if (datatype.equals(DataType.OPTION)) { + result.setContent(true); + String[] firstOptions = new String[]{}; + String[] secondOptions = new String[]{}; + firstOptions = CompareUtil.genArray(op1, "option"); + secondOptions = CompareUtil.genArray(op2, "option"); + if (firstOptions.length != secondOptions.length) { + result.setContent(true); + } else { + int i = 0; + for (; i < firstOptions.length; i++) { + boolean loopresult = OperatorEqualsLessMore.executeInner("!=", firstOptions[i], secondOptions[i]); + if (!loopresult) { + result.setContent(false); + break; + } + } + } + } else if (op1 instanceof DataType && op2 instanceof DataType && DateUtil.isDateComponent(op1) && DateUtil.isDateComponent(op2)) { + + + Object dateStringOne = null; + if (op1 instanceof DataType) { + DataType dataTypeOne = (DataType) op1; + dateStringOne = dataTypeOne.getContent(); + } else { + dateStringOne = op1; + } + + Object dateStringTwo = null; + if (op2 instanceof DataType) { + DataType dataTypeTwo = (DataType) op2; + dateStringTwo = dataTypeTwo.getContent(); + } else { + dateStringTwo = op2; + } + boolean dateResult = false; + Date firstDate = DateUtil.buildDateByDateChar(dateStringOne == null ? "" : dateStringOne + ""); + Date secondDate = DateUtil.buildDateByDateChar(dateStringTwo == null ? "" : dateStringTwo + ""); + if (firstDate == null && secondDate == null) { + dateResult = false; + } else if ((firstDate == null && secondDate != null) || (firstDate != null && secondDate == null)) { + dateResult = true; + } else { + dateResult = firstDate.getTime() != secondDate.getTime(); + } + result.setContent(dateResult); + } else { + List dataList = ExcelParamUtil.converParamValue(op1, op2); + Object firstParam = ExcelParamUtil.getParamContent(dataList.get(0), ""); + Object secondParam = ExcelParamUtil.getParamContent(dataList.get(1), ""); + if ((firstParam instanceof String || firstParam instanceof Character) && (secondParam instanceof String || secondParam instanceof Character)) { + if (firstParam.toString().length() == 1 && secondParam.toString().length() == 1) { + boolean r = !(firstParam.toString().equals(secondParam.toString())); + result.setContent(r); + return result; + } + } + boolean r = OperatorEqualsLessMore.executeInner("!=", firstParam, secondParam); + result.setContent(r); + } + } catch (Exception e) { + logger.error("err", e); + result.setContent(false); + } + Compareutils.buildNotEqFilterParam(result, op1, op2); + return result; + } + + public NotEqueOperator(String aName) { + super(aName); + } + + public NotEqueOperator(String aAliasName, String aName, String aErrorInfo) { + super(aAliasName, aName, aErrorInfo); + } +} diff --git a/src/com/engine/salary/formlua/func/compare/OperatorInTest.java b/src/com/engine/salary/formlua/func/compare/OperatorInTest.java new file mode 100644 index 000000000..ec5701582 --- /dev/null +++ b/src/com/engine/salary/formlua/func/compare/OperatorInTest.java @@ -0,0 +1,38 @@ +package com.engine.salary.formlua.func.compare; + +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.engine.salary.formlua.util.IgnoreParamFilter; +import com.ql.util.express.instruction.op.OperatorIn; + +import java.util.ArrayList; +import java.util.List; + + +public class OperatorInTest extends OperatorIn { + + @Override + public Object executeInner(Object[] list) throws Exception { + DataType result=new DataType(); + result.setDataType(DataType.BOOL); + result.setContent(true); + if(list.length<2||list[1]==null){ + Integer number= IgnoreParamFilter.getSetFuncNumber("IN"); + } + List paramList=new ArrayList<>(); + paramList.add(list[0]); + Object[] objectArray=(Object[])list[1]; + for (int i=0;i operList= CommonOper.operAddReduceList(obj1,obj2); + for (int i=0;i operList= CommonOper.operDivMultiList(firstParam,secondParam,"/"); + Object[] results=new Object[operList.size()]; + for (int i=0;i operList= CommonOper.operDivMultiList(firstParam,secondParam,"*"); + Object[] results=new Object[operList.size()]; + for (int i=0;i operList= CommonOper.operAddReduceList(obj1,obj2); + for (int i=0;i 0) { + return new DataType(DataType.STRING, ""); + } + formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String nowStr = formatter.format(new Date()); + return new DataType(DataType.STRING, nowStr); + } + + /** + * 返回当前日期 + * + * @return + */ + @Override + public DataType today(Object... objects) { + int number = IgnoreParamFilter.getSetFuncNumber(FuncNames.TODAY.toString()); + if (objects.length > 0) { + return new DataType(DataType.STRING, ""); + } + formatter = new SimpleDateFormat("yyyy-MM-dd"); + String dateStr = formatter.format(new Date()); + return new DataType(DataType.STRING, dateStr); + } + + /** + * 格式化时间日期 + * + * @param objects + * @return + */ + @Override + public DataType dateFormat(Object... objects) { + Class[] typeObjects = new Class[]{DateAndString.class, String.class}; + String func = "DATEFORMAT"; + IgnoreParamFilter.commonFilter(func, 2, 2, typeObjects, objects); + Object result = objects[0]; + String dateStr = ""; + Object p1 = objects[0]; + Object p2 = objects[1]; + if (ExcelParamUtil.checkIsNull(p1, p2)) { + throw new RuntimeException("日期格式化函数参数不能为空"); + } + if (p1 instanceof DataType) { + DataType dataType = (DataType) p1; + dateStr = ExcelParamUtil.getParamContent(dataType.getContent(), "date") != null ? ExcelParamUtil.getParamContent(dataType.getContent(), "date").toString() : ""; + } else { + if (p1 instanceof Date) { + dateStr = formatter.format(p1); + } else { + dateStr = p1.toString(); + } + } + String formatStr = (ExcelParamUtil.getParamContent(p2, "string") != null ? ExcelParamUtil.getParamContent(p2, "string") : "").toString().replaceAll("D", "d"); + try { + String formatterStr = DateUtil.buildFormat(dateStr); + formatter = new SimpleDateFormat(formatterStr); + Date sourceDate = formatter.parse(dateStr); + formatter = new SimpleDateFormat(formatStr); + dateStr = formatter.format(sourceDate); + result = dateStr; + } catch (ParseException e) { + logger.error("err", e); + return new DataType(DataType.STRING, ""); + } + + return new DataType(DataType.STRING, result); + } + + /** + * 两个日期加减 + * + * @param + * @param + * @return + */ + @Override + public DataType dateDiff(Object... objects) { + Class[] typeObjects = new Class[]{DateAndString.class, DateAndString.class, String.class}; + IgnoreParamFilter.commonFilter("DATEDIFF", 2, 3, typeObjects, objects); + Long secondsL = new Long(60 * 60 * 1000);//计算日期时间间距的单位,默认为小时 + + Long nd = buildSecondsFmt("D"); + Long nh = buildSecondsFmt("H"); + Long nm = buildSecondsFmt("I"); + Long ns = buildSecondsFmt("S"); + + + Double result = new Double(0); + String type = "D"; + String sContent = DateUtil.getContent(objects[0], formatter); + String eContent = DateUtil.getContent(objects[1], formatter); + if (ExcelParamUtil.checkIsNull(sContent, eContent, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + Date startDate = null; + Date endDate = null; + + format = DateUtil.buildFormat(sContent); + startDate = formateDateStr(sContent, format); + format = DateUtil.buildFormat(eContent); + endDate = formateDateStr(eContent, format); + if (startDate == null || endDate == null) { + return new DataType(DataType.NUMBER, 0); + } + Calendar cal1 = Calendar.getInstance(); + cal1.setTime(startDate); + //当前时间 + Calendar cal2 = Calendar.getInstance(); + cal2.setTime(endDate); + + + long diff = cal2.getTime().getTime() - cal1.getTime().getTime(); + + if (objects.length == 3) { + type = ExcelParamUtil.getParamContent(objects[2], "string") != null ? ExcelParamUtil.getParamContent(objects[2], "string").toString() : ""; + secondsL = buildSecondsFmt(type); + } + Double time = new Double(0); + boolean checkType = true; + switch (type) { + case "Y": + time = DateTimeServiceImpl.getTime(startDate, endDate) / (nd.doubleValue()) / 365.0; + break; + case "M": + Long monthR = DateTimeServiceImpl.getByField(cal1, cal2, Calendar.YEAR) * 12 + DateTimeServiceImpl.getByField(cal1, cal2, Calendar.MONTH); + time = monthR.doubleValue(); + break; + case "D": + double dayR = DateTimeServiceImpl.getTime(startDate, endDate) / (nd.doubleValue()); + time = dayR; + break; + case "H": + double hourH = DateTimeServiceImpl.getTime(startDate, endDate) / (nh.doubleValue()); + time = hourH; + break; + case "I": + double minuR = DateTimeServiceImpl.getTime(startDate, endDate) / (nm.doubleValue()); + time = minuR; + break; + case "S": + double seconR = DateTimeServiceImpl.getTime(startDate, endDate) / ns.doubleValue(); + time = seconR; + break; + default: + checkType = false; + break; + } + if (!checkType) { + return new DataType(DataType.STRING, ""); + } + BigDecimal b = new BigDecimal(time); + double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); + result = f1; + return new DataType(DataType.NUMBER, result); + } + + /** + * 日期加减天数 + * + * @param objects + * @return + */ + @Override + public DataType dateAdd(Object... objects) { + Class[] typeObjects = new Class[]{DateAndString.class, Integer.class, String.class}; + IgnoreParamFilter.commonFilter("DATEADD", 2, 3, typeObjects, objects); + + String type = "D"; + if (objects.length == 3) { + type = objects[2].toString(); + } + + Object tcontent = DateUtil.getContent(objects[0], formatter); + Double numD = Double.parseDouble(ExcelParamUtil.getParamContent(objects[1], "") != null ? ExcelParamUtil.getParamContent(objects[1], "").toString() : ""); + + int num = numD.intValue(); + if (ExcelParamUtil.checkIsNull(tcontent, numD, type, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.STRING, ""); + } + Object result = ""; + + try { + Date date = null; + if (tcontent instanceof String || tcontent instanceof Character) { + format = DateUtil.buildFormat(tcontent.toString()); + if (null == format) { + return new DataType(DataType.STRING, ""); + } + date = formateDateStr(tcontent.toString(), format); + } else { + date = (Date) tcontent; + } + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + boolean checkType = true; + switch (type) { + case "Y": + cal.add(Calendar.YEAR, num); + break; + case "M": + cal.add(Calendar.MONTH, num); + break; + case "D": + cal.add(Calendar.DAY_OF_MONTH, num); + break; + case "H": + cal.add(Calendar.HOUR_OF_DAY, num); + break; + case "I": + cal.add(Calendar.MINUTE, num); + break; + case "S": + cal.add(Calendar.SECOND, num); + break; + default: + checkType = false; + break; + } + if (!checkType) { + String func = "DATEADD"; + return new DataType(DataType.STRING, ""); + } + Date newDate = cal.getTime(); + String nDate = formateDateStr(newDate, format); + result = nDate; + + } catch (ParseException e) { + logger.error("err", e); + } + return new DataType(DataType.STRING, result); + } + + /** + * 返回年份 + * + * @param objects + * @return + */ + @Override + public DataType year(Object... objects) { + Object reuslt = new Object(); + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("YEAR", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + int year = 0; + try { + year = getDateTimeValue(date, "Y", "YEAR"); + reuslt = year; + } catch (ParseException e) { + logger.error("err", e); + } + + return new DataType(DataType.NUMBER, reuslt); + } + + /** + * 返回是今年第几月 + * + * @param objects + * @return + */ + @Override + public DataType month(Object... objects) { + + Object reuslt = new Object(); + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("MONTH", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + boolean isDate = checkDateString(date != null ? date.toString() : ""); + if (!isDate) { + return new DataType(DataType.NUMBER, 0); + } + int month = 0; + try { + month = getDateTimeValue(date, "M", "MONTH"); + reuslt = month + 1; + } catch (ParseException e) { + logger.error("err", e); + } + + return new DataType(DataType.NUMBER, reuslt); + + } + + /** + * 返回日期是本月几号 + * + * @param objects + * @return + */ + @Override + public DataType day(Object... objects) { + Object reuslt = new Object(); + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("DAY", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + int day = 0; + try { + day = getDateTimeValue(date, "D", "DAY"); + reuslt = day; + } catch (ParseException e) { + logger.error("err", e); + } + + return new DataType(DataType.NUMBER, reuslt); + + } + + /** + * 返回时钟位置 + * + * @param objects + * @return + */ + @Override + public DataType hour(Object... objects) { + + Object reuslt = new Object(); + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("HOUR", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + Integer hour = 0; + try { + hour = getDateTimeValue(date, "H", "HOUR"); + reuslt = hour; + } catch (ParseException e) { + logger.error("err", e); + } + + return new DataType(DataType.NUMBER, reuslt); + + } + + /** + * 返回分钟位置 + * + * @param objects + * @return + */ + @Override + public DataType minute(Object... objects) { + Object reuslt = new Object(); + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("MINUTE", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + int minute = 0; + try { + minute = getDateTimeValue(date, "I", "MINUTE"); + + reuslt = minute; + } catch (ParseException e) { + logger.error("err", e); + } + + return new DataType(DataType.NUMBER, reuslt); + } + + /*** + * 返回秒钟位置 + * @param objects + * @return + */ + @Override + public DataType seconds(Object... objects) { + Object reuslt = new Object(); + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("SECOND", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + int seconds = 0; + try { + seconds = getDateTimeValue(date, "S", "SECOND"); + reuslt = seconds; + } catch (ParseException e) { + logger.error("err", e); + } + + return new DataType(DataType.NUMBER, reuslt); + + } + + /** + * 计算是本月的第几周 + * + * @param objects + * @return + */ + @Override + public DataType weekNum(Object... objects) { + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("WEEKNUM", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + int weekNum = 0; + try { + weekNum = getDateTimeValue(date, "WM", "WEEKNUM"); + } catch (ParseException e) { + logger.error("err", e); + } + return new DataType(DataType.NUMBER, weekNum); + } + + /** + * 判断是周几,因为周几是从周天的0开始算,所以返回数据需要减1 + * + * @param objects + * @return + */ + @Override + public DataType weekDay(Object... objects) { + Class[] typeObjects = new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("WEEKDAY", 1, 1, typeObjects, objects); + Object obj = objects[0]; + Object date = DateUtil.getContent(obj, formatter); + if (ExcelParamUtil.checkIsNull(date, ExcelParamUtil.CHECKLEVEL_STRING)) { + return new DataType(DataType.NUMBER, 0); + } + int weekDay = 0; + try { + weekDay = getDateTimeValue(date, "DW", "WEEKDAY"); + } catch (ParseException e) { + logger.error("err", e); + } + return new DataType(DataType.NUMBER, weekDay > 0 ? (weekDay - 1) : weekDay); + } + + @Override + public DataType dayOfMonth(Object... objects) { + String dayType = ""; + if (objects != null && objects.length > 0 && objects[0] != null) { + dayType = objects[0].toString(); + } + + // 获取当前年份、月份、日期 + Calendar cale = null; + // 获取当月第一天和最后一天 + SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + String firstday = "", lastday = ""; + String date = ""; + switch (dayType.toLowerCase()) { + case "first": + // 获取当前月的第一天 + cale = Calendar.getInstance(); + cale.add(Calendar.MONTH, 0); + cale.set(Calendar.DAY_OF_MONTH, 1); + cale.set(Calendar.HOUR_OF_DAY, 0); + cale.set(Calendar.MINUTE, 0); + firstday = formatTemp.format(cale.getTime()); + date = firstday; + break; + case "last": + // 获取当前月的最后一天 + cale = Calendar.getInstance(); + cale.add(Calendar.MONTH, 1); + cale.set(Calendar.DAY_OF_MONTH, 0); + cale.set(Calendar.HOUR_OF_DAY, 0); + cale.set(Calendar.MINUTE, 0); + lastday = formatTemp.format(cale.getTime()); + date = lastday; + break; + default: + // 获取指定的某一天 + if (dayType == null || dayType.trim().equalsIgnoreCase("")) { + dayType = "0"; + } + cale = Calendar.getInstance(); + cale.add(Calendar.MONTH, 1); + cale.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dayType)); + cale.set(Calendar.HOUR_OF_DAY, 0); + cale.set(Calendar.MINUTE, 0); + lastday = formatTemp.format(cale.getTime()); + date = lastday; + break; + } + logger.info("firstday:" + firstday + " lastday:" + lastday); + return new DataType(DataType.STRING, date); + } + + @Override + public DataType monthOfYear(Object... objects) { + String dayType = ""; + if (objects != null && objects.length > 0 && objects[0] != null) { + dayType = objects[0].toString(); + } + if (dayType == null || dayType.equalsIgnoreCase("")) { + dayType = "0"; + } + int month = Integer.parseInt(dayType); + if (month > 0) { + month -= 1; + } + SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + Calendar cale = Calendar.getInstance(); + cale.set(cale.get(Calendar.YEAR), month, 1); + + String lastday = formatTemp.format(cale.getTime()); + System.out.println(lastday); + return new DataType(DataType.STRING, lastday); + } + + @Override + public DataType timeOfDay(Object... objects) { + String dayType = ""; + if (objects != null && objects.length > 0 && objects[0] != null) { + dayType = objects[0].toString(); + } + SimpleDateFormat dayFormatTemp = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat formatTemp = new SimpleDateFormat("HH:mm"); + Calendar cale = Calendar.getInstance(); + try { + cale.setTime(new Date()); + } catch (Exception e) { + logger.error("err", e); + } + cale.set(Calendar.HOUR_OF_DAY, Integer.parseInt(dayType)); + cale.set(Calendar.MINUTE, 0); + String lastday = formatTemp.format(cale.getTime()); + return new DataType(DataType.STRING, lastday); + } + + @Override + public DataType eoMonth(Object... objects) { + Object result = ""; + //校验 + Class[] typeObjects = new Class[]{DateAndString.class, Integer.class}; + IgnoreParamFilter.commonFilter("EOMONTH", 1, 2, typeObjects, objects); + + //获取日期和加减参数 + Object dateObj = objects[0]; + Object dateContent = dateObj != null ? DateUtil.getContent(dateObj, formatter) : null; + + Object tempObj = objects.length > 1 ? objects[1] : null; + Object numObj = tempObj != null && ExcelParamUtil.getParamContent(tempObj, "") != null ? ExcelParamUtil.getParamContent(tempObj, "").toString() : null; + + int num = numObj != null ? Integer.parseInt(numObj + "") : 0; + if (ExcelParamUtil.checkIsNull(dateContent, ExcelParamUtil.CHECKLEVEL_STRING)) { + throw new RuntimeException("日期参数不能为空"); + } + + try { + Date date = null; + if (dateContent instanceof String || dateContent instanceof Character) { + format = DateUtil.buildFormat(dateContent.toString()); + if (null == format) { + return null; + } + date = formateDateStr(dateContent.toString(), format); + } else { + date = (Date) dateContent; + } + + //在传入日期上进行月份加减操作,并设置为当月第一天 + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.MONTH, num); + cal.set(Calendar.DAY_OF_MONTH, 1); + + //取该月最后一天 + cal.add(Calendar.MONTH, 1); + cal.add(Calendar.DAY_OF_MONTH, -1); + + Date newDate = cal.getTime(); + result = formateDateStr(newDate, format); + } catch (ParseException e) { + logger.error("eoMonth执行出错:" + e.getMessage(), e); + } + return new DataType(DataType.STRING, result); + } + +// @Override +// public DataType workdayIntl(Object... objects) { +// //校验 +// Object result = null; +// IgnoreParamFilter.commonFilter("NETWORKDAYSPI", 3, 3, null, objects); +// +// //获取开始日期 +// Object startObj = objects[0]; +// Object startDateObj = startObj != null ? DateUtil.getContent(startObj, formatter) : null; +// +// Date startDate = null; +// if (startDateObj != null) { +// +// if (startDateObj instanceof String || startDateObj instanceof Character) { +// format = DateUtil.buildFormat(startDateObj.toString()); +// if (null == format) { +// logger.error("workdayIntl函数执行时,开始时间获取format为空,已返回null"); +// return null; +// } +// startDate = formateDateStr(startDateObj.toString(), format); +// } else { +// startDate = (Date) startDateObj; +// } +// } +// +// //结束日期 +// Object endObj = objects[1]; +// Object endDateObj = endObj != null ? DateUtil.getContent(endObj, formatter) : null; +// +// Date endDate = null; +// if (endDateObj != null) { +// +// if (endDateObj instanceof String || endDateObj instanceof Character) { +// format = DateUtil.buildFormat(endDateObj.toString()); +// if (null == format) { +// logger.error("workdayIntl函数执行时,结束时间获取format为空,已返回null"); +// return null; +// } +// endDate = formateDateStr(endDateObj.toString(), format); +// } else { +// endDate = (Date) endDateObj; +// } +// } +// +// //人员参数 +// Object employeeObj = objects[2]; +// String empIdStr = employeeObj != null ? ((DataType) employeeObj).getContent() + "" : null; +// +// SimpleEmployee currEmp = employeeObj != null ? ((DataType) employeeObj).getEmployee() : null; +// String tenantKey = currEmp != null ? currEmp.getTenantKey() : null; +// +// if (ExcelParamUtil.checkIsNull(startDate, endDate, empIdStr, ExcelParamUtil.CHECKLEVEL_STRING)) { +// throw new RuntimeException("NETWORKDAYSPI函数参数不能为空"); +// } +// +// if (StringUtils.isEmpty(tenantKey)) { +// logger.error("workdayIntl函数执行时,tenantKey,已返回null"); +// return null; +// } +// +// //结果是否取相反数 +// boolean isOpposite = false; +// Date begin = startDate; +// Date end = endDate; +// +// if (startDate.after(end)) { +// isOpposite = true; +// begin = endDate; +// end = startDate; +// } +// +// //结束时间临界值为昨天23:59:59 +// Date yesterdayEnd = new Date(); +// yesterdayEnd = DateUtils.addDays(yesterdayEnd, -1); +// yesterdayEnd = com.weaver.teams.util.DateUtils.setTimeToEndOfDay(yesterdayEnd); +// +// //最小时间大于昨天最后一刻,则计算结果为0 +// if (begin.after(yesterdayEnd)) { +// return new DataType(DataType.NUMBER, 0); +// } +// //最大日期大于昨天最后一刻,另结束时间等于昨天最后一刻 +// if (end.after(yesterdayEnd)) { +// end = yesterdayEnd; +// } +// +// //间隔天数 +// int workDays = 0; +// //是否购买了考勤模块 +// boolean attendPay = tenantHttpInvokerService.isPayModule(tenantKey, TenantModuleType.attend); +// +// if (attendPay) { +// //按考勤规则设置来 +// Long empId = Long.parseLong(empIdStr); +// Map> tempMap = null; +// +// try { +// WeaverSentinelContext.setDowngradeType(false); +// tempMap = remoteAttendService.queryDayType(Lists.newArrayList(empId), begin, end, tenantKey); +// } catch (Exception e) { +// if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { +// //降级逻辑编写 +// logger.info("******workdayIntl的remoteAttendService.queryDayType走了weaver-common-excel-formula中的降级******"); +// return new DataType(DataType.NUMBER, 0); +// } else { +// logger.error("workdayIntl的remoteAttendService.queryDayType查询出错:" + e.getMessage()); +// } +// } +// +// if (MapUtils.isNotEmpty(tempMap)) { +// Map dayTypeMap = tempMap.get(empId); +// if (MapUtils.isEmpty(dayTypeMap)) { +// dayTypeMap = Maps.newHashMap(); +// } +// +// Date attendDate = null; +// AttendDayType dayType = null; +// int days = DateUtil.daysBetween(begin, end); +// +// //计算工作日天数 +// for (int i = 0; i <= days; i++) { +// attendDate = DateUtils.addDays(begin, i); +// String dayStr = DateFormatUtils.format(attendDate, "yyyy-MM-dd"); +// +// dayType = dayTypeMap.get(dayStr); +// if (dayType != null && dayType == AttendDayType.WORK) { +// workDays++; +// } +// } +// } +// } else { +// //按法定节假日算 +// List tempHolidays = Lists.newArrayList(); +// List holidays = null; +// +// try { +// WeaverSentinelContext.setDowngradeType(false); +// holidays = remoteAttend4FormService.queryDefaultHoliday(begin, end); +// } catch (Exception e) { +// if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { +// //降级逻辑编写 +// logger.info("******workdayIntl的remoteAttend4FormService.queryDefaultHoliday走了weaver-common-excel-formula中的降级******"); +// return new DataType(DataType.NUMBER, 0); +// } else { +// logger.error("workdayIntl的remoteAttend4FormService.queryDefaultHoliday查询出错:" + e.getMessage()); +// } +// } +// +// if (CollectionUtils.isNotEmpty(holidays)) { +// for (Attend4FormDay tempDay : holidays) { +// String dayStr = DateFormatUtils.format(tempDay.getDay(), "yyyy-MM-dd"); +// tempHolidays.add(dayStr); +// } +// } +// +// Date attendDate = null; +// Calendar cal = Calendar.getInstance(); +// int days = DateUtil.daysBetween(begin, end); +// +// //计算工作日天数 +// for (int i = 0; i <= days; i++) { +// attendDate = DateUtils.addDays(begin, i); +// String dayStr = DateFormatUtils.format(attendDate, "yyyy-MM-dd"); +// +// //节假日 +// if (tempHolidays.contains(dayStr)) { +// continue; +// } +// +// //周末 +// cal.setTime(attendDate); +// if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) { +// continue; +// } +// +// //工作日 +// workDays++; +// } +// } +// if (isOpposite) { +// workDays = workDays * (-1); +// } +// +// logger.info("workdayIntl计算结果:" + workDays); +// return new DataType(DataType.NUMBER, workDays); +// +// } + + @Override + public DataType maxDate(Object... objects) { + Object dateObj = null; + Date date = null; + Date maxDate = null; + + //取最大日期 + for (int i = 0; i < objects.length; i++) { + dateObj = objects[i]; + if (dateObj == null) continue; + + //如果类型是DataType + if (dateObj instanceof DataType) { + DataType dataType = (DataType) dateObj; + dateObj = dataType.getContent(); + } + if (dateObj == null) continue; + + //字符串或Date强转 + if (dateObj instanceof String || dateObj instanceof Character) { + String format = DateUtil.buildFormat(dateObj.toString()); + if (StringUtils.isNotEmpty(format)) date = formateDateStr(dateObj.toString(), format); + } else { + date = (Date) dateObj; + } + + if (date != null && (maxDate == null || date.after(maxDate))) maxDate = date; + } + + //日期格式化 + String rtnStr = maxDate != null ? DateFormatUtils.format(maxDate, "yyyy-MM-dd") : ""; + return new DataType(DataType.STRING, rtnStr); + } + + @Override + public DataType minDate(Object... objects) { + Object dateObj = null; + Date date = null; + Date minDate = null; + + //取最小日期 + for (int i = 0; i < objects.length; i++) { + dateObj = objects[i]; + if (dateObj == null) continue; + + //如果类型是DataType + if (dateObj instanceof DataType) { + DataType dataType = (DataType) dateObj; + dateObj = dataType.getContent(); + } + if (dateObj == null) continue; + + if (dateObj instanceof String || dateObj instanceof Character) { + String format = DateUtil.buildFormat(dateObj.toString()); + if (StringUtils.isNotEmpty(format)) date = formateDateStr(dateObj.toString(), format); + } else { + date = (Date) dateObj; + } + + if (date != null && (minDate == null || date.before(minDate))) minDate = date; + } + + //日期格式化 + String rtnStr = minDate != null ? DateFormatUtils.format(minDate, "yyyy-MM-dd") : ""; + return new DataType(DataType.STRING, rtnStr); + } + + @Override + public DataType compareDate(Object... objects) { + Date first = null; + Date second = null; + Object paramObj = objects[0]; + Object paramObjSecond = objects[1]; + if (paramObj instanceof DataType) { + DataType dataType = (DataType) paramObj; + if (dataType.getContent() != null && StringUtils.isNotEmpty(dataType.getContent() + "")) { + boolean isDate = DateUtil.isDateComponent(paramObj); + if (isDate) { + first = DateUtil.buildDateByDateChar(dataType.getContent() + ""); + } + } + } else { + first = DateUtil.buildDateByDateChar(paramObj + ""); + } + + if (paramObjSecond instanceof DataType) { + DataType dataType = (DataType) paramObjSecond; + if (dataType.getContent() != null && StringUtils.isNotEmpty(dataType.getContent() + "")) { + boolean isDate = DateUtil.isDateComponent(paramObjSecond); + if (isDate) { + second = DateUtil.buildDateByDateChar(dataType.getContent() + ""); + } + } + } else { + second = DateUtil.buildDateByDateChar(paramObjSecond + ""); + } + + if (first == null || second == null) { + return new DataType(DataType.BOOL, false); + } + + if (first.getTime() - second.getTime() != 0) { + return new DataType(DataType.BOOL, false); + } else { + return new DataType(DataType.BOOL, true); + } + } + + @Override + public DataType currYear(Object... objects) { + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year = cal.get(Calendar.YEAR); + return new DataType(DataType.NUMBER, year); + } + + @Override + public DataType currMonth(Object... objects) { + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year = cal.get(Calendar.MONTH) + 1; + return new DataType(DataType.NUMBER, year); + } + + @Override + public DataType currDay(Object... objects) { + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year = cal.get(Calendar.DAY_OF_MONTH); + return new DataType(DataType.NUMBER, year); + } + + @Override + public DataType currWeek(Object... objects) { + int weekDay = 0; + try { + weekDay = getDateTimeValue(new Date(), "DW", "WEEKDAY"); + } catch (ParseException e) { + logger.error("err", e); + } + return new DataType(DataType.NUMBER, weekDay > 0 ? (weekDay - 1) : weekDay); + } + + @Override + public DataType currHour(Object... objects) { + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year = cal.get(Calendar.HOUR_OF_DAY); + return new DataType(DataType.NUMBER, year); + } + + @Override + public DataType currMinute(Object... objects) { + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year = cal.get(Calendar.MINUTE); + return new DataType(DataType.NUMBER, year); + } + + @Override + public DataType currSecond(Object... objects) { + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year = cal.get(Calendar.SECOND); + return new DataType(DataType.NUMBER, year); + } + /*******以下为日期函数的一些公共逻辑********/ + + + /** + * 获取日期时间的单位值,指定类型为Type,默认为 'D' 天数 + * + * @param date + * @param type + * @return + * @throws ParseException + */ + public Integer getDateTimeValue(Object date, String type, String func) throws ParseException { + int result = 0; + try { + boolean isTime = false; + Date fDate = null; + if (date instanceof String) { + boolean isDate = checkDateString(date != null ? date.toString() : ""); + if (!isDate) { + return 0; + } + format = DateUtil.buildFormat(date.toString(), type); + if (format == null) { + format = DateUtil.buildFormat(date.toString()); + } + fDate = formateDateStr(date.toString(), format); + if (date.toString().indexOf(":") > 0 && date.toString().indexOf("-") < 0) { + isTime = true; + if (!type.equals("H") && !type.equals("I") && !type.equals("S")) { + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func, number, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } else { + fDate = (Date) date; + } + + int calendarType = 0; + switch (type) { + case "Y": + calendarType = Calendar.YEAR; + break; + case "M": + calendarType = Calendar.MONTH; + break; + case "D": + calendarType = Calendar.DAY_OF_MONTH; + break; + case "H": + if (isTime) { + return Integer.parseInt(date.toString().split(":")[0]); + } + calendarType = Calendar.HOUR_OF_DAY; + break; + case "I": + if (isTime) { + return Integer.parseInt(date.toString().split(":")[1]); + } + calendarType = Calendar.MINUTE; + break; + case "S": + if (isTime) { + return Integer.parseInt(date.toString().split(":")[2]); + } + calendarType = Calendar.SECOND; + break; + case "WM": + calendarType = Calendar.WEEK_OF_YEAR; + long startTime1 = fDate.getTime(); + Calendar calendar = Calendar.getInstance(); + calendar.setFirstDayOfWeek(Calendar.SUNDAY);//设置星期一为一周开始的第一天 + calendar.setMinimalDaysInFirstWeek(4);//可以不用设置 + calendar.setTimeInMillis(startTime1);//获得当前的时间戳 + int weekOfYear = calendar.get(calendarType);//获得当前日期属于今年的第几周 + result = weekOfYear; + logger.info("当前是第" + result + "周"); + return result; + case "DW": + calendarType = Calendar.DAY_OF_WEEK; + break; + default: + calendarType = Calendar.HOUR_OF_DAY; + break; + } + calendar.setTime(fDate); + result = calendar.get(calendarType); + } catch (RuntimeException e) { + logger.error("err", e); + result = 0; + } + return result; + } + + /** + * 格式化日期时间 + * + * @param dateStr 日期时间原字符串 + * @param format 格式 + * @return + * @throws ParseException + */ + private Date formateDateStr(String dateStr, String format) { + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date ndate = null; + try { + ndate = sdf.parse(dateStr); + } catch (ParseException e) { + logger.error("err", e); + } + return ndate; + } + + /** + * 格式日期时间为字符串 + * + * @param date + * @param format + * @return + * @throws ParseException + */ + private String formateDateStr(Date date, String format) throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat(format); + String ndate = sdf.format(date); + return ndate; + } + + + /** + * 判断时间间距的单位类型 + * + * @param type + * @return + */ + private Long buildSecondsFmt(String type) { + Long secondsL = null; + switch (type) { + case "Y": + secondsL = (long) (365 * 24 * 60 * 60 * 1000); + break; + case "M": + secondsL = (long) (30 * 24 * 60 * 60 * 1000); + break; + case "D": + secondsL = (long) (24 * 60 * 60 * 1000); + break; + case "H": + secondsL = (long) (60 * 60 * 1000); + break; + case "I": + secondsL = (long) (60 * 1000); + break; + case "S": + secondsL = 1000L; + break; + default: + secondsL = (long) (60 * 60 * 1000); + break; + } + return secondsL; + } + + static Calendar calendar2 = Calendar.getInstance(); + public static SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + static String format2 = "yyyy-MM-dd HH:mm:ss"; + + + public static Integer getDateTimeValue2(Object date, String type, String func) throws ParseException { + int result = 0; + boolean isTime = false; + Date fDate = null; + if (date instanceof String) { + format2 = DateUtil.buildFormat(date.toString()); + fDate = formateDateStr2(date.toString(), format2); + if (date.toString().indexOf(":") > 0 && !date.toString().contains("-")) { + isTime = true; + if (!type.equals("H") && !type.equals("I") && !type.equals("S")) { + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func, number, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } else { + fDate = (Date) date; + } + + int calendarType = 0; + switch (type) { + case "Y": + calendarType = Calendar.YEAR; + break; + case "M": + calendarType = Calendar.MONTH; + break; + case "D": + calendarType = Calendar.DAY_OF_MONTH; + break; + case "H": + if (isTime) { + return Integer.parseInt(date.toString().split(":")[0]); + } + calendarType = Calendar.HOUR_OF_DAY; + break; + case "I": + if (isTime) { + return Integer.parseInt(date.toString().split(":")[1]); + } + calendarType = Calendar.MINUTE; + break; + case "S": + if (isTime) { + return Integer.parseInt(date.toString().split(":")[2]); + } + calendarType = Calendar.SECOND; + break; + case "WM": + calendarType = Calendar.WEEK_OF_MONTH; + break; + case "DW": + calendarType = Calendar.DAY_OF_WEEK; + break; + default: + calendarType = Calendar.HOUR_OF_DAY; + break; + } + calendar2.setTime(fDate); + result = calendar2.get(calendarType); + return result; + } + + private static Date formateDateStr2(String dateStr, String format) throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date ndate = null; + ndate = sdf.parse(dateStr); + return ndate; + } + + private boolean checkDateString(String dateString) { + List datafList = new ArrayList(); + datafList.add("yyyyMMddHHmmss"); + datafList.add("yyyyMMdd"); + datafList.add("yyyyMMddHHmm"); + datafList.add("HH:mm"); + datafList.add("HH:mm:ss"); + if (RegularUtil.isNumber(dateString)) { + return false; + } + boolean r = false; + for (String s : datafList) { + SimpleDateFormat sdf = new SimpleDateFormat(s); + + Date ndate = null; + try { + ndate = sdf.parse(dateString); + r = true; + break; + } catch (ParseException e) { + logger.info(e.getMessage()); + r = false; + } + } + if (r) { + if (RegularUtil.isNumber(dateString)) { + r = false; + } + } + return r; + } + + + public static double getBetween(String beginTime, String endTime, String returnPattern) throws ParseException { + + String format = DateUtil.buildFormat(beginTime); + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date beginDate = sdf.parse(beginTime); + + format = DateUtil.buildFormat(endTime); + sdf = new SimpleDateFormat(format); + Date endDate = sdf.parse(endTime); + + Calendar beginCalendar = Calendar.getInstance(); + Calendar endCalendar = Calendar.getInstance(); + beginCalendar.setTime(beginDate); + endCalendar.setTime(endDate); + + double resutl; + switch (returnPattern) { + case "Y": + resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (24 * 60 * 60 * 1000) / 365.0; + break; + case "M": + resutl = DateTimeServiceImpl.getByField(beginCalendar, endCalendar, Calendar.YEAR) * 12 + DateTimeServiceImpl.getByField(beginCalendar, endCalendar, Calendar.MONTH); + break; + case "D": + resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (24 * 60 * 60 * 1000); + break; + case "H": + Long nd = new Long(60 * 60 * 1000); + resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (nd.doubleValue()); + break; + case "I": + resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / (60 * 1000); + break; + case "S": + resutl = DateTimeServiceImpl.getTime(beginDate, endDate) / 1000; + break; + default: + resutl = 0L; + break; + } + return resutl; + } + + + private static Long getByField(Calendar beginCalendar, Calendar endCalendar, int calendarField) { + int r = endCalendar.get(calendarField) - beginCalendar.get(calendarField); + return (long) r; + } + + private static long getTime(Date beginDate, Date endDate) { + return endDate.getTime() - beginDate.getTime(); + } + +// public static void main(String[] args) { +// try { +// logger.info(DateTimeServiceImpl.getBetween("2017-05-02 22:00:00", "2016-10-02 23:15:00", "Y")); +// } catch (ParseException e) { +// logger.error("err",e); +// } +// +// } +} diff --git a/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java b/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java new file mode 100644 index 000000000..18031fbb7 --- /dev/null +++ b/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java @@ -0,0 +1,1208 @@ +package com.engine.salary.formlua.func.date; + +import com.alibaba.fastjson.JSONObject; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.DateAndString; +import com.weaver.excel.formula.entity.parameter.FuncNames; +import com.weaver.excel.formula.util.*; +import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +@Service("dateTimeTestService") +public class DateTimeTestServiceImpl implements DateTimeService { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private String format="yyyy-MM-dd HH:mm:ss"; + private Calendar calendar=Calendar.getInstance(); + + /** + * 返回当前日期时间 + * @return + */ + @Override + public DataType now(Object... objects) { + int number= IgnoreParamFilter.getSetFuncNumber(FuncNames.NOW.toString()); + if(objects.length>0){ + throw new RuntimeException("NOW函数不能有参数"); + } + formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String nowStr=formatter.format(new Date()); + return new DataType(DataType.STRING,nowStr); + } + + /** + * 返回当前日期 + * @return + */ + @Override + public DataType today(Object... objects) { + int number=IgnoreParamFilter.getSetFuncNumber(FuncNames.TODAY.toString()); + if(objects.length>0){ + throw new RuntimeException("TODAY函数不能有参数"); + } + formatter=new SimpleDateFormat("yyyy-MM-dd"); + String dateStr=formatter.format(new Date()); + return new DataType(DataType.STRING,dateStr); + } + + /** + * 格式化时间日期 + * @param objects + * @return + */ + @Override + public DataType dateFormat(Object... objects) { + Class[] typeObjects=new Class[]{DateAndString.class,String.class}; + String func="DATEFORMAT"; + IgnoreParamFilter.commonFilter(func,2,2,typeObjects,objects); + Object result=objects[0]; + String dateStr=""; + Object p1=objects[0]; + Object p2=objects[1]; + if(ExcelParamUtil.checkIsNull(p1,p2)){ + throw new RuntimeException("日期格式化函数参数不能为空"); + } + if(p1 instanceof DataType){ + DataType dataType=(DataType) p1; + if(dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE)){ + dateStr="2020-09-08 12:00"; + }else{ + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + number-=1; + throw new RuntimeException(func+"函数格式错误"); + } + + }else { + if(p1 instanceof Date){ + dateStr=formatter.format(p1); + }else { + dateStr=p1.toString(); + } + } + String formatStr=(ExcelParamUtil.getParamContent(p2,"string")!=null?ExcelParamUtil.getParamContent(p2,"string"):"").toString().replaceAll("D","d"); + try { + String formatterStr= DateUtil.buildFormat(dateStr); + formatter=new SimpleDateFormat(formatterStr); + Date sourceDate=formatter.parse(dateStr); + formatter= new SimpleDateFormat(formatStr); + dateStr=formatter.format(sourceDate); + result=dateStr; + } catch (ParseException e) { + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + number-=1; + JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数格式错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + return new DataType(DataType.STRING,result); + } + + /** + * 两个日期加减 + * @param + * @param + * @return + */ + @Override + public DataType dateDiff(Object... objects){ + Class[] typeObjects=new Class[]{DateAndString.class,DateAndString.class,String.class}; + IgnoreParamFilter.commonFilter("DATEDIFF",2,3,typeObjects,objects); + Long secondsL=new Long(60*60*1000);//计算日期时间间距的单位,默认为小时 + + Long nd = buildSecondsFmt("D"); + Long nh = buildSecondsFmt("H"); + Long nm = buildSecondsFmt("I"); + Long ns = buildSecondsFmt("S"); + + + Double result=new Double(0); + String type="D"; + String sContent=DateUtil.getContent(objects[0],formatter); + String eContent=DateUtil.getContent(objects[1],formatter); + if(ExcelParamUtil.checkIsNull(sContent,eContent,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + Date startDate=null; + Date endDate=null; + + format= DateUtil.buildFormat(sContent); + startDate=formateDateStr(sContent,format); + format=DateUtil.buildFormat(eContent); + endDate=formateDateStr(eContent,format); + if(startDate==null||endDate==null){ + return new DataType(DataType.NUMBER,0); + } + Calendar cal1 = Calendar.getInstance(); + cal1.setTime(startDate); + //当前时间 + Calendar cal2 = Calendar.getInstance(); + cal2.setTime(endDate); + + + long diff = cal2.getTime().getTime() - cal1.getTime().getTime(); + + if(objects.length==3){ + type=ExcelParamUtil.getParamContent(objects[2],"string")!=null?ExcelParamUtil.getParamContent(objects[2],"string").toString():""; + secondsL=buildSecondsFmt(type); + } + Double time=new Double(0); + boolean checkType=true; + switch (type){ + case "Y": + time= getTime(startDate, endDate)/(nd.doubleValue())/365.0; + break; + case "M": + Long monthR=getByField(cal1, cal2, Calendar.YEAR)*12 + getByField(cal1, cal2, Calendar.MONTH); + time= monthR.doubleValue(); + break; + case "D": + double dayR=getTime(startDate, endDate)/(nd.doubleValue()); + time= dayR; + break; + case "H": + double hourH=getTime(startDate, endDate)/(nh.doubleValue()); + time= hourH; + break; + case "I": + double minuR= getTime(startDate, endDate)/(nm.doubleValue()); + time=minuR; + break; + case "S": + double seconR=getTime(startDate, endDate)/ns.doubleValue(); + time= seconR; + break; + default: + checkType=false; + break; + } + if(!checkType){ + String func="DATEDIFF"; + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson= ErrorUtil.buildError(func,number-1,number-1,func+"函数第3个参数不正确"); + throw new RuntimeException(errorJson.getString("msg")); + } + BigDecimal b = new BigDecimal(time); + double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); + result=f1; + return new DataType(DataType.NUMBER,result); + } + + /** + * 日期加减天数 + * @param objects + * @return + */ + @Override + public DataType dateAdd(Object... objects) { + Class[] typeObjects=new Class[]{DateAndString.class,Integer.class,String.class}; + IgnoreParamFilter.commonFilter("DATEADD",2,3,typeObjects,objects); + + String type="D"; + if(objects.length==3){ + type=objects[2].toString(); + } + + Object tcontent=DateUtil.getContent(objects[0],formatter); + Double numD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"")!=null?ExcelParamUtil.getParamContent(objects[1],"").toString():""); + + int num=numD.intValue(); + if(ExcelParamUtil.checkIsNull(tcontent,numD,type,ExcelParamUtil.CHECKLEVEL_STRING)){ + throw new RuntimeException("日期加减函数的参数不能为空"); + } + Object result=""; + + try { + Date date=null; + if(tcontent instanceof String || tcontent instanceof Character){ + format=DateUtil.buildFormat(tcontent.toString()); + if(null==format){ + throw new RuntimeException("日期加减函数的格式化参数不能为空"); + } + date=formateDateStr(tcontent.toString(),format); + }else { + date=(Date)tcontent; + } + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + boolean checkType=true; + switch (type){ + case "Y": + cal.add(Calendar.YEAR,num); + break; + case "M": + cal.add(Calendar.MONTH,num); + break; + case "D": + cal.add(Calendar.DAY_OF_MONTH,num); + break; + case "H": + cal.add(Calendar.HOUR_OF_DAY,num); + break; + case "I": + cal.add(Calendar.MINUTE,num); + break; + case "S": + cal.add(Calendar.SECOND,num); + break; + default: + checkType=false; + break; + } + if(!checkType){ + String func="DATEADD"; + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson= ErrorUtil.buildError(func,number-1,number-1,func+"函数第3个参数不正确"); + throw new RuntimeException(errorJson.getString("msg")); + } + Date newDate=cal.getTime(); + String nDate=formateDateStr(newDate,format); + result=nDate; + + } catch (ParseException e) { + logger.error("err",e); + } + return new DataType(DataType.STRING,result); + } + + /** + * 返回年份 + * @param objects + * @return + */ + @Override + public DataType year(Object... objects) { + Object reuslt=new Object(); + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("YEAR",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + int year=0; + try { + year=getDateTimeValue(date,"Y","YEAR"); + reuslt=year; + } catch (ParseException e) { + logger.error("err",e); + } + + return new DataType(DataType.NUMBER,reuslt); + } + + /** + * 返回是今年第几月 + * @param objects + * @return + */ + @Override + public DataType month(Object... objects) { + + Object reuslt=new Object(); + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("MONTH",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + boolean isDate=checkDateString(date!=null?date.toString():""); + if(!isDate){ + return new DataType(DataType.NUMBER,0); + } + int month=0; + try { + month=getDateTimeValue(date,"M","MONTH"); + reuslt=month+1; + } catch (ParseException e) { + logger.error("err",e); + } + + return new DataType(DataType.NUMBER,reuslt); + } + + /** + * 返回日期是本月几号 + * @param objects + * @return + */ + @Override + public DataType day(Object... objects) { + Object reuslt=new Object(); + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("DAY",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + int day=0; + try { + day=getDateTimeValue(date,"D","DAY"); + reuslt=day; + } catch (ParseException e) { + logger.error("err",e); + } + + return new DataType(DataType.NUMBER,reuslt); + + } + + /** + * 返回时钟位置 + * @param objects + * @return + */ + @Override + public DataType hour(Object... objects) { + + Object reuslt=new Object(); + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("HOUR",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + Integer hour=0; + try { + hour=getDateTimeValue(date,"H","HOUR"); + reuslt=hour; + } catch (ParseException e) { + logger.error("err",e); + } + + return new DataType(DataType.NUMBER,reuslt); + + } + + /** + * 返回分钟位置 + * @param objects + * @return + */ + @Override + public DataType minute(Object... objects) { + Object reuslt=new Object(); + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("MINUTE",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + int minute=0; + try { + minute=getDateTimeValue(date,"I","MINUTE"); + + reuslt=minute; + } catch (ParseException e) { + logger.error("err",e); + } + + return new DataType(DataType.NUMBER,reuslt); + } + + /*** + * 返回秒钟位置 + * @param objects + * @return + */ + @Override + public DataType seconds(Object... objects) { + Object reuslt=new Object(); + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("SECOND",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + int seconds=0; + try { + seconds=getDateTimeValue(date,"S","SECOND"); + reuslt=seconds; + } catch (ParseException e) { + logger.error("err",e); + } + + return new DataType(DataType.NUMBER,reuslt); + + } + + /** + * 计算是本月的第几周 + * @param objects + * @return + */ + @Override + public DataType weekNum(Object... objects) { + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("WEEKNUM",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + int weekNum=0; + try { + //在JDK中可能会把前一年末尾的几天判定为下一年的第一周 + weekNum=getDateTimeValue(date,"WM","WEEKNUM"); + + } catch (ParseException e) { + logger.error("err",e); + } + return new DataType(DataType.NUMBER,weekNum); + } + + /** + * 判断是周几,因为周几是从周天的0开始算,所以返回数据需要减1 + * @param objects + * @return + */ + @Override + public DataType weekDay(Object... objects) { + Class[] typeObjects=new Class[]{DateAndString.class}; + IgnoreParamFilter.commonFilter("WEEKDAY",1,1,typeObjects,objects); + Object obj=objects[0]; + Object date=DateUtil.getContent(obj,formatter); + if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ + return new DataType(DataType.NUMBER,0); + } + int weekDay=0; + try { + weekDay=getDateTimeValue(date,"DW","WEEKDAY"); + } catch (ParseException e) { + logger.error("err",e); + } + + return new DataType(DataType.NUMBER,weekDay>0?(weekDay-1):weekDay); + } + + @Override + public DataType dayOfMonth(Object... objects) { + String dayType=""; + if(objects!=null && objects.length>0 && objects[0]!=null){ + dayType=objects[0].toString(); + } + + // 获取当前年份、月份、日期 + Calendar cale = Calendar.getInstance(); + // 获取当月第一天和最后一天 + SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + String firstday="", lastday=""; + String date=""; + switch (dayType.toLowerCase()){ + case "first": + // 获取当前月的第一天 + cale = Calendar.getInstance(); + cale.add(Calendar.MONTH, 0); + cale.set(Calendar.DAY_OF_MONTH, 1); + cale.set(Calendar.HOUR_OF_DAY,0); + cale.set(Calendar.MINUTE,0); + firstday = formatTemp.format(cale.getTime()); + date=firstday; + break; + case "last": + // 获取当前月的最后一天 + cale = Calendar.getInstance(); + cale.add(Calendar.MONTH, 1); + cale.set(Calendar.DAY_OF_MONTH, 0); + cale.set(Calendar.HOUR_OF_DAY,0); + cale.set(Calendar.MINUTE,0); + lastday = formatTemp.format(cale.getTime()); + date=lastday; + break; + default: + // 获取指定的某一天 + if(dayType==null || dayType.trim().equalsIgnoreCase("")){ + dayType="0"; + } + cale = Calendar.getInstance(); + cale.add(Calendar.MONTH, 1); + cale.set(Calendar.HOUR_OF_DAY,0); + cale.set(Calendar.MINUTE,0); + cale.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dayType)); + lastday = formatTemp.format(cale.getTime()); + date=lastday; + break; + } + logger.info("firstday:"+firstday+" lastday:"+lastday); + return new DataType(DataType.STRING,date); + } + + @Override + public DataType monthOfYear(Object... objects) { + String dayType=""; + if(objects!=null && objects.length>0 && objects[0]!=null){ + dayType=objects[0].toString(); + } + if(dayType==null || dayType.equalsIgnoreCase("")){ + dayType="0"; + } + int month=Integer.parseInt(dayType); + if(month>0){ + month-=1; + } + SimpleDateFormat dayFormatTemp = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + Calendar cale = Calendar.getInstance(); + cale.set(cale.get(Calendar.YEAR),month,1); + + String lastday = formatTemp.format(cale.getTime()); + System.out.println(lastday); + return new DataType(DataType.STRING,lastday); + } + + @Override + public DataType timeOfDay(Object... objects) { + String dayType=""; + if(objects!=null && objects.length>0 && objects[0]!=null){ + dayType=objects[0].toString(); + } + + SimpleDateFormat dayFormatTemp = new SimpleDateFormat("yyyy-MM-dd"); + SimpleDateFormat formatTemp = new SimpleDateFormat("HH:mm"); + Calendar cale = Calendar.getInstance(); + try { + cale.setTime(dayFormatTemp.parse("2021-01-17 13:22")); + } catch (ParseException e) { + logger.error("err",e); + } + cale.set(Calendar.HOUR_OF_DAY,Integer.parseInt(dayType)); + cale.set(Calendar.MINUTE,0); + String lastday = formatTemp.format(cale.getTime()); + return new DataType(DataType.STRING,lastday); + } + + @Override + public DataType eoMonth(Object... objects) { + //校验 + Class[] typeObjects = new Class[]{DateAndString.class, Integer.class}; + IgnoreParamFilter.commonFilter("EOMONTH",1,2, typeObjects, objects); + + //获取日期和加减参数 + Object dateObj = objects[0]; + Object dateContent = dateObj != null ? DateUtil.getContent(dateObj, formatter):null; + + //不支持变量 + if(objects.length > 1 && objects[1] instanceof DataType){ + throw new RuntimeException("EOMONTH函数第二个参数只能是常量"); + } + + Object tempObj = objects.length > 1 ? objects[1]:null; + Object numObj = tempObj != null && ExcelParamUtil.getParamContent(tempObj,"") != null ? ExcelParamUtil.getParamContent(tempObj,"").toString():null; + + int num = 0; + if(numObj != null){ + try{ + num = Integer.parseInt(numObj+""); + }catch (Exception e){ + throw new RuntimeException("EOMONTH函数第二个参数只能是整数"); + } + } + if(ExcelParamUtil.checkIsNull(dateContent, ExcelParamUtil.CHECKLEVEL_STRING)) throw new RuntimeException("日期参数不能为空"); + + Date date=null; + try { + if(dateContent instanceof String || dateContent instanceof Character){ + format = DateUtil.buildFormat(dateContent.toString()); + SimpleDateFormat sdf = new SimpleDateFormat(format); + date = sdf.parse(dateContent.toString()); + }else { + date = (Date)dateContent; + } + } catch (Exception e) { + throw new RuntimeException("EOMONTH函数参数类型错误"); + } + + //在传入日期上进行月份加减操作,并设置为当月第一天 + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.add(Calendar.MONTH, num); + cal.set(Calendar.DAY_OF_MONTH, 1); + + //取该月最后一天 + cal.add(Calendar.MONTH,1); + cal.add(Calendar.DAY_OF_MONTH,-1); + + Date newDate = cal.getTime(); + Object rtnStr = null; + try { + rtnStr = formateDateStr(newDate,format); + } catch (ParseException e) { + logger.error("err",e); + } + return new DataType(DataType.STRING,rtnStr); + } + + @Override + public DataType workdayIntl(Object... objects) { + //校验 + String func = "NETWORKDAYSPI"; + IgnoreParamFilter.commonFilter(func,3,3, null, objects); + + //获取开始日期 + Object startObj = objects[0]; + Object startDateObj = startObj != null ? DateUtil.getContent(startObj, formatter):null; + + Date startDate = null; + if(startDateObj != null){ + if(startDateObj instanceof String || startDateObj instanceof Character){ + format = DateUtil.buildFormat(startDateObj.toString()); + + if(StringUtils.isEmpty(format)) { + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数开始时间格式错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + startDate = formateDateStr(startDateObj.toString(), format); + }else { + startDate = (Date)startDateObj; + } + } + + //结束日期 + Object endObj = objects[1]; + Object endDateObj = endObj != null ? DateUtil.getContent(endObj, formatter):null; + + Date endDate = null; + if(endDateObj != null){ + + if(endDateObj instanceof String || endDateObj instanceof Character){ + format = DateUtil.buildFormat(endDateObj.toString()); + if(StringUtils.isEmpty(format)) { + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数结束时间格式错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + endDate = formateDateStr(endDateObj.toString(), format); + }else { + endDate = (Date)startDateObj; + } + } + + //人员参数 + Object employeeObj = objects[2]; + if(!IgnoreParamFilter.isEmployee(employeeObj)) throw new RuntimeException(func+"函数第三个参数必须是人员参数"); + + String empIdStr = employeeObj != null ? ((DataType)employeeObj).getContent()+"" : null; + SimpleEmployee currEmp = employeeObj != null ? ((DataType)employeeObj).getEmployee() : null; + String tenantKey = currEmp != null ? currEmp.getTenantKey() : null; + + if(ExcelParamUtil.checkIsNull(startDate, endDate, empIdStr, ExcelParamUtil.CHECKLEVEL_STRING)){ + throw new RuntimeException(func+"函数参数不能为空"); + } + + if(StringUtils.isEmpty(tenantKey)){ + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数未能获取到租户"); + throw new RuntimeException(errorJson.getString("msg")); + } + return new DataType(DataType.NUMBER, 1); + } + + @Override + public DataType maxDate(Object... objects) { + if(objects == null || objects.length == 0){ + throw new RuntimeException("MAXDATE函数的参数不能为空"); + } + Object dateObj = null; + Date date = null; + + for(int i=0; i0){ + throw new RuntimeException("CURRYEAR函数不允许有参数"); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year=cal.get(Calendar.YEAR); + return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); + } + + @Override + public DataType currMonth(Object... objects) { + if(objects.length>0){ + throw new RuntimeException("CURRMONTH函数不允许有参数"); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year=cal.get(Calendar.MONTH)+1; + return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); + } + + @Override + public DataType currDay(Object... objects) { + if(objects.length>0){ + throw new RuntimeException("CURRDAY函数不允许有参数"); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year=cal.get(Calendar.DAY_OF_MONTH); + return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); + } + + @Override + public DataType currWeek(Object... objects) { + if(objects.length>0){ + throw new RuntimeException("CURRWEEK函数不允许有参数"); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year=cal.get(Calendar.WEEK_OF_MONTH); + return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); + } + + @Override + public DataType currHour(Object... objects) { + if(objects.length>0){ + throw new RuntimeException("CURRHOUR函数不允许有参数"); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year=cal.get(Calendar.HOUR_OF_DAY); + return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); + } + + @Override + public DataType currMinute(Object... objects) { + if(objects.length>0){ + throw new RuntimeException("CURRMINUTE函数不允许有参数"); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year=cal.get(Calendar.MINUTE); + return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); + } + + @Override + public DataType currSecond(Object... objects) { + if(objects.length>0){ + throw new RuntimeException("CURRSECOND函数不允许有参数"); + } + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + int year=cal.get(Calendar.SECOND); + return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); + } + + /*******以下为日期函数的一些公共逻辑********/ + + + + + /** + * 获取日期时间的单位值,指定类型为Type,默认为 'D' 天数 + * @param date + * @param type + * @return + * @throws ParseException + */ + public Integer getDateTimeValue(Object date,String type,String func) throws ParseException { + int result=0; + try { + boolean isTime=false; + Date fDate=null; + if(date instanceof String){ + boolean isDate=checkDateString(date!=null?date.toString():""); + if(!isDate){ + return 0; + } + format=DateUtil.buildFormat(date.toString(),type); + if(format==null){ + format=DateUtil.buildFormat(date.toString()); + } + fDate=formateDateStr(date.toString(),format); + if(date.toString().indexOf(":")>0&&date.toString().indexOf("-")<0){ + isTime=true; + if(!type.equals("H")&&!type.equals("I")&&!type.equals("S")){ + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + }else { + fDate=(Date)date; + } + + int calendarType=0; + switch (type){ + case "Y": + calendarType=Calendar.YEAR; + break; + case "M": + calendarType=Calendar.MONTH; + break; + case "D": + calendarType=Calendar.DAY_OF_MONTH; + break; + case "H": + if(isTime){ + return Integer.parseInt(date.toString().split(":")[0]); + } + calendarType=Calendar.HOUR_OF_DAY; + break; + case "I": + if(isTime){ + return Integer.parseInt(date.toString().split(":")[1]); + } + calendarType=Calendar.MINUTE; + break; + case "S": + if(isTime){ + return Integer.parseInt(date.toString().split(":")[2]); + } + calendarType=Calendar.SECOND; + break; + case "WM": + calendarType=Calendar.WEEK_OF_YEAR; + long startTime1 = fDate.getTime(); + Calendar calendar = Calendar.getInstance(); + calendar.setFirstDayOfWeek(Calendar.SUNDAY);//设置星期一为一周开始的第一天 + calendar.setMinimalDaysInFirstWeek(4);//可以不用设置 + calendar.setTimeInMillis(startTime1);//获得当前的时间戳 + int weekOfYear = calendar.get(calendarType);//获得当前日期属于今年的第几周 + result=weekOfYear; + logger.info("当前是第"+result+"周"); + return result; + case "DW": + calendarType=Calendar.DAY_OF_WEEK; + break; + default: + calendarType=Calendar.HOUR_OF_DAY; + break; + } + calendar.setTime(fDate); + result=calendar.get(calendarType); + } catch (RuntimeException e) { + logger.error("err",e); + result=0; + } + return result; + } + /** + * 格式化日期时间 + * @param dateStr 日期时间原字符串 + * @param format 格式 + * @return + * @throws ParseException + */ + private Date formateDateStr(String dateStr,String format){ + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date ndate= null; + try { + ndate = sdf.parse(dateStr); + } catch (ParseException e) { + logger.error("err",e); + } + return ndate; + } + + /** + * 格式日期时间为字符串 + * @param date + * @param format + * @return + * @throws ParseException + */ + private String formateDateStr(Date date,String format) throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat(format); + String ndate=sdf.format(date); + return ndate; + } + + + + + /** + * 判断时间间距的单位类型 + * @param type + * @return + */ + private Long buildSecondsFmt(String type){ + Long secondsL=null; + switch (type){ + case "Y": + secondsL=new Long(365*24*60*60*1000); + break; + case "M": + secondsL=new Long(30*24*60*60*1000); + break; + case "D": + secondsL=new Long(24*60*60*1000); + break; + case "H": + secondsL=new Long(60*60*1000); + break; + case "I": + secondsL=new Long(60*1000); + break; + case "S": + secondsL=new Long(1000); + break; + default: + secondsL=new Long(60*60*1000); + break; + } + return secondsL; + } + + static Calendar calendar2=Calendar.getInstance(); + public static SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + static String format2="yyyy-MM-dd HH:mm:ss"; + + + + public static Integer getDateTimeValue2(Object date,String type,String func) throws ParseException { + int result=0; + boolean isTime=false; + Date fDate=null; + if(date instanceof String){ + format2=DateUtil.buildFormat(date.toString()); + fDate=formateDateStr2(date.toString(),format2); + if(date.toString().indexOf(":")>0&&date.toString().indexOf("-")<0){ + isTime=true; + if(!type.equals("H")&&!type.equals("I")&&!type.equals("S")){ + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + }else { + fDate=(Date)date; + } + + int calendarType=0; + switch (type){ + case "Y": + calendarType=Calendar.YEAR; + break; + case "M": + calendarType=Calendar.MONTH; + break; + case "D": + calendarType=Calendar.DAY_OF_MONTH; + break; + case "H": + if(isTime){ + return Integer.parseInt(date.toString().split(":")[0]); + } + calendarType=Calendar.HOUR_OF_DAY; + break; + case "I": + if(isTime){ + return Integer.parseInt(date.toString().split(":")[1]); + } + calendarType=Calendar.MINUTE; + break; + case "S": + if(isTime){ + return Integer.parseInt(date.toString().split(":")[2]); + } + calendarType=Calendar.SECOND; + break; + case "WM": + calendarType=Calendar.WEEK_OF_MONTH; + break; + case "DW": + calendarType=Calendar.DAY_OF_WEEK; + break; + default: + calendarType=Calendar.HOUR_OF_DAY; + break; + } + calendar2.setTime(fDate); + result=calendar2.get(calendarType); + return result; + } + + private static Date formateDateStr2(String dateStr,String format) throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date ndate= null; + ndate = sdf.parse(dateStr); + return ndate; + } + private boolean checkDateString(String dateString){ + List datafList=new ArrayList(); + datafList.add("yyyyMMddHHmmss"); + datafList.add("yyyyMMdd"); + datafList.add("yyyyMMddHHmm"); + datafList.add("HH:mm"); + datafList.add("HH:mm:ss"); + if(RegularUtil.isNumber(dateString)){ + return false; + } + boolean r=false; + for(String s:datafList){ + SimpleDateFormat sdf = new SimpleDateFormat(s); + + Date ndate= null; + try { + ndate = sdf.parse(dateString); + r=true; + break; + } catch (ParseException e) { + logger.info(e.getMessage()); + r=false; + } + } + if(r){ + if(RegularUtil.isNumber(dateString)){ + r=false; + } + } + return r; + } + + + public static double getBetween(String beginTime, String endTime, String returnPattern) throws ParseException{ + + String format= DateUtil.buildFormat(beginTime); + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date beginDate =sdf.parse(beginTime); + + format=DateUtil.buildFormat(endTime); + sdf = new SimpleDateFormat(format); + Date endDate =sdf.parse(endTime); + + Calendar beginCalendar = Calendar.getInstance(); + Calendar endCalendar = Calendar.getInstance(); + beginCalendar.setTime(beginDate); + endCalendar.setTime(endDate); + + double resutl; + switch (returnPattern) { + case "Y": + resutl= getTime(beginDate, endDate)/(24*60*60*1000)/365.0; + break; + case "M": + resutl= getByField(beginCalendar, endCalendar, Calendar.YEAR)*12 + getByField(beginCalendar, endCalendar, Calendar.MONTH); + break; + case "D": + resutl= getTime(beginDate, endDate)/(24*60*60*1000); + break; + case "H": + Long nd=new Long(60*60*1000); + resutl= getTime(beginDate, endDate)/(nd.doubleValue()); + break; + case "I": + resutl= getTime(beginDate, endDate)/(60*1000); + break; + case "S": + resutl= getTime(beginDate, endDate)/1000; + break; + default: + resutl= new Long(0); + break; + } + return resutl; + } + + + + private static Long getByField(Calendar beginCalendar, Calendar endCalendar, int calendarField){ + int r=endCalendar.get(calendarField) - beginCalendar.get(calendarField); + return new Long(r); + } + + private static long getTime(Date beginDate, Date endDate){ + return endDate.getTime() - beginDate.getTime(); + } + + +} diff --git a/src/com/engine/salary/formlua/func/finance/FinanceService.java b/src/com/engine/salary/formlua/func/finance/FinanceService.java new file mode 100644 index 000000000..29861d790 --- /dev/null +++ b/src/com/engine/salary/formlua/func/finance/FinanceService.java @@ -0,0 +1,15 @@ +package com.engine.salary.formlua.func.finance; + +import com.engine.salary.formlua.entity.parameter.DataType; + +/** + * 财务函数分类 + */ +public interface FinanceService { + /** + * 金额转换 + * @param objects + * @return + */ + public DataType getMoney(Object... objects); +} diff --git a/src/com/engine/salary/formlua/func/finance/FinanceServiceImpl.java b/src/com/engine/salary/formlua/func/finance/FinanceServiceImpl.java new file mode 100644 index 000000000..acda12221 --- /dev/null +++ b/src/com/engine/salary/formlua/func/finance/FinanceServiceImpl.java @@ -0,0 +1,119 @@ +package com.engine.salary.formlua.func.finance; + +import com.engine.salary.formlua.entity.parameter.DataType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigDecimal; +public class FinanceServiceImpl implements FinanceService{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Override + public DataType getMoney(Object... objects) { + DataType moneyDataType=new DataType(); + moneyDataType.setDataType(DataType.STRING); + moneyDataType.setContent(""); + if(objects!=null && objects.length>0){ + String money=null; + if(objects[0] instanceof DataType){ + DataType dataType=(DataType)objects[0]; + money=dataType.getContent()==null?null:dataType.getContent().toString(); + }else{ + if(objects[0]!=null){ + money=objects[0].toString(); + } + } + moneyDataType=convertCurrency(money); + } + return moneyDataType; + } + public DataType convertCurrency(String param) { + // 汉字的数字 + String[] cnNums = new String[]{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; + // 基本单位 + String[] cnIntRadice = new String[]{"", "拾", "佰", "仟"}; + // 对应整数部分扩展单位 + String[] cnIntUnits = new String[]{"", "万", "亿", "兆"}; + // 对应小数部分单位 + String[] cnDecUnits = new String[]{"角", "分", "毫", "厘"}; + // 整数金额时后面跟的字符 + String cnInteger = "整"; + // 整型完以后的单位 + String cnIntLast = "元"; + // 最大处理的数字 + BigDecimal maxNum = new BigDecimal(999999999999999.9999); + // 金额整数部分 + String integerNum; + // 金额小数部分 + String decimalNum; + // 输出的中文金额字符串 + String chineseStr = ""; + // 分离金额后用的数组,预定义 + String[] parts; + BigDecimal money=null; + if (param == null || param.equalsIgnoreCase("")) { + return new DataType(DataType.STRING,""); + } + money = new BigDecimal(param); + if (money.compareTo(maxNum)==0) { + // 超出最大处理数字 + return new DataType(DataType.STRING,""); + } + if (money.intValue() == 0) { + chineseStr = cnNums[0] + cnIntLast + cnInteger; + return new DataType(DataType.STRING,chineseStr); + } + // 转换为字符串 + //如果是整数 + if (param.indexOf('.') == -1) { + integerNum = money.intValue()+""; + decimalNum = ""; + //如果存在小数 + } else { + parts = param.split("\\."); + integerNum = parts[0]; + decimalNum = parts[1]; + } + // 获取整型部分转换 + if (integerNum.length() > 0) { + int zeroCount = 0; + int intLen = integerNum.length(); + for (int i = 0; i < intLen; i++) { + String n = integerNum.substring(i, i+1); + logger.info("转换中文:"+n); + int p = intLen - i - 1; + int q = p / 4; + int m = p % 4; + if (n.equals("0")) { + zeroCount++; + } else { + if (zeroCount > 0) { + chineseStr += cnNums[0]; + } + // 归零 + zeroCount = 0; + chineseStr += cnNums[Integer.parseInt(n)] + cnIntRadice[m]; + } + if (m == 0 && zeroCount < 4) { + chineseStr += cnIntUnits[q]; + } + } + chineseStr += cnIntLast; + } + // 小数部分 + if (!decimalNum.equals("")) { + int decLen = decimalNum.length(); + for (int i = 0; i < decLen; i++) { + String n = decimalNum.substring(i, i+1); + if (!n.equals("0")) { + chineseStr += cnNums[Integer.parseInt(n)] + cnDecUnits[i]; + } + } + } + if (chineseStr.equals("")) { + chineseStr += cnNums[0] + cnIntLast + cnInteger; + } else if (decimalNum.equals("")) { + chineseStr += cnInteger; + } + return new DataType(DataType.STRING,chineseStr); + } +} diff --git a/src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java b/src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java new file mode 100644 index 000000000..ef169dbc5 --- /dev/null +++ b/src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java @@ -0,0 +1,45 @@ +package com.engine.salary.formlua.func.finance; + +import com.engine.salary.formlua.entity.parameter.DataType; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author + */ +public class FinanceServiceTestImpl implements FinanceService{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + String[] cnNums = new String[]{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; + @Override + public DataType getMoney(Object... objects) { + if(objects==null){ + throw new RuntimeException("GETMONEY函数的参数不能为空"); + }else if(objects.length!=1){ + throw new RuntimeException("GETMONEY函数只能允许一个参数"); + } + Object param=objects[0]; + Object content=null; + if(param instanceof DataType){ + DataType dataType=(DataType)param; + content=dataType.getContent(); + }else{ + content=param; + } + if(content!=null && !content.toString().equals("")){ + char[] chars=content.toString().toCharArray(); + String chineseNum=""; + for(char cstr:chars){ + String charstr=String.valueOf(cstr); + if(StringUtils.isNumeric(charstr)){ + int csNum=Integer.parseInt(charstr); + chineseNum+=cnNums[csNum]; + }else if(charstr.equalsIgnoreCase(".")){ + chineseNum+=""; + } + } + logger.info(chineseNum); + } + return null; + } +} diff --git a/src/com/engine/salary/formlua/func/find/FindFuncsService.java b/src/com/engine/salary/formlua/func/find/FindFuncsService.java new file mode 100644 index 000000000..65bdcba0e --- /dev/null +++ b/src/com/engine/salary/formlua/func/find/FindFuncsService.java @@ -0,0 +1,31 @@ +package com.engine.salary.formlua.func.find; + + +import com.engine.salary.formlua.entity.parameter.DataType; + +/** + * 查找函数 + */ +public interface FindFuncsService { + Object chooseOne(Object... objects); + /** + * choose函数 + * @param objs + * @return + */ + Object choose(Object... objs); + + /** + * match函数 + * @param objs + * @return + */ + DataType match(Object... objs); + + /** + * vlookups函数 + * @param objs + * @return + */ + Object vlookups(Object... objs); +} diff --git a/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java b/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java new file mode 100644 index 000000000..347ad130e --- /dev/null +++ b/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java @@ -0,0 +1,193 @@ +package com.engine.salary.formlua.func.find; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.weaver.excel.formula.core.rpc.ExcelDubboInvoker; +import com.weaver.excel.formula.core.rpc.RpcMethod; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.FuncNames; +import com.weaver.excel.formula.entity.parameter.standard.FormulaFilterData; +import com.weaver.excel.formula.util.ErrorUtil; +import com.weaver.excel.formula.util.ExcelParamUtil; +import com.weaver.excel.formula.util.IgnoreParamFilter; +import com.weaver.teams.domain.user.SimpleEmployee; +import org.apache.commons.beanutils.BeanUtils; +import org.apache.commons.compress.utils.Lists; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Map; + +@Service("findFuncsService") +public class FindFuncsServiceImpl implements FindFuncsService{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + private ExcelDubboInvoker excelDubboInvoker; + + @Override + public Object chooseOne(Object... objects) { + DataType chooseResult=new DataType(); + if(objects != null && objects.length>=2){ + List dataList= ExcelParamUtil.getParamContent(objects); + Object firstData=dataList.get(0); + for (int i=1;i filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList(): Lists.newArrayList(); + SimpleEmployee user = formObj.getEmployee(); + + Object[] params = {formId, filterDatas, user}; + return excelDubboInvoker.invokeCommonDubbo(DataType.class,formObj.getModule()+"", RpcMethod.choose, params); + } + + @Override + public DataType match(Object... objects) { + //参数校验 + String func = FuncNames.MATCH.toString(); + IgnoreParamFilter.commonFilter(func,2,2, null, objects); + + Object valueObj = objects[0]; + Object[] arrayObj = null; + + //将第二个参数转数组 + try{ + arrayObj = (Object[]) objects[1]; + }catch (Exception e){ + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数必须是数组类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + + //所在下标 + int index = ArrayUtils.indexOf(arrayObj, valueObj); + return new DataType(DataType.NUMBER, index); + } + + @Override + public Object vlookups(Object... objects) { + //参数校验 + String func = FuncNames.VLOOKUPS.toString(); + IgnoreParamFilter.commonFilter(func,3,3, null, objects); + + DataType formObj = (DataType)objects[0]; + DataType conditionObj = objects[1] != null ? (DataType)objects[1] : null; + //拿出返回数据 + Object returnObjs=objects[2]; + //初始化数组 + DataType[] rtnCols = null; + //判断是否是数组 + if(returnObjs!=null && returnObjs.getClass().isArray()){ + logger.info("执行器查找函数返回数据为DataType数组"+JSON.toJSONString(returnObjs)); + //获取数组长度 + int len= Array.getLength(returnObjs); + rtnCols=new DataType[len]; + //遍历并转换数据后放入rtnCols + for(int i=0;i fieldIds = Lists.newArrayList(); + if(ArrayUtils.isNotEmpty(rtnCols)){ + for (DataType item : rtnCols) { + if(item != null && StringUtils.isNotEmpty(item.getFieldId())) fieldIds.add(item.getFieldId()); + } + } + + Long formId = formObj.getFormId(); + List filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList() : Lists.newArrayList(); + SimpleEmployee user = formObj.getEmployee(); + + Object[] params = {formId+"", filterDatas, fieldIds, null,user}; + + DataType[] dataTypes=new DataType[1]; + Object dubboResult=excelDubboInvoker.invokeCommonDubbo(List.class,formObj.getModule()+"", RpcMethod.vlookups, params); + logger.info("返回结果:"+JSON.toJSONString(dubboResult)); + + if(dubboResult!=null && dubboResult instanceof List){ + try { + List resultObjectList=(List)dubboResult; + dataTypes=new DataType[resultObjectList.size()]; + for(int i =0;i classa=Class.forName(map.get("class").toString()) ; + Object typeObject=classa.newInstance(); + BeanUtils.populate(typeObject,map); + if(typeObject instanceof DataType){ + dataTypes[i]=(DataType) typeObject; + } + }else if(resultParam instanceof DataType){ + dataTypes[i]=(DataType) resultParam; + }else{ + logger.info("Dubbo接口返回异常数据类型:"+resultParam.getClass().getName()); + } + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + }catch (Exception e){ + e.printStackTrace(); + } + }else{ + DataType nomalData=new DataType(DataType.NUMBER, 0); + dataTypes[0]=nomalData; + } + return dataTypes.length==1?dataTypes[0]:dataTypes; + } +} diff --git a/src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java b/src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java new file mode 100644 index 000000000..4afb2fc0b --- /dev/null +++ b/src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java @@ -0,0 +1,166 @@ +package com.engine.salary.formlua.func.find; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.entity.parameter.FuncNames; +import com.engine.salary.formlua.util.ErrorUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.engine.salary.formlua.util.IgnoreParamFilter; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.compress.utils.Lists; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + + +public class FindFuncsTestServiceImpl implements FindFuncsService{ + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Override + public Object chooseOne(Object... objects) { + + if(objects==null || objects.length<2){ + throw new RuntimeException("CHOOSE函数的参数不能少于两个"); + } + DataType dataType=new DataType(); + boolean checkResult= IgnoreParamFilter.checkType(objects); + if(checkResult){ + int indexData=0; + Object firstObj=objects[0]; + try { + if(firstObj !=null){ + Double doubleValue=null; + if(firstObj instanceof DataType){ + DataType indexDataType=(DataType)firstObj; + if(ExcelParamUtil.findDataType(indexDataType.getDataType()).equalsIgnoreCase(DataType.NUMBER)){ + if(indexDataType.getContent()!=null){ + doubleValue=Double.parseDouble(indexDataType.getContent()+""); + } + } + }else{ + doubleValue=Double.parseDouble(firstObj+""); + } + indexData=doubleValue.intValue(); + }else{ + throw new RuntimeException("CHOOSE函数第一个参数不能为空"); + } + + } catch (NumberFormatException e) { + logger.error("err",e); + } + List dataList=ExcelParamUtil.getParamContent(objects); + if(indexData>=dataList.size()){ + indexData=dataList.size()-1; + } + Object resultObj=dataList.get(indexData); + if(resultObj!=null){ + if(resultObj instanceof DataType){ + dataType=(DataType)resultObj; + }else { + String type=ExcelParamUtil.getParamType(resultObj.getClass().getName()); + dataType.setDataType(type); + dataType.setContent(resultObj); + } + } + }else { + throw new RuntimeException("CHOOSE函数的参数类型不一致"); + } + logger.info("CHOOSE校验执行结果:"+ JSON.toJSONString(dataType)); + return dataType; + } + + @Override + public Object choose(Object... objects) { + //参数校验 + String func = FuncNames.CHOOSE.toString(); + IgnoreParamFilter.commonFilter(func,2,2, null, objects); + + //参数类型校验 + if(!(objects[0] instanceof DataType) || !DataType.FORM.equals(((DataType)objects[0]).getDataType())){ + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第一个参数必须是来源表"); + throw new RuntimeException(errorJson.getString("msg")); + } + + //第二个参数校验 + List conditionList = ExcelParamUtil.getParamContent(objects[1]); + if(CollectionUtils.isEmpty(conditionList)){ + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数返回值必须是boolean类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + + DataType data = new DataType(DataType.NUMBER, 1); + List rtnList = Lists.newArrayList(); + rtnList.add(data); + return rtnList; + } + + @Override + public DataType match(Object... objects) { + //参数校验 + String func = FuncNames.MATCH.toString(); + IgnoreParamFilter.commonFilter(func,2,2, null, objects); + + Object valueObj = objects[0]; + List arrayList = ExcelParamUtil.getParamContent(objects[1]); + + if(valueObj instanceof DataType){ + valueObj = ((DataType) valueObj).getContent(); + } + + //将第二个参数转数组 + if(CollectionUtils.isEmpty(arrayList)){ + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数必须是数组类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + + //所在下标 + int index = arrayList.indexOf(valueObj); + return new DataType(DataType.NUMBER, index); + } + + @Override + public Object vlookups(Object... objects) { + //参数校验 + String func = FuncNames.VLOOKUPS.toString(); + IgnoreParamFilter.commonFilter(func,3,3, null, objects); + + List conditionList = ExcelParamUtil.getParamContent(objects[1]); + DataType conditionObj=new DataType(); + if(conditionList!=null && conditionList.size()>1){ + conditionObj=(DataType) conditionList.get(0); + } + List rtnCols = ExcelParamUtil.getParamContent(objects[2]); + + //参数类型校验 +// if(!(objects[0] instanceof DataType) || !DataType.FORM.equals(((DataType)objects[0]).getDataType())){ +// Integer number = IgnoreParamFilter.getSetFuncNumber(func); +// JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第一个参数必须是数据源"); +// throw new RuntimeException(errorJson.getString("msg")); +// } + if(CollectionUtils.isEmpty(conditionList)){ + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数返回值必须是boolean类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + if(conditionObj!=null && conditionObj.getSubLogic()!=null && conditionObj.getSubLogic().size()>1){ + throw new RuntimeException("VLOOKUPS函数的第二组参数不能嵌套使用逻辑函数(AND、OR)"); + } + if (CollectionUtils.isEmpty(rtnCols)){ + Integer number = IgnoreParamFilter.getSetFuncNumber(func); + JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第三个参数返回值必须是集合类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + + DataType data = new DataType(DataType.NUMBER, 1); +// List rtnList = Lists.newArrayList(); +// rtnList.add(data); + //函数中,涉及到集合,只解析数组类型,List识别不了 + DataType[] dataTypes=new DataType[1]; + dataTypes[0]=data; + return dataTypes.length==1?dataTypes[0]:dataTypes; + } +} diff --git a/src/com/engine/salary/formlua/func/logic/IfOperator.java b/src/com/engine/salary/formlua/func/logic/IfOperator.java new file mode 100644 index 000000000..8c1791b54 --- /dev/null +++ b/src/com/engine/salary/formlua/func/logic/IfOperator.java @@ -0,0 +1,97 @@ +package com.engine.salary.formlua.func.logic; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.engine.salary.formlua.core.exception.ExcelRunTimeException; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.ErrorUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.engine.salary.formlua.util.IgnoreParamFilter; +import com.ql.util.express.ArraySwap; +import com.ql.util.express.InstructionSetContext; +import com.ql.util.express.OperateData; +import com.ql.util.express.instruction.op.OperatorIf; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class IfOperator extends OperatorIf { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Override + public OperateData executeInner(InstructionSetContext parent, ArraySwap list) throws Exception { + Integer number= IgnoreParamFilter.getSetFuncNumber("IF"); + if(list==null ||list.length !=3){ + JSONObject errorJson= ErrorUtil.buildError("IF",number,number,"IF函数只允许三个参数"); + throw new ExcelRunTimeException("IF函数只允许三个参数"); + } + Object obj = list.get(0).getObject(parent); + logger.info("IF参数:"+ JSON.toJSONString(obj)); + boolean isDataTypeBool=false; + DataType boolDtaType=null; + if(obj!=null && obj instanceof DataType){ + boolDtaType=(DataType)obj; + if(boolDtaType.getContent() !=null && ( boolDtaType.getContent() instanceof Boolean )){ + isDataTypeBool=true; + obj=boolDtaType.getContent(); + }else{ + switch (obj+""){ + case "true": + obj=true; + isDataTypeBool=true; + break; + case "false": + obj=false; + isDataTypeBool=true; + break; + default: + isDataTypeBool=false; + break; + } + } + }else if(obj instanceof Boolean){ + isDataTypeBool=true; + } + if (obj == null) { + JSONObject errorJson=ErrorUtil.buildError("IF",number,number,"IF函数参数不能为空"); + throw new RuntimeException(errorJson.getString("msg")); + } else if (!(obj instanceof Boolean) && (! (obj instanceof DataType) )) { + JSONObject errorJson=ErrorUtil.buildError("IF",number,number,"IF函数判断条件必须是真假值"); + throw new RuntimeException(errorJson.getString("msg")); + }else if(!isDataTypeBool){ + JSONObject errorJson=ErrorUtil.buildError("IF",number,number,"IF函数判断条件必须是真假值"); + throw new RuntimeException(errorJson.getString("msg")); + }else { + if (((Boolean)obj).booleanValue() == true){ + OperateData operateData=list.get(1); + Object object=operateData.getObject(parent); +// if(object instanceof DataType){ +// String type= ExcelParamUtil.getParamType(object); +// if(type.equalsIgnoreCase("date")){ +// object=ExcelParamUtil.getParamContent(object,"string"); +// } +// } + OperateData operateData1=new OperateData(ExcelParamUtil.getParamContent(object,""),operateData.getType(parent)); + return operateData1; + }else{ + OperateData operateData=list.get(2); + Object object=operateData.getObject(parent); +// if(object instanceof DataType){ +// String type=ExcelParamUtil.getParamType(object); +// if(type.equalsIgnoreCase("date")){ +// object=ExcelParamUtil.getParamContent(object,"string"); +// } +// } + OperateData operateData1=new OperateData(ExcelParamUtil.getParamContent(object,""),operateData.getType(parent)); + return operateData1; + } + } + } + + public IfOperator(String aName) { + super(aName); + } + + public IfOperator(String aAliasName, String aName, String aErrorInfo) { + super(aAliasName, aName, aErrorInfo); + } +} diff --git a/src/com/engine/salary/formlua/func/logic/LogicService.java b/src/com/engine/salary/formlua/func/logic/LogicService.java new file mode 100644 index 000000000..722608ab3 --- /dev/null +++ b/src/com/engine/salary/formlua/func/logic/LogicService.java @@ -0,0 +1,17 @@ +package com.engine.salary.formlua.func.logic; + +import com.engine.salary.formlua.entity.parameter.DataType; + + +public interface LogicService { + public DataType not(Object... object); + public DataType isEmpty(Object... objs); + public DataType isTrue(Object... objs); + public DataType isFalse(Object... objs); + public DataType and(Object... objs); + public DataType or(Object... objs); + public DataType likeFunc(Object... objects); + public DataType ifs(Object... objects); + public DataType find(Object... objects); + public DataType switchs(Object... objects); +} diff --git a/src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java b/src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java new file mode 100644 index 000000000..d8a9b1a81 --- /dev/null +++ b/src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java @@ -0,0 +1,495 @@ +package com.engine.salary.formlua.func.logic; + +import com.alibaba.fastjson.JSONObject; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.IgnoreParamFilter; +import com.weaver.excel.formula.entity.parameter.FuncNames; +import com.weaver.excel.formula.util.ErrorUtil; +import com.weaver.excel.formula.util.ExcelParamUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @className: + * @Description:Excel逻辑函数 + * @Author: + * @date: + */ +public class LogicServiceImpl implements LogicService { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Override + public DataType not(Object... objects) { + DataType resultdataType=new DataType(); + resultdataType.setDataType(DataType.BOOL); + Class[] typeObjects=new Class[]{boolean.class}; + IgnoreParamFilter.commonFilter("NOT",1,1,typeObjects,objects); + Object object=objects[0]; + if(object == null){ + resultdataType.setContent(false); + return resultdataType; + } + Boolean cnd; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + cnd=dataType.getContent()!=null?((Boolean) dataType.getContent()):false; + }else{ + cnd=(boolean)object; + } + + resultdataType.setContent(!cnd); + return resultdataType; + } + + @Override + public DataType isEmpty(Object... objs) { + int number=IgnoreParamFilter.getSetFuncNumber(FuncNames.ISEMPTY.toString()); + if(objs.length!=1){ + throw new RuntimeException("ISEMPTY函数只允许一个参数"); + } + boolean result=false; + if(null==objs||objs.length==0){ + DataType dataType=new DataType(); + dataType.setDataType(DataType.BOOL); + dataType.setContent(true); + return dataType; + } + for(int i=0;i0){ + throw new RuntimeException("TRUE函数不能有参数"); + } + DataType dataType=new DataType(); + dataType.setDataType(DataType.BOOL); + dataType.setContent(true); + return dataType; + } + @Override + public DataType isFalse(Object... objects){ + int number=IgnoreParamFilter.getSetFuncNumber(FuncNames.FALSE.toString()); + if(objects.length>0){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.FALSE.toString(),number,number,"FALSE函数不能有参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + DataType dataType=new DataType(); + dataType.setDataType(DataType.BOOL); + dataType.setContent(false); + return dataType; + } + + + @Override + public DataType and(Object... objs) { + IgnoreParamFilter.filterLogicAndORFunc(objs,"AND"); + Object result; + int trueCount=0; + int falseCount=0; + DataType dataType=new DataType(); + for(int i=0;i0){ + dataType.getSubLogic().addAll(paramdataType.getSubLogic()); + } + }else{ + bool=(boolean)objs[i]; + } + + if(bool){ + trueCount++; + }else{ + falseCount++; + } + } + if(trueCount==objs.length){ + result= true; + }else{ + result= false; + } + + dataType.setDataType(DataType.BOOL); + dataType.setContent(result); + dataType.getSubLogic().add("and"); + + LogicUtils.buildAndOrFilterParam("AND",dataType,objs); + return dataType; + } + + @Override + public DataType or(Object... objs) { + IgnoreParamFilter.filterLogicAndORFunc(objs,"OR"); + Object result; + int trueCount=0; + int falseCount=0; + DataType dataType=new DataType(); + for(int i=0;i0){ + dataType.getSubLogic().addAll(paramdataType.getSubLogic()); + } + }else{ + bool=(boolean)objs[i]; + } + if(bool){ + trueCount++; + }else{ + falseCount++; + } + } + if(trueCount>0){ + result= true; + }else{ + result= false; + } + + dataType.setDataType(DataType.BOOL); + dataType.setContent(result); + dataType.getSubLogic().add("or"); + LogicUtils.buildAndOrFilterParam("OR",dataType,objs); + return dataType; + } + + + + @Override + public DataType likeFunc(Object... objects) { + IgnoreParamFilter.filterLikeFunc(objects); + Object object=objects[0]; + Object result=false; + String txtS=""; + if(object instanceof DataType){ + txtS=ExcelParamUtil.getParamContent(object,"string").toString(); + }else { + txtS=object.toString(); + } + if(null==txtS||txtS.trim().equals("")){ + return new DataType(DataType.BOOL,false); + } + Object[] partamArray=(Object[])objects[1]; + for(int i=0;i=0?true:false){ + result=ridx>=0?true:false; + break; + } + + + } + DataType dataType=new DataType(DataType.BOOL,result); + LogicUtils.buildLikeFilterParam(dataType,objects); + return dataType; + } + + @Override + public DataType ifs(Object... objects) { + int number=IgnoreParamFilter.getSetFuncNumber(FuncNames.IFS.toString()); + if(objects.length==0 || objects.length%2!=1 || objects.length<3){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数的参数必须大于3个且为单数"); + throw new RuntimeException(errorJson.getString("msg")); + } + int testI; + for(testI=1;testI<=objects.length;testI++){ + if(testI%2>0 && testI!=objects.length){ + Object cndObj=objects[testI-1]; + if(!(cndObj instanceof Boolean) && !(cndObj instanceof DataType)){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); + throw new RuntimeException(errorJson.getString("msg")); + }else if(cndObj instanceof DataType){ + DataType boolDataType=(DataType)cndObj; + if(boolDataType.getContent()!=null && !(boolDataType.getContent() instanceof Boolean)){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + } + + boolean paramCheck=checkParamType(objects); + if(!paramCheck){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数多个条件的返回值必须一致"); + throw new RuntimeException(errorJson.getString("msg")); + } + + int i; + for(i=1;i<=objects.length;i++){ + if(i%2==0){ + Object cndObj=objects[i-2]; + if(cndObj instanceof Boolean){ + Boolean cnd=(Boolean)cndObj; + if(cnd){ + if(objects[i-1] instanceof DataType){ + return (DataType) objects[i-1]; + }else{ + return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i-1].getClass().getName())),objects[i-1]); + } +// return new DataType(DataType.BOOL,objects[i-1]); + } + }else if(cndObj instanceof DataType){ + DataType boolData=(DataType)cndObj; + Boolean cnd=boolData.getContent()!=null?( (Boolean)boolData.getContent() ) : false; + if(cnd){ + if(objects[i-1] instanceof DataType){ + return (DataType) objects[i-1]; + }else { + return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i-1].getClass().getName())),objects[i-1]); + } + + } + } + } + } + //如果没有条件符合,返回默认值,最后一个参数为默认值 + Object result=ExcelParamUtil.getParamContent(objects[objects.length-1],""); + if(result instanceof DataType){ + return (DataType)result; + }else{ + return new DataType(DataType.returnType(ExcelParamUtil.getParamType(result.getClass().getName())),result); + } + + } + + @Override + public DataType find(Object... objects) { + + return new DataType(DataType.BOOL,finds(objects)); + } + + @Override + public DataType switchs(Object... objects) { + if(objects.length==0||objects==null){ + throw new RuntimeException("参数不能为空"); + } + if(objects.length<4){ + throw new RuntimeException("switch函数的参数长度必须大于4个"); + } + if(objects.length%2!=0){ + throw new RuntimeException("switch函数的参数长度必须为双数"); + } + Object source=objects[0]; + Object defaultValue=objects[objects.length-1]; + if(source instanceof DataType){ + source=ExcelParamUtil.getParamContent(source,""); + } + if(defaultValue instanceof DataType){ + defaultValue=ExcelParamUtil.getParamContent(defaultValue,""); + } + Object result=null; + for (int i=1;i=3 ){ + if(objects[objects.length-1] instanceof Integer){ + vali=Integer.parseInt(objects[objects.length-1].toString()); + if(vali!=1&&vali!=2){ + throw new RuntimeException("FIND函数第三个参数只允许1和2"); + } + }else{ + throw new RuntimeException("FIND函数第三个参数只允许1和2"); + } + } + + + //将参数转换成List,要判断参数是数组还是单个对象 + List objs1=null; + List objs2=null; + if(objects[0] instanceof Object[]){ + Object[] transObj=(Object[])objects[0]; + objs1=Arrays.asList(transObj); + }else{ + objs1=Arrays.asList(objects[0]); + } + if(objects[1] instanceof Object[]){ + Object[] transObj=(Object[])objects[1]; + objs2=Arrays.asList(transObj); + }else{ + objs2=Arrays.asList(objects[1]); + } + + + if(objs1.size()==0 || objs2.size() == 0 ){ + throw new RuntimeException("参数不能为空"); + } + + //判断参数类型是否一致 + List all=new ArrayList<>(); + all.addAll(objs1); + all.addAll(objs2); + for (Object obj:all){ + String localType=""; + if(obj instanceof DataType){ + String paramType=ExcelParamUtil.getParamType(obj); + if(!paramType.toLowerCase().equals("option")){ + localType=ExcelParamUtil.checkParamType(paramType); + }else{ + localType=paramType; + } + }else{ + localType=ExcelParamUtil.checkParamType(ExcelParamUtil.getParamType(obj.getClass().getName())); + } + if(type==null){ + type=localType; + }else{ + if(!type.equalsIgnoreCase(localType)){ + throw new RuntimeException("参数类型不一致"); + } + } + } + + //根据超找类型判断谁是查找目标,谁是查找依据 + List targetList=new ArrayList<>(); + List keyList=new ArrayList<>(); + switch (vali){ + case 1: + targetList=transOptionData(objs1); + keyList=transOptionData(objs2); + break; + case 2: + targetList=transOptionData(objs2); + keyList=transOptionData(objs1); + break; + default: + throw new RuntimeException("查找类型错误"); + } + + for (Object keyO:keyList){ + for (Object target:targetList){ + if(keyO.equals(target)){ + return true; + } + } + } + + return false; + } + + private List transOptionData(List dataList){ + List contentArrays=new ArrayList<>(); + for (Object data:dataList){ + Object param1=ExcelParamUtil.getParamContent(data,""); + //获取依据数据的类型 + String keyType=""; + if(data instanceof DataType){ + keyType=ExcelParamUtil.getParamType(data); + }else{ + keyType=ExcelParamUtil.getParamType(data.getClass().getName()); + } + keyType=ExcelParamUtil.checkParamType(keyType); + + if(keyType.toLowerCase().equals(DataType.OPTION)){ + contentArrays.addAll(Arrays.asList(param1.toString().split(","))); + }else if(data instanceof Character){ + contentArrays.add(param1.toString()); + }else if(keyType.toLowerCase().equals("number")){ + contentArrays.add(Double.parseDouble(param1.toString())); + }else{ + contentArrays.add(param1); + } + } + return contentArrays; + } + + private boolean checkParamType(Object[] objects){ + boolean result=false; + String type=null; + for (int i=1;i<=objects.length;i++){ + if(i%2==0){ + Object obj=objects[i-1]; + String typeStr=ExcelParamUtil.getParamType(obj); + typeStr=ExcelParamUtil.checkParamType(typeStr); + logger.info(typeStr); + if(type==null){ + type=typeStr; + }else{ + result=typeStr.equalsIgnoreCase(type); + if(!result){ + return result; + } + + } + } + } + String typeStr=ExcelParamUtil.checkParamType(ExcelParamUtil.getParamType(objects[objects.length-1])); + result=type.equalsIgnoreCase(typeStr); + return result; + } + +} diff --git a/src/com/engine/salary/formlua/func/logic/LogicUtils.java b/src/com/engine/salary/formlua/func/logic/LogicUtils.java new file mode 100644 index 000000000..0768e9b12 --- /dev/null +++ b/src/com/engine/salary/formlua/func/logic/LogicUtils.java @@ -0,0 +1,110 @@ +package com.engine.salary.formlua.func.logic; + +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.entity.standard.FormulaFilterData; +import com.weaver.common.form.stat.FilterFormData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * 逻辑函数构建条件工具类 + */ +public class LogicUtils { + protected static final Logger logger = LoggerFactory.getLogger(LogicUtils.class); + /** + * 构建AND和OR函数的条件 + * @param func + * @param dataType + * @param objs + */ + public static void buildAndOrFilterParam(String func,DataType dataType,Object... objs){ + List filterFormDataList=new ArrayList<>(); + try { + if(objs != null && objs.length > 0) { + for(int i=0;i paramFilterDataList=paramData.getFormulaFilterDataList(); + if(paramFilterDataList!=null){ + paramFilterDataList.forEach(val->{ + if(func.equalsIgnoreCase("AND")){ + val.setCondition(FormulaFilterData.CONDITION_AND); + }else if(func.equalsIgnoreCase("OR")){ + val.setCondition(FormulaFilterData.CONDITION_OR); + } + + }); + filterFormDataList.addAll(paramFilterDataList); + } + } + } +// dataType.setFormulaFilterDataList(filterFormDataList); + } + } catch (Exception e) { + logger.error("err",e); + } + } + + /** + * 构建Like函数的过滤条件 + * @param dataType + * @param objs + */ + public static void buildLikeFilterParam(DataType dataType,Object... objs){ + try { + if(dataType != null && objs.length > 0) { + if(dataType.getDataType().equalsIgnoreCase(DataType.DATASOURCE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION) || dataType.getDataType().equalsIgnoreCase(DataType.FORM)) { + throw new RuntimeException("筛选条件函数[LIKE]:第一个参数不能是选项型"); + } + List formulaFilterDataList=new ArrayList<>(); + FormulaFilterData formulaFilterData=new FormulaFilterData(); + List contents = new ArrayList(); + for(Object str : objs) { + if(str instanceof DataType){ + DataType data=(DataType)str; + contents.add(data.getContent()+""); + }else { + contents.add(str+""); + } + } + formulaFilterData.setContents(contents); +// formulaFilterData.setTerm(FilterFormData.TERM_LIKE); +// formulaFilterData.setFieldId(dataType.getFieldId()+""); +// formulaFilterDataList.add(formulaFilterData); +// dataType.setFormulaFilterDataList(formulaFilterDataList); + } + } catch (RuntimeException RuntimeException) { + RuntimeException.printStackTrace(); + } + } + + public static void buildInFilterParam(DataType dataType, Object... objs){ + try { + if(dataType != null && objs.length > 0) { + if(!dataType.getDataType().equalsIgnoreCase(DataType.DATASOURCE) && !dataType.getDataType().equalsIgnoreCase(DataType.OPTION)) { + return; + } + List formulaFilterDataList=new ArrayList<>(); + FormulaFilterData formulaFilterData=new FormulaFilterData(); + List ids = new ArrayList(); + for(Object option : objs) { + if(option instanceof DataType){ + DataType data=(DataType)option; + ids.add(data.getContent()+""); + } + } + formulaFilterData.setIds(ids); + formulaFilterData.setFieldId(dataType.getFieldId()+""); +// formulaFilterData.setTerm(FilterFormData.TERM_EQ); +// formulaFilterDataList.add(formulaFilterData); +// dataType.setFormulaFilterDataList(formulaFilterDataList); + } + } catch (Exception e) { + logger.error("err",e); + } + } + +} diff --git a/src/com/engine/salary/formlua/func/math/MathFuncsService.java b/src/com/engine/salary/formlua/func/math/MathFuncsService.java new file mode 100644 index 000000000..7f9565aad --- /dev/null +++ b/src/com/engine/salary/formlua/func/math/MathFuncsService.java @@ -0,0 +1,79 @@ +package com.engine.salary.formlua.func.math; + +import com.engine.salary.formlua.entity.parameter.DataType; + +public interface MathFuncsService { + /** + * 向上取整 + * @param object + * @return + */ + public DataType roundUp(Object... object); + + /** + * 向下取整 + * @param object + * @return + */ + public DataType roundDown(Object... object); + + /** + * 四舍五入 + * @param object + * @return + */ + public DataType round(Object... object); + + /** + * 统计函数 + * @param objects + * @return + */ + public DataType aggregation(Object... objects); + + /** + * 取余函数 + * @param objects + * @return + */ + public DataType mod(Object... objects); + + /** + * 精度控制函数 + * @param number + * @param numDigits + * @return + */ + public DataType Trunc(Object number,Object numDigits); + + /** + * 随机数 + * @param length 随机数长度 + * @param type 随机数类型,分为纯数字、纯英文字母、英文和数字的组合 + * @return + */ + public DataType randomNumber(Object length,Object type); + + /** + * 分组函数 + * @param objects 分组的数据 + * @return 返回一个结果集,这个结果集不能直接使用,要通过其他函数继续运算得出结果,比如aggregation统计函数 + */ + public DataType group(Object... objects); + + /** + * 是否是整数 + * @param objects + * @return + */ + public DataType isInt(Object... objects); + + /** + * 是否是数字 + * @param objects + * @return + */ + public DataType isNumber(Object... objects); + + +} diff --git a/src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java b/src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java new file mode 100644 index 000000000..f5a4362b3 --- /dev/null +++ b/src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java @@ -0,0 +1,468 @@ +package com.engine.salary.formlua.func.math; + +import com.alibaba.fastjson.JSONObject; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.FuncNames; +import com.weaver.excel.formula.util.ErrorUtil; +import com.weaver.excel.formula.util.ExcelParamUtil; +import com.weaver.excel.formula.util.IgnoreParamFilter; +import com.weaver.excel.formula.util.RegularUtil; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +@Service("mathFuncsService") +public class MathFuncsServiceImpl implements MathFuncsService { + private final String randomNumber="NUM"; + private final String randomChar="CHAR"; + private final String randomNumANDChar="FIX"; + + @Override + public DataType roundUp(Object... objects) { + Integer errorNumber= IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDUP.getName()); + Object number=null; + Object object = objects[0]; + + //小数位 + int numDigits = 0; + Object numDigitsObj = null; + + //获取小数点位数参数 + if(objects != null && objects.length > 1) { + numDigitsObj = objects[1]; + + if(numDigitsObj != null && numDigitsObj instanceof DataType){ + numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj,""); + } + } + + //整数校验 + if(numDigitsObj != null){ + try{ + numDigits = (int) numDigitsObj; + }catch (Exception e){ + throw new RuntimeException("小数点位数必须是整数"); + } + } + + if(object instanceof DataType){ + DataType dataType=(DataType)object; + if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + number=dataType.getContent(); + }else{ + BigDecimal db = new BigDecimal(object.toString()); + number=db; + } + if(!RegularUtil.isNumber(number)){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + + BigDecimal bigDecimal = new BigDecimal(number+""); + Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_CEILING).doubleValue(); + + if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result, ComponentType.NumberComponent.toString()); + } + + @Override + public DataType roundDown(Object... objects) { + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDDOWN.getName()); + Object number=null; + Object object = objects[0]; + + //小数位 + int numDigits = 0; + Object numDigitsObj = null; + + //获取小数点位数参数 + if(objects != null && objects.length > 1) { + numDigitsObj = objects[1]; + + if(numDigitsObj != null && numDigitsObj instanceof DataType){ + numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj,""); + } + } + + //整数校验 + if(numDigitsObj != null){ + try{ + numDigits = (int) numDigitsObj; + }catch (Exception e){ + throw new RuntimeException("小数点位数必须是整数"); + } + } + + if(object instanceof DataType){ + DataType dataType=(DataType)object; + if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ + return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + } + number=dataType.getContent(); + }else{ + BigDecimal db = new BigDecimal(object.toString()); + number=db; + } + + if(!RegularUtil.isNumber(number)){ + return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + } + + BigDecimal bigDecimal = new BigDecimal(number+""); + Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_FLOOR).doubleValue(); + + if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType round(Object... objects) { + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUND.getName()); + Object number=null; + Object object = objects[0]; + + //小数位 + int numDigits = 0; + Object numDigitsObj = null; + + //获取小数点位数参数 + if(objects != null && objects.length > 1) { + numDigitsObj = objects[1]; + + if(numDigitsObj != null && numDigitsObj instanceof DataType){ + numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj,""); + } + } + + //整数校验 + if(numDigitsObj != null){ + try{ + numDigits = (int) numDigitsObj; + }catch (Exception e){ + throw new RuntimeException("小数点位数必须是整数"); + } + } + + if(object instanceof DataType){ + DataType dataType=(DataType)object; + if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ + return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + } + number=dataType.getContent(); + }else{ + BigDecimal db = new BigDecimal(object.toString()); + number=db; + } + + if(!RegularUtil.isNumber(number)){ + return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + } + + BigDecimal bigDecimal = new BigDecimal(number+""); + Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_HALF_UP).doubleValue(); + + if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType aggregation(Object... objects) { + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.AGGREGATION.getName()); + Double result=0d; + if(objects.length==0||objects.length<2){ + return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + } + List dataList=new ArrayList(); + for (int i=0;i5){ + digitsIntVal=5; + } + BigDecimal b = new BigDecimal(numberVal.toString()); + f1 = b.setScale(digitsIntVal, BigDecimal.ROUND_HALF_UP).doubleValue(); + if(digitsIntVal==0){ + f1=b.intValue(); + } + }else { + JSONObject errorJson= ErrorUtil.buildError(FuncNames.TRUNC.toString(),errorNumber,errorNumber,"小数点格式化只允许数字"); + throw new RuntimeException(errorJson.getString("msg")); + } + return new DataType(DataType.NUMBER,f1,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType randomNumber(Object length,Object type) { + String value=""; + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.RANDOMNUMBER.getName()); + Double numberLength=0.0; + Object param=10; + String dataValueType=""; + if(length!=null){ + if(length instanceof DataType){ + DataType dataType=(DataType)length; + dataValueType=ExcelParamUtil.checkParamType(dataType); + param=ExcelParamUtil.getParamContent(length,""); + }else{ + dataValueType=ExcelParamUtil.checkParamType(length); + param=length; + } + } + //判断length长度数据类型是否合规 + if(!dataValueType.equalsIgnoreCase("number")){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数只允许数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + //判断用户设置的length是否大于0,生成的随机数长度必须是大于1的 + if(param!=null){ + numberLength=Double.parseDouble(param.toString()); + if(numberLength<=0){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数长度必须大于0"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + String typeString=randomNumber; + if(type !=null){ + if(type instanceof DataType){ + DataType dataType=(DataType)length; + typeString=ExcelParamUtil.getParamContent(type,"").toString(); + }else{ + typeString=type.toString(); + } + } + + switch (typeString){ + case randomNumber: + value=randomFunc(numberLength,randomNumber); + break; + case randomChar: + value=randomFunc(numberLength,randomChar); + break; + case randomNumANDChar: + value=randomFunc(numberLength,randomNumANDChar); + break; + default: + JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数的返回值只允许数字、字符以及数字和字符的混合类型"); + throw new RuntimeException(errorJson.getString("msg")); + + } + + return new DataType(DataType.NUMBER,value,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType group(Object... objects) { + return null; + } + + @Override + public DataType isInt(Object... objects) { + boolean isInt=false; + if(objects[0] instanceof DataType){ + DataType dataType=(DataType)objects[0]; + isInt=RegularUtil.isInteger(dataType.getContent()); + }else{ + isInt=RegularUtil.isInteger(objects[0]); + } + return new DataType(DataType.BOOL,isInt); + } + + @Override + public DataType isNumber(Object... objects) { + boolean isInt=false; + if(objects[0] instanceof DataType){ + DataType dataType=(DataType)objects[0]; + isInt=RegularUtil.isNumber(dataType.getContent()); + }else{ + isInt=RegularUtil.isNumber(objects[0]); + } + return new DataType(DataType.BOOL,isInt); + } + + private String randomFunc(Double length,String type){ + Random r = new Random(); + StringBuffer sbff=new StringBuffer(); + + //数字类型随机数 + if(type.equalsIgnoreCase("number")){ + for (double i=0;i0){ + charloop=(length-1)/2; + numloop=charloop+1; + }else{ + charloop=length/2; + numloop=charloop; + } + } + for (double i=0;i 1) { + numDigitsObj = objects[1]; + if(numDigitsObj != null && numDigitsObj instanceof DataType) throw new RuntimeException("ROUNDUP函数第二个参数只能是常量"); + } + + //整数校验 + if(numDigitsObj != null){ + try{ + numDigits = (int) numDigitsObj; + }catch (Exception e){ + throw new RuntimeException("小数点位数必须是整数"); + } + } + + if(object instanceof DataType){ + DataType dataType=(DataType)object; + if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + number=dataType.getContent(); + }else{ + BigDecimal db = new BigDecimal(object.toString()); + number=db; + } + if(!RegularUtil.isNumber(number)){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + + BigDecimal bigDecimal = new BigDecimal(number+""); + Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_CEILING).doubleValue(); + + if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result); + } + + @Override + public DataType roundDown(Object... objects) { + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDDOWN.getName()); + Object number=null; + Object object = objects[0]; + + //小数位 + int numDigits = 0; + Object numDigitsObj = null; + + //获取小数点位数参数 + if(objects != null && objects.length > 1) { + numDigitsObj = objects[1]; + if(numDigitsObj != null && numDigitsObj instanceof DataType) throw new RuntimeException("ROUNDDOWN函数第二个参数只能是常量"); + } + + //整数校验 + if(numDigitsObj != null){ + try{ + numDigits = (int) numDigitsObj; + }catch (Exception e){ + throw new RuntimeException("小数点位数必须是整数"); + } + } + + if(object instanceof DataType){ + DataType dataType=(DataType)object; + if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDDOWN.toString(),errorNumber,errorNumber,"ROUNDDOWN函数只接受数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + number=dataType.getContent(); + }else{ + BigDecimal db = new BigDecimal(object.toString()); + number=db; + } + + if(!RegularUtil.isNumber(number)){ + return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + } + + BigDecimal bigDecimal = new BigDecimal(number+""); + Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_FLOOR).doubleValue(); + + if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType round(Object... objects) { + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUND.getName()); + Object number=null; + Object object = objects[0]; + + //小数位 + int numDigits = 0; + Object numDigitsObj = null; + + //获取小数点位数参数 + if(objects != null && objects.length > 1) { + numDigitsObj = objects[1]; + if(numDigitsObj != null && numDigitsObj instanceof DataType) throw new RuntimeException("ROUND函数第二个参数只能是常量"); + } + + //整数校验 + if(numDigitsObj != null){ + try{ + numDigits = (int) numDigitsObj; + }catch (Exception e){ + throw new RuntimeException("小数点位数必须是整数"); + } + } + + if(object instanceof DataType){ + DataType dataType=(DataType)object; + if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUND.toString(),errorNumber,errorNumber,"ROUND函数只接受数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + number=dataType.getContent(); + }else{ + BigDecimal db = new BigDecimal(object.toString()); + number=db; + } + + if(!RegularUtil.isNumber(number)){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUND.toString(),errorNumber,errorNumber,"ROUND函数只接受数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + + BigDecimal bigDecimal = new BigDecimal(number+""); + Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_HALF_UP).doubleValue(); + + if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType aggregation(Object... objects) { + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.AGGREGATION.getName()); + Double result=0d; + if(objects.length==0||objects.length<2){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.AGGREGATION.toString(),errorNumber,errorNumber,"统计函数至少需要两个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + List dataList=new ArrayList(); + for (int i=0;i5){ + digitsIntVal=5; + } + BigDecimal b = new BigDecimal(numberVal.toString()); + f1 = b.setScale(digitsIntVal, BigDecimal.ROUND_HALF_UP).doubleValue(); + if(digitsIntVal==0){ + f1=b.intValue(); + } + }else { + JSONObject errorJson= ErrorUtil.buildError(FuncNames.TRUNC.toString(),errorNumber,errorNumber,"小数点格式化只允许数字"); + throw new RuntimeException(errorJson.getString("msg")); + } + return new DataType(DataType.NUMBER,f1,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType randomNumber(Object length,Object type) { + String value=""; + Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.RANDOMNUMBER.getName()); + Double numberLength=0.0; + Object param=10; + String dataValueType=""; + if(length!=null){ + if(length instanceof DataType){ + DataType dataType=(DataType)length; + dataValueType=ExcelParamUtil.checkParamType(dataType); + param=ExcelParamUtil.getParamContent(length,""); + }else{ + dataValueType=ExcelParamUtil.checkParamType(length); + param=length; + } + } + //判断length长度数据类型是否合规 + if(!dataValueType.equalsIgnoreCase("number")){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数只允许数字参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + //判断用户设置的length是否大于0,生成的随机数长度必须是大于1的 + if(param!=null){ + numberLength=Double.parseDouble(param.toString()); + if(numberLength<=0){ + JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数长度必须大于0"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + String typeString=randomNumber; + if(type !=null){ + if(type instanceof DataType){ + DataType dataType=(DataType)length; + typeString=ExcelParamUtil.getParamContent(type,"").toString(); + }else{ + typeString=type.toString(); + } + } + + switch (typeString){ + case randomNumber: + value=randomFunc(numberLength,randomNumber); + break; + case randomChar: + value=randomFunc(numberLength,randomChar); + break; + case randomNumANDChar: + value=randomFunc(numberLength,randomNumANDChar); + break; + default: + JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数的返回值只允许数字、字符以及数字和字符的混合类型"); + throw new RuntimeException(errorJson.getString("msg")); + + } + + return new DataType(DataType.NUMBER,value,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType group(Object... objects) { + return null; + } + + @Override + public DataType isInt(Object... objects) { + if(objects==null || objects.length==0){ + throw new RuntimeException("【ISINT】函数的参数不能为空"); + } + Object paramObj=objects[0]; + String type=""; + Object content; + if(paramObj instanceof DataType){ + DataType paramDataType=(DataType)paramObj; + type=paramDataType.getDataType(); + content=paramDataType.getContent(); + }else{ + type=ExcelParamUtil.getParamType(paramObj.getClass().getName()); + content=paramObj; + } + if(!type.equalsIgnoreCase("String") && !type.equalsIgnoreCase("number")){ + throw new RuntimeException("【ISINT】函数的参数必须为字符或者数字类型"); + } + + return new DataType(DataType.BOOL,true); + } + + @Override + public DataType isNumber(Object... objects) { + if(objects==null || objects.length==0){ + throw new RuntimeException("【ISNUMBER】函数的参数不能为空"); + } + Object paramObj=objects[0]; + String type=""; + Object content; + if(paramObj instanceof DataType){ + DataType paramDataType=(DataType)paramObj; + type=paramDataType.getDataType(); + content=paramDataType.getContent(); + }else{ + type=ExcelParamUtil.getParamType(paramObj.getClass().getName()); + content=paramObj; + } + if(!type.equalsIgnoreCase("String")){ + throw new RuntimeException("【ISNUMBER】函数的参数必须为字符类型"); + } + return new DataType(DataType.BOOL,false); + } + + private String randomFunc(Double length,String type){ + Random r = new Random(); + StringBuffer sbff=new StringBuffer(); + + //数字类型随机数 + if(type.equalsIgnoreCase("number")){ + for (double i=0;i0){ + charloop=(length-1)/2; + numloop=charloop+1; + }else{ + charloop=length/2; + numloop=charloop; + } + } + for (double i=0;i newObjs=new ArrayList<>(); + for (int i=0;i0){ + for(Object object:newObjs){ + if(object instanceof DataType){ + DataType dataType=(DataType)object; + if(dataType.getDataType().equalsIgnoreCase(DataType.NUMBER)){ + newString.append(dataType.getContent()); + }else{ + newString.append(ExcelParamUtil.getParamContent(object,"string")); + } + }else { + newString.append(ExcelParamUtil.getParamContent(object,"string")); + } + + } + } + return new DataType(DataType.STRING,newString.toString()); + } + + /** + * 转成String + * @param objs + * @return + */ + @Override + public DataType text(Object... objs) { + String func="TEXT"; + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + if(null==objs||objs.length>1){ + throw new RuntimeException(func+"函数参数只允许一个参数"); + } + Object obj=objs[0]; + if(null==obj){ + throw new RuntimeException(func+"函数参数为空"); + } + Object result; + if(obj instanceof DataType){ + DataType dataType=(DataType)obj; + if(dataType.getDataType().equalsIgnoreCase(DataType.NUMBER)){ + result=dataType.getContent(); + }else if(dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ + result=dataType.getOptionContent(); + }else if(dataType.getComponentKey()!=null && dataType.getComponentKey().equalsIgnoreCase("FileComponent")){ + result=dataType.getOptionContent(); + }else{ + result=ExcelParamUtil.getParamContent(dataType,DataType.STRING).toString(); + } + }else { + result=obj.toString(); + } + + return new DataType(DataType.STRING,result); + } + + + /** + * 转成Int类型 + * 提取字符中的数字并返回 + * @param objs + * @return + */ + @Override + public DataType value(Object... objs) { + boolean isNumber=false; + Object txt=objs[0]; + Object result; + Class[] typeObjects=new Class[]{}; + IgnoreParamFilter.commonFilter("VALUE",1,1,typeObjects,objs); + String numberStr; + + if(txt instanceof DataType){ + DataType dataType=(DataType)txt; + if(dataType.getDataType().toLowerCase().equals(DataType.NUMBER)){ + isNumber=true; + if(ExcelParamUtil.getParamContent(txt,"string")==null){ + numberStr="0"; + }else { + numberStr=ExcelParamUtil.getParamContent(txt,"string").toString(); + } + + }else { + if(ExcelParamUtil.getParamContent(txt,"string")==null){ + numberStr="0"; + }else{ + numberStr=ExcelParamUtil.getParamContent(txt,"string").toString(); + } + if(!RegularUtil.isNumber(numberStr)){ + numberStr="0"; + } + } + + }else { + if(RegularUtil.isNumber(txt.toString())){ + isNumber=true; + numberStr=txt.toString(); + }else { + numberStr="0"; + } + } + + if(numberStr.indexOf(".")>0){ + if(numberStr.length()>17){ + numberStr=numberStr.substring(0,17); + } + result=new BigDecimal(numberStr); + }else { + if(numberStr.length()>16){ + numberStr=numberStr.substring(0,16); + } + result=Long.parseLong(numberStr); + } + return new DataType(DataType.NUMBER,result); + } + + + /** + * 获取字符串长度 + * @param txt + * @return + */ + @Override + public DataType len(Object... txt) { + Class[] typeObjects=new Class[]{String.class}; + IgnoreParamFilter.commonFilter("LEN",1,1,typeObjects,txt); + int length=ExcelParamUtil.getParamContent(txt[0],"string").toString().length(); + return new DataType(DataType.NUMBER,length); + } + + /** + *搜索字符返回位置下标 + * 第一个参数是搜索字符 + * 第二个参数是源字符串 + * @param objects + * @return + */ + @Override + public DataType search(Object... objects) { + Class[] typeObjects=new Class[]{String.class,String.class,Integer.class}; + int idx=0; + IgnoreParamFilter.commonFilter("SEARCH",2,3,typeObjects,objects); + if(objects.length==3){ + Object idxObj=ExcelParamUtil.getParamContent(objects[2],"option"); + if(idxObj.toString().indexOf(".")>0){ + idx=Integer.parseInt(idxObj.toString().split("\\.")[0]); + }else { + idx=Integer.parseInt(idxObj.toString()); + } + idx=idx>=0?idx:0; + idx=idx==0?idx:idx-1; + } + String sourceStr=ExcelParamUtil.getParamContent(objects[1],"string").toString(); + String searchWord=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + int findIdx=sourceStr.indexOf(searchWord,idx); + findIdx=findIdx<0?0:findIdx+1; + return new DataType(DataType.NUMBER,findIdx); + } + + /** + * 替换字符函数 + * 第一个参数是源字符串 + * 第二个参数是替换开始位置,以0开始 + * 第三个参数是替换字符的长度,从替换位置开始到结束的字符,为需要替换的字符串 + * 第四个参数作为替换字符 + * @param objects + * @return + */ + @Override + public DataType replace(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class,Integer.class,String.class}; + IgnoreParamFilter.commonFilter("REPLACE",4,4,typeObjects,objects); + String sourceStr=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + Double ridxD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"string").toString()); + int repIdx=ridxD.intValue(); + + Double repD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[2],"string").toString()); + int repLenth=repD.intValue(); + + + String repWord=ExcelParamUtil.getParamContent(objects[3],"string").toString(); + int replaceLength=(repIdx-1)+repLenth; + if(replaceLength>sourceStr.length()){ +// throw new RunTimeException(errorJson.getString("msg")); + logger.info("REPLACE函数替换位置超过了字符长度"); + replaceLength=sourceStr.length(); + } + String cutStr=sourceStr.substring(repIdx-1,replaceLength); + sourceStr=sourceStr.replaceFirst(cutStr,repWord); + result=sourceStr; + return new DataType(DataType.STRING,result); + } + + /** + * 参数重复叠加函数 + * 第一个参数为源字符 + * 第二个为叠加次数 + * @param objects + * @return + */ + @Override + public DataType repeat(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class}; + IgnoreParamFilter.commonFilter("REPEAT",2,2,typeObjects,objects); + String str=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + Double repeatD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"string").toString()); + int repeat=repeatD.intValue(); + repeat=repeat>=1?repeat:1; + StringBuffer sbf=new StringBuffer(); + sbf.append(str); + for(int i=1;i=0?sourceLength:0; + String fillStr=ExcelParamUtil.getParamContent(objects[2],"string").toString(); + String fillPosition="RIGHT"; + if(objects.length==4){ + fillPosition=ExcelParamUtil.getParamContent(objects[3],"string").toString(); + Arrays.sort(fillPositonArray); + if(Arrays.binarySearch(fillPositonArray,fillPosition)<0){ + String func="TEXT"; + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + throw new RuntimeException(func+"函数第四个参数值不正确"); + } + } + if(sourceStr.length() chars=new ArrayList<>(); + sourceStr=ExcelParamUtil.appendString(fillStr,sourceStr,sourceLength,fillPosition); + } + result=sourceStr; + return new DataType(DataType.STRING,result); + } + + + + /** + * 去首尾空格 + * @param objects + * @return + */ + @Override + public DataType trim(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class}; + IgnoreParamFilter.commonFilter("TRIM",1,1,typeObjects,objects); + + String sourceStr=ExcelParamUtil.getParamContent(objects[0],"string").toString().trim(); + result=sourceStr; + return new DataType(DataType.STRING,result); + } + /** + * 字符左截取函数 + * 返回从左边开始到指定位置的字符串 + * 第一个参数是源字符串 + * 第二个参数是截取长度 + * @param objects + * @return + */ + @Override + public DataType left(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class}; + IgnoreParamFilter.commonFilter("LEFT",2,2,typeObjects,objects); + String sourceStr=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + Double cutIdxD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"string").toString()); + int cutIdx=cutIdxD.intValue(); + cutIdx=cutIdx>=0?cutIdx:1; + if(cutIdx>sourceStr.length()){ + cutIdx=sourceStr.length(); + } + sourceStr=sourceStr.substring(0,cutIdx); + result=sourceStr; + return new DataType(DataType.STRING,result); + } + + /** + * 字符右截取函数 + * 返回从右边开始到指定位置的字符串 + * 第一个参数是源字符串 + * 第二个参数是截取长度 + * @param objects + * @return + */ + @Override + public DataType right(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class}; + IgnoreParamFilter.commonFilter("RIGHT",2,2,typeObjects,objects); + String sourceStr=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + Double cutIdxD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"string").toString()); + int cutIdx=cutIdxD.intValue(); + cutIdx=cutIdx>=0?cutIdx:1; + if(cutIdx>sourceStr.length()){ + cutIdx=sourceStr.length(); + } + sourceStr=sourceStr.substring(sourceStr.length()-cutIdx); + result=sourceStr; + return new DataType(DataType.STRING,result); + } + + /** + * 字符自由截取函数 + * 第一个参数是源字符串 + * 第二个参数是截取开始位置 + * 第三个参数是截取结束位置 + * @param objects + * @return + */ + @Override + public DataType mid(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class,Integer.class}; + IgnoreParamFilter.commonFilter("MID",3,3,typeObjects,objects); + String sourceStr=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + if(null==sourceStr||sourceStr.trim().equals("")){ + return new DataType(DataType.STRING,""); + } + Double cutidxD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"string").toString()); + int cutIdx=cutidxD.intValue(); + cutIdx=cutIdx>0?cutIdx:1; + Double cutStrLenD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[2],"string").toString()); + int cutStrLen=cutStrLenD.intValue(); + cutStrLen=cutStrLen>0?cutStrLen:1; + if((cutIdx-1+cutStrLen)>sourceStr.length()){ + sourceStr=sourceStr.substring(cutIdx-1,sourceStr.length()); + }else { + sourceStr=sourceStr.substring(cutIdx-1,(cutIdx-1)+cutStrLen); + } + + result=sourceStr; + return new DataType(DataType.STRING,result); + } + + @Override + public DataType score(Object... objs) { + Object result; + DataType fraction=(DataType)objs[0]; + result=fraction.getScore(); + if(result==null){ + result=0; + } + return new DataType(DataType.NUMBER,result); + } + + @Override + public DataType idCard(Object... objects) { + Object result=""; +// IgnoreParamFilter.checkValiIdCard("IDCARD",objects); + String operType=ExcelParamUtil.getParamContent(objects[1],"string").toString(); + String idCard=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + RegularUtil.validateIDCard(idCard); + if(idCard.length()!=18&&idCard.length()!=15){ + Integer number=IgnoreParamFilter.getSetFuncNumber("IDCARD"); + throw new RuntimeException("只能计算中国大陆的身份证"); + } + DataType exeResult=new DataType(); + if(operType.equalsIgnoreCase("BD")){ + exeResult=bd(idCard); + }else if(operType.equalsIgnoreCase("NA")){ + exeResult=nativePlace(idCard); + }else if(operType.equalsIgnoreCase("AGE")){ + exeResult=age(idCard); + }else if(operType.equalsIgnoreCase("GENDER")){ + exeResult=sex(idCard); + } + return exeResult; + } + + @Override + public DataType sex(String IDCard){ + String sex =""; + //15位身份证号 + if (IDCard.length() == 15){ + if (Integer.parseInt(IDCard.substring(14, 15)) % 2 == 0) { + sex = "女"; + } else { + sex = "男"; + } + //18位身份证号 + }else if(IDCard.length() == 18){ + // 判断性别 + if (Integer.parseInt(IDCard.substring(16).substring(0, 1)) % 2 == 0) { + sex = "女"; + } else { + sex = "男"; + } + } + logger.info(sex); + return new DataType(DataType.STRING,sex); + } + + @Override + public DataType nativePlace(String idCard){ + int nativePlaceCode=Integer.parseInt(idCard.substring(0, 6)); + String nativePlace= NativePlace.getNativePlace(nativePlaceCode); + logger.info("您所在的地区为:\n" + nativePlace); + return new DataType(DataType.STRING,nativePlace); + } + + @Override + public DataType age(String idCard){ + Object age=0; + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + DataType datatype=bd(idCard); + String birthdayStr=datatype.getContent()!=null?datatype.getContent()+"":""; + try { + if(StringUtils.isNotEmpty(birthdayStr)){ + String today=formatter.format(new Date()); + Double ageN= DateTimeServiceImpl.getBetween(birthdayStr,today,"Y");//使用日期函数获取日期间隔年数 + DataType dataType=mathFuncsService.roundDown(ageN);//做一次向下取整 + if(dataType!=null && dataType.getContent()!=null){ + age=dataType.getContent(); + } + logger.info("年龄:"+age); + } + } catch (ParseException e) { + logger.error("err",e); + } + return new DataType(DataType.NUMBER,age); + } + + @Override + public DataType bd(String idCard){ + String result=null; + Calendar c=Calendar.getInstance(); + Integer number=IgnoreParamFilter.getSetFuncNumber("IDCARD"); + switch(idCard.length()) { + case 18: + case 15: + String year = idCard.substring(6, 10); + if(Integer.decode(year) <1900 && Integer.decode(year)>c.get(Calendar.YEAR)){ + + JSONObject errorJson=ErrorUtil.buildError("IDCARD",number,number,"IDCARD函数身份证字符不正确"); + throw new RuntimeException(errorJson.getString("msg")); + } + + String month = idCard.substring(10,12); + if(Integer.parseInt(month)<1 && Integer.parseInt(month)>12){ + JSONObject errorJson= ErrorUtil.buildError("IDCARD",number,number,"IDCARD函数身份证字符不正确"); + throw new RuntimeException(errorJson.getString("msg")); + } + + String day = idCard.substring(12,14); + c.set(Integer.parseInt(year) ,Integer.parseInt(month), 0); + if(Integer.parseInt(day)>c.get(Calendar.DAY_OF_MONTH)){ + JSONObject errorJson=ErrorUtil.buildError("IDCARD",number,number,"IDCARD函数身份证字符不正确"); + throw new RuntimeException(errorJson.getString("msg")); + } + + String birth=year+"-"+month+"-"+day; + logger.info("生日为:"+birth); + result=birth; + break; + + } + return new DataType(DataType.STRING,result); + } + + @Override + public DataType addressAnalysis(Object obj1, Object obj2) { + Integer number=IgnoreParamFilter.getSetFuncNumber(FuncNames.ADDRESS.getName()); + + String addressType=ExcelParamUtil.checkParamType(obj1); + String levelType=ExcelParamUtil.checkParamType(obj2); + if(!addressType.equalsIgnoreCase("string") || !levelType.equalsIgnoreCase("string")){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.ADDRESS.toString(),number,number,"地址解析函数的参数只允许字符类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + String address=""; + String level=""; + if(obj1 instanceof DataType){ + address=ExcelParamUtil.getParamContent(obj1).toString(); + }else{ + address=obj1.toString(); + } + + if(obj2 instanceof DataType){ + level=ExcelParamUtil.getParamContent(obj2).toString(); + }else { + level=obj2.toString(); + } + + Map placeMap=NativePlace.getAddressInfo(address); + String result=""; + switch (level){ + case PROVINCE: + result=placeMap.get(PROVINCE); + break; + case CITY: + result=placeMap.get(CITY); + break; + case TOWN: + result=placeMap.get(TOWN); + break; + case ADDR: + result=placeMap.get(ADDR); + default: + JSONObject errorJson=ErrorUtil.buildError(FuncNames.ADDRESS.toString(),number,number,"行政区块只支持省、市、区县"); + throw new RuntimeException(errorJson.getString("msg")); + + } + return new DataType(DataType.STRING,result); + } + + @Override + public DataType subString(Object... objects) { + String newString=""; + if(objects!=null && objects.length==3){ + String sourceString=null; + BigDecimal subIdx=null; + BigDecimal subEndIdx=null; + if(objects[0] instanceof DataType){ + sourceString=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + }else{ + sourceString=objects[0]+""; + } + //如果字符为空,直接返回 + if(sourceString==null || sourceString.length()==0){ + return new DataType(DataType.STRING,newString); + } + if(objects[1] instanceof DataType){ + subIdx=new BigDecimal(ExcelParamUtil.getParamContent(objects[1],"").toString()); + }else{ + subIdx=new BigDecimal(objects[1]+""); + } + + if(objects[2] instanceof DataType){ + subEndIdx=new BigDecimal(ExcelParamUtil.getParamContent(objects[2],"").toString()); + }else{ + subEndIdx=new BigDecimal(objects[2]+""); + } + + //如果截取位置小于0或者大于字符长度,直接返回 + if(subIdx.intValue()<0 || subIdx.intValue()>sourceString.length()){ + return new DataType(DataType.STRING,newString); + } + //如果截取位置小于0或者大于字符长度,直接返回 + if(subEndIdx.intValue()<0 || subEndIdx.intValue()>sourceString.length()){ + return new DataType(DataType.STRING,newString); + } + newString=sourceString.substring(subIdx.intValue()-1,subEndIdx.intValue()); + } + return new DataType(DataType.STRING,newString); + } + + @Override + public DataType substitue(Object... objects) { + String newString=""; + if(objects!=null && objects.length==3){ + String sourceString=null; + String replaceChar=null; + String newChar=null; + if(objects[0] instanceof DataType){ + sourceString=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + }else{ + sourceString=objects[0]+""; + } + + if(objects[1] instanceof DataType){ + replaceChar=ExcelParamUtil.getParamContent(objects[1],"string").toString(); + }else{ + replaceChar=objects[1]+""; + } + + if(objects[2] instanceof DataType){ + newChar=ExcelParamUtil.getParamContent(objects[2],"string").toString(); + }else{ + newChar=objects[2]+""; + } + + if(sourceString==null || replaceChar.length()>sourceString.length() || newChar.length()>sourceString.length()){ + return new DataType(DataType.STRING,newString); + } + newString=sourceString.replaceAll(replaceChar,newChar); + } + return new DataType(DataType.STRING,newString); + } + + @Override + public DataType extract(Object... objects) { + return null; + } + + @Override + public DataType lower(Object... objects) { + String sourceString=""; + if(objects!=null){ + if(objects[0]!=null){ + if(objects[0] instanceof DataType){ + sourceString=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + }else { + sourceString=objects[0]+""; + } + } + } + return new DataType(DataType.STRING,sourceString.toLowerCase()); + } + + @Override + public DataType upper(Object... objects) { + String sourceString=""; + if(objects!=null){ + if(objects[0]!=null){ + if(objects[0] instanceof DataType){ + sourceString=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + }else { + sourceString=objects[0]+""; + } + } + } + return new DataType(DataType.STRING,sourceString.toUpperCase()); + } + + @Override + public DataType exact(Object... objects) { + boolean eq=false; + if(objects!=null && objects.length==2){ + String sourceOne=""; + String sourceTwo=""; + if(objects[0] instanceof DataType){ + sourceOne=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + }else{ + sourceOne=objects[0]+""; + } + if(objects[1] instanceof DataType){ + sourceTwo=ExcelParamUtil.getParamContent(objects[1],"string").toString(); + }else{ + sourceTwo=objects[1]+""; + } + if(sourceOne!=null && sourceTwo!=null){ + eq=sourceOne.equals(sourceTwo); + return new DataType(DataType.BOOL,eq); + }else if(sourceOne == null && sourceTwo == null){ + return new DataType(DataType.BOOL,true); + }else if(sourceOne == null && sourceTwo != null){ + return new DataType(DataType.BOOL,false); + }else if(sourceOne != null && sourceTwo == null){ + return new DataType(DataType.BOOL,false); + } + + } + return new DataType(DataType.BOOL,eq); + } + + @Override + public DataType isString(Object... objects) { + Object object=objects[0]; + String fieldType=""; + DataType resultDataType; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); + }else { + fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); + } + if(fieldType.equalsIgnoreCase("string")){ + resultDataType=new DataType(DataType.BOOL,true); + }else{ + resultDataType=new DataType(DataType.BOOL,false); + } + return resultDataType; + } + + @Override + public DataType isJson(Object... objects) { + Object object=objects[0]; + String fieldType=""; + DataType resultDataType; + Object content=null; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + content=dataType.getContent(); + fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); + }else { + fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); + content=object; + } + if(fieldType.equalsIgnoreCase("string")){ + if(content!=null){ + try { + logger.info("isJson函数的JSON字符转换:"+content+""); + JSON.parseObject(content+""); + resultDataType=new DataType(DataType.BOOL,true); + } catch (Exception e) { + logger.info("err",e); + logger.info("不是正常的JSON字符"); + resultDataType=new DataType(DataType.BOOL,false); + } + }else{ + resultDataType=new DataType(DataType.BOOL,false); + } + }else{ + resultDataType=new DataType(DataType.BOOL,false); + } + return resultDataType; + } + + @Override + public DataType getJSONValue(Object... objects) { + Object object=objects[0]; + Object objectKeyObj=objects[1]; + String fieldType=""; + DataType resultDataType; + Object content=null; + Object objectKey=null; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + content=dataType.getContent(); + fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); + }else { + fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); + content=object; + } + + if(objectKeyObj instanceof DataType){ + DataType dataType=(DataType)objectKeyObj; + objectKey=dataType.getContent(); + }else{ + objectKey=objectKeyObj; + } + + if(fieldType.equalsIgnoreCase("string")){ + if(content!=null){ + try { + logger.info("isJson函数的JSON字符转换:"+content+""); + JSONObject jsonObject=JSON.parseObject(content+""); + Object jsonValue=jsonObject.get(objectKey+""); + resultDataType=new DataType(DataType.STRING,jsonValue==null?"":jsonValue.toString()); + } catch (Exception e) { + logger.info("err",e); + logger.info("不是正常的JSON字符"); + resultDataType=new DataType(DataType.STRING,""); + } + }else{ + resultDataType=new DataType(DataType.STRING,""); + } + }else{ + resultDataType=new DataType(DataType.STRING,""); + } + return resultDataType; + } +} diff --git a/src/com/engine/salary/formlua/func/string/StringFormulaServiceTestImpl.java b/src/com/engine/salary/formlua/func/string/StringFormulaServiceTestImpl.java new file mode 100644 index 000000000..2e2a1ed7b --- /dev/null +++ b/src/com/engine/salary/formlua/func/string/StringFormulaServiceTestImpl.java @@ -0,0 +1,555 @@ +package com.engine.salary.formlua.func.string; + +import com.alibaba.fastjson.JSONObject; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.FuncNames; +import com.weaver.excel.formula.func.math.MathFuncsService; +import com.weaver.excel.formula.util.ErrorUtil; +import com.weaver.excel.formula.util.ExcelParamUtil; +import com.weaver.excel.formula.util.IgnoreParamFilter; +import com.weaver.excel.formula.util.RegularUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +@Service("stringFormulaServiceTest") +public class StringFormulaServiceTestImpl implements StringFormulaService { + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final String[] fillPositonArray=new String[]{"LEFT","RIGHT"}; + private final static String PROVINCE="province"; + private final static String CITY="city"; + private final static String TOWN="town"; + private final static String ADDR="addr"; + @Autowired + MathFuncsService mathFuncsService; + @Autowired + StringFormulaService stringFormulaService; + @Override + public DataType concatString(Object... objs) { + List newObjs=new ArrayList<>(); + for (int i=0;i0){ + for(Object object:newObjs){ + newString.append(ExcelParamUtil.getParamContent(object,"string")); + } + } + return new DataType(DataType.STRING,newString.toString(), ComponentType.Text.toString()); + } + + @Override + public DataType text(Object... objs) { + String func="TEXT"; + Integer number=IgnoreParamFilter.getSetFuncNumber(func); + if(null==objs||objs.length>1){ + JSONObject errorJson= ErrorUtil.buildError(func,0,number,func+"函数参数只允许一个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + Object obj=objs[0]; + if(null==obj){ + JSONObject errorJson= ErrorUtil.buildError(func,0,number,func+"函数参数为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + Object result; + if(obj instanceof DataType){ + DataType dataType=(DataType)obj; + result=ExcelParamUtil.getParamContent(dataType,"string").toString(); + }else { + result=obj.toString(); + } + + return new DataType(DataType.STRING,result,ComponentType.Text.toString()); + } + + @Override + public DataType value(Object... objs) { + Object txt=objs[0]; + Object result; + Class[] typeObjects=new Class[]{}; + + IgnoreParamFilter.commonFilter("VALUE",1,1,typeObjects,objs); + String regEx="[^0-9]"; + Pattern p = Pattern.compile(regEx); + String paramContent=""; + if(ExcelParamUtil.getParamContent(txt,"string")!=null){ + paramContent=ExcelParamUtil.getParamContent(txt,"string")!=null?ExcelParamUtil.getParamContent(txt,"string").toString():""; + } + if(!RegularUtil.isNumber(paramContent)){ + paramContent="0"; + } + Matcher m = p.matcher(paramContent); + String numberStr=m.replaceAll("").trim(); + if(!numberStr.equals("")){ + if(numberStr.length()>19){ + numberStr=numberStr.substring(0,19); + } + Long txtTint=Long.parseLong(numberStr); + result=txtTint; + }else { + result=0; + } + return new DataType(DataType.NUMBER,result,ComponentType.Text.toString()); + } + + @Override + public DataType len(Object... txt) { + Class[] typeObjects=new Class[]{String.class}; + IgnoreParamFilter.commonFilter("LEN",1,1,typeObjects,txt); + int length=ExcelParamUtil.getParamContent(txt[0],"string").toString().length(); + + return new DataType(DataType.NUMBER,length,ComponentType.Text.toString()); + } + + @Override + public DataType search(Object... objects) { + Class[] typeObjects=new Class[]{String.class,String.class,Integer.class}; + int idx=0; + IgnoreParamFilter.commonFilter("SEARCH",2,3,typeObjects,objects); + return new DataType(DataType.NUMBER,0,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType replace(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class,Integer.class,String.class}; + IgnoreParamFilter.commonFilter("REPLACE",4,4,typeObjects,objects); + return new DataType(DataType.STRING,"泛微网络",ComponentType.Text.toString()); + } + + @Override + public DataType repeat(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class}; + IgnoreParamFilter.commonFilter("REPEAT",2,2,typeObjects,objects); + String str=ExcelParamUtil.getParamContent(objects[0],"string").toString(); + Double repeatD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"string").toString()); + int repeat=repeatD.intValue(); + StringBuffer sbf=new StringBuffer(); + for(int i=0;i chars=new ArrayList<>(); + sourceStr=ExcelParamUtil.appendString(fillStr,sourceStr,sourceLength,fillPosition); + } + result=sourceStr; + return new DataType(DataType.STRING,result,ComponentType.Text.toString()); + } + + @Override + public DataType trim(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class}; + IgnoreParamFilter.commonFilter("TRIM",1,1,typeObjects,objects); + + String sourceStr=ExcelParamUtil.getParamContent(objects[0],"string").toString().trim(); + result=sourceStr; + return new DataType(DataType.STRING,result,ComponentType.Text.toString()); + } + + @Override + public DataType left(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class}; + IgnoreParamFilter.commonFilter("LEFT",2,2,typeObjects,objects); + result="泛微"; + return new DataType(DataType.STRING,result,ComponentType.Text.toString()); + } + + @Override + public DataType right(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class}; + IgnoreParamFilter.commonFilter("RIGHT",2,2,typeObjects,objects); + result="泛微"; + return new DataType(DataType.STRING,result,ComponentType.Text.toString()); + } + + @Override + public DataType mid(Object... objects) { + Object result; + Class[] typeObjects=new Class[]{String.class,Integer.class,Integer.class}; + IgnoreParamFilter.commonFilter("MID",3,3,typeObjects,objects); + result="泛微云"; + return new DataType(DataType.STRING,result,ComponentType.Text.toString()); + } + + @Override + public DataType score(Object... objs) { + Object result; + IgnoreParamFilter.checkFraction("SCORE",objs); + DataType fraction=(DataType)objs[0]; + result=fraction.getScore(); + if(result==null){ + result=0; + } + return new DataType(DataType.NUMBER,result,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType idCard(Object... objects) { + Integer number=IgnoreParamFilter.getSetFuncNumber(FuncNames.IDCARD.getName()); + DataType result=new DataType(); + IgnoreParamFilter.checkValiIdCard("IDCARD",objects); + if(objects[0] instanceof DataType){ + DataType dataType=(DataType) objects[0]; + dataType.setContent("43070319900202665X"); + dataType.setText("43070319900202665X"); + } + RegularUtil.validateIDCard(ExcelParamUtil.getParamContent(objects[0],"string").toString()); + String operType=objects[1].toString(); + String idCard=objects[0].toString(); + if(operType.equalsIgnoreCase("BD")){ + result=bd(idCard); + }else if(operType.equalsIgnoreCase("NA")){ + result=nativePlace(idCard); + }else if(operType.equalsIgnoreCase("AGE")){ + result=age(idCard); + }else if(operType.equalsIgnoreCase("GENDER")){ + result=sex(idCard); + }else{ + JSONObject errorJson=ErrorUtil.buildError("IDCARD",number,number,"IDCARD函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + return result; + } + + + @Override + public DataType sex(String idCard) { + return new DataType(DataType.STRING,"男",ComponentType.Text.toString()); + } + + @Override + public DataType nativePlace(String idCard) { + return new DataType(DataType.STRING,"上海市闵行区浦江",ComponentType.Text.toString()); + } + + @Override + public DataType age(String idCard) { + return new DataType(DataType.NUMBER,18,ComponentType.NumberComponent.toString()); + } + + @Override + public DataType bd(String idCard) { + return new DataType(DataType.STRING,"2020-11-11",ComponentType.Text.toString()); + } + + @Override + public DataType addressAnalysis(Object obj1, Object obj2) { + Integer number=IgnoreParamFilter.getSetFuncNumber(FuncNames.ADDRESS.getName()); + String addressType=ExcelParamUtil.checkParamType(obj1); + String levelType=ExcelParamUtil.checkParamType(obj2); + if(!addressType.equalsIgnoreCase("string") || !levelType.equalsIgnoreCase("string")){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.ADDRESS.toString(),number,number,"地址解析函数的参数只允许字符类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + String level=""; + if(obj2 instanceof DataType){ + level=ExcelParamUtil.getParamContent(obj2,"").toString(); + }else { + level=obj2.toString(); + } + + String result=""; + switch (level){ + case PROVINCE: + break; + case CITY: + break; + case TOWN: + break; + case ADDR: + break; + default: + JSONObject errorJson=ErrorUtil.buildError(FuncNames.ADDRESS.toString(),number,number,"行政区块只支持省、市、区县"); + throw new RuntimeException(errorJson.getString("msg")); + + } + + return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); + } + + @Override + public DataType subString(Object... objects) { + if(objects==null || objects.length!=3){ + throw new RuntimeException("字符截取函数只允许3个参数:源字符、截取开始位置、截取结束位置"); + } + List paramTypeList=new ArrayList<>(); + paramTypeList.add(DataType.STRING); + paramTypeList.add(DataType.NUMBER); + paramTypeList.add(DataType.NUMBER); + List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); + if(errorIdxList!=null && errorIdxList.size()>0){ + String errorMsg=""; + switch (errorIdxList.get(0)){ + case 0: + errorMsg="【SUBSTRING 字符截取函数】的第一个参数只能是字符串"; + break; + case 1: + errorMsg="【SUBSTRING 字符截取函数】的第二个参数只能是数字"; + break; + case 2: + errorMsg="【SUBSTRING 字符截取函数】的第三个参数只能是数字"; + break; + default: + errorMsg="【SUBSTRING 字符截取函数】的参数异常"; + break; + } + throw new RuntimeException(errorMsg); + } + return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); + } + + @Override + public DataType substitue(Object... objects) { + if(objects==null || objects.length!=3){ + throw new RuntimeException("字符查找替换函数只允许3个参数:源字符、被替换字符、新字符"); + } + List paramTypeList=new ArrayList<>(); + paramTypeList.add(DataType.STRING); + paramTypeList.add(DataType.STRING); + paramTypeList.add(DataType.STRING); + List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); + if(errorIdxList!=null && errorIdxList.size()>0){ + String errorMsg=""; + switch (errorIdxList.get(0)){ + case 0: + errorMsg="【SUBSTITUE 字符查找替换函数】的第一个参数只能是字符串"; + break; + case 1: + errorMsg="【SUBSTITUE 字符查找替换函数】的第二个参数只能是字符串"; + break; + case 2: + errorMsg="【SUBSTITUE 字符查找替换函数】的第三个参数只能是字符串"; + break; + default: + errorMsg="【SUBSTITUE 字符查找替换函数】的参数异常"; + break; + } + throw new RuntimeException(errorMsg); + } + + return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); + } + + @Override + public DataType extract(Object... objects) { + if(objects==null || objects.length!=2){ + throw new RuntimeException("字符提取函数只允许2个参数:源字符、提取类型"); + } + List paramTypeList=new ArrayList<>(); + paramTypeList.add(DataType.STRING); + paramTypeList.add(DataType.STRING); + List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); + if(errorIdxList!=null && errorIdxList.size()>0){ + String errorMsg=""; + switch (errorIdxList.get(0)){ + case 0: + errorMsg="【EXTRACT 字符提取函数】的第一个参数只能是字符串"; + break; + case 1: + errorMsg="【EXTRACT 字符提取函数】的第二个参数只能是字符串"; + break; + default: + errorMsg="【EXTRACT 字符提取函数】的参数异常"; + break; + } + throw new RuntimeException(errorMsg); + } + return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); + } + + @Override + public DataType lower(Object... objects) { + if(objects==null || objects.length!=1){ + throw new RuntimeException("字符小写函数只允许1个参数:源字符"); + } + List paramTypeList=new ArrayList<>(); + paramTypeList.add(DataType.STRING); + List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); + if(errorIdxList!=null && errorIdxList.size()>0){ + throw new RuntimeException("【LOWER 字符小写函数】的参数只能是字符串"); + } + return new DataType(DataType.STRING,"abc",ComponentType.Text.toString()); + } + + @Override + public DataType upper(Object... objects) { + if(objects==null || objects.length!=1){ + throw new RuntimeException("字符大写函数只允许1个参数:源字符"); + } + List paramTypeList=new ArrayList<>(); + paramTypeList.add(DataType.STRING); + List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); + if(errorIdxList!=null && errorIdxList.size()>0){ + throw new RuntimeException("【UPPER 字符大写函数】的参数只能是字符串"); + } + return new DataType(DataType.STRING,"ABC",ComponentType.Text.toString()); + } + + @Override + public DataType exact(Object... objects) { + if(objects==null || objects.length!=2){ + throw new RuntimeException("字符比较函数只允许2个参数:字符、字符"); + } + List paramTypeList=new ArrayList<>(); + paramTypeList.add(DataType.STRING); + paramTypeList.add(DataType.STRING); + List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); + if(errorIdxList!=null && errorIdxList.size()>0){ + String errorMsg=""; + switch (errorIdxList.get(0)){ + case 0: + errorMsg="【EXACT 字符比较函数】的第一个参数只能是字符串"; + break; + case 1: + errorMsg="【EXACT 字符比较函数】的第二个参数只能是字符串"; + break; + default: + errorMsg="【EXTRACT 字符比较函数】的参数异常"; + break; + } + throw new RuntimeException(errorMsg); + } + return new DataType(DataType.BOOL,true); + } + + @Override + public DataType isString(Object... objects) { + if(objects==null){ + throw new RuntimeException("ISSTRING函数的参数不能为空"); + } + if(objects.length!=1){ + throw new RuntimeException("ISSTRING函数只能有一个参数"); + } + Object object=objects[0]; + String fieldType=""; + DataType resultDataType; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); + }else { + fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); + } + if(fieldType.equalsIgnoreCase("string")){ + resultDataType=new DataType(DataType.BOOL,true); + }else{ + resultDataType=new DataType(DataType.BOOL,false); + } + return resultDataType; + } + + @Override + public DataType isJson(Object... objects) { + Object object=objects[0]; + String fieldType=""; + DataType resultDataType; + Object content=null; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + content=dataType.getContent(); + fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); + }else { + fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); + content=object; + } + if(fieldType.equalsIgnoreCase("string")){ + if(content!=null){ + try { + logger.info("isJson函数的JSON字符转换:"+content+""); + resultDataType=new DataType(DataType.BOOL,true); + } catch (Exception e) { + logger.info("err",e); + logger.info("不是正常的JSON字符"); + resultDataType=new DataType(DataType.BOOL,false); + } + }else{ + resultDataType=new DataType(DataType.BOOL,false); + } + }else{ + resultDataType=new DataType(DataType.BOOL,false); + } + return resultDataType; + } + + @Override + public DataType getJSONValue(Object... objects) { + Object object=objects[0]; + String fieldType=""; + DataType resultDataType; + Object content=null; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + content=dataType.getContent(); + fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); + }else { + fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); + content=object; + } + if(fieldType.equalsIgnoreCase("string")){ + if(content!=null){ + try { + logger.info("isJson函数的JSON字符转换:"+content+""); + resultDataType=new DataType(DataType.STRING,"JSON字符"); + } catch (Exception e) { + logger.info("err",e); + logger.info("不是正常的JSON字符"); + throw new RuntimeException("GETJSONVALUE函数只能接收JSON字符"); + } + }else{ + throw new RuntimeException("GETJSONVALUE函数只能接收JSON字符"); + } + }else{ + throw new RuntimeException("GETJSONVALUE函数只能接收JSON字符"); + } + return resultDataType; + } +} diff --git a/src/com/engine/salary/formlua/util/CompareUtil.java b/src/com/engine/salary/formlua/util/CompareUtil.java new file mode 100644 index 000000000..570e1e998 --- /dev/null +++ b/src/com/engine/salary/formlua/util/CompareUtil.java @@ -0,0 +1,24 @@ +package com.engine.salary.formlua.util; + + +public class CompareUtil { + public static String[] genArray(Object obj, String type) { + String[] resultArray = new String[]{}; + if (obj.getClass().isArray()) { + Object[] op1Array = (Object[]) obj; + resultArray = new String[op1Array.length]; + for (int i = 0; i < op1Array.length; i++) { + if (ExcelParamUtil.getParamContent(op1Array[i], type) != null) { + String p = ExcelParamUtil.getParamContent(op1Array[i], type).toString(); + resultArray[i] = p; + } + } + } else { + if (ExcelParamUtil.getParamContent(obj, type) != null) { + String opStr = ExcelParamUtil.getParamContent(obj, type).toString(); + resultArray = opStr.split(","); + } + } + return resultArray; + } +} diff --git a/src/com/engine/salary/formlua/util/DateUtil.java b/src/com/engine/salary/formlua/util/DateUtil.java new file mode 100644 index 000000000..9abbdeb30 --- /dev/null +++ b/src/com/engine/salary/formlua/util/DateUtil.java @@ -0,0 +1,212 @@ +package com.engine.salary.formlua.util; + +import com.weaver.excel.formula.entity.parameter.DataType; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; +import org.joda.time.DateTime; +import org.joda.time.Days; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + + +public class DateUtil { + protected static final Logger logger = LoggerFactory.getLogger(DateUtil.class); + private static String[] parsePatterns = {"yyyy-MM-dd","yyyy年MM月dd日", + "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd", + "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyyMMdd","yy-MM","yy/MM"}; + private static String[] dateComponentKeyList={"DateComponent","DateInterval","TimeComponent"}; + public static void main(String args[]){ + } + /** + * 构建日期对象 + * @param dateChar + * @return + */ + public static Date buildDateByDateChar(String dateChar){ + + Date resultDate=null; + if(StringUtils.isEmpty(dateChar)){ + return resultDate; + } + String formatString=buildFormat(dateChar); + if(StringUtils.isEmpty(formatString)){ + return resultDate; + } + SimpleDateFormat simpleDateFormat=new SimpleDateFormat(formatString); + simpleDateFormat.setLenient(false); + try { + resultDate=simpleDateFormat.parse(dateChar); + } catch (ParseException e) { + logger.error("err",e); + } + return resultDate; + } + + /** + * 判断是否是日期控件 + * @param data + * @return + */ + public static boolean isDateComponent(Object data){ + if(data instanceof DataType){ + DataType dataType=(DataType)data; + if(dataType.getComponentKey()!=null){ + for (String dateKey:dateComponentKeyList){ + if(dateKey.equalsIgnoreCase(dataType.getComponentKey())){ + return true; + } + } + } + }else if(data!=null && isValidDate(data+"")){ + return true; + } + + return false; + } + + + public static boolean isValidDate(String str) { + boolean convertSuccess=false; + for(String s:parsePatterns){ + convertSuccess=parseDateString(str,s); + if(convertSuccess){ + break; + } + } + return convertSuccess; + } + + public static boolean parseDateString(String dateString,String formatString){ + boolean convertSuccess=true; + SimpleDateFormat format = new SimpleDateFormat(formatString); + try { + format.setLenient(false); + format.parse(dateString); + logger.info(dateString); + } catch (ParseException e) { +// logger.error("err",e); + convertSuccess=false; + } + return convertSuccess; + } + /** + * 判断日期时间的格式 + * @param dateTimeStr + * @return + */ + public static String buildFormat(String dateTimeStr,String type){ + String fmateStr=null; + int len=dateTimeStr.length(); + switch (type){ + case "Y": + fmateStr="yyyy"; + break; + case "M": + fmateStr="yyyy-MM"; + break; + case "D": + fmateStr="yyyy-MM-dd"; + break; + case "H": + fmateStr="yyyy-MM-dd HH"; + break; + case "I": + fmateStr="yyyy-MM-dd HH:mm"; + break; + case "S": + fmateStr="yyyy-MM-dd HH:mm:ss"; + break; + } + return fmateStr; + } + + public static String buildFormat(String dateTimeStr){ + String fmateStr=null; + int len=dateTimeStr.length(); + switch (len){ + case 4: + if(dateTimeStr.indexOf(":")<0){ + fmateStr="yyyy"; + }else if(dateTimeStr.indexOf("-")<0){ + fmateStr="H:mm"; + } + break; + case 5: + if(dateTimeStr.indexOf(":")<0){ + fmateStr="yy-MM"; + }else if(dateTimeStr.indexOf("-")<0){ + fmateStr="HH:mm"; + } + break; + case 7: + if(dateTimeStr.indexOf(":")<0){ + fmateStr="yyyy-MM"; + }else if(dateTimeStr.indexOf("-")<0){ + fmateStr="H:mm:ss"; + } + break; + case 8: + fmateStr="HH:mm:ss"; + break; + case 9: + fmateStr="yyyy-MM-dd"; + break; + case 10: + fmateStr="yyyy-MM-dd"; + break; + case 13: + fmateStr="yyyy-MM-dd HH"; + break; + case 16: + fmateStr="yyyy-MM-dd HH:mm"; + break; + case 19: + fmateStr="yyyy-MM-dd HH:mm:ss"; + break; + default: + fmateStr=""; + } + return fmateStr; + } + + /** + * 判断参数类型,并且获取content属性的值,或者String类型直接返回 + * @param obj + * @return + */ + public static String getContent(Object obj, SimpleDateFormat formatter){ + String date=""; + if(obj instanceof String || obj instanceof Character){ + date=obj.toString(); + }else if(obj instanceof Date){ + date=formatter.format(obj); + }else{ + DataType dataType=(DataType)obj; + Object content=dataType.getText(); + if(null!=content){ + date=content.toString(); + }else { + date = dataType.getContent() == null ? null : dataType.getContent().toString(); + } + } + return date; + } + + /** + * 计算日期间相隔天数 + * @param start + * @param end + * @return + */ + public static int daysBetween(Date start, Date end) { + if(start == null || end == null || start.getTime() >= end.getTime()) return 0; + + Date startDate = DateUtils.truncate(start, Calendar.DATE); + return Days.daysBetween(new DateTime(startDate), new DateTime(end)).getDays(); + } +} diff --git a/src/com/engine/salary/formlua/util/ErrorUtil.java b/src/com/engine/salary/formlua/util/ErrorUtil.java new file mode 100644 index 000000000..2ed8d55fd --- /dev/null +++ b/src/com/engine/salary/formlua/util/ErrorUtil.java @@ -0,0 +1,33 @@ +package com.engine.salary.formlua.util; + +import com.alibaba.fastjson.JSONObject; + + +public class ErrorUtil { + private static JSONObject errorJson=new JSONObject(); + public static JSONObject buildDataError(String func,int errorIdx,Object errorData,String msg){ + errorJson.put("msg",msg); + errorJson.put("func",func); + errorJson.put("errorIdx",errorIdx); + errorJson.put("errorData",errorData); + errorJson.put("excute",false); + return errorJson; + } + public static JSONObject buildError(String func,Integer errorIdx,Integer errorFunc,String msg){ + errorJson.put("msg",msg); + errorJson.put("func",func); + errorJson.put("errorIdx",errorIdx); + errorJson.put("errorFunc",errorFunc); + errorJson.put("excute",false); + return errorJson; + } + public static JSONObject buildError(String func,int errorIdx,int endIndex,Object errorData,String msg){ + errorJson.put("msg",msg); + errorJson.put("func",func); + errorJson.put("errorIdx",errorIdx); + errorJson.put("errorEndIdx",endIndex); + errorJson.put("errorData",errorData); + errorJson.put("excute",false); + return errorJson; + } +} diff --git a/src/com/engine/salary/formlua/util/ExcelParamUtil.java b/src/com/engine/salary/formlua/util/ExcelParamUtil.java new file mode 100644 index 000000000..10b20219c --- /dev/null +++ b/src/com/engine/salary/formlua/util/ExcelParamUtil.java @@ -0,0 +1,1104 @@ +package com.engine.salary.formlua.util; + +import com.alibaba.fastjson.JSONObject; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.weaver.common.form.component.base.Component; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.common.form.conditionrule.FixedField; +import com.weaver.common.form.metadata.ModuleSource; +import com.weaver.excel.formula.api.entity.FormulaVar; +import com.weaver.excel.formula.entity.parameter.*; +import com.weaver.excel.formula.entity.standard.execute.FixFieldType; +import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class ExcelParamUtil { + protected static final Logger logger = LoggerFactory.getLogger(ExcelParamUtil.class); + public final static String[] NUMBERFIELD=new String[]{"NumberComponent","Money","Monitor","Raty","ProgressBar", FixFieldType.Num.toString(),DataType.NUMBER}; + public final static String[] DATEFIELD=new String[]{"DateComponent","DateInterval","TimeComponent",DataType.DATE}; + public final static String[] TEXTFIELD=new String[]{"Text","TextArea","Email","Phone","Mobile","IDCard","FileComponent","SerialNumber","PositionComponent","Paragraph",FixFieldType.Text.toString(),DataType.STRING}; + public final static String[] SELECTFIELD=new String[]{"ImageComponent","RadioBox","CheckBox","Select","ComboSelect","ImageRadioBox","ImageCheckBox","TreeSelect","MatrixComponent",FixFieldType.Select.toString(),"option","employee","department","subcompany","operator",DataType.OPTION}; + public final static String[] DATASOURCEFIELD=new String[]{"Employee","Department","Mainline","Task","Document","Workflow","AgendaComponent","FormComponent","CustomerComponent","ClueComponent","Subcompany", + "OrderComponent","ContactComponent","ChanceComponent","ProductionComponent","ContractComponent","ActivityComponent","WorkreportComponent","CompetitorComponent","KpiFlowComponent","Ebuilder","QuoteComponent","AttendComponent","DataSource", + FixFieldType.Department.toString(),FixFieldType.Employee.toString()}; + + private static String[] funcArray= IllegalList.getInstance().getNameIllegalArray(); + private final static String[] NUMBERCOMPONENTS=new String[]{"NumberComponent","Money","Raty","ProgressBar","Monitor"}; + private static String[] numberTypes=new String[]{"Integer","integer","Long","Double","Float","float","int","double","long","float","bigdecimal","BigDecimal"}; + public final static String CHECKLEVEL_NULL="NULL"; + public final static String CHECKLEVEL_STRING="STRING"; + + /** + * 自定义脚本生成调用的逻辑 + * @param funcString + * @return + */ + public static String initFunc(String funcString){ + if(StringUtils.isEmpty(funcString)){ + return funcString; + } + int startIdx=funcString.indexOf("("); + int endIdx=funcString.indexOf(")"); + int funcIdx=funcString.indexOf("function"); + if(startIdx==-1 ){ + throw new RuntimeException("【语法错误】缺少左括号("); + }else if(endIdx == -1){ + throw new RuntimeException("【语法错误】缺少右括号)"); + }else if(funcIdx ==-1){ + throw new RuntimeException("【语法错误】缺少function关键字"); + } + String funcName=funcString.substring(funcIdx+8,startIdx).trim(); + String paramStr=funcString.substring(startIdx+1,endIdx); + if(paramStr.trim().equalsIgnoreCase("")){ + funcString+=funcName+"();"; + return funcString; + } + String[] paramStrArray=paramStr.split(","); + logger.info("总参数个数:"+paramStrArray.length); + String paramNames=""; + for (int i=0;i numberList=Arrays.asList(NUMBERFIELD); + List textList=Arrays.asList(TEXTFIELD); + List selectList=Arrays.asList(SELECTFIELD); + List dataSourceList=Arrays.asList(DATASOURCEFIELD); + List dateList=Arrays.asList(DATEFIELD); + if(numberList.contains(compnentKey)){ + return DataType.NUMBER; + }else if(textList.contains(compnentKey)){ + return DataType.STRING; + }else if(dateList.contains(compnentKey)){ + return DataType.STRING; + }else if(selectList.contains(compnentKey)){ + return DataType.OPTION; + }else if(dataSourceList.contains(compnentKey)){ + return DataType.OPTION; + }else { + return ""; + } + } + + public static String findDataType(String compnentKey){ + List numberList=Arrays.asList(NUMBERFIELD); + List textList=Arrays.asList(TEXTFIELD); + List selectList=Arrays.asList(SELECTFIELD); + List dataSourceList=Arrays.asList(DATASOURCEFIELD); + List dateList=Arrays.asList(DATEFIELD); + if(numberList.contains(compnentKey)){ + return DataType.NUMBER; + }else if(textList.contains(compnentKey)){ + return DataType.STRING; + }else if(dateList.contains(compnentKey)){ + return DataType.STRING; + }else if(selectList.contains(compnentKey)){ + return DataType.OPTION; + }else if(dataSourceList.contains(compnentKey)){ + return DataType.OPTION; + }else { + return DataType.STRING; + } + } + public static String findTestDataType(String compnentKey){ + List numberList=Arrays.asList(NUMBERFIELD); + List textList=Arrays.asList(TEXTFIELD); + List selectList=Arrays.asList(SELECTFIELD); + List dataSourceList=Arrays.asList(DATASOURCEFIELD); + List dateList=Arrays.asList(DATEFIELD); + if(numberList.contains(compnentKey)){ + return DataType.NUMBER; + }else if(textList.contains(compnentKey)){ + return DataType.STRING; + }else if(dateList.contains(compnentKey)){ + return DataType.DATE; + }else if(selectList.contains(compnentKey)){ + return DataType.OPTION; + }else if(dataSourceList.contains(compnentKey)){ + return DataType.OPTION; + }else { + return DataType.STRING; + } + } + /** + * 判断变量是否为空 + * @param objects + * @return + */ + public static boolean checkIsNull(Object... objects){ + String checkLevel=objects[objects.length-1].toString(); + List formulavars=new ArrayList<>(); + for (int i=0;i findAggParam(String sql){ + List list=new LinkedList<>(); + String partternStr="(COUNT|SUM|MIN|MAX|AVG){1}\\(+.+?\\)+"; + Pattern pt=Pattern.compile(partternStr); + Matcher matcher=pt.matcher(sql); + while (matcher.find()){ + String aggStr=matcher.group(); + aggStr=aggStr.replaceAll("(COUNT|SUM|MIN|MAX|AVG){1}",""); + String[] paramArray=aggStr.split(",",2); + if(paramArray.length==2){ + String cndParam=paramArray[1]; + cndParam=cndParam.substring(0,cndParam.length()-1); + list.add(cndParam); + } + } + + + return list; + } + + /** + * 替换聚合函数的条件参数,一般是从规则库返回过来的条件语句 + * @param sql + * @param replaceArray + * @return + */ + public static String replaceAggParam(String sql,List replaceArray){ + String partternStr="(COUNT|SUM|MIN|MAX|AVG){1}\\(.+?\\){1}?"; + Pattern pt=Pattern.compile(partternStr); + Matcher matcher=pt.matcher(sql); + String paramPattStr="\\(.+?\\){1}?"; + Pattern ppatt=Pattern.compile(paramPattStr); + int loop=0; + while (matcher.find()){ + String matherString=matcher.group(); + String[] paramStrArray=matherString.replaceAll("(\\(|\\))","").split(","); + String newmatherString=matherString.replace(paramStrArray[1],"{"+replaceArray.get(loop)+"}"); + sql=sql.replace(matherString,newmatherString); + loop++; + } + return sql; + } + + + + public static void checkParamArrayDataType(List formulavars){ + for (FormulaVar formulaVar:formulavars){ + if(formulaVar.getComponentKey()!=null&&!formulaVar.getComponentKey().equals("")){ + String componentKey=formulaVar.getComponentKey(); + Arrays.sort(NUMBERCOMPONENTS); + int searchIdx=Arrays.binarySearch(NUMBERCOMPONENTS,componentKey); + if(searchIdx>=0){ + formulaVar.setFieldType("Number"); + } + Arrays.sort(ReturnType.CHECK_TYPE); + if(Arrays.binarySearch(ReturnType.CHECK_TYPE,componentKey)>=0){ + formulaVar.setFieldType("String"); + } + if(formulaVar.getOptionId()!=null){ + formulaVar.setFieldType("String"); + } + } + + } + } + + + /** + * 替换语句中的参数为参数列表中的Key + * @param sql + * @param formulaVars + * @return + */ + public static String replaceAllParam(String sql,List formulaVars){ + if(null==formulaVars){ + return sql; + } + //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 + String partternStr="\\{.+?\\}{1}?"; + Pattern pt=Pattern.compile(partternStr); + Matcher matcher=pt.matcher(sql); + + int loop=0; + //替换逻辑 + while (matcher.find()){ + String matherString=matcher.group(); + //替换特殊字符 + matherString=matherString.replace("{",""); + matherString=matherString.replace("}",""); + matherString=matherString.replace("(","\\("); + matherString=matherString.replace(")","\\)"); + matherString=matherString.replaceAll("\\+","\\\\+"); + matherString=matherString.replaceAll("\\-","\\\\-"); + matherString=matherString.replaceAll("\\*","\\\\*"); + matherString=matherString.replaceAll("\\/","\\\\/"); + if(formulaVars!=null&&loop") + .replace("<","<"); + return formatStr; + } + + /** + * 过滤 除了数字外的其他参数类型 + * @param param + * @return + */ + public static boolean inNumber(Object param){ + boolean r=false; + Class[] paramClasses=new Class[]{Integer.class,Double.class,Float.class,Long.class,Short.class}; + for(int i=0;i numberList=Arrays.asList(numberTypes); + if(typeAllName.equals("Character")){ + return "String"; + }else if(numberList.contains(typeAllName.toLowerCase())){ + return "Number"; + } + return typeAllName; + } + + /** + * 获取参数类型 + * @param + * @return + */ + public static String getParamType(Object dataType){ + if(dataType instanceof DataType){ + DataType data=(DataType)dataType; + String filedType=data.getDataType(); + filedType=filedType.toLowerCase(); + + switch (filedType){ + case "number": + filedType= ParamType.DOUBLE.getName(); + break; + case "string": + filedType=ParamType.STRING.getName(); + break; + case "boolean": + filedType=ParamType.BOOLEAN.getName(); + break; + case "select": + filedType=ParamType.STRING.getName(); + break; + case "text": + filedType=ParamType.STRING.getName(); + break; + case "employee": + filedType= ParamType.STRING.getName(); + break; + case "department": + filedType=ParamType.STRING.getName(); + break; + case "integer": + filedType=ParamType.DOUBLE.getName(); + break; + case "double": + filedType=ParamType.DOUBLE.getName(); + break; + case "float": + filedType=ParamType.DOUBLE.getName(); + break; + case "int": + filedType=ParamType.DOUBLE.getName(); + break; + case "long": + filedType=ParamType.DOUBLE.getName(); + break; + case "bigdecimal": + filedType=ParamType.DOUBLE.getName(); + break; + + } + return filedType; + }else { + return getParamType(dataType.getClass().getName()); + } + } + + /** + * 从DataType中获取值 + * @param object + * @return + */ + public static List getParamContent(Object object){ + List dataList=new ArrayList<>(); + if(object!=null){ + if(object instanceof DataType){ + DataType data=(DataType)object; + dataList.add(getDataTypeContent(data)); + return dataList; + }else if(object instanceof List){ + List sourceDataList=(List)object; + for (Object paramObj:sourceDataList){ + if(paramObj instanceof DataType){ + DataType pramDataType=(DataType)paramObj; + dataList.add(pramDataType.getContent()); + }else{ + dataList.add(paramObj); + } + } + return dataList; + }else if(object instanceof Object[]){ + Object[] sourceDataList=(Object[]) object; + for (Object paramObj:sourceDataList){ + if(paramObj instanceof DataType){ + DataType pramDataType=(DataType)paramObj; + dataList.add(pramDataType.getContent()); + }else{ + dataList.add(paramObj); + } + } + return dataList; + }else { + dataList.add(object); + return dataList; + } + } + dataList.add(object); + return dataList; + } + public static Object getDataTypeContent(DataType dataType){ + String properType=""; + Object content=null; + if(StringUtils.isNotEmpty(dataType.getComponentKey())){ + properType=dataType.getComponentKey(); + }else if(StringUtils.isNotEmpty(dataType.getDataType())){ + properType=dataType.getDataType(); + } + switch (findType(properType)){ + case DataType.NUMBER: + case DataType.STRING: + case DataType.DATE: + content=dataType.getContent(); + break; + case DataType.OPTION: + content=dataType.getContent(); + break; + } + return content; + } + + /** + * 获取JSON的content内容 + * @param object + * @return + */ + public static Object getParamContent(Object object,String funcType){ + Object result=null; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + switch (dataType.getDataType()){ + case DataType.DATE: + if(dataType.getContent()==null||dataType.getContent().equals("")){ + return ""; + } + String format= DateUtil.buildFormat(dataType.getContent().toString()); + SimpleDateFormat formatter = new SimpleDateFormat(format); + try { + Date date=formatter.parse(dataType.getContent().toString()); + result=funcType.equalsIgnoreCase("string")?dataType.getContent():date.getTime(); + } catch (ParseException e) { + logger.error("err",e); + } + break; + case DataType.NUMBER: + if(null==dataType.getContent()||dataType.getContent().equals("")){ + return 0; + } + if(funcType.equalsIgnoreCase("string")){ + result=dataType.getContent(); + + }else { + if(!RegularUtil.isNumber(dataType.getContent())){ + return 0; + } + if(dataType.getContent().toString().indexOf(".")>=0){ +// result=Double.parseDouble(dataType.getContent().toString()); + result=new BigDecimal(dataType.getContent().toString()); + }else if(dataType.getContent().toString().length()<=9){ + result=Integer.parseInt(dataType.getContent().toString()); + }else { + result=Long.parseLong(dataType.getContent().toString()); + } + } + break; + case DataType.STRING: + if(null==dataType.getContent()){ + result=""; + }else { + result=dataType.getContent().toString().trim(); + } + + break; + case DataType.OPTION: + if(funcType.equalsIgnoreCase("string")){ + if(StringUtils.isNotEmpty(dataType.getOptionContent())){ + result=dataType.getOptionContent(); + }else { + result=""; + } + + }else { + result=dataType.getContent(); + } + break; + case DataType.BOOL: + result=dataType.getContent(); + break; + default: + if(dataType.getContent()==null){ + return ""; + } + result=dataType.getContent().toString(); + break; + } + }else if(object instanceof Date){ + Date date=(Date)object; + result=date.getTime(); + }else { + if(funcType.equalsIgnoreCase(DataType.BOOL)){ + result=object==null?false:object; + }else if(object instanceof Boolean){ + result=object; + }else if(object instanceof Integer || object instanceof Double || object instanceof Long || object instanceof BigDecimal){ + result=object; + }else { + result=object==null?"":object+""; + } + + } + return result; + } + + /** + * 获取参数的数据类型,从DataType中获取或者直接获取 + * @param object + * @return + */ + public static String checkParamType(Object object){ + String typeName=null; + if(object instanceof DataType){ + DataType dataType=(DataType)object; + typeName= dataType.getDataType(); + }else { + typeName= ExcelParamUtil.getParamType(object.getClass().getName()); + } + return typeName; + } + + /** + * 运行公式时的参数设置 + * @param formulavars + * @param expressMap + * @return + */ + public static Map buildParam(List formulavars, Map expressMap){ + checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 + for(FormulaVar formulaVar:formulavars){ + DataType dataType=new DataType(); + String key=null; + if(formulaVar.getFormId()!=null&&formulaVar.getFieldId()==null){ + key="form"+formulaVar.getFormId(); + }else if(formulaVar.getFieldId()!=null&&formulaVar.getOptionId()==null){ + String fieldId=formulaVar.getFieldId().toString(); + key="field"+fieldId; + dataType.setFieldId(fieldId); + }else if(formulaVar.getOptionId()!=null){ + key="option"+formulaVar.getOptionId(); + dataType.setContent(formulaVar.getOptionId()); + }else { + key="option"+formulaVar.getOptionId(); + } + + Arrays.sort(funcArray); + int sidx= Arrays.binarySearch(funcArray,key); + if( sidx>=0 ){ + throw new RuntimeException("变量名非法"); + } + if(formulaVar.getOptionId()!=null){ + dataType.setDataType(DataType.OPTION); + } + if(expressMap.containsKey(key)){ + String newKey= ExcelParamUtil.randomNumber()+"_"+key; + expressMap.put(newKey,dataType); + formulaVar.setKey(newKey); + }else { + expressMap.put(key,dataType); + } + } + + return expressMap; + } + + /*** + * 验证函数时构建参数设置参数值 + * 把FormulaVar类型的参数封装成DataType类型参数 + * @param formulavars 入参类型 + * @param expressMap 返回Map + * @return + */ + public static Map buildLocalParam(List formulavars, Map expressMap, SimpleEmployee employee){ + + checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 + for(FormulaVar formulaVar:formulavars){ + DataType dataType=new DataType(); + dataType.setScore(0d); + dataType.setName((null==formulaVar.getName() || formulaVar.getName().equals(""))?formulaVar.getParent():formulaVar.getName()); + dataType.setFieldId(formulaVar.getFieldId()!=null?formulaVar.getFieldId().toString():null); + String key=null; + if(formulaVar.getModule()!=null&&!formulaVar.getModule().equals("")){ + try { + dataType.setModule(formulaVar.getModule()); + } catch (IllegalArgumentException e) { + logger.error("err",e); + dataType.setModule(formulaVar.getModule()); + } + } + dataType.setFormId(formulaVar.getFormId()!=null?Long.parseLong(formulaVar.getFormId()):null); + if(formulaVar.getName()!=null&&formulaVar.getName().equals("当前操作人")){ + key=formulaVar.getKey(); + formulaVar.setContent(employee.getUserId().toString()); + dataType.setContent(formulaVar.getContent()); + dataType.setText(formulaVar.getContent()); + dataType.setDataType(DataType.OPTION); + }else{ + if(formulaVar.getFormId()!=null&&formulaVar.getFieldId()==null&&formulaVar.getOptionId()==null){ + key="form"+formulaVar.getFormId().toString(); + ThreadLocalData threadLocalData=new ThreadLocalData(); + threadLocalData.setEmployee(employee); + threadLocalData.setModuleSource(ModuleSource.biaoge); + ParamContext.get().setValue(formulaVar.getFormId().toString(),threadLocalData); + }else if(formulaVar.getFieldId()!=null&&formulaVar.getOptionId()==null){ + String fieldId=formulaVar.getFieldId().toString(); + key="field"+fieldId; + dataType.setFieldId(fieldId); + }else if(formulaVar.getOptionId()!=null){ + key="option"+formulaVar.getOptionId().toString(); + dataType.setContent(formulaVar.getOptionId()); + dataType.setText(formulaVar.getName()); + dataType.setFormId(null); + }else { + key="option"+formulaVar.getOptionId().toString(); + } + } + + Arrays.sort(funcArray); + int sidx= Arrays.binarySearch(funcArray,key); + if( sidx>=0 ){ + throw new RuntimeException("变量名非法"); + } + if(formulaVar.getOptionId()!=null){ + dataType.setDataType(DataType.OPTION); + } + + if(StringUtils.isEmpty(dataType.getDataType())){ + String typeKey=null; + if(StringUtils.isNotEmpty(formulaVar.getFieldType())){ + typeKey=formulaVar.getFieldType(); + }else if(StringUtils.isNotEmpty(formulaVar.getType())){ + typeKey=formulaVar.getType(); + }else if(StringUtils.isNotEmpty(formulaVar.getFieldType())){ + typeKey=formulaVar.getFieldType(); + } + dataType.setDataType(ExcelParamUtil.findTestDataType(typeKey)); + } + if(StringUtils.isEmpty(dataType.getComponentKey())){ + dataType.setComponentKey(formulaVar.getComponentKey()); + } + if(expressMap.containsKey(key)){ + String newKey=key+ ExcelParamUtil.randomNumber(); + formulaVar.setKey(newKey); + dataType.setAggCndKey(key); + expressMap.put(newKey,dataType); + }else { + expressMap.put(key,dataType); + } + } + + return expressMap; + } + + /** + * 格式化变量为数字 + * @param + */ + public static Object convertParamValToNumber(Object op1){ + BigDecimal oop1=new BigDecimal(ExcelParamUtil.getParamContent(op1,"string").toString()); + return oop1; + } + /** + * 格式化参数 + * @param op1 + * @param op2 + * @return + */ + public static List converParamValue(Object op1,Object op2){ + List list=new ArrayList<>(); + + + if(op1 instanceof DataType){ + list.add(op1); + DataType op1Data=(DataType)op1; + if(!(op2 instanceof DataType)&&op1Data.getDataType().toLowerCase().equals("date")){ + DataType dataType=new DataType(); + dataType.setDataType(DataType.STRING); + dataType.setContent(op2); + list.add(dataType); + }else if(op2 instanceof DataType&&op1Data.getDataType().toLowerCase().equals("date")){ + DataType dataType=(DataType)op2; + dataType.setDataType(DataType.STRING); + list.add(dataType); + }else{ + list.add(op2); + } + + }else if(op2 instanceof DataType){ + DataType op2Data=(DataType)op2; + if(!(op1 instanceof DataType)&&op2Data.getDataType().toLowerCase().equals("date")){ + DataType dataType=new DataType(); + dataType.setDataType(DataType.STRING); + dataType.setContent(op1); + list.add(dataType); + }else if(op1 instanceof DataType&&op2Data.getDataType().toLowerCase().equals("date")){ + DataType dataType=(DataType)op1; + dataType.setDataType(DataType.STRING); + list.add(dataType); + }else { + list.add(op1); + } + list.add(op2); + }else { + list.add(op1); + list.add(op2); + } + + return list; + } + + /** + * 统一处理参数类型不一致问题 + * @param typeName + * @return + */ + public static String checkParamType(String typeName){ + typeName=typeName.toLowerCase(); + switch (typeName){ + case "option": + typeName=ParamType.STRING.getName(); + break; + case "date": + typeName=DataType.STRING; + break; + case "number": + typeName=DataType.NUMBER; + break; + case "string": + typeName=ParamType.STRING.getName(); + break; + case "boolean": + typeName=ParamType.BOOLEAN.getName(); + break; + case "select": + typeName=ParamType.STRING.getName(); + break; + case "text": + typeName=ParamType.STRING.getName(); + break; + case "employee": + typeName=ParamType.STRING.getName(); + break; + case "department": + typeName=ParamType.STRING.getName(); + break; + case "integer": + typeName=DataType.NUMBER; + break; + case "double": + typeName=DataType.NUMBER; + break; + case "float": + typeName=DataType.NUMBER; + break; + case "int": + typeName=DataType.NUMBER; + break; + case "long": + typeName=DataType.NUMBER; + break; + case "bigdecimal": + typeName=DataType.NUMBER; + break; + + } + return typeName; + } + public static String getKeyString(Object obj){ + if(obj instanceof JSONObject){ + JSONObject jsonObject=(JSONObject)obj; + return jsonObject.getString("key"); + }else { + return obj.toString(); + } + } + /** + * 替换变量的错误位置 + * @param startIdx + * @param endIdx + * @param excuteStr + */ + public static Map replaceErrorPlace(int startIdx,int endIdx,String errorFunc,String excuteStr,Map paramMap){ + Map kvMap=loopMap(paramMap); + Map replaceMap=new HashMap<>(); + String excuteLeftStr=excuteStr.substring(0,startIdx); + if(!excuteLeftStr.equals("")){ + Iterator wordItaretor=kvMap.keySet().iterator(); + while (wordItaretor.hasNext()){ + String key=wordItaretor.next(); + String name=kvMap.get(key); + if(excuteLeftStr.indexOf(key)>=0){ + String newStr=excuteLeftStr.replaceAll(key,name); + startIdx=startIdx-(excuteLeftStr.length()-newStr.length()); + } + } + + } + if(kvMap.get(errorFunc)!=null){ + endIdx=startIdx+kvMap.get(errorFunc).length()-1; + }else { + endIdx=startIdx+errorFunc.length()-1; + } + + replaceMap.put("startIdx",startIdx); + replaceMap.put("endIdx",endIdx); + return replaceMap; + } + + public static Map loopMap(Map paramMap){ + Map kvMap=new HashMap<>(); + + Set set=paramMap.keySet(); + Iterator iterator=set.iterator(); + while (iterator.hasNext()){ + String key=iterator.next(); + DataType dataType=(DataType)paramMap.get(key); + kvMap.put(key,dataType.getName()); + } + return kvMap; + } + + public static boolean isNumber(Object object){ + String type= ExcelParamUtil.getParamType(object.getClass().getName()); + Arrays.sort(numberTypes); + if(Arrays.binarySearch(numberTypes,type)>=0){ + return true; + } + return false; + } + + public static String randomNumber(){ + int max=1000,min=1; + long randomNum = System.currentTimeMillis(); + int ran3 = (int) (randomNum%(max-min)+min); + return ran3+""; + } + + /** + * 长度不够则添加元素的字符串拼接 + * @param chars 将要拼接的字符 + * @param sourceStr 源字符 + * @param targetLength 目标字符长度 + * @param place 位置在左还是右 + * @return + */ + public static String appendString(String chars, String sourceStr, int targetLength, String place){ + StringBuilder builder = new StringBuilder(sourceStr); + + while (true){ + //长度相等,不做处理 + if(builder.length() == targetLength){ + break; + }else if(builder.length() > targetLength){ + //源字符长度大于目标长度则截取 + int length = builder.length() - targetLength; + + if("LEFT".equals(place)){ + String tempStr = builder.substring(length, builder.length()); + builder.replace(0, builder.length(), tempStr); + }else { + String tempStr = builder.substring(0, targetLength); + builder.replace(0, builder.length(), tempStr); + } + break; + } + + //源字符长度小于目标长度则不断拼接 + if("LEFT".equals(place)){ + builder.insert(0, chars.replaceAll(",","")); + }else { + builder.append(chars.replaceAll(",","")); + } + } + return builder.toString(); + } + + public static FormulaVar getFixFieldVar(List list, String key){ + FormulaVar formulaVar=new FormulaVar(); + for (FixedField fixedField:list){ + if(fixedField.getKey().equals(key)){ + Component component=(Component)fixedField.getMatchs().get(0); + ComponentType componentType=component.getComponentKey(); + if(componentType.equals(ComponentType.Text)){ + + } + } + } + return formulaVar; + } + + public static String findAggCndStr(String sql,Map paramMap){ + String partternStr="(COUNT|SUM|MIN|MAX|AVG|count|sum|min|max)+\\(+(.)+\\)+"; + Pattern pattern = Pattern.compile(partternStr); + Matcher matcher = pattern.matcher(sql ); + int i=0; + while (matcher.find()) { + String cnd = matcher.group(); + String[] cndArray=cnd.split(",",2); + if(cndArray.length==2){ + String realCnd=cndArray[1].substring(0,cndArray[1].length()-1); + String key="cnd"+i+Math.abs(realCnd.hashCode())+""; + sql=sql.replace(realCnd,key); + realCnd=realCnd.replace("{",""); + realCnd=realCnd.replace("}",""); + paramMap.put(key,realCnd); + } + i++; + } + return sql; + } + + + /** + * 执行语句的断句算法,通过计算小括号的数量进行断句断点的确定,然后拆分语句 + * @param sql + */ + public static String spliteSql(String sql,Map paramMap){ + List strList=new ArrayList<>(); + int pointIdx=0; + char[] charArray=sql.toCharArray(); + int leftBrakets=0; + char brackeLeft='('; + char brackeRight=')'; + boolean find=false; + for (int i=0;i=0?cndArray[0].length():0); + replaceSql+=cndArray[0]+findAggCndStr(realCnd,paramMap); + } + + }else { + replaceSql+=findAggCndStr(s,paramMap); + } + + } + sql=replaceSql; + return sql; + } + +} diff --git a/src/com/engine/salary/formlua/util/ExcelResult.java b/src/com/engine/salary/formlua/util/ExcelResult.java new file mode 100644 index 000000000..aaf70d575 --- /dev/null +++ b/src/com/engine/salary/formlua/util/ExcelResult.java @@ -0,0 +1,36 @@ +package com.engine.salary.formlua.util; + +import java.io.Serializable; + +/** + * @author + */ +public class ExcelResult implements Serializable { + private Object data; + private int code; + private String errorInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getErrorInfo() { + return errorInfo; + } + + public void setErrorInfo(String errorInfo) { + this.errorInfo = errorInfo; + } +} diff --git a/src/com/engine/salary/formlua/util/ExcelStandardUtil.java b/src/com/engine/salary/formlua/util/ExcelStandardUtil.java new file mode 100644 index 000000000..45489e83d --- /dev/null +++ b/src/com/engine/salary/formlua/util/ExcelStandardUtil.java @@ -0,0 +1,492 @@ +package com.engine.salary.formlua.util; + + +import com.alibaba.fastjson.JSON; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.excel.formula.api.entity.DataOption; +import com.weaver.excel.formula.api.entity.FormulaVar; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.ParamFactory; +import com.weaver.excel.formula.entity.standard.front.CurrentVar; +import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ExcelStandardUtil { + protected static final Logger logger = LoggerFactory.getLogger(ExcelStandardUtil.class); + + public static Map replaceAllParam(String sql, List localVars,List dataVars, SimpleEmployee employee){ + if(null!=localVars){ + for (FormulaVar formulaVar:localVars){ + if(StringUtils.isNotEmpty(formulaVar.getDataId()) && StringUtils.isEmpty(formulaVar.getFormId())){ + formulaVar.setFormId(formulaVar.getDataId()); + } + if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_department")){ + formulaVar.setType("department"); + formulaVar.setComponentKey(ComponentType.Department.toString()); + } + if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_superior")){ + formulaVar.setType("employee"); + formulaVar.setComponentKey(ComponentType.Employee.toString()); + } + } + } + + Map dataMap=new HashMap<>(); + Map paramKeyMap=new HashMap<>(); + //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 + String partternStr="\\{.+?\\}{1}?"; + Pattern pt=Pattern.compile(partternStr); + Matcher matcher=pt.matcher(sql); + + int loop=0; + //替换逻辑 + while (matcher.find()){ + String matherString=matcher.group(); + //替换特殊字符 + matherString=matherString.replace("{",""); + matherString=matherString.replace("}",""); + matherString=matherString.replace("(","\\("); + matherString=matherString.replace(")","\\)"); + matherString=matherString.replaceAll("\\+","\\\\+"); + matherString=matherString.replaceAll("\\-","\\\\-"); + matherString=matherString.replaceAll("\\*","\\\\*"); + matherString=matherString.replaceAll("\\/","\\\\/"); + if(localVars!=null&&loop"+JSON.toJSONString(dataType)); + } + }else{ + String typeKey=localFormulaVar.getProperKey(); + if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ + typeKey=localFormulaVar.getFieldType(); + }else if(StringUtils.isNotEmpty(localFormulaVar.getType())){ + typeKey=localFormulaVar.getType(); + }else if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ + typeKey=localFormulaVar.getFieldType(); + localFormulaVar.setComponentKey(localFormulaVar.getFieldType()); + } + dataType.setDataType(ExcelParamUtil.findDataType(typeKey)); + dataType.setFieldId(localFormulaVar.getFieldId()); + dataType.setFormId(StringUtils.isNotEmpty(localFormulaVar.getFormId())?Long.parseLong(localFormulaVar.getFormId()):null); + try { + dataType.setModule(localFormulaVar.getModule()); + } catch (IllegalArgumentException e) { + logger.error("err",e); + dataType.setModule(localFormulaVar.getModule()); + } + dataType.setContent(""); + if(!paramKeyMap.containsKey(key)){ + paramKeyMap.put(key,dataType); + }else{ + logger.info("存在同名参数:"+key+"-->"+JSON.toJSONString(dataType)); + } + } + } + loop++; + } + } +// if(loop!=localVars.size()){ +// throw new RuntimeException("参数列表与执行语句不一致"); +// } + dataMap.put("param",paramKeyMap); + dataMap.put("sql",sql); + return dataMap; + } + + public static Map replaceAllParamForTest(String sql, List formulaVars, SimpleEmployee employee){ + if(null==formulaVars){ + return null; + } + for (FormulaVar formulaVar:formulaVars){ + if(StringUtils.isNotEmpty(formulaVar.getDataId()) && StringUtils.isEmpty(formulaVar.getFormId())){ + formulaVar.setFormId(formulaVar.getDataId()); + if(StringUtils.isNotEmpty(formulaVar.getType()) && StringUtils.isEmpty(formulaVar.getComponentKey())){ + if(formulaVar.getType().equalsIgnoreCase("operator") || formulaVar.getType().equalsIgnoreCase("employee")){ + formulaVar.setComponentKey(""); + } + } + } + if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_department")){ + formulaVar.setType("department"); + formulaVar.setComponentKey("Department"); + } + if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_superior")){ + formulaVar.setType("employee"); + formulaVar.setComponentKey("Employee"); + } + } + Map dataMap=new HashMap<>(); + Map paramKeyMap=new HashMap<>(); + //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 + String partternStr="\\{.+?\\}{1}?"; + Pattern pt=Pattern.compile(partternStr); + Matcher matcher=pt.matcher(sql); + + int loop=0; + //替换逻辑 + while (matcher.find()){ + String matherString=matcher.group(); + //替换特殊字符 + matherString=matherString.replace("{",""); + matherString=matherString.replace("}",""); + matherString=matherString.replace("(","\\("); + matherString=matherString.replace(")","\\)"); + matherString=matherString.replaceAll("\\+","\\\\+"); + matherString=matherString.replaceAll("\\-","\\\\-"); + matherString=matherString.replaceAll("\\*","\\\\*"); + matherString=matherString.replaceAll("\\/","\\\\/"); + if(formulaVars!=null&&loop dataVars,SimpleEmployee employee){ + DataType dataType =new DataType(); + if(localFormulaVar == null){ + return null; + } + + String typeKey=localFormulaVar.getProperKey(); + if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ + typeKey=localFormulaVar.getFieldType(); + }else if(StringUtils.isNotEmpty(localFormulaVar.getType())){ + typeKey=localFormulaVar.getType(); + }else if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ + typeKey=localFormulaVar.getFieldType(); + localFormulaVar.setComponentKey(localFormulaVar.getFieldType()); + } + logger.info(localFormulaVar.getId()+"typeKey=:"+typeKey); + switch (ExcelParamUtil.findDataType(typeKey)){ + case DataType.DATE: + dataType.setDataType(DataType.STRING); + setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); + if(dataType.getContent()==null){ + dataType.setContent(""); + } + break; + case DataType.STRING: + dataType.setDataType(DataType.STRING); + setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); + if(dataType.getContent()==null){ + dataType.setContent(""); + } + break; + case DataType.NUMBER: + dataType.setDataType(DataType.NUMBER); + setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); + break; + case DataType.OPTION: + logger.info("函数构建选项型:"+JSON.toJSONString(localFormulaVar)); + dataType.setDataType(DataType.OPTION); + setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"option"); + if(dataType.getContent() == null){ + dataType.setContent(localFormulaVar.getId()!=null?localFormulaVar.getId():localFormulaVar.getOptionId()); + dataType.setText(dataType.getContent()+""); + } + //当前操作人赋值 + if(localFormulaVar.getId()!=null){ + switch (localFormulaVar.getId()){ + case "current_user": + dataType.setContent(employee.getId()); + dataType.setOptionContent(employee.getName()); + break; + case "current_superior": + dataType.setContent(employee.getSuperiorId()); + break; + case "current_department": + dataType.setContent(employee.getDepartmentId()); + break; + case "current_position": + dataType.setContent(employee.getPositionId()); + break; + default: + break; + } + logger.info("当前操作人赋值完成:"+JSON.toJSONString(dataType)); + } + break; + case DataType.DATASOURCE: + dataType.setDataType(DataType.DATASOURCE); + setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"option"); + break; + default: + logger.info("未匹配到参数类型:"+(JSON.toJSONString(localFormulaVar))); + break; + } + if(StringUtils.isNotEmpty(localFormulaVar.getDataType())){ + dataType.setDataType(localFormulaVar.getDataType()); + } + if(StringUtils.isEmpty(dataType.getComponentKey())){ + if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ + dataType.setComponentKey(localFormulaVar.getFieldType()); + }else if(StringUtils.isNotEmpty(localFormulaVar.getProperKey())){ + dataType.setComponentKey(localFormulaVar.getProperKey()); + }else if(StringUtils.isNotEmpty(localFormulaVar.getComponentKey())){ + dataType.setComponentKey(localFormulaVar.getComponentKey()); + } + } + dataType.setFieldId(localFormulaVar.getFieldId()+""); + dataType.setFormId(localFormulaVar.getFormId()!=null?Long.parseLong(localFormulaVar.getFormId()):null); + dataType.setEmployee(employee); + if(StringUtils.isNotEmpty(localFormulaVar.getModule())){ + try { + dataType.setModule(localFormulaVar.getModule()); + } catch (IllegalArgumentException e) { + logger.error("err",e); + dataType.setModule(localFormulaVar.getModule()); + } + } + dataType.setName(localFormulaVar.getTitle()!=null?localFormulaVar.getTitle():localFormulaVar.getName()); + logger.info("构建值完毕:"+JSON.toJSONString(dataType)); + return dataType; + } + private static void setContent(DataType dataType,String typeKey,String sourceVar,List targetVarList,String type){ + if(sourceVar==null){ + return ; + } + for (FormulaVar loopVar:targetVarList){ + switch (type){ + case "field": + if(sourceVar.equalsIgnoreCase(loopVar.getFieldId())){ + dataType.setContent(loopVar.getContent()!=null?loopVar.getContent():""); + dataType.setText(dataType.getContent()+""); + if(StringUtils.isNotEmpty(loopVar.getsFormId())){ + dataType.setSubFormId(Long.parseLong(loopVar.getsFormId())); + } + dataType.setComponentKey(loopVar.getComponentKey()); + }else{ + dataType.setComponentKey(typeKey); + } + break; + case "form": + if(sourceVar.equalsIgnoreCase(loopVar.getFormId())){ + dataType.setContent(loopVar.getContent()); + } + break; + case "option": + if(sourceVar.equalsIgnoreCase(loopVar.getFieldId())){ + dataType.setContent(loopVar.getContent()); + if(dataType.getContent()==null){ + dataType.setContent(loopVar.getOptionId()); + dataType.setText(loopVar.getOptionId()); + } + //常量 + if(StringUtils.isNotEmpty(loopVar.getOptionContent())){ + dataType.setOptionContent(loopVar.getOptionContent()); + }else if(loopVar.getDataOptionList()!=null && loopVar.getDataOptionList().size()>0){ + String optionContents=""; + List dataOptions=loopVar.getDataOptionList(); + for(DataOption dataOption:dataOptions){ + optionContents+=dataOption.getOptionContent()+","; + } + if(optionContents.lastIndexOf(",")>0){ + optionContents=optionContents.substring(0,optionContents.lastIndexOf(",")); + } + dataType.setOptionContent(optionContents); + }else {//变量 + dataType.setOptionContent(loopVar.getContent()); + } + + dataType.setScore(loopVar.getScore()); + if(StringUtils.isNotEmpty(loopVar.getsFormId())){ + dataType.setSubFormId(Long.parseLong(loopVar.getsFormId())); + } + dataType.setComponentKey(loopVar.getComponentKey()); + } + break; + default: + break; + } + } + } +} diff --git a/src/com/engine/salary/formlua/util/ExecuteTest.java b/src/com/engine/salary/formlua/util/ExecuteTest.java new file mode 100644 index 000000000..cfd350d6c --- /dev/null +++ b/src/com/engine/salary/formlua/util/ExecuteTest.java @@ -0,0 +1,47 @@ +package com.engine.salary.formlua.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.ql.util.express.ExpressRunner; +import com.weaver.excel.formula.api.entity.ExpressFormula; +import com.weaver.excel.formula.api.entity.FormulaVar; +import com.weaver.teams.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class ExecuteTest { + protected static final Logger logger = LoggerFactory.getLogger(ExecuteTest.class); + public static ExpressRunner runner; + + public static void main(String[] args){ + String[] strs=new String[]{"1","2","3"}; + List obj1=new ArrayList<>(); + for (int i =1 ;i localVars=paramArray.toJavaList(FormulaVar.class); + ExcelStandardUtil.replaceAllParam(expressFormula.getFormula(),localVars,null,null); + } + } + } + } +} diff --git a/src/com/engine/salary/formlua/util/ExpressRegularUtil.java b/src/com/engine/salary/formlua/util/ExpressRegularUtil.java new file mode 100644 index 000000000..a953ef1ec --- /dev/null +++ b/src/com/engine/salary/formlua/util/ExpressRegularUtil.java @@ -0,0 +1,227 @@ +package com.engine.salary.formlua.util; + +import com.alibaba.fastjson.JSONObject; +import com.engine.salary.formlua.entity.parameter.FormulaContext; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + + +public class ExpressRegularUtil { + private static final String[] checkRegularNullParameter=new String[]{"TRUE","FALSE","NOW","TODAY"}; + private static final String[] operSymbs=new String[]{">",">=","=","<","<=","\\+","-","\\*","\\/","!="}; + private static final String checkRegularParameter="AND|OR|IF|NOT|LIKE|DATEDIFF|DATEADD|WEEKNUM|WEEKDAY|DATEFORMAT|Y|M|D|H|I|S|COUNT|SUM|MAX|MIN|CONCAT|SEARCH|TEXT|PAD|REPLACE|VALUE|LEN|LEFT|RIGHT|MID"; + private final static String leftCircleBracket="Unmatched closing '('"; + private final static String rightCircleBracket="Unmatched closing ')'"; + private final static String leftSquareBracket="Unmatched closing '['"; + private final static String rightSquareeBracket="Unmatched closing ']'"; + private final static String leftBigBracket="Unmatched closing '{'"; + private final static String rightBigBracket="Unmatched closing '}'"; + public static boolean checkFuncExpress(String str){ + filter(str); + return true; + } + + public static boolean isContainChinese(String str) { + Pattern p = Pattern.compile("[\u4E00-\u9FA5|\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]"); + Matcher m = p.matcher(str); + if (m.find()) { + return true; + } + return false; + } + + private static void filter(String formula){ + try { + testSymbol(formula); + checkNullRegular(formula); + checkOperatorNullParam(formula); + formula=formula.replaceAll("","#"); + String leftReplace=""; + String rightReplace=""; + leftReplace=formula.replaceAll("\\(",""); + rightReplace=formula.replaceAll("\\)",""); + if(leftReplace.length()>rightReplace.length()){ + PatternSyntaxException patternSyntaxException=new PatternSyntaxException(leftCircleBracket,formula,formula.lastIndexOf(")")); + throw patternSyntaxException; + } + if(leftReplace.length()rightReplace.length()){ + PatternSyntaxException patternSyntaxException=new PatternSyntaxException(leftBigBracket,formula,formula.lastIndexOf("}")); + throw patternSyntaxException; + } + if(leftReplace.length()rightReplace.length()){ + PatternSyntaxException patternSyntaxException=new PatternSyntaxException(leftSquareBracket,formula,formula.lastIndexOf("]")); + throw patternSyntaxException; + } + if(leftReplace.length()=0){ + if(FormulaContext.get().getValue(checkRegularNullParameter[i])!=null){ + Integer paramCount=FormulaContext.get().getValue(checkRegularNullParameter[i]); + paramCount++; + FormulaContext.get().setValue(checkRegularNullParameter[i]); + }else { + FormulaContext.get().setValue(checkRegularNullParameter[i]); + } + filterPattern=checkRegularNullParameter[i]+"{1}\\({1}\\){1}"; + Pattern pattern= Pattern.compile(filterPattern); + Matcher matcher=pattern.matcher(formula); + boolean excuteBool=matcher.find(); + if(!excuteBool){ + eidx=0; + Integer errorCount=FormulaContext.get().getFormulaJson().getInteger(checkRegularNullParameter[i]); + String [] errorCutArray=formula.split(checkRegularNullParameter[i]); + for (int fi=0;fi1&&fi>0){ + eidx+=checkRegularNullParameter[i].length(); + } + } + PatternSyntaxException patternSyntaxException=new PatternSyntaxException(checkRegularNullParameter[i]+"函数不能有参数",formula,eidx); + throw patternSyntaxException; + } + }else { + + } + } + } + + private static void checkOperatorNullParam(String formula){ + formula=formula.trim(); + JSONObject errorJson=new JSONObject(); + Map operMap=new HashMap<>(); + + for (int i=0;i="); + } + + +} diff --git a/src/com/engine/salary/formlua/util/IgnoreFilter.java b/src/com/engine/salary/formlua/util/IgnoreFilter.java new file mode 100644 index 000000000..a5ab03f14 --- /dev/null +++ b/src/com/engine/salary/formlua/util/IgnoreFilter.java @@ -0,0 +1,21 @@ +package com.engine.salary.formlua.util; + +import java.util.LinkedList; +import java.util.List; + + +public class IgnoreFilter { + private static List list=new LinkedList(); + public static boolean contains(String key){ + list.add("formId"); + return list.contains(key); + } + public static boolean containsFixedKey(String key){ + list.add("operators"); + list.add("names"); + list.add("createTimes"); + list.add("types"); + list.add("datastatus"); + return list.contains(key); + } +} diff --git a/src/com/engine/salary/formlua/util/IgnoreParamFilter.java b/src/com/engine/salary/formlua/util/IgnoreParamFilter.java new file mode 100644 index 000000000..31f670347 --- /dev/null +++ b/src/com/engine/salary/formlua/util/IgnoreParamFilter.java @@ -0,0 +1,769 @@ +package com.engine.salary.formlua.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.engine.salary.formlua.core.exception.ErrorType; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.entity.parameter.FormulaContext; +import com.engine.salary.formlua.entity.parameter.FuncNames; +import com.weaver.esb.server.enums.ParamType; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + + +public class IgnoreParamFilter { + protected static final Logger logger = LoggerFactory.getLogger(IgnoreParamFilter.class); + private static JSONObject errorJson = null; + private static String[] dateFuncs = new String[]{"YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND"}; + private static String[] numberOperArray = new String[]{">", "<", ">=", "<="}; + + public static void main(String[] args) throws Exception { + DataType dataType = new DataType(); + dataType.setDataType(DataType.NUMBER); + dataType.setContent(0.0); +// DataType dataType2=new DataType(); +// dataType2.setDataType(DataType.STRING); +// DataType dataType3=new DataType(); +// dataType3.setDataType(DataType.STRING); + + filterCompareFunc("", 0.5); + } + + /** + * 判断是人员参数 + * + * @param object + * @return + */ + public static boolean isEmployee(Object object) { + logger.info("校验人员参数" + JSON.toJSONString(object)); +// if (object instanceof DataType) { +// DataType dataType = (DataType) object; +// if (dataType.getComponentKey() != null && dataType.getComponentKey().equalsIgnoreCase(ComponentType.Employee.toString())) { +// return true; +// } +// } + return false; + } + + /** + * 通用的校验参数类型一致的方法 + * + * @param objects + * @return + */ + public static boolean checkType(Object... objects) { + if (objects == null || objects.length == 0) { + return true; + } + Map typeCheckMap = new HashMap<>(); + int i; + for (i = 0; i < objects.length; i++) { + Object obj = objects[i]; + if (obj instanceof DataType) { + DataType dataType = (DataType) obj; + if (StringUtils.isNotEmpty(dataType.getDataType())) { + typeCheckMap.put(DataType.returnType(dataType.getDataType()).toLowerCase(), obj); + } else if (StringUtils.isNotEmpty(dataType.getComponentKey())) { + typeCheckMap.put(DataType.returnType(dataType.getComponentKey()).toLowerCase(), obj); + } + } else { + String localtype = obj.getClass().getName(); + typeCheckMap.put(DataType.returnType(ExcelParamUtil.getParamType(localtype).toLowerCase()), obj); + } + } + if (typeCheckMap.keySet().size() > 1) { + return false; + } else { + return true; + } + } + + /** + * 校验参数是否统一了类型 + * + * @param objects + * @return + */ + public static boolean commonCheckParamsType(Object... objects) { + if (objects == null || objects.length == 0) { + return false; + } + String type = null; + String objFunc = objects[objects.length - 1].toString(); + for (int i = 0; i < objects.length - 1; i++) { + Object obj = objects[i]; + + String loopType = ExcelParamUtil.getParamType(obj); + if (type == null) { + type = loopType; + } else { + if (!type.equalsIgnoreCase(loopType)) { + return false; + } + } + } + return true; + } + + public static void filterParams(String func, int min, int max, Object... objects) { + Integer number = getSetFuncNumber(func); + if (null == objects) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (objects.length < min) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数至少需要" + min + "个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (max > 0 && objects.length > max) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数最多允许" + max + "个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + public static void filterDateParamTypes(String func, int funcNumber, Class[] typeClasses, Object... objects) { + Integer number = funcNumber; + if (null == objects || null == typeClasses || objects.length == 0 || typeClasses.length == 0 || objects.length > typeClasses.length) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + /** + * 通用验证方法 + * + * @param func + * @param min + * @param max + * @param typeClasses + * @param objects + */ + public static void commonFilter(String func, int min, int max, Class[] typeClasses, Object... objects) { + Integer number = getSetFuncNumber(func); + if (null == objects) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (objects.length < min) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数至少需要" + min + "个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (max > 0 && objects.length > max) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数最多允许" + max + "个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (typeClasses != null && typeClasses.length > 0) { + if (null == objects || objects.length == 0 || typeClasses.length == 0 || objects.length > typeClasses.length) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + for (int i = 0; i < objects.length; i++) { + String fieldType = null; + String paramType = ExcelParamUtil.getParamType(typeClasses[i].getName()); + paramType = ExcelParamUtil.checkParamType(paramType); + if (objects[i] instanceof DataType) { + DataType dataType = (DataType) objects[i]; + List datafunclist = Arrays.asList(dateFuncs); + if (datafunclist.contains(func)) { + fieldType = dataType.getDataType(); + } else { + fieldType = ExcelParamUtil.checkParamType(dataType.getDataType()); + } + } else { + fieldType = ExcelParamUtil.getParamType(objects[i].getClass().getName()); + fieldType = ExcelParamUtil.checkParamType(fieldType); + } + if (null == fieldType) { + errorJson = ErrorUtil.buildError(func, i + 1, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + boolean compareResult = false; + if (paramType.equals("dateandstring") && (fieldType.toLowerCase().equals("string") || fieldType.toLowerCase().equals("date"))) { + compareResult = true; + } else if (paramType.toLowerCase().equals(fieldType.toLowerCase())) { + compareResult = true; + } else if (ExcelParamUtil.inNumber(paramType) && ExcelParamUtil.inNumber(fieldType)) { + compareResult = true; + } else { + if (!compareResult) { + errorJson = ErrorUtil.buildError(func, (i + 1), number, func + "函数参数类型错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + } + + } + + + /** + * 过滤字符串函数参数 + * + * @param objects + */ + public static void filterStringConcat(int min, int max, Object... objects) { + + Integer number = getSetFuncNumber(FuncNames.CONCAT.toString()); + String func = FuncNames.CONCAT.toString(); + if (objects.length < min) { + errorJson = ErrorUtil.buildError(func, number, number, "CONCAT函数至少需要" + min + "个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (max > 0 && objects.length > max) { + errorJson = ErrorUtil.buildError(func, number, number, "CONCAT函数最多允许" + min + "个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + + /** + * 过滤聚合函数参数 + * + * @param objects + * @throws RuntimeException + */ + public static void filterAggFunc(String func, Object... objects) throws RuntimeException { + logger.info("聚合参数:" + JSON.toJSONString(objects)); + Integer number = getSetFuncNumber(func); + Map map = new HashMap<>(); + boolean mustNumber = false; + if (objects == null) { + errorJson = ErrorUtil.buildError(func, number, number, func + ErrorType.VAR_TYPE_WRONG.name()); + throw new RuntimeException(errorJson.getString("msg")); + } + if (objects.length > 2) { + errorJson = ErrorUtil.buildError(func, number, number, func + "函数最多只支持两个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + checkArrayParamNull(func, number, objects); + Object obj = objects[0]; + if (func.equals("MAX") || func.equals("MIN") || func.equals("AVG") || func.equals("SUM")) { + mustNumber = true; + } + if (!(obj instanceof DataType)) { + number = getSetFuncNumber(obj.toString()); + errorJson = ErrorUtil.buildError(obj.toString(), number, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + String paramType = ""; + DataType dataType = (DataType) objects[0]; + if (dataType.getFormId() == null && dataType.getFieldId() == null) { + number = getSetFuncNumber(obj.toString()); + errorJson = ErrorUtil.buildError(obj.toString(), number, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + + //除了 + if (mustNumber) { + if (objects[0] instanceof DataType && dataType.getDataType() != null) { + paramType = ExcelParamUtil.checkParamType(dataType.getDataType()); + if (paramType != null) { + paramType = ExcelParamUtil.checkParamType(paramType); + } + } else { + errorJson = ErrorUtil.buildError(func, number, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (paramType == null || !(paramType.equals(DataType.NUMBER))) { + errorJson = ErrorUtil.buildError(func, number, number, func + "第一个变量必须为数字字段"); + throw new RuntimeException(errorJson.getString("msg")); + } + } else { + if (dataType.getFormId() == null) { + errorJson = ErrorUtil.buildError(func, number, number, func + "第一个变量必须为表格"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + for (int i = 0; i < objects.length; i++) { + Object param = objects[i]; + if (param != null && param instanceof DataType) { + DataType pramDataType = (DataType) param; + if (pramDataType.getSubLogic() != null && pramDataType.getSubLogic().size() > 1) { + throw new RuntimeException(func + "函数的参数不能嵌套使用逻辑函数(AND、OR)"); + } + } + } + + } + + public static void filterInFunc(Object... objects) { + String oper = objects[objects.length - 1].toString(); + Integer number = getSetFuncNumber(oper); + List params = (List) objects[0]; + if (params.size() < 2) { + errorJson = ErrorUtil.buildError(oper, number, number, "IN操作符第二个条件至少需要两个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + String type = null; + for (Object object : params) { + String thisType; + if (object instanceof DataType) { + thisType = ((DataType) object).getDataType(); + if (type == null) { + type = thisType; + } else { + if (!thisType.equals(type)) { + errorJson = ErrorUtil.buildError(oper, number, number, "IN操作符参数类型不一致"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + } + } + + /*** + * 过滤比较操作符的参数类型 + * @param objects + */ + public static void filterCompareFunc(Object... objects) throws Exception { + String oper = objects[objects.length - 1].toString(); + Integer number = getSetFuncNumber(oper); + String type1 = ""; + String type2 = ""; + + for (int i = 0; i < objects.length; i++) { + Object object = objects[i]; + if (object == null) { + throw new RuntimeException("[" + oper + "]" + ErrorType.VAR_NOT_NULL.name()); + } + } + if (objects.length < 2) { + throw new RuntimeException("[" + oper + "]" + ErrorType.VAR_NOT_NULL.name()); + } + boolean isDate = false; + for (int i = 0; i < objects.length - 1; i++) { + + Object object = objects[i]; + if (object == null) { + throw new RuntimeException("[" + oper + "]" + ErrorType.VAR_NOT_NULL.name()); + } + String typeName = ""; + + if (object instanceof DataType) { + DataType param = (DataType) object; + typeName = param.getDataType(); + if (typeName.equalsIgnoreCase(DataType.FORM)) { + throw new RuntimeException("[" + oper + "]" + ErrorType.CANT_FORM_FIELD.name()); + } + + if (!typeName.toLowerCase().equals("option")) { + typeName = ExcelParamUtil.checkParamType(typeName.toLowerCase()); + } + if (typeName.toLowerCase().equals(DataType.DATE.toLowerCase())) { + typeName = DataType.STRING; + isDate = true; + } + } else { + //校验比较操作符中的数组是不是为空 + if (object instanceof Object[]) { + Object[] arrayP = (Object[]) object; + if (arrayP.length == 0) { + throw new RuntimeException("[" + oper + "]" + ErrorType.VAR_NOT_NULL.name()); + } + if (arrayP[0] instanceof DataType) { + DataType arrayParamOne = (DataType) arrayP[0]; + typeName = arrayParamOne.getDataType(); + } else { + typeName = ExcelParamUtil.getParamType(arrayP[0].getClass().getName()); + } + } else { + typeName = ExcelParamUtil.getParamType(object.getClass().getName()); + + } + if (!typeName.equalsIgnoreCase("option")) { + typeName = ExcelParamUtil.checkParamType(typeName); + } + } + //判断非等于和不等于操作符的两端参数是否为数字,不是数字返回错误 + if (!isDate && !oper.equals("=") && !oper.equals("!=") && (typeName.toLowerCase().equals(DataType.OPTION))) { + errorJson = ErrorUtil.buildError(oper, 1, number, "比较操作符'" + oper + "'不支持选项类型的运算"); + throw new RuntimeException(errorJson.getString("msg")); + } + + + if (i == 0) { + type1 = typeName; + } else { + type2 = typeName; + } + } + List operList = Arrays.asList(numberOperArray); + if (operList.contains(oper) && (type1.equalsIgnoreCase("string") || type2.equalsIgnoreCase("string"))) { + String msg = "[" + oper + "]操作符不允许非数字类型参数"; + throw new RuntimeException(msg); + } + if (!IgnoreParamFilter.checkType(objects[0], objects[1])) { + errorJson = ErrorUtil.buildError(oper, 1, number, "比较操作符参数类型不一致"); + throw new RuntimeException(errorJson.getString("msg")); + } + + if (objects[0] instanceof Object[]) { + errorJson = ErrorUtil.buildError(oper, 1, number, "比较操作符不支持数组参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + /** + * 过滤日期函数参数 + * + * @param objects + * @throws Exception + */ + public static void filterDateFunc(Object... objects) throws Exception { + Integer number = getSetFuncNumber(""); + boolean isWrong = false; + if (objects.length < 2) { + errorJson = ErrorUtil.buildError("Date", 0, number, "日期函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + int idx = 1; + for (Object object : objects) { + + if (!(object instanceof String) && !(object instanceof Date) && !(object instanceof DataType)) { + isWrong = true; + break; + + } else if (object instanceof DataType) { + Object content; + DataType dataType = (DataType) object; + content = dataType.getContent(); + if (!(content instanceof String) && !(content instanceof Date) && !(content instanceof DataType)) { + isWrong = true; + break; + } + } + idx++; + } + if (isWrong) { + errorJson = ErrorUtil.buildDataError("Date", idx, objects, "日期函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + + } + + + /** + * 逻辑函数过滤器 + * + * @param objects + */ + public static void filterLogicAndORFunc(Object... objects) { + String method = objects[objects.length - 1].toString(); + FormulaContext.get().setValue(method); + Object[] paramArray = (Object[]) objects[0]; + Integer number = getSetFuncNumber(method); + if (null == paramArray || paramArray.length == 0) { + errorJson = ErrorUtil.buildError(method, 0, number, method + "函数参数不能为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + for (int i = 0; i < paramArray.length; i++) { + String fieldType = null; + if (paramArray[i] instanceof DataType) { + DataType dataType = (DataType) paramArray[i]; + fieldType = dataType.getDataType(); + } else { + fieldType = ExcelParamUtil.getParamType(paramArray[i].getClass().getName()); + } + fieldType = ExcelParamUtil.checkParamType(fieldType); + if (!fieldType.equalsIgnoreCase(ParamType.BOOLEAN.getValue())) { + errorJson = ErrorUtil.buildError(method, (i + 1), number, method + "函数第" + (i + 1) + "个条件必须为真假值"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + + /** + * 判断IF函数的参数合法性 + * + * @param objects + */ + public static void filterIfFunc(Object... objects) { + Integer number = getSetFuncNumber("IF"); + String cndType = ""; + if (objects[0] instanceof DataType) { + DataType dataType = (DataType) objects[0]; + cndType = dataType.getDataType(); + } else { + cndType = ExcelParamUtil.getParamType(objects[0].getClass().getName()); + } + cndType = ExcelParamUtil.checkParamType(cndType); + if (null == cndType || !cndType.equals(ParamType.BOOLEAN.getValue())) { + errorJson = ErrorUtil.buildError("If", 0, number, "IF函数条件应为真假值类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + + String pType1 = ""; + String pType2 = ""; + if (objects[1] instanceof DataType) { + DataType dataType = (DataType) objects[1]; + pType1 = dataType.getDataType(); + } else { + pType1 = ExcelParamUtil.getParamType(objects[1].getClass().getName()); + } + pType1 = ExcelParamUtil.checkParamType(pType1); + if (objects[2] instanceof DataType) { + DataType dataType = (DataType) objects[2]; + pType2 = dataType.getDataType(); + } else { + pType2 = ExcelParamUtil.getParamType(objects[2].getClass().getName()); + } + pType2 = ExcelParamUtil.checkParamType(pType2); + if (!pType1.equals(pType2)) { + errorJson = ErrorUtil.buildError("If", 0, number, "IF函数表达式返回值不一致"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + public static void filterLikeFunc(Object... objects) { + Integer number = getSetFuncNumber("LIKE"); + String sourceTxt = ""; + List params = new ArrayList() { + }; + if (objects.length < 2) { + errorJson = ErrorUtil.buildError("LIKE", 0, number, "LIKE函数至少需要两个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } else if (objects.length > 2) { + errorJson = ErrorUtil.buildError("LIKE", 0, number, "LIKE函数最多支持两个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + for (Object obj : objects) { + if (obj.getClass().isArray()) { + Object[] subArray = (Object[]) obj; + for (int i = 0; i < subArray.length; i++) { + params.add(subArray[i]); + } + } else { + params.add(obj); + } + } + Object object = params.get(0); + if (object instanceof DataType) { + DataType dataType = (DataType) object; + sourceTxt = dataType.getDataType(); + } else { + sourceTxt = ExcelParamUtil.getParamType(object.getClass().getName()); + } + sourceTxt = ExcelParamUtil.checkParamType(sourceTxt); + if (null == sourceTxt || !sourceTxt.toLowerCase().equals(ParamType.STRING.getValue().toLowerCase())) { + String key = ExcelParamUtil.getKeyString(object); + number = getSetFuncNumber(key); + errorJson = ErrorUtil.buildError(key, 0, number, "LIKE函数第1个参数应该为文本类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + + for (int i = 0; i < params.size(); i++) { + Object txtObj = params.get(i); + if (null == txtObj) { + errorJson = ErrorUtil.buildError("LIKE", (i + 1), number, "LIKE函数条件错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + String txt = ""; + if (txtObj instanceof DataType) { + DataType dataType = (DataType) txtObj; + txt = dataType.getDataType(); + } else { + txt = ExcelParamUtil.getParamType(txtObj.getClass().getName()); + } + txt = ExcelParamUtil.checkParamType(txt); + if (!txt.toLowerCase().equals(ExcelParamUtil.getParamType(ParamType.STRING.getValue().toLowerCase()))) { + errorJson = ErrorUtil.buildError("LIKE", (i + 1), number, "LIKE函数条件数组第" + (i + 1) + "个参数应该为文本类型"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + } + + + public static int getSetFuncNumber(String func) { + Integer number = 0; + FormulaContext.get().getValue(func); + if (number == null || number == 0) { + FormulaContext.get().setValue(func); + number = FormulaContext.get().getValue(func); + } else { + FormulaContext.get().setValue(func); + number = FormulaContext.get().getValue(func); + } + return number; + } + + public static void checkArrayParamNull(String func, int number, Object[] objects) { + for (Object object : objects) { + if (object == null) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数条件存在未知参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + + /** + * 校验数学加减乘除运算符号 + * + * @param objects + * @param oper + */ + public static void checkNumberOper(Object[] objects, String oper) { + Integer number = getSetFuncNumber(""); + if (objects.length != 2) { + errorJson = ErrorUtil.buildError(oper, 1, number, "操作符只支持数字类型的运算"); + throw new RuntimeException(errorJson.getString("msg")); + } + String type1 = ""; + String type2 = ""; + for (int i = 0; i < objects.length; i++) { + + Object object = objects[i]; + if (object == null) { + errorJson = ErrorUtil.buildError(oper, 1, number, "[" + oper + "]" + "操作符参数不能为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + String typeName = ""; + + if (object instanceof DataType) { + DataType param = (DataType) object; + if (param.getContent() == null) { + param.setContent(0);//没有值时给0,保存函数运算结果 + } + if (param.getName() != null && param.getName().equals("当前表格")) { + errorJson = ErrorUtil.buildError(oper, 1, number, "[" + oper + "]" + "操作符参数不能为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + typeName = param.getDataType(); + if (!typeName.toLowerCase().equals("option")) { + typeName = ExcelParamUtil.checkParamType(typeName.toLowerCase()); + } + if (typeName.toLowerCase().equals(DataType.DATE.toLowerCase())) { + typeName = DataType.STRING; + } + } else if (object instanceof Date) { + typeName = "string"; + //当参数为数组时 + } else if (object instanceof Object[]) { + Object[] objArray = (Object[]) object; + String arrayType = null; + for (Object obj : objArray) { + String localType = null; + if (obj instanceof DataType) { + localType = ExcelParamUtil.getParamType(obj); + localType = ExcelParamUtil.checkParamType(localType); + } else { + localType = ExcelParamUtil.getParamType(obj.getClass().getName()).toLowerCase(); + localType = ExcelParamUtil.checkParamType(localType); + } + if (arrayType == null) { + arrayType = localType; + } else { + if (!arrayType.equals(localType)) { + errorJson = ErrorUtil.buildError(oper, 1, number, "操作符参数类型不一致"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + typeName = arrayType; + } else { + typeName = ExcelParamUtil.getParamType(object.getClass().getName()); + typeName = ExcelParamUtil.checkParamType(typeName); + } + //判断非等于和不等于操作符的两端参数是否为数字,不是数字返回错误 + if (!typeName.toLowerCase().equals(DataType.NUMBER)) { + errorJson = ErrorUtil.buildError(oper, 1, number, "操作符只支持数字类型的运算"); + throw new RuntimeException(errorJson.getString("msg")); + } + + if (i == 0) { + type1 = typeName; + } else { + type2 = typeName; + } + } + if (!type1.toLowerCase().equals(type2.toLowerCase()) || type1.equals("") || type2.equals("")) { + errorJson = ErrorUtil.buildError(oper, 1, number, "操作符参数类型不一致"); + throw new RuntimeException(errorJson.getString("msg")); + } + + } + + /** + * 校验分数取值函数 + * + * @param func + * @param objects + */ + public static void checkFraction(String func, Object... objects) { + Integer number = getSetFuncNumber(func); + if (objects == null || objects.length == 0) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (objects.length > 1) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + Object object = objects[0]; + if (object instanceof DataType) { + DataType dataType = (DataType) object; + if (null == dataType.getScore()) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数类型错误"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + + } + + public static void checkValiIdCard(String func, Object... objects) { + Integer number = getSetFuncNumber(func); + if (objects == null || objects.length == 0) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数参数为空"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (objects.length != 2) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数只允许两个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + if (objects[0] instanceof DataType) { + DataType dataType = (DataType) objects[0]; + if (dataType.getDataType().equalsIgnoreCase(DataType.OPTION) || dataType.getDataType().equalsIgnoreCase(DataType.DATE)) { + errorJson = ErrorUtil.buildError(func, 0, number, func + "函数只允许操作数字或字符"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + + /** + * 校验参数类型 + * + * @param paramArray + * @param exclDataTypeList + * @return + */ + public static List checkParamType(Object[] paramArray, List exclDataTypeList) { + List errorIdxList = new ArrayList(); + if (paramArray != null && paramArray.length != 0) { + for (int i = 0; i < paramArray.length; i++) { + Object object = paramArray[i]; + if (object instanceof DataType) { + DataType paramDataType = (DataType) object; + if (paramDataType.getDataType() != null && !paramDataType.getDataType().equalsIgnoreCase(exclDataTypeList.get(i))) { + errorIdxList.add(i); + return errorIdxList; + } + } else { + String typeString = ExcelParamUtil.getParamType(object.getClass().getName()); + typeString = DataType.returnType(typeString); + if (!typeString.equalsIgnoreCase(exclDataTypeList.get(0))) { + errorIdxList.add(i); + return errorIdxList; + } + } + } + } + return errorIdxList; + } + + +} diff --git a/src/com/engine/salary/formlua/util/NativePlace.java b/src/com/engine/salary/formlua/util/NativePlace.java new file mode 100644 index 000000000..94aa01640 --- /dev/null +++ b/src/com/engine/salary/formlua/util/NativePlace.java @@ -0,0 +1,7162 @@ +package com.engine.salary.formlua.util; + +import org.apache.commons.lang.StringUtils; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class NativePlace { + + public static void main(String args[]){ + Map placeMap=getAddressInfo("湖南省长沙市雨花区蔡锷路103号"); + } + /** + * 解析地址 + * @param address + * @return + */ + public static Map getAddressInfo(String address) { + //1级 省 直辖市 自治区 2级 市 自治州 地区 3级:区县市旗 + String province = null, city = null, provinceAndCity = null, town = null ,addr=null; + Map row = new LinkedHashMap<>(); + List> table = new ArrayList<>(); + Map resultMap = new HashMap<>(4); + + //不解析香港、澳门、台湾,这些特别行政地区过于特殊 + if (address.startsWith("香港")) { + resultMap.put("province","香港"); + return resultMap; + } else if (address.contains("澳门")) { + resultMap.put("province","澳门"); + return resultMap; + } else if (address.contains("台湾")) { + resultMap.put("province","台湾"); + return resultMap; + } else { + //普通地址,先将省市匹配出来,用户输入的时候必须要有至少两个级别的行政单位 + String regex = "((?[^市]+市|.*?自治州|.*?区|.*县)(?[^区]+区|.*?市|.*?县|.*?路|.*?街|.*?道|.*?镇|.*?旗)(?.*))"; + Matcher m = Pattern.compile(regex).matcher(address); + //匹配出省市后再拆分出省自治区直辖市,上面的正则先从整体角度匹配,确保地址的基本信息正确, + //拆分省市的时候,只要匹配到了省、直辖市、自治区,那么剩下的全部视为二级行政单位名称 + // 拆分的时候如果没有省级行政单位,那就只返回一个区 + while (m.find()) { + provinceAndCity = m.group("provinceAndCity"); + String regex2 = "((?[^省]+省|.+自治区|上海市|北京市|天津市|重庆市|上海|北京|天津|重庆)(?.*))"; + Matcher m2 = Pattern.compile(regex2).matcher(provinceAndCity); + while (m2.find()) { + province = m2.group("province"); + row.put("province", province == null ? "" : province.trim()); + city = m2.group("city"); + row.put("city", city == null ? "" : city.trim()); + } + town = m.group("town"); + addr = m.group("detailAddress"); + row.put("town", town == null ? "" : town.trim()); + row.put("addr",addr == null ? "" :addr.trim()); + table.add(row); + } + } + //对直辖市自治区做二次调整,提取名称,直辖市的二级行政单位和一级名称保持一致,自治区去掉后面的自治区后缀 + if (table != null && table.size() > 0) { + if (StringUtils.isNotBlank(table.get(0).get("province"))) { + province = table.get(0).get("province"); + //如果用户输入的是自治区,对自治区进行处理,自治区的一共五个,一个西藏两个名字,其他的是四个或者3个名字,这里截取后会存在多一个字符的情况,后面会接着处理 + if (province.contains("自治区")) { + if (province.contains("内蒙古")) { + province = province.substring(0,4); + } else { + province = province.substring(0,3); + } + + } + } + if (StringUtils.isNotBlank(province)) { + //直辖市的二级行政单位也是自己 + if (StringUtils.isNotBlank(table.get(0).get("city"))) { + city = table.get(0).get("city"); + if (city.equals("上海市") || city.equals("重庆市") || city.equals("北京市") || city.equals("天津市")) { + province = table.get(0).get("city"); + } + } + + else if (province.equals("上海市") || province.equals("重庆市") || province.equals("北京市") || province.equals("天津市")) { + city = province; + } + //所有直辖市、自治区,名称去掉行政单位(区、市) + if (StringUtils.isNotBlank(table.get(0).get("town"))) { + town = table.get(0).get("town"); + } + //对提取名称多出一个字的情况做处理,直辖市的去掉"市" + province = province.substring(0,province.length() - 1); + + } + + } else { + return resultMap; + } + resultMap.put("province",province); + resultMap.put("city",city); + resultMap.put("town",town); + resultMap.put("addr",addr); + return resultMap; + } + + + + + + public static String getNativePlace(int nativePlaceCode) { + int shengCode = nativePlaceCode / 10000; + int shiCode = nativePlaceCode / 100; + int quxianCode = nativePlaceCode; + String sheng = getNameString(shengCode); + String shi = getNameString(shiCode); + String quxian = getNameString(quxianCode); + String nativePlace = ""; + if (sheng != null) { + nativePlace += sheng; + } + if (shi != null) { + nativePlace += shi; + } + if (quxian != null) { + nativePlace += quxian; + } + return sheng; + } + + private static String getNameString(int code) { + switch (code) { + case 11: + return "北京市"; + case 1101: + return "市辖区"; + case 110101: + return "东城区"; + case 110102: + return "西城区"; + case 110105: + return "朝阳区"; + case 110106: + return "丰台区"; + case 110107: + return "石景山区"; + case 110108: + return "海淀区"; + case 110109: + return "门头沟区"; + case 110111: + return "房山区"; + case 110112: + return "通州区"; + case 110113: + return "顺义区"; + case 110114: + return "昌平区"; + case 110115: + return "大兴区"; + case 110116: + return "怀柔区"; + case 110117: + return "平谷区"; + case 1102: + return "县"; + case 110228: + return "密云县"; + case 110229: + return "延庆县"; + case 12: + return "天津市"; + case 1201: + return "市辖区"; + case 120101: + return "和平区"; + case 120102: + return "河东区"; + case 120103: + return "河西区"; + case 120104: + return "南开区"; + case 120105: + return "河北区"; + case 120106: + return "红桥区"; + case 120110: + return "东丽区"; + case 120111: + return "西青区"; + case 120112: + return "津南区"; + case 120113: + return "北辰区"; + case 120114: + return "武清区"; + case 120115: + return "宝坻区"; + case 120116: + return "滨海新区"; + case 1202: + return "县"; + case 120221: + return "宁河县"; + case 120223: + return "静海县"; + case 120225: + return "蓟县"; + case 13: + return "河北省"; + case 1301: + return "石家庄市"; + case 130101: + return "市辖区"; + case 130102: + return "长安区"; + case 130104: + return "桥西区"; + case 130105: + return "新华区"; + case 130107: + return "井陉矿区"; + case 130108: + return "裕华区"; + case 130109: + return "藁城区"; + case 130110: + return "鹿泉区"; + case 130111: + return "栾城区"; + case 130121: + return "井陉县"; + case 130123: + return "正定县"; + case 130125: + return "行唐县"; + case 130126: + return "灵寿县"; + case 130127: + return "高邑县"; + case 130128: + return "深泽县"; + case 130129: + return "赞皇县"; + case 130130: + return "无极县"; + case 130131: + return "平山县"; + case 130132: + return "元氏县"; + case 130133: + return "赵县"; + case 130183: + return "晋州市"; + case 130184: + return "新乐市"; + case 1302: + return "唐山市"; + case 130201: + return "市辖区"; + case 130202: + return "路南区"; + case 130203: + return "路北区"; + case 130204: + return "古冶区"; + case 130205: + return "开平区"; + case 130207: + return "丰南区"; + case 130208: + return "丰润区"; + case 130209: + return "曹妃甸区"; + case 130223: + return "滦县"; + case 130224: + return "滦南县"; + case 130225: + return "乐亭县"; + case 130227: + return "迁西县"; + case 130229: + return "玉田县"; + case 130281: + return "遵化市"; + case 130283: + return "迁安市"; + case 1303: + return "秦皇岛市"; + case 130301: + return "市辖区"; + case 130302: + return "海港区"; + case 130303: + return "山海关区"; + case 130304: + return "北戴河区"; + case 130321: + return "青龙满族自治县"; + case 130322: + return "昌黎县"; + case 130323: + return "抚宁县"; + case 130324: + return "卢龙县"; + case 1304: + return "邯郸市"; + case 130401: + return "市辖区"; + case 130402: + return "邯山区"; + case 130403: + return "丛台区"; + case 130404: + return "复兴区"; + case 130406: + return "峰峰矿区"; + case 130421: + return "邯郸县"; + case 130423: + return "临漳县"; + case 130424: + return "成安县"; + case 130425: + return "大名县"; + case 130426: + return "涉县"; + case 130427: + return "磁县"; + case 130428: + return "肥乡县"; + case 130429: + return "永年县"; + case 130430: + return "邱县"; + case 130431: + return "鸡泽县"; + case 130432: + return "广平县"; + case 130433: + return "馆陶县"; + case 130434: + return "魏县"; + case 130435: + return "曲周县"; + case 130481: + return "武安市"; + case 1305: + return "邢台市"; + case 130501: + return "市辖区"; + case 130502: + return "桥东区"; + case 130503: + return "桥西区"; + case 130521: + return "邢台县"; + case 130522: + return "临城县"; + case 130523: + return "内丘县"; + case 130524: + return "柏乡县"; + case 130525: + return "隆尧县"; + case 130526: + return "任县"; + case 130527: + return "南和县"; + case 130528: + return "宁晋县"; + case 130529: + return "巨鹿县"; + case 130530: + return "新河县"; + case 130531: + return "广宗县"; + case 130532: + return "平乡县"; + case 130533: + return "威县"; + case 130534: + return "清河县"; + case 130535: + return "临西县"; + case 130581: + return "南宫市"; + case 130582: + return "沙河市"; + case 1306: + return "保定市"; + case 130601: + return "市辖区"; + case 130602: + return "新市区"; + case 130603: + return "北市区"; + case 130604: + return "南市区"; + case 130621: + return "满城县"; + case 130622: + return "清苑县"; + case 130623: + return "涞水县"; + case 130624: + return "阜平县"; + case 130625: + return "徐水县"; + case 130626: + return "定兴县"; + case 130627: + return "唐县"; + case 130628: + return "高阳县"; + case 130629: + return "容城县"; + case 130630: + return "涞源县"; + case 130631: + return "望都县"; + case 130632: + return "安新县"; + case 130633: + return "易县"; + case 130634: + return "曲阳县"; + case 130635: + return "蠡县"; + case 130636: + return "顺平县"; + case 130637: + return "博野县"; + case 130638: + return "雄县"; + case 130681: + return "涿州市"; + case 130683: + return "安国市"; + case 130684: + return "高碑店市"; + case 1307: + return "张家口市"; + case 130701: + return "市辖区"; + case 130702: + return "桥东区"; + case 130703: + return "桥西区"; + case 130705: + return "宣化区"; + case 130706: + return "下花园区"; + case 130721: + return "宣化县"; + case 130722: + return "张北县"; + case 130723: + return "康保县"; + case 130724: + return "沽源县"; + case 130725: + return "尚义县"; + case 130726: + return "蔚县"; + case 130727: + return "阳原县"; + case 130728: + return "怀安县"; + case 130729: + return "万全县"; + case 130730: + return "怀来县"; + case 130731: + return "涿鹿县"; + case 130732: + return "赤城县"; + case 130733: + return "崇礼县"; + case 1308: + return "承德市"; + case 130801: + return "市辖区"; + case 130802: + return "双桥区"; + case 130803: + return "双滦区"; + case 130804: + return "鹰手营子矿区"; + case 130821: + return "承德县"; + case 130822: + return "兴隆县"; + case 130823: + return "平泉县"; + case 130824: + return "滦平县"; + case 130825: + return "隆化县"; + case 130826: + return "丰宁满族自治县"; + case 130827: + return "宽城满族自治县"; + case 130828: + return "围场满族蒙古族自治县"; + case 1309: + return "沧州市"; + case 130901: + return "市辖区"; + case 130902: + return "新华区"; + case 130903: + return "运河区"; + case 130921: + return "沧县"; + case 130922: + return "青县"; + case 130923: + return "东光县"; + case 130924: + return "海兴县"; + case 130925: + return "盐山县"; + case 130926: + return "肃宁县"; + case 130927: + return "南皮县"; + case 130928: + return "吴桥县"; + case 130929: + return "献县"; + case 130930: + return "孟村回族自治县"; + case 130981: + return "泊头市"; + case 130982: + return "任丘市"; + case 130983: + return "黄骅市"; + case 130984: + return "河间市"; + case 1310: + return "廊坊市"; + case 131001: + return "市辖区"; + case 131002: + return "安次区"; + case 131003: + return "广阳区"; + case 131022: + return "固安县"; + case 131023: + return "永清县"; + case 131024: + return "香河县"; + case 131025: + return "大城县"; + case 131026: + return "文安县"; + case 131028: + return "大厂回族自治县"; + case 131081: + return "霸州市"; + case 131082: + return "三河市"; + case 1311: + return "衡水市"; + case 131101: + return "市辖区"; + case 131102: + return "桃城区"; + case 131121: + return "枣强县"; + case 131122: + return "武邑县"; + case 131123: + return "武强县"; + case 131124: + return "饶阳县"; + case 131125: + return "安平县"; + case 131126: + return "故城县"; + case 131127: + return "景县"; + case 131128: + return "阜城县"; + case 131181: + return "冀州市"; + case 131182: + return "深州市"; + case 1390: + return "省直辖县级行政区划"; + case 139001: + return "定州市"; + case 139002: + return "辛集市"; + case 14: + return "山西省"; + case 1401: + return "太原市"; + case 140101: + return "市辖区"; + case 140105: + return "小店区"; + case 140106: + return "迎泽区"; + case 140107: + return "杏花岭区"; + case 140108: + return "尖草坪区"; + case 140109: + return "万柏林区"; + case 140110: + return "晋源区"; + case 140121: + return "清徐县"; + case 140122: + return "阳曲县"; + case 140123: + return "娄烦县"; + case 140181: + return "古交市"; + case 1402: + return "大同市"; + case 140201: + return "市辖区"; + case 140202: + return "城区"; + case 140203: + return "矿区"; + case 140211: + return "南郊区"; + case 140212: + return "新荣区"; + case 140221: + return "阳高县"; + case 140222: + return "天镇县"; + case 140223: + return "广灵县"; + case 140224: + return "灵丘县"; + case 140225: + return "浑源县"; + case 140226: + return "左云县"; + case 140227: + return "大同县"; + case 1403: + return "阳泉市"; + case 140301: + return "市辖区"; + case 140302: + return "城区"; + case 140303: + return "矿区"; + case 140311: + return "郊区"; + case 140321: + return "平定县"; + case 140322: + return "盂县"; + case 1404: + return "长治市"; + case 140401: + return "市辖区"; + case 140402: + return "城区"; + case 140411: + return "郊区"; + case 140421: + return "长治县"; + case 140423: + return "襄垣县"; + case 140424: + return "屯留县"; + case 140425: + return "平顺县"; + case 140426: + return "黎城县"; + case 140427: + return "壶关县"; + case 140428: + return "长子县"; + case 140429: + return "武乡县"; + case 140430: + return "沁县"; + case 140431: + return "沁源县"; + case 140481: + return "潞城市"; + case 1405: + return "晋城市"; + case 140501: + return "市辖区"; + case 140502: + return "城区"; + case 140521: + return "沁水县"; + case 140522: + return "阳城县"; + case 140524: + return "陵川县"; + case 140525: + return "泽州县"; + case 140581: + return "高平市"; + case 1406: + return "朔州市"; + case 140601: + return "市辖区"; + case 140602: + return "朔城区"; + case 140603: + return "平鲁区"; + case 140621: + return "山阴县"; + case 140622: + return "应县"; + case 140623: + return "右玉县"; + case 140624: + return "怀仁县"; + case 1407: + return "晋中市"; + case 140701: + return "市辖区"; + case 140702: + return "榆次区"; + case 140721: + return "榆社县"; + case 140722: + return "左权县"; + case 140723: + return "和顺县"; + case 140724: + return "昔阳县"; + case 140725: + return "寿阳县"; + case 140726: + return "太谷县"; + case 140727: + return "祁县"; + case 140728: + return "平遥县"; + case 140729: + return "灵石县"; + case 140781: + return "介休市"; + case 1408: + return "运城市"; + case 140801: + return "市辖区"; + case 140802: + return "盐湖区"; + case 140821: + return "临猗县"; + case 140822: + return "万荣县"; + case 140823: + return "闻喜县"; + case 140824: + return "稷山县"; + case 140825: + return "新绛县"; + case 140826: + return "绛县"; + case 140827: + return "垣曲县"; + case 140828: + return "夏县"; + case 140829: + return "平陆县"; + case 140830: + return "芮城县"; + case 140881: + return "永济市"; + case 140882: + return "河津市"; + case 1409: + return "忻州市"; + case 140901: + return "市辖区"; + case 140902: + return "忻府区"; + case 140921: + return "定襄县"; + case 140922: + return "五台县"; + case 140923: + return "代县"; + case 140924: + return "繁峙县"; + case 140925: + return "宁武县"; + case 140926: + return "静乐县"; + case 140927: + return "神池县"; + case 140928: + return "五寨县"; + case 140929: + return "岢岚县"; + case 140930: + return "河曲县"; + case 140931: + return "保德县"; + case 140932: + return "偏关县"; + case 140981: + return "原平市"; + case 1410: + return "临汾市"; + case 141001: + return "市辖区"; + case 141002: + return "尧都区"; + case 141021: + return "曲沃县"; + case 141022: + return "翼城县"; + case 141023: + return "襄汾县"; + case 141024: + return "洪洞县"; + case 141025: + return "古县"; + case 141026: + return "安泽县"; + case 141027: + return "浮山县"; + case 141028: + return "吉县"; + case 141029: + return "乡宁县"; + case 141030: + return "大宁县"; + case 141031: + return "隰县"; + case 141032: + return "永和县"; + case 141033: + return "蒲县"; + case 141034: + return "汾西县"; + case 141081: + return "侯马市"; + case 141082: + return "霍州市"; + case 1411: + return "吕梁市"; + case 141101: + return "市辖区"; + case 141102: + return "离石区"; + case 141121: + return "文水县"; + case 141122: + return "交城县"; + case 141123: + return "兴县"; + case 141124: + return "临县"; + case 141125: + return "柳林县"; + case 141126: + return "石楼县"; + case 141127: + return "岚县"; + case 141128: + return "方山县"; + case 141129: + return "中阳县"; + case 141130: + return "交口县"; + case 141181: + return "孝义市"; + case 141182: + return "汾阳市"; + case 15: + return "内蒙古自治区"; + case 1501: + return "呼和浩特市"; + case 150101: + return "市辖区"; + case 150102: + return "新城区"; + case 150103: + return "回民区"; + case 150104: + return "玉泉区"; + case 150105: + return "赛罕区"; + case 150121: + return "土默特左旗"; + case 150122: + return "托克托县"; + case 150123: + return "和林格尔县"; + case 150124: + return "清水河县"; + case 150125: + return "武川县"; + case 1502: + return "包头市"; + case 150201: + return "市辖区"; + case 150202: + return "东河区"; + case 150203: + return "昆都仑区"; + case 150204: + return "青山区"; + case 150205: + return "石拐区"; + case 150206: + return "白云鄂博矿区"; + case 150207: + return "九原区"; + case 150221: + return "土默特右旗"; + case 150222: + return "固阳县"; + case 150223: + return "达尔罕茂明安联合旗"; + case 1503: + return "乌海市"; + case 150301: + return "市辖区"; + case 150302: + return "海勃湾区"; + case 150303: + return "海南区"; + case 150304: + return "乌达区"; + case 1504: + return "赤峰市"; + case 150401: + return "市辖区"; + case 150402: + return "红山区"; + case 150403: + return "元宝山区"; + case 150404: + return "松山区"; + case 150421: + return "阿鲁科尔沁旗"; + case 150422: + return "巴林左旗"; + case 150423: + return "巴林右旗"; + case 150424: + return "林西县"; + case 150425: + return "克什克腾旗"; + case 150426: + return "翁牛特旗"; + case 150428: + return "喀喇沁旗"; + case 150429: + return "宁城县"; + case 150430: + return "敖汉旗"; + case 1505: + return "通辽市"; + case 150501: + return "市辖区"; + case 150502: + return "科尔沁区"; + case 150521: + return "科尔沁左翼中旗"; + case 150522: + return "科尔沁左翼后旗"; + case 150523: + return "开鲁县"; + case 150524: + return "库伦旗"; + case 150525: + return "奈曼旗"; + case 150526: + return "扎鲁特旗"; + case 150581: + return "霍林郭勒市"; + case 1506: + return "鄂尔多斯市"; + case 150601: + return "市辖区"; + case 150602: + return "东胜区"; + case 150621: + return "达拉特旗"; + case 150622: + return "准格尔旗"; + case 150623: + return "鄂托克前旗"; + case 150624: + return "鄂托克旗"; + case 150625: + return "杭锦旗"; + case 150626: + return "乌审旗"; + case 150627: + return "伊金霍洛旗"; + case 1507: + return "呼伦贝尔市"; + case 150701: + return "市辖区"; + case 150702: + return "海拉尔区"; + case 150703: + return "扎赉诺尔区"; + case 150721: + return "阿荣旗"; + case 150722: + return "莫力达瓦达斡尔族自治旗"; + case 150723: + return "鄂伦春自治旗"; + case 150724: + return "鄂温克族自治旗"; + case 150725: + return "陈巴尔虎旗"; + case 150726: + return "新巴尔虎左旗"; + case 150727: + return "新巴尔虎右旗"; + case 150781: + return "满洲里市"; + case 150782: + return "牙克石市"; + case 150783: + return "扎兰屯市"; + case 150784: + return "额尔古纳市"; + case 150785: + return "根河市"; + case 1508: + return "巴彦淖尔市"; + case 150801: + return "市辖区"; + case 150802: + return "临河区"; + case 150821: + return "五原县"; + case 150822: + return "磴口县"; + case 150823: + return "乌拉特前旗"; + case 150824: + return "乌拉特中旗"; + case 150825: + return "乌拉特后旗"; + case 150826: + return "杭锦后旗"; + case 1509: + return "乌兰察布市"; + case 150901: + return "市辖区"; + case 150902: + return "集宁区"; + case 150921: + return "卓资县"; + case 150922: + return "化德县"; + case 150923: + return "商都县"; + case 150924: + return "兴和县"; + case 150925: + return "凉城县"; + case 150926: + return "察哈尔右翼前旗"; + case 150927: + return "察哈尔右翼中旗"; + case 150928: + return "察哈尔右翼后旗"; + case 150929: + return "四子王旗"; + case 150981: + return "丰镇市"; + case 1522: + return "兴安盟"; + case 152201: + return "乌兰浩特市"; + case 152202: + return "阿尔山市"; + case 152221: + return "科尔沁右翼前旗"; + case 152222: + return "科尔沁右翼中旗"; + case 152223: + return "扎赉特旗"; + case 152224: + return "突泉县"; + case 1525: + return "锡林郭勒盟"; + case 152501: + return "二连浩特市"; + case 152502: + return "锡林浩特市"; + case 152522: + return "阿巴嘎旗"; + case 152523: + return "苏尼特左旗"; + case 152524: + return "苏尼特右旗"; + case 152525: + return "东乌珠穆沁旗"; + case 152526: + return "西乌珠穆沁旗"; + case 152527: + return "太仆寺旗"; + case 152528: + return "镶黄旗"; + case 152529: + return "正镶白旗"; + case 152530: + return "正蓝旗"; + case 152531: + return "多伦县"; + case 1529: + return "阿拉善盟"; + case 152921: + return "阿拉善左旗"; + case 152922: + return "阿拉善右旗"; + case 152923: + return "额济纳旗"; + case 21: + return "辽宁省"; + case 2101: + return "沈阳市"; + case 210101: + return "市辖区"; + case 210102: + return "和平区"; + case 210103: + return "沈河区"; + case 210104: + return "大东区"; + case 210105: + return "皇姑区"; + case 210106: + return "铁西区"; + case 210111: + return "苏家屯区"; + case 210112: + return "浑南区"; + case 210113: + return "沈北新区"; + case 210114: + return "于洪区"; + case 210122: + return "辽中县"; + case 210123: + return "康平县"; + case 210124: + return "法库县"; + case 210181: + return "新民市"; + case 2102: + return "大连市"; + case 210201: + return "市辖区"; + case 210202: + return "中山区"; + case 210203: + return "西岗区"; + case 210204: + return "沙河口区"; + case 210211: + return "甘井子区"; + case 210212: + return "旅顺口区"; + case 210213: + return "金州区"; + case 210224: + return "长海县"; + case 210281: + return "瓦房店市"; + case 210282: + return "普兰店市"; + case 210283: + return "庄河市"; + case 2103: + return "鞍山市"; + case 210301: + return "市辖区"; + case 210302: + return "铁东区"; + case 210303: + return "铁西区"; + case 210304: + return "立山区"; + case 210311: + return "千山区"; + case 210321: + return "台安县"; + case 210323: + return "岫岩满族自治县"; + case 210381: + return "海城市"; + case 2104: + return "抚顺市"; + case 210401: + return "市辖区"; + case 210402: + return "新抚区"; + case 210403: + return "东洲区"; + case 210404: + return "望花区"; + case 210411: + return "顺城区"; + case 210421: + return "抚顺县"; + case 210422: + return "新宾满族自治县"; + case 210423: + return "清原满族自治县"; + case 2105: + return "本溪市"; + case 210501: + return "市辖区"; + case 210502: + return "平山区"; + case 210503: + return "溪湖区"; + case 210504: + return "明山区"; + case 210505: + return "南芬区"; + case 210521: + return "本溪满族自治县"; + case 210522: + return "桓仁满族自治县"; + case 2106: + return "丹东市"; + case 210601: + return "市辖区"; + case 210602: + return "元宝区"; + case 210603: + return "振兴区"; + case 210604: + return "振安区"; + case 210624: + return "宽甸满族自治县"; + case 210681: + return "东港市"; + case 210682: + return "凤城市"; + case 2107: + return "锦州市"; + case 210701: + return "市辖区"; + case 210702: + return "古塔区"; + case 210703: + return "凌河区"; + case 210711: + return "太和区"; + case 210726: + return "黑山县"; + case 210727: + return "义县"; + case 210781: + return "凌海市"; + case 210782: + return "北镇市"; + case 2108: + return "营口市"; + case 210801: + return "市辖区"; + case 210802: + return "站前区"; + case 210803: + return "西市区"; + case 210804: + return "鲅鱼圈区"; + case 210811: + return "老边区"; + case 210881: + return "盖州市"; + case 210882: + return "大石桥市"; + case 2109: + return "阜新市"; + case 210901: + return "市辖区"; + case 210902: + return "海州区"; + case 210903: + return "新邱区"; + case 210904: + return "太平区"; + case 210905: + return "清河门区"; + case 210911: + return "细河区"; + case 210921: + return "阜新蒙古族自治县"; + case 210922: + return "彰武县"; + case 2110: + return "辽阳市"; + case 211001: + return "市辖区"; + case 211002: + return "白塔区"; + case 211003: + return "文圣区"; + case 211004: + return "宏伟区"; + case 211005: + return "弓长岭区"; + case 211011: + return "太子河区"; + case 211021: + return "辽阳县"; + case 211081: + return "灯塔市"; + case 2111: + return "盘锦市"; + case 211101: + return "市辖区"; + case 211102: + return "双台子区"; + case 211103: + return "兴隆台区"; + case 211121: + return "大洼县"; + case 211122: + return "盘山县"; + case 2112: + return "铁岭市"; + case 211201: + return "市辖区"; + case 211202: + return "银州区"; + case 211204: + return "清河区"; + case 211221: + return "铁岭县"; + case 211223: + return "西丰县"; + case 211224: + return "昌图县"; + case 211281: + return "调兵山市"; + case 211282: + return "开原市"; + case 2113: + return "朝阳市"; + case 211301: + return "市辖区"; + case 211302: + return "双塔区"; + case 211303: + return "龙城区"; + case 211321: + return "朝阳县"; + case 211322: + return "建平县"; + case 211324: + return "喀喇沁左翼蒙古族自治县"; + case 211381: + return "北票市"; + case 211382: + return "凌源市"; + case 2114: + return "葫芦岛市"; + case 211401: + return "市辖区"; + case 211402: + return "连山区"; + case 211403: + return "龙港区"; + case 211404: + return "南票区"; + case 211421: + return "绥中县"; + case 211422: + return "建昌县"; + case 211481: + return "兴城市"; + case 22: + return "吉林省"; + case 2201: + return "长春市"; + case 220101: + return "市辖区"; + case 220102: + return "南关区"; + case 220103: + return "宽城区"; + case 220104: + return "朝阳区"; + case 220105: + return "二道区"; + case 220106: + return "绿园区"; + case 220112: + return "双阳区"; + case 220113: + return "九台区"; + case 220122: + return "农安县"; + case 220182: + return "榆树市"; + case 220183: + return "德惠市"; + case 2202: + return "吉林市"; + case 220201: + return "市辖区"; + case 220202: + return "昌邑区"; + case 220203: + return "龙潭区"; + case 220204: + return "船营区"; + case 220211: + return "丰满区"; + case 220221: + return "永吉县"; + case 220281: + return "蛟河市"; + case 220282: + return "桦甸市"; + case 220283: + return "舒兰市"; + case 220284: + return "磐石市"; + case 2203: + return "四平市"; + case 220301: + return "市辖区"; + case 220302: + return "铁西区"; + case 220303: + return "铁东区"; + case 220322: + return "梨树县"; + case 220323: + return "伊通满族自治县"; + case 220381: + return "公主岭市"; + case 220382: + return "双辽市"; + case 2204: + return "辽源市"; + case 220401: + return "市辖区"; + case 220402: + return "龙山区"; + case 220403: + return "西安区"; + case 220421: + return "东丰县"; + case 220422: + return "东辽县"; + case 2205: + return "通化市"; + case 220501: + return "市辖区"; + case 220502: + return "东昌区"; + case 220503: + return "二道江区"; + case 220521: + return "通化县"; + case 220523: + return "辉南县"; + case 220524: + return "柳河县"; + case 220581: + return "梅河口市"; + case 220582: + return "集安市"; + case 2206: + return "白山市"; + case 220601: + return "市辖区"; + case 220602: + return "浑江区"; + case 220605: + return "江源区"; + case 220621: + return "抚松县"; + case 220622: + return "靖宇县"; + case 220623: + return "长白朝鲜族自治县"; + case 220681: + return "临江市"; + case 2207: + return "松原市"; + case 220701: + return "市辖区"; + case 220702: + return "宁江区"; + case 220721: + return "前郭尔罗斯蒙古族自治县"; + case 220722: + return "长岭县"; + case 220723: + return "乾安县"; + case 220781: + return "扶余市"; + case 2208: + return "白城市"; + case 220801: + return "市辖区"; + case 220802: + return "洮北区"; + case 220821: + return "镇赉县"; + case 220822: + return "通榆县"; + case 220881: + return "洮南市"; + case 220882: + return "大安市"; + case 2224: + return "延边朝鲜族自治州"; + case 222401: + return "延吉市"; + case 222402: + return "图们市"; + case 222403: + return "敦化市"; + case 222404: + return "珲春市"; + case 222405: + return "龙井市"; + case 222406: + return "和龙市"; + case 222424: + return "汪清县"; + case 222426: + return "安图县"; + case 23: + return "黑龙江省"; + case 2301: + return "哈尔滨市"; + case 230101: + return "市辖区"; + case 230102: + return "道里区"; + case 230103: + return "南岗区"; + case 230104: + return "道外区"; + case 230108: + return "平房区"; + case 230109: + return "松北区"; + case 230110: + return "香坊区"; + case 230111: + return "呼兰区"; + case 230112: + return "阿城区"; + case 230123: + return "依兰县"; + case 230124: + return "方正县"; + case 230125: + return "宾县"; + case 230126: + return "巴彦县"; + case 230127: + return "木兰县"; + case 230128: + return "通河县"; + case 230129: + return "延寿县"; + case 230182: + return "双城市"; + case 230183: + return "尚志市"; + case 230184: + return "五常市"; + case 2302: + return "齐齐哈尔市"; + case 230201: + return "市辖区"; + case 230202: + return "龙沙区"; + case 230203: + return "建华区"; + case 230204: + return "铁锋区"; + case 230205: + return "昂昂溪区"; + case 230206: + return "富拉尔基区"; + case 230207: + return "碾子山区"; + case 230208: + return "梅里斯达斡尔族区"; + case 230221: + return "龙江县"; + case 230223: + return "依安县"; + case 230224: + return "泰来县"; + case 230225: + return "甘南县"; + case 230227: + return "富裕县"; + case 230229: + return "克山县"; + case 230230: + return "克东县"; + case 230231: + return "拜泉县"; + case 230281: + return "讷河市"; + case 2303: + return "鸡西市"; + case 230301: + return "市辖区"; + case 230302: + return "鸡冠区"; + case 230303: + return "恒山区"; + case 230304: + return "滴道区"; + case 230305: + return "梨树区"; + case 230306: + return "城子河区"; + case 230307: + return "麻山区"; + case 230321: + return "鸡东县"; + case 230381: + return "虎林市"; + case 230382: + return "密山市"; + case 2304: + return "鹤岗市"; + case 230401: + return "市辖区"; + case 230402: + return "向阳区"; + case 230403: + return "工农区"; + case 230404: + return "南山区"; + case 230405: + return "兴安区"; + case 230406: + return "东山区"; + case 230407: + return "兴山区"; + case 230421: + return "萝北县"; + case 230422: + return "绥滨县"; + case 2305: + return "双鸭山市"; + case 230501: + return "市辖区"; + case 230502: + return "尖山区"; + case 230503: + return "岭东区"; + case 230505: + return "四方台区"; + case 230506: + return "宝山区"; + case 230521: + return "集贤县"; + case 230522: + return "友谊县"; + case 230523: + return "宝清县"; + case 230524: + return "饶河县"; + case 2306: + return "大庆市"; + case 230601: + return "市辖区"; + case 230602: + return "萨尔图区"; + case 230603: + return "龙凤区"; + case 230604: + return "让胡路区"; + case 230605: + return "红岗区"; + case 230606: + return "大同区"; + case 230621: + return "肇州县"; + case 230622: + return "肇源县"; + case 230623: + return "林甸县"; + case 230624: + return "杜尔伯特蒙古族自治县"; + case 2307: + return "伊春市"; + case 230701: + return "市辖区"; + case 230702: + return "伊春区"; + case 230703: + return "南岔区"; + case 230704: + return "友好区"; + case 230705: + return "西林区"; + case 230706: + return "翠峦区"; + case 230707: + return "新青区"; + case 230708: + return "美溪区"; + case 230709: + return "金山屯区"; + case 230710: + return "五营区"; + case 230711: + return "乌马河区"; + case 230712: + return "汤旺河区"; + case 230713: + return "带岭区"; + case 230714: + return "乌伊岭区"; + case 230715: + return "红星区"; + case 230716: + return "上甘岭区"; + case 230722: + return "嘉荫县"; + case 230781: + return "铁力市"; + case 2308: + return "佳木斯市"; + case 230801: + return "市辖区"; + case 230803: + return "向阳区"; + case 230804: + return "前进区"; + case 230805: + return "东风区"; + case 230811: + return "郊区"; + case 230822: + return "桦南县"; + case 230826: + return "桦川县"; + case 230828: + return "汤原县"; + case 230833: + return "抚远县"; + case 230881: + return "同江市"; + case 230882: + return "富锦市"; + case 2309: + return "七台河市"; + case 230901: + return "市辖区"; + case 230902: + return "新兴区"; + case 230903: + return "桃山区"; + case 230904: + return "茄子河区"; + case 230921: + return "勃利县"; + case 2310: + return "牡丹江市"; + case 231001: + return "市辖区"; + case 231002: + return "东安区"; + case 231003: + return "阳明区"; + case 231004: + return "爱民区"; + case 231005: + return "西安区"; + case 231024: + return "东宁县"; + case 231025: + return "林口县"; + case 231081: + return "绥芬河市"; + case 231083: + return "海林市"; + case 231084: + return "宁安市"; + case 231085: + return "穆棱市"; + case 2311: + return "黑河市"; + case 231101: + return "市辖区"; + case 231102: + return "爱辉区"; + case 231121: + return "嫩江县"; + case 231123: + return "逊克县"; + case 231124: + return "孙吴县"; + case 231181: + return "北安市"; + case 231182: + return "五大连池市"; + case 2312: + return "绥化市"; + case 231201: + return "市辖区"; + case 231202: + return "北林区"; + case 231221: + return "望奎县"; + case 231222: + return "兰西县"; + case 231223: + return "青冈县"; + case 231224: + return "庆安县"; + case 231225: + return "明水县"; + case 231226: + return "绥棱县"; + case 231281: + return "安达市"; + case 231282: + return "肇东市"; + case 231283: + return "海伦市"; + case 2327: + return "大兴安岭地区"; + case 232721: + return "呼玛县"; + case 232722: + return "塔河县"; + case 232723: + return "漠河县"; + case 31: + return "上海市"; + case 3101: + return "市辖区"; + case 310101: + return "黄浦区"; + case 310104: + return "徐汇区"; + case 310105: + return "长宁区"; + case 310106: + return "静安区"; + case 310107: + return "普陀区"; + case 310108: + return "闸北区"; + case 310109: + return "虹口区"; + case 310110: + return "杨浦区"; + case 310112: + return "闵行区"; + case 310113: + return "宝山区"; + case 310114: + return "嘉定区"; + case 310115: + return "浦东新区"; + case 310116: + return "金山区"; + case 310117: + return "松江区"; + case 310118: + return "青浦区"; + case 310120: + return "奉贤区"; + case 3102: + return "县"; + case 310230: + return "崇明县"; + case 32: + return "江苏省"; + case 3201: + return "南京市"; + case 320101: + return "市辖区"; + case 320102: + return "玄武区"; + case 320104: + return "秦淮区"; + case 320105: + return "建邺区"; + case 320106: + return "鼓楼区"; + case 320111: + return "浦口区"; + case 320113: + return "栖霞区"; + case 320114: + return "雨花台区"; + case 320115: + return "江宁区"; + case 320116: + return "六合区"; + case 320117: + return "溧水区"; + case 320118: + return "高淳区"; + case 3202: + return "无锡市"; + case 320201: + return "市辖区"; + case 320202: + return "崇安区"; + case 320203: + return "南长区"; + case 320204: + return "北塘区"; + case 320205: + return "锡山区"; + case 320206: + return "惠山区"; + case 320211: + return "滨湖区"; + case 320281: + return "江阴市"; + case 320282: + return "宜兴市"; + case 3203: + return "徐州市"; + case 320301: + return "市辖区"; + case 320302: + return "鼓楼区"; + case 320303: + return "云龙区"; + case 320305: + return "贾汪区"; + case 320311: + return "泉山区"; + case 320312: + return "铜山区"; + case 320321: + return "丰县"; + case 320322: + return "沛县"; + case 320324: + return "睢宁县"; + case 320381: + return "新沂市"; + case 320382: + return "邳州市"; + case 3204: + return "常州市"; + case 320401: + return "市辖区"; + case 320402: + return "天宁区"; + case 320404: + return "钟楼区"; + case 320405: + return "戚墅堰区"; + case 320411: + return "新北区"; + case 320412: + return "武进区"; + case 320481: + return "溧阳市"; + case 320482: + return "金坛市"; + case 3205: + return "苏州市"; + case 320501: + return "市辖区"; + case 320505: + return "虎丘区"; + case 320506: + return "吴中区"; + case 320507: + return "相城区"; + case 320508: + return "姑苏区"; + case 320509: + return "吴江区"; + case 320581: + return "常熟市"; + case 320582: + return "张家港市"; + case 320583: + return "昆山市"; + case 320585: + return "太仓市"; + case 3206: + return "南通市"; + case 320601: + return "市辖区"; + case 320602: + return "崇川区"; + case 320611: + return "港闸区"; + case 320612: + return "通州区"; + case 320621: + return "海安县"; + case 320623: + return "如东县"; + case 320681: + return "启东市"; + case 320682: + return "如皋市"; + case 320684: + return "海门市"; + case 3207: + return "连云港市"; + case 320701: + return "市辖区"; + case 320703: + return "连云区"; + case 320706: + return "海州区"; + case 320707: + return "赣榆区"; + case 320722: + return "东海县"; + case 320723: + return "灌云县"; + case 320724: + return "灌南县"; + case 3208: + return "淮安市"; + case 320801: + return "市辖区"; + case 320802: + return "清河区"; + case 320803: + return "淮安区"; + case 320804: + return "淮阴区"; + case 320811: + return "清浦区"; + case 320826: + return "涟水县"; + case 320829: + return "洪泽县"; + case 320830: + return "盱眙县"; + case 320831: + return "金湖县"; + case 3209: + return "盐城市"; + case 320901: + return "市辖区"; + case 320902: + return "亭湖区"; + case 320903: + return "盐都区"; + case 320921: + return "响水县"; + case 320922: + return "滨海县"; + case 320923: + return "阜宁县"; + case 320924: + return "射阳县"; + case 320925: + return "建湖县"; + case 320981: + return "东台市"; + case 320982: + return "大丰市"; + case 3210: + return "扬州市"; + case 321001: + return "市辖区"; + case 321002: + return "广陵区"; + case 321003: + return "邗江区"; + case 321012: + return "江都区"; + case 321023: + return "宝应县"; + case 321081: + return "仪征市"; + case 321084: + return "高邮市"; + case 3211: + return "镇江市"; + case 321101: + return "市辖区"; + case 321102: + return "京口区"; + case 321111: + return "润州区"; + case 321112: + return "丹徒区"; + case 321181: + return "丹阳市"; + case 321182: + return "扬中市"; + case 321183: + return "句容市"; + case 3212: + return "泰州市"; + case 321201: + return "市辖区"; + case 321202: + return "海陵区"; + case 321203: + return "高港区"; + case 321204: + return "姜堰区"; + case 321281: + return "兴化市"; + case 321282: + return "靖江市"; + case 321283: + return "泰兴市"; + case 3213: + return "宿迁市"; + case 321301: + return "市辖区"; + case 321302: + return "宿城区"; + case 321311: + return "宿豫区"; + case 321322: + return "沭阳县"; + case 321323: + return "泗阳县"; + case 321324: + return "泗洪县"; + case 33: + return "浙江省"; + case 3301: + return "杭州市"; + case 330101: + return "市辖区"; + case 330102: + return "上城区"; + case 330103: + return "下城区"; + case 330104: + return "江干区"; + case 330105: + return "拱墅区"; + case 330106: + return "西湖区"; + case 330108: + return "滨江区"; + case 330109: + return "萧山区"; + case 330110: + return "余杭区"; + case 330122: + return "桐庐县"; + case 330127: + return "淳安县"; + case 330182: + return "建德市"; + case 330183: + return "富阳市"; + case 330185: + return "临安市"; + case 3302: + return "宁波市"; + case 330201: + return "市辖区"; + case 330203: + return "海曙区"; + case 330204: + return "江东区"; + case 330205: + return "江北区"; + case 330206: + return "北仑区"; + case 330211: + return "镇海区"; + case 330212: + return "鄞州区"; + case 330225: + return "象山县"; + case 330226: + return "宁海县"; + case 330281: + return "余姚市"; + case 330282: + return "慈溪市"; + case 330283: + return "奉化市"; + case 3303: + return "温州市"; + case 330301: + return "市辖区"; + case 330302: + return "鹿城区"; + case 330303: + return "龙湾区"; + case 330304: + return "瓯海区"; + case 330322: + return "洞头县"; + case 330324: + return "永嘉县"; + case 330326: + return "平阳县"; + case 330327: + return "苍南县"; + case 330328: + return "文成县"; + case 330329: + return "泰顺县"; + case 330381: + return "瑞安市"; + case 330382: + return "乐清市"; + case 3304: + return "嘉兴市"; + case 330401: + return "市辖区"; + case 330402: + return "南湖区"; + case 330411: + return "秀洲区"; + case 330421: + return "嘉善县"; + case 330424: + return "海盐县"; + case 330481: + return "海宁市"; + case 330482: + return "平湖市"; + case 330483: + return "桐乡市"; + case 3305: + return "湖州市"; + case 330501: + return "市辖区"; + case 330502: + return "吴兴区"; + case 330503: + return "南浔区"; + case 330521: + return "德清县"; + case 330522: + return "长兴县"; + case 330523: + return "安吉县"; + case 3306: + return "绍兴市"; + case 330601: + return "市辖区"; + case 330602: + return "越城区"; + case 330603: + return "柯桥区"; + case 330604: + return "上虞区"; + case 330624: + return "新昌县"; + case 330681: + return "诸暨市"; + case 330683: + return "嵊州市"; + case 3307: + return "金华市"; + case 330701: + return "市辖区"; + case 330702: + return "婺城区"; + case 330703: + return "金东区"; + case 330723: + return "武义县"; + case 330726: + return "浦江县"; + case 330727: + return "磐安县"; + case 330781: + return "兰溪市"; + case 330782: + return "义乌市"; + case 330783: + return "东阳市"; + case 330784: + return "永康市"; + case 3308: + return "衢州市"; + case 330801: + return "市辖区"; + case 330802: + return "柯城区"; + case 330803: + return "衢江区"; + case 330822: + return "常山县"; + case 330824: + return "开化县"; + case 330825: + return "龙游县"; + case 330881: + return "江山市"; + case 3309: + return "舟山市"; + case 330901: + return "市辖区"; + case 330902: + return "定海区"; + case 330903: + return "普陀区"; + case 330921: + return "岱山县"; + case 330922: + return "嵊泗县"; + case 3310: + return "台州市"; + case 331001: + return "市辖区"; + case 331002: + return "椒江区"; + case 331003: + return "黄岩区"; + case 331004: + return "路桥区"; + case 331021: + return "玉环县"; + case 331022: + return "三门县"; + case 331023: + return "天台县"; + case 331024: + return "仙居县"; + case 331081: + return "温岭市"; + case 331082: + return "临海市"; + case 3311: + return "丽水市"; + case 331101: + return "市辖区"; + case 331102: + return "莲都区"; + case 331121: + return "青田县"; + case 331122: + return "缙云县"; + case 331123: + return "遂昌县"; + case 331124: + return "松阳县"; + case 331125: + return "云和县"; + case 331126: + return "庆元县"; + case 331127: + return "景宁畲族自治县"; + case 331181: + return "龙泉市"; + case 34: + return "安徽省"; + case 3401: + return "合肥市"; + case 340101: + return "市辖区"; + case 340102: + return "瑶海区"; + case 340103: + return "庐阳区"; + case 340104: + return "蜀山区"; + case 340111: + return "包河区"; + case 340121: + return "长丰县"; + case 340122: + return "肥东县"; + case 340123: + return "肥西县"; + case 340124: + return "庐江县"; + case 340181: + return "巢湖市"; + case 3402: + return "芜湖市"; + case 340201: + return "市辖区"; + case 340202: + return "镜湖区"; + case 340203: + return "弋江区"; + case 340207: + return "鸠江区"; + case 340208: + return "三山区"; + case 340221: + return "芜湖县"; + case 340222: + return "繁昌县"; + case 340223: + return "南陵县"; + case 340225: + return "无为县"; + case 3403: + return "蚌埠市"; + case 340301: + return "市辖区"; + case 340302: + return "龙子湖区"; + case 340303: + return "蚌山区"; + case 340304: + return "禹会区"; + case 340311: + return "淮上区"; + case 340321: + return "怀远县"; + case 340322: + return "五河县"; + case 340323: + return "固镇县"; + case 3404: + return "淮南市"; + case 340401: + return "市辖区"; + case 340402: + return "大通区"; + case 340403: + return "田家庵区"; + case 340404: + return "谢家集区"; + case 340405: + return "八公山区"; + case 340406: + return "潘集区"; + case 340421: + return "凤台县"; + case 3405: + return "马鞍山市"; + case 340501: + return "市辖区"; + case 340503: + return "花山区"; + case 340504: + return "雨山区"; + case 340506: + return "博望区"; + case 340521: + return "当涂县"; + case 340522: + return "含山县"; + case 340523: + return "和县"; + case 3406: + return "淮北市"; + case 340601: + return "市辖区"; + case 340602: + return "杜集区"; + case 340603: + return "相山区"; + case 340604: + return "烈山区"; + case 340621: + return "濉溪县"; + case 3407: + return "铜陵市"; + case 340701: + return "市辖区"; + case 340702: + return "铜官山区"; + case 340703: + return "狮子山区"; + case 340711: + return "郊区"; + case 340721: + return "铜陵县"; + case 3408: + return "安庆市"; + case 340801: + return "市辖区"; + case 340802: + return "迎江区"; + case 340803: + return "大观区"; + case 340811: + return "宜秀区"; + case 340822: + return "怀宁县"; + case 340823: + return "枞阳县"; + case 340824: + return "潜山县"; + case 340825: + return "太湖县"; + case 340826: + return "宿松县"; + case 340827: + return "望江县"; + case 340828: + return "岳西县"; + case 340881: + return "桐城市"; + case 3410: + return "黄山市"; + case 341001: + return "市辖区"; + case 341002: + return "屯溪区"; + case 341003: + return "黄山区"; + case 341004: + return "徽州区"; + case 341021: + return "歙县"; + case 341022: + return "休宁县"; + case 341023: + return "黟县"; + case 341024: + return "祁门县"; + case 3411: + return "滁州市"; + case 341101: + return "市辖区"; + case 341102: + return "琅琊区"; + case 341103: + return "南谯区"; + case 341122: + return "来安县"; + case 341124: + return "全椒县"; + case 341125: + return "定远县"; + case 341126: + return "凤阳县"; + case 341181: + return "天长市"; + case 341182: + return "明光市"; + case 3412: + return "阜阳市"; + case 341201: + return "市辖区"; + case 341202: + return "颍州区"; + case 341203: + return "颍东区"; + case 341204: + return "颍泉区"; + case 341221: + return "临泉县"; + case 341222: + return "太和县"; + case 341225: + return "阜南县"; + case 341226: + return "颍上县"; + case 341282: + return "界首市"; + case 3413: + return "宿州市"; + case 341301: + return "市辖区"; + case 341302: + return "埇桥区"; + case 341321: + return "砀山县"; + case 341322: + return "萧县"; + case 341323: + return "灵璧县"; + case 341324: + return "泗县"; + case 3415: + return "六安市"; + case 341501: + return "市辖区"; + case 341502: + return "金安区"; + case 341503: + return "裕安区"; + case 341521: + return "寿县"; + case 341522: + return "霍邱县"; + case 341523: + return "舒城县"; + case 341524: + return "金寨县"; + case 341525: + return "霍山县"; + case 3416: + return "亳州市"; + case 341601: + return "市辖区"; + case 341602: + return "谯城区"; + case 341621: + return "涡阳县"; + case 341622: + return "蒙城县"; + case 341623: + return "利辛县"; + case 3417: + return "池州市"; + case 341701: + return "市辖区"; + case 341702: + return "贵池区"; + case 341721: + return "东至县"; + case 341722: + return "石台县"; + case 341723: + return "青阳县"; + case 3418: + return "宣城市"; + case 341801: + return "市辖区"; + case 341802: + return "宣州区"; + case 341821: + return "郎溪县"; + case 341822: + return "广德县"; + case 341823: + return "泾县"; + case 341824: + return "绩溪县"; + case 341825: + return "旌德县"; + case 341881: + return "宁国市"; + case 35: + return "福建省"; + case 3501: + return "福州市"; + case 350101: + return "市辖区"; + case 350102: + return "鼓楼区"; + case 350103: + return "台江区"; + case 350104: + return "仓山区"; + case 350105: + return "马尾区"; + case 350111: + return "晋安区"; + case 350121: + return "闽侯县"; + case 350122: + return "连江县"; + case 350123: + return "罗源县"; + case 350124: + return "闽清县"; + case 350125: + return "永泰县"; + case 350128: + return "平潭县"; + case 350181: + return "福清市"; + case 350182: + return "长乐市"; + case 3502: + return "厦门市"; + case 350201: + return "市辖区"; + case 350203: + return "思明区"; + case 350205: + return "海沧区"; + case 350206: + return "湖里区"; + case 350211: + return "集美区"; + case 350212: + return "同安区"; + case 350213: + return "翔安区"; + case 3503: + return "莆田市"; + case 350301: + return "市辖区"; + case 350302: + return "城厢区"; + case 350303: + return "涵江区"; + case 350304: + return "荔城区"; + case 350305: + return "秀屿区"; + case 350322: + return "仙游县"; + case 3504: + return "三明市"; + case 350401: + return "市辖区"; + case 350402: + return "梅列区"; + case 350403: + return "三元区"; + case 350421: + return "明溪县"; + case 350423: + return "清流县"; + case 350424: + return "宁化县"; + case 350425: + return "大田县"; + case 350426: + return "尤溪县"; + case 350427: + return "沙县"; + case 350428: + return "将乐县"; + case 350429: + return "泰宁县"; + case 350430: + return "建宁县"; + case 350481: + return "永安市"; + case 3505: + return "泉州市"; + case 350501: + return "市辖区"; + case 350502: + return "鲤城区"; + case 350503: + return "丰泽区"; + case 350504: + return "洛江区"; + case 350505: + return "泉港区"; + case 350521: + return "惠安县"; + case 350524: + return "安溪县"; + case 350525: + return "永春县"; + case 350526: + return "德化县"; + case 350527: + return "金门县"; + case 350581: + return "石狮市"; + case 350582: + return "晋江市"; + case 350583: + return "南安市"; + case 3506: + return "漳州市"; + case 350601: + return "市辖区"; + case 350602: + return "芗城区"; + case 350603: + return "龙文区"; + case 350622: + return "云霄县"; + case 350623: + return "漳浦县"; + case 350624: + return "诏安县"; + case 350625: + return "长泰县"; + case 350626: + return "东山县"; + case 350627: + return "南靖县"; + case 350628: + return "平和县"; + case 350629: + return "华安县"; + case 350681: + return "龙海市"; + case 3507: + return "南平市"; + case 350701: + return "市辖区"; + case 350702: + return "延平区"; + case 350721: + return "顺昌县"; + case 350722: + return "浦城县"; + case 350723: + return "光泽县"; + case 350724: + return "松溪县"; + case 350725: + return "政和县"; + case 350781: + return "邵武市"; + case 350782: + return "武夷山市"; + case 350783: + return "建瓯市"; + case 350784: + return "建阳市"; + case 3508: + return "龙岩市"; + case 350801: + return "市辖区"; + case 350802: + return "新罗区"; + case 350821: + return "长汀县"; + case 350822: + return "永定县"; + case 350823: + return "上杭县"; + case 350824: + return "武平县"; + case 350825: + return "连城县"; + case 350881: + return "漳平市"; + case 3509: + return "宁德市"; + case 350901: + return "市辖区"; + case 350902: + return "蕉城区"; + case 350921: + return "霞浦县"; + case 350922: + return "古田县"; + case 350923: + return "屏南县"; + case 350924: + return "寿宁县"; + case 350925: + return "周宁县"; + case 350926: + return "柘荣县"; + case 350981: + return "福安市"; + case 350982: + return "福鼎市"; + case 36: + return "江西省"; + case 3601: + return "南昌市"; + case 360101: + return "市辖区"; + case 360102: + return "东湖区"; + case 360103: + return "西湖区"; + case 360104: + return "青云谱区"; + case 360105: + return "湾里区"; + case 360111: + return "青山湖区"; + case 360121: + return "南昌县"; + case 360122: + return "新建县"; + case 360123: + return "安义县"; + case 360124: + return "进贤县"; + case 3602: + return "景德镇市"; + case 360201: + return "市辖区"; + case 360202: + return "昌江区"; + case 360203: + return "珠山区"; + case 360222: + return "浮梁县"; + case 360281: + return "乐平市"; + case 3603: + return "萍乡市"; + case 360301: + return "市辖区"; + case 360302: + return "安源区"; + case 360313: + return "湘东区"; + case 360321: + return "莲花县"; + case 360322: + return "上栗县"; + case 360323: + return "芦溪县"; + case 3604: + return "九江市"; + case 360401: + return "市辖区"; + case 360402: + return "庐山区"; + case 360403: + return "浔阳区"; + case 360421: + return "九江县"; + case 360423: + return "武宁县"; + case 360424: + return "修水县"; + case 360425: + return "永修县"; + case 360426: + return "德安县"; + case 360427: + return "星子县"; + case 360428: + return "都昌县"; + case 360429: + return "湖口县"; + case 360430: + return "彭泽县"; + case 360481: + return "瑞昌市"; + case 360482: + return "共青城市"; + case 3605: + return "新余市"; + case 360501: + return "市辖区"; + case 360502: + return "渝水区"; + case 360521: + return "分宜县"; + case 3606: + return "鹰潭市"; + case 360601: + return "市辖区"; + case 360602: + return "月湖区"; + case 360622: + return "余江县"; + case 360681: + return "贵溪市"; + case 3607: + return "赣州市"; + case 360701: + return "市辖区"; + case 360702: + return "章贡区"; + case 360703: + return "南康区"; + case 360721: + return "赣县"; + case 360722: + return "信丰县"; + case 360723: + return "大余县"; + case 360724: + return "上犹县"; + case 360725: + return "崇义县"; + case 360726: + return "安远县"; + case 360727: + return "龙南县"; + case 360728: + return "定南县"; + case 360729: + return "全南县"; + case 360730: + return "宁都县"; + case 360731: + return "于都县"; + case 360732: + return "兴国县"; + case 360733: + return "会昌县"; + case 360734: + return "寻乌县"; + case 360735: + return "石城县"; + case 360781: + return "瑞金市"; + case 3608: + return "吉安市"; + case 360801: + return "市辖区"; + case 360802: + return "吉州区"; + case 360803: + return "青原区"; + case 360821: + return "吉安县"; + case 360822: + return "吉水县"; + case 360823: + return "峡江县"; + case 360824: + return "新干县"; + case 360825: + return "永丰县"; + case 360826: + return "泰和县"; + case 360827: + return "遂川县"; + case 360828: + return "万安县"; + case 360829: + return "安福县"; + case 360830: + return "永新县"; + case 360881: + return "井冈山市"; + case 3609: + return "宜春市"; + case 360901: + return "市辖区"; + case 360902: + return "袁州区"; + case 360921: + return "奉新县"; + case 360922: + return "万载县"; + case 360923: + return "上高县"; + case 360924: + return "宜丰县"; + case 360925: + return "靖安县"; + case 360926: + return "铜鼓县"; + case 360981: + return "丰城市"; + case 360982: + return "樟树市"; + case 360983: + return "高安市"; + case 3610: + return "抚州市"; + case 361001: + return "市辖区"; + case 361002: + return "临川区"; + case 361021: + return "南城县"; + case 361022: + return "黎川县"; + case 361023: + return "南丰县"; + case 361024: + return "崇仁县"; + case 361025: + return "乐安县"; + case 361026: + return "宜黄县"; + case 361027: + return "金溪县"; + case 361028: + return "资溪县"; + case 361029: + return "东乡县"; + case 361030: + return "广昌县"; + case 3611: + return "上饶市"; + case 361101: + return "市辖区"; + case 361102: + return "信州区"; + case 361121: + return "上饶县"; + case 361122: + return "广丰县"; + case 361123: + return "玉山县"; + case 361124: + return "铅山县"; + case 361125: + return "横峰县"; + case 361126: + return "弋阳县"; + case 361127: + return "余干县"; + case 361128: + return "鄱阳县"; + case 361129: + return "万年县"; + case 361130: + return "婺源县"; + case 361181: + return "德兴市"; + case 37: + return "山东省"; + case 3701: + return "济南市"; + case 370101: + return "市辖区"; + case 370102: + return "历下区"; + case 370103: + return "市中区"; + case 370104: + return "槐荫区"; + case 370105: + return "天桥区"; + case 370112: + return "历城区"; + case 370113: + return "长清区"; + case 370124: + return "平阴县"; + case 370125: + return "济阳县"; + case 370126: + return "商河县"; + case 370181: + return "章丘市"; + case 3702: + return "青岛市"; + case 370201: + return "市辖区"; + case 370202: + return "市南区"; + case 370203: + return "市北区"; + case 370211: + return "黄岛区"; + case 370212: + return "崂山区"; + case 370213: + return "李沧区"; + case 370214: + return "城阳区"; + case 370281: + return "胶州市"; + case 370282: + return "即墨市"; + case 370283: + return "平度市"; + case 370285: + return "莱西市"; + case 3703: + return "淄博市"; + case 370301: + return "市辖区"; + case 370302: + return "淄川区"; + case 370303: + return "张店区"; + case 370304: + return "博山区"; + case 370305: + return "临淄区"; + case 370306: + return "周村区"; + case 370321: + return "桓台县"; + case 370322: + return "高青县"; + case 370323: + return "沂源县"; + case 3704: + return "枣庄市"; + case 370401: + return "市辖区"; + case 370402: + return "市中区"; + case 370403: + return "薛城区"; + case 370404: + return "峄城区"; + case 370405: + return "台儿庄区"; + case 370406: + return "山亭区"; + case 370481: + return "滕州市"; + case 3705: + return "东营市"; + case 370501: + return "市辖区"; + case 370502: + return "东营区"; + case 370503: + return "河口区"; + case 370521: + return "垦利县"; + case 370522: + return "利津县"; + case 370523: + return "广饶县"; + case 3706: + return "烟台市"; + case 370601: + return "市辖区"; + case 370602: + return "芝罘区"; + case 370611: + return "福山区"; + case 370612: + return "牟平区"; + case 370613: + return "莱山区"; + case 370634: + return "长岛县"; + case 370681: + return "龙口市"; + case 370682: + return "莱阳市"; + case 370683: + return "莱州市"; + case 370684: + return "蓬莱市"; + case 370685: + return "招远市"; + case 370686: + return "栖霞市"; + case 370687: + return "海阳市"; + case 3707: + return "潍坊市"; + case 370701: + return "市辖区"; + case 370702: + return "潍城区"; + case 370703: + return "寒亭区"; + case 370704: + return "坊子区"; + case 370705: + return "奎文区"; + case 370724: + return "临朐县"; + case 370725: + return "昌乐县"; + case 370781: + return "青州市"; + case 370782: + return "诸城市"; + case 370783: + return "寿光市"; + case 370784: + return "安丘市"; + case 370785: + return "高密市"; + case 370786: + return "昌邑市"; + case 3708: + return "济宁市"; + case 370801: + return "市辖区"; + case 370811: + return "任城区"; + case 370812: + return "兖州区"; + case 370826: + return "微山县"; + case 370827: + return "鱼台县"; + case 370828: + return "金乡县"; + case 370829: + return "嘉祥县"; + case 370830: + return "汶上县"; + case 370831: + return "泗水县"; + case 370832: + return "梁山县"; + case 370881: + return "曲阜市"; + case 370883: + return "邹城市"; + case 3709: + return "泰安市"; + case 370901: + return "市辖区"; + case 370902: + return "泰山区"; + case 370911: + return "岱岳区"; + case 370921: + return "宁阳县"; + case 370923: + return "东平县"; + case 370982: + return "新泰市"; + case 370983: + return "肥城市"; + case 3710: + return "威海市"; + case 371001: + return "市辖区"; + case 371002: + return "环翠区"; + case 371003: + return "文登区"; + case 371082: + return "荣成市"; + case 371083: + return "乳山市"; + case 3711: + return "日照市"; + case 371101: + return "市辖区"; + case 371102: + return "东港区"; + case 371103: + return "岚山区"; + case 371121: + return "五莲县"; + case 371122: + return "莒县"; + case 3712: + return "莱芜市"; + case 371201: + return "市辖区"; + case 371202: + return "莱城区"; + case 371203: + return "钢城区"; + case 3713: + return "临沂市"; + case 371301: + return "市辖区"; + case 371302: + return "兰山区"; + case 371311: + return "罗庄区"; + case 371312: + return "河东区"; + case 371321: + return "沂南县"; + case 371322: + return "郯城县"; + case 371323: + return "沂水县"; + case 371324: + return "兰陵县"; + case 371325: + return "费县"; + case 371326: + return "平邑县"; + case 371327: + return "莒南县"; + case 371328: + return "蒙阴县"; + case 371329: + return "临沭县"; + case 3714: + return "德州市"; + case 371401: + return "市辖区"; + case 371402: + return "德城区"; + case 371403: + return "陵城区"; + case 371422: + return "宁津县"; + case 371423: + return "庆云县"; + case 371424: + return "临邑县"; + case 371425: + return "齐河县"; + case 371426: + return "平原县"; + case 371427: + return "夏津县"; + case 371428: + return "武城县"; + case 371481: + return "乐陵市"; + case 371482: + return "禹城市"; + case 3715: + return "聊城市"; + case 371501: + return "市辖区"; + case 371502: + return "东昌府区"; + case 371521: + return "阳谷县"; + case 371522: + return "莘县"; + case 371523: + return "茌平县"; + case 371524: + return "东阿县"; + case 371525: + return "冠县"; + case 371526: + return "高唐县"; + case 371581: + return "临清市"; + case 3716: + return "滨州市"; + case 371601: + return "市辖区"; + case 371602: + return "滨城区"; + case 371603: + return "沾化区"; + case 371621: + return "惠民县"; + case 371622: + return "阳信县"; + case 371623: + return "无棣县"; + case 371625: + return "博兴县"; + case 371626: + return "邹平县"; + case 3717: + return "菏泽市"; + case 371701: + return "市辖区"; + case 371702: + return "牡丹区"; + case 371721: + return "曹县"; + case 371722: + return "单县"; + case 371723: + return "成武县"; + case 371724: + return "巨野县"; + case 371725: + return "郓城县"; + case 371726: + return "鄄城县"; + case 371727: + return "定陶县"; + case 371728: + return "东明县"; + case 41: + return "河南省"; + case 4101: + return "郑州市"; + case 410101: + return "市辖区"; + case 410102: + return "中原区"; + case 410103: + return "二七区"; + case 410104: + return "管城回族区"; + case 410105: + return "金水区"; + case 410106: + return "上街区"; + case 410108: + return "惠济区"; + case 410122: + return "中牟县"; + case 410181: + return "巩义市"; + case 410182: + return "荥阳市"; + case 410183: + return "新密市"; + case 410184: + return "新郑市"; + case 410185: + return "登封市"; + case 4102: + return "开封市"; + case 410201: + return "市辖区"; + case 410202: + return "龙亭区"; + case 410203: + return "顺河回族区"; + case 410204: + return "鼓楼区"; + case 410205: + return "禹王台区"; + case 410211: + return "金明区"; + case 410221: + return "杞县"; + case 410222: + return "通许县"; + case 410223: + return "尉氏县"; + case 410224: + return "开封县"; + case 410225: + return "兰考县"; + case 4103: + return "洛阳市"; + case 410301: + return "市辖区"; + case 410302: + return "老城区"; + case 410303: + return "西工区"; + case 410304: + return "瀍河回族区"; + case 410305: + return "涧西区"; + case 410306: + return "吉利区"; + case 410311: + return "洛龙区"; + case 410322: + return "孟津县"; + case 410323: + return "新安县"; + case 410324: + return "栾川县"; + case 410325: + return "嵩县"; + case 410326: + return "汝阳县"; + case 410327: + return "宜阳县"; + case 410328: + return "洛宁县"; + case 410329: + return "伊川县"; + case 410381: + return "偃师市"; + case 4104: + return "平顶山市"; + case 410401: + return "市辖区"; + case 410402: + return "新华区"; + case 410403: + return "卫东区"; + case 410404: + return "石龙区"; + case 410411: + return "湛河区"; + case 410421: + return "宝丰县"; + case 410422: + return "叶县"; + case 410423: + return "鲁山县"; + case 410425: + return "郏县"; + case 410481: + return "舞钢市"; + case 410482: + return "汝州市"; + case 4105: + return "安阳市"; + case 410501: + return "市辖区"; + case 410502: + return "文峰区"; + case 410503: + return "北关区"; + case 410505: + return "殷都区"; + case 410506: + return "龙安区"; + case 410522: + return "安阳县"; + case 410523: + return "汤阴县"; + case 410526: + return "滑县"; + case 410527: + return "内黄县"; + case 410581: + return "林州市"; + case 4106: + return "鹤壁市"; + case 410601: + return "市辖区"; + case 410602: + return "鹤山区"; + case 410603: + return "山城区"; + case 410611: + return "淇滨区"; + case 410621: + return "浚县"; + case 410622: + return "淇县"; + case 4107: + return "新乡市"; + case 410701: + return "市辖区"; + case 410702: + return "红旗区"; + case 410703: + return "卫滨区"; + case 410704: + return "凤泉区"; + case 410711: + return "牧野区"; + case 410721: + return "新乡县"; + case 410724: + return "获嘉县"; + case 410725: + return "原阳县"; + case 410726: + return "延津县"; + case 410727: + return "封丘县"; + case 410728: + return "长垣县"; + case 410781: + return "卫辉市"; + case 410782: + return "辉县市"; + case 4108: + return "焦作市"; + case 410801: + return "市辖区"; + case 410802: + return "解放区"; + case 410803: + return "中站区"; + case 410804: + return "马村区"; + case 410811: + return "山阳区"; + case 410821: + return "修武县"; + case 410822: + return "博爱县"; + case 410823: + return "武陟县"; + case 410825: + return "温县"; + case 410882: + return "沁阳市"; + case 410883: + return "孟州市"; + case 4109: + return "濮阳市"; + case 410901: + return "市辖区"; + case 410902: + return "华龙区"; + case 410922: + return "清丰县"; + case 410923: + return "南乐县"; + case 410926: + return "范县"; + case 410927: + return "台前县"; + case 410928: + return "濮阳县"; + case 4110: + return "许昌市"; + case 411001: + return "市辖区"; + case 411002: + return "魏都区"; + case 411023: + return "许昌县"; + case 411024: + return "鄢陵县"; + case 411025: + return "襄城县"; + case 411081: + return "禹州市"; + case 411082: + return "长葛市"; + case 4111: + return "漯河市"; + case 411101: + return "市辖区"; + case 411102: + return "源汇区"; + case 411103: + return "郾城区"; + case 411104: + return "召陵区"; + case 411121: + return "舞阳县"; + case 411122: + return "临颍县"; + case 4112: + return "三门峡市"; + case 411201: + return "市辖区"; + case 411202: + return "湖滨区"; + case 411221: + return "渑池县"; + case 411222: + return "陕县"; + case 411224: + return "卢氏县"; + case 411281: + return "义马市"; + case 411282: + return "灵宝市"; + case 4113: + return "南阳市"; + case 411301: + return "市辖区"; + case 411302: + return "宛城区"; + case 411303: + return "卧龙区"; + case 411321: + return "南召县"; + case 411322: + return "方城县"; + case 411323: + return "西峡县"; + case 411324: + return "镇平县"; + case 411325: + return "内乡县"; + case 411326: + return "淅川县"; + case 411327: + return "社旗县"; + case 411328: + return "唐河县"; + case 411329: + return "新野县"; + case 411330: + return "桐柏县"; + case 411381: + return "邓州市"; + case 4114: + return "商丘市"; + case 411401: + return "市辖区"; + case 411402: + return "梁园区"; + case 411403: + return "睢阳区"; + case 411421: + return "民权县"; + case 411422: + return "睢县"; + case 411423: + return "宁陵县"; + case 411424: + return "柘城县"; + case 411425: + return "虞城县"; + case 411426: + return "夏邑县"; + case 411481: + return "永城市"; + case 4115: + return "信阳市"; + case 411501: + return "市辖区"; + case 411502: + return "浉河区"; + case 411503: + return "平桥区"; + case 411521: + return "罗山县"; + case 411522: + return "光山县"; + case 411523: + return "新县"; + case 411524: + return "商城县"; + case 411525: + return "固始县"; + case 411526: + return "潢川县"; + case 411527: + return "淮滨县"; + case 411528: + return "息县"; + case 4116: + return "周口市"; + case 411601: + return "市辖区"; + case 411602: + return "川汇区"; + case 411621: + return "扶沟县"; + case 411622: + return "西华县"; + case 411623: + return "商水县"; + case 411624: + return "沈丘县"; + case 411625: + return "郸城县"; + case 411626: + return "淮阳县"; + case 411627: + return "太康县"; + case 411628: + return "鹿邑县"; + case 411681: + return "项城市"; + case 4117: + return "驻马店市"; + case 411701: + return "市辖区"; + case 411702: + return "驿城区"; + case 411721: + return "西平县"; + case 411722: + return "上蔡县"; + case 411723: + return "平舆县"; + case 411724: + return "正阳县"; + case 411725: + return "确山县"; + case 411726: + return "泌阳县"; + case 411727: + return "汝南县"; + case 411728: + return "遂平县"; + case 411729: + return "新蔡县"; + case 4190: + return "省直辖县级行政区划"; + case 419001: + return "济源市"; + case 42: + return "湖北省"; + case 4201: + return "武汉市"; + case 420101: + return "市辖区"; + case 420102: + return "江岸区"; + case 420103: + return "江汉区"; + case 420104: + return "硚口区"; + case 420105: + return "汉阳区"; + case 420106: + return "武昌区"; + case 420107: + return "青山区"; + case 420111: + return "洪山区"; + case 420112: + return "东西湖区"; + case 420113: + return "汉南区"; + case 420114: + return "蔡甸区"; + case 420115: + return "江夏区"; + case 420116: + return "黄陂区"; + case 420117: + return "新洲区"; + case 4202: + return "黄石市"; + case 420201: + return "市辖区"; + case 420202: + return "黄石港区"; + case 420203: + return "西塞山区"; + case 420204: + return "下陆区"; + case 420205: + return "铁山区"; + case 420222: + return "阳新县"; + case 420281: + return "大冶市"; + case 4203: + return "十堰市"; + case 420301: + return "市辖区"; + case 420302: + return "茅箭区"; + case 420303: + return "张湾区"; + case 420304: + return "郧阳区"; + case 420322: + return "郧西县"; + case 420323: + return "竹山县"; + case 420324: + return "竹溪县"; + case 420325: + return "房县"; + case 420381: + return "丹江口市"; + case 4205: + return "宜昌市"; + case 420501: + return "市辖区"; + case 420502: + return "西陵区"; + case 420503: + return "伍家岗区"; + case 420504: + return "点军区"; + case 420505: + return "猇亭区"; + case 420506: + return "夷陵区"; + case 420525: + return "远安县"; + case 420526: + return "兴山县"; + case 420527: + return "秭归县"; + case 420528: + return "长阳土家族自治县"; + case 420529: + return "五峰土家族自治县"; + case 420581: + return "宜都市"; + case 420582: + return "当阳市"; + case 420583: + return "枝江市"; + case 4206: + return "襄阳市"; + case 420601: + return "市辖区"; + case 420602: + return "襄城区"; + case 420606: + return "樊城区"; + case 420607: + return "襄州区"; + case 420624: + return "南漳县"; + case 420625: + return "谷城县"; + case 420626: + return "保康县"; + case 420682: + return "老河口市"; + case 420683: + return "枣阳市"; + case 420684: + return "宜城市"; + case 4207: + return "鄂州市"; + case 420701: + return "市辖区"; + case 420702: + return "梁子湖区"; + case 420703: + return "华容区"; + case 420704: + return "鄂城区"; + case 4208: + return "荆门市"; + case 420801: + return "市辖区"; + case 420802: + return "东宝区"; + case 420804: + return "掇刀区"; + case 420821: + return "京山县"; + case 420822: + return "沙洋县"; + case 420881: + return "钟祥市"; + case 4209: + return "孝感市"; + case 420901: + return "市辖区"; + case 420902: + return "孝南区"; + case 420921: + return "孝昌县"; + case 420922: + return "大悟县"; + case 420923: + return "云梦县"; + case 420981: + return "应城市"; + case 420982: + return "安陆市"; + case 420984: + return "汉川市"; + case 4210: + return "荆州市"; + case 421001: + return "市辖区"; + case 421002: + return "沙市区"; + case 421003: + return "荆州区"; + case 421022: + return "公安县"; + case 421023: + return "监利县"; + case 421024: + return "江陵县"; + case 421081: + return "石首市"; + case 421083: + return "洪湖市"; + case 421087: + return "松滋市"; + case 4211: + return "黄冈市"; + case 421101: + return "市辖区"; + case 421102: + return "黄州区"; + case 421121: + return "团风县"; + case 421122: + return "红安县"; + case 421123: + return "罗田县"; + case 421124: + return "英山县"; + case 421125: + return "浠水县"; + case 421126: + return "蕲春县"; + case 421127: + return "黄梅县"; + case 421181: + return "麻城市"; + case 421182: + return "武穴市"; + case 4212: + return "咸宁市"; + case 421201: + return "市辖区"; + case 421202: + return "咸安区"; + case 421221: + return "嘉鱼县"; + case 421222: + return "通城县"; + case 421223: + return "崇阳县"; + case 421224: + return "通山县"; + case 421281: + return "赤壁市"; + case 4213: + return "随州市"; + case 421301: + return "市辖区"; + case 421303: + return "曾都区"; + case 421321: + return "随县"; + case 421381: + return "广水市"; + case 4228: + return "恩施土家族苗族自治州"; + case 422801: + return "恩施市"; + case 422802: + return "利川市"; + case 422822: + return "建始县"; + case 422823: + return "巴东县"; + case 422825: + return "宣恩县"; + case 422826: + return "咸丰县"; + case 422827: + return "来凤县"; + case 422828: + return "鹤峰县"; + case 4290: + return "省直辖县级行政区划"; + case 429004: + return "仙桃市"; + case 429005: + return "潜江市"; + case 429006: + return "天门市"; + case 429021: + return "神农架林区"; + case 43: + return "湖南省"; + case 4301: + return "长沙市"; + case 430101: + return "市辖区"; + case 430102: + return "芙蓉区"; + case 430103: + return "天心区"; + case 430104: + return "岳麓区"; + case 430105: + return "开福区"; + case 430111: + return "雨花区"; + case 430112: + return "望城区"; + case 430121: + return "长沙县"; + case 430124: + return "宁乡县"; + case 430181: + return "浏阳市"; + case 4302: + return "株洲市"; + case 430201: + return "市辖区"; + case 430202: + return "荷塘区"; + case 430203: + return "芦淞区"; + case 430204: + return "石峰区"; + case 430211: + return "天元区"; + case 430221: + return "株洲县"; + case 430223: + return "攸县"; + case 430224: + return "茶陵县"; + case 430225: + return "炎陵县"; + case 430281: + return "醴陵市"; + case 4303: + return "湘潭市"; + case 430301: + return "市辖区"; + case 430302: + return "雨湖区"; + case 430304: + return "岳塘区"; + case 430321: + return "湘潭县"; + case 430381: + return "湘乡市"; + case 430382: + return "韶山市"; + case 4304: + return "衡阳市"; + case 430401: + return "市辖区"; + case 430405: + return "珠晖区"; + case 430406: + return "雁峰区"; + case 430407: + return "石鼓区"; + case 430408: + return "蒸湘区"; + case 430412: + return "南岳区"; + case 430421: + return "衡阳县"; + case 430422: + return "衡南县"; + case 430423: + return "衡山县"; + case 430424: + return "衡东县"; + case 430426: + return "祁东县"; + case 430481: + return "耒阳市"; + case 430482: + return "常宁市"; + case 4305: + return "邵阳市"; + case 430501: + return "市辖区"; + case 430502: + return "双清区"; + case 430503: + return "大祥区"; + case 430511: + return "北塔区"; + case 430521: + return "邵东县"; + case 430522: + return "新邵县"; + case 430523: + return "邵阳县"; + case 430524: + return "隆回县"; + case 430525: + return "洞口县"; + case 430527: + return "绥宁县"; + case 430528: + return "新宁县"; + case 430529: + return "城步苗族自治县"; + case 430581: + return "武冈市"; + case 4306: + return "岳阳市"; + case 430601: + return "市辖区"; + case 430602: + return "岳阳楼区"; + case 430603: + return "云溪区"; + case 430611: + return "君山区"; + case 430621: + return "岳阳县"; + case 430623: + return "华容县"; + case 430624: + return "湘阴县"; + case 430626: + return "平江县"; + case 430681: + return "汨罗市"; + case 430682: + return "临湘市"; + case 4307: + return "常德市"; + case 430701: + return "市辖区"; + case 430702: + return "武陵区"; + case 430703: + return "鼎城区"; + case 430721: + return "安乡县"; + case 430722: + return "汉寿县"; + case 430723: + return "澧县"; + case 430724: + return "临澧县"; + case 430725: + return "桃源县"; + case 430726: + return "石门县"; + case 430781: + return "津市市"; + case 4308: + return "张家界市"; + case 430801: + return "市辖区"; + case 430802: + return "永定区"; + case 430811: + return "武陵源区"; + case 430821: + return "慈利县"; + case 430822: + return "桑植县"; + case 4309: + return "益阳市"; + case 430901: + return "市辖区"; + case 430902: + return "资阳区"; + case 430903: + return "赫山区"; + case 430921: + return "南县"; + case 430922: + return "桃江县"; + case 430923: + return "安化县"; + case 430981: + return "沅江市"; + case 4310: + return "郴州市"; + case 431001: + return "市辖区"; + case 431002: + return "北湖区"; + case 431003: + return "苏仙区"; + case 431021: + return "桂阳县"; + case 431022: + return "宜章县"; + case 431023: + return "永兴县"; + case 431024: + return "嘉禾县"; + case 431025: + return "临武县"; + case 431026: + return "汝城县"; + case 431027: + return "桂东县"; + case 431028: + return "安仁县"; + case 431081: + return "资兴市"; + case 4311: + return "永州市"; + case 431101: + return "市辖区"; + case 431102: + return "零陵区"; + case 431103: + return "冷水滩区"; + case 431121: + return "祁阳县"; + case 431122: + return "东安县"; + case 431123: + return "双牌县"; + case 431124: + return "道县"; + case 431125: + return "江永县"; + case 431126: + return "宁远县"; + case 431127: + return "蓝山县"; + case 431128: + return "新田县"; + case 431129: + return "江华瑶族自治县"; + case 4312: + return "怀化市"; + case 431201: + return "市辖区"; + case 431202: + return "鹤城区"; + case 431221: + return "中方县"; + case 431222: + return "沅陵县"; + case 431223: + return "辰溪县"; + case 431224: + return "溆浦县"; + case 431225: + return "会同县"; + case 431226: + return "麻阳苗族自治县"; + case 431227: + return "新晃侗族自治县"; + case 431228: + return "芷江侗族自治县"; + case 431229: + return "靖州苗族侗族自治县"; + case 431230: + return "通道侗族自治县"; + case 431281: + return "洪江市"; + case 4313: + return "娄底市"; + case 431301: + return "市辖区"; + case 431302: + return "娄星区"; + case 431321: + return "双峰县"; + case 431322: + return "新化县"; + case 431381: + return "冷水江市"; + case 431382: + return "涟源市"; + case 4331: + return "湘西土家族苗族自治州"; + case 433101: + return "吉首市"; + case 433122: + return "泸溪县"; + case 433123: + return "凤凰县"; + case 433124: + return "花垣县"; + case 433125: + return "保靖县"; + case 433126: + return "古丈县"; + case 433127: + return "永顺县"; + case 433130: + return "龙山县"; + case 44: + return "广东省"; + case 4401: + return "广州市"; + case 440101: + return "市辖区"; + case 440103: + return "荔湾区"; + case 440104: + return "越秀区"; + case 440105: + return "海珠区"; + case 440106: + return "天河区"; + case 440111: + return "白云区"; + case 440112: + return "黄埔区"; + case 440113: + return "番禺区"; + case 440114: + return "花都区"; + case 440115: + return "南沙区"; + case 440116: + return "萝岗区"; + case 440117: + return "从化区"; + case 440118: + return "增城区"; + case 4402: + return "韶关市"; + case 440201: + return "市辖区"; + case 440203: + return "武江区"; + case 440204: + return "浈江区"; + case 440205: + return "曲江区"; + case 440222: + return "始兴县"; + case 440224: + return "仁化县"; + case 440229: + return "翁源县"; + case 440232: + return "乳源瑶族自治县"; + case 440233: + return "新丰县"; + case 440281: + return "乐昌市"; + case 440282: + return "南雄市"; + case 4403: + return "深圳市"; + case 440301: + return "市辖区"; + case 440303: + return "罗湖区"; + case 440304: + return "福田区"; + case 440305: + return "南山区"; + case 440306: + return "宝安区"; + case 440307: + return "龙岗区"; + case 440308: + return "盐田区"; + case 4404: + return "珠海市"; + case 440401: + return "市辖区"; + case 440402: + return "香洲区"; + case 440403: + return "斗门区"; + case 440404: + return "金湾区"; + case 4405: + return "汕头市"; + case 440501: + return "市辖区"; + case 440507: + return "龙湖区"; + case 440511: + return "金平区"; + case 440512: + return "濠江区"; + case 440513: + return "潮阳区"; + case 440514: + return "潮南区"; + case 440515: + return "澄海区"; + case 440523: + return "南澳县"; + case 4406: + return "佛山市"; + case 440601: + return "市辖区"; + case 440604: + return "禅城区"; + case 440605: + return "南海区"; + case 440606: + return "顺德区"; + case 440607: + return "三水区"; + case 440608: + return "高明区"; + case 4407: + return "江门市"; + case 440701: + return "市辖区"; + case 440703: + return "蓬江区"; + case 440704: + return "江海区"; + case 440705: + return "新会区"; + case 440781: + return "台山市"; + case 440783: + return "开平市"; + case 440784: + return "鹤山市"; + case 440785: + return "恩平市"; + case 4408: + return "湛江市"; + case 440801: + return "市辖区"; + case 440802: + return "赤坎区"; + case 440803: + return "霞山区"; + case 440804: + return "坡头区"; + case 440811: + return "麻章区"; + case 440823: + return "遂溪县"; + case 440825: + return "徐闻县"; + case 440881: + return "廉江市"; + case 440882: + return "雷州市"; + case 440883: + return "吴川市"; + case 4409: + return "茂名市"; + case 440901: + return "市辖区"; + case 440902: + return "茂南区"; + case 440904: + return "电白区"; + case 440981: + return "高州市"; + case 440982: + return "化州市"; + case 440983: + return "信宜市"; + case 4412: + return "肇庆市"; + case 441201: + return "市辖区"; + case 441202: + return "端州区"; + case 441203: + return "鼎湖区"; + case 441223: + return "广宁县"; + case 441224: + return "怀集县"; + case 441225: + return "封开县"; + case 441226: + return "德庆县"; + case 441283: + return "高要市"; + case 441284: + return "四会市"; + case 4413: + return "惠州市"; + case 441301: + return "市辖区"; + case 441302: + return "惠城区"; + case 441303: + return "惠阳区"; + case 441322: + return "博罗县"; + case 441323: + return "惠东县"; + case 441324: + return "龙门县"; + case 4414: + return "梅州市"; + case 441401: + return "市辖区"; + case 441402: + return "梅江区"; + case 441403: + return "梅县区"; + case 441422: + return "大埔县"; + case 441423: + return "丰顺县"; + case 441424: + return "五华县"; + case 441426: + return "平远县"; + case 441427: + return "蕉岭县"; + case 441481: + return "兴宁市"; + case 4415: + return "汕尾市"; + case 441501: + return "市辖区"; + case 441502: + return "城区"; + case 441521: + return "海丰县"; + case 441523: + return "陆河县"; + case 441581: + return "陆丰市"; + case 4416: + return "河源市"; + case 441601: + return "市辖区"; + case 441602: + return "源城区"; + case 441621: + return "紫金县"; + case 441622: + return "龙川县"; + case 441623: + return "连平县"; + case 441624: + return "和平县"; + case 441625: + return "东源县"; + case 4417: + return "阳江市"; + case 441701: + return "市辖区"; + case 441702: + return "江城区"; + case 441721: + return "阳西县"; + case 441723: + return "阳东县"; + case 441781: + return "阳春市"; + case 4418: + return "清远市"; + case 441801: + return "市辖区"; + case 441802: + return "清城区"; + case 441803: + return "清新区"; + case 441821: + return "佛冈县"; + case 441823: + return "阳山县"; + case 441825: + return "连山壮族瑶族自治县"; + case 441826: + return "连南瑶族自治县"; + case 441881: + return "英德市"; + case 441882: + return "连州市"; + case 4419: + return "东莞市"; + case 4420: + return "中山市"; + case 4451: + return "潮州市"; + case 445101: + return "市辖区"; + case 445102: + return "湘桥区"; + case 445103: + return "潮安区"; + case 445122: + return "饶平县"; + case 4452: + return "揭阳市"; + case 445201: + return "市辖区"; + case 445202: + return "榕城区"; + case 445203: + return "揭东区"; + case 445222: + return "揭西县"; + case 445224: + return "惠来县"; + case 445281: + return "普宁市"; + case 4453: + return "云浮市"; + case 445301: + return "市辖区"; + case 445302: + return "云城区"; + case 445303: + return "云安区"; + case 445321: + return "新兴县"; + case 445322: + return "郁南县"; + case 445381: + return "罗定市"; + case 45: + return "广西壮族自治区"; + case 4501: + return "南宁市"; + case 450101: + return "市辖区"; + case 450102: + return "兴宁区"; + case 450103: + return "青秀区"; + case 450105: + return "江南区"; + case 450107: + return "西乡塘区"; + case 450108: + return "良庆区"; + case 450109: + return "邕宁区"; + case 450122: + return "武鸣县"; + case 450123: + return "隆安县"; + case 450124: + return "马山县"; + case 450125: + return "上林县"; + case 450126: + return "宾阳县"; + case 450127: + return "横县"; + case 4502: + return "柳州市"; + case 450201: + return "市辖区"; + case 450202: + return "城中区"; + case 450203: + return "鱼峰区"; + case 450204: + return "柳南区"; + case 450205: + return "柳北区"; + case 450221: + return "柳江县"; + case 450222: + return "柳城县"; + case 450223: + return "鹿寨县"; + case 450224: + return "融安县"; + case 450225: + return "融水苗族自治县"; + case 450226: + return "三江侗族自治县"; + case 4503: + return "桂林市"; + case 450301: + return "市辖区"; + case 450302: + return "秀峰区"; + case 450303: + return "叠彩区"; + case 450304: + return "象山区"; + case 450305: + return "七星区"; + case 450311: + return "雁山区"; + case 450312: + return "临桂区"; + case 450321: + return "阳朔县"; + case 450323: + return "灵川县"; + case 450324: + return "全州县"; + case 450325: + return "兴安县"; + case 450326: + return "永福县"; + case 450327: + return "灌阳县"; + case 450328: + return "龙胜各族自治县"; + case 450329: + return "资源县"; + case 450330: + return "平乐县"; + case 450331: + return "荔浦县"; + case 450332: + return "恭城瑶族自治县"; + case 4504: + return "梧州市"; + case 450401: + return "市辖区"; + case 450403: + return "万秀区"; + case 450405: + return "长洲区"; + case 450406: + return "龙圩区"; + case 450421: + return "苍梧县"; + case 450422: + return "藤县"; + case 450423: + return "蒙山县"; + case 450481: + return "岑溪市"; + case 4505: + return "北海市"; + case 450501: + return "市辖区"; + case 450502: + return "海城区"; + case 450503: + return "银海区"; + case 450512: + return "铁山港区"; + case 450521: + return "合浦县"; + case 4506: + return "防城港市"; + case 450601: + return "市辖区"; + case 450602: + return "港口区"; + case 450603: + return "防城区"; + case 450621: + return "上思县"; + case 450681: + return "东兴市"; + case 4507: + return "钦州市"; + case 450701: + return "市辖区"; + case 450702: + return "钦南区"; + case 450703: + return "钦北区"; + case 450721: + return "灵山县"; + case 450722: + return "浦北县"; + case 4508: + return "贵港市"; + case 450801: + return "市辖区"; + case 450802: + return "港北区"; + case 450803: + return "港南区"; + case 450804: + return "覃塘区"; + case 450821: + return "平南县"; + case 450881: + return "桂平市"; + case 4509: + return "玉林市"; + case 450901: + return "市辖区"; + case 450902: + return "玉州区"; + case 450903: + return "福绵区"; + case 450921: + return "容县"; + case 450922: + return "陆川县"; + case 450923: + return "博白县"; + case 450924: + return "兴业县"; + case 450981: + return "北流市"; + case 4510: + return "百色市"; + case 451001: + return "市辖区"; + case 451002: + return "右江区"; + case 451021: + return "田阳县"; + case 451022: + return "田东县"; + case 451023: + return "平果县"; + case 451024: + return "德保县"; + case 451025: + return "靖西县"; + case 451026: + return "那坡县"; + case 451027: + return "凌云县"; + case 451028: + return "乐业县"; + case 451029: + return "田林县"; + case 451030: + return "西林县"; + case 451031: + return "隆林各族自治县"; + case 4511: + return "贺州市"; + case 451101: + return "市辖区"; + case 451102: + return "八步区"; + case 451121: + return "昭平县"; + case 451122: + return "钟山县"; + case 451123: + return "富川瑶族自治县"; + case 4512: + return "河池市"; + case 451201: + return "市辖区"; + case 451202: + return "金城江区"; + case 451221: + return "南丹县"; + case 451222: + return "天峨县"; + case 451223: + return "凤山县"; + case 451224: + return "东兰县"; + case 451225: + return "罗城仫佬族自治县"; + case 451226: + return "环江毛南族自治县"; + case 451227: + return "巴马瑶族自治县"; + case 451228: + return "都安瑶族自治县"; + case 451229: + return "大化瑶族自治县"; + case 451281: + return "宜州市"; + case 4513: + return "来宾市"; + case 451301: + return "市辖区"; + case 451302: + return "兴宾区"; + case 451321: + return "忻城县"; + case 451322: + return "象州县"; + case 451323: + return "武宣县"; + case 451324: + return "金秀瑶族自治县"; + case 451381: + return "合山市"; + case 4514: + return "崇左市"; + case 451401: + return "市辖区"; + case 451402: + return "江州区"; + case 451421: + return "扶绥县"; + case 451422: + return "宁明县"; + case 451423: + return "龙州县"; + case 451424: + return "大新县"; + case 451425: + return "天等县"; + case 451481: + return "凭祥市"; + case 46: + return "海南省"; + case 4601: + return "海口市"; + case 460101: + return "市辖区"; + case 460105: + return "秀英区"; + case 460106: + return "龙华区"; + case 460107: + return "琼山区"; + case 460108: + return "美兰区"; + case 4602: + return "三亚市"; + case 460201: + return "市辖区"; + case 460202: + return "海棠区"; + case 460203: + return "吉阳区"; + case 460204: + return "天涯区"; + case 460205: + return "崖州区"; + case 4603: + return "三沙市"; + case 4690: + return "省直辖县级行政区划"; + case 469001: + return "五指山市"; + case 469002: + return "琼海市"; + case 469003: + return "儋州市"; + case 469005: + return "文昌市"; + case 469006: + return "万宁市"; + case 469007: + return "东方市"; + case 469021: + return "定安县"; + case 469022: + return "屯昌县"; + case 469023: + return "澄迈县"; + case 469024: + return "临高县"; + case 469025: + return "白沙黎族自治县"; + case 469026: + return "昌江黎族自治县"; + case 469027: + return "乐东黎族自治县"; + case 469028: + return "陵水黎族自治县"; + case 469029: + return "保亭黎族苗族自治县"; + case 469030: + return "琼中黎族苗族自治县"; + case 50: + return "重庆市"; + case 5001: + return "市辖区"; + case 500101: + return "万州区"; + case 500102: + return "涪陵区"; + case 500103: + return "渝中区"; + case 500104: + return "大渡口区"; + case 500105: + return "江北区"; + case 500106: + return "沙坪坝区"; + case 500107: + return "九龙坡区"; + case 500108: + return "南岸区"; + case 500109: + return "北碚区"; + case 500110: + return "綦江区"; + case 500111: + return "大足区"; + case 500112: + return "渝北区"; + case 500113: + return "巴南区"; + case 500114: + return "黔江区"; + case 500115: + return "长寿区"; + case 500116: + return "江津区"; + case 500117: + return "合川区"; + case 500118: + return "永川区"; + case 500119: + return "南川区"; + case 500120: + return "璧山区"; + case 500151: + return "铜梁区"; + case 5002: + return "县"; + case 500223: + return "潼南县"; + case 500226: + return "荣昌县"; + case 500228: + return "梁平县"; + case 500229: + return "城口县"; + case 500230: + return "丰都县"; + case 500231: + return "垫江县"; + case 500232: + return "武隆县"; + case 500233: + return "忠县"; + case 500234: + return "开县"; + case 500235: + return "云阳县"; + case 500236: + return "奉节县"; + case 500237: + return "巫山县"; + case 500238: + return "巫溪县"; + case 500240: + return "石柱土家族自治县"; + case 500241: + return "秀山土家族苗族自治县"; + case 500242: + return "酉阳土家族苗族自治县"; + case 500243: + return "彭水苗族土家族自治县"; + case 51: + return "四川省"; + case 5101: + return "成都市"; + case 510101: + return "市辖区"; + case 510104: + return "锦江区"; + case 510105: + return "青羊区"; + case 510106: + return "金牛区"; + case 510107: + return "武侯区"; + case 510108: + return "成华区"; + case 510112: + return "龙泉驿区"; + case 510113: + return "青白江区"; + case 510114: + return "新都区"; + case 510115: + return "温江区"; + case 510121: + return "金堂县"; + case 510122: + return "双流县"; + case 510124: + return "郫县"; + case 510129: + return "大邑县"; + case 510131: + return "蒲江县"; + case 510132: + return "新津县"; + case 510181: + return "都江堰市"; + case 510182: + return "彭州市"; + case 510183: + return "邛崃市"; + case 510184: + return "崇州市"; + case 5103: + return "自贡市"; + case 510301: + return "市辖区"; + case 510302: + return "自流井区"; + case 510303: + return "贡井区"; + case 510304: + return "大安区"; + case 510311: + return "沿滩区"; + case 510321: + return "荣县"; + case 510322: + return "富顺县"; + case 5104: + return "攀枝花市"; + case 510401: + return "市辖区"; + case 510402: + return "东区"; + case 510403: + return "西区"; + case 510411: + return "仁和区"; + case 510421: + return "米易县"; + case 510422: + return "盐边县"; + case 5105: + return "泸州市"; + case 510501: + return "市辖区"; + case 510502: + return "江阳区"; + case 510503: + return "纳溪区"; + case 510504: + return "龙马潭区"; + case 510521: + return "泸县"; + case 510522: + return "合江县"; + case 510524: + return "叙永县"; + case 510525: + return "古蔺县"; + case 5106: + return "德阳市"; + case 510601: + return "市辖区"; + case 510603: + return "旌阳区"; + case 510623: + return "中江县"; + case 510626: + return "罗江县"; + case 510681: + return "广汉市"; + case 510682: + return "什邡市"; + case 510683: + return "绵竹市"; + case 5107: + return "绵阳市"; + case 510701: + return "市辖区"; + case 510703: + return "涪城区"; + case 510704: + return "游仙区"; + case 510722: + return "三台县"; + case 510723: + return "盐亭县"; + case 510724: + return "安县"; + case 510725: + return "梓潼县"; + case 510726: + return "北川羌族自治县"; + case 510727: + return "平武县"; + case 510781: + return "江油市"; + case 5108: + return "广元市"; + case 510801: + return "市辖区"; + case 510802: + return "利州区"; + case 510811: + return "昭化区"; + case 510812: + return "朝天区"; + case 510821: + return "旺苍县"; + case 510822: + return "青川县"; + case 510823: + return "剑阁县"; + case 510824: + return "苍溪县"; + case 5109: + return "遂宁市"; + case 510901: + return "市辖区"; + case 510903: + return "船山区"; + case 510904: + return "安居区"; + case 510921: + return "蓬溪县"; + case 510922: + return "射洪县"; + case 510923: + return "大英县"; + case 5110: + return "内江市"; + case 511001: + return "市辖区"; + case 511002: + return "市中区"; + case 511011: + return "东兴区"; + case 511024: + return "威远县"; + case 511025: + return "资中县"; + case 511028: + return "隆昌县"; + case 5111: + return "乐山市"; + case 511101: + return "市辖区"; + case 511102: + return "市中区"; + case 511111: + return "沙湾区"; + case 511112: + return "五通桥区"; + case 511113: + return "金口河区"; + case 511123: + return "犍为县"; + case 511124: + return "井研县"; + case 511126: + return "夹江县"; + case 511129: + return "沐川县"; + case 511132: + return "峨边彝族自治县"; + case 511133: + return "马边彝族自治县"; + case 511181: + return "峨眉山市"; + case 5113: + return "南充市"; + case 511301: + return "市辖区"; + case 511302: + return "顺庆区"; + case 511303: + return "高坪区"; + case 511304: + return "嘉陵区"; + case 511321: + return "南部县"; + case 511322: + return "营山县"; + case 511323: + return "蓬安县"; + case 511324: + return "仪陇县"; + case 511325: + return "西充县"; + case 511381: + return "阆中市"; + case 5114: + return "眉山市"; + case 511401: + return "市辖区"; + case 511402: + return "东坡区"; + case 511421: + return "仁寿县"; + case 511422: + return "彭山县"; + case 511423: + return "洪雅县"; + case 511424: + return "丹棱县"; + case 511425: + return "青神县"; + case 5115: + return "宜宾市"; + case 511501: + return "市辖区"; + case 511502: + return "翠屏区"; + case 511503: + return "南溪区"; + case 511521: + return "宜宾县"; + case 511523: + return "江安县"; + case 511524: + return "长宁县"; + case 511525: + return "高县"; + case 511526: + return "珙县"; + case 511527: + return "筠连县"; + case 511528: + return "兴文县"; + case 511529: + return "屏山县"; + case 5116: + return "广安市"; + case 511601: + return "市辖区"; + case 511602: + return "广安区"; + case 511603: + return "前锋区"; + case 511621: + return "岳池县"; + case 511622: + return "武胜县"; + case 511623: + return "邻水县"; + case 511681: + return "华蓥市"; + case 5117: + return "达州市"; + case 511701: + return "市辖区"; + case 511702: + return "通川区"; + case 511703: + return "达川区"; + case 511722: + return "宣汉县"; + case 511723: + return "开江县"; + case 511724: + return "大竹县"; + case 511725: + return "渠县"; + case 511781: + return "万源市"; + case 5118: + return "雅安市"; + case 511801: + return "市辖区"; + case 511802: + return "雨城区"; + case 511803: + return "名山区"; + case 511822: + return "荥经县"; + case 511823: + return "汉源县"; + case 511824: + return "石棉县"; + case 511825: + return "天全县"; + case 511826: + return "芦山县"; + case 511827: + return "宝兴县"; + case 5119: + return "巴中市"; + case 511901: + return "市辖区"; + case 511902: + return "巴州区"; + case 511903: + return "恩阳区"; + case 511921: + return "通江县"; + case 511922: + return "南江县"; + case 511923: + return "平昌县"; + case 5120: + return "资阳市"; + case 512001: + return "市辖区"; + case 512002: + return "雁江区"; + case 512021: + return "安岳县"; + case 512022: + return "乐至县"; + case 512081: + return "简阳市"; + case 5132: + return "阿坝藏族羌族自治州"; + case 513221: + return "汶川县"; + case 513222: + return "理县"; + case 513223: + return "茂县"; + case 513224: + return "松潘县"; + case 513225: + return "九寨沟县"; + case 513226: + return "金川县"; + case 513227: + return "小金县"; + case 513228: + return "黑水县"; + case 513229: + return "马尔康县"; + case 513230: + return "壤塘县"; + case 513231: + return "阿坝县"; + case 513232: + return "若尔盖县"; + case 513233: + return "红原县"; + case 5133: + return "甘孜藏族自治州"; + case 513321: + return "康定县"; + case 513322: + return "泸定县"; + case 513323: + return "丹巴县"; + case 513324: + return "九龙县"; + case 513325: + return "雅江县"; + case 513326: + return "道孚县"; + case 513327: + return "炉霍县"; + case 513328: + return "甘孜县"; + case 513329: + return "新龙县"; + case 513330: + return "德格县"; + case 513331: + return "白玉县"; + case 513332: + return "石渠县"; + case 513333: + return "色达县"; + case 513334: + return "理塘县"; + case 513335: + return "巴塘县"; + case 513336: + return "乡城县"; + case 513337: + return "稻城县"; + case 513338: + return "得荣县"; + case 5134: + return "凉山彝族自治州"; + case 513401: + return "西昌市"; + case 513422: + return "木里藏族自治县"; + case 513423: + return "盐源县"; + case 513424: + return "德昌县"; + case 513425: + return "会理县"; + case 513426: + return "会东县"; + case 513427: + return "宁南县"; + case 513428: + return "普格县"; + case 513429: + return "布拖县"; + case 513430: + return "金阳县"; + case 513431: + return "昭觉县"; + case 513432: + return "喜德县"; + case 513433: + return "冕宁县"; + case 513434: + return "越西县"; + case 513435: + return "甘洛县"; + case 513436: + return "美姑县"; + case 513437: + return "雷波县"; + case 52: + return "贵州省"; + case 5201: + return "贵阳市"; + case 520101: + return "市辖区"; + case 520102: + return "南明区"; + case 520103: + return "云岩区"; + case 520111: + return "花溪区"; + case 520112: + return "乌当区"; + case 520113: + return "白云区"; + case 520115: + return "观山湖区"; + case 520121: + return "开阳县"; + case 520122: + return "息烽县"; + case 520123: + return "修文县"; + case 520181: + return "清镇市"; + case 5202: + return "六盘水市"; + case 520201: + return "钟山区"; + case 520203: + return "六枝特区"; + case 520221: + return "水城县"; + case 520222: + return "盘县"; + case 5203: + return "遵义市"; + case 520301: + return "市辖区"; + case 520302: + return "红花岗区"; + case 520303: + return "汇川区"; + case 520321: + return "遵义县"; + case 520322: + return "桐梓县"; + case 520323: + return "绥阳县"; + case 520324: + return "正安县"; + case 520325: + return "道真仡佬族苗族自治县"; + case 520326: + return "务川仡佬族苗族自治县"; + case 520327: + return "凤冈县"; + case 520328: + return "湄潭县"; + case 520329: + return "余庆县"; + case 520330: + return "习水县"; + case 520381: + return "赤水市"; + case 520382: + return "仁怀市"; + case 5204: + return "安顺市"; + case 520401: + return "市辖区"; + case 520402: + return "西秀区"; + case 520421: + return "平坝县"; + case 520422: + return "普定县"; + case 520423: + return "镇宁布依族苗族自治县"; + case 520424: + return "关岭布依族苗族自治县"; + case 520425: + return "紫云苗族布依族自治县"; + case 5205: + return "毕节市"; + case 520501: + return "市辖区"; + case 520502: + return "七星关区"; + case 520521: + return "大方县"; + case 520522: + return "黔西县"; + case 520523: + return "金沙县"; + case 520524: + return "织金县"; + case 520525: + return "纳雍县"; + case 520526: + return "威宁彝族回族苗族自治县"; + case 520527: + return "赫章县"; + case 5206: + return "铜仁市"; + case 520601: + return "市辖区"; + case 520602: + return "碧江区"; + case 520603: + return "万山区"; + case 520621: + return "江口县"; + case 520622: + return "玉屏侗族自治县"; + case 520623: + return "石阡县"; + case 520624: + return "思南县"; + case 520625: + return "印江土家族苗族自治县"; + case 520626: + return "德江县"; + case 520627: + return "沿河土家族自治县"; + case 520628: + return "松桃苗族自治县"; + case 5223: + return "黔西南布依族苗族自治州"; + case 522301: + return "兴义市"; + case 522322: + return "兴仁县"; + case 522323: + return "普安县"; + case 522324: + return "晴隆县"; + case 522325: + return "贞丰县"; + case 522326: + return "望谟县"; + case 522327: + return "册亨县"; + case 522328: + return "安龙县"; + case 5226: + return "黔东南苗族侗族自治州"; + case 522601: + return "凯里市"; + case 522622: + return "黄平县"; + case 522623: + return "施秉县"; + case 522624: + return "三穗县"; + case 522625: + return "镇远县"; + case 522626: + return "岑巩县"; + case 522627: + return "天柱县"; + case 522628: + return "锦屏县"; + case 522629: + return "剑河县"; + case 522630: + return "台江县"; + case 522631: + return "黎平县"; + case 522632: + return "榕江县"; + case 522633: + return "从江县"; + case 522634: + return "雷山县"; + case 522635: + return "麻江县"; + case 522636: + return "丹寨县"; + case 5227: + return "黔南布依族苗族自治州"; + case 522701: + return "都匀市"; + case 522702: + return "福泉市"; + case 522722: + return "荔波县"; + case 522723: + return "贵定县"; + case 522725: + return "瓮安县"; + case 522726: + return "独山县"; + case 522727: + return "平塘县"; + case 522728: + return "罗甸县"; + case 522729: + return "长顺县"; + case 522730: + return "龙里县"; + case 522731: + return "惠水县"; + case 522732: + return "三都水族自治县"; + case 53: + return "云南省"; + case 5301: + return "昆明市"; + case 530101: + return "市辖区"; + case 530102: + return "五华区"; + case 530103: + return "盘龙区"; + case 530111: + return "官渡区"; + case 530112: + return "西山区"; + case 530113: + return "东川区"; + case 530114: + return "呈贡区"; + case 530122: + return "晋宁县"; + case 530124: + return "富民县"; + case 530125: + return "宜良县"; + case 530126: + return "石林彝族自治县"; + case 530127: + return "嵩明县"; + case 530128: + return "禄劝彝族苗族自治县"; + case 530129: + return "寻甸回族彝族自治县"; + case 530181: + return "安宁市"; + case 5303: + return "曲靖市"; + case 530301: + return "市辖区"; + case 530302: + return "麒麟区"; + case 530321: + return "马龙县"; + case 530322: + return "陆良县"; + case 530323: + return "师宗县"; + case 530324: + return "罗平县"; + case 530325: + return "富源县"; + case 530326: + return "会泽县"; + case 530328: + return "沾益县"; + case 530381: + return "宣威市"; + case 5304: + return "玉溪市"; + case 530401: + return "市辖区"; + case 530402: + return "红塔区"; + case 530421: + return "江川县"; + case 530422: + return "澄江县"; + case 530423: + return "通海县"; + case 530424: + return "华宁县"; + case 530425: + return "易门县"; + case 530426: + return "峨山彝族自治县"; + case 530427: + return "新平彝族傣族自治县"; + case 530428: + return "元江哈尼族彝族傣族自治县"; + case 5305: + return "保山市"; + case 530501: + return "市辖区"; + case 530502: + return "隆阳区"; + case 530521: + return "施甸县"; + case 530522: + return "腾冲县"; + case 530523: + return "龙陵县"; + case 530524: + return "昌宁县"; + case 5306: + return "昭通市"; + case 530601: + return "市辖区"; + case 530602: + return "昭阳区"; + case 530621: + return "鲁甸县"; + case 530622: + return "巧家县"; + case 530623: + return "盐津县"; + case 530624: + return "大关县"; + case 530625: + return "永善县"; + case 530626: + return "绥江县"; + case 530627: + return "镇雄县"; + case 530628: + return "彝良县"; + case 530629: + return "威信县"; + case 530630: + return "水富县"; + case 5307: + return "丽江市"; + case 530701: + return "市辖区"; + case 530702: + return "古城区"; + case 530721: + return "玉龙纳西族自治县"; + case 530722: + return "永胜县"; + case 530723: + return "华坪县"; + case 530724: + return "宁蒗彝族自治县"; + case 5308: + return "普洱市"; + case 530801: + return "市辖区"; + case 530802: + return "思茅区"; + case 530821: + return "宁洱哈尼族彝族自治县"; + case 530822: + return "墨江哈尼族自治县"; + case 530823: + return "景东彝族自治县"; + case 530824: + return "景谷傣族彝族自治县"; + case 530825: + return "镇沅彝族哈尼族拉祜族自治县"; + case 530826: + return "江城哈尼族彝族自治县"; + case 530827: + return "孟连傣族拉祜族佤族自治县"; + case 530828: + return "澜沧拉祜族自治县"; + case 530829: + return "西盟佤族自治县"; + case 5309: + return "临沧市"; + case 530901: + return "市辖区"; + case 530902: + return "临翔区"; + case 530921: + return "凤庆县"; + case 530922: + return "云县"; + case 530923: + return "永德县"; + case 530924: + return "镇康县"; + case 530925: + return "双江拉祜族佤族布朗族傣族自治县"; + case 530926: + return "耿马傣族佤族自治县"; + case 530927: + return "沧源佤族自治县"; + case 5323: + return "楚雄彝族自治州"; + case 532301: + return "楚雄市"; + case 532322: + return "双柏县"; + case 532323: + return "牟定县"; + case 532324: + return "南华县"; + case 532325: + return "姚安县"; + case 532326: + return "大姚县"; + case 532327: + return "永仁县"; + case 532328: + return "元谋县"; + case 532329: + return "武定县"; + case 532331: + return "禄丰县"; + case 5325: + return "红河哈尼族彝族自治州"; + case 532501: + return "个旧市"; + case 532502: + return "开远市"; + case 532503: + return "蒙自市"; + case 532504: + return "弥勒市"; + case 532523: + return "屏边苗族自治县"; + case 532524: + return "建水县"; + case 532525: + return "石屏县"; + case 532527: + return "泸西县"; + case 532528: + return "元阳县"; + case 532529: + return "红河县"; + case 532530: + return "金平苗族瑶族傣族自治县"; + case 532531: + return "绿春县"; + case 532532: + return "河口瑶族自治县"; + case 5326: + return "文山壮族苗族自治州"; + case 532601: + return "文山市"; + case 532622: + return "砚山县"; + case 532623: + return "西畴县"; + case 532624: + return "麻栗坡县"; + case 532625: + return "马关县"; + case 532626: + return "丘北县"; + case 532627: + return "广南县"; + case 532628: + return "富宁县"; + case 5328: + return "西双版纳傣族自治州"; + case 532801: + return "景洪市"; + case 532822: + return "勐海县"; + case 532823: + return "勐腊县"; + case 5329: + return "大理白族自治州"; + case 532901: + return "大理市"; + case 532922: + return "漾濞彝族自治县"; + case 532923: + return "祥云县"; + case 532924: + return "宾川县"; + case 532925: + return "弥渡县"; + case 532926: + return "南涧彝族自治县"; + case 532927: + return "巍山彝族回族自治县"; + case 532928: + return "永平县"; + case 532929: + return "云龙县"; + case 532930: + return "洱源县"; + case 532931: + return "剑川县"; + case 532932: + return "鹤庆县"; + case 5331: + return "德宏傣族景颇族自治州"; + case 533102: + return "瑞丽市"; + case 533103: + return "芒市"; + case 533122: + return "梁河县"; + case 533123: + return "盈江县"; + case 533124: + return "陇川县"; + case 5333: + return "怒江傈僳族自治州"; + case 533321: + return "泸水县"; + case 533323: + return "福贡县"; + case 533324: + return "贡山独龙族怒族自治县"; + case 533325: + return "兰坪白族普米族自治县"; + case 5334: + return "迪庆藏族自治州"; + case 533421: + return "香格里拉县"; + case 533422: + return "德钦县"; + case 533423: + return "维西傈僳族自治县"; + case 54: + return "西藏自治区"; + case 5401: + return "拉萨市"; + case 540101: + return "市辖区"; + case 540102: + return "城关区"; + case 540121: + return "林周县"; + case 540122: + return "当雄县"; + case 540123: + return "尼木县"; + case 540124: + return "曲水县"; + case 540125: + return "堆龙德庆县"; + case 540126: + return "达孜县"; + case 540127: + return "墨竹工卡县"; + case 5402: + return "日喀则市"; + case 540202: + return "桑珠孜区"; + case 540221: + return "南木林县"; + case 540222: + return "江孜县"; + case 540223: + return "定日县"; + case 540224: + return "萨迦县"; + case 540225: + return "拉孜县"; + case 540226: + return "昂仁县"; + case 540227: + return "谢通门县"; + case 540228: + return "白朗县"; + case 540229: + return "仁布县"; + case 540230: + return "康马县"; + case 540231: + return "定结县"; + case 540232: + return "仲巴县"; + case 540233: + return "亚东县"; + case 540234: + return "吉隆县"; + case 540235: + return "聂拉木县"; + case 540236: + return "萨嘎县"; + case 540237: + return "岗巴县"; + case 5421: + return "昌都地区"; + case 542121: + return "昌都县"; + case 542122: + return "江达县"; + case 542123: + return "贡觉县"; + case 542124: + return "类乌齐县"; + case 542125: + return "丁青县"; + case 542126: + return "察雅县"; + case 542127: + return "八宿县"; + case 542128: + return "左贡县"; + case 542129: + return "芒康县"; + case 542132: + return "洛隆县"; + case 542133: + return "边坝县"; + case 5422: + return "山南地区"; + case 542221: + return "乃东县"; + case 542222: + return "扎囊县"; + case 542223: + return "贡嘎县"; + case 542224: + return "桑日县"; + case 542225: + return "琼结县"; + case 542226: + return "曲松县"; + case 542227: + return "措美县"; + case 542228: + return "洛扎县"; + case 542229: + return "加查县"; + case 542231: + return "隆子县"; + case 542232: + return "错那县"; + case 542233: + return "浪卡子县"; + case 5424: + return "那曲地区"; + case 542421: + return "那曲县"; + case 542422: + return "嘉黎县"; + case 542423: + return "比如县"; + case 542424: + return "聂荣县"; + case 542425: + return "安多县"; + case 542426: + return "申扎县"; + case 542427: + return "索县"; + case 542428: + return "班戈县"; + case 542429: + return "巴青县"; + case 542430: + return "尼玛县"; + case 542431: + return "双湖县"; + case 5425: + return "阿里地区"; + case 542521: + return "普兰县"; + case 542522: + return "札达县"; + case 542523: + return "噶尔县"; + case 542524: + return "日土县"; + case 542525: + return "革吉县"; + case 542526: + return "改则县"; + case 542527: + return "措勤县"; + case 5426: + return "林芝地区"; + case 542621: + return "林芝县"; + case 542622: + return "工布江达县"; + case 542623: + return "米林县"; + case 542624: + return "墨脱县"; + case 542625: + return "波密县"; + case 542626: + return "察隅县"; + case 542627: + return "朗县"; + case 61: + return "陕西省"; + case 6101: + return "西安市"; + case 610101: + return "市辖区"; + case 610102: + return "新城区"; + case 610103: + return "碑林区"; + case 610104: + return "莲湖区"; + case 610111: + return "灞桥区"; + case 610112: + return "未央区"; + case 610113: + return "雁塔区"; + case 610114: + return "阎良区"; + case 610115: + return "临潼区"; + case 610116: + return "长安区"; + case 610122: + return "蓝田县"; + case 610124: + return "周至县"; + case 610125: + return "户县"; + case 610126: + return "高陵县"; + case 6102: + return "铜川市"; + case 610201: + return "市辖区"; + case 610202: + return "王益区"; + case 610203: + return "印台区"; + case 610204: + return "耀州区"; + case 610222: + return "宜君县"; + case 6103: + return "宝鸡市"; + case 610301: + return "市辖区"; + case 610302: + return "渭滨区"; + case 610303: + return "金台区"; + case 610304: + return "陈仓区"; + case 610322: + return "凤翔县"; + case 610323: + return "岐山县"; + case 610324: + return "扶风县"; + case 610326: + return "眉县"; + case 610327: + return "陇县"; + case 610328: + return "千阳县"; + case 610329: + return "麟游县"; + case 610330: + return "凤县"; + case 610331: + return "太白县"; + case 6104: + return "咸阳市"; + case 610401: + return "市辖区"; + case 610402: + return "秦都区"; + case 610403: + return "杨陵区"; + case 610404: + return "渭城区"; + case 610422: + return "三原县"; + case 610423: + return "泾阳县"; + case 610424: + return "乾县"; + case 610425: + return "礼泉县"; + case 610426: + return "永寿县"; + case 610427: + return "彬县"; + case 610428: + return "长武县"; + case 610429: + return "旬邑县"; + case 610430: + return "淳化县"; + case 610431: + return "武功县"; + case 610481: + return "兴平市"; + case 6105: + return "渭南市"; + case 610501: + return "市辖区"; + case 610502: + return "临渭区"; + case 610521: + return "华县"; + case 610522: + return "潼关县"; + case 610523: + return "大荔县"; + case 610524: + return "合阳县"; + case 610525: + return "澄城县"; + case 610526: + return "蒲城县"; + case 610527: + return "白水县"; + case 610528: + return "富平县"; + case 610581: + return "韩城市"; + case 610582: + return "华阴市"; + case 6106: + return "延安市"; + case 610601: + return "市辖区"; + case 610602: + return "宝塔区"; + case 610621: + return "延长县"; + case 610622: + return "延川县"; + case 610623: + return "子长县"; + case 610624: + return "安塞县"; + case 610625: + return "志丹县"; + case 610626: + return "吴起县"; + case 610627: + return "甘泉县"; + case 610628: + return "富县"; + case 610629: + return "洛川县"; + case 610630: + return "宜川县"; + case 610631: + return "黄龙县"; + case 610632: + return "黄陵县"; + case 6107: + return "汉中市"; + case 610701: + return "市辖区"; + case 610702: + return "汉台区"; + case 610721: + return "南郑县"; + case 610722: + return "城固县"; + case 610723: + return "洋县"; + case 610724: + return "西乡县"; + case 610725: + return "勉县"; + case 610726: + return "宁强县"; + case 610727: + return "略阳县"; + case 610728: + return "镇巴县"; + case 610729: + return "留坝县"; + case 610730: + return "佛坪县"; + case 6108: + return "榆林市"; + case 610801: + return "市辖区"; + case 610802: + return "榆阳区"; + case 610821: + return "神木县"; + case 610822: + return "府谷县"; + case 610823: + return "横山县"; + case 610824: + return "靖边县"; + case 610825: + return "定边县"; + case 610826: + return "绥德县"; + case 610827: + return "米脂县"; + case 610828: + return "佳县"; + case 610829: + return "吴堡县"; + case 610830: + return "清涧县"; + case 610831: + return "子洲县"; + case 6109: + return "安康市"; + case 610901: + return "市辖区"; + case 610902: + return "汉滨区"; + case 610921: + return "汉阴县"; + case 610922: + return "石泉县"; + case 610923: + return "宁陕县"; + case 610924: + return "紫阳县"; + case 610925: + return "岚皋县"; + case 610926: + return "平利县"; + case 610927: + return "镇坪县"; + case 610928: + return "旬阳县"; + case 610929: + return "白河县"; + case 6110: + return "商洛市"; + case 611001: + return "市辖区"; + case 611002: + return "商州区"; + case 611021: + return "洛南县"; + case 611022: + return "丹凤县"; + case 611023: + return "商南县"; + case 611024: + return "山阳县"; + case 611025: + return "镇安县"; + case 611026: + return "柞水县"; + case 62: + return "甘肃省"; + case 6201: + return "兰州市"; + case 620101: + return "市辖区"; + case 620102: + return "城关区"; + case 620103: + return "七里河区"; + case 620104: + return "西固区"; + case 620105: + return "安宁区"; + case 620111: + return "红古区"; + case 620121: + return "永登县"; + case 620122: + return "皋兰县"; + case 620123: + return "榆中县"; + case 6202: + return "嘉峪关市"; + case 620201: + return "市辖区"; + case 6203: + return "金昌市"; + case 620301: + return "市辖区"; + case 620302: + return "金川区"; + case 620321: + return "永昌县"; + case 6204: + return "白银市"; + case 620401: + return "市辖区"; + case 620402: + return "白银区"; + case 620403: + return "平川区"; + case 620421: + return "靖远县"; + case 620422: + return "会宁县"; + case 620423: + return "景泰县"; + case 6205: + return "天水市"; + case 620501: + return "市辖区"; + case 620502: + return "秦州区"; + case 620503: + return "麦积区"; + case 620521: + return "清水县"; + case 620522: + return "秦安县"; + case 620523: + return "甘谷县"; + case 620524: + return "武山县"; + case 620525: + return "张家川回族自治县"; + case 6206: + return "武威市"; + case 620601: + return "市辖区"; + case 620602: + return "凉州区"; + case 620621: + return "民勤县"; + case 620622: + return "古浪县"; + case 620623: + return "天祝藏族自治县"; + case 6207: + return "张掖市"; + case 620701: + return "市辖区"; + case 620702: + return "甘州区"; + case 620721: + return "肃南裕固族自治县"; + case 620722: + return "民乐县"; + case 620723: + return "临泽县"; + case 620724: + return "高台县"; + case 620725: + return "山丹县"; + case 6208: + return "平凉市"; + case 620801: + return "市辖区"; + case 620802: + return "崆峒区"; + case 620821: + return "泾川县"; + case 620822: + return "灵台县"; + case 620823: + return "崇信县"; + case 620824: + return "华亭县"; + case 620825: + return "庄浪县"; + case 620826: + return "静宁县"; + case 6209: + return "酒泉市"; + case 620901: + return "市辖区"; + case 620902: + return "肃州区"; + case 620921: + return "金塔县"; + case 620922: + return "瓜州县"; + case 620923: + return "肃北蒙古族自治县"; + case 620924: + return "阿克塞哈萨克族自治县"; + case 620981: + return "玉门市"; + case 620982: + return "敦煌市"; + case 6210: + return "庆阳市"; + case 621001: + return "市辖区"; + case 621002: + return "西峰区"; + case 621021: + return "庆城县"; + case 621022: + return "环县"; + case 621023: + return "华池县"; + case 621024: + return "合水县"; + case 621025: + return "正宁县"; + case 621026: + return "宁县"; + case 621027: + return "镇原县"; + case 6211: + return "定西市"; + case 621101: + return "市辖区"; + case 621102: + return "安定区"; + case 621121: + return "通渭县"; + case 621122: + return "陇西县"; + case 621123: + return "渭源县"; + case 621124: + return "临洮县"; + case 621125: + return "漳县"; + case 621126: + return "岷县"; + case 6212: + return "陇南市"; + case 621201: + return "市辖区"; + case 621202: + return "武都区"; + case 621221: + return "成县"; + case 621222: + return "文县"; + case 621223: + return "宕昌县"; + case 621224: + return "康县"; + case 621225: + return "西和县"; + case 621226: + return "礼县"; + case 621227: + return "徽县"; + case 621228: + return "两当县"; + case 6229: + return "临夏回族自治州"; + case 622901: + return "临夏市"; + case 622921: + return "临夏县"; + case 622922: + return "康乐县"; + case 622923: + return "永靖县"; + case 622924: + return "广河县"; + case 622925: + return "和政县"; + case 622926: + return "东乡族自治县"; + case 622927: + return "积石山保安族东乡族撒拉族自治县"; + case 6230: + return "甘南藏族自治州"; + case 623001: + return "合作市"; + case 623021: + return "临潭县"; + case 623022: + return "卓尼县"; + case 623023: + return "舟曲县"; + case 623024: + return "迭部县"; + case 623025: + return "玛曲县"; + case 623026: + return "碌曲县"; + case 623027: + return "夏河县"; + case 63: + return "青海省"; + case 6301: + return "西宁市"; + case 630101: + return "市辖区"; + case 630102: + return "城东区"; + case 630103: + return "城中区"; + case 630104: + return "城西区"; + case 630105: + return "城北区"; + case 630121: + return "大通回族土族自治县"; + case 630122: + return "湟中县"; + case 630123: + return "湟源县"; + case 6302: + return "海东市"; + case 630202: + return "乐都区"; + case 630221: + return "平安县"; + case 630222: + return "民和回族土族自治县"; + case 630223: + return "互助土族自治县"; + case 630224: + return "化隆回族自治县"; + case 630225: + return "循化撒拉族自治县"; + case 6322: + return "海北藏族自治州"; + case 632221: + return "门源回族自治县"; + case 632222: + return "祁连县"; + case 632223: + return "海晏县"; + case 632224: + return "刚察县"; + case 6323: + return "黄南藏族自治州"; + case 632321: + return "同仁县"; + case 632322: + return "尖扎县"; + case 632323: + return "泽库县"; + case 632324: + return "河南蒙古族自治县"; + case 6325: + return "海南藏族自治州"; + case 632521: + return "共和县"; + case 632522: + return "同德县"; + case 632523: + return "贵德县"; + case 632524: + return "兴海县"; + case 632525: + return "贵南县"; + case 6326: + return "果洛藏族自治州"; + case 632621: + return "玛沁县"; + case 632622: + return "班玛县"; + case 632623: + return "甘德县"; + case 632624: + return "达日县"; + case 632625: + return "久治县"; + case 632626: + return "玛多县"; + case 6327: + return "玉树藏族自治州"; + case 632701: + return "玉树市"; + case 632722: + return "杂多县"; + case 632723: + return "称多县"; + case 632724: + return "治多县"; + case 632725: + return "囊谦县"; + case 632726: + return "曲麻莱县"; + case 6328: + return "海西蒙古族藏族自治州"; + case 632801: + return "格尔木市"; + case 632802: + return "德令哈市"; + case 632821: + return "乌兰县"; + case 632822: + return "都兰县"; + case 632823: + return "天峻县"; + case 64: + return "宁夏回族自治区"; + case 6401: + return "银川市"; + case 640101: + return "市辖区"; + case 640104: + return "兴庆区"; + case 640105: + return "西夏区"; + case 640106: + return "金凤区"; + case 640121: + return "永宁县"; + case 640122: + return "贺兰县"; + case 640181: + return "灵武市"; + case 6402: + return "石嘴山市"; + case 640201: + return "市辖区"; + case 640202: + return "大武口区"; + case 640205: + return "惠农区"; + case 640221: + return "平罗县"; + case 6403: + return "吴忠市"; + case 640301: + return "市辖区"; + case 640302: + return "利通区"; + case 640303: + return "红寺堡区"; + case 640323: + return "盐池县"; + case 640324: + return "同心县"; + case 640381: + return "青铜峡市"; + case 6404: + return "固原市"; + case 640401: + return "市辖区"; + case 640402: + return "原州区"; + case 640422: + return "西吉县"; + case 640423: + return "隆德县"; + case 640424: + return "泾源县"; + case 640425: + return "彭阳县"; + case 6405: + return "中卫市"; + case 640501: + return "市辖区"; + case 640502: + return "沙坡头区"; + case 640521: + return "中宁县"; + case 640522: + return "海原县"; + case 65: + return "新疆维吾尔自治区"; + case 6501: + return "乌鲁木齐市"; + case 650101: + return "市辖区"; + case 650102: + return "天山区"; + case 650103: + return "沙依巴克区"; + case 650104: + return "新市区"; + case 650105: + return "水磨沟区"; + case 650106: + return "头屯河区"; + case 650107: + return "达坂城区"; + case 650109: + return "米东区"; + case 650121: + return "乌鲁木齐县"; + case 6502: + return "克拉玛依市"; + case 650201: + return "市辖区"; + case 650202: + return "独山子区"; + case 650203: + return "克拉玛依区"; + case 650204: + return "白碱滩区"; + case 650205: + return "乌尔禾区"; + case 6521: + return "吐鲁番地区"; + case 652101: + return "吐鲁番市"; + case 652122: + return "鄯善县"; + case 652123: + return "托克逊县"; + case 6522: + return "哈密地区"; + case 652201: + return "哈密市"; + case 652222: + return "巴里坤哈萨克自治县"; + case 652223: + return "伊吾县"; + case 6523: + return "昌吉回族自治州"; + case 652301: + return "昌吉市"; + case 652302: + return "阜康市"; + case 652323: + return "呼图壁县"; + case 652324: + return "玛纳斯县"; + case 652325: + return "奇台县"; + case 652327: + return "吉木萨尔县"; + case 652328: + return "木垒哈萨克自治县"; + case 6527: + return "博尔塔拉蒙古自治州"; + case 652701: + return "博乐市"; + case 652702: + return "阿拉山口市"; + case 652722: + return "精河县"; + case 652723: + return "温泉县"; + case 6528: + return "巴音郭楞蒙古自治州"; + case 652801: + return "库尔勒市"; + case 652822: + return "轮台县"; + case 652823: + return "尉犁县"; + case 652824: + return "若羌县"; + case 652825: + return "且末县"; + case 652826: + return "焉耆回族自治县"; + case 652827: + return "和静县"; + case 652828: + return "和硕县"; + case 652829: + return "博湖县"; + case 6529: + return "阿克苏地区"; + case 652901: + return "阿克苏市"; + case 652922: + return "温宿县"; + case 652923: + return "库车县"; + case 652924: + return "沙雅县"; + case 652925: + return "新和县"; + case 652926: + return "拜城县"; + case 652927: + return "乌什县"; + case 652928: + return "阿瓦提县"; + case 652929: + return "柯坪县"; + case 6530: + return "克孜勒苏柯尔克孜自治州"; + case 653001: + return "阿图什市"; + case 653022: + return "阿克陶县"; + case 653023: + return "阿合奇县"; + case 653024: + return "乌恰县"; + case 6531: + return "喀什地区"; + case 653101: + return "喀什市"; + case 653121: + return "疏附县"; + case 653122: + return "疏勒县"; + case 653123: + return "英吉沙县"; + case 653124: + return "泽普县"; + case 653125: + return "莎车县"; + case 653126: + return "叶城县"; + case 653127: + return "麦盖提县"; + case 653128: + return "岳普湖县"; + case 653129: + return "伽师县"; + case 653130: + return "巴楚县"; + case 653131: + return "塔什库尔干塔吉克自治县"; + case 6532: + return "和田地区"; + case 653201: + return "和田市"; + case 653221: + return "和田县"; + case 653222: + return "墨玉县"; + case 653223: + return "皮山县"; + case 653224: + return "洛浦县"; + case 653225: + return "策勒县"; + case 653226: + return "于田县"; + case 653227: + return "民丰县"; + case 6540: + return "伊犁哈萨克自治州"; + case 654002: + return "伊宁市"; + case 654003: + return "奎屯市"; + case 654021: + return "伊宁县"; + case 654022: + return "察布查尔锡伯自治县"; + case 654023: + return "霍城县"; + case 654024: + return "巩留县"; + case 654025: + return "新源县"; + case 654026: + return "昭苏县"; + case 654027: + return "特克斯县"; + case 654028: + return "尼勒克县"; + case 6542: + return "塔城地区"; + case 654201: + return "塔城市"; + case 654202: + return "乌苏市"; + case 654221: + return "额敏县"; + case 654223: + return "沙湾县"; + case 654224: + return "托里县"; + case 654225: + return "裕民县"; + case 654226: + return "和布克赛尔蒙古自治县"; + case 6543: + return "阿勒泰地区"; + case 654301: + return "阿勒泰市"; + case 654321: + return "布尔津县"; + case 654322: + return "富蕴县"; + case 654323: + return "福海县"; + case 654324: + return "哈巴河县"; + case 654325: + return "青河县"; + case 654326: + return "吉木乃县"; + case 6590: + return "自治区直辖县级行政区划"; + case 659001: + return "石河子市"; + case 659002: + return "阿拉尔市"; + case 659003: + return "图木舒克市"; + case 659004: + return "五家渠市"; + case 71: + return "台湾省"; + case 81: + return "香港特别行政区"; + case 82: + return "澳门特别行政区"; + default: + return null; + } + } + +} diff --git a/src/com/engine/salary/formlua/util/RegularUtil.java b/src/com/engine/salary/formlua/util/RegularUtil.java new file mode 100644 index 000000000..9ea89a9dc --- /dev/null +++ b/src/com/engine/salary/formlua/util/RegularUtil.java @@ -0,0 +1,241 @@ +package com.engine.salary.formlua.util; + + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @className: + * @Description:正则表达式工具 + * @Author: + * @date: + */ +public class RegularUtil { + public static void validateIDCard(String idCard){ + Pattern pattern = Pattern.compile("^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"); + Matcher matcher = pattern.matcher(idCard); + if (!matcher.matches()) { + throw new RuntimeException("身份证号码不合法"); + } + } + public static void checkAggCnd(String formula){ + String startPartternStr="^(OR\\(|AND\\()"; + Pattern startPattern = Pattern.compile(startPartternStr); + Matcher startMatcher = startPattern.matcher(formula); + if(!startMatcher.find()){ + throw new RuntimeException("条件筛选函数只允许AND函数与OR函数"); + } +// else { +// String partternStr="(AND|OR)+\\(+(.)+\\)+"; +// Pattern pattern = Pattern.compile(partternStr); +// Matcher matcher = pattern.matcher(formula); +// while (matcher.find()){ +// String fr=matcher.group(); +// logger.info(fr); +// fr=fr.replaceAll("(AND|OR)",""); +// String partternStr2="(.)+\\(+(.)+\\)+"; +// Pattern pattern2 = Pattern.compile(partternStr2); +// Matcher matcher2 = pattern2.matcher(fr); +// if(matcher2.find()){ +// throw new RuntimeException("条件筛选参数不正确"); +// } +// } +// } + } + public static boolean isNumber(Object obj) { + if(obj==null){ + return false; + } + String nstr=obj.toString(); + String reg = "\\d+(\\.\\d+)?"; + if(nstr.startsWith("-")){ + nstr=nstr.substring(1); + } + Boolean strResult = nstr.matches(reg); + return strResult; + } + + /** + * 判断是否是0或正整数 + * @param obj + * @return + */ + public static boolean isNonNegativeInteger(Object obj) { + if(obj == null) return false; + String nstr = obj.toString(); + + String reg = "^[1-9]\\d*|0$"; + return nstr.matches(reg); + } + + /** + * 是否是整数,正整数、0、负整数 + * @param obj + * @return + */ + public static boolean isInteger(Object obj){ + if(obj == null) return false; + String nstr = obj.toString(); + + String reg = "^-?[1-9]\\d*$"; + return nstr.matches(reg); + } + + /** + * IF函数的规则判断 + * @param str + * @return + */ + public static Map checkIfFunc(String str){ + Map rmap=new HashMap(); + str=str.trim().replaceAll(" ",""); + boolean r=true; + String patt="if{1}\\({1}\\w+[<|>|!=|==]+\\w+\\){1}[\\w\\{\\}]*"; + String charCheckIf="if{1}"; + String charCheckLf="if{1}\\({1}"; + String charCheckRf="\\){1}"; + String paramLeft="\\({1}\\w+[<|>|!=]+"; + String paramRight="[<|>|!=]+\\w+\\){1}"; + String paramOperSym="[<|>|!=]+"; + Pattern rPattern = Pattern.compile(patt); + Pattern ifPattern=Pattern.compile(charCheckIf); + Pattern leftPattern=Pattern.compile(charCheckLf); + Pattern rightPattern=Pattern.compile(charCheckRf); + Pattern leftParamPatt=Pattern.compile(paramLeft); + Pattern rightParamPatt = Pattern.compile(paramRight); + Pattern operSybmPattern=Pattern.compile(paramOperSym); + + //先测试整条语句是否符合规则 + boolean pOneResult=rPattern.matcher(str).find(); + + + if(!pOneResult){ + //以下为逐一排查问题的位置 + boolean pIfResult =ifPattern.matcher(str).find(); + boolean leftResult=leftPattern.matcher(str).find(); + boolean rightResult=rightPattern.matcher(str).find(); + boolean lpResult=leftParamPatt.matcher(str).find(); + boolean rpResult=rightParamPatt.matcher(str).find(); + boolean operSybmResult=operSybmPattern.matcher(str).find(); + r=false; + rmap.put("result",r); + if(!pIfResult){ + rmap.put("info","格式不正确缺少if标识符"); + }else if(!leftResult){ + rmap.put("info","格式不正确缺少左括号(标识符"); + }else if(!rightResult){ + rmap.put("info","格式不正确缺少右括号)标识符"); + }else if(!lpResult){ + rmap.put("info","格式不正确缺少左侧参数"); + }else if(!rpResult){ + rmap.put("info","格式不正确缺少右侧参数"); + }else if(!operSybmResult){ + rmap.put("info","格式不正确缺少操作符"); + }else{ + rmap.put("info","格式未通过格式验证"); + } + + } + return rmap; + } + /** + * 判断是否含有字母 + * @param str + * @return + */ + public static boolean containsLetter(String str) { + String patt="[a-z|A-Z]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + return matcher.find(); + } + + /** + * 判断是否含有数字 + * @param str + * @return + */ + public static boolean containsNum(String str) { + String patt="[0-9]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + return matcher.find(); + } + + /** + * 判断是否含有非字母 + * @param str + * @return + */ + public static boolean containsNotLetter(String str) { + String patt="[^a-z|^A-Z]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + return matcher.find(); + } + + /** + * 判断是否包含非数字 + * @param str + * @return + */ + public static boolean containsNotNum(String str){ + String patt="[^0-9]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + return matcher.find(); + } + /** + * 替换非字母 + * @param str + * @return + */ + public static String containsNotLetterR(String str,String replaceStr) { + String patt="[^a-z|^A-Z]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + return matcher.replaceAll(replaceStr); + } + /** + * 替换非数字 + * @param str + * @param replaceStr + * @return + */ + public static String containsNotNumR(String str,String replaceStr){ + String patt="[^0-9]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + return matcher.replaceAll(replaceStr); + } + + /** + * 判断是否含有字母并替换 + * @param str + * @param replaceStr + * @return + */ + public static String containsLetterR(String str,String replaceStr) { + String patt="[a-z|A-Z]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + str=matcher.replaceAll(replaceStr); + return str; + } + + /** + * 判断是否含有数字并替换 + * @param str + * @param replaceStr + * @return + */ + public static String containsNumR(String str,String replaceStr) { + String patt="[0-9]"; + Pattern r = Pattern.compile(patt); + Matcher matcher = r.matcher(str); + return matcher.replaceAll(replaceStr); + } + +} diff --git a/src/com/engine/salary/formlua/util/SortUtil.java b/src/com/engine/salary/formlua/util/SortUtil.java new file mode 100644 index 000000000..f3081283e --- /dev/null +++ b/src/com/engine/salary/formlua/util/SortUtil.java @@ -0,0 +1,49 @@ +package com.engine.salary.formlua.util; + + +public class SortUtil { + /** + * 数组快速排序 + * @param array + * @param left + * @param right + */ + public static void sort(int[] array, int left, int right){ + if(left > right) { + return; + } + // base中存放基准数 + int base = array[left]; + int i = left, j = right; + while(i != j) { + // 顺序很重要,先从右边开始往左找,直到找到比base值小的数 + while(array[j] >= base && i < j) { + j--; + } + + // 再从左往右边找,直到找到比base值大的数 + while(array[i] <= base && i < j) { + i++; + } + + // 上面的循环结束表示找到了位置或者(i>=j)了,交换两个数在数组中的位置 + if(i < j) { + int tmp = array[i]; + array[i] = array[j]; + array[j] = tmp; + } + } + + // 将基准数放到中间的位置(基准数归位) + array[left] = array[i]; + array[i] = base; + + // 递归,继续向基准的左右两边执行和上面同样的操作 + // i的索引处为上面已确定好的基准值的位置,无需再处理 + sort(array, left, i - 1); + sort(array, i + 1, right); + } + + + +} diff --git a/src/com/engine/salary/formlua/util/TestUtil.java b/src/com/engine/salary/formlua/util/TestUtil.java new file mode 100644 index 000000000..1fcab01eb --- /dev/null +++ b/src/com/engine/salary/formlua/util/TestUtil.java @@ -0,0 +1,403 @@ +package com.engine.salary.formlua.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.ql.util.express.DynamicParamsUtil; +import com.ql.util.express.ExpressRunner; +import com.ql.util.express.IExpressContext; +import com.weaver.common.form.component.base.ComponentType; +import com.weaver.common.form.stat.FilterFormData; +import com.weaver.excel.formula.api.entity.CustomFunc; +import com.weaver.excel.formula.core.QLExpressContext; +import com.weaver.excel.formula.entity.parameter.DataType; +import com.weaver.excel.formula.entity.parameter.FuncNames; +import com.weaver.excel.formula.entity.parameter.standard.FormulaFilterData; +import com.weaver.excel.formula.func.compare.EqOperator; +import com.weaver.excel.formula.func.compare.test.GreaterOperator; +import com.weaver.excel.formula.func.compare.test.LessOperator; +import com.weaver.excel.formula.func.custom.CustomService; +import com.weaver.excel.formula.func.custom.CustomServiceTestImpl; +import com.weaver.excel.formula.func.date.DateTimeService; +import com.weaver.excel.formula.func.date.DateTimeServiceImpl; +import com.weaver.excel.formula.func.extend.ExcelExtendFuncService; +import com.weaver.excel.formula.func.extend.ExcelExtendFuncServiceImpl; +import com.weaver.excel.formula.func.finance.FinanceService; +import com.weaver.excel.formula.func.finance.FinanceServiceImpl; +import com.weaver.excel.formula.func.logic.LogicUtils; +import com.weaver.excel.formula.func.math.MathFuncsService; +import com.weaver.excel.formula.func.math.MathFuncsServiceImpl; +import com.weaver.excel.formula.func.string.StringFormulaService; +import com.weaver.excel.formula.func.string.StringFormulaServiceImpl; +import com.weaver.excel.formula.util.standard.ExcelDataType; +import com.weaver.teams.domain.user.SimpleEmployee; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +import java.util.*; + +public class TestUtil { + protected static final Logger logger = LoggerFactory.getLogger(TestUtil.class); + @Autowired + ApplicationContext applicationContext; + public void test() throws Exception { + DynamicParamsUtil.supportDynamicParams = true; + ExpressRunner runner = new ExpressRunner(true,false); + initRunner(runner); + Map context=new HashMap<>(); + DataType dataType1=new DataType(); + dataType1.setContent(1); + dataType1.setFieldId("a"); + dataType1.setComponentKey(ComponentType.NumberComponent.toString()); + dataType1.setDataType(DataType.NUMBER); + + DataType dataType2=new DataType(); + dataType2.setFieldId("b"); + dataType2.setComponentKey(ComponentType.NumberComponent.toString()); + dataType2.setContent(2); + dataType2.setDataType(DataType.NUMBER); + + context.put("key111","2345.66"); + context.put("a",dataType1); + context.put("b",dataType2); + context.put("dateA",dataType1); + context.put("dateB",dataType2); + IExpressContext expressContext = new QLExpressContext(context,applicationContext); +// String expressSql="c=10;function add(int a,int b){return a+b+c;};add(a,b);"; +// String expressSql="import com.weaver.excel.formula.util.DateUtil;isdate=DateUtil.isDateComponent('a');System.out.println('是日期吗?'+(isdate?'是':'不是'));"; +// String expressSql="TEST(key111)=TEST(key111)"; + + String expressSql="CUSTOM1(dateA,function1());"; + + String [] varList=runner.getOutVarNames(expressSql); + String [] funcList=runner.getOutFunctionNames(expressSql); +// OperatorBase operatorBase=runner.getFunciton("TEST"); + Object result=runner.execute(expressSql, expressContext, null, false, false); + logger.info("执行结果:"+JSON.toJSONString(result)); + } + + private void initRunner(ExpressRunner runner) throws Exception { + ExcelExtendFuncService excelExtendFuncService=new ExcelExtendFuncServiceImpl("biaoge","TEST"); + ExcelExtendFuncService excelExtendFuncService2=new ExcelExtendFuncServiceImpl("workflow","TEST2"); + //加载自定义脚本函数 + CustomFunc customFunc=new CustomFunc(); + customFunc.setFuncContent("function add(int a,int b){return a+b;};add(a1,b1);"); + customFunc.setFuncName("CUSTOM1"); + customFunc.setFuncTitle("自定义函数1"); + customFunc.setExcelDataType(ExcelDataType.number.toString()); + CustomService customService=new CustomServiceTestImpl(customFunc); + + DateTimeService dateTimeService=new DateTimeServiceImpl(); +// DateTimeService dateTimeService=new DateTimeTestServiceImpl(); + MathFuncsService mathFuncsService=new MathFuncsServiceImpl(); + StringFormulaService stringFormulaService=new StringFormulaServiceImpl(); + FinanceService financeService=new FinanceServiceImpl(); + runner.replaceOperator("=",new EqOperator("=")); + runner.replaceOperator(">",new GreaterOperator(">")); + runner.replaceOperator("<",new LessOperator("<")); + runner.addFunctionOfServiceMethod( "TEST",excelExtendFuncService,"execute",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "TEST2",excelExtendFuncService2,"execute",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "ISINT",mathFuncsService,"isInt",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "ISNUMBER",mathFuncsService,"isNumber",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "ISJSON",stringFormulaService,"isJson",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "GETJSONVALUE",stringFormulaService,"getJSONValue",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "COMPAREDATE",dateTimeService,"compareDate",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "CURRYEAR",dateTimeService,"currYear",new Class[]{},""); + runner.addFunctionOfServiceMethod( "CURRMONTH",dateTimeService,"currMonth",new Class[]{},""); + runner.addFunctionOfServiceMethod( "CURRDAY",dateTimeService,"currDay",new Class[]{},""); + runner.addFunctionOfServiceMethod( "CURRWEEK",dateTimeService,"currWeek",new Class[]{},""); + runner.addFunctionOfServiceMethod( "CURRHOUR",dateTimeService,"currHour",new Class[]{},""); + runner.addFunctionOfServiceMethod( "CURRMINUTE",dateTimeService,"currMinute",new Class[]{},""); + runner.addFunctionOfServiceMethod( "CURRSECOND",dateTimeService,"currSecond",new Class[]{},""); + runner.addFunctionOfServiceMethod( "GETMONEY", financeService,"getMoney",new Class[]{Object[].class},""); + runner.addFunctionOfServiceMethod( "CUSTOM1", customService,"execute",new Class[]{Object[].class},""); + } + + + public static void parseJ(){ + JSONObject queryObj=JSON.parseObject("{\"expressSql\":\"VLOOKUPS({工资薪金税(居民)},AND({薪资项目.当前累计应纳税所得额}>{个税税表.应纳税所得额下限},{薪资项目.当前累计应纳税额}<={个税税表.应纳税所得额上限}),[{个税税表.税率}])\",\"parameters\":[{\"dataId\":\"60000000000000001\",\"title\":\"工资薪金税(居民)\",\"module\":\"hrmsalary\",\"name\":\"工资薪金税(居民)\",\"id\":\"60000000000000001\",\"action\":\"DataSource\"},{\"name\":\"当前累计应纳税所得额\",\"module\":\"hrmsalary\",\"fieldId\":\"1_addUpTaxableIncome\",\"formId\":\"1\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"当前累计应纳税所得额\"},{\"name\":\"应纳税所得额下限\",\"module\":\"hrmsalary\",\"fieldId\":\"10_taxableIncomeLLimit\",\"formId\":\"10\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"应纳税所得额下限\"},{\"name\":\"当前累计应纳税额\",\"module\":\"hrmsalary\",\"fieldId\":\"1_addUpTaxPayable\",\"formId\":\"1\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"当前累计应纳税额\"},{\"name\":\"应纳税所得额上限\",\"module\":\"hrmsalary\",\"fieldId\":\"10_taxableIncomeULimit\",\"formId\":\"10\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"应纳税所得额上限\"},{\"name\":\"税率\",\"module\":\"hrmsalary\",\"fieldId\":\"10_taxRate\",\"formId\":\"10\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"税率\"}],\"returnType\":\"number\",\"validateType\":\"normal\"}"); + JSONArray jsonArray = queryObj.getJSONArray("parameters"); + List dataTypeList=new ArrayList<>(); + + for (Object obj : jsonArray) { + JSONObject jsonObj = (JSONObject) obj; + DataType paramData=new DataType(); + paramData.setComponentKey(DataType.STRING); + paramData.setFieldId(jsonObj.getString("fieldId")); + paramData.setContent("123"); + dataTypeList.add(paramData); + } + + DataType dataType1=dataTypeList.get(1); + DataType dataType2=dataTypeList.get(3); + FormulaFilterData formulaFilterData1=new FormulaFilterData(); + formulaFilterData1.setContent(dataType1.getContent()+""); + formulaFilterData1.setCondition(FilterFormData.TERM_GT); + formulaFilterData1.setFieldId(dataType1.getFieldId()); + formulaFilterData1.setCondition(FormulaFilterData.CONDITION_AND); + + FormulaFilterData formulaFilterData2=new FormulaFilterData(); + formulaFilterData2.setContent(dataType2.getContent()+""); + formulaFilterData2.setCondition(FilterFormData.TERM_GT); + formulaFilterData2.setFieldId(dataType2.getFieldId()); + formulaFilterData2.setCondition(FormulaFilterData.CONDITION_AND); + + + List filterDatas=new ArrayList<>(); + filterDatas.add(formulaFilterData1); + filterDatas.add(formulaFilterData2); + String dataId="60000000000000001"; + String[] cols=new String[]{"10_taxRate"}; + SimpleEmployee employee=new SimpleEmployee(); + employee.setTenantKey("tm7tozevws"); + employee.setUserId(5113514575963198048L); + employee.setId(3573514574891514361L); + employee.setUsername("顿顿"); + System.out.println(dataId); + System.out.println(JSON.toJSONString(filterDatas)); + System.out.println(JSON.toJSONString(cols)); + System.out.println(JSON.toJSONString(employee)); + } + public static Object executeInner(Object[] list) throws Exception { + DataType result=new DataType(); + result.setDataType(DataType.BOOL); + if(list.length<1||list[1]==null){ + Integer number= IgnoreParamFilter.getSetFuncNumber("IN"); + JSONObject errorJson= ErrorUtil.buildError("IN",number,number,"IN函数至少需要两个参数"); + throw new RuntimeException(errorJson.getString("msg")); + } + List paramList=new ArrayList<>(); + paramList.add(list[0]); + + Object[] objectArray=null; + if(list[1].getClass().isArray()){ + objectArray=(Object[])list[1]; + for (int i=0;i(); + paramList.add(null); + List dataArray=new ArrayList<>(); + if(list[0] instanceof DataType){ + DataType dataType=(DataType)list[0]; + if(dataType.getDataType().equals(DataType.OPTION)){ + if(dataType.getContent()!=null){ + String[] arrys=dataType.getContent().toString().split(","); + for (int i=0;i0 && testI!=objects.length){ + Object cndObj=objects[testI-1]; + if(!(cndObj instanceof Boolean) && !(cndObj instanceof DataType)){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); + throw new RuntimeException(errorJson.getString("msg")); + }else if(cndObj instanceof DataType){ + DataType boolDataType=(DataType)cndObj; + if(boolDataType.getContent()!=null && !(boolDataType.getContent() instanceof Boolean)){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); + throw new RuntimeException(errorJson.getString("msg")); + } + } + } + } + + boolean paramCheck=checkParamType(objects); + if(!paramCheck){ + JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数多个条件的返回值必须一致"); + throw new RuntimeException(errorJson.getString("msg")); + } + + int i; + for(i=1;i<=objects.length;i++){ + if(i%2==0){ + Object cndObj=objects[i-2]; + if(cndObj instanceof Boolean){ + Boolean cnd=(Boolean)cndObj; + if(cnd){ + if(objects[i-1] instanceof DataType){ + return (DataType) objects[i-1]; + }else{ + return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i-1].getClass().getName())),objects[i-1]); + } +// return new DataType(DataType.BOOL,objects[i-1]); + } + }else if(cndObj instanceof DataType){ + DataType boolData=(DataType)cndObj; + Boolean cnd=boolData.getContent()!=null?( (Boolean)boolData.getContent() ) : false; + if(cnd){ + if(objects[i-1] instanceof DataType){ + return (DataType) objects[i-1]; + }else { + return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i-1].getClass().getName())),objects[i-1]); + } + + } + } + } + } + //如果没有条件符合,返回默认值,最后一个参数为默认值 + Object result=ExcelParamUtil.getParamContent(objects[objects.length-1],""); + if(result instanceof DataType){ + return (DataType)result; + }else{ + return new DataType(DataType.returnType(ExcelParamUtil.getParamType(result.getClass().getName())),result); + } + + } + private static boolean checkParamType(Object[] objects){ + boolean result=false; + String type=null; + for (int i=1;i<=objects.length;i++){ + if(i%2==0){ + Object obj=objects[i-1]; + String typeStr=ExcelParamUtil.getParamType(obj); + typeStr=ExcelParamUtil.checkParamType(typeStr); + logger.info(typeStr); + if(type==null){ + type=typeStr; + }else{ + result=typeStr.equalsIgnoreCase(type); + if(!result){ + return result; + } + + } + } + } + String typeStr=ExcelParamUtil.checkParamType(ExcelParamUtil.getParamType(objects[objects.length-1])); + result=type.equalsIgnoreCase(typeStr); + return result; + } + public static Object chooseOne(Object... objects) { + if(objects==null || objects.length<2){ + throw new RuntimeException("CHOOSE函数的参数不能少于两个"); + } + DataType dataType=new DataType(); + boolean checkResult=IgnoreParamFilter.checkType(objects); + if(checkResult){ + int indexData=0; + Object firstObj=objects[0]; + try { + if(firstObj !=null){ + Double doubleValue=null; + if(firstObj instanceof DataType){ + DataType indexDataType=(DataType)firstObj; + if(ExcelParamUtil.findDataType(indexDataType.getDataType()).equalsIgnoreCase(DataType.NUMBER)){ + if(indexDataType.getContent()!=null){ + doubleValue=Double.parseDouble(indexDataType.getContent()+""); + } + } + }else{ + doubleValue=Double.parseDouble(firstObj+""); + } + indexData=doubleValue.intValue(); + }else{ + throw new RuntimeException("CHOOSE函数第一个参数不能为空"); + } + + } catch (NumberFormatException e) { + logger.error("err",e); + } + List dataList=ExcelParamUtil.getParamContent(objects); + if(indexData>=dataList.size()){ + indexData=dataList.size()-1; + } + Object resultObj=dataList.get(indexData); + if(resultObj!=null){ + if(resultObj instanceof DataType){ + dataType=(DataType)resultObj; + }else { + String type=ExcelParamUtil.getParamType(resultObj.getClass().getName()); + dataType.setDataType(type); + dataType.setContent(resultObj); + } + } + }else { + throw new RuntimeException("CHOOSE函数的参数类型不一致"); + } + logger.info("CHOOSE校验执行结果:"+ JSON.toJSONString(dataType)); + return dataType; + } + private static void testOption(DataType dataType,DataType dataType2){ + //对option的特殊处理,获取option的字符串后根据逗号分割,然后排序数组,数组长度不一致返回false,一致则循环对比直到同样下标的数据不一致返回false,否则为true + String[] firstOptions=new String[]{}; + String[] secondOptions=new String[]{}; + firstOptions= CompareUtil.genArray(dataType,"option"); + secondOptions=CompareUtil.genArray(dataType2,"option"); + Arrays.sort(firstOptions); + Arrays.sort(secondOptions); + + logger.info("比较选项:"+JSON.toJSONString(firstOptions)+"-->"+JSON.toJSONString(secondOptions)); + if(firstOptions.length!=secondOptions.length){ + }else{ + int i=0; + for (;i dataOptions, FixFieldType fixFieldType){ + FormulaVar formulaVar=new FormulaVar(); + formulaVar.setFormId(sourceId+""); + formulaVar.setDataType(ExcelParamUtil.findType(fixFieldType.toString())); + formulaVar.setContent(content); + formulaVar.setFixName(name); + formulaVar.setFixFieldKey(fixFieldKey); + formulaVar.setId(fixFieldKey); + formulaVar.setKey(fixFieldKey); + formulaVar.setFieldId(fixFieldKey); + if(fixFieldType==FixFieldType.Select || fixFieldType==FixFieldType.Department || fixFieldType == FixFieldType.Employee || fixFieldType == FixFieldType.Relate){ + formulaVar.setDataOptionList(dataOptions); + String options=""; + for(DataOption dataOption:dataOptions){ + options+=dataOption.getOptionId(); + } + formulaVar.setContent(options); + formulaVar.setComponentKey(ComponentType.Employee.toString()); + } + return formulaVar; + } + + /** + * 构建字段数据,文本、数字、日期使用此方法 + * @param sourceId + * @param fieldId + * @param excelDataType + * @param module + * @param value + * @return + */ + public static FormulaVar buildTxtNumDateField(Long sourceId,Long fieldId,ExcelDataType excelDataType,String module,Object value){ + return commonBuildField(sourceId,fieldId,excelDataType,module,null,value); + } + + /** + * 构建选项型或数据源型使用此方法 + * @param sourceId + * @param fieldId + * @param excelDataType + * @param module + * @param dataOptions + * @return + */ + public static FormulaVar buildOptionField(Long sourceId,Long fieldId,ExcelDataType excelDataType,String module,List dataOptions){ + return commonBuildField(sourceId,fieldId,excelDataType,module,dataOptions,null); + } + private static FormulaVar commonBuildField(Long sourceId,Long fieldId,ExcelDataType excelDataType,String module,List dataOptions,Object value){ + FormulaVar formulaVar =new FormulaVar(); + formulaVar.setContent(value+""); + formulaVar.setFieldId(fieldId+""); + formulaVar.setFormId(sourceId+""); + formulaVar.setDataType(excelDataType.toString()); + formulaVar.setModule(module); + if(dataOptions!=null && dataOptions.size()>0){ + formulaVar.setDataOptionList(dataOptions); + String optionStr=""; + for(DataOption dataOption:dataOptions){ + optionStr+=dataOption.getOptionId(); + } + formulaVar.setContent(optionStr); + } + return formulaVar; + } + + /** + * 转换表单字段数据为函数标准参数对象 + * @param formDataDetailList 表单字段数据列表 + * @param sourceId 表单ID或者数据源ID + * @param module 所属模块 + * @return + */ + public List transFieldForForm(List formDataDetailList,Long layoutId, Long sourceId, ModuleSource module,SimpleEmployee simpleEmployee){ + List formulaVarList=new ArrayList<>(); + if(formDataDetailList!=null && formDataDetailList.size()>0){ + + Map fieldMap = bulidFreeFormService(module).getFieldMapByFormId(sourceId, simpleEmployee); + FormulaVar formulaVar =null; + Map replaceMap=new HashMap<>(); + for (FormDataDetail formDataDetail:formDataDetailList){ + if(formDataDetail.getFormField()==null){ + throw new RuntimeException("函数数据转换失败,找不到表单字段数据"); + } + FormField newFormField=fieldMap.get(formDataDetail.getFormField().getId()); + if(newFormField!=null){ + formDataDetail.setFormField(newFormField); + } + Double score=getDetailScoreForForm(formDataDetail,module,layoutId,simpleEmployee); +// Double score=getDetailScore(formDataDetail,module,layoutId,simpleEmployee); + formulaVar=new FormulaVar(); + if(score!=null){ + formulaVar.setScore(score); + } + FormField formField=formDataDetail.getFormField(); + formulaVar.setContent(formDataDetail.getContent()); + if(formDataDetail.getDataText()!=null && StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ + if(StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ + formulaVar.setContent(formDataDetail.getDataText().getContent()); + } + } + formulaVar.setFieldId(formField.getId()!=null?formField.getId()+"":null); + formulaVar.setFormId(formField.getFormId()!=null?formField.getFormId()+"":null); + formulaVar.setComponentKey(formField.getComponentKey()); + if(formField.getSubForm()!=null){ + formulaVar.setsFormId(formField.getSubForm().getId()+""); + } + formulaVar.setDataType(ExcelParamUtil.findType(formField.getComponentKey())); + formulaVar.setModule(module.toString()); + if(formulaVar.getFormId()==null){ + formulaVar.setFormId(sourceId+""); + } + if(formDataDetail.getDataOptions()!=null && formDataDetail.getDataOptions().size()>0){ + List formDataOptions=formDataDetail.getDataOptions(); + List excelOptionList=new ArrayList<>(); + String optionstr=""; + String optionContent=""; + for(FormDataOption formDataOption:formDataOptions){ + DataOption dataOption=new DataOption(); + dataOption.setOptionId(formDataOption.getOptionId()+""); + dataOption.setOptionContent(formDataOption.getContent()); + excelOptionList.add(dataOption); + optionstr+=formDataOption.getOptionId(); + optionContent+=formDataOption.getContent(); + } + if(StringUtils.isNotEmpty(optionstr)){ + formulaVar.setContent(optionstr); + } + formulaVar.setOptionContent(optionContent); + formulaVar.setDataOptionList(excelOptionList); + } + //明细替换处理 + try { + if(!replaceMap.containsKey(formDataDetail.getFormField().getId())){ + replaceMap.put(formDataDetail.getFormField().getId(),formDataDetail); + }else{ + FormDataDetail lastFormDataDetail=replaceMap.get(formDataDetail.getFormField().getId()); + if(formDataDetail.getDataIndex()!=null && lastFormDataDetail.getDataIndex()!=null){ + if(formDataDetail.getDataIndex().longValue() loopData.getFieldId().equalsIgnoreCase(formDataDetail.getFormField().getId().toString())); + logger.info("替换了:"+JSON.toJSONString(formDataDetail)); + }else{ + continue; + } + } + } + } catch (Exception e) { + logger.error("err",e); + } + + formulaVarList.add(formulaVar); + } + } + return formulaVarList; + } + + /** + * 转换表单字段数据为函数标准参数对象 + * @param formDataDetailList 表单字段数据列表 + * @param sourceId 表单ID或者数据源ID + * @param module 所属模块 + * @return + */ + public List transField(List formDataDetailList,Long layoutId, Long sourceId, ModuleSource module,SimpleEmployee simpleEmployee){ + List formulaVarList=new ArrayList<>(); + if(formDataDetailList!=null && formDataDetailList.size()>0){ + + Map fieldMap = bulidFreeFormService(module).getFieldMapByFormId(sourceId, simpleEmployee); + + FormulaVar formulaVar =null; + for (FormDataDetail formDataDetail:formDataDetailList){ + if(formDataDetail.getFormField()==null){ + throw new RuntimeException("函数数据转换失败,找不到表单字段数据"); + } + FormField newFormField=fieldMap.get(formDataDetail.getFormField().getId()); + if(newFormField!=null){ + formDataDetail.setFormField(newFormField); + } + Double score=getDetailScore(formDataDetail,module,layoutId,simpleEmployee); + + formulaVar=new FormulaVar(); + if(score!=null){ + formulaVar.setScore(score); + } + FormField formField=formDataDetail.getFormField(); + formulaVar.setContent(formDataDetail.getContent()); + if(formDataDetail.getDataText()!=null && StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ + if(StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ + formulaVar.setContent(formDataDetail.getDataText().getContent()); + } + } + formulaVar.setFieldId(formField.getId()!=null?formField.getId()+"":null); + formulaVar.setFormId(formField.getFormId()!=null?formField.getFormId()+"":null); + formulaVar.setComponentKey(formField.getComponentKey()); + if(formField.getSubForm()!=null){ + formulaVar.setsFormId(formField.getSubForm().getId()+""); + } + formulaVar.setDataType(ExcelParamUtil.findType(formField.getComponentKey())); + formulaVar.setModule(module.toString()); + if(formulaVar.getFormId()==null){ + formulaVar.setFormId(sourceId+""); + } + if(formDataDetail.getDataOptions()!=null && formDataDetail.getDataOptions().size()>0){ + List formDataOptions=formDataDetail.getDataOptions(); + List excelOptionList=new ArrayList<>(); + String optionstr=""; + String optionContent=""; + for(FormDataOption formDataOption:formDataOptions){ + DataOption dataOption=new DataOption(); + dataOption.setOptionId(formDataOption.getOptionId()+""); + dataOption.setOptionContent(formDataOption.getContent()); + excelOptionList.add(dataOption); + optionstr+=formDataOption.getOptionId(); + optionContent+=formDataOption.getContent(); + } + if(StringUtils.isNotEmpty(optionstr)){ + formulaVar.setContent(optionstr); + } + formulaVar.setOptionContent(optionContent); + formulaVar.setDataOptionList(excelOptionList); + } + + formulaVarList.add(formulaVar); + } + } + return formulaVarList; + } + + public Double getDetailScore(FormDataDetail dataDetail, ModuleSource module, Long layoutId, SimpleEmployee employee) { + Double score = null; + FormField formField=dataDetail.getFormField(); +// logger.info("获取分数的参数:"+(JSON.toJSONString(dataDetail))); +// logger.info("获取分数的布局ID:"+(layoutId)); + if( ComponentType.RadioBox.toString().equals(formField.getComponentKey()) + || ComponentType.CheckBox.toString().equals(formField.getComponentKey()) + || ComponentType.Select.toString().equals(formField.getComponentKey())) { +// score=getDetailScoreForForm(dataDetail,module,layoutId,employee); + score = bulidFreeFormService(module).getOptionScore(dataDetail.getFormField().getId()+"", layoutId, dataDetail, employee).doubleValue(); + } + return score; + } + public Double getDetailScoreForForm(FormDataDetail dataDetail, ModuleSource module, Long layoutId, SimpleEmployee employee) { + Double score = null; + FormField formField=dataDetail.getFormField(); + if( ComponentType.RadioBox.toString().equals(formField.getComponentKey()) + || ComponentType.CheckBox.toString().equals(formField.getComponentKey()) + || ComponentType.Select.toString().equals(formField.getComponentKey())) { + if(dataDetail.getDataOptions()!=null && dataDetail.getDataOptions().size()>0){ + Double scoreSum=0D; + for(FormDataOption formDataOption:dataDetail.getDataOptions()){ + try { + if(StringUtils.isNotEmpty(formDataOption.getScore())){ + scoreSum+=Double.parseDouble(formDataOption.getScore()); + } + } catch (NumberFormatException e) { + logger.error("err",e); + } +// scoreString=scoreSum.toString(); + } + if(scoreSum!=null){ + try { + score=scoreSum; + } catch (NumberFormatException e) { + logger.error("err",e); + } + } + logger.info("获取分数:"+score); + } + } + return score; + } + public FreeFormService bulidFreeFormService(ModuleSource module) { + return freeFormAssistService.buildFreeFormService(module.toString()); + } + +} From a19b19e23dff3ff0ed0f3ace840d47d33a3a3b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Wed, 19 Apr 2023 10:15:01 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../salary/component/SalaryWeaTable.java | 4 +- .../datacollection/bo/AttendQuoteDataBO.java | 6 +- .../salaryacct/bo/SalaryCheckResultBO.java | 6 +- .../formlua/data/ExpressDataService.java | 85 - .../formlua/data/ExpressDataServiceImpl.java | 662 ------ .../salary/formlua/data/func/EqOperator.java | 117 - .../formlua/data/func/LessMoreOperator.java | 115 - .../salary/formlua/data/func/LogicFunc.java | 99 - .../formlua/data/func/NotEqOperator.java | 112 - .../formlua/data/func/QLExpressContext.java | 47 - .../formlua/data/func/QlExpressUtil.java | 148 -- .../formlua/entity/parameter/ExcelFuncs.java | 218 +- .../entity/parameter/FuncDescUtil.java | 222 +- .../entity/parameter/ThreadLocalData.java | 10 +- .../func/date/DateTimeServiceImpl.java | 2 +- .../func/date/DateTimeTestServiceImpl.java | 4 +- .../func/find/FindFuncsServiceImpl.java | 6 +- .../salary/formlua/util/ExcelParamUtil.java | 2042 +++++++++-------- .../formlua/util/ExcelStandardUtil.java | 10 +- .../engine/salary/formlua/util/TestUtil.java | 4 +- .../formlua/util/standard/ExcelTransUtil.java | 320 --- .../remote/attend/cmd/GetKQReportCmd.java | 20 +- .../salary/service/RemoteExcelService.java | 14 +- .../impl/AddUpDeductionServiceImpl.java | 2 +- .../impl/AddUpSituationServiceImpl.java | 2 +- .../service/impl/RemoteExcelServiceImpl.java | 16 +- .../impl/SalaryAcctExcelServiceImpl.java | 4 +- .../service/impl/SalarySendServiceImpl.java | 4 +- .../impl/TaxDeclarationDetailServiceImpl.java | 2 +- .../engine/salary/util/SalaryI18nUtil.java | 6 +- .../salary/web/SalaryAcctController.java | 4 +- .../salary/wrapper/OtherDeductionWrapper.java | 2 +- .../wrapper/SalaryAcctExcelWrapper.java | 4 +- .../wrapper/SalaryAcctResultWrapper.java | 2 +- 34 files changed, 1308 insertions(+), 3013 deletions(-) delete mode 100644 src/com/engine/salary/formlua/data/ExpressDataService.java delete mode 100644 src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java delete mode 100644 src/com/engine/salary/formlua/data/func/EqOperator.java delete mode 100644 src/com/engine/salary/formlua/data/func/LessMoreOperator.java delete mode 100644 src/com/engine/salary/formlua/data/func/LogicFunc.java delete mode 100644 src/com/engine/salary/formlua/data/func/NotEqOperator.java delete mode 100644 src/com/engine/salary/formlua/data/func/QLExpressContext.java delete mode 100644 src/com/engine/salary/formlua/data/func/QlExpressUtil.java delete mode 100644 src/com/engine/salary/formlua/util/standard/ExcelTransUtil.java diff --git a/src/com/engine/salary/component/SalaryWeaTable.java b/src/com/engine/salary/component/SalaryWeaTable.java index b4e41a76c..98110f7ce 100644 --- a/src/com/engine/salary/component/SalaryWeaTable.java +++ b/src/com/engine/salary/component/SalaryWeaTable.java @@ -56,7 +56,7 @@ public class SalaryWeaTable extends WeaTable { Arrays.stream(operates).forEach(o -> { String text = o.text(); int labelId = o.labelId(); - String htmlLabelName = SystemEnv.getHtmlLabelName(labelId, user.getLanguage()); + String htmlLabelName = SalaryI18nUtil.getI18nLabel(labelId, user.getLanguage()); if (StringUtils.isNotBlank(htmlLabelName)) { text = htmlLabelName; } @@ -86,7 +86,7 @@ public class SalaryWeaTable extends WeaTable { SalaryTableColumn columnAnn = f.getAnnotation(SalaryTableColumn.class); String text = columnAnn.text(); int labelId = columnAnn.labelId(); - String htmlLabelName = SystemEnv.getHtmlLabelName(labelId, user.getLanguage()); + String htmlLabelName = SalaryI18nUtil.getI18nLabel(labelId, user.getLanguage()); if (StringUtils.isNotBlank(htmlLabelName)) { text = htmlLabelName; } diff --git a/src/com/engine/salary/entity/datacollection/bo/AttendQuoteDataBO.java b/src/com/engine/salary/entity/datacollection/bo/AttendQuoteDataBO.java index 66bc83223..144ed4c0e 100644 --- a/src/com/engine/salary/entity/datacollection/bo/AttendQuoteDataBO.java +++ b/src/com/engine/salary/entity/datacollection/bo/AttendQuoteDataBO.java @@ -47,10 +47,10 @@ public class AttendQuoteDataBO { }); } -// public static SimpleEmployee getCurrentUser4Remote() { -// SimpleEmployee se = UserContext.getCurrentUser(); +// public static DataCollectionEmployee getCurrentUser4Remote() { +// DataCollectionEmployee se = UserContext.getCurrentUser(); // if(se != null){ -// SimpleEmployee simple = new SimpleEmployee(); +// DataCollectionEmployee simple = new DataCollectionEmployee(); // simple.setId(se.getId()); // simple.setUserId(se.getUserId()); // simple.setUsername(se.getUsername()); diff --git a/src/com/engine/salary/entity/salaryacct/bo/SalaryCheckResultBO.java b/src/com/engine/salary/entity/salaryacct/bo/SalaryCheckResultBO.java index 34b4f3267..a9d26843c 100644 --- a/src/com/engine/salary/entity/salaryacct/bo/SalaryCheckResultBO.java +++ b/src/com/engine/salary/entity/salaryacct/bo/SalaryCheckResultBO.java @@ -8,7 +8,7 @@ //import com.weaver.hrm.salary.entity.salaryacct.po.SalaryCheckResultRecordPO; //import com.weaver.hrm.salary.entity.salarysob.po.SalarySobCheckRulePO; //import com.weaver.hrm.salary.util.SalaryEntityUtil; -//import com.weaver.teams.domain.user.SimpleEmployee; +//import com.weaver.teams.domain.user.DataCollectionEmployee; //import org.apache.commons.collections4.CollectionUtils; //import org.apache.commons.lang3.StringUtils; //import org.apache.commons.lang3.math.NumberUtils; @@ -71,13 +71,13 @@ // public static List convert2RecordListDTO(List salaryCheckResultRecords, // List salarySobCheckRules, // List expressFormulas, -// List simpleEmployees) { +// List simpleEmployees) { // if (CollectionUtils.isEmpty(salaryCheckResultRecords)) { // return Collections.emptyList(); // } // Map formulaMap = SalaryEntityUtil.convert2Map(expressFormulas, ExpressFormula::getId, ExpressFormula::getFormula); // Map checkRuleMap = SalaryEntityUtil.convert2Map(salarySobCheckRules, SalarySobCheckRulePO::getId, SalarySobCheckRulePO::getName); -// Map employeeMap = SalaryEntityUtil.convert2Map(simpleEmployees, SimpleEmployee::getEmployeeId, SimpleEmployee::getName); +// Map employeeMap = SalaryEntityUtil.convert2Map(simpleEmployees, DataCollectionEmployee::getEmployeeId, DataCollectionEmployee::getName); // return salaryCheckResultRecords.stream() // .map(e -> SalaryCheckResultRecordListDTO.builder() // .id(e.getId()) diff --git a/src/com/engine/salary/formlua/data/ExpressDataService.java b/src/com/engine/salary/formlua/data/ExpressDataService.java deleted file mode 100644 index 239974af7..000000000 --- a/src/com/engine/salary/formlua/data/ExpressDataService.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.engine.salary.formlua.data; - -import com.weaver.common.form.data.FormData; -import com.weaver.excel.formula.api.entity.ExpressFormula; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.teams.domain.user.SimpleEmployee; - -import java.util.List; -import java.util.Map; - -/** - * 公式数据交互service - * @author Failymiss - * - */ -public interface ExpressDataService { - - public Map buildCndFilter(Long formId, Long fieldId, String express, Map params, String module, SimpleEmployee employee); - - /** - * 统计函数条件校验 - * @param formId - * @param fieldId - * @param funcName - * @param express - * @param params - * @param module - * @param employee - * @return - * @throws Exception - */ - public Double getAggregateDataTest(Long formId, Long fieldId, String funcName,String module,Map params,SimpleEmployee employee) throws Exception; - - /** - * @param formId - * @param fieldId - * @param funcName - * @param express - * @param params - * @param module - * @param employee - * @return - */ - public Double getAggregateData(Long formId, Long fieldId, String funcName, String express, Map params, String module, SimpleEmployee employee); - - public Double getCommonAggregateData(Long formId,Long fieldId,String funcName,List cndDataType,String moduleSource,SimpleEmployee employee); - - /** - * formdata封装成函数需要的数据结构 - * @param fieldIds 字段id - * @param dataId 当前数据id(上报id,审批id) - * @param module 当前数据module - * @param employee 操作人 - * @return - */ -// public Map bulidDataType(List fieldIds, Long dataId, ModuleSource module, SimpleEmployee employee); - - /** - * @param fieldIds - * @param formData - * @param module - * @param employee - * @return - */ - public Map bulidDataType(List fieldIds, FormData formData, String module,SimpleEmployee employee); - - /** - * 测试统计筛选条件 - */ - public void testFunc(SimpleEmployee employee); - - String getDataType(String componentKey); - - /** - * 给规则库更新时构建筛选条件的一个接口 - * @param formula - * @param targetFormId - * @param employee - * @param formData - * @param module - * @return - */ - Map buildFilterParam(ExpressFormula formula, Long targetFormId, SimpleEmployee employee, FormData formData, String module); - -} diff --git a/src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java b/src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java deleted file mode 100644 index 5d6991b5f..000000000 --- a/src/com/engine/salary/formlua/data/ExpressDataServiceImpl.java +++ /dev/null @@ -1,662 +0,0 @@ -package com.engine.salary.formlua.data; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.google.common.collect.Maps; -import com.weaver.common.base.entity.result.WeaResult; -import com.weaver.common.form.FreeFormAssistService; -import com.weaver.common.form.FreeFormService; -import com.weaver.common.form.FreeStatAssistService; -import com.weaver.common.form.component.base.ComponentConfig; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.common.form.constant.FormGroup; -import com.weaver.common.form.data.FormData; -import com.weaver.common.form.data.FormDataStatus; -import com.weaver.common.form.data.detail.FormDataDetail; -import com.weaver.common.form.data.option.FormDataOption; -import com.weaver.common.form.data.text.FormDataText; -import com.weaver.common.form.metadata.ModuleSource; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.common.form.remoteService.RemoteFreeStatService; -import com.weaver.common.form.stat.FilterFormData; -import com.weaver.common.form.stat.domain.search.FilterFormDataParam; -import com.weaver.common.form.stat.service.serarch.FilterFormDataSearchService; -import com.weaver.context.WeaverSentinelContext; -import com.weaver.excel.formula.api.entity.ExpressFormula; -import com.weaver.excel.formula.api.entity.FormulaVar; -import com.weaver.excel.formula.core.rpc.ExcelDubboInvoker; -import com.weaver.excel.formula.core.rpc.RemoteExcelService; -import com.weaver.excel.formula.data.func.QlExpressUtil; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.entity.parameter.FormulaContext; -import com.weaver.excel.formula.entity.parameter.standard.AggFunc; -import com.weaver.excel.formula.entity.parameter.standard.ExcelResult; -import com.weaver.excel.formula.entity.parameter.standard.FormulaFilterData; -import com.weaver.excel.formula.util.ExcelParamUtil; -import com.weaver.excel.formula.util.standard.ExcelTransUtil; -import com.weaver.framework.rpc.annotation.RpcReference; -import com.weaver.teams.core.orm.mybatis.Page; -import com.weaver.teams.domain.user.SimpleEmployee; -import com.weaver.teams.formreport.remote.RemoteFormReportService; -import com.weaver.utils.WeaverDubboSentinelUtil; -import com.weaver.workflow.common.entity.list.requestlist.RequestListDataVoEntity; -import com.weaver.workflow.common.entity.list.requestlist.RequestListSearchConditionEntity; -import com.weaver.workflow.list.api.rest.publicapi.WflRequestListFormRest; -import com.weaver.workflow.list.api.rest.publicapi.WflSearchConditionRest; -import com.weaver.workflow.report.api.rest.reportstat.WfcReportStatRest; -import org.apache.dubbo.rpc.RpcException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; - -import java.math.BigDecimal; -import java.util.*; - -@Service -@SuppressWarnings("unused") -public class ExpressDataServiceImpl implements ExpressDataService { - - protected final Logger logger = LoggerFactory.getLogger(getClass()); - @Autowired - protected FreeFormAssistService freeFormAssistService; - @RpcReference(group = FormGroup.WORKFLOW) - protected RemoteFreeStatService remoteFlowFreeStatService; - @Autowired - private FreeStatAssistService freeStatAssistService; - @RpcReference(group = "biaoge") - protected RemoteExcelService remoteExcelService; - @RpcReference(group = FormGroup.FORMREPORT) - protected RemoteFreeStatService remoteReportFreeStatService; - @Autowired - private QlExpressUtil qlExpressUtil; - @RpcReference - RemoteFormReportService remoteFormReportService; -// @RpcReference -// private WfcSearchConditionRest wfcSearchConditionRest; - @RpcReference(group = "workflow") - private WflSearchConditionRest wflSearchConditionRest; -// @RpcReference(group = "workflow",timeout = 300000) -// private WfcRequestListFormRest wfcRequestListFormRpc; - @RpcReference(group = "workflow") - private WflRequestListFormRest wflRequestListFormRest; - @Autowired - private ExcelDubboInvoker excelDubboInvoker; - @Autowired - private ExcelTransUtil excelTransUtil; -// @RpcReference(group = "workflow") -// private WfcRequestListFormRest wfcRequestListFormRest; - @RpcReference(group = "hrmsalary") - private RemoteExcelService remoteExcelServiceHrmSalary; - @RpcReference(group = "workflow") - private WfcReportStatRest wfcReportStatRest; - @Autowired - private FilterFormDataSearchService filterFormDataSearchService; - @Override - public void testFunc(SimpleEmployee employee) { - - try { - Map params = new HashMap(); - List formFields = bulidFreeFormService(ModuleSource.biaoge).getFormFieldListByStatus(2598433966837708893L, null, employee); - if(formFields != null && formFields.size() > 0) { - for(FormField formField:formFields) { - params.put("fieldId_"+formField.getId(), formField); - } - } - - String str = "2=5"; - - //测试= ==方法 - logger.info("测试=,==方法"); - - String str2 = "fieldId_2598434392040299458=5"; - - String str3 = "fieldId_3419471597648354446=5"; - logger.info("数字控件:"+JSON.toJSONString(qlExpressUtil.execute(str3, params))); - - String str4 = "fieldId_2598434963895899468='2020-07-14'"; - logger.info("日期控件:"+JSON.toJSONString(qlExpressUtil.execute(str4, params))); - - String str5 = "fieldId_3419471597648354447=5"; - logger.info("选项控件:"+JSON.toJSONString(qlExpressUtil.execute(str5, params))); - - //测试= ==方法 - logger.info("测试 >= <= > < 方法"); - - String str7 = "fieldId_3419471597648354446=5"; - logger.info("数字控件:"+JSON.toJSONString(qlExpressUtil.execute(str3, params))); - - String str8 = "fieldId_2598434963895899468='2020-07-14'"; - logger.info("日期控件:"+JSON.toJSONString(qlExpressUtil.execute(str4, params))); - - logger.info("测试 >= =< !=方法"); - } catch (Exception e) { - logger.error("err",e); - } - } - - @Override - public Double getAggregateDataTest(Long formId, Long fieldId, String funcName,String module,Map params,SimpleEmployee employee) throws Exception { - Double value = 0d; - return 1d; - } - - @SuppressWarnings("unchecked") - @Override - public Map buildCndFilter(Long formId, Long fieldId, String express, Map params, String module, SimpleEmployee employee) { - Map paramMap=new HashMap<>(); - List filterFormDatas = new ArrayList(); - if(express != null) { - if(params == null) { - params = new HashMap(); - } - List formFields = bulidFreeFormService(ModuleSource.valueOf(module)).getFormFieldListByStatus(formId, null, employee); - if(formFields != null && formFields.size() > 0) { - for(FormField formField:formFields) { - params.put("field"+formField.getId(), formField); - } - } - try { - Object object = qlExpressUtil.execute(express, params); - if(object instanceof FilterFormData) { - filterFormDatas.add((FilterFormData) object); - }else if((object instanceof List) && (((List) object).get(0) instanceof FilterFormData)) { - filterFormDatas.addAll((List)object); - } - } catch (Exception e) { - logger.error("err",e); - } - } - Map param = assemblyParam(formId, employee); - if(filterFormDatas != null && filterFormDatas.size() > 0) { - param.put("condition", filterFormDatas.get(0).getCondition()); - } - paramMap.put("param",param); - paramMap.put("filterFormDatas",filterFormDatas); - return paramMap; - } - - @Override - @SuppressWarnings("unchecked") - public Double getAggregateData(Long formId, Long fieldId, String funcName,String express, Map params, String module, SimpleEmployee employee) { - Double value = 0d; - List filterFormDatas = new ArrayList(); - if(express != null) { - if(params == null) { - params = new HashMap(); - } - - List formFields = bulidFreeFormService(ModuleSource.valueOf(module)).getFormFieldListByStatus(formId, null, employee); - if(formFields != null && formFields.size() > 0) { - for(FormField formField:formFields) { - boolean isput=false; - Iterator keysets=params.keySet().iterator(); - while (keysets.hasNext()){ - String key=keysets.next(); - Object obj=params.get(key); - logger.info("聚合函数匹配表单控件:"+key+"-->"+formField.getId()); - if(obj instanceof DataType){ - DataType dataType=(DataType)obj; - if(null!=dataType.getFieldId()&&Long.parseLong(dataType.getFieldId())==formField.getId() && !dataType.getName().equals("当前数据")){ - params.put(key, formField); - }else if(key.indexOf(formField.getId()+"")>0){ - params.put(key, formField); - } - }else if(key.indexOf(formField.getId()+"")>0){ - params.put(key, formField); - } - } - if(!isput){ - params.put("field"+formField.getId(), formField); - } - } - } - logger.info(formId+"aggregate express:"+express); - try { - Object object = qlExpressUtil.execute(express, params); - if(object instanceof FilterFormData) { - filterFormDatas.add((FilterFormData) object); - }else if((object instanceof List) && (((List) object).get(0) instanceof FilterFormData)) { - filterFormDatas.addAll((List)object); - } - } catch (Exception e) { - logger.error("err",e); - } - } - Map param = assemblyParam(formId, employee); - if(filterFormDatas != null && filterFormDatas.size() > 0) { - logger.info(filterFormDatas.get(0).getCondition()); - param.put("condition", StringUtils.isEmpty(filterFormDatas.get(0).getCondition())?"AND":filterFormDatas.get(0).getCondition()); - } -// logger.info(formId+"param聚合参数:"+(param!=null?JSON.toJSONString(param):"NULL")); -// logger.info(formId+"filterFormDatas聚合参数:"+(filterFormDatas!=null?JSON.toJSONString(filterFormDatas):"NULL")); -// logger.info(formId+"fieldId聚合参数:"+fieldId); - if("count".equalsIgnoreCase(funcName)) { - if(module.equalsIgnoreCase(ModuleSource.biaoge.toString())){ - value=Double.valueOf(remoteFormReportService.countStatFormDatasForReportNum(param, filterFormDatas, null, employee)); - } else if(module.equalsIgnoreCase(ModuleSource.workflow.toString())){ -// value=Double.valueOf(remoteFlowDataStatQueryService.countStatFormDatasForFlowNum(param, filterFormDatas, employee)); - value = getFlowData(param, filterFormDatas, employee, formId); - } - }else { - if (module.equalsIgnoreCase(ModuleSource.workflow.toString())) { - value = remoteFlowFreeStatService.findFieldStatByField(param, filterFormDatas, - fieldId, funcName,employee); - } else if(module.equalsIgnoreCase(ModuleSource.biaoge.toString())){ - value = remoteReportFreeStatService.findFieldStatByField(param, filterFormDatas, - fieldId, funcName,employee); - } - } - logger.info(funcName+"聚合结果:"+value); - return value; - } - - @Override - public Double getCommonAggregateData(Long formId, Long fieldId, String funcName, List cndDataType, String moduleSource, SimpleEmployee employee) { - Double value=0d; - funcName=funcName.toLowerCase(); - List filterFormDatas=null; - List formulaFilterDataList=new ArrayList<>(); - for (int i=1;i paramFilterList=paramObj.getFormulaFilterDataList(); -// logger.info(JSON.toJSONString(paramFilterList)); - formulaFilterDataList.addAll(paramFilterList); - } - } - - //审批、上报使用老条件 - if(moduleSource.equalsIgnoreCase(ModuleSource.workflow.toString()) || moduleSource.equalsIgnoreCase(ModuleSource.biaoge.toString())){ - JSONArray jsonArray=JSON.parseArray(JSON.toJSONString(formulaFilterDataList)); - filterFormDatas=jsonArray.toJavaList(FilterFormData.class); -// logger.info("函数条件新转老结果:"+(JSON.toJSONString(filterFormDatas))); - } - logger.info("条件参数:"+JSON.toJSONString(filterFormDatas)); - Map param = assemblyParam(formId, employee); - if(filterFormDatas != null && filterFormDatas.size() > 0) { - param.put("condition", StringUtils.isEmpty(filterFormDatas.get(0).getCondition())?"AND":filterFormDatas.get(0).getCondition()); - } - if(formulaFilterDataList !=null && formulaFilterDataList.size()>0){ - param.put("condition", StringUtils.isEmpty(formulaFilterDataList.get(0).getCondition())?"AND":formulaFilterDataList.get(0).getCondition()); - } - - - if(moduleSource.equalsIgnoreCase(ModuleSource.workflow.toString())){ - if("count".equalsIgnoreCase(funcName)) { - value = getFlowData(param, filterFormDatas, employee, formId); - }else { -// value = freeStatAssistService.buildFreeStatService("workflow").findFieldStatByField(param, filterFormDatas, -// fieldId, funcName,employee); - List filterFormDataParamList=filterFormDataSearchService.conversionOldFilterFormDataToNew(filterFormDatas,employee); - logger.info("conversionOldFilterFormDataToNew函数统计转换条件:"+JSON.toJSONString(filterFormDataParamList)); - Map aggResultMap= null; - try { - WeaverSentinelContext.setDowngradeType(false); - aggResultMap = wfcReportStatRest.findFieldCalculateByCondition(formId,fieldId,filterFormDataParamList,funcName,employee); - } catch (RpcException e) { - logger.error("err",e); - if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { - //降级逻辑编写 - logger.error("审批服务不可用"); - } - } - logger.info("审批新统计结果:"+JSON.toJSONString(aggResultMap)); - Object aggResultObject=aggResultMap.get(funcName.toLowerCase()); - if(aggResultObject!=null){ - BigDecimal bigDecimal=new BigDecimal(aggResultObject+""); - value=bigDecimal.doubleValue(); - } - } - logger.info("审批聚合结果:"+value); - }else if(moduleSource.equalsIgnoreCase(ModuleSource.biaoge.toString())){ - ExcelResult excelResult= null; - try { - WeaverSentinelContext.setDowngradeType(false); - excelResult = remoteExcelService.aggregation(AggFunc.valueOf(funcName.toLowerCase()),formId+"",fieldId+"",formulaFilterDataList,null,employee); - } catch (IllegalArgumentException e) { - logger.error("err",e); - }catch (RpcException e){ - logger.error("err",e); - if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { - //降级逻辑编写 - logger.error("上报服务不可用"); - } - } - try { - value=Double.parseDouble(excelResult.getData()+""); - } catch (NumberFormatException e) { - logger.error("err",e); - } - logger.info("上报聚合结果:"+JSON.toJSONString(excelResult)); - }else if(moduleSource.equalsIgnoreCase("hrmsalary")){ - ExcelResult excelResult= null; - try { - excelResult = remoteExcelServiceHrmSalary.aggregation(AggFunc.valueOf(funcName.toLowerCase()),formId+"",fieldId+"",formulaFilterDataList,null,employee); - } catch (IllegalArgumentException e) { - logger.error("err",e); - }catch (RpcException e){ - logger.error("err",e); - if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { - //降级逻辑编写 - logger.error("薪酬服务不可用"); - } - } - try { - value=Double.parseDouble(excelResult.getData()+""); - } catch (NumberFormatException e) { - logger.error("err",e); - } - logger.info("薪酬聚合结果:"+JSON.toJSONString(excelResult)); - } - return value; - } - - /** - * 根据表单参数查询审批数据量 - * @param paramMap - * @param filterFormDatas - * @param employee - * @return - */ - private Double getFlowData(Map paramMap, List filterFormDatas, SimpleEmployee employee, Long formId) { - List datas =null; - FormDataOption formDataOption=new FormDataOption(); - Page pageDatas=new Page(); - - JSONObject filter=new JSONObject(); - JSONArray filterArray=JSON.parseArray(JSON.toJSONString(filterFormDatas)); - - for(int i=0;i weaResult= null; - try { - WeaverSentinelContext.setDowngradeType(false); - weaResult = wflSearchConditionRest.convertCondition(cndString); -// weaResult = wfcSearchConditionRest.convertCondition(cndString); - } catch (RpcException e) { - if (WeaverDubboSentinelUtil.isRpcNoProviderException(e)) { - //降级逻辑编写 - logger.error("审批服务不可用"); - logger.error("err",e); - } - } - JSONObject flowJson=JSON.parseObject(weaResult.getData()); - JSONObject formDatas=new JSONObject(); - formDatas.put("formDatas",flowJson); - cndString=formDatas.toJSONString(); - logger.error("转换审批条件后:"+cndString); - RequestListSearchConditionEntity listSearchCondition =new RequestListSearchConditionEntity(); - JSONObject newFlowCndJson=JSON.parseObject(cndString); - if(paramMap != null) listSearchCondition = newFlowCndJson.toJavaObject(RequestListSearchConditionEntity.class); - if(paramMap.get("condition")!=null){ - listSearchCondition.setType(paramMap.get("condition")+""); - } - logger.info("JSON转换成审批条件对象:"+(listSearchCondition!=null?JSON.toJSONString(listSearchCondition):"NULL")); - //listSearchCondition.setType(paramMap.get("condition")!=null?paramMap.get("condition")+"":"AND"); - com.weaver.common.component.table.page.Page page = new com.weaver.common.component.table.page.Page(1, 10); - page.setSize(Integer.MAX_VALUE); - paramMap.put("isAdmin",true); - paramMap.remove("filterFormDatas"); - logger.error("函数执行条件paramMap:"+JSON.toJSONString(paramMap)); - Long flowCount = wflRequestListFormRest.getFormFilterRequestCount(paramMap, formId, listSearchCondition, employee); - if(flowCount==null){ - flowCount=0L; - } - return flowCount.doubleValue(); -// List tempDatas=wfcRequestListFormRest.getFormFilterRequestDatasByWfId(paramMap,formId,listSearchCondition,page,employee); -// List tempDatas=wfcRequestListFormRpc.getFormFilterRequestDatas(paramMap,formId,listSearchCondition,page,employee); -// return new Double(tempDatas.size()); - } - - // 封装高级搜索参数 - private Map assemblyParam(Long formId, SimpleEmployee employee) { - Map param = new HashMap(); - - param.put("employeeId", employee.getUserId()); - param.put("formId", formId); // 表单id - param.put("isAdmin", true); // 统计默认有管理元权限 - param.put("status", FormDataStatus.submit.toString()); // 统计默认有管理元权限 - - return param; - } - - - public FreeFormService bulidFreeFormService(ModuleSource module) { - return freeFormAssistService.buildFreeFormService(module.toString()); - } - - @Override - public Map bulidDataType(List fieldIds, FormData formData, String module, - SimpleEmployee employee) { - Map dataMap = new HashMap(); - if(fieldIds != null && fieldIds.size() > 0 && formData != null) { - List dataDetails = formData.getDataDetails(); - Map> dataDetailMap = new HashMap>(); - if(dataDetails != null && dataDetails.size() > 0) { - for(FormDataDetail dataDetail : dataDetails) { - if(dataDetailMap.containsKey(dataDetail.getFormField().getId())) { - dataDetailMap.get(dataDetail.getFormField().getId()).add(dataDetail); - }else { - List values = new ArrayList(); - values.add(dataDetail); - dataDetailMap.put(dataDetail.getFormField().getId(), values); - } - - } - } - Map fieldMap = bulidFreeFormService(ModuleSource.valueOf(module)).getFieldMapByFormId(formData.getForm().getId(), employee); - for(String field : fieldIds) { - Long fieldId = Long.parseLong(field); - FormField formField = fieldMap.get(fieldId); - if(formField != null) { - DataType dataType = new DataType(); - dataType.setFieldId(field); - dataType.setDataType(getDataType(formField.getComponentKey())); - if(dataDetailMap.containsKey(fieldId)) { - dataType.setContent(getDetailValue(dataDetailMap.get(fieldId))); - dataType.setText(getDetailContent(dataDetailMap.get(fieldId))); - if( ComponentType.RadioBox.toString().equals(formField.getComponentKey()) - || ComponentType.CheckBox.toString().equals(formField.getComponentKey()) - || ComponentType.Select.toString().equals(formField.getComponentKey())) { - dataType.setScore(getDetailScore(dataDetailMap.get(fieldId),ModuleSource.valueOf(module),formData.getFormLayout().getId(),employee)); - } - }else { - dataType.setContent(""); - dataType.setText(""); - } - dataMap.put(field, dataType); - } - } - } - return dataMap; - } - - private Double getDetailScore(List dataDetails, ModuleSource module,Long layoutId,SimpleEmployee employee) { - Double score =0d; - for (FormDataDetail formDataDetail :dataDetails){ - score=excelTransUtil.getDetailScore(formDataDetail,module,layoutId,employee); - } -// if(dataDetails != null && dataDetails.size() > 0) { -// FormDataDetail dataDetail = dataDetails.get(0); -// if(dataDetail != null) { -// score = bulidFreeFormService(module).getOptionScore(dataDetail.getFormField().getId()+"", layoutId, dataDetail, employee).doubleValue(); -// } -// } - return score; - } - - private String getDetailValue(List dataDetails) { - String content =""; - if(dataDetails != null && dataDetails.size() > 0) { - FormDataDetail dataDetail = dataDetails.get(0); - if(dataDetail != null) { - content = dataDetail.getContent() == null ? "" : dataDetail.getContent(); // 字段新数据 - FormDataText formDataText = dataDetail.getDataText(); - if (formDataText != null) { // 如果是多行文本框 - content = formDataText.getContent(); - } - List optDetails = dataDetail.getDataOptions(); // 填写选项明细 - if ((optDetails != null) && (optDetails.size() > 0)) {// 如果是选项类型控件 - for (FormDataOption formDataOption : optDetails) { - content += formDataOption.getOptionId()+","; - } - if ((content != null) && (content.length() > 0)) { - content = content.substring(0, content.length() - 1); // 去掉最后一个逗号 - } - } - } - } - return content; - } - - private String getDetailContent(List dataDetails) { - String content =""; - if(dataDetails != null && dataDetails.size() > 0) { - FormDataDetail dataDetail = dataDetails.get(0); - if(dataDetail != null) { - content = dataDetail.getContent() == null ? "" : dataDetail.getContent(); // 字段新数据 - FormDataText formDataText = dataDetail.getDataText(); - if (formDataText != null) { // 如果是多行文本框 - content = formDataText.getContent(); - } - List optDetails = dataDetail.getDataOptions(); // 填写选项明细 - if ((optDetails != null) && (optDetails.size() > 0)) {// 如果是选项类型控件 - for (FormDataOption formDataOption : optDetails) { - content += formDataOption.getContent() + ","; - } - if ((content != null) && (content.length() > 0)) { - content = content.substring(0, content.length() - 1); // 去掉最后一个逗号 - } - } - } - } - return content; - } - - /** - * 检查控件类型 - * @param componentKey - * @return - */ - @Override - public String getDataType(String componentKey){ - DataType dataType = new DataType(); - if(ComponentConfig.isNumberComponent(componentKey)) { - return DataType.NUMBER; - }else if(ComponentConfig.isOptionComponent(componentKey)) { - return DataType.OPTION; - }else if(componentKey.equals(ComponentType.DateComponent.toString())) { - return DataType.STRING; - }else { - return DataType.STRING; - } - } - - @Override - public Map buildFilterParam(ExpressFormula dataExpressFormula, Long targetFormId, SimpleEmployee employee, FormData formData, String module) { - String moduleStr=module.toString(); - FormulaContext.get().setValue(moduleStr); - - Map expressMap=new HashMap<>(); - Map paramMap = Maps.newHashMap(); - if(dataExpressFormula==null) throw new RuntimeException("公式不存在"); - - try { - JSONObject paramJson= JSON.parseObject(dataExpressFormula.getParameter()); - List varList=null; - if(dataExpressFormula.getParameter()!=null){ - JSONArray paramArray=paramJson.getJSONArray("formulavars"); - varList=paramArray.toJavaList(FormulaVar.class); - List fieldIds=new ArrayList<>(); - for(FormulaVar formulaVar:varList){ - if(formulaVar.getFieldId()!=null&&formulaVar.getOptionId()==null&&!formulaVar.getFormId().equalsIgnoreCase(targetFormId.toString())){ - fieldIds.add(formulaVar.getFieldId().toString()); - } - } - - Map dataTypeMap=bulidDataType(fieldIds,formData,module,employee); - for(FormulaVar formulaVar:varList){ - if(formulaVar.getFieldId()!=null&&dataTypeMap.containsKey(formulaVar.getFieldId().toString())){ - DataType dataType=dataTypeMap.get(formulaVar.getFieldId().toString()); - if(formulaVar.getFormId()!=null){ - dataType.setFormId(Long.parseLong(formulaVar.getFormId())); - } - - try { - dataType.setModule(formulaVar.getModule()); - } catch (IllegalArgumentException e) { - logger.error("err",e); - dataType.setModule(formulaVar.getModule()); - } - dataType.setEmployee(employee); - if(formulaVar.getName()!=null){ - if(dataType.getContent()==null){ - dataType.setContent(formulaVar.getOptionId()); - } - if(dataType.getText()==null){ - dataType.setText(formulaVar.getName()); - } - } - expressMap.put(formulaVar.getKey(),dataType); - }else{ - DataType dataType=new DataType(); - - if(formulaVar.getKey().equals("current_operator")){ - dataType.setContent(employee.getId()); - dataType.setText(employee.getUsername()); - dataType.setDataType(DataType.OPTION); - expressMap.put(formulaVar.getKey(),dataType); - }else if(formulaVar.getOptionId()!=null){ - dataType.setDataType(DataType.OPTION); - dataType.setContent(formulaVar.getOptionId()); - dataType.setText(formulaVar.getName()); - expressMap.put(formulaVar.getKey(),dataType); - }else { - dataType.setContent(formulaVar.getFormId()); - try { - dataType.setModule(formulaVar.getModule()); - } catch (IllegalArgumentException e) { - logger.error("err",e); - dataType.setModule(formulaVar.getModule()); - } - dataType.setEmployee(employee); - } - dataType.setFormId(formulaVar.getFormId()!=null?Long.parseLong(formulaVar.getFormId()):null); - expressMap.put(formulaVar.getKey(),dataType); - } - } - - List paramDatas=paramJson.getJSONArray("formulavars").toJavaList(FormulaVar.class); - String filterGenFormula= ExcelParamUtil.replaceAllParam(dataExpressFormula.getFormula(),paramDatas); - filterGenFormula= ExcelParamUtil.spliteSql(filterGenFormula,expressMap); - filterGenFormula=filterGenFormula.replaceAll("\\{",""); - filterGenFormula=filterGenFormula.replaceAll("\\}",""); - paramMap=this.buildCndFilter(targetFormId,null,filterGenFormula,expressMap,module,employee); - } - } catch (Exception e) { - logger.error("err",e); - } - return paramMap; - } - -} diff --git a/src/com/engine/salary/formlua/data/func/EqOperator.java b/src/com/engine/salary/formlua/data/func/EqOperator.java deleted file mode 100644 index 83ef15e15..000000000 --- a/src/com/engine/salary/formlua/data/func/EqOperator.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.engine.salary.formlua.data.func; - -import com.ql.util.express.Operator; -import com.weaver.common.form.component.base.ComponentConfig; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.common.form.excel.validator.Validator; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.common.form.stat.FilterFormData; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.teams.util.StringUtils; - -import java.util.ArrayList; -import java.util.List; - - -/** - * equals转成筛选条件 - * @author Failymiss - */ -public class EqOperator extends Operator { - - private static final long serialVersionUID = -6647187680280498682L; - - - public Object executeInner(Object[] list) throws Exception { - Object obj=executeInner(list[0], list[1]); - return obj; - } - - public Object executeInner(Object obj1,Object obj2) throws Exception { - FilterFormData filterFormData = null; - String content = null; - FormField field = null; - if(checkParam(obj1, obj2)) { - field = (FormField) obj1; - if(obj2 instanceof DataType) { - content = ((DataType) obj2).getContent()+""; - }else { - content = obj2+""; - } - } - if (field != null && content != null) { - String componentKey = field.getComponentKey(); - filterFormData = new FilterFormData(); - filterFormData.setFieldId(field.getId()+""); - if(field.getSubForm() != null) { - filterFormData.setSubFormId(field.getSubForm().getId()+""); - } - filterFormData.setComponentKey(componentKey); - if(StringUtils.isEmpty(content)) { - filterFormData.setTerm(FilterFormData.TERM_NULL); - }else{ - filterFormData.setTerm(FilterFormData.TERM_EQ); - //数字类型 - if(ComponentConfig.isNumberComponent(componentKey) - || componentKey.equals(ComponentType.DateComponent.toString()) - || componentKey.equals(ComponentType.TimeComponent.toString())) { - filterFormData.setContent(content); - //选项控件 - }else if(ComponentConfig.isOptionComponent(componentKey)) { - List ids = new ArrayList<>(); - String[] idsArray = content.split(","); - for(String idStr : idsArray) { - if(StringUtils.isNotBlank(idStr)) { - ids.add(idStr); - } - } - filterFormData.setIds(ids); - //文本型 - }else { - filterFormData.setContent(content); - } - } - } - return filterFormData; - } - - private boolean checkParam(Object obj1,Object obj2) { - if(obj1 instanceof FormField) { - String componentKey = ((FormField) obj1).getComponentKey(); - if(ComponentConfig.isNumberComponent(componentKey)) { - if(obj2 instanceof DataType) { - if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)){ - return true; - }else { - throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); - } - }else if(StringUtils.isEmpty(obj2+"") || Validator.isFloat(obj2+"") ){ - return true; - }else { - throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); - } - }else if(ComponentConfig.isOptionComponent(componentKey)){ - if(StringUtils.isEmpty(obj2+"") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { - return true; - }else { - throw new RuntimeException("筛选条件[=]:选项控件右边必须是选项"); - } - } else { - if(StringUtils.isEmpty(obj2+"") || obj2 instanceof String || obj2 instanceof Character) { - return true; - }else if(obj2 instanceof DataType){ - if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ - return true; - }else if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ - return true; - }else { - throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); - } - }else { - throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); - } - } - } - throw new RuntimeException("筛选条件[=]:左边必须是表单控件"); - } -} \ No newline at end of file diff --git a/src/com/engine/salary/formlua/data/func/LessMoreOperator.java b/src/com/engine/salary/formlua/data/func/LessMoreOperator.java deleted file mode 100644 index 35cf47591..000000000 --- a/src/com/engine/salary/formlua/data/func/LessMoreOperator.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.engine.salary.formlua.data.func; - -import com.alibaba.fastjson.JSON; -import com.ql.util.express.Operator; -import com.weaver.common.form.component.base.ComponentConfig; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.common.form.excel.validator.Validator; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.common.form.stat.FilterFormData; -import com.weaver.excel.formula.entity.parameter.DataType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * >= <= > < 转成筛选条件 - * @author Failymiss - */ -public class LessMoreOperator extends Operator{ - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - private static final long serialVersionUID = -1001332992613137814L; - - public LessMoreOperator(String aName) { - this.name = aName; - } - - @Override - public Object executeInner(Object[] list) throws Exception { - - return executeInner(list[0], list[1]); - } - - private Object executeInner(Object obj1, Object obj2) { - FilterFormData filterFormData = null; - FormField field = null; - String content = null; - if(checkParam(obj1, obj2)) { - field = (FormField) obj1; - if(obj2 instanceof DataType) { - content = ((DataType) obj2).getContent()+""; - }else { - content = obj2+""; - } - } - if (field != null && content != null) { - String componentKey = field.getComponentKey(); - if(ComponentConfig.isNumberComponent(componentKey) - || componentKey.equals(ComponentType.DateComponent.toString()) - || componentKey.equals(ComponentType.TimeComponent.toString())) { - - filterFormData = new FilterFormData(); - filterFormData.setFieldId(field.getId()+""); - if(field.getSubForm() != null) { - filterFormData.setSubFormId(field.getSubForm().getId()+""); - } - filterFormData.setComponentKey(componentKey); - switch (this.name) { - case ">=": - filterFormData.setTerm(FilterFormData.TERM_GE); - break; - case ">": - filterFormData.setTerm(FilterFormData.TERM_GT); - break; - case "<=": - filterFormData.setTerm(FilterFormData.TERM_LE); - break; - case "<": - filterFormData.setTerm(FilterFormData.TERM_LT); - break; - default: - break; - } - filterFormData.setContent(content); - } - } - return filterFormData; - } - - private boolean checkParam(Object obj1,Object obj2) { - logger.info("聚合函数校验,第一个参数:"+ JSON.toJSONString(obj1)); - logger.info("聚合函数校验,第二个参数:"+ JSON.toJSONString(obj2)); - if(obj1 instanceof FormField) { - String componentKey = ((FormField) obj1).getComponentKey(); - if(ComponentConfig.isNumberComponent(componentKey)) { - if(obj2 instanceof Number) { - return true; - }else if(obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)){ - return true; - }else { - throw new RuntimeException("筛选条件["+this.name+"]:数字控件右边必须是数字"); - } - } - if(componentKey.equals(ComponentType.DateComponent.toString())) { - if(obj2 instanceof String && Validator.isDate((String)obj2)) { - return true; - }else if(obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ - return true; - }else { - throw new RuntimeException("筛选条件["+this.name+"]:日期控件右边必须是日期字符串"); - } - - } - if(componentKey.equals(ComponentType.TimeComponent.toString())) { - if(obj2 instanceof String && Validator.isTime((String)obj2)) { - return true; - }else if(obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING) ){ - return true; - }else { - throw new RuntimeException("筛选条件["+this.name+"]:时间控件右边必须是时间字符串"); - } - } - } - throw new RuntimeException("筛选条件["+this.name+"]:左边必须是数字控件或时间控件"); - } - -} diff --git a/src/com/engine/salary/formlua/data/func/LogicFunc.java b/src/com/engine/salary/formlua/data/func/LogicFunc.java deleted file mode 100644 index 655aaf249..000000000 --- a/src/com/engine/salary/formlua/data/func/LogicFunc.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.engine.salary.formlua.data.func; - -import com.weaver.common.form.component.base.ComponentConfig; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.common.form.stat.FilterFormData; -import com.weaver.excel.formula.entity.parameter.DataType; - -import java.util.ArrayList; -import java.util.List; - -public class LogicFunc { - - public static List and(Object... objs){ - List filterFormDatas = new ArrayList<>(); - if(objs != null && objs.length > 0) { - for(int i=0;i,>=,<,<=,LIKE,AND,OR'条件公式"); - } - } - } - return filterFormDatas; - } - - /** - * - * @param objs - * @return - */ - public static List or(Object... objs){ - List filterFormDatas = new ArrayList<>(); - if(objs != null && objs.length > 0) { - for(int i=0;i,>=,<,<=,LIKE,AND,OR'条件公式"); - } - } - } - return filterFormDatas; - } - - /** - * 支持文本、数字、日期 - * @param formField - * @param strs - * @return - */ - public static FilterFormData like(FormField formField,Object[] strs){ - if(formField != null && strs.length > 0) { - if(ComponentConfig.isOptionComponent(formField.getComponentKey())) { - throw new RuntimeException("筛选条件函数[LIKE]:第一个参数不能是选项控件"); - } - FilterFormData filterFormData = new FilterFormData(); - List contents = new ArrayList(); - for(Object str : strs) { - contents.add(str+""); - } - filterFormData.setContents(contents); - filterFormData.setTerm(FilterFormData.TERM_LIKE); - filterFormData.setFieldId(formField.getId()+""); - return filterFormData; - }else { - throw new RuntimeException("筛选条件函数[LIKE]:参数异常"); - } - } - - /** - * 仅支持选项型控件 - * @param formField - * @param options - * @return - */ - public static FilterFormData in(FormField formField,DataType[] options){ - if(formField != null && options.length > 0) { - if(!ComponentConfig.isOptionComponent(formField.getComponentKey())) { - throw new RuntimeException("筛选条件函数[IN]:第一个参数必须选项控件"); - } - FilterFormData filterFormData = new FilterFormData(); - List ids = new ArrayList(); - for(DataType option : options) { - ids.add(option.getContent()+""); - } - filterFormData.setIds(ids); - filterFormData.setFieldId(formField.getId()+""); - filterFormData.setTerm(FilterFormData.TERM_EQ); - return filterFormData; - }else { - throw new RuntimeException("筛选条件函数[IN]:参数异常"); - } - } -} diff --git a/src/com/engine/salary/formlua/data/func/NotEqOperator.java b/src/com/engine/salary/formlua/data/func/NotEqOperator.java deleted file mode 100644 index 494e291a8..000000000 --- a/src/com/engine/salary/formlua/data/func/NotEqOperator.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.engine.salary.formlua.data.func; - -import com.ql.util.express.Operator; -import com.weaver.common.form.component.base.ComponentConfig; -import com.weaver.common.form.excel.validator.Validator; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.common.form.stat.FilterFormData; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.teams.util.StringUtils; - -import java.util.ArrayList; -import java.util.List; - - -/** - * equals转成筛选条件 - * @author Failymiss - */ -public class NotEqOperator extends Operator { - - private static final long serialVersionUID = -6647187680280498682L; - - public Object executeInner(Object[] list) throws Exception { - return executeInner(list[0], list[1]); - } - - public Object executeInner(Object obj1,Object obj2) throws Exception { - FilterFormData filterFormData = null; - String content = null; - FormField field = null; - if(checkParam(obj1, obj2)) { - field = (FormField) obj1; - if(obj2 instanceof DataType) { - content = ((DataType) obj2).getContent()+""; - }else { - content = obj2+""; - } - } - if (field != null && content != null) { - String componentKey = field.getComponentKey(); - filterFormData = new FilterFormData(); - filterFormData.setFieldId(field.getId()+""); - if(field.getSubForm() != null) { - filterFormData.setSubFormId(field.getSubForm().getId()+""); - } - filterFormData.setComponentKey(componentKey); - if(StringUtils.isEmpty(content)) { - filterFormData.setTerm(FilterFormData.TERM_NOT_NULL); - }else{ - //选项控件 - if(ComponentConfig.isOptionComponent(componentKey)) { - filterFormData.setTerm(FilterFormData.TERM_NOT_EQ); - List ids = new ArrayList<>(); - String[] idsArray = content.split(","); - for(String idStr : idsArray) { - if(StringUtils.isNotBlank(idStr)) { - ids.add(idStr); - } - } - filterFormData.setIds(ids); - //其他 - }else { - filterFormData.setTerm(FilterFormData.TERM_NOT_EQ); - filterFormData.setContent(content); - } - } - } - return filterFormData; - } - - private boolean checkParam(Object obj1,Object obj2) { - if(obj1 instanceof FormField) { - String componentKey = ((FormField) obj1).getComponentKey(); - if(ComponentConfig.isNumberComponent(componentKey)) { - if(obj2 instanceof DataType) { - if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)){ - return true; - }else { - throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); - } - }else if(StringUtils.isEmpty(obj2+"") || Validator.isFloat(obj2+"") ){ - return true; - }else { - throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); - } - }else if(ComponentConfig.isOptionComponent(componentKey)){ - if(StringUtils.isEmpty(obj2+"") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { - return true; - }else { - throw new RuntimeException("筛选条件[!=]:选项控件右边必须是选项"); - } - } else { - if(StringUtils.isEmpty(obj2+"") || obj2 instanceof String || obj2 instanceof Character) { - return true; - }else if(obj2 instanceof DataType){ - if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING) ){ - return true; - }else if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ - return true; - }else if(((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)){ - return true; - }else { - throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); - } - }else { - throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); - } - } - } - throw new RuntimeException("筛选条件[!=]:左边必须是表单控件"); - } -} diff --git a/src/com/engine/salary/formlua/data/func/QLExpressContext.java b/src/com/engine/salary/formlua/data/func/QLExpressContext.java deleted file mode 100644 index 86cf3d8af..000000000 --- a/src/com/engine/salary/formlua/data/func/QLExpressContext.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.engine.salary.formlua.data.func; - - -import com.ql.util.express.IExpressContext; -import org.springframework.context.ApplicationContext; - -import java.util.HashMap; -import java.util.Map; - -@SuppressWarnings("serial") -public class QLExpressContext extends HashMap implements - IExpressContext { - - private ApplicationContext context; - - public QLExpressContext(ApplicationContext aContext) { - this.context = aContext; - } - - public QLExpressContext(Map aProperties,ApplicationContext aContext) { - super(aProperties); - this.context = aContext; - } - - /** - * 抽象方法:根据名称从属性列表中提取属性值 - */ - public Object get(Object name) { - Object result = null; - result = super.get(name); - try { - if (result == null && this.context != null - && this.context.containsBean((String) name)) { - // 如果在Spring容器中包含bean,则返回String的Bean - result = this.context.getBean((String) name); - } - } catch (Exception e) { - throw new RuntimeException(e.getMessage()); - } - return result; - } - - public Object put(String name, Object object) { - return super.put(name, object); - } - -} \ No newline at end of file diff --git a/src/com/engine/salary/formlua/data/func/QlExpressUtil.java b/src/com/engine/salary/formlua/data/func/QlExpressUtil.java deleted file mode 100644 index 8f254735d..000000000 --- a/src/com/engine/salary/formlua/data/func/QlExpressUtil.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.engine.salary.formlua.data.func; - -import com.ql.util.express.DynamicParamsUtil; -import com.ql.util.express.ExpressRunner; -import com.ql.util.express.IExpressContext; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.entity.parameter.FuncNames; -import com.weaver.excel.formula.func.aggregate.AggregationFunc; -import com.weaver.excel.formula.func.compare.WOperatorAdd; -import com.weaver.excel.formula.func.compare.WOperatorDiv; -import com.weaver.excel.formula.func.compare.WOperatorMulti; -import com.weaver.excel.formula.func.compare.WOperatorReduce; -import com.weaver.excel.formula.func.date.DateTimeService; -import com.weaver.excel.formula.func.logic.IfOperator; -import com.weaver.excel.formula.func.logic.LogicService; -import com.weaver.excel.formula.func.math.MathFuncsService; -import com.weaver.excel.formula.func.string.StringFormulaService; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Component; - -import java.util.Map; - -/** - * 函数转换筛选条件类 - * @author Failymiss - */ -@Component -public class QlExpressUtil { - @Autowired - AggregationFunc aggregationFunc; - @Autowired - LogicService logicService; - @Autowired - DateTimeService dateTimeService; - @Autowired - StringFormulaService stringFormulaService; - @Autowired - MathFuncsService mathFuncsService; - - - private static ExpressRunner runner; - static { - runner = new ExpressRunner(true,false); - } - private static boolean isInitialRunner = false; - private ApplicationContext applicationContext;// spring上下文 - - /** - * - * @param statement - * 执行语句 - * @param context - * 上下文 - * @throws Exception - */ - public Object execute(String statement, Map context) - throws Exception { - DynamicParamsUtil.supportDynamicParams = true; - initRunner(runner); - IExpressContext expressContext = new QLExpressContext(context, - applicationContext); - return runner.execute(statement, expressContext, null, true, false); - } - - private void initRunner(ExpressRunner runner) { - if (isInitialRunner == true) { - return; - } - synchronized (runner) { - if (isInitialRunner == true) { - return; - } - try { - runner.replaceOperator("=",new EqOperator()); - runner.replaceOperator("==",new EqOperator()); - runner.replaceOperator("!=",new NotEqOperator()); - runner.replaceOperator(">=",new LessMoreOperator(">=")); - runner.replaceOperator(">",new LessMoreOperator(">")); - runner.replaceOperator("<=",new LessMoreOperator("<=")); - runner.replaceOperator("<",new LessMoreOperator("<")); - runner.addFunctionOfClassMethod("LIKE",LogicFunc.class.getName(),"like", new Class[] {FormField.class, Object[].class},""); - runner.addFunctionOfClassMethod("IN",LogicFunc.class.getName(),"in",new Class[] {FormField.class, DataType[].class},""); - runner.addFunctionOfClassMethod("AND",LogicFunc.class.getName(),"and",new Class[]{Object[].class},""); - runner.addFunctionOfClassMethod("OR",LogicFunc.class.getName(),"or",new Class[]{Object[].class},""); - - /**********************一下函数引入后不会构建成高级搜索条件***********************/ - - //字符串函数 - runner.addFunctionOfServiceMethod("CONCAT",stringFormulaService,"concatString",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("SEARCH",stringFormulaService,"search",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("TEXT",stringFormulaService,"text",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("PAD",stringFormulaService,"pad",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("REPLACE",stringFormulaService,"replace",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("VALUE",stringFormulaService,"value",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("LEN",stringFormulaService,"len",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("LEFT",stringFormulaService,"left",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("RIGHT",stringFormulaService,"right",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("MID",stringFormulaService,"mid",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("REPT",stringFormulaService,"repeat",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("TRIM",stringFormulaService,"trim",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("SCORE",stringFormulaService,"score",new Class[]{Object[].class},""); - - //数学函数 - runner.addFunctionOfServiceMethod("ROUNDUP",mathFuncsService,"roundUp",new Class[]{Object.class},""); - runner.addFunctionOfServiceMethod("ROUNDDOWN",mathFuncsService,"roundDown",new Class[]{Object.class},""); - - //日期函数 - runner.addFunctionOfServiceMethod( "DATEDIFF",dateTimeService,"dateDiff",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "DATEADD",dateTimeService,"dateAdd",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "YEAR",dateTimeService,"year",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "MONTH",dateTimeService,"month",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "DAY",dateTimeService,"day",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "HOUR",dateTimeService,"hour",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "MINUTE",dateTimeService,"minute",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "SECOND",dateTimeService,"seconds",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "WEEKNUM",dateTimeService,"weekNum",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "WEEKDAY",dateTimeService,"weekDay",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "NOW",dateTimeService,"now",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "TODAY",dateTimeService,"today",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod("DATEFORMAT",dateTimeService,"dateFormat",new Class[]{Object[].class},""); - - //逻辑函数 - runner.replaceOperator("IF",new IfOperator("IF")); - runner.addFunctionOfServiceMethod(FuncNames.TRUE.toString(),logicService,FuncNames.TRUE.getName(),new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod(FuncNames.FALSE.toString(),logicService,FuncNames.FALSE.getName(),new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod(FuncNames.ISEMPTY.toString(),logicService,FuncNames.ISEMPTY.getName(),new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod(FuncNames.NOT.toString(),logicService,FuncNames.NOT.getName(),new Class[]{Object[].class},""); - - runner.replaceOperator("+",new WOperatorAdd("+")); - runner.replaceOperator("-",new WOperatorReduce("-")); - runner.replaceOperator("*",new WOperatorMulti("*")); - runner.replaceOperator("/",new WOperatorDiv("/")); - - } catch (Exception e) { - throw new RuntimeException("初始化失败表达式"); - } - } - isInitialRunner = true; - } - - public void setApplicationContext(ApplicationContext aContext) - throws BeansException { - applicationContext = aContext; - } -} diff --git a/src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java b/src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java index 92ddf028d..437d8376e 100644 --- a/src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java +++ b/src/com/engine/salary/formlua/entity/parameter/ExcelFuncs.java @@ -2,17 +2,12 @@ package com.engine.salary.formlua.entity.parameter; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import com.weaver.common.i18n.label.SystemEnv; -import com.weaver.excel.formula.core.rpc.ExcelDubboInvoker; -import com.weaver.excel.formula.core.rpc.RemoteExcelExtendFuncService; -import com.weaver.excel.formula.core.rpc.RpcMethod; +import com.engine.salary.util.SalaryI18nUtil; import org.apache.commons.compress.utils.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -28,34 +23,30 @@ public class ExcelFuncs { static private String[] paramDatas=new String[]{}; static private String[] allParamDatas=new String[]{"{}","[]"}; static private String[] moduleList=new String[]{"biaoge","workflow"}; - @Autowired - ExcelDubboInvoker excelDubboInvoker; - - @Autowired private FuncDescUtil funcDescUtil; public List getCompList(){ //比较操作符 List compList=new LinkedList<>(); ExcelFunc excelFunc=null; String [] paramArray=new String[]{}; - excelFunc=new ExcelFunc(">",SystemEnv.getHtmlLabelName(12132,"大于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc(">",SalaryI18nUtil.getI18nLabel(12132,"大于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); compList.add(excelFunc); - excelFunc=new ExcelFunc(">=",SystemEnv.getHtmlLabelName(27694,"大于等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc(">=",SalaryI18nUtil.getI18nLabel(27694,"大于等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); compList.add(excelFunc); - excelFunc=new ExcelFunc("<",SystemEnv.getHtmlLabelName(20009,"小于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("<",SalaryI18nUtil.getI18nLabel(20009,"小于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); compList.add(excelFunc); - excelFunc=new ExcelFunc("<=",SystemEnv.getHtmlLabelName(15251,"小于等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("<=",SalaryI18nUtil.getI18nLabel(15251,"小于等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); compList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("=",SystemEnv.getHtmlLabelName(15112,"等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("=",SalaryI18nUtil.getI18nLabel(15112,"等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); compList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("!=",SystemEnv.getHtmlLabelName(14897,"不等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("!=", SalaryI18nUtil.getI18nLabel(14897,"不等于"), "","",paramArray,paramDatas,"Boolean",CURRENTDATA); compList.add(excelFunc); return compList; @@ -70,98 +61,98 @@ public class ExcelFuncs { List dateList=new LinkedList<>(); ExcelFunc excelFunc=null; String [] paramArray=new String[]{}; - excelFunc=new ExcelFunc("TODAY",SystemEnv.getHtmlLabelName(94924,"当前日期"), funcDescUtil.get("TODAY"),"TODAY()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("TODAY",SalaryI18nUtil.getI18nLabel(94924,"当前日期"), funcDescUtil.get("TODAY"),"TODAY()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("NOW",SystemEnv.getHtmlLabelName(94925,"当前日期时间"), funcDescUtil.get("NOW"),"NOW()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("NOW",SalaryI18nUtil.getI18nLabel(94925,"当前日期时间"), funcDescUtil.get("NOW"),"NOW()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("DATEADD",SystemEnv.getHtmlLabelName(94926,"对日期加减年、月、日"), funcDescUtil.get("DATEADD"),"DATEADD(日期, 数值, ['单位'])",nullParamDatas,paramArray,"String",CURRENTDATA); + excelFunc=new ExcelFunc("DATEADD",SalaryI18nUtil.getI18nLabel(94926,"对日期加减年、月、日"), funcDescUtil.get("DATEADD"),"DATEADD(日期, 数值, ['单位'])",nullParamDatas,paramArray,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("DATEDIFF",SystemEnv.getHtmlLabelName(94927,"返回两个日期的差值"), funcDescUtil.get("DATEDIFF"),"DATEDIFF(日期1, 日期2, ['单位'])",nullParamDatas,paramArray,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("DATEDIFF",SalaryI18nUtil.getI18nLabel(94927,"返回两个日期的差值"), funcDescUtil.get("DATEDIFF"),"DATEDIFF(日期1, 日期2, ['单位'])",nullParamDatas,paramArray,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("DATEFORMAT",SystemEnv.getHtmlLabelName(94928,"返回指定格式的日期"), funcDescUtil.get("DATEFORMAT"),"DATEFORMAT(日期, '可选格式')",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("DATEFORMAT",SalaryI18nUtil.getI18nLabel(94928,"返回指定格式的日期"), funcDescUtil.get("DATEFORMAT"),"DATEFORMAT(日期, '可选格式')",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("YEAR",SystemEnv.getHtmlLabelName(94929,"返回日期中的年"), funcDescUtil.get("YEAR"),"YEAR(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("YEAR",SalaryI18nUtil.getI18nLabel(94929,"返回日期中的年"), funcDescUtil.get("YEAR"),"YEAR(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{"String"}; - excelFunc=new ExcelFunc("MONTH",SystemEnv.getHtmlLabelName(94930,"返回日期中的月"), funcDescUtil.get("MONTH"),"MONTH(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("MONTH",SalaryI18nUtil.getI18nLabel(94930,"返回日期中的月"), funcDescUtil.get("MONTH"),"MONTH(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("DAY",SystemEnv.getHtmlLabelName(94931,"返回日期中的日"), funcDescUtil.get("DAY"),"DAY(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("DAY",SalaryI18nUtil.getI18nLabel(94931,"返回日期中的日"), funcDescUtil.get("DAY"),"DAY(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("HOUR",SystemEnv.getHtmlLabelName(94932,"返回日期中的小时"), funcDescUtil.get("HOUR"),"HOUR(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("HOUR",SalaryI18nUtil.getI18nLabel(94932,"返回日期中的小时"), funcDescUtil.get("HOUR"),"HOUR(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("MINUTE",SystemEnv.getHtmlLabelName(94933,"返回日期中的分钟"), funcDescUtil.get("MINUTE"),"MINUTE(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("MINUTE",SalaryI18nUtil.getI18nLabel(94933,"返回日期中的分钟"), funcDescUtil.get("MINUTE"),"MINUTE(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("SECOND",SystemEnv.getHtmlLabelName(94934,"返回日期中的秒"), funcDescUtil.get("SECOND"),"SECOND(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("SECOND",SalaryI18nUtil.getI18nLabel(94934,"返回日期中的秒"), funcDescUtil.get("SECOND"),"SECOND(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("WEEKNUM",SystemEnv.getHtmlLabelName(94936,"返回日期为第几周"), funcDescUtil.get("WEEKNUM"),"WEEKNUM(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("WEEKNUM",SalaryI18nUtil.getI18nLabel(94936,"返回日期为第几周"), funcDescUtil.get("WEEKNUM"),"WEEKNUM(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("WEEKDAY",SystemEnv.getHtmlLabelName(94937,"返回日期为星期几"), funcDescUtil.get("WEEKDAY"),"WEEKDAY(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("WEEKDAY",SalaryI18nUtil.getI18nLabel(94937,"返回日期为星期几"), funcDescUtil.get("WEEKDAY"),"WEEKDAY(日期)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("NETWORKDAYSPI",SystemEnv.getHtmlLabelName(94938,"返回指定日期之间包含的工作日天数(仅限的过去时间)"), funcDescUtil.get("NETWORKDAYSPI"),"NETWORKDAYSPI(日期1, 日期2, 成员)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("NETWORKDAYSPI",SalaryI18nUtil.getI18nLabel(94938,"返回指定日期之间包含的工作日天数(仅限的过去时间)"), funcDescUtil.get("NETWORKDAYSPI"),"NETWORKDAYSPI(日期1, 日期2, 成员)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("EOMONTH",SystemEnv.getHtmlLabelName(94939,"返回某月最后一天日期"), funcDescUtil.get("EOMONTH"),"EOMONTH(日期,指定日期之前或之后的月数)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("EOMONTH",SalaryI18nUtil.getI18nLabel(94939,"返回某月最后一天日期"), funcDescUtil.get("EOMONTH"),"EOMONTH(日期,指定日期之前或之后的月数)",paramArray,nullParamDatas,"Number",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("CURRYEAR",SystemEnv.getHtmlLabelName(101059,"返回当前年份"), funcDescUtil.get("CURRYEAR"),"CURRYEAR()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CURRYEAR",SalaryI18nUtil.getI18nLabel(101059,"返回当前年份"), funcDescUtil.get("CURRYEAR"),"CURRYEAR()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("CURRMONTH",SystemEnv.getHtmlLabelName(101060,"返回当前月份"), funcDescUtil.get("CURRMONTH"),"CURRMONTH()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CURRMONTH",SalaryI18nUtil.getI18nLabel(101060,"返回当前月份"), funcDescUtil.get("CURRMONTH"),"CURRMONTH()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("CURRDAY",SystemEnv.getHtmlLabelName(101061,"返回当前第几日(当月)"), funcDescUtil.get("CURRDAY"),"CURRDAY()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CURRDAY",SalaryI18nUtil.getI18nLabel(101061,"返回当前第几日(当月)"), funcDescUtil.get("CURRDAY"),"CURRDAY()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("CURRWEEK",SystemEnv.getHtmlLabelName(101062,"返回当前是周几"), funcDescUtil.get("CURRWEEK"),"CURRWEEK()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CURRWEEK",SalaryI18nUtil.getI18nLabel(101062,"返回当前是周几"), funcDescUtil.get("CURRWEEK"),"CURRWEEK()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("CURRHOUR",SystemEnv.getHtmlLabelName(101063,"返回当前小时"), funcDescUtil.get("CURRHOUR"),"CURRHOUR()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CURRHOUR",SalaryI18nUtil.getI18nLabel(101063,"返回当前小时"), funcDescUtil.get("CURRHOUR"),"CURRHOUR()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("CURRMINUTE",SystemEnv.getHtmlLabelName(101064,"返回当前分"), funcDescUtil.get("CURRMINUTE"),"CURRMINUTE()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CURRMINUTE",SalaryI18nUtil.getI18nLabel(101064,"返回当前分"), funcDescUtil.get("CURRMINUTE"),"CURRMINUTE()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("CURRSECOND",SystemEnv.getHtmlLabelName(101065,"返回当前秒"), funcDescUtil.get("CURRSECOND"),"CURRSECOND()",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CURRSECOND",SalaryI18nUtil.getI18nLabel(101065,"返回当前秒"), funcDescUtil.get("CURRSECOND"),"CURRSECOND()",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("MAXDATE",SystemEnv.getHtmlLabelName(100803,"返回一组日期中的最大值"), funcDescUtil.get("MAXDATE"),"MAXDATE(日期1,日期2,……)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("MAXDATE",SalaryI18nUtil.getI18nLabel(100803,"返回一组日期中的最大值"), funcDescUtil.get("MAXDATE"),"MAXDATE(日期1,日期2,……)",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("MINDATE",SystemEnv.getHtmlLabelName(100805,"返回一组日期中的最小值"), funcDescUtil.get("MINDATE"),"MINDATE(日期1,日期2,……)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("MINDATE",SalaryI18nUtil.getI18nLabel(100805,"返回一组日期中的最小值"), funcDescUtil.get("MINDATE"),"MINDATE(日期1,日期2,……)",paramArray,nullParamDatas,"String",CURRENTDATA); dateList.add(excelFunc); return dateList; } @@ -175,47 +166,47 @@ public class ExcelFuncs { List logicList=new LinkedList<>(); ExcelFunc excelFunc=null; String [] paramArray=new String[]{}; - excelFunc=new ExcelFunc("IF",SystemEnv.getHtmlLabelName(94940,"如果条件为真,则...否则..."), funcDescUtil.get("IF"),"IF(条件, 表达式1, 表达式2)",paramArray,nullParamDatas,"Object",CURRENTDATA); + excelFunc=new ExcelFunc("IF",SalaryI18nUtil.getI18nLabel(94940,"如果条件为真,则...否则..."), funcDescUtil.get("IF"),"IF(条件, 表达式1, 表达式2)",paramArray,nullParamDatas,"Object",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("AND",SystemEnv.getHtmlLabelName(51100,"且"), funcDescUtil.get("AND"),"AND(条件1, 条件2, [条件3, …])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("AND",SalaryI18nUtil.getI18nLabel(51100,"且"), funcDescUtil.get("AND"),"AND(条件1, 条件2, [条件3, …])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("OR",SystemEnv.getHtmlLabelName(35824,"或"), funcDescUtil.get("OR"),"OR(条件1, 条件2, [条件3, …])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("OR",SalaryI18nUtil.getI18nLabel(35824,"或"), funcDescUtil.get("OR"),"OR(条件1, 条件2, [条件3, …])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("NOT",SystemEnv.getHtmlLabelName(94942,"反转真假结果"), funcDescUtil.get("NOT"),"NOT(逻辑结果)",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("NOT",SalaryI18nUtil.getI18nLabel(94942,"反转真假结果"), funcDescUtil.get("NOT"),"NOT(逻辑结果)",paramArray,nullParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("IN",SystemEnv.getHtmlLabelName(94943,"变量是否包含在一组结果中"), funcDescUtil.get("IN"),"IN(变量, [变量1, 变量2, …])",paramArray,allParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("IN",SalaryI18nUtil.getI18nLabel(94943,"变量是否包含在一组结果中"), funcDescUtil.get("IN"),"IN(变量, [变量1, 变量2, …])",paramArray,allParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("LIKE",SystemEnv.getHtmlLabelName(94944,"文本是否包含任意一个关键字"), funcDescUtil.get("LIKE"),"LIKE(文本, [文本1, 文本2, …])",paramArray,allParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("LIKE",SalaryI18nUtil.getI18nLabel(94944,"文本是否包含任意一个关键字"), funcDescUtil.get("LIKE"),"LIKE(文本, [文本1, 文本2, …])",paramArray,allParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("ISEMPTY",SystemEnv.getHtmlLabelName(94945,"是否为空"), funcDescUtil.get("ISEMPTY"),"ISEMPTY(变量)",paramArray,paramDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("ISEMPTY",SalaryI18nUtil.getI18nLabel(94945,"是否为空"), funcDescUtil.get("ISEMPTY"),"ISEMPTY(变量)",paramArray,paramDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("TRUE",SystemEnv.getHtmlLabelName(94946,"返回真"), funcDescUtil.get("TRUE"),"TRUE()",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("TRUE",SalaryI18nUtil.getI18nLabel(94946,"返回真"), funcDescUtil.get("TRUE"),"TRUE()",paramArray,nullParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("FALSE",SystemEnv.getHtmlLabelName(94947,"返回假"), funcDescUtil.get("FALSE"),"FALSE()",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("FALSE",SalaryI18nUtil.getI18nLabel(94947,"返回假"), funcDescUtil.get("FALSE"),"FALSE()",paramArray,nullParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("IFS",SystemEnv.getHtmlLabelName(94948,"多条件"), funcDescUtil.get("IFS"),"IFS({条件1},{结果1},{条件2},{结果2}...{默认结果})",paramArray,nullParamDatas,"Object",CURRENTDATA); + excelFunc=new ExcelFunc("IFS",SalaryI18nUtil.getI18nLabel(94948,"多条件"), funcDescUtil.get("IFS"),"IFS({条件1},{结果1},{条件2},{结果2}...{默认结果})",paramArray,nullParamDatas,"Object",CURRENTDATA); logicList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("FIND",SystemEnv.getHtmlLabelName(31835,"查找"), funcDescUtil.get("FIND"),"FIND([{查找值1},{查找值2}...{查找值N}],[{查找目标1},{查找目标2}...{查找目标N}])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); + excelFunc=new ExcelFunc("FIND",SalaryI18nUtil.getI18nLabel(31835,"查找"), funcDescUtil.get("FIND"),"FIND([{查找值1},{查找值2}...{查找值N}],[{查找目标1},{查找目标2}...{查找目标N}])",paramArray,nullParamDatas,"Boolean",CURRENTDATA); logicList.add(excelFunc); return logicList; } @@ -229,81 +220,81 @@ public class ExcelFuncs { List stringList=new LinkedList<>(); ExcelFunc excelFunc=null; String [] paramArray=new String[]{}; - excelFunc=new ExcelFunc("CONCAT",SystemEnv.getHtmlLabelName(94949,"链接多个文本"), funcDescUtil.get("CONCAT"),"CONCAT(文本1, 文本2, [文本3, …])",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("CONCAT",SalaryI18nUtil.getI18nLabel(94949,"链接多个文本"), funcDescUtil.get("CONCAT"),"CONCAT(文本1, 文本2, [文本3, …])",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("TEXT",SystemEnv.getHtmlLabelName(94950,"将变量转为文本"), funcDescUtil.get("TEXT"),"TEXT(变量)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("TEXT",SalaryI18nUtil.getI18nLabel(94950,"将变量转为文本"), funcDescUtil.get("TEXT"),"TEXT(变量)",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("VALUE",SystemEnv.getHtmlLabelName(94951,"将文本转为数字"), funcDescUtil.get("VALUE"),"VALUE(文本)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("VALUE",SalaryI18nUtil.getI18nLabel(94951,"将文本转为数字"), funcDescUtil.get("VALUE"),"VALUE(文本)",paramArray,nullParamDatas,"Number",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("LEN",SystemEnv.getHtmlLabelName(94952,"返回文本长度"), funcDescUtil.get("LEN"),"LEN(文本)",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("LEN",SalaryI18nUtil.getI18nLabel(94952,"返回文本长度"), funcDescUtil.get("LEN"),"LEN(文本)",paramArray,nullParamDatas,"Number",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("SEARCH",SystemEnv.getHtmlLabelName(94953,"在文本中查找关键字"), funcDescUtil.get("SEARCH"),"SEARCH(关键字, 文本, [搜索开始位置])",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("SEARCH",SalaryI18nUtil.getI18nLabel(94953,"在文本中查找关键字"), funcDescUtil.get("SEARCH"),"SEARCH(关键字, 文本, [搜索开始位置])",paramArray,nullParamDatas,"Number",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("REPLACE",SystemEnv.getHtmlLabelName(94954,"替换文本中的字"), funcDescUtil.get("REPLACE"),"REPLACE(原文本, 替换开始位置, 替换字符数, 新文本)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("REPLACE",SalaryI18nUtil.getI18nLabel(94954,"替换文本中的字"), funcDescUtil.get("REPLACE"),"REPLACE(原文本, 替换开始位置, 替换字符数, 新文本)",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("REPT",SystemEnv.getHtmlLabelName(94955,"将文本重复指定次数"), funcDescUtil.get("REPT"),"REPT(文本, 重复次数)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("REPT",SalaryI18nUtil.getI18nLabel(94955,"将文本重复指定次数"), funcDescUtil.get("REPT"),"REPT(文本, 重复次数)",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("PAD",SystemEnv.getHtmlLabelName(94956,"将文本填充至指定长度"), funcDescUtil.get("PAD"),"PAD(原文本, 长度, 填充用的文本, ['填充位置'])",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("PAD",SalaryI18nUtil.getI18nLabel(94956,"将文本填充至指定长度"), funcDescUtil.get("PAD"),"PAD(原文本, 长度, 填充用的文本, ['填充位置'])",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("TRIM",SystemEnv.getHtmlLabelName(94957,"清除前后空格"), funcDescUtil.get("TRIM"),"TRIM(文本)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("TRIM",SalaryI18nUtil.getI18nLabel(94957,"清除前后空格"), funcDescUtil.get("TRIM"),"TRIM(文本)",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("LEFT",SystemEnv.getHtmlLabelName(94958,"返回文本左侧开始的文字"), funcDescUtil.get("LEFT"),"LEFT(文本, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("LEFT",SalaryI18nUtil.getI18nLabel(94958,"返回文本左侧开始的文字"), funcDescUtil.get("LEFT"),"LEFT(文本, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("RIGHT",SystemEnv.getHtmlLabelName(94959,"返回文本右侧开始的文字"), funcDescUtil.get("RIGHT"),"RIGHT(文本, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("RIGHT",SalaryI18nUtil.getI18nLabel(94959,"返回文本右侧开始的文字"), funcDescUtil.get("RIGHT"),"RIGHT(文本, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("MID",SystemEnv.getHtmlLabelName(94960,"返回文本指定位置开始的文字"), funcDescUtil.get("MID"),"MID(文本, 指定位置, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("MID",SalaryI18nUtil.getI18nLabel(94960,"返回文本指定位置开始的文字"), funcDescUtil.get("MID"),"MID(文本, 指定位置, 截取字符数)",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("SCORE",SystemEnv.getHtmlLabelName(94961,"获取选项型控件分数"), funcDescUtil.get("SCORE"),"SCORE({选项型控件})",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("SCORE",SalaryI18nUtil.getI18nLabel(94961,"获取选项型控件分数"), funcDescUtil.get("SCORE"),"SCORE({选项型控件})",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("IDCARD",SystemEnv.getHtmlLabelName(94962,"身份证函数"), funcDescUtil.get("IDCARD"),"IDCARD({身份证号码}, {查找类型})",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("IDCARD",SalaryI18nUtil.getI18nLabel(94962,"身份证函数"), funcDescUtil.get("IDCARD"),"IDCARD({身份证号码}, {查找类型})",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("ISSTRING",SystemEnv.getHtmlLabelName(0,"是否是字符串"), funcDescUtil.get("ISSTRING"),"ISSTRING({任意控件})",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("ISSTRING",SalaryI18nUtil.getI18nLabel(0,"是否是字符串"), funcDescUtil.get("ISSTRING"),"ISSTRING({任意控件})",paramArray,nullParamDatas,"String",CURRENTDATA); stringList.add(excelFunc); // paramArray=new String[]{}; -// excelFunc=new ExcelFunc("SUBSTRING",SystemEnv.getHtmlLabelName(97524,"字符截取函数"), funcDescUtil.get("SUBSTRING"),"SUBSTRING({源字符}, {截取开始位置},{截取结束位置})",paramArray,nullParamDatas,"String",CURRENTDATA); +// excelFunc=new ExcelFunc("SUBSTRING",SalaryI18nUtil.getI18nLabel(97524,"字符截取函数"), funcDescUtil.get("SUBSTRING"),"SUBSTRING({源字符}, {截取开始位置},{截取结束位置})",paramArray,nullParamDatas,"String",CURRENTDATA); // stringList.add(excelFunc); // paramArray=new String[]{}; -// excelFunc=new ExcelFunc("SUBSTITUE",SystemEnv.getHtmlLabelName(97525,"字符查找替换函数"), funcDescUtil.get("SUBSTITUE"),"SUBSTITUE({源字符}, {被替换字符},{新字符})",paramArray,nullParamDatas,"String",CURRENTDATA); +// excelFunc=new ExcelFunc("SUBSTITUE",SalaryI18nUtil.getI18nLabel(97525,"字符查找替换函数"), funcDescUtil.get("SUBSTITUE"),"SUBSTITUE({源字符}, {被替换字符},{新字符})",paramArray,nullParamDatas,"String",CURRENTDATA); // stringList.add(excelFunc); // paramArray=new String[]{}; -// excelFunc=new ExcelFunc("LOWER",SystemEnv.getHtmlLabelName(97526,"字符转小写函数"), funcDescUtil.get("LOWER"),"LOWER({源字符})",paramArray,nullParamDatas,"String",CURRENTDATA); +// excelFunc=new ExcelFunc("LOWER",SalaryI18nUtil.getI18nLabel(97526,"字符转小写函数"), funcDescUtil.get("LOWER"),"LOWER({源字符})",paramArray,nullParamDatas,"String",CURRENTDATA); // stringList.add(excelFunc); // paramArray=new String[]{}; -// excelFunc=new ExcelFunc("UPPER",SystemEnv.getHtmlLabelName(97527,"字符转大写函数"), funcDescUtil.get("UPPER"),"UPPER({源字符})",paramArray,nullParamDatas,"String",CURRENTDATA); +// excelFunc=new ExcelFunc("UPPER",SalaryI18nUtil.getI18nLabel(97527,"字符转大写函数"), funcDescUtil.get("UPPER"),"UPPER({源字符})",paramArray,nullParamDatas,"String",CURRENTDATA); // stringList.add(excelFunc); // paramArray=new String[]{}; -// excelFunc=new ExcelFunc("EXACT",SystemEnv.getHtmlLabelName(97528,"字符比较函数"), funcDescUtil.get("EXACT"),"EXACT({字符1}, {字符2})",paramArray,nullParamDatas,"String",CURRENTDATA); +// excelFunc=new ExcelFunc("EXACT",SalaryI18nUtil.getI18nLabel(97528,"字符比较函数"), funcDescUtil.get("EXACT"),"EXACT({字符1}, {字符2})",paramArray,nullParamDatas,"String",CURRENTDATA); // stringList.add(excelFunc); return stringList; } @@ -316,36 +307,36 @@ public class ExcelFuncs { List mathList=new LinkedList<>(); ExcelFunc excelFunc=null; String [] paramArray=new String[]{}; - excelFunc=new ExcelFunc("ROUNDUP",SystemEnv.getHtmlLabelName(94963,"向上舍入"), funcDescUtil.get("ROUNDUP"),"ROUNDUP(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("ROUNDUP",SalaryI18nUtil.getI18nLabel(94963,"向上舍入"), funcDescUtil.get("ROUNDUP"),"ROUNDUP(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); mathList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("ROUND",SystemEnv.getHtmlLabelName(17392,"四舍五入"), funcDescUtil.get("ROUND"),"ROUND(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("ROUND",SalaryI18nUtil.getI18nLabel(17392,"四舍五入"), funcDescUtil.get("ROUND"),"ROUND(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); mathList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("ROUNDDOWN",SystemEnv.getHtmlLabelName(94964,"向下舍入"), funcDescUtil.get("ROUNDDOWN"),"ROUNDDOWN(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("ROUNDDOWN",SalaryI18nUtil.getI18nLabel(94964,"向下舍入"), funcDescUtil.get("ROUNDDOWN"),"ROUNDDOWN(数值, [小数位精确度])",paramArray,nullParamDatas,"Number",CURRENTDATA); mathList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("AGGREGATION",SystemEnv.getHtmlLabelName(94965,"聚合运算"), funcDescUtil.get("AGGREGATION"),"AGGREGATION({数字}...,{聚合运算类型})",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("AGGREGATION",SalaryI18nUtil.getI18nLabel(94965,"聚合运算"), funcDescUtil.get("AGGREGATION"),"AGGREGATION({数字}...,{聚合运算类型})",paramArray,nullParamDatas,"Number",CURRENTDATA); mathList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("MOD",SystemEnv.getHtmlLabelName(94966,"求余"), funcDescUtil.get("MOD"),"ROUNDDOWN({数字},{数字})",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("MOD",SalaryI18nUtil.getI18nLabel(94966,"求余"), funcDescUtil.get("MOD"),"ROUNDDOWN({数字},{数字})",paramArray,nullParamDatas,"Number",CURRENTDATA); mathList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("TRUNC",SystemEnv.getHtmlLabelName(94967,"数字格式化"), funcDescUtil.get("TRUNC"),"ROUNDDOWN({数字},{精度})",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("TRUNC",SalaryI18nUtil.getI18nLabel(94967,"数字格式化"), funcDescUtil.get("TRUNC"),"ROUNDDOWN({数字},{精度})",paramArray,nullParamDatas,"Number",CURRENTDATA); mathList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("ISINT",SystemEnv.getHtmlLabelName(0,"字符内容是否是整数"), funcDescUtil.get("ISINT"),"ISINT({字符})",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("ISINT",SalaryI18nUtil.getI18nLabel(0,"字符内容是否是整数"), funcDescUtil.get("ISINT"),"ISINT({字符})",paramArray,nullParamDatas,"String",CURRENTDATA); mathList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("ISNUMBER",SystemEnv.getHtmlLabelName(0,"字符内容是否是数字"), funcDescUtil.get("ISNUMBER"),"ISNUMBER({字符})",paramArray,nullParamDatas,"String",CURRENTDATA); + excelFunc=new ExcelFunc("ISNUMBER",SalaryI18nUtil.getI18nLabel(0,"字符内容是否是数字"), funcDescUtil.get("ISNUMBER"),"ISNUMBER({字符})",paramArray,nullParamDatas,"String",CURRENTDATA); mathList.add(excelFunc); return mathList; @@ -360,15 +351,15 @@ public class ExcelFuncs { List findList=new LinkedList<>(); ExcelFunc excelFunc=null; String [] paramArray=new String[]{}; - excelFunc=new ExcelFunc("CHOOSE",SystemEnv.getHtmlLabelName(94968,"返回索引范围内指定的值"), funcDescUtil.get("CHOOSE"),"CHOOSE(数据源,[条件])",paramArray,nullParamDatas,"Array",CURRENTDATA); + excelFunc=new ExcelFunc("CHOOSE",SalaryI18nUtil.getI18nLabel(94968,"返回索引范围内指定的值"), funcDescUtil.get("CHOOSE"),"CHOOSE(数据源,[条件])",paramArray,nullParamDatas,"Array",CURRENTDATA); findList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("VLOOKUPS",SystemEnv.getHtmlLabelName(94969,"按列查找,返回所需值"), funcDescUtil.get("VLOOKUPS"),"VLOOKUPS(表,[条件],[返回参数])",paramArray,nullParamDatas,"Array",CURRENTDATA); + excelFunc=new ExcelFunc("VLOOKUPS",SalaryI18nUtil.getI18nLabel(94969,"按列查找,返回所需值"), funcDescUtil.get("VLOOKUPS"),"VLOOKUPS(表,[条件],[返回参数])",paramArray,nullParamDatas,"Array",CURRENTDATA); findList.add(excelFunc); paramArray=new String[]{}; - excelFunc=new ExcelFunc("MATCH",SystemEnv.getHtmlLabelName(94970,"返回指定数值在指定数组区域中的位置"), funcDescUtil.get("MATCH"),"MATCH(值,[数组])",paramArray,nullParamDatas,"Number",CURRENTDATA); + excelFunc=new ExcelFunc("MATCH",SalaryI18nUtil.getI18nLabel(94970,"返回指定数值在指定数组区域中的位置"), funcDescUtil.get("MATCH"),"MATCH(值,[数组])",paramArray,nullParamDatas,"Number",CURRENTDATA); findList.add(excelFunc); return findList; } @@ -382,23 +373,23 @@ public class ExcelFuncs { ExcelFunc excelFunc=null; String [] paramArray=new String[]{"Form","Number","Boolean"}; - excelFunc=new ExcelFunc("COUNT", SystemEnv.getHtmlLabelName(16654,"计数"), funcDescUtil.get("COUNT"),"COUNT(表格)",paramArray,paramDatas,"Number",ALLFORM); + excelFunc=new ExcelFunc("COUNT", SalaryI18nUtil.getI18nLabel(16654,"计数"), funcDescUtil.get("COUNT"),"COUNT(表格)",paramArray,paramDatas,"Number",ALLFORM); aggList.add(excelFunc); paramArray=new String[]{"Number","Number","Boolean"}; - excelFunc=new ExcelFunc("SUM",SystemEnv.getHtmlLabelName(95012,"求和") , funcDescUtil.get("SUM"),"SUM(数字字段)",paramArray,paramDatas,"Number",ALLFORM); + excelFunc=new ExcelFunc("SUM",SalaryI18nUtil.getI18nLabel(95012,"求和") , funcDescUtil.get("SUM"),"SUM(数字字段)",paramArray,paramDatas,"Number",ALLFORM); aggList.add(excelFunc); paramArray=new String[]{"Number","Number","Boolean"}; - excelFunc=new ExcelFunc("AVG",SystemEnv.getHtmlLabelName(19550,"平均值"), funcDescUtil.get("AVG"),"AVG(数字字段)",paramArray,paramDatas,"Number",ALLFORM); + excelFunc=new ExcelFunc("AVG",SalaryI18nUtil.getI18nLabel(19550,"平均值"), funcDescUtil.get("AVG"),"AVG(数字字段)",paramArray,paramDatas,"Number",ALLFORM); aggList.add(excelFunc); paramArray=new String[]{"Number","Number","Boolean"}; - excelFunc=new ExcelFunc("MIN",SystemEnv.getHtmlLabelName(12318,"最小值"), funcDescUtil.get("MIN"),"MIN(表格)",paramArray,paramDatas,"Number",ALLFORM); + excelFunc=new ExcelFunc("MIN",SalaryI18nUtil.getI18nLabel(12318,"最小值"), funcDescUtil.get("MIN"),"MIN(表格)",paramArray,paramDatas,"Number",ALLFORM); aggList.add(excelFunc); paramArray=new String[]{"Number","Number","Boolean"}; - excelFunc=new ExcelFunc("MAX",SystemEnv.getHtmlLabelName(66750,"最大值"), funcDescUtil.get("MAX"),"MAX(表格)",paramArray,paramDatas,"Number",ALLFORM); + excelFunc=new ExcelFunc("MAX",SalaryI18nUtil.getI18nLabel(66750,"最大值"), funcDescUtil.get("MAX"),"MAX(表格)",paramArray,paramDatas,"Number",ALLFORM); aggList.add(excelFunc); return aggList; } @@ -410,7 +401,7 @@ public class ExcelFuncs { public Object getFinanceList(){ ExcelFunc excelFunc = null; List funcs = Lists.newArrayList(); - excelFunc = new ExcelFunc("GETMONEY",SystemEnv.getHtmlLabelName(0,"获取锁给定数字的金额大写"), funcDescUtil.get("GETMONEY"),"GETMONEY({数字})",null,nullParamDatas,"",CURRENTDATA); + excelFunc = new ExcelFunc("GETMONEY",SalaryI18nUtil.getI18nLabel(0,"获取锁给定数字的金额大写"), funcDescUtil.get("GETMONEY"),"GETMONEY({数字})",null,nullParamDatas,"",CURRENTDATA); funcs.add(excelFunc); return funcs; @@ -423,73 +414,54 @@ public class ExcelFuncs { ExcelFunc excelFunc = null; List funcs = Lists.newArrayList(); -// excelFunc = new ExcelFunc("GETHRMLOGINID",SystemEnv.getHtmlLabelName(100807,"返回指定人员系统账号"), funcDescUtil.get("GETHRMLOGINID"),"GETHRMLOGINID({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETHRMLOGINID",SalaryI18nUtil.getI18nLabel(100807,"返回指定人员系统账号"), funcDescUtil.get("GETHRMLOGINID"),"GETHRMLOGINID({表单.人员})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETHRMWORKCODE",SystemEnv.getHtmlLabelName(100809,"返回指定人员编号"), funcDescUtil.get("GETHRMWORKCODE"),"GETHRMWORKCODE({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETHRMWORKCODE",SalaryI18nUtil.getI18nLabel(100809,"返回指定人员编号"), funcDescUtil.get("GETHRMWORKCODE"),"GETHRMWORKCODE({表单.人员})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETHRMMANAGER",SystemEnv.getHtmlLabelName(100811,"返回指定人员直接上级"), funcDescUtil.get("GETHRMMANAGER"),"GETHRMMANAGER({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETHRMMANAGER",SalaryI18nUtil.getI18nLabel(100811,"返回指定人员直接上级"), funcDescUtil.get("GETHRMMANAGER"),"GETHRMMANAGER({表单.人员})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETHRMALLMANAGER",SystemEnv.getHtmlLabelName(100813,"返回指定人员所有上级"), funcDescUtil.get("GETHRMALLMANAGER"),"GETHRMALLMANAGER({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETHRMALLMANAGER",SalaryI18nUtil.getI18nLabel(100813,"返回指定人员所有上级"), funcDescUtil.get("GETHRMALLMANAGER"),"GETHRMALLMANAGER({表单.人员})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETHRMDEPARTMENT",SystemEnv.getHtmlLabelName(100815,"返回指定人员部门"), funcDescUtil.get("GETHRMDEPARTMENT"),"GETHRMDEPARTMENT({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETHRMDEPARTMENT",SalaryI18nUtil.getI18nLabel(100815,"返回指定人员部门"), funcDescUtil.get("GETHRMDEPARTMENT"),"GETHRMDEPARTMENT({表单.人员})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETHRMSUBCOMPANY",SystemEnv.getHtmlLabelName(100817,"返回指定人员分部"), funcDescUtil.get("GETHRMSUBCOMPANY"),"GETHRMSUBCOMPANY({表单.人员})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETHRMSUBCOMPANY",SalaryI18nUtil.getI18nLabel(100817,"返回指定人员分部"), funcDescUtil.get("GETHRMSUBCOMPANY"),"GETHRMSUBCOMPANY({表单.人员})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETDEPARTMENTNAME",SystemEnv.getHtmlLabelName(100819,"返回指定部门名称"), funcDescUtil.get("GETDEPARTMENTNAME"),"GETDEPARTMENTNAME({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETDEPARTMENTNAME",SalaryI18nUtil.getI18nLabel(100819,"返回指定部门名称"), funcDescUtil.get("GETDEPARTMENTNAME"),"GETDEPARTMENTNAME({表单.部门})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETDEPARTMENTCODE",SystemEnv.getHtmlLabelName(100821,"返回指定部门编号"), funcDescUtil.get("GETDEPARTMENTCODE"),"GETDEPARTMENTCODE({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETDEPARTMENTCODE",SalaryI18nUtil.getI18nLabel(100821,"返回指定部门编号"), funcDescUtil.get("GETDEPARTMENTCODE"),"GETDEPARTMENTCODE({表单.部门})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETSUPERDEPARTMENT",SystemEnv.getHtmlLabelName(100823,"返回指定部门直接上级部门"), funcDescUtil.get("GETSUPERDEPARTMENT"),"GETSUPERDEPARTMENT({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETSUPERDEPARTMENT",SalaryI18nUtil.getI18nLabel(100823,"返回指定部门直接上级部门"), funcDescUtil.get("GETSUPERDEPARTMENT"),"GETSUPERDEPARTMENT({表单.部门})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETALLSUPERDEPARTMENT",SystemEnv.getHtmlLabelName(100825,"返回指定部门所有上级部门"), funcDescUtil.get("GETALLSUPERDEPARTMENT"),"GETALLSUPERDEPARTMENT({表单.部门})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETALLSUPERDEPARTMENT",SalaryI18nUtil.getI18nLabel(100825,"返回指定部门所有上级部门"), funcDescUtil.get("GETALLSUPERDEPARTMENT"),"GETALLSUPERDEPARTMENT({表单.部门})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETSUBCOMPANYNAME",SystemEnv.getHtmlLabelName(100827,"返回指定分部名称"), funcDescUtil.get("GETSUBCOMPANYNAME"),"GETSUBCOMPANYNAME({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETSUBCOMPANYNAME",SalaryI18nUtil.getI18nLabel(100827,"返回指定分部名称"), funcDescUtil.get("GETSUBCOMPANYNAME"),"GETSUBCOMPANYNAME({表单.分部})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETSUBCOMPANYCODE",SystemEnv.getHtmlLabelName(100829,"返回指定分部编号"), funcDescUtil.get("GETSUBCOMPANYCODE"),"GETSUBCOMPANYCODE({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETSUBCOMPANYCODE",SalaryI18nUtil.getI18nLabel(100829,"返回指定分部编号"), funcDescUtil.get("GETSUBCOMPANYCODE"),"GETSUBCOMPANYCODE({表单.分部})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETSUPERSUBCOMPANY",SystemEnv.getHtmlLabelName(100831,"返回指定分部直接上级分部"), funcDescUtil.get("GETSUPERSUBCOMPANY"),"GETSUPERSUBCOMPANY({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETSUPERSUBCOMPANY",SalaryI18nUtil.getI18nLabel(100831,"返回指定分部直接上级分部"), funcDescUtil.get("GETSUPERSUBCOMPANY"),"GETSUPERSUBCOMPANY({表单.分部})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); // -// excelFunc = new ExcelFunc("GETALLSUPERSUBCOMPANY",SystemEnv.getHtmlLabelName(100833,"返回指定分部所有上级分部"), funcDescUtil.get("GETALLSUPERSUBCOMPANY"),"GETALLSUPERSUBCOMPANY({表单.分部})",null,nullParamDatas,"",CURRENTDATA); +// excelFunc = new ExcelFunc("GETALLSUPERSUBCOMPANY",SalaryI18nUtil.getI18nLabel(100833,"返回指定分部所有上级分部"), funcDescUtil.get("GETALLSUPERSUBCOMPANY"),"GETALLSUPERSUBCOMPANY({表单.分部})",null,nullParamDatas,"",CURRENTDATA); // funcs.add(excelFunc); - excelFunc = new ExcelFunc("GETHRMNAME",SystemEnv.getHtmlLabelName(100833,"获取人员名称"), funcDescUtil.get("GETHRMNAME"),"GETHRMNAME({人员})",null,nullParamDatas,"",CURRENTDATA); + excelFunc = new ExcelFunc("GETHRMNAME",SalaryI18nUtil.getI18nLabel(100833,"获取人员名称"), funcDescUtil.get("GETHRMNAME"),"GETHRMNAME({人员})",null,nullParamDatas,"",CURRENTDATA); funcs.add(excelFunc); - excelFunc = new ExcelFunc("GETHRMMOBILE",SystemEnv.getHtmlLabelName(100833,"获取人员手机号码"), funcDescUtil.get("GETHRMMOBILE"),"GETHRMMOBILE({人员})",null,nullParamDatas,"",CURRENTDATA); + excelFunc = new ExcelFunc("GETHRMMOBILE",SalaryI18nUtil.getI18nLabel(100833,"获取人员手机号码"), funcDescUtil.get("GETHRMMOBILE"),"GETHRMMOBILE({人员})",null,nullParamDatas,"",CURRENTDATA); funcs.add(excelFunc); return funcs; } - - public List getOtherFuncs(){ - List otherFuncs=new ArrayList<>(); - for(int i=0;i moduleFuncs=(List)result; - if(moduleFuncs.size()>0){ - otherFuncs.addAll(moduleFuncs); - } - } - } catch (Exception e) { - logger.error("err",e); - } - } - return otherFuncs; - } } diff --git a/src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java b/src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java index 1b0ea6889..d4e5fcee3 100644 --- a/src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java +++ b/src/com/engine/salary/formlua/entity/parameter/FuncDescUtil.java @@ -1,6 +1,6 @@ package com.engine.salary.formlua.entity.parameter; -import com.weaver.common.i18n.label.SystemEnv; +import com.engine.salary.util.SalaryI18nUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -11,122 +11,124 @@ import java.util.Map; @Component public class FuncDescUtil { - protected final Logger logger = LoggerFactory.getLogger(FuncDescUtil.class); - Map funcMap=new HashMap(); - public void initData(){ - //聚合函数 - funcMap.put("COUNT",SystemEnv.getHtmlLabelName(94986,"返回指定表格中满足条件的数据条数。示例:COUNT({员工表})")); - funcMap.put("SUM",SystemEnv.getHtmlLabelName(94987,"返回指定表格中满足条件的数据,其指定数字字段值的总和。统计条件中不可嵌套使用统计函数。示例:SUM({员工表.工资})")); - funcMap.put("AVG",SystemEnv.getHtmlLabelName(94988,"返回指定表格中满足条件的数据,其指定数字字段值的平均值。统计条件中不可嵌套使用统计函数。示例:AVG({员工表.工资})")); - funcMap.put("MIN",SystemEnv.getHtmlLabelName(94989,"返回指定表格中满足条件的数据,其指定数字字段值的最小值。统计条件中不可嵌套使用统计函数。示例:MIN({员工表.工资})")); - funcMap.put("MAX",SystemEnv.getHtmlLabelName(94990,"返回指定表格中满足条件的数据,其指定数字字段值的最大值。统计条件中不可嵌套使用统计函数。示例:MAX({员工表.工资})")); - //日期函数 - funcMap.put("TODAY",SystemEnv.getHtmlLabelName(97678,"返回当天日期。示例:TODAY() 结果: '2020-01-01'")); - funcMap.put("NOW",SystemEnv.getHtmlLabelName(97689,"返回当天日期+时间。示例:NOW() 结果: '2016-12-24 12:05:38'")); - funcMap.put("DATEADD",SystemEnv.getHtmlLabelName(97691,"对日期加减按照单位加减。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。示例:
DATEADD('2016-12-21', 3) 结果: '2016-12-24'
DATEADD('2016-12-24 20:00:00', 3, 'H') 结果: '2016-12-24 23:00:00'")); - funcMap.put("DATEDIFF",SystemEnv.getHtmlLabelName(97692,"根据指定的单位,返回日期2减去日期1的差值。当日期2小于日期1时,差值为负值。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。
示例:
DATEDIF('2016-12-21', '2016-12-24') 结果: 3
DATEDIF('2016-12-24 20:00:00', '2016-12-25 20:00:00', 'H') 结果: 24")); - funcMap.put("DATEFORMAT",SystemEnv.getHtmlLabelName(97693,"将日期转为指定格式返回。 示例:
DATEFORMAT('2016-12-24', 'YY年MM月DD日') 结果: 2016年12月24日
yyyy 将年份显示为1900-9999
yy 将年份显示为00-99
mm 将月份显示为 01–12
dd 将日期显示为 01–31")); - funcMap.put("YEAR",SystemEnv.getHtmlLabelName(97694,"返回指定日期中的年。示例:
YEAR('2016-12-24') 结果: 2016")); - funcMap.put("MONTH",SystemEnv.getHtmlLabelName(97695,"返回指定日期中的月。示例:
MONTH('2016-12-24') 结果: 12")); - funcMap.put("DAY",SystemEnv.getHtmlLabelName(97696,"返回指定日期中的日。示例:
DAY('2016-12-24') 结果: 24")); - funcMap.put("HOUR",SystemEnv.getHtmlLabelName(97697,"返回指定日期中的小时。示例:
HOUR('2016-12-24 20:30:56') 结果: 20")); - funcMap.put("MINUTE",SystemEnv.getHtmlLabelName(97698,"返回指定日期中的分钟。示例:
MINUTE('2016-12-24 20:30:56') 结果: 30")); - funcMap.put("SECOND",SystemEnv.getHtmlLabelName(97699,"返回指定日期中的秒钟。示例:
SECOND('2016-12-24 20:30:56') 结果: 56")); - funcMap.put("WEEKNUM",SystemEnv.getHtmlLabelName(97700,"返回指定日期为第几周,从每年第1天开始算第1周。示例:
WEEKNUM('2016-12-24') 结果: 52")); - funcMap.put("WEEKDAY",SystemEnv.getHtmlLabelName(97701,"返回指定日期为星期几。返回值为0~6,代表周日~周六。示例:
WEEKDAY('2016-12-24') 结果: 6")); - funcMap.put("EOMONTH",SystemEnv.getHtmlLabelName(97702,"将某月最后一天日期返回。日期可以为指定日期也可以是日期参数,之前的月数用负数表示,之后的月数用正数表示。所输入月数需为整数。
示例:EOMONTH('2021-11-07', -2)
结果:2021-09-30")); - funcMap.put("NETWORKDAYSPI",SystemEnv.getHtmlLabelName(97703,"将指定日期(仅限的过去时间,最大支持跨度为365天)之间包含的工作日天数返回。注意:此函数只能选择过去的时间才可使用,跨度不能超过365天。当日期2小于日期1时,差值为负值。单位默认为日。
示例:想知道李四在2021-11-07和2021-11-12之间的工作日天数。
NETWORKDAYSPI('2021-11-07', '2021-11-12','李四')
结果:5")); - funcMap.put("MAXDATE", SystemEnv.getHtmlLabelName(100804, "取一组日期中的最大值。示例:
MAXDATE('2016-12-24', '2022-12-24') 结果: 2022-12-24")); - funcMap.put("MINDATE", SystemEnv.getHtmlLabelName(100806, "取一组日期中的最小值。示例:
MINDATE('2016-12-24', '2022-12-24') 结果: 2016-12-24")); - //日期中的当前时间操作 - funcMap.put("CURRYEAR", SystemEnv.getHtmlLabelName(101066, "取当前日期的年份。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRYEAR() 结果: 2022")); - funcMap.put("CURRMONTH", SystemEnv.getHtmlLabelName(101067, "取当前日期的月份。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRMONTH() 结果: 2")); - funcMap.put("CURRDAY", SystemEnv.getHtmlLabelName(101068, "取当前日期的天。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRDAY() 结果: 17")); - funcMap.put("CURRWEEK", SystemEnv.getHtmlLabelName(101069, "取当前日期是周几。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRWEEK() 结果: 4")); - funcMap.put("CURRHOUR", SystemEnv.getHtmlLabelName(101070, "取当前日期的小时。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRHOUR() 结果: 11")); - funcMap.put("CURRMINUTE", SystemEnv.getHtmlLabelName(101071, "取当前日期的分钟。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRMINUTE() 结果: 20")); - funcMap.put("CURRSECOND", SystemEnv.getHtmlLabelName(101072, "取当前日期的秒钟。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRSECOND() 结果: 30")); + protected final Logger logger = LoggerFactory.getLogger(FuncDescUtil.class); + Map funcMap = new HashMap(); - //逻辑函数 - funcMap.put("IF",SystemEnv.getHtmlLabelName(97704,"如果条件为真,则执行表达式1,为假则执行表达式2。条件中不可嵌套使用IF函数。示例:
IF({员工表.年龄} > 60, '退休', '在职')、IF({员工表.年龄} > 60, IF({员工表.性别} = {员工表.性别.女}, '退休', '在职'), '在职')")); - funcMap.put("AND",SystemEnv.getHtmlLabelName(97705,"所有条件均为真,则返回真,否则返回假。逻辑操作AND的函数模式。示例:
AND(2 = 2, 2 < 2)")); - funcMap.put("OR",SystemEnv.getHtmlLabelName(97706,"任意一个条件为真,则返回真,否则返回假。逻辑操作OR的函数模式。示例:
OR(2 = 2, 2 > 3)")); - funcMap.put("NOT",SystemEnv.getHtmlLabelName(97707,"对逻辑结果取反。示例:
NOT(2 > 3)")); - funcMap.put("IN",SystemEnv.getHtmlLabelName(97708,"任意类型的变量或常量等于一组同类型变量或常量结果中的任意一个,则返回真。示例:
IN(2, [2, 3, 4])")); - funcMap.put("LIKE",SystemEnv.getHtmlLabelName(97709,"文本类型的变量或常量包含一组文本类型变量或常量结果中的任意一个,则返回真。逻辑操作LIKE的函数模式。示例:
LIKE('大家好', ['大家', '好'])")); - funcMap.put("TRUE",SystemEnv.getHtmlLabelName(97710,"返回真。示例:TRUE()")); - funcMap.put("FALSE",SystemEnv.getHtmlLabelName(97712,"返回假。示例:FALSE()")); - funcMap.put("IFS",SystemEnv.getHtmlLabelName(97713,"多个条件判断,位于单数位置的参数设置为条件,位于双数位置的参数设置为结果,最后一个参数为默认返回值,当所有条件都不满足的时候返回默认参数。示例:IFS(1>1,1,1=1,2,0),结果:2")); - funcMap.put("FIND",SystemEnv.getHtmlLabelName(97714,"用指定参数去另一个参数列表中查找匹配项,指定参数时,填写1则去第一个参数列表中查找,2则是第二个参数列表里匹配查找第一个参数,成功则返回true,失败返回false。示例:FIND([1,2,3],[1,2,3,4],1),结果:true")); + public void initData() { + //聚合函数 + funcMap.put("COUNT", SalaryI18nUtil.getI18nLabel(94986, "返回指定表格中满足条件的数据条数。示例:COUNT({员工表})")); + funcMap.put("SUM", SalaryI18nUtil.getI18nLabel(94987, "返回指定表格中满足条件的数据,其指定数字字段值的总和。统计条件中不可嵌套使用统计函数。示例:SUM({员工表.工资})")); + funcMap.put("AVG", SalaryI18nUtil.getI18nLabel(94988, "返回指定表格中满足条件的数据,其指定数字字段值的平均值。统计条件中不可嵌套使用统计函数。示例:AVG({员工表.工资})")); + funcMap.put("MIN", SalaryI18nUtil.getI18nLabel(94989, "返回指定表格中满足条件的数据,其指定数字字段值的最小值。统计条件中不可嵌套使用统计函数。示例:MIN({员工表.工资})")); + funcMap.put("MAX", SalaryI18nUtil.getI18nLabel(94990, "返回指定表格中满足条件的数据,其指定数字字段值的最大值。统计条件中不可嵌套使用统计函数。示例:MAX({员工表.工资})")); + //日期函数 + funcMap.put("TODAY", SalaryI18nUtil.getI18nLabel(97678, "返回当天日期。示例:TODAY() 结果: '2020-01-01'")); + funcMap.put("NOW", SalaryI18nUtil.getI18nLabel(97689, "返回当天日期+时间。示例:NOW() 结果: '2016-12-24 12:05:38'")); + funcMap.put("DATEADD", SalaryI18nUtil.getI18nLabel(97691, "对日期加减按照单位加减。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。示例:
DATEADD('2016-12-21', 3) 结果: '2016-12-24'
DATEADD('2016-12-24 20:00:00', 3, 'H') 结果: '2016-12-24 23:00:00'")); + funcMap.put("DATEDIFF", SalaryI18nUtil.getI18nLabel(97692, "根据指定的单位,返回日期2减去日期1的差值。当日期2小于日期1时,差值为负值。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。
示例:
DATEDIF('2016-12-21', '2016-12-24') 结果: 3
DATEDIF('2016-12-24 20:00:00', '2016-12-25 20:00:00', 'H') 结果: 24")); + funcMap.put("DATEFORMAT", SalaryI18nUtil.getI18nLabel(97693, "将日期转为指定格式返回。 示例:
DATEFORMAT('2016-12-24', 'YY年MM月DD日') 结果: 2016年12月24日
yyyy 将年份显示为1900-9999
yy 将年份显示为00-99
mm 将月份显示为 01–12
dd 将日期显示为 01–31")); + funcMap.put("YEAR", SalaryI18nUtil.getI18nLabel(97694, "返回指定日期中的年。示例:
YEAR('2016-12-24') 结果: 2016")); + funcMap.put("MONTH", SalaryI18nUtil.getI18nLabel(97695, "返回指定日期中的月。示例:
MONTH('2016-12-24') 结果: 12")); + funcMap.put("DAY", SalaryI18nUtil.getI18nLabel(97696, "返回指定日期中的日。示例:
DAY('2016-12-24') 结果: 24")); + funcMap.put("HOUR", SalaryI18nUtil.getI18nLabel(97697, "返回指定日期中的小时。示例:
HOUR('2016-12-24 20:30:56') 结果: 20")); + funcMap.put("MINUTE", SalaryI18nUtil.getI18nLabel(97698, "返回指定日期中的分钟。示例:
MINUTE('2016-12-24 20:30:56') 结果: 30")); + funcMap.put("SECOND", SalaryI18nUtil.getI18nLabel(97699, "返回指定日期中的秒钟。示例:
SECOND('2016-12-24 20:30:56') 结果: 56")); + funcMap.put("WEEKNUM", SalaryI18nUtil.getI18nLabel(97700, "返回指定日期为第几周,从每年第1天开始算第1周。示例:
WEEKNUM('2016-12-24') 结果: 52")); + funcMap.put("WEEKDAY", SalaryI18nUtil.getI18nLabel(97701, "返回指定日期为星期几。返回值为0~6,代表周日~周六。示例:
WEEKDAY('2016-12-24') 结果: 6")); + funcMap.put("EOMONTH", SalaryI18nUtil.getI18nLabel(97702, "将某月最后一天日期返回。日期可以为指定日期也可以是日期参数,之前的月数用负数表示,之后的月数用正数表示。所输入月数需为整数。
示例:EOMONTH('2021-11-07', -2)
结果:2021-09-30")); + funcMap.put("NETWORKDAYSPI", SalaryI18nUtil.getI18nLabel(97703, "将指定日期(仅限的过去时间,最大支持跨度为365天)之间包含的工作日天数返回。注意:此函数只能选择过去的时间才可使用,跨度不能超过365天。当日期2小于日期1时,差值为负值。单位默认为日。
示例:想知道李四在2021-11-07和2021-11-12之间的工作日天数。
NETWORKDAYSPI('2021-11-07', '2021-11-12','李四')
结果:5")); + funcMap.put("MAXDATE", SalaryI18nUtil.getI18nLabel(100804, "取一组日期中的最大值。示例:
MAXDATE('2016-12-24', '2022-12-24') 结果: 2022-12-24")); + funcMap.put("MINDATE", SalaryI18nUtil.getI18nLabel(100806, "取一组日期中的最小值。示例:
MINDATE('2016-12-24', '2022-12-24') 结果: 2016-12-24")); + //日期中的当前时间操作 + funcMap.put("CURRYEAR", SalaryI18nUtil.getI18nLabel(101066, "取当前日期的年份。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRYEAR() 结果: 2022")); + funcMap.put("CURRMONTH", SalaryI18nUtil.getI18nLabel(101067, "取当前日期的月份。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRMONTH() 结果: 2")); + funcMap.put("CURRDAY", SalaryI18nUtil.getI18nLabel(101068, "取当前日期的天。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRDAY() 结果: 17")); + funcMap.put("CURRWEEK", SalaryI18nUtil.getI18nLabel(101069, "取当前日期是周几。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRWEEK() 结果: 4")); + funcMap.put("CURRHOUR", SalaryI18nUtil.getI18nLabel(101070, "取当前日期的小时。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRHOUR() 结果: 11")); + funcMap.put("CURRMINUTE", SalaryI18nUtil.getI18nLabel(101071, "取当前日期的分钟。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRMINUTE() 结果: 20")); + funcMap.put("CURRSECOND", SalaryI18nUtil.getI18nLabel(101072, "取当前日期的秒钟。示例:
假设当前时间为:2022年2月17日 11:20:30 ,CURRSECOND() 结果: 30")); - //文本函数 - funcMap.put("CONCAT",SystemEnv.getHtmlLabelName(97730,"可用于连接多个任意类型的文本、日期、数字变量或常量。示例:
CONCAT({总价}/10000, '万元')")); - funcMap.put("TEXT",SystemEnv.getHtmlLabelName(97731,"将变量转为文本。示例:
TEXT({当前数据.性别}) 结果: '男'")); - funcMap.put("VALUE",SystemEnv.getHtmlLabelName(97732,"将文本转为数字。示例:
VALUE('23') 结果: 23")); - funcMap.put("LEN",SystemEnv.getHtmlLabelName(97733,"返回文本的长度,中文、英文都算1个字符。示例:
LEN('大家好dajiahao') 结果: 12")); - funcMap.put("SEARCH",SystemEnv.getHtmlLabelName(97734,"在指定文本中查找关键字,返回第一次出现关键字的字符位置,文本的第一个字记为1。未找到,返回0。搜索开始位置,表示从文本的第几个字符开始搜索,默认为1。示例:
SEARCH('大家', '大家好大家好', 3) 结果: 4")); - funcMap.put("REPLACE",SystemEnv.getHtmlLabelName(97735,"在原文本中,从替换位置开始,往后数指定的替换字符数,将这段文本替换为新文本。示例:
REPLACE('大家好大家好', 2, 3, 'dajia') 结果: '大dajia家好'")); - funcMap.put("REPT",SystemEnv.getHtmlLabelName(97736,"将文本重复指定次数。示例:
REPT('大家', 2) 结果: '大家大家'")); - funcMap.put("PAD",SystemEnv.getHtmlLabelName(97737,"将原文本填充到指定长度,如果文本长度大于设置的长度,则不做任何操作。填充位置可用参数:'LEFT'、'RIGHT'。示例:
PAD('你好', 4, '你', 'LEFT') 结果: '你你你好'")); - funcMap.put("TRIM",SystemEnv.getHtmlLabelName(97738,"删除文本首尾的空格。示例:
TRIM(' 大家好 ') 结果: '大家好'")); - funcMap.put("LEFT",SystemEnv.getHtmlLabelName(97739,"从文本左侧开始,返回指定字符数的文字。示例:
LEFT('大家好', 2) 结果: '大家'")); - funcMap.put("RIGHT",SystemEnv.getHtmlLabelName(97740,"从文本右侧开始,返回指定字符数的文字。示例:
RIGHT('大家好', 2) 结果: '家好'")); - funcMap.put("MID",SystemEnv.getHtmlLabelName(97741,"从文本指定位置之后开始,返回指定字符数的文字。示例:
MID('大家好', 2, 1) 结果: '家'")); - funcMap.put("ISEMPTY",SystemEnv.getHtmlLabelName(97742,"变量为空或未填写,则返回真。示例:
ISEMPTY({员工表.电话})")); - funcMap.put("IDCARD",SystemEnv.getHtmlLabelName(97743,"从身份证号码中获取相关信息,比如:生日(BD)、年龄(AGE)、籍贯(NA)、性别(GENDER)。示例:
IDCARD( ‘43070319980706334X’ , ‘BD’ ) 结果: '1998-07-06'")); - funcMap.put("SCORE",SystemEnv.getHtmlLabelName(97744,"获取选项型控件(单选框、复选框、下拉菜单)分数。示例:SCORE({当前数据.单选框}) 结果:选项分数
注:未设置选项分数时,结果为0")); - funcMap.put("SUBSTRING", SystemEnv.getHtmlLabelName(97745,"字符截取函数,用于按起始位置截取字符。
示例:SUBSTRING('abcdefg',2,3)
结果:bc")); - funcMap.put("SUBSTITUE", SystemEnv.getHtmlLabelName(97746,"字符查找替换函数,替换字符中的所有关键词为新字符。
示例:SUBSTITUE('泛微移动办公','泛微','eteams')
结果:eteams移动办公")); - funcMap.put("LOWER", SystemEnv.getHtmlLabelName(97747,"将字符中的字母转为小写。
示例:LOWER('abc')
结果:ABC")); - funcMap.put("UPPER", SystemEnv.getHtmlLabelName(97748,"将字符中的字母转为大写。
示例:LOWER('ABC')
结果:abc")); - funcMap.put("EXACT", SystemEnv.getHtmlLabelName(97749,"比较两个字符是否相等,区分字母的大小写。
示例:EXACT('泛微Eteams','泛微eteams')
结果:false")); - funcMap.put("ISSTRING", SystemEnv.getHtmlLabelName(0,"判断是否是字符。
示例:ISSTRING('泛微Eteams')
结果:true")); + //逻辑函数 + funcMap.put("IF", SalaryI18nUtil.getI18nLabel(97704, "如果条件为真,则执行表达式1,为假则执行表达式2。条件中不可嵌套使用IF函数。示例:
IF({员工表.年龄} > 60, '退休', '在职')、IF({员工表.年龄} > 60, IF({员工表.性别} = {员工表.性别.女}, '退休', '在职'), '在职')")); + funcMap.put("AND", SalaryI18nUtil.getI18nLabel(97705, "所有条件均为真,则返回真,否则返回假。逻辑操作AND的函数模式。示例:
AND(2 = 2, 2 < 2)")); + funcMap.put("OR", SalaryI18nUtil.getI18nLabel(97706, "任意一个条件为真,则返回真,否则返回假。逻辑操作OR的函数模式。示例:
OR(2 = 2, 2 > 3)")); + funcMap.put("NOT", SalaryI18nUtil.getI18nLabel(97707, "对逻辑结果取反。示例:
NOT(2 > 3)")); + funcMap.put("IN", SalaryI18nUtil.getI18nLabel(97708, "任意类型的变量或常量等于一组同类型变量或常量结果中的任意一个,则返回真。示例:
IN(2, [2, 3, 4])")); + funcMap.put("LIKE", SalaryI18nUtil.getI18nLabel(97709, "文本类型的变量或常量包含一组文本类型变量或常量结果中的任意一个,则返回真。逻辑操作LIKE的函数模式。示例:
LIKE('大家好', ['大家', '好'])")); + funcMap.put("TRUE", SalaryI18nUtil.getI18nLabel(97710, "返回真。示例:TRUE()")); + funcMap.put("FALSE", SalaryI18nUtil.getI18nLabel(97712, "返回假。示例:FALSE()")); + funcMap.put("IFS", SalaryI18nUtil.getI18nLabel(97713, "多个条件判断,位于单数位置的参数设置为条件,位于双数位置的参数设置为结果,最后一个参数为默认返回值,当所有条件都不满足的时候返回默认参数。示例:IFS(1>1,1,1=1,2,0),结果:2")); + funcMap.put("FIND", SalaryI18nUtil.getI18nLabel(97714, "用指定参数去另一个参数列表中查找匹配项,指定参数时,填写1则去第一个参数列表中查找,2则是第二个参数列表里匹配查找第一个参数,成功则返回true,失败返回false。示例:FIND([1,2,3],[1,2,3,4],1),结果:true")); - //数学函数 - funcMap.put("ROUND",SystemEnv.getHtmlLabelName(97750,"根据设置的小数位精确度,返回对数值四舍五入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,针对小数点后的数据进行四舍五入;如果小数位精确度等于 0,返回最接近数值的整数;如果小数位精确度为负整数,针对小数点前的数据进行四舍五入,被舍掉的数据用0占位。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。
示例:ROUND(123.456,2),ROUND(123.456,0),ROUND(123.456,-2)
结果:依次为123.46,123,100")); - funcMap.put("ROUNDUP",SystemEnv.getHtmlLabelName(97751,"根据设置的小数位精确度,返回对数值向上舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向上舍入到指定的小数位。如果小数位精确度等于 0,则向上舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向上进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。示例:ROUNDDOWN(76.9,0)结果:77")); - funcMap.put("ROUNDDOWN",SystemEnv.getHtmlLabelName(97752,"根据设置的小数位精确度,返回对数值向下舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向下舍入到指定的小数位。如果小数位精确度等于 0,则向下舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向下进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。
示例:ROUNDDOWN(76.9,0)
结果:76")); - funcMap.put("AGGREGATION",SystemEnv.getHtmlLabelName(97753,"将一组数据进行统计计算,支持最大值(MAX)、最小值(MIN)、平均值(AVG)。示例:AGGREGATION(1 , 2,3,'AVG'),结果:2")); - funcMap.put("MOD",SystemEnv.getHtmlLabelName(97754,"将两个参数进行除法运算然后得出余数返回。示例:MOD( 7 , 3 ),结果:1")); - funcMap.put("TRUNC",SystemEnv.getHtmlLabelName(97755,"将小数点格式化成指定位数。示例:TRUNC( 2.123 , 2 ),结果:2.12")); - funcMap.put("ISINT",SystemEnv.getHtmlLabelName(0,"判断字符内容是否是整数。示例:ISINT( 2.123 ),结果:false")); - funcMap.put("ISNUMBER",SystemEnv.getHtmlLabelName(0,"判断字符内容是否是数字。示例:ISNUMBER('2.123'),结果:true")); + //文本函数 + funcMap.put("CONCAT", SalaryI18nUtil.getI18nLabel(97730, "可用于连接多个任意类型的文本、日期、数字变量或常量。示例:
CONCAT({总价}/10000, '万元')")); + funcMap.put("TEXT", SalaryI18nUtil.getI18nLabel(97731, "将变量转为文本。示例:
TEXT({当前数据.性别}) 结果: '男'")); + funcMap.put("VALUE", SalaryI18nUtil.getI18nLabel(97732, "将文本转为数字。示例:
VALUE('23') 结果: 23")); + funcMap.put("LEN", SalaryI18nUtil.getI18nLabel(97733, "返回文本的长度,中文、英文都算1个字符。示例:
LEN('大家好dajiahao') 结果: 12")); + funcMap.put("SEARCH", SalaryI18nUtil.getI18nLabel(97734, "在指定文本中查找关键字,返回第一次出现关键字的字符位置,文本的第一个字记为1。未找到,返回0。搜索开始位置,表示从文本的第几个字符开始搜索,默认为1。示例:
SEARCH('大家', '大家好大家好', 3) 结果: 4")); + funcMap.put("REPLACE", SalaryI18nUtil.getI18nLabel(97735, "在原文本中,从替换位置开始,往后数指定的替换字符数,将这段文本替换为新文本。示例:
REPLACE('大家好大家好', 2, 3, 'dajia') 结果: '大dajia家好'")); + funcMap.put("REPT", SalaryI18nUtil.getI18nLabel(97736, "将文本重复指定次数。示例:
REPT('大家', 2) 结果: '大家大家'")); + funcMap.put("PAD", SalaryI18nUtil.getI18nLabel(97737, "将原文本填充到指定长度,如果文本长度大于设置的长度,则不做任何操作。填充位置可用参数:'LEFT'、'RIGHT'。示例:
PAD('你好', 4, '你', 'LEFT') 结果: '你你你好'")); + funcMap.put("TRIM", SalaryI18nUtil.getI18nLabel(97738, "删除文本首尾的空格。示例:
TRIM(' 大家好 ') 结果: '大家好'")); + funcMap.put("LEFT", SalaryI18nUtil.getI18nLabel(97739, "从文本左侧开始,返回指定字符数的文字。示例:
LEFT('大家好', 2) 结果: '大家'")); + funcMap.put("RIGHT", SalaryI18nUtil.getI18nLabel(97740, "从文本右侧开始,返回指定字符数的文字。示例:
RIGHT('大家好', 2) 结果: '家好'")); + funcMap.put("MID", SalaryI18nUtil.getI18nLabel(97741, "从文本指定位置之后开始,返回指定字符数的文字。示例:
MID('大家好', 2, 1) 结果: '家'")); + funcMap.put("ISEMPTY", SalaryI18nUtil.getI18nLabel(97742, "变量为空或未填写,则返回真。示例:
ISEMPTY({员工表.电话})")); + funcMap.put("IDCARD", SalaryI18nUtil.getI18nLabel(97743, "从身份证号码中获取相关信息,比如:生日(BD)、年龄(AGE)、籍贯(NA)、性别(GENDER)。示例:
IDCARD( ‘43070319980706334X’ , ‘BD’ ) 结果: '1998-07-06'")); + funcMap.put("SCORE", SalaryI18nUtil.getI18nLabel(97744, "获取选项型控件(单选框、复选框、下拉菜单)分数。示例:SCORE({当前数据.单选框}) 结果:选项分数
注:未设置选项分数时,结果为0")); + funcMap.put("SUBSTRING", SalaryI18nUtil.getI18nLabel(97745, "字符截取函数,用于按起始位置截取字符。
示例:SUBSTRING('abcdefg',2,3)
结果:bc")); + funcMap.put("SUBSTITUE", SalaryI18nUtil.getI18nLabel(97746, "字符查找替换函数,替换字符中的所有关键词为新字符。
示例:SUBSTITUE('泛微移动办公','泛微','eteams')
结果:eteams移动办公")); + funcMap.put("LOWER", SalaryI18nUtil.getI18nLabel(97747, "将字符中的字母转为小写。
示例:LOWER('abc')
结果:ABC")); + funcMap.put("UPPER", SalaryI18nUtil.getI18nLabel(97748, "将字符中的字母转为大写。
示例:LOWER('ABC')
结果:abc")); + funcMap.put("EXACT", SalaryI18nUtil.getI18nLabel(97749, "比较两个字符是否相等,区分字母的大小写。
示例:EXACT('泛微Eteams','泛微eteams')
结果:false")); + funcMap.put("ISSTRING", SalaryI18nUtil.getI18nLabel(0, "判断是否是字符。
示例:ISSTRING('泛微Eteams')
结果:true")); - //查找函数 - funcMap.put("CHOOSE",SystemEnv.getHtmlLabelName(97756,"根据条件获取指定数据源中的全部数据。数据源支持选表单、表单中的字段。
示例:想知道税表中,收入大于15000的数值
CHOOSE({税表}, {税表.收入}>15000)
结果:返回税表中收入大于15000的集合")); - funcMap.put("MATCH",SystemEnv.getHtmlLabelName(97757,"将指定数值在指定数组区域中的位置返回。若数组中无指定值,返回null。
示例:MATCH(15000, [1000, 15000, 2000])
结果:1")); - funcMap.put("VLOOKUPS", SystemEnv.getHtmlLabelName(97758,"按列查找,返回所需值。常用于薪酬模块。根据条件获取查询参数所在列的返回参数的值。返回参数可填写多个,用英文逗号隔开。若查询不到返回null。
示例:VLOOKUPS({税表},{税表.收入},AND({税表.收入}>{税表.应纳税所得额下限},{税表.收入}<{税表.应纳税所得额上限}),[{税表.税率},{税表.速算扣除数}])
结果:按列查找返回税表中收入所在的收入区间所对应的税率和速算扣除数的数值")); + //数学函数 + funcMap.put("ROUND", SalaryI18nUtil.getI18nLabel(97750, "根据设置的小数位精确度,返回对数值四舍五入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,针对小数点后的数据进行四舍五入;如果小数位精确度等于 0,返回最接近数值的整数;如果小数位精确度为负整数,针对小数点前的数据进行四舍五入,被舍掉的数据用0占位。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。
示例:ROUND(123.456,2),ROUND(123.456,0),ROUND(123.456,-2)
结果:依次为123.46,123,100")); + funcMap.put("ROUNDUP", SalaryI18nUtil.getI18nLabel(97751, "根据设置的小数位精确度,返回对数值向上舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向上舍入到指定的小数位。如果小数位精确度等于 0,则向上舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向上进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。示例:ROUNDDOWN(76.9,0)结果:77")); + funcMap.put("ROUNDDOWN", SalaryI18nUtil.getI18nLabel(97752, "根据设置的小数位精确度,返回对数值向下舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向下舍入到指定的小数位。如果小数位精确度等于 0,则向下舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向下进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。
示例:ROUNDDOWN(76.9,0)
结果:76")); + funcMap.put("AGGREGATION", SalaryI18nUtil.getI18nLabel(97753, "将一组数据进行统计计算,支持最大值(MAX)、最小值(MIN)、平均值(AVG)。示例:AGGREGATION(1 , 2,3,'AVG'),结果:2")); + funcMap.put("MOD", SalaryI18nUtil.getI18nLabel(97754, "将两个参数进行除法运算然后得出余数返回。示例:MOD( 7 , 3 ),结果:1")); + funcMap.put("TRUNC", SalaryI18nUtil.getI18nLabel(97755, "将小数点格式化成指定位数。示例:TRUNC( 2.123 , 2 ),结果:2.12")); + funcMap.put("ISINT", SalaryI18nUtil.getI18nLabel(0, "判断字符内容是否是整数。示例:ISINT( 2.123 ),结果:false")); + funcMap.put("ISNUMBER", SalaryI18nUtil.getI18nLabel(0, "判断字符内容是否是数字。示例:ISNUMBER('2.123'),结果:true")); - //数据库函数 - funcMap.put("GETHRMLOGINID", SystemEnv.getHtmlLabelName(100808, "获取指定人员系统账号。
示例:GETHRMLOGINID({表单.张三})
结果:zhangsan@qq.com")); - funcMap.put("GETHRMWORKCODE", SystemEnv.getHtmlLabelName(100810, "获取指定人员编号。
示例:GETHRMWORKCODE({表单.张三})
结果:A001")); - funcMap.put("GETHRMMANAGER", SystemEnv.getHtmlLabelName(100812, "获取指定人员直接上级。
示例:GETHRMMANAGER({表单.张三})
结果:返回张三的直接上级")); - funcMap.put("GETHRMALLMANAGER", SystemEnv.getHtmlLabelName(100814, "获取指定人员所有上级。
示例:GETHRMMANAGER({表单.张三})
结果:返回张三的所有上级形成的数组")); - funcMap.put("GETHRMDEPARTMENT", SystemEnv.getHtmlLabelName(100816, "获取指定人员部门。
示例:GETHRMDEPARTMENT({表单.张三})
结果:返回张三的部门")); - funcMap.put("GETHRMSUBCOMPANY", SystemEnv.getHtmlLabelName(100818, "获取指定人员分部。
示例:GETHRMSUBCOMPANY({表单.张三})
结果:返回张三的分部")); - funcMap.put("GETDEPARTMENTNAME", SystemEnv.getHtmlLabelName(100820, "获取指定部门名称。
示例:GETDEPARTMENTNAME({表单.A部门})
结果:A部门")); - funcMap.put("GETDEPARTMENTCODE", SystemEnv.getHtmlLabelName(100822, "获取指定部门编号。
示例:GETDEPARTMENTCODE({表单.A部门})
结果:A001")); - funcMap.put("GETSUPERDEPARTMENT", SystemEnv.getHtmlLabelName(100824, "获取指定部门直接上级部门。
示例:GETDEPARTMENTCODE({表单.A部门})
结果:A部门的直接上级部门")); - funcMap.put("GETALLSUPERDEPARTMENT", SystemEnv.getHtmlLabelName(100826, "获取指定部门所有上级部门。
示例:GETALLSUPERDEPARTMENT({表单.A部门})
结果:A部门的所有上级部门形成的数组")); - funcMap.put("GETSUBCOMPANYNAME", SystemEnv.getHtmlLabelName(100828, "获取指定分部名称。
示例:GETSUBCOMPANYNAME({表单.A分部})
结果:A分部")); - funcMap.put("GETSUBCOMPANYCODE", SystemEnv.getHtmlLabelName(100830, "获取指定分部编号。
示例:GETSUBCOMPANYCODE({表单.A分部})
结果:B001")); - funcMap.put("GETSUPERSUBCOMPANY", SystemEnv.getHtmlLabelName(100832, "获取指定分部直接上级分部。
示例:GETSUPERSUBCOMPANY({表单.A分部})
结果:A分部的直接上级分部")); - funcMap.put("GETALLSUPERSUBCOMPANY", SystemEnv.getHtmlLabelName(100834, "获取指定分部所有上级分部。
示例:GETALLSUPERSUBCOMPANY({表单.A分部})
结果:A分部的所有上级分部形成的数组")); - funcMap.put("GETHRMNAME", SystemEnv.getHtmlLabelName(100834, "获取指定人员的姓名。
示例:GETHRMNAME({U:张三})
结果:张三")); - funcMap.put("GETHRMMOBILE", SystemEnv.getHtmlLabelName(100834, "获取指定人员的手机号码。
示例:GETHRMMOBILE({U:张三})
结果:13123232323")); + //查找函数 + funcMap.put("CHOOSE", SalaryI18nUtil.getI18nLabel(97756, "根据条件获取指定数据源中的全部数据。数据源支持选表单、表单中的字段。
示例:想知道税表中,收入大于15000的数值
CHOOSE({税表}, {税表.收入}>15000)
结果:返回税表中收入大于15000的集合")); + funcMap.put("MATCH", SalaryI18nUtil.getI18nLabel(97757, "将指定数值在指定数组区域中的位置返回。若数组中无指定值,返回null。
示例:MATCH(15000, [1000, 15000, 2000])
结果:1")); + funcMap.put("VLOOKUPS", SalaryI18nUtil.getI18nLabel(97758, "按列查找,返回所需值。常用于薪酬模块。根据条件获取查询参数所在列的返回参数的值。返回参数可填写多个,用英文逗号隔开。若查询不到返回null。
示例:VLOOKUPS({税表},{税表.收入},AND({税表.收入}>{税表.应纳税所得额下限},{税表.收入}<{税表.应纳税所得额上限}),[{税表.税率},{税表.速算扣除数}])
结果:按列查找返回税表中收入所在的收入区间所对应的税率和速算扣除数的数值")); - //财务函数 - funcMap.put("GETMONEY", SystemEnv.getHtmlLabelName(0, "将金额转换成中文金额大写。
示例:GETMONEY({1234})
结果:壹仟贰佰叁拾肆元整")); + //数据库函数 + funcMap.put("GETHRMLOGINID", SalaryI18nUtil.getI18nLabel(100808, "获取指定人员系统账号。
示例:GETHRMLOGINID({表单.张三})
结果:zhangsan@qq.com")); + funcMap.put("GETHRMWORKCODE", SalaryI18nUtil.getI18nLabel(100810, "获取指定人员编号。
示例:GETHRMWORKCODE({表单.张三})
结果:A001")); + funcMap.put("GETHRMMANAGER", SalaryI18nUtil.getI18nLabel(100812, "获取指定人员直接上级。
示例:GETHRMMANAGER({表单.张三})
结果:返回张三的直接上级")); + funcMap.put("GETHRMALLMANAGER", SalaryI18nUtil.getI18nLabel(100814, "获取指定人员所有上级。
示例:GETHRMMANAGER({表单.张三})
结果:返回张三的所有上级形成的数组")); + funcMap.put("GETHRMDEPARTMENT", SalaryI18nUtil.getI18nLabel(100816, "获取指定人员部门。
示例:GETHRMDEPARTMENT({表单.张三})
结果:返回张三的部门")); + funcMap.put("GETHRMSUBCOMPANY", SalaryI18nUtil.getI18nLabel(100818, "获取指定人员分部。
示例:GETHRMSUBCOMPANY({表单.张三})
结果:返回张三的分部")); + funcMap.put("GETDEPARTMENTNAME", SalaryI18nUtil.getI18nLabel(100820, "获取指定部门名称。
示例:GETDEPARTMENTNAME({表单.A部门})
结果:A部门")); + funcMap.put("GETDEPARTMENTCODE", SalaryI18nUtil.getI18nLabel(100822, "获取指定部门编号。
示例:GETDEPARTMENTCODE({表单.A部门})
结果:A001")); + funcMap.put("GETSUPERDEPARTMENT", SalaryI18nUtil.getI18nLabel(100824, "获取指定部门直接上级部门。
示例:GETDEPARTMENTCODE({表单.A部门})
结果:A部门的直接上级部门")); + funcMap.put("GETALLSUPERDEPARTMENT", SalaryI18nUtil.getI18nLabel(100826, "获取指定部门所有上级部门。
示例:GETALLSUPERDEPARTMENT({表单.A部门})
结果:A部门的所有上级部门形成的数组")); + funcMap.put("GETSUBCOMPANYNAME", SalaryI18nUtil.getI18nLabel(100828, "获取指定分部名称。
示例:GETSUBCOMPANYNAME({表单.A分部})
结果:A分部")); + funcMap.put("GETSUBCOMPANYCODE", SalaryI18nUtil.getI18nLabel(100830, "获取指定分部编号。
示例:GETSUBCOMPANYCODE({表单.A分部})
结果:B001")); + funcMap.put("GETSUPERSUBCOMPANY", SalaryI18nUtil.getI18nLabel(100832, "获取指定分部直接上级分部。
示例:GETSUPERSUBCOMPANY({表单.A分部})
结果:A分部的直接上级分部")); + funcMap.put("GETALLSUPERSUBCOMPANY", SalaryI18nUtil.getI18nLabel(100834, "获取指定分部所有上级分部。
示例:GETALLSUPERSUBCOMPANY({表单.A分部})
结果:A分部的所有上级分部形成的数组")); + funcMap.put("GETHRMNAME", SalaryI18nUtil.getI18nLabel(100834, "获取指定人员的姓名。
示例:GETHRMNAME({U:张三})
结果:张三")); + funcMap.put("GETHRMMOBILE", SalaryI18nUtil.getI18nLabel(100834, "获取指定人员的手机号码。
示例:GETHRMMOBILE({U:张三})
结果:13123232323")); - } - public String get(String key){ - if(funcMap.size()>0){ + //财务函数 + funcMap.put("GETMONEY", SalaryI18nUtil.getI18nLabel(0, "将金额转换成中文金额大写。
示例:GETMONEY({1234})
结果:壹仟贰佰叁拾肆元整")); + + } + + public String get(String key) { + if (funcMap.size() > 0) { // logger.info("描述数据存在:"+funcMap.size()); - }else { - logger.info("初始化函数描述数据"); - initData(); - } + } else { + logger.info("初始化函数描述数据"); + initData(); + } - return funcMap.get(key); - } + return funcMap.get(key); + } } diff --git a/src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java b/src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java index 4a06cc07e..7e9c14289 100644 --- a/src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java +++ b/src/com/engine/salary/formlua/entity/parameter/ThreadLocalData.java @@ -1,7 +1,7 @@ package com.engine.salary.formlua.entity.parameter; -import com.weaver.common.form.metadata.ModuleSource; -import com.weaver.teams.domain.user.SimpleEmployee; +import com.engine.salary.entity.datacollection.DataCollectionEmployee; +import org.mozilla.javascript.commonjs.module.provider.ModuleSource; import java.util.Iterator; import java.util.Map; @@ -11,7 +11,7 @@ public class ThreadLocalData { private Map expressContext; private ModuleSource moduleSource; - private SimpleEmployee employee; + private DataCollectionEmployee employee; public ModuleSource getModuleSource() { return moduleSource; @@ -21,11 +21,11 @@ public class ThreadLocalData { this.moduleSource = moduleSource; } - public SimpleEmployee getEmployee() { + public DataCollectionEmployee getEmployee() { return employee; } - public void setEmployee(SimpleEmployee employee) { + public void setEmployee(DataCollectionEmployee employee) { this.employee = employee; } diff --git a/src/com/engine/salary/formlua/func/date/DateTimeServiceImpl.java b/src/com/engine/salary/formlua/func/date/DateTimeServiceImpl.java index 150606a81..fa6bbd7bc 100644 --- a/src/com/engine/salary/formlua/func/date/DateTimeServiceImpl.java +++ b/src/com/engine/salary/formlua/func/date/DateTimeServiceImpl.java @@ -685,7 +685,7 @@ public class DateTimeServiceImpl implements DateTimeService { // Object employeeObj = objects[2]; // String empIdStr = employeeObj != null ? ((DataType) employeeObj).getContent() + "" : null; // -// SimpleEmployee currEmp = employeeObj != null ? ((DataType) employeeObj).getEmployee() : null; +// DataCollectionEmployee currEmp = employeeObj != null ? ((DataType) employeeObj).getEmployee() : null; // String tenantKey = currEmp != null ? currEmp.getTenantKey() : null; // // if (ExcelParamUtil.checkIsNull(startDate, endDate, empIdStr, ExcelParamUtil.CHECKLEVEL_STRING)) { diff --git a/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java b/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java index 18031fbb7..bbdc37dec 100644 --- a/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java +++ b/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java @@ -6,7 +6,7 @@ import com.weaver.excel.formula.entity.parameter.DataType; import com.weaver.excel.formula.entity.parameter.DateAndString; import com.weaver.excel.formula.entity.parameter.FuncNames; import com.weaver.excel.formula.util.*; -import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.domain.user.DataCollectionEmployee; import com.weaver.teams.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -698,7 +698,7 @@ public class DateTimeTestServiceImpl implements DateTimeService { if(!IgnoreParamFilter.isEmployee(employeeObj)) throw new RuntimeException(func+"函数第三个参数必须是人员参数"); String empIdStr = employeeObj != null ? ((DataType)employeeObj).getContent()+"" : null; - SimpleEmployee currEmp = employeeObj != null ? ((DataType)employeeObj).getEmployee() : null; + DataCollectionEmployee currEmp = employeeObj != null ? ((DataType)employeeObj).getEmployee() : null; String tenantKey = currEmp != null ? currEmp.getTenantKey() : null; if(ExcelParamUtil.checkIsNull(startDate, endDate, empIdStr, ExcelParamUtil.CHECKLEVEL_STRING)){ diff --git a/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java b/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java index 347ad130e..7164fe9fd 100644 --- a/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java +++ b/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java @@ -10,7 +10,7 @@ import com.weaver.excel.formula.entity.parameter.standard.FormulaFilterData; import com.weaver.excel.formula.util.ErrorUtil; import com.weaver.excel.formula.util.ExcelParamUtil; import com.weaver.excel.formula.util.IgnoreParamFilter; -import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.domain.user.DataCollectionEmployee; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.compress.utils.Lists; import org.apache.commons.lang.ArrayUtils; @@ -71,7 +71,7 @@ public class FindFuncsServiceImpl implements FindFuncsService{ Long formId = formObj.getFormId(); List filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList(): Lists.newArrayList(); - SimpleEmployee user = formObj.getEmployee(); + DataCollectionEmployee user = formObj.getEmployee(); Object[] params = {formId, filterDatas, user}; return excelDubboInvoker.invokeCommonDubbo(DataType.class,formObj.getModule()+"", RpcMethod.choose, params); @@ -145,7 +145,7 @@ public class FindFuncsServiceImpl implements FindFuncsService{ Long formId = formObj.getFormId(); List filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList() : Lists.newArrayList(); - SimpleEmployee user = formObj.getEmployee(); + DataCollectionEmployee user = formObj.getEmployee(); Object[] params = {formId+"", filterDatas, fieldIds, null,user}; diff --git a/src/com/engine/salary/formlua/util/ExcelParamUtil.java b/src/com/engine/salary/formlua/util/ExcelParamUtil.java index 10b20219c..8d576c7b5 100644 --- a/src/com/engine/salary/formlua/util/ExcelParamUtil.java +++ b/src/com/engine/salary/formlua/util/ExcelParamUtil.java @@ -1,16 +1,16 @@ package com.engine.salary.formlua.util; import com.alibaba.fastjson.JSONObject; +import com.engine.salary.entity.datacollection.DataCollectionEmployee; +import com.engine.salary.entity.salaryformula.po.FormulaVar; import com.engine.salary.formlua.entity.parameter.DataType; import com.weaver.common.form.component.base.Component; import com.weaver.common.form.component.base.ComponentType; import com.weaver.common.form.conditionrule.FixedField; import com.weaver.common.form.metadata.ModuleSource; -import com.weaver.excel.formula.api.entity.FormulaVar; import com.weaver.excel.formula.entity.parameter.*; import com.weaver.excel.formula.entity.standard.execute.FixFieldType; -import com.weaver.teams.domain.user.SimpleEmployee; -import com.weaver.teams.util.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,1081 +24,1107 @@ import java.util.regex.Pattern; public class ExcelParamUtil { - protected static final Logger logger = LoggerFactory.getLogger(ExcelParamUtil.class); - public final static String[] NUMBERFIELD=new String[]{"NumberComponent","Money","Monitor","Raty","ProgressBar", FixFieldType.Num.toString(),DataType.NUMBER}; - public final static String[] DATEFIELD=new String[]{"DateComponent","DateInterval","TimeComponent",DataType.DATE}; - public final static String[] TEXTFIELD=new String[]{"Text","TextArea","Email","Phone","Mobile","IDCard","FileComponent","SerialNumber","PositionComponent","Paragraph",FixFieldType.Text.toString(),DataType.STRING}; - public final static String[] SELECTFIELD=new String[]{"ImageComponent","RadioBox","CheckBox","Select","ComboSelect","ImageRadioBox","ImageCheckBox","TreeSelect","MatrixComponent",FixFieldType.Select.toString(),"option","employee","department","subcompany","operator",DataType.OPTION}; - public final static String[] DATASOURCEFIELD=new String[]{"Employee","Department","Mainline","Task","Document","Workflow","AgendaComponent","FormComponent","CustomerComponent","ClueComponent","Subcompany", - "OrderComponent","ContactComponent","ChanceComponent","ProductionComponent","ContractComponent","ActivityComponent","WorkreportComponent","CompetitorComponent","KpiFlowComponent","Ebuilder","QuoteComponent","AttendComponent","DataSource", - FixFieldType.Department.toString(),FixFieldType.Employee.toString()}; + protected static final Logger logger = LoggerFactory.getLogger(ExcelParamUtil.class); + public final static String[] NUMBERFIELD = new String[]{"NumberComponent", "Money", "Monitor", "Raty", "ProgressBar", FixFieldType.Num.toString(), DataType.NUMBER}; + public final static String[] DATEFIELD = new String[]{"DateComponent", "DateInterval", "TimeComponent", DataType.DATE}; + public final static String[] TEXTFIELD = new String[]{"Text", "TextArea", "Email", "Phone", "Mobile", "IDCard", "FileComponent", "SerialNumber", "PositionComponent", "Paragraph", FixFieldType.Text.toString(), DataType.STRING}; + public final static String[] SELECTFIELD = new String[]{"ImageComponent", "RadioBox", "CheckBox", "Select", "ComboSelect", "ImageRadioBox", "ImageCheckBox", "TreeSelect", "MatrixComponent", FixFieldType.Select.toString(), "option", "employee", "department", "subcompany", "operator", DataType.OPTION}; + public final static String[] DATASOURCEFIELD = new String[]{"Employee", "Department", "Mainline", "Task", "Document", "Workflow", "AgendaComponent", "FormComponent", "CustomerComponent", "ClueComponent", "Subcompany", + "OrderComponent", "ContactComponent", "ChanceComponent", "ProductionComponent", "ContractComponent", "ActivityComponent", "WorkreportComponent", "CompetitorComponent", "KpiFlowComponent", "Ebuilder", "QuoteComponent", "AttendComponent", "DataSource", + FixFieldType.Department.toString(), FixFieldType.Employee.toString()}; - private static String[] funcArray= IllegalList.getInstance().getNameIllegalArray(); - private final static String[] NUMBERCOMPONENTS=new String[]{"NumberComponent","Money","Raty","ProgressBar","Monitor"}; - private static String[] numberTypes=new String[]{"Integer","integer","Long","Double","Float","float","int","double","long","float","bigdecimal","BigDecimal"}; - public final static String CHECKLEVEL_NULL="NULL"; - public final static String CHECKLEVEL_STRING="STRING"; + private static String[] funcArray = IllegalList.getInstance().getNameIllegalArray(); + private final static String[] NUMBERCOMPONENTS = new String[]{"NumberComponent", "Money", "Raty", "ProgressBar", "Monitor"}; + private static String[] numberTypes = new String[]{"Integer", "integer", "Long", "Double", "Float", "float", "int", "double", "long", "float", "bigdecimal", "BigDecimal"}; + public final static String CHECKLEVEL_NULL = "NULL"; + public final static String CHECKLEVEL_STRING = "STRING"; - /** - * 自定义脚本生成调用的逻辑 - * @param funcString - * @return - */ - public static String initFunc(String funcString){ - if(StringUtils.isEmpty(funcString)){ - return funcString; - } - int startIdx=funcString.indexOf("("); - int endIdx=funcString.indexOf(")"); - int funcIdx=funcString.indexOf("function"); - if(startIdx==-1 ){ - throw new RuntimeException("【语法错误】缺少左括号("); - }else if(endIdx == -1){ - throw new RuntimeException("【语法错误】缺少右括号)"); - }else if(funcIdx ==-1){ - throw new RuntimeException("【语法错误】缺少function关键字"); - } - String funcName=funcString.substring(funcIdx+8,startIdx).trim(); - String paramStr=funcString.substring(startIdx+1,endIdx); - if(paramStr.trim().equalsIgnoreCase("")){ - funcString+=funcName+"();"; - return funcString; - } - String[] paramStrArray=paramStr.split(","); - logger.info("总参数个数:"+paramStrArray.length); - String paramNames=""; - for (int i=0;i numberList=Arrays.asList(NUMBERFIELD); - List textList=Arrays.asList(TEXTFIELD); - List selectList=Arrays.asList(SELECTFIELD); - List dataSourceList=Arrays.asList(DATASOURCEFIELD); - List dateList=Arrays.asList(DATEFIELD); - if(numberList.contains(compnentKey)){ - return DataType.NUMBER; - }else if(textList.contains(compnentKey)){ - return DataType.STRING; - }else if(dateList.contains(compnentKey)){ - return DataType.STRING; - }else if(selectList.contains(compnentKey)){ - return DataType.OPTION; - }else if(dataSourceList.contains(compnentKey)){ - return DataType.OPTION; - }else { - return ""; - } - } + /** + * 判断控件所属的数据类型 + * + * @param compnentKey FormField中的ComponentKey + * @return + */ + public static String findType(String compnentKey) { + List numberList = Arrays.asList(NUMBERFIELD); + List textList = Arrays.asList(TEXTFIELD); + List selectList = Arrays.asList(SELECTFIELD); + List dataSourceList = Arrays.asList(DATASOURCEFIELD); + List dateList = Arrays.asList(DATEFIELD); + if (numberList.contains(compnentKey)) { + return DataType.NUMBER; + } else if (textList.contains(compnentKey)) { + return DataType.STRING; + } else if (dateList.contains(compnentKey)) { + return DataType.STRING; + } else if (selectList.contains(compnentKey)) { + return DataType.OPTION; + } else if (dataSourceList.contains(compnentKey)) { + return DataType.OPTION; + } else { + return ""; + } + } - public static String findDataType(String compnentKey){ - List numberList=Arrays.asList(NUMBERFIELD); - List textList=Arrays.asList(TEXTFIELD); - List selectList=Arrays.asList(SELECTFIELD); - List dataSourceList=Arrays.asList(DATASOURCEFIELD); - List dateList=Arrays.asList(DATEFIELD); - if(numberList.contains(compnentKey)){ - return DataType.NUMBER; - }else if(textList.contains(compnentKey)){ - return DataType.STRING; - }else if(dateList.contains(compnentKey)){ - return DataType.STRING; - }else if(selectList.contains(compnentKey)){ - return DataType.OPTION; - }else if(dataSourceList.contains(compnentKey)){ - return DataType.OPTION; - }else { - return DataType.STRING; - } - } - public static String findTestDataType(String compnentKey){ - List numberList=Arrays.asList(NUMBERFIELD); - List textList=Arrays.asList(TEXTFIELD); - List selectList=Arrays.asList(SELECTFIELD); - List dataSourceList=Arrays.asList(DATASOURCEFIELD); - List dateList=Arrays.asList(DATEFIELD); - if(numberList.contains(compnentKey)){ - return DataType.NUMBER; - }else if(textList.contains(compnentKey)){ - return DataType.STRING; - }else if(dateList.contains(compnentKey)){ - return DataType.DATE; - }else if(selectList.contains(compnentKey)){ - return DataType.OPTION; - }else if(dataSourceList.contains(compnentKey)){ - return DataType.OPTION; - }else { - return DataType.STRING; - } - } - /** - * 判断变量是否为空 - * @param objects - * @return - */ - public static boolean checkIsNull(Object... objects){ - String checkLevel=objects[objects.length-1].toString(); - List formulavars=new ArrayList<>(); - for (int i=0;i numberList = Arrays.asList(NUMBERFIELD); + List textList = Arrays.asList(TEXTFIELD); + List selectList = Arrays.asList(SELECTFIELD); + List dataSourceList = Arrays.asList(DATASOURCEFIELD); + List dateList = Arrays.asList(DATEFIELD); + if (numberList.contains(compnentKey)) { + return DataType.NUMBER; + } else if (textList.contains(compnentKey)) { + return DataType.STRING; + } else if (dateList.contains(compnentKey)) { + return DataType.STRING; + } else if (selectList.contains(compnentKey)) { + return DataType.OPTION; + } else if (dataSourceList.contains(compnentKey)) { + return DataType.OPTION; + } else { + return DataType.STRING; + } + } - for (Object object:formulavars){ - switch (checkLevel){ - case CHECKLEVEL_NULL: - if(null==object){ - return true; - } - break; - case CHECKLEVEL_STRING: - if(null==object){ - return true; - } - if(object instanceof String || object instanceof Character){ - if(object.toString().trim().equals("")){ - return true; - } - } - break; - } + public static String findTestDataType(String compnentKey) { + List numberList = Arrays.asList(NUMBERFIELD); + List textList = Arrays.asList(TEXTFIELD); + List selectList = Arrays.asList(SELECTFIELD); + List dataSourceList = Arrays.asList(DATASOURCEFIELD); + List dateList = Arrays.asList(DATEFIELD); + if (numberList.contains(compnentKey)) { + return DataType.NUMBER; + } else if (textList.contains(compnentKey)) { + return DataType.STRING; + } else if (dateList.contains(compnentKey)) { + return DataType.DATE; + } else if (selectList.contains(compnentKey)) { + return DataType.OPTION; + } else if (dataSourceList.contains(compnentKey)) { + return DataType.OPTION; + } else { + return DataType.STRING; + } + } - } - return false; - } + /** + * 判断变量是否为空 + * + * @param objects + * @return + */ + public static boolean checkIsNull(Object... objects) { + String checkLevel = objects[objects.length - 1].toString(); + List formulavars = new ArrayList<>(); + for (int i = 0; i < objects.length; i++) { + Object object = objects[i]; + if (object instanceof Array) { + Object[] subArray = (Object[]) object; + for (int j = 0; j < subArray.length; j++) { + formulavars.add(subArray[j]); + } + } else { + formulavars.add(object); + } + } - /** - * 替换所有中文参数为Key - * @param sql - * @param replaceArray - * @return - */ - public static String replaceAllParam(String sql,String[] replaceArray){ - String partternStr="\\{.+?\\}{1}?"; - Pattern pt=Pattern.compile(partternStr); - Matcher matcher=pt.matcher(sql); + for (Object object : formulavars) { + switch (checkLevel) { + case CHECKLEVEL_NULL: + if (null == object) { + return true; + } + break; + case CHECKLEVEL_STRING: + if (null == object) { + return true; + } + if (object instanceof String || object instanceof Character) { + if (object.toString().trim().equals("")) { + return true; + } + } + break; + } - int loop=0; - while (matcher.find()){ - String matherString=matcher.group(); - matherString=matherString.replaceAll("(\\{|\\})",""); - String replaceStr=replaceArray[loop]; - sql=sql.replaceFirst(matherString,replaceStr); - loop++; - } - return sql; - } + } + return false; + } - /** - * 找到聚合函数的条件参数 - * @param sql - * @return - */ - public static List findAggParam(String sql){ - List list=new LinkedList<>(); - String partternStr="(COUNT|SUM|MIN|MAX|AVG){1}\\(+.+?\\)+"; - Pattern pt=Pattern.compile(partternStr); - Matcher matcher=pt.matcher(sql); - while (matcher.find()){ - String aggStr=matcher.group(); - aggStr=aggStr.replaceAll("(COUNT|SUM|MIN|MAX|AVG){1}",""); - String[] paramArray=aggStr.split(",",2); - if(paramArray.length==2){ - String cndParam=paramArray[1]; - cndParam=cndParam.substring(0,cndParam.length()-1); - list.add(cndParam); - } - } + /** + * 替换所有中文参数为Key + * + * @param sql + * @param replaceArray + * @return + */ + public static String replaceAllParam(String sql, String[] replaceArray) { + String partternStr = "\\{.+?\\}{1}?"; + Pattern pt = Pattern.compile(partternStr); + Matcher matcher = pt.matcher(sql); + + int loop = 0; + while (matcher.find()) { + String matherString = matcher.group(); + matherString = matherString.replaceAll("(\\{|\\})", ""); + String replaceStr = replaceArray[loop]; + sql = sql.replaceFirst(matherString, replaceStr); + loop++; + } + return sql; + } + + /** + * 找到聚合函数的条件参数 + * + * @param sql + * @return + */ + public static List findAggParam(String sql) { + List list = new LinkedList<>(); + String partternStr = "(COUNT|SUM|MIN|MAX|AVG){1}\\(+.+?\\)+"; + Pattern pt = Pattern.compile(partternStr); + Matcher matcher = pt.matcher(sql); + while (matcher.find()) { + String aggStr = matcher.group(); + aggStr = aggStr.replaceAll("(COUNT|SUM|MIN|MAX|AVG){1}", ""); + String[] paramArray = aggStr.split(",", 2); + if (paramArray.length == 2) { + String cndParam = paramArray[1]; + cndParam = cndParam.substring(0, cndParam.length() - 1); + list.add(cndParam); + } + } - return list; - } + return list; + } - /** - * 替换聚合函数的条件参数,一般是从规则库返回过来的条件语句 - * @param sql - * @param replaceArray - * @return - */ - public static String replaceAggParam(String sql,List replaceArray){ - String partternStr="(COUNT|SUM|MIN|MAX|AVG){1}\\(.+?\\){1}?"; - Pattern pt=Pattern.compile(partternStr); - Matcher matcher=pt.matcher(sql); - String paramPattStr="\\(.+?\\){1}?"; - Pattern ppatt=Pattern.compile(paramPattStr); - int loop=0; - while (matcher.find()){ - String matherString=matcher.group(); - String[] paramStrArray=matherString.replaceAll("(\\(|\\))","").split(","); - String newmatherString=matherString.replace(paramStrArray[1],"{"+replaceArray.get(loop)+"}"); - sql=sql.replace(matherString,newmatherString); - loop++; - } - return sql; - } + /** + * 替换聚合函数的条件参数,一般是从规则库返回过来的条件语句 + * + * @param sql + * @param replaceArray + * @return + */ + public static String replaceAggParam(String sql, List replaceArray) { + String partternStr = "(COUNT|SUM|MIN|MAX|AVG){1}\\(.+?\\){1}?"; + Pattern pt = Pattern.compile(partternStr); + Matcher matcher = pt.matcher(sql); + String paramPattStr = "\\(.+?\\){1}?"; + Pattern ppatt = Pattern.compile(paramPattStr); + int loop = 0; + while (matcher.find()) { + String matherString = matcher.group(); + String[] paramStrArray = matherString.replaceAll("(\\(|\\))", "").split(","); + String newmatherString = matherString.replace(paramStrArray[1], "{" + replaceArray.get(loop) + "}"); + sql = sql.replace(matherString, newmatherString); + loop++; + } + return sql; + } + public static void checkParamArrayDataType(List formulavars) { + for (FormulaVar formulaVar : formulavars) { + if (formulaVar.getComponentKey() != null && !formulaVar.getComponentKey().equals("")) { + String componentKey = formulaVar.getComponentKey(); + Arrays.sort(NUMBERCOMPONENTS); + int searchIdx = Arrays.binarySearch(NUMBERCOMPONENTS, componentKey); + if (searchIdx >= 0) { + formulaVar.setFieldType("Number"); + } + Arrays.sort(ReturnType.CHECK_TYPE); + if (Arrays.binarySearch(ReturnType.CHECK_TYPE, componentKey) >= 0) { + formulaVar.setFieldType("String"); + } + if (formulaVar.getOptionId() != null) { + formulaVar.setFieldType("String"); + } + } - public static void checkParamArrayDataType(List formulavars){ - for (FormulaVar formulaVar:formulavars){ - if(formulaVar.getComponentKey()!=null&&!formulaVar.getComponentKey().equals("")){ - String componentKey=formulaVar.getComponentKey(); - Arrays.sort(NUMBERCOMPONENTS); - int searchIdx=Arrays.binarySearch(NUMBERCOMPONENTS,componentKey); - if(searchIdx>=0){ - formulaVar.setFieldType("Number"); - } - Arrays.sort(ReturnType.CHECK_TYPE); - if(Arrays.binarySearch(ReturnType.CHECK_TYPE,componentKey)>=0){ - formulaVar.setFieldType("String"); - } - if(formulaVar.getOptionId()!=null){ - formulaVar.setFieldType("String"); - } - } - - } - } + } + } - /** - * 替换语句中的参数为参数列表中的Key - * @param sql - * @param formulaVars - * @return - */ - public static String replaceAllParam(String sql,List formulaVars){ - if(null==formulaVars){ - return sql; - } - //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 - String partternStr="\\{.+?\\}{1}?"; - Pattern pt=Pattern.compile(partternStr); - Matcher matcher=pt.matcher(sql); + /** + * 替换语句中的参数为参数列表中的Key + * + * @param sql + * @param formulaVars + * @return + */ + public static String replaceAllParam(String sql, List formulaVars) { + if (null == formulaVars) { + return sql; + } + //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 + String partternStr = "\\{.+?\\}{1}?"; + Pattern pt = Pattern.compile(partternStr); + Matcher matcher = pt.matcher(sql); - int loop=0; - //替换逻辑 - while (matcher.find()){ - String matherString=matcher.group(); - //替换特殊字符 - matherString=matherString.replace("{",""); - matherString=matherString.replace("}",""); - matherString=matherString.replace("(","\\("); - matherString=matherString.replace(")","\\)"); - matherString=matherString.replaceAll("\\+","\\\\+"); - matherString=matherString.replaceAll("\\-","\\\\-"); - matherString=matherString.replaceAll("\\*","\\\\*"); - matherString=matherString.replaceAll("\\/","\\\\/"); - if(formulaVars!=null&&loop") - .replace("<","<"); - return formatStr; - } + /** + * 替换参数 + * + * @param sourceString + * @return + */ + public static String replaceParam(String sourceString) { + String formatStr = sourceString.replace(">", ">") + .replace("<", "<"); + return formatStr; + } - /** - * 过滤 除了数字外的其他参数类型 - * @param param - * @return - */ - public static boolean inNumber(Object param){ - boolean r=false; - Class[] paramClasses=new Class[]{Integer.class,Double.class,Float.class,Long.class,Short.class}; - for(int i=0;i numberList=Arrays.asList(numberTypes); - if(typeAllName.equals("Character")){ - return "String"; - }else if(numberList.contains(typeAllName.toLowerCase())){ - return "Number"; - } - return typeAllName; - } + /** + * 获取参数名 + * + * @param typeAllName + * @return + */ + public static String getParamType(String typeAllName) { + int fnameIdx = typeAllName.lastIndexOf("."); + typeAllName = typeAllName.substring(fnameIdx + 1); + List numberList = Arrays.asList(numberTypes); + if (typeAllName.equals("Character")) { + return "String"; + } else if (numberList.contains(typeAllName.toLowerCase())) { + return "Number"; + } + return typeAllName; + } - /** - * 获取参数类型 - * @param - * @return - */ - public static String getParamType(Object dataType){ - if(dataType instanceof DataType){ - DataType data=(DataType)dataType; - String filedType=data.getDataType(); - filedType=filedType.toLowerCase(); + /** + * 获取参数类型 + * + * @param + * @return + */ + public static String getParamType(Object dataType) { + if (dataType instanceof DataType) { + DataType data = (DataType) dataType; + String filedType = data.getDataType(); + filedType = filedType.toLowerCase(); - switch (filedType){ - case "number": - filedType= ParamType.DOUBLE.getName(); - break; - case "string": - filedType=ParamType.STRING.getName(); - break; - case "boolean": - filedType=ParamType.BOOLEAN.getName(); - break; - case "select": - filedType=ParamType.STRING.getName(); - break; - case "text": - filedType=ParamType.STRING.getName(); - break; - case "employee": - filedType= ParamType.STRING.getName(); - break; - case "department": - filedType=ParamType.STRING.getName(); - break; - case "integer": - filedType=ParamType.DOUBLE.getName(); - break; - case "double": - filedType=ParamType.DOUBLE.getName(); - break; - case "float": - filedType=ParamType.DOUBLE.getName(); - break; - case "int": - filedType=ParamType.DOUBLE.getName(); - break; - case "long": - filedType=ParamType.DOUBLE.getName(); - break; - case "bigdecimal": - filedType=ParamType.DOUBLE.getName(); - break; + switch (filedType) { + case "number": + filedType = ParamType.DOUBLE.getName(); + break; + case "string": + filedType = ParamType.STRING.getName(); + break; + case "boolean": + filedType = ParamType.BOOLEAN.getName(); + break; + case "select": + filedType = ParamType.STRING.getName(); + break; + case "text": + filedType = ParamType.STRING.getName(); + break; + case "employee": + filedType = ParamType.STRING.getName(); + break; + case "department": + filedType = ParamType.STRING.getName(); + break; + case "integer": + filedType = ParamType.DOUBLE.getName(); + break; + case "double": + filedType = ParamType.DOUBLE.getName(); + break; + case "float": + filedType = ParamType.DOUBLE.getName(); + break; + case "int": + filedType = ParamType.DOUBLE.getName(); + break; + case "long": + filedType = ParamType.DOUBLE.getName(); + break; + case "bigdecimal": + filedType = ParamType.DOUBLE.getName(); + break; - } - return filedType; - }else { - return getParamType(dataType.getClass().getName()); - } - } + } + return filedType; + } else { + return getParamType(dataType.getClass().getName()); + } + } - /** - * 从DataType中获取值 - * @param object - * @return - */ - public static List getParamContent(Object object){ - List dataList=new ArrayList<>(); - if(object!=null){ - if(object instanceof DataType){ - DataType data=(DataType)object; - dataList.add(getDataTypeContent(data)); - return dataList; - }else if(object instanceof List){ - List sourceDataList=(List)object; - for (Object paramObj:sourceDataList){ - if(paramObj instanceof DataType){ - DataType pramDataType=(DataType)paramObj; - dataList.add(pramDataType.getContent()); - }else{ - dataList.add(paramObj); - } - } - return dataList; - }else if(object instanceof Object[]){ - Object[] sourceDataList=(Object[]) object; - for (Object paramObj:sourceDataList){ - if(paramObj instanceof DataType){ - DataType pramDataType=(DataType)paramObj; - dataList.add(pramDataType.getContent()); - }else{ - dataList.add(paramObj); - } - } - return dataList; - }else { - dataList.add(object); - return dataList; - } - } - dataList.add(object); - return dataList; - } - public static Object getDataTypeContent(DataType dataType){ - String properType=""; - Object content=null; - if(StringUtils.isNotEmpty(dataType.getComponentKey())){ - properType=dataType.getComponentKey(); - }else if(StringUtils.isNotEmpty(dataType.getDataType())){ - properType=dataType.getDataType(); - } - switch (findType(properType)){ - case DataType.NUMBER: - case DataType.STRING: - case DataType.DATE: - content=dataType.getContent(); - break; - case DataType.OPTION: - content=dataType.getContent(); - break; - } - return content; - } + /** + * 从DataType中获取值 + * + * @param object + * @return + */ + public static List getParamContent(Object object) { + List dataList = new ArrayList<>(); + if (object != null) { + if (object instanceof DataType) { + DataType data = (DataType) object; + dataList.add(getDataTypeContent(data)); + return dataList; + } else if (object instanceof List) { + List sourceDataList = (List) object; + for (Object paramObj : sourceDataList) { + if (paramObj instanceof DataType) { + DataType pramDataType = (DataType) paramObj; + dataList.add(pramDataType.getContent()); + } else { + dataList.add(paramObj); + } + } + return dataList; + } else if (object instanceof Object[]) { + Object[] sourceDataList = (Object[]) object; + for (Object paramObj : sourceDataList) { + if (paramObj instanceof DataType) { + DataType pramDataType = (DataType) paramObj; + dataList.add(pramDataType.getContent()); + } else { + dataList.add(paramObj); + } + } + return dataList; + } else { + dataList.add(object); + return dataList; + } + } + dataList.add(object); + return dataList; + } - /** - * 获取JSON的content内容 - * @param object - * @return - */ - public static Object getParamContent(Object object,String funcType){ - Object result=null; - if(object instanceof DataType){ - DataType dataType=(DataType)object; - switch (dataType.getDataType()){ - case DataType.DATE: - if(dataType.getContent()==null||dataType.getContent().equals("")){ - return ""; - } - String format= DateUtil.buildFormat(dataType.getContent().toString()); - SimpleDateFormat formatter = new SimpleDateFormat(format); - try { - Date date=formatter.parse(dataType.getContent().toString()); - result=funcType.equalsIgnoreCase("string")?dataType.getContent():date.getTime(); - } catch (ParseException e) { - logger.error("err",e); - } - break; - case DataType.NUMBER: - if(null==dataType.getContent()||dataType.getContent().equals("")){ - return 0; - } - if(funcType.equalsIgnoreCase("string")){ - result=dataType.getContent(); + public static Object getDataTypeContent(DataType dataType) { + String properType = ""; + Object content = null; + if (StringUtils.isNotEmpty(dataType.getComponentKey())) { + properType = dataType.getComponentKey(); + } else if (StringUtils.isNotEmpty(dataType.getDataType())) { + properType = dataType.getDataType(); + } + switch (findType(properType)) { + case DataType.NUMBER: + case DataType.STRING: + case DataType.DATE: + content = dataType.getContent(); + break; + case DataType.OPTION: + content = dataType.getContent(); + break; + } + return content; + } - }else { - if(!RegularUtil.isNumber(dataType.getContent())){ - return 0; - } - if(dataType.getContent().toString().indexOf(".")>=0){ + /** + * 获取JSON的content内容 + * + * @param object + * @return + */ + public static Object getParamContent(Object object, String funcType) { + Object result = null; + if (object instanceof DataType) { + DataType dataType = (DataType) object; + switch (dataType.getDataType()) { + case DataType.DATE: + if (dataType.getContent() == null || dataType.getContent().equals("")) { + return ""; + } + String format = DateUtil.buildFormat(dataType.getContent().toString()); + SimpleDateFormat formatter = new SimpleDateFormat(format); + try { + Date date = formatter.parse(dataType.getContent().toString()); + result = funcType.equalsIgnoreCase("string") ? dataType.getContent() : date.getTime(); + } catch (ParseException e) { + logger.error("err", e); + } + break; + case DataType.NUMBER: + if (null == dataType.getContent() || dataType.getContent().equals("")) { + return 0; + } + if (funcType.equalsIgnoreCase("string")) { + result = dataType.getContent(); + + } else { + if (!RegularUtil.isNumber(dataType.getContent())) { + return 0; + } + if (dataType.getContent().toString().indexOf(".") >= 0) { // result=Double.parseDouble(dataType.getContent().toString()); - result=new BigDecimal(dataType.getContent().toString()); - }else if(dataType.getContent().toString().length()<=9){ - result=Integer.parseInt(dataType.getContent().toString()); - }else { - result=Long.parseLong(dataType.getContent().toString()); - } - } - break; - case DataType.STRING: - if(null==dataType.getContent()){ - result=""; - }else { - result=dataType.getContent().toString().trim(); - } + result = new BigDecimal(dataType.getContent().toString()); + } else if (dataType.getContent().toString().length() <= 9) { + result = Integer.parseInt(dataType.getContent().toString()); + } else { + result = Long.parseLong(dataType.getContent().toString()); + } + } + break; + case DataType.STRING: + if (null == dataType.getContent()) { + result = ""; + } else { + result = dataType.getContent().toString().trim(); + } - break; - case DataType.OPTION: - if(funcType.equalsIgnoreCase("string")){ - if(StringUtils.isNotEmpty(dataType.getOptionContent())){ - result=dataType.getOptionContent(); - }else { - result=""; - } + break; + case DataType.OPTION: + if (funcType.equalsIgnoreCase("string")) { + if (StringUtils.isNotEmpty(dataType.getOptionContent())) { + result = dataType.getOptionContent(); + } else { + result = ""; + } - }else { - result=dataType.getContent(); - } - break; - case DataType.BOOL: - result=dataType.getContent(); - break; - default: - if(dataType.getContent()==null){ - return ""; - } - result=dataType.getContent().toString(); - break; - } - }else if(object instanceof Date){ - Date date=(Date)object; - result=date.getTime(); - }else { - if(funcType.equalsIgnoreCase(DataType.BOOL)){ - result=object==null?false:object; - }else if(object instanceof Boolean){ - result=object; - }else if(object instanceof Integer || object instanceof Double || object instanceof Long || object instanceof BigDecimal){ - result=object; - }else { - result=object==null?"":object+""; - } + } else { + result = dataType.getContent(); + } + break; + case DataType.BOOL: + result = dataType.getContent(); + break; + default: + if (dataType.getContent() == null) { + return ""; + } + result = dataType.getContent().toString(); + break; + } + } else if (object instanceof Date) { + Date date = (Date) object; + result = date.getTime(); + } else { + if (funcType.equalsIgnoreCase(DataType.BOOL)) { + result = object == null ? false : object; + } else if (object instanceof Boolean) { + result = object; + } else if (object instanceof Integer || object instanceof Double || object instanceof Long || object instanceof BigDecimal) { + result = object; + } else { + result = object == null ? "" : object + ""; + } - } - return result; - } + } + return result; + } - /** - * 获取参数的数据类型,从DataType中获取或者直接获取 - * @param object - * @return - */ - public static String checkParamType(Object object){ - String typeName=null; - if(object instanceof DataType){ - DataType dataType=(DataType)object; - typeName= dataType.getDataType(); - }else { - typeName= ExcelParamUtil.getParamType(object.getClass().getName()); - } - return typeName; - } + /** + * 获取参数的数据类型,从DataType中获取或者直接获取 + * + * @param object + * @return + */ + public static String checkParamType(Object object) { + String typeName = null; + if (object instanceof DataType) { + DataType dataType = (DataType) object; + typeName = dataType.getDataType(); + } else { + typeName = ExcelParamUtil.getParamType(object.getClass().getName()); + } + return typeName; + } - /** - * 运行公式时的参数设置 - * @param formulavars - * @param expressMap - * @return - */ - public static Map buildParam(List formulavars, Map expressMap){ - checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 - for(FormulaVar formulaVar:formulavars){ - DataType dataType=new DataType(); - String key=null; - if(formulaVar.getFormId()!=null&&formulaVar.getFieldId()==null){ - key="form"+formulaVar.getFormId(); - }else if(formulaVar.getFieldId()!=null&&formulaVar.getOptionId()==null){ - String fieldId=formulaVar.getFieldId().toString(); - key="field"+fieldId; - dataType.setFieldId(fieldId); - }else if(formulaVar.getOptionId()!=null){ - key="option"+formulaVar.getOptionId(); - dataType.setContent(formulaVar.getOptionId()); - }else { - key="option"+formulaVar.getOptionId(); - } + /** + * 运行公式时的参数设置 + * + * @param formulavars + * @param expressMap + * @return + */ + public static Map buildParam(List formulavars, Map expressMap) { + checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 + for (FormulaVar formulaVar : formulavars) { + DataType dataType = new DataType(); + String key = null; + if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null) { + key = "form" + formulaVar.getFormId(); + } else if (formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { + String fieldId = formulaVar.getFieldId().toString(); + key = "field" + fieldId; + dataType.setFieldId(fieldId); + } else if (formulaVar.getOptionId() != null) { + key = "option" + formulaVar.getOptionId(); + dataType.setContent(formulaVar.getOptionId()); + } else { + key = "option" + formulaVar.getOptionId(); + } - Arrays.sort(funcArray); - int sidx= Arrays.binarySearch(funcArray,key); - if( sidx>=0 ){ - throw new RuntimeException("变量名非法"); - } - if(formulaVar.getOptionId()!=null){ - dataType.setDataType(DataType.OPTION); - } - if(expressMap.containsKey(key)){ - String newKey= ExcelParamUtil.randomNumber()+"_"+key; - expressMap.put(newKey,dataType); - formulaVar.setKey(newKey); - }else { - expressMap.put(key,dataType); - } - } + Arrays.sort(funcArray); + int sidx = Arrays.binarySearch(funcArray, key); + if (sidx >= 0) { + throw new RuntimeException("变量名非法"); + } + if (formulaVar.getOptionId() != null) { + dataType.setDataType(DataType.OPTION); + } + if (expressMap.containsKey(key)) { + String newKey = ExcelParamUtil.randomNumber() + "_" + key; + expressMap.put(newKey, dataType); + formulaVar.setKey(newKey); + } else { + expressMap.put(key, dataType); + } + } - return expressMap; - } + return expressMap; + } - /*** - * 验证函数时构建参数设置参数值 - * 把FormulaVar类型的参数封装成DataType类型参数 - * @param formulavars 入参类型 - * @param expressMap 返回Map - * @return - */ - public static Map buildLocalParam(List formulavars, Map expressMap, SimpleEmployee employee){ + /*** + * 验证函数时构建参数设置参数值 + * 把FormulaVar类型的参数封装成DataType类型参数 + * @param formulavars 入参类型 + * @param expressMap 返回Map + * @return + */ + public static Map buildLocalParam(List formulavars, Map expressMap, DataCollectionEmployee employee) { - checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 - for(FormulaVar formulaVar:formulavars){ - DataType dataType=new DataType(); - dataType.setScore(0d); - dataType.setName((null==formulaVar.getName() || formulaVar.getName().equals(""))?formulaVar.getParent():formulaVar.getName()); - dataType.setFieldId(formulaVar.getFieldId()!=null?formulaVar.getFieldId().toString():null); - String key=null; - if(formulaVar.getModule()!=null&&!formulaVar.getModule().equals("")){ - try { - dataType.setModule(formulaVar.getModule()); - } catch (IllegalArgumentException e) { - logger.error("err",e); - dataType.setModule(formulaVar.getModule()); - } - } - dataType.setFormId(formulaVar.getFormId()!=null?Long.parseLong(formulaVar.getFormId()):null); - if(formulaVar.getName()!=null&&formulaVar.getName().equals("当前操作人")){ - key=formulaVar.getKey(); - formulaVar.setContent(employee.getUserId().toString()); - dataType.setContent(formulaVar.getContent()); - dataType.setText(formulaVar.getContent()); - dataType.setDataType(DataType.OPTION); - }else{ - if(formulaVar.getFormId()!=null&&formulaVar.getFieldId()==null&&formulaVar.getOptionId()==null){ - key="form"+formulaVar.getFormId().toString(); - ThreadLocalData threadLocalData=new ThreadLocalData(); - threadLocalData.setEmployee(employee); - threadLocalData.setModuleSource(ModuleSource.biaoge); - ParamContext.get().setValue(formulaVar.getFormId().toString(),threadLocalData); - }else if(formulaVar.getFieldId()!=null&&formulaVar.getOptionId()==null){ - String fieldId=formulaVar.getFieldId().toString(); - key="field"+fieldId; - dataType.setFieldId(fieldId); - }else if(formulaVar.getOptionId()!=null){ - key="option"+formulaVar.getOptionId().toString(); - dataType.setContent(formulaVar.getOptionId()); - dataType.setText(formulaVar.getName()); - dataType.setFormId(null); - }else { - key="option"+formulaVar.getOptionId().toString(); - } - } + checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 + for (FormulaVar formulaVar : formulavars) { + DataType dataType = new DataType(); + dataType.setScore(0d); + dataType.setName((null == formulaVar.getName() || formulaVar.getName().equals("")) ? formulaVar.getParent() : formulaVar.getName()); + dataType.setFieldId(formulaVar.getFieldId() != null ? formulaVar.getFieldId().toString() : null); + String key = null; + if (formulaVar.getModule() != null && !formulaVar.getModule().equals("")) { + try { + dataType.setModule(formulaVar.getModule()); + } catch (IllegalArgumentException e) { + logger.error("err", e); + dataType.setModule(formulaVar.getModule()); + } + } + dataType.setFormId(formulaVar.getFormId() != null ? Long.parseLong(formulaVar.getFormId()) : null); + if (formulaVar.getName() != null && formulaVar.getName().equals("当前操作人")) { + key = formulaVar.getKey(); + formulaVar.setContent(employee.getUserId().toString()); + dataType.setContent(formulaVar.getContent()); + dataType.setText(formulaVar.getContent()); + dataType.setDataType(DataType.OPTION); + } else { + if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null && formulaVar.getOptionId() == null) { + key = "form" + formulaVar.getFormId().toString(); + ThreadLocalData threadLocalData = new ThreadLocalData(); + threadLocalData.setEmployee(employee); + threadLocalData.setModuleSource(ModuleSource.biaoge); + ParamContext.get().setValue(formulaVar.getFormId().toString(), threadLocalData); + } else if (formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { + String fieldId = formulaVar.getFieldId().toString(); + key = "field" + fieldId; + dataType.setFieldId(fieldId); + } else if (formulaVar.getOptionId() != null) { + key = "option" + formulaVar.getOptionId().toString(); + dataType.setContent(formulaVar.getOptionId()); + dataType.setText(formulaVar.getName()); + dataType.setFormId(null); + } else { + key = "option" + formulaVar.getOptionId().toString(); + } + } - Arrays.sort(funcArray); - int sidx= Arrays.binarySearch(funcArray,key); - if( sidx>=0 ){ - throw new RuntimeException("变量名非法"); - } - if(formulaVar.getOptionId()!=null){ - dataType.setDataType(DataType.OPTION); - } + Arrays.sort(funcArray); + int sidx = Arrays.binarySearch(funcArray, key); + if (sidx >= 0) { + throw new RuntimeException("变量名非法"); + } + if (formulaVar.getOptionId() != null) { + dataType.setDataType(DataType.OPTION); + } - if(StringUtils.isEmpty(dataType.getDataType())){ - String typeKey=null; - if(StringUtils.isNotEmpty(formulaVar.getFieldType())){ - typeKey=formulaVar.getFieldType(); - }else if(StringUtils.isNotEmpty(formulaVar.getType())){ - typeKey=formulaVar.getType(); - }else if(StringUtils.isNotEmpty(formulaVar.getFieldType())){ - typeKey=formulaVar.getFieldType(); - } - dataType.setDataType(ExcelParamUtil.findTestDataType(typeKey)); - } - if(StringUtils.isEmpty(dataType.getComponentKey())){ - dataType.setComponentKey(formulaVar.getComponentKey()); - } - if(expressMap.containsKey(key)){ - String newKey=key+ ExcelParamUtil.randomNumber(); - formulaVar.setKey(newKey); - dataType.setAggCndKey(key); - expressMap.put(newKey,dataType); - }else { - expressMap.put(key,dataType); - } - } + if (StringUtils.isEmpty(dataType.getDataType())) { + String typeKey = null; + if (StringUtils.isNotEmpty(formulaVar.getFieldType())) { + typeKey = formulaVar.getFieldType(); + } else if (StringUtils.isNotEmpty(formulaVar.getType())) { + typeKey = formulaVar.getType(); + } else if (StringUtils.isNotEmpty(formulaVar.getFieldType())) { + typeKey = formulaVar.getFieldType(); + } + dataType.setDataType(ExcelParamUtil.findTestDataType(typeKey)); + } + if (StringUtils.isEmpty(dataType.getComponentKey())) { + dataType.setComponentKey(formulaVar.getComponentKey()); + } + if (expressMap.containsKey(key)) { + String newKey = key + ExcelParamUtil.randomNumber(); + formulaVar.setKey(newKey); + dataType.setAggCndKey(key); + expressMap.put(newKey, dataType); + } else { + expressMap.put(key, dataType); + } + } - return expressMap; - } + return expressMap; + } - /** - * 格式化变量为数字 - * @param - */ - public static Object convertParamValToNumber(Object op1){ - BigDecimal oop1=new BigDecimal(ExcelParamUtil.getParamContent(op1,"string").toString()); - return oop1; - } - /** - * 格式化参数 - * @param op1 - * @param op2 - * @return - */ - public static List converParamValue(Object op1,Object op2){ - List list=new ArrayList<>(); + /** + * 格式化变量为数字 + * + * @param + */ + public static Object convertParamValToNumber(Object op1) { + BigDecimal oop1 = new BigDecimal(ExcelParamUtil.getParamContent(op1, "string").toString()); + return oop1; + } + + /** + * 格式化参数 + * + * @param op1 + * @param op2 + * @return + */ + public static List converParamValue(Object op1, Object op2) { + List list = new ArrayList<>(); - if(op1 instanceof DataType){ - list.add(op1); - DataType op1Data=(DataType)op1; - if(!(op2 instanceof DataType)&&op1Data.getDataType().toLowerCase().equals("date")){ - DataType dataType=new DataType(); - dataType.setDataType(DataType.STRING); - dataType.setContent(op2); - list.add(dataType); - }else if(op2 instanceof DataType&&op1Data.getDataType().toLowerCase().equals("date")){ - DataType dataType=(DataType)op2; - dataType.setDataType(DataType.STRING); - list.add(dataType); - }else{ - list.add(op2); - } + if (op1 instanceof DataType) { + list.add(op1); + DataType op1Data = (DataType) op1; + if (!(op2 instanceof DataType) && op1Data.getDataType().toLowerCase().equals("date")) { + DataType dataType = new DataType(); + dataType.setDataType(DataType.STRING); + dataType.setContent(op2); + list.add(dataType); + } else if (op2 instanceof DataType && op1Data.getDataType().toLowerCase().equals("date")) { + DataType dataType = (DataType) op2; + dataType.setDataType(DataType.STRING); + list.add(dataType); + } else { + list.add(op2); + } - }else if(op2 instanceof DataType){ - DataType op2Data=(DataType)op2; - if(!(op1 instanceof DataType)&&op2Data.getDataType().toLowerCase().equals("date")){ - DataType dataType=new DataType(); - dataType.setDataType(DataType.STRING); - dataType.setContent(op1); - list.add(dataType); - }else if(op1 instanceof DataType&&op2Data.getDataType().toLowerCase().equals("date")){ - DataType dataType=(DataType)op1; - dataType.setDataType(DataType.STRING); - list.add(dataType); - }else { - list.add(op1); - } - list.add(op2); - }else { - list.add(op1); - list.add(op2); - } + } else if (op2 instanceof DataType) { + DataType op2Data = (DataType) op2; + if (!(op1 instanceof DataType) && op2Data.getDataType().toLowerCase().equals("date")) { + DataType dataType = new DataType(); + dataType.setDataType(DataType.STRING); + dataType.setContent(op1); + list.add(dataType); + } else if (op1 instanceof DataType && op2Data.getDataType().toLowerCase().equals("date")) { + DataType dataType = (DataType) op1; + dataType.setDataType(DataType.STRING); + list.add(dataType); + } else { + list.add(op1); + } + list.add(op2); + } else { + list.add(op1); + list.add(op2); + } - return list; - } + return list; + } - /** - * 统一处理参数类型不一致问题 - * @param typeName - * @return - */ - public static String checkParamType(String typeName){ - typeName=typeName.toLowerCase(); - switch (typeName){ - case "option": - typeName=ParamType.STRING.getName(); - break; - case "date": - typeName=DataType.STRING; - break; - case "number": - typeName=DataType.NUMBER; - break; - case "string": - typeName=ParamType.STRING.getName(); - break; - case "boolean": - typeName=ParamType.BOOLEAN.getName(); - break; - case "select": - typeName=ParamType.STRING.getName(); - break; - case "text": - typeName=ParamType.STRING.getName(); - break; - case "employee": - typeName=ParamType.STRING.getName(); - break; - case "department": - typeName=ParamType.STRING.getName(); - break; - case "integer": - typeName=DataType.NUMBER; - break; - case "double": - typeName=DataType.NUMBER; - break; - case "float": - typeName=DataType.NUMBER; - break; - case "int": - typeName=DataType.NUMBER; - break; - case "long": - typeName=DataType.NUMBER; - break; - case "bigdecimal": - typeName=DataType.NUMBER; - break; + /** + * 统一处理参数类型不一致问题 + * + * @param typeName + * @return + */ + public static String checkParamType(String typeName) { + typeName = typeName.toLowerCase(); + switch (typeName) { + case "option": + typeName = ParamType.STRING.getName(); + break; + case "date": + typeName = DataType.STRING; + break; + case "number": + typeName = DataType.NUMBER; + break; + case "string": + typeName = ParamType.STRING.getName(); + break; + case "boolean": + typeName = ParamType.BOOLEAN.getName(); + break; + case "select": + typeName = ParamType.STRING.getName(); + break; + case "text": + typeName = ParamType.STRING.getName(); + break; + case "employee": + typeName = ParamType.STRING.getName(); + break; + case "department": + typeName = ParamType.STRING.getName(); + break; + case "integer": + typeName = DataType.NUMBER; + break; + case "double": + typeName = DataType.NUMBER; + break; + case "float": + typeName = DataType.NUMBER; + break; + case "int": + typeName = DataType.NUMBER; + break; + case "long": + typeName = DataType.NUMBER; + break; + case "bigdecimal": + typeName = DataType.NUMBER; + break; - } - return typeName; - } - public static String getKeyString(Object obj){ - if(obj instanceof JSONObject){ - JSONObject jsonObject=(JSONObject)obj; - return jsonObject.getString("key"); - }else { - return obj.toString(); - } - } - /** - * 替换变量的错误位置 - * @param startIdx - * @param endIdx - * @param excuteStr - */ - public static Map replaceErrorPlace(int startIdx,int endIdx,String errorFunc,String excuteStr,Map paramMap){ - Map kvMap=loopMap(paramMap); - Map replaceMap=new HashMap<>(); - String excuteLeftStr=excuteStr.substring(0,startIdx); - if(!excuteLeftStr.equals("")){ - Iterator wordItaretor=kvMap.keySet().iterator(); - while (wordItaretor.hasNext()){ - String key=wordItaretor.next(); - String name=kvMap.get(key); - if(excuteLeftStr.indexOf(key)>=0){ - String newStr=excuteLeftStr.replaceAll(key,name); - startIdx=startIdx-(excuteLeftStr.length()-newStr.length()); - } - } + } + return typeName; + } - } - if(kvMap.get(errorFunc)!=null){ - endIdx=startIdx+kvMap.get(errorFunc).length()-1; - }else { - endIdx=startIdx+errorFunc.length()-1; - } + public static String getKeyString(Object obj) { + if (obj instanceof JSONObject) { + JSONObject jsonObject = (JSONObject) obj; + return jsonObject.getString("key"); + } else { + return obj.toString(); + } + } - replaceMap.put("startIdx",startIdx); - replaceMap.put("endIdx",endIdx); - return replaceMap; - } + /** + * 替换变量的错误位置 + * + * @param startIdx + * @param endIdx + * @param excuteStr + */ + public static Map replaceErrorPlace(int startIdx, int endIdx, String errorFunc, String excuteStr, Map paramMap) { + Map kvMap = loopMap(paramMap); + Map replaceMap = new HashMap<>(); + String excuteLeftStr = excuteStr.substring(0, startIdx); + if (!excuteLeftStr.equals("")) { + Iterator wordItaretor = kvMap.keySet().iterator(); + while (wordItaretor.hasNext()) { + String key = wordItaretor.next(); + String name = kvMap.get(key); + if (excuteLeftStr.indexOf(key) >= 0) { + String newStr = excuteLeftStr.replaceAll(key, name); + startIdx = startIdx - (excuteLeftStr.length() - newStr.length()); + } + } - public static Map loopMap(Map paramMap){ - Map kvMap=new HashMap<>(); + } + if (kvMap.get(errorFunc) != null) { + endIdx = startIdx + kvMap.get(errorFunc).length() - 1; + } else { + endIdx = startIdx + errorFunc.length() - 1; + } - Set set=paramMap.keySet(); - Iterator iterator=set.iterator(); - while (iterator.hasNext()){ - String key=iterator.next(); - DataType dataType=(DataType)paramMap.get(key); - kvMap.put(key,dataType.getName()); - } - return kvMap; - } + replaceMap.put("startIdx", startIdx); + replaceMap.put("endIdx", endIdx); + return replaceMap; + } - public static boolean isNumber(Object object){ - String type= ExcelParamUtil.getParamType(object.getClass().getName()); - Arrays.sort(numberTypes); - if(Arrays.binarySearch(numberTypes,type)>=0){ - return true; - } - return false; - } + public static Map loopMap(Map paramMap) { + Map kvMap = new HashMap<>(); - public static String randomNumber(){ - int max=1000,min=1; - long randomNum = System.currentTimeMillis(); - int ran3 = (int) (randomNum%(max-min)+min); - return ran3+""; - } + Set set = paramMap.keySet(); + Iterator iterator = set.iterator(); + while (iterator.hasNext()) { + String key = iterator.next(); + DataType dataType = (DataType) paramMap.get(key); + kvMap.put(key, dataType.getName()); + } + return kvMap; + } - /** - * 长度不够则添加元素的字符串拼接 - * @param chars 将要拼接的字符 - * @param sourceStr 源字符 - * @param targetLength 目标字符长度 - * @param place 位置在左还是右 - * @return - */ - public static String appendString(String chars, String sourceStr, int targetLength, String place){ - StringBuilder builder = new StringBuilder(sourceStr); + public static boolean isNumber(Object object) { + String type = ExcelParamUtil.getParamType(object.getClass().getName()); + Arrays.sort(numberTypes); + if (Arrays.binarySearch(numberTypes, type) >= 0) { + return true; + } + return false; + } - while (true){ - //长度相等,不做处理 - if(builder.length() == targetLength){ - break; - }else if(builder.length() > targetLength){ - //源字符长度大于目标长度则截取 - int length = builder.length() - targetLength; + public static String randomNumber() { + int max = 1000, min = 1; + long randomNum = System.currentTimeMillis(); + int ran3 = (int) (randomNum % (max - min) + min); + return ran3 + ""; + } - if("LEFT".equals(place)){ - String tempStr = builder.substring(length, builder.length()); - builder.replace(0, builder.length(), tempStr); - }else { - String tempStr = builder.substring(0, targetLength); - builder.replace(0, builder.length(), tempStr); - } - break; - } + /** + * 长度不够则添加元素的字符串拼接 + * + * @param chars 将要拼接的字符 + * @param sourceStr 源字符 + * @param targetLength 目标字符长度 + * @param place 位置在左还是右 + * @return + */ + public static String appendString(String chars, String sourceStr, int targetLength, String place) { + StringBuilder builder = new StringBuilder(sourceStr); - //源字符长度小于目标长度则不断拼接 - if("LEFT".equals(place)){ - builder.insert(0, chars.replaceAll(",","")); - }else { - builder.append(chars.replaceAll(",","")); - } - } - return builder.toString(); - } + while (true) { + //长度相等,不做处理 + if (builder.length() == targetLength) { + break; + } else if (builder.length() > targetLength) { + //源字符长度大于目标长度则截取 + int length = builder.length() - targetLength; - public static FormulaVar getFixFieldVar(List list, String key){ - FormulaVar formulaVar=new FormulaVar(); - for (FixedField fixedField:list){ - if(fixedField.getKey().equals(key)){ - Component component=(Component)fixedField.getMatchs().get(0); - ComponentType componentType=component.getComponentKey(); - if(componentType.equals(ComponentType.Text)){ + if ("LEFT".equals(place)) { + String tempStr = builder.substring(length, builder.length()); + builder.replace(0, builder.length(), tempStr); + } else { + String tempStr = builder.substring(0, targetLength); + builder.replace(0, builder.length(), tempStr); + } + break; + } - } - } - } - return formulaVar; - } + //源字符长度小于目标长度则不断拼接 + if ("LEFT".equals(place)) { + builder.insert(0, chars.replaceAll(",", "")); + } else { + builder.append(chars.replaceAll(",", "")); + } + } + return builder.toString(); + } - public static String findAggCndStr(String sql,Map paramMap){ - String partternStr="(COUNT|SUM|MIN|MAX|AVG|count|sum|min|max)+\\(+(.)+\\)+"; - Pattern pattern = Pattern.compile(partternStr); - Matcher matcher = pattern.matcher(sql ); - int i=0; - while (matcher.find()) { - String cnd = matcher.group(); - String[] cndArray=cnd.split(",",2); - if(cndArray.length==2){ - String realCnd=cndArray[1].substring(0,cndArray[1].length()-1); - String key="cnd"+i+Math.abs(realCnd.hashCode())+""; - sql=sql.replace(realCnd,key); - realCnd=realCnd.replace("{",""); - realCnd=realCnd.replace("}",""); - paramMap.put(key,realCnd); - } - i++; - } - return sql; - } + public static FormulaVar getFixFieldVar(List list, String key) { + FormulaVar formulaVar = new FormulaVar(); + for (FixedField fixedField : list) { + if (fixedField.getKey().equals(key)) { + Component component = (Component) fixedField.getMatchs().get(0); + ComponentType componentType = component.getComponentKey(); + if (componentType.equals(ComponentType.Text)) { + + } + } + } + return formulaVar; + } + + public static String findAggCndStr(String sql, Map paramMap) { + String partternStr = "(COUNT|SUM|MIN|MAX|AVG|count|sum|min|max)+\\(+(.)+\\)+"; + Pattern pattern = Pattern.compile(partternStr); + Matcher matcher = pattern.matcher(sql); + int i = 0; + while (matcher.find()) { + String cnd = matcher.group(); + String[] cndArray = cnd.split(",", 2); + if (cndArray.length == 2) { + String realCnd = cndArray[1].substring(0, cndArray[1].length() - 1); + String key = "cnd" + i + Math.abs(realCnd.hashCode()) + ""; + sql = sql.replace(realCnd, key); + realCnd = realCnd.replace("{", ""); + realCnd = realCnd.replace("}", ""); + paramMap.put(key, realCnd); + } + i++; + } + return sql; + } - /** - * 执行语句的断句算法,通过计算小括号的数量进行断句断点的确定,然后拆分语句 - * @param sql - */ - public static String spliteSql(String sql,Map paramMap){ - List strList=new ArrayList<>(); - int pointIdx=0; - char[] charArray=sql.toCharArray(); - int leftBrakets=0; - char brackeLeft='('; - char brackeRight=')'; - boolean find=false; - for (int i=0;i=0?cndArray[0].length():0); - replaceSql+=cndArray[0]+findAggCndStr(realCnd,paramMap); - } + /** + * 执行语句的断句算法,通过计算小括号的数量进行断句断点的确定,然后拆分语句 + * + * @param sql + */ + public static String spliteSql(String sql, Map paramMap) { + List strList = new ArrayList<>(); + int pointIdx = 0; + char[] charArray = sql.toCharArray(); + int leftBrakets = 0; + char brackeLeft = '('; + char brackeRight = ')'; + boolean find = false; + for (int i = 0; i < charArray.length; i++) { + char charstr = charArray[i]; + if (charstr == brackeLeft) { + find = true; + leftBrakets++; + } + if (leftBrakets != 0 && charstr == brackeRight) { + leftBrakets--; + } + if (find && leftBrakets == 0) { + pointIdx = i; + break; + } + } + pointIdx += 1; + if (pointIdx == sql.length()) { + strList.add(sql.substring(0, pointIdx)); + } else { + strList.add(sql.substring(0, pointIdx)); + strList.add(sql.substring(pointIdx)); + } + String replaceSql = ""; + for (String s : strList) { + String[] cndArray = s.split("(COUNT|SUM|MIN|MAX|count|sum|min|max)"); + if (cndArray.length == 2) { + if (cndArray[0].equals("")) { + replaceSql += findAggCndStr(s, paramMap); + } else { + String realCnd = s.substring(cndArray[0].length() - 1 >= 0 ? cndArray[0].length() : 0); + replaceSql += cndArray[0] + findAggCndStr(realCnd, paramMap); + } - }else { - replaceSql+=findAggCndStr(s,paramMap); - } + } else { + replaceSql += findAggCndStr(s, paramMap); + } - } - sql=replaceSql; - return sql; - } + } + sql = replaceSql; + return sql; + } } diff --git a/src/com/engine/salary/formlua/util/ExcelStandardUtil.java b/src/com/engine/salary/formlua/util/ExcelStandardUtil.java index 45489e83d..ba3cb6da8 100644 --- a/src/com/engine/salary/formlua/util/ExcelStandardUtil.java +++ b/src/com/engine/salary/formlua/util/ExcelStandardUtil.java @@ -8,7 +8,7 @@ import com.weaver.excel.formula.api.entity.FormulaVar; import com.weaver.excel.formula.entity.parameter.DataType; import com.weaver.excel.formula.entity.parameter.ParamFactory; import com.weaver.excel.formula.entity.standard.front.CurrentVar; -import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.domain.user.DataCollectionEmployee; import com.weaver.teams.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +22,7 @@ import java.util.regex.Pattern; public class ExcelStandardUtil { protected static final Logger logger = LoggerFactory.getLogger(ExcelStandardUtil.class); - public static Map replaceAllParam(String sql, List localVars,List dataVars, SimpleEmployee employee){ + public static Map replaceAllParam(String sql, List localVars,List dataVars, DataCollectionEmployee employee){ if(null!=localVars){ for (FormulaVar formulaVar:localVars){ if(StringUtils.isNotEmpty(formulaVar.getDataId()) && StringUtils.isEmpty(formulaVar.getFormId())){ @@ -131,7 +131,7 @@ public class ExcelStandardUtil { return dataMap; } - public static Map replaceAllParamForTest(String sql, List formulaVars, SimpleEmployee employee){ + public static Map replaceAllParamForTest(String sql, List formulaVars, DataCollectionEmployee employee){ if(null==formulaVars){ return null; } @@ -234,7 +234,7 @@ public class ExcelStandardUtil { return dataMap; } - private static DataType transFormulaVarToDataTypeTesy(FormulaVar formulaVar,SimpleEmployee employee){ + private static DataType transFormulaVarToDataTypeTesy(FormulaVar formulaVar,DataCollectionEmployee employee){ DataType dataType =new DataType(); ParamFactory paramFactory=ParamFactory.getInstance(); dataType.setContent(formulaVar.getContent()); @@ -330,7 +330,7 @@ public class ExcelStandardUtil { return dataType; } - private static DataType transFormulaVarToDataType(FormulaVar localFormulaVar,List dataVars,SimpleEmployee employee){ + private static DataType transFormulaVarToDataType(FormulaVar localFormulaVar,List dataVars,DataCollectionEmployee employee){ DataType dataType =new DataType(); if(localFormulaVar == null){ return null; diff --git a/src/com/engine/salary/formlua/util/TestUtil.java b/src/com/engine/salary/formlua/util/TestUtil.java index 1fcab01eb..3e8e39ed2 100644 --- a/src/com/engine/salary/formlua/util/TestUtil.java +++ b/src/com/engine/salary/formlua/util/TestUtil.java @@ -30,7 +30,7 @@ import com.weaver.excel.formula.func.math.MathFuncsServiceImpl; import com.weaver.excel.formula.func.string.StringFormulaService; import com.weaver.excel.formula.func.string.StringFormulaServiceImpl; import com.weaver.excel.formula.util.standard.ExcelDataType; -import com.weaver.teams.domain.user.SimpleEmployee; +import com.weaver.teams.domain.user.DataCollectionEmployee; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -150,7 +150,7 @@ public class TestUtil { filterDatas.add(formulaFilterData2); String dataId="60000000000000001"; String[] cols=new String[]{"10_taxRate"}; - SimpleEmployee employee=new SimpleEmployee(); + DataCollectionEmployee employee=new DataCollectionEmployee(); employee.setTenantKey("tm7tozevws"); employee.setUserId(5113514575963198048L); employee.setId(3573514574891514361L); diff --git a/src/com/engine/salary/formlua/util/standard/ExcelTransUtil.java b/src/com/engine/salary/formlua/util/standard/ExcelTransUtil.java deleted file mode 100644 index fb3d4422a..000000000 --- a/src/com/engine/salary/formlua/util/standard/ExcelTransUtil.java +++ /dev/null @@ -1,320 +0,0 @@ -package com.engine.salary.formlua.util.standard; - -import com.alibaba.fastjson.JSON; -import com.weaver.common.form.FreeFormAssistService; -import com.weaver.common.form.FreeFormService; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.common.form.data.detail.FormDataDetail; -import com.weaver.common.form.data.option.FormDataOption; -import com.weaver.common.form.metadata.ModuleSource; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.excel.formula.api.entity.DataOption; -import com.weaver.excel.formula.api.entity.FormulaVar; -import com.weaver.excel.formula.entity.standard.execute.FixFieldType; -import com.weaver.excel.formula.util.ExcelParamUtil; -import com.weaver.teams.domain.user.SimpleEmployee; -import com.weaver.teams.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 函数标准数据转换工具 - */ -@Component -public class ExcelTransUtil { - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - protected FreeFormAssistService freeFormAssistService; - /** - * 固定字段数据转换方法 - * @param sourceId 来源ID或表单ID - * @param fixFieldKey 固定字段属性ID - * @param name 固定字段名称,记录日志使用 - * @param content 文本、数字的值 - * @param dataOptions 选项型数据的值 - * @param fixFieldType 固定字段类型,使用函数提供的FixFieldType标记 - * @return - */ - public static FormulaVar buildFixField(Long sourceId, String fixFieldKey,String name, String content, List dataOptions, FixFieldType fixFieldType){ - FormulaVar formulaVar=new FormulaVar(); - formulaVar.setFormId(sourceId+""); - formulaVar.setDataType(ExcelParamUtil.findType(fixFieldType.toString())); - formulaVar.setContent(content); - formulaVar.setFixName(name); - formulaVar.setFixFieldKey(fixFieldKey); - formulaVar.setId(fixFieldKey); - formulaVar.setKey(fixFieldKey); - formulaVar.setFieldId(fixFieldKey); - if(fixFieldType==FixFieldType.Select || fixFieldType==FixFieldType.Department || fixFieldType == FixFieldType.Employee || fixFieldType == FixFieldType.Relate){ - formulaVar.setDataOptionList(dataOptions); - String options=""; - for(DataOption dataOption:dataOptions){ - options+=dataOption.getOptionId(); - } - formulaVar.setContent(options); - formulaVar.setComponentKey(ComponentType.Employee.toString()); - } - return formulaVar; - } - - /** - * 构建字段数据,文本、数字、日期使用此方法 - * @param sourceId - * @param fieldId - * @param excelDataType - * @param module - * @param value - * @return - */ - public static FormulaVar buildTxtNumDateField(Long sourceId,Long fieldId,ExcelDataType excelDataType,String module,Object value){ - return commonBuildField(sourceId,fieldId,excelDataType,module,null,value); - } - - /** - * 构建选项型或数据源型使用此方法 - * @param sourceId - * @param fieldId - * @param excelDataType - * @param module - * @param dataOptions - * @return - */ - public static FormulaVar buildOptionField(Long sourceId,Long fieldId,ExcelDataType excelDataType,String module,List dataOptions){ - return commonBuildField(sourceId,fieldId,excelDataType,module,dataOptions,null); - } - private static FormulaVar commonBuildField(Long sourceId,Long fieldId,ExcelDataType excelDataType,String module,List dataOptions,Object value){ - FormulaVar formulaVar =new FormulaVar(); - formulaVar.setContent(value+""); - formulaVar.setFieldId(fieldId+""); - formulaVar.setFormId(sourceId+""); - formulaVar.setDataType(excelDataType.toString()); - formulaVar.setModule(module); - if(dataOptions!=null && dataOptions.size()>0){ - formulaVar.setDataOptionList(dataOptions); - String optionStr=""; - for(DataOption dataOption:dataOptions){ - optionStr+=dataOption.getOptionId(); - } - formulaVar.setContent(optionStr); - } - return formulaVar; - } - - /** - * 转换表单字段数据为函数标准参数对象 - * @param formDataDetailList 表单字段数据列表 - * @param sourceId 表单ID或者数据源ID - * @param module 所属模块 - * @return - */ - public List transFieldForForm(List formDataDetailList,Long layoutId, Long sourceId, ModuleSource module,SimpleEmployee simpleEmployee){ - List formulaVarList=new ArrayList<>(); - if(formDataDetailList!=null && formDataDetailList.size()>0){ - - Map fieldMap = bulidFreeFormService(module).getFieldMapByFormId(sourceId, simpleEmployee); - FormulaVar formulaVar =null; - Map replaceMap=new HashMap<>(); - for (FormDataDetail formDataDetail:formDataDetailList){ - if(formDataDetail.getFormField()==null){ - throw new RuntimeException("函数数据转换失败,找不到表单字段数据"); - } - FormField newFormField=fieldMap.get(formDataDetail.getFormField().getId()); - if(newFormField!=null){ - formDataDetail.setFormField(newFormField); - } - Double score=getDetailScoreForForm(formDataDetail,module,layoutId,simpleEmployee); -// Double score=getDetailScore(formDataDetail,module,layoutId,simpleEmployee); - formulaVar=new FormulaVar(); - if(score!=null){ - formulaVar.setScore(score); - } - FormField formField=formDataDetail.getFormField(); - formulaVar.setContent(formDataDetail.getContent()); - if(formDataDetail.getDataText()!=null && StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ - if(StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ - formulaVar.setContent(formDataDetail.getDataText().getContent()); - } - } - formulaVar.setFieldId(formField.getId()!=null?formField.getId()+"":null); - formulaVar.setFormId(formField.getFormId()!=null?formField.getFormId()+"":null); - formulaVar.setComponentKey(formField.getComponentKey()); - if(formField.getSubForm()!=null){ - formulaVar.setsFormId(formField.getSubForm().getId()+""); - } - formulaVar.setDataType(ExcelParamUtil.findType(formField.getComponentKey())); - formulaVar.setModule(module.toString()); - if(formulaVar.getFormId()==null){ - formulaVar.setFormId(sourceId+""); - } - if(formDataDetail.getDataOptions()!=null && formDataDetail.getDataOptions().size()>0){ - List formDataOptions=formDataDetail.getDataOptions(); - List excelOptionList=new ArrayList<>(); - String optionstr=""; - String optionContent=""; - for(FormDataOption formDataOption:formDataOptions){ - DataOption dataOption=new DataOption(); - dataOption.setOptionId(formDataOption.getOptionId()+""); - dataOption.setOptionContent(formDataOption.getContent()); - excelOptionList.add(dataOption); - optionstr+=formDataOption.getOptionId(); - optionContent+=formDataOption.getContent(); - } - if(StringUtils.isNotEmpty(optionstr)){ - formulaVar.setContent(optionstr); - } - formulaVar.setOptionContent(optionContent); - formulaVar.setDataOptionList(excelOptionList); - } - //明细替换处理 - try { - if(!replaceMap.containsKey(formDataDetail.getFormField().getId())){ - replaceMap.put(formDataDetail.getFormField().getId(),formDataDetail); - }else{ - FormDataDetail lastFormDataDetail=replaceMap.get(formDataDetail.getFormField().getId()); - if(formDataDetail.getDataIndex()!=null && lastFormDataDetail.getDataIndex()!=null){ - if(formDataDetail.getDataIndex().longValue() loopData.getFieldId().equalsIgnoreCase(formDataDetail.getFormField().getId().toString())); - logger.info("替换了:"+JSON.toJSONString(formDataDetail)); - }else{ - continue; - } - } - } - } catch (Exception e) { - logger.error("err",e); - } - - formulaVarList.add(formulaVar); - } - } - return formulaVarList; - } - - /** - * 转换表单字段数据为函数标准参数对象 - * @param formDataDetailList 表单字段数据列表 - * @param sourceId 表单ID或者数据源ID - * @param module 所属模块 - * @return - */ - public List transField(List formDataDetailList,Long layoutId, Long sourceId, ModuleSource module,SimpleEmployee simpleEmployee){ - List formulaVarList=new ArrayList<>(); - if(formDataDetailList!=null && formDataDetailList.size()>0){ - - Map fieldMap = bulidFreeFormService(module).getFieldMapByFormId(sourceId, simpleEmployee); - - FormulaVar formulaVar =null; - for (FormDataDetail formDataDetail:formDataDetailList){ - if(formDataDetail.getFormField()==null){ - throw new RuntimeException("函数数据转换失败,找不到表单字段数据"); - } - FormField newFormField=fieldMap.get(formDataDetail.getFormField().getId()); - if(newFormField!=null){ - formDataDetail.setFormField(newFormField); - } - Double score=getDetailScore(formDataDetail,module,layoutId,simpleEmployee); - - formulaVar=new FormulaVar(); - if(score!=null){ - formulaVar.setScore(score); - } - FormField formField=formDataDetail.getFormField(); - formulaVar.setContent(formDataDetail.getContent()); - if(formDataDetail.getDataText()!=null && StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ - if(StringUtils.isNotEmpty(formDataDetail.getDataText().getContent())){ - formulaVar.setContent(formDataDetail.getDataText().getContent()); - } - } - formulaVar.setFieldId(formField.getId()!=null?formField.getId()+"":null); - formulaVar.setFormId(formField.getFormId()!=null?formField.getFormId()+"":null); - formulaVar.setComponentKey(formField.getComponentKey()); - if(formField.getSubForm()!=null){ - formulaVar.setsFormId(formField.getSubForm().getId()+""); - } - formulaVar.setDataType(ExcelParamUtil.findType(formField.getComponentKey())); - formulaVar.setModule(module.toString()); - if(formulaVar.getFormId()==null){ - formulaVar.setFormId(sourceId+""); - } - if(formDataDetail.getDataOptions()!=null && formDataDetail.getDataOptions().size()>0){ - List formDataOptions=formDataDetail.getDataOptions(); - List excelOptionList=new ArrayList<>(); - String optionstr=""; - String optionContent=""; - for(FormDataOption formDataOption:formDataOptions){ - DataOption dataOption=new DataOption(); - dataOption.setOptionId(formDataOption.getOptionId()+""); - dataOption.setOptionContent(formDataOption.getContent()); - excelOptionList.add(dataOption); - optionstr+=formDataOption.getOptionId(); - optionContent+=formDataOption.getContent(); - } - if(StringUtils.isNotEmpty(optionstr)){ - formulaVar.setContent(optionstr); - } - formulaVar.setOptionContent(optionContent); - formulaVar.setDataOptionList(excelOptionList); - } - - formulaVarList.add(formulaVar); - } - } - return formulaVarList; - } - - public Double getDetailScore(FormDataDetail dataDetail, ModuleSource module, Long layoutId, SimpleEmployee employee) { - Double score = null; - FormField formField=dataDetail.getFormField(); -// logger.info("获取分数的参数:"+(JSON.toJSONString(dataDetail))); -// logger.info("获取分数的布局ID:"+(layoutId)); - if( ComponentType.RadioBox.toString().equals(formField.getComponentKey()) - || ComponentType.CheckBox.toString().equals(formField.getComponentKey()) - || ComponentType.Select.toString().equals(formField.getComponentKey())) { -// score=getDetailScoreForForm(dataDetail,module,layoutId,employee); - score = bulidFreeFormService(module).getOptionScore(dataDetail.getFormField().getId()+"", layoutId, dataDetail, employee).doubleValue(); - } - return score; - } - public Double getDetailScoreForForm(FormDataDetail dataDetail, ModuleSource module, Long layoutId, SimpleEmployee employee) { - Double score = null; - FormField formField=dataDetail.getFormField(); - if( ComponentType.RadioBox.toString().equals(formField.getComponentKey()) - || ComponentType.CheckBox.toString().equals(formField.getComponentKey()) - || ComponentType.Select.toString().equals(formField.getComponentKey())) { - if(dataDetail.getDataOptions()!=null && dataDetail.getDataOptions().size()>0){ - Double scoreSum=0D; - for(FormDataOption formDataOption:dataDetail.getDataOptions()){ - try { - if(StringUtils.isNotEmpty(formDataOption.getScore())){ - scoreSum+=Double.parseDouble(formDataOption.getScore()); - } - } catch (NumberFormatException e) { - logger.error("err",e); - } -// scoreString=scoreSum.toString(); - } - if(scoreSum!=null){ - try { - score=scoreSum; - } catch (NumberFormatException e) { - logger.error("err",e); - } - } - logger.info("获取分数:"+score); - } - } - return score; - } - public FreeFormService bulidFreeFormService(ModuleSource module) { - return freeFormAssistService.buildFreeFormService(module.toString()); - } - -} diff --git a/src/com/engine/salary/remote/attend/cmd/GetKQReportCmd.java b/src/com/engine/salary/remote/attend/cmd/GetKQReportCmd.java index 632802719..f1d3b612d 100644 --- a/src/com/engine/salary/remote/attend/cmd/GetKQReportCmd.java +++ b/src/com/engine/salary/remote/attend/cmd/GetKQReportCmd.java @@ -95,7 +95,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { if("leave".equalsIgnoreCase(kqReportFieldComInfo.getFieldname())&&leaveRules.size()==0)continue; column = new HashMap(); - column.put("title", SystemEnv.getHtmlLabelNames(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); + column.put("title", SalaryI18nUtil.getI18nLabels(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); column.put("unit", KQReportBiz.getUnitType(kqReportFieldComInfo, user)); column.put("dataIndex", kqReportFieldComInfo.getFieldname()); column.put("type", kqReportFieldComInfo.getFieldname()); @@ -143,7 +143,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { // } // column = new HashMap(); -// column.put("title", SystemEnv.getHtmlLabelName(386476, user.getLanguage())); +// column.put("title", SalaryI18nUtil.getI18nLabel(386476, user.getLanguage())); // column.put("dataIndex", "kqCalendar"); // column.put("key", "kqCalendar"); // if(childColumns.size()>0) {//跨列width取子列的width @@ -430,7 +430,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { if(DateUtil.compDate(today, date)>0){ data.put(date,""); }else{ - data.put(date,detialDatas.get(id+"|"+date)==null?SystemEnv.getHtmlLabelName(26593, user.getLanguage()):detialDatas.get(id+"|"+date)); + data.put(date,detialDatas.get(id+"|"+date)==null?SalaryI18nUtil.getI18nLabel(26593, user.getLanguage()):detialDatas.get(id+"|"+date)); } cal.setTime(DateUtil.parseToDate(date)); date = DateUtil.getDate(cal.getTime(), 1); @@ -489,7 +489,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { String unitType = Util.null2String(leaveRule.get("unitType")); column = new HashMap(); column.put("title", name); - column.put("unit", KQUnitBiz.isLeaveHour(unitType) ?SystemEnv.getHtmlLabelName(391, user.getLanguage()):SystemEnv.getHtmlLabelName(1925, user.getLanguage())); + column.put("unit", KQUnitBiz.isLeaveHour(unitType) ?SalaryI18nUtil.getI18nLabel(391, user.getLanguage()):SalaryI18nUtil.getI18nLabel(1925, user.getLanguage())); column.put("width", 65); column.put("dataIndex", id); column.put("key", id); @@ -517,16 +517,16 @@ public class GetKQReportCmd extends AbstractCommonCommand> { String unitTypeName = ""; if(Util.null2String(unitType).length()>0){ if(unitType.equals("1")){ - unitTypeName=SystemEnv.getHtmlLabelName(1925, user.getLanguage()); + unitTypeName=SalaryI18nUtil.getI18nLabel(1925, user.getLanguage()); }else if(unitType.equals("2")){ - unitTypeName=SystemEnv.getHtmlLabelName(391, user.getLanguage()); + unitTypeName=SalaryI18nUtil.getI18nLabel(391, user.getLanguage()); }else if(unitType.equals("3")){ - unitTypeName=SystemEnv.getHtmlLabelName(18083, user.getLanguage()); + unitTypeName=SalaryI18nUtil.getI18nLabel(18083, user.getLanguage()); } } column.put("unit", unitTypeName); } - column.put("title", SystemEnv.getHtmlLabelNames(fieldlabel, user.getLanguage())); + column.put("title", SalaryI18nUtil.getI18nLabels(fieldlabel, user.getLanguage())); column.put("dataIndex", id); column.put("key", id); column.put("rowSpan", 1); @@ -547,7 +547,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { if(kqReportFieldComInfo.getParentid().equals(parentid)) { if(!kqReportFieldComInfo.getReportType().equals("month"))continue; column = new HashMap(); - column.put("title", SystemEnv.getHtmlLabelNames(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); + column.put("title", SalaryI18nUtil.getI18nLabels(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); column.put("unit", KQReportBiz.getUnitType(kqReportFieldComInfo, user)); column.put("width", Util.getIntValue(kqReportFieldComInfo.getWidth())); column.put("dataIndex", kqReportFieldComInfo.getFieldname()); @@ -579,7 +579,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { if(!kqReportFieldComInfo.getReportType().equals("month"))continue; if (kqReportFieldComInfo.getFieldname().equals(lsCascadeKey.get(i))){ column = new HashMap(); - column.put("title", SystemEnv.getHtmlLabelNames(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); + column.put("title", SalaryI18nUtil.getI18nLabels(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); column.put("unit", KQReportBiz.getUnitType(kqReportFieldComInfo, user)); column.put("width", Util.getIntValue(kqReportFieldComInfo.getWidth())); column.put("dataIndex", kqReportFieldComInfo.getFieldname()); diff --git a/src/com/engine/salary/service/RemoteExcelService.java b/src/com/engine/salary/service/RemoteExcelService.java index 8081451ee..d65e6197d 100644 --- a/src/com/engine/salary/service/RemoteExcelService.java +++ b/src/com/engine/salary/service/RemoteExcelService.java @@ -7,22 +7,22 @@ import java.util.List; import java.util.Map; public interface RemoteExcelService { -// ExcelResult aggregation(AggFunc func, String sourceId, String fieldId, List filterFormDataList, Map extendParam, SimpleEmployee employee); +// ExcelResult aggregation(AggFunc func, String sourceId, String fieldId, List filterFormDataList, Map extendParam, DataCollectionEmployee employee); // -// ExcelPage categoryList(ExcelPage page, Map extendParam, SimpleEmployee employee); +// ExcelPage categoryList(ExcelPage page, Map extendParam, DataCollectionEmployee employee); List fieldList(String sourceId, Map extendParam); List> fieldGroupList(Map extendParam); -// ExcelPage dataSourceList(String categoryId, ExcelPage page, Map extendParam, SimpleEmployee employee); +// ExcelPage dataSourceList(String categoryId, ExcelPage page, Map extendParam, DataCollectionEmployee employee); // -// List findProperData(String dataId, String fieldId, String fieldType, Map extendParam, SimpleEmployee employee); +// List findProperData(String dataId, String fieldId, String fieldType, Map extendParam, DataCollectionEmployee employee); // -// List choose(String sourceId, List filterFormDataList, Map extendParam, SimpleEmployee employee); +// List choose(String sourceId, List filterFormDataList, Map extendParam, DataCollectionEmployee employee); // -// List vlookups(String sourceId, List filterFormDataList, List returnFields, Map extendParam, SimpleEmployee employee); +// List vlookups(String sourceId, List filterFormDataList, List returnFields, Map extendParam, DataCollectionEmployee employee); // -// Map findSourceName(String Module, List idList, Map extendParam, SimpleEmployee employee); +// Map findSourceName(String Module, List idList, Map extendParam, DataCollectionEmployee employee); } diff --git a/src/com/engine/salary/service/impl/AddUpDeductionServiceImpl.java b/src/com/engine/salary/service/impl/AddUpDeductionServiceImpl.java index edeb2ed77..716150827 100644 --- a/src/com/engine/salary/service/impl/AddUpDeductionServiceImpl.java +++ b/src/com/engine/salary/service/impl/AddUpDeductionServiceImpl.java @@ -161,7 +161,7 @@ public class AddUpDeductionServiceImpl extends Service implements AddUpDeduction //日期范围选项 // List dateOptions = new ArrayList(); -// dateOptions.add(new SearchConditionOption("6", SystemEnv.getHtmlLabelName(32530, user.getLanguage()), true));//指定日期范围(必须为6) +// dateOptions.add(new SearchConditionOption("6", SalaryI18nUtil.getI18nLabel(32530, user.getLanguage()), true));//指定日期范围(必须为6) // SearchConditionItem hiredate = conditionFactory.createCondition(ConditionType.RANGEPICKER, 18648, new String[]{"hiredate", "hiredate"}); // hiredate.setInputType("rangepicker"); // hiredate.setFormat("yyyy-MM-dd"); diff --git a/src/com/engine/salary/service/impl/AddUpSituationServiceImpl.java b/src/com/engine/salary/service/impl/AddUpSituationServiceImpl.java index f3b04ecf1..e7a2ad739 100644 --- a/src/com/engine/salary/service/impl/AddUpSituationServiceImpl.java +++ b/src/com/engine/salary/service/impl/AddUpSituationServiceImpl.java @@ -144,7 +144,7 @@ public class AddUpSituationServiceImpl extends Service implements AddUpSituation // // //日期范围选项 // List dateOptions = new ArrayList(); -// dateOptions.add(new SearchConditionOption("6", SystemEnv.getHtmlLabelName(32530, user.getLanguage()), true));//指定日期范围(必须为6) +// dateOptions.add(new SearchConditionOption("6", SalaryI18nUtil.getI18nLabel(32530, user.getLanguage()), true));//指定日期范围(必须为6) // SearchConditionItem hiredate = conditionFactory.createCondition(ConditionType.RANGEPICKER, 18648, new String[]{"hiredate", "hiredate"}); // hiredate.setInputType("rangepicker"); // hiredate.setFormat("yyyy-MM-dd"); diff --git a/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java b/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java index 93b7c17ea..53591543c 100644 --- a/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java +++ b/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java @@ -79,12 +79,12 @@ public class RemoteExcelServiceImpl extends Service implements RemoteExcelServic // @Override // public ExcelResult aggregation(AggFunc func, String sourceId, String fieldId, List filterFormDataList, Map extendParam, -// SimpleEmployee employee) { +// DataCollectionEmployee employee) { // return null; // } // @Override -// public ExcelPage categoryList(ExcelPage page, Map extendParam, SimpleEmployee employee) { +// public ExcelPage categoryList(ExcelPage page, Map extendParam, DataCollectionEmployee employee) { // log.info("page: {}", JsonUtil.toJsonString(page)); // List categories = Lists.newArrayList(); // FormulaCategory category = new FormulaCategory(); @@ -201,7 +201,7 @@ public class RemoteExcelServiceImpl extends Service implements RemoteExcelServic } // @Override -// public ExcelPage dataSourceList(String categoryId, ExcelPage page, Map extendParam, SimpleEmployee employee) { +// public ExcelPage dataSourceList(String categoryId, ExcelPage page, Map extendParam, DataCollectionEmployee employee) { // log.info("categoryId: {}, page: {}", categoryId, JsonUtil.toJsonString(page)); // if (StringUtils.equals("TAX_RATE", categoryId)) { // taxRate2FormulaDataSource(page, employee.getTenantKey()); @@ -211,18 +211,18 @@ public class RemoteExcelServiceImpl extends Service implements RemoteExcelServic // } // // @Override -// public List findProperData(String dataId, String fieldId, String fieldType, Map extendParam, SimpleEmployee employee) { +// public List findProperData(String dataId, String fieldId, String fieldType, Map extendParam, DataCollectionEmployee employee) { // return null; // } // // @Override -// public List choose(String sourceId, List filterFormDataList, Map extendParam, SimpleEmployee employee) { +// public List choose(String sourceId, List filterFormDataList, Map extendParam, DataCollectionEmployee employee) { // return null; // } // //// @Override // public List vlookups(String sourceId, List filterFormDataList, List returnFields, Map extendParam, -// SimpleEmployee employee) { +// DataCollectionEmployee employee) { // log.info("sourceId: {}, filterFormDataList: {}, returnFields: {}", sourceId, JsonUtil.toJsonString(filterFormDataList), JsonUtil.toJsonString(returnFields)); // Map columnMap = Maps.newHashMap(); // for (Field declaredField : SalaryFormulaTaxRateDTO.class.getDeclaredFields()) { @@ -257,12 +257,12 @@ public class RemoteExcelServiceImpl extends Service implements RemoteExcelServic // } // // @Override -// public Map findSourceName(String Module, List idList, Map extendParam, SimpleEmployee employee) { +// public Map findSourceName(String Module, List idList, Map extendParam, DataCollectionEmployee employee) { // return null; // } // //// @Override -//// public List getFieldData(String dataId, List fieldIds, SimpleEmployee employee) { +//// public List getFieldData(String dataId, List fieldIds, DataCollectionEmployee employee) { //// return null; //// } // diff --git a/src/com/engine/salary/service/impl/SalaryAcctExcelServiceImpl.java b/src/com/engine/salary/service/impl/SalaryAcctExcelServiceImpl.java index 11bb3bd78..9ffd25384 100644 --- a/src/com/engine/salary/service/impl/SalaryAcctExcelServiceImpl.java +++ b/src/com/engine/salary/service/impl/SalaryAcctExcelServiceImpl.java @@ -1129,8 +1129,8 @@ public class SalaryAcctExcelServiceImpl extends Service implements SalaryAcctExc // return excelSheetData; // } // List employeeIds = SalaryEntityUtil.properties(salaryCheckResultRecords, SalaryCheckResultRecordPO::getEmployeeId, Collectors.toList()); -// List simpleEmployees = hrmCommonEmployeeService.getEmployeeByIds(employeeIds); -// Map simpleEmployeeMap = SalaryEntityUtil.convert2Map(simpleEmployees, SimpleEmployee::getEmployeeId, SimpleEmployee::getUsername); +// List simpleEmployees = hrmCommonEmployeeService.getEmployeeByIds(employeeIds); +// Map simpleEmployeeMap = SalaryEntityUtil.convert2Map(simpleEmployees, DataCollectionEmployee::getEmployeeId, DataCollectionEmployee::getUsername); // List expressFormulas = getSalaryFormulaService(user).listExpressFormula(Collections.singleton(checkResult.getFormulaId())); // Map formulaMap = SalaryEntityUtil.convert2Map(expressFormulas, ExpressFormula::getId, ExpressFormula::getFormula); // for (SalaryCheckResultRecordPO salaryCheckResultRecord : salaryCheckResultRecords) { diff --git a/src/com/engine/salary/service/impl/SalarySendServiceImpl.java b/src/com/engine/salary/service/impl/SalarySendServiceImpl.java index 01bfb5162..d2672d07c 100644 --- a/src/com/engine/salary/service/impl/SalarySendServiceImpl.java +++ b/src/com/engine/salary/service/impl/SalarySendServiceImpl.java @@ -1014,13 +1014,13 @@ public class SalarySendServiceImpl extends Service implements SalarySendService // // // 获取所有人员信息 // List ids = enableSendList.stream().map(e->Long.valueOf(e.get("employeeId").toString())).collect(Collectors.toList()); -// List allEmployees = hrmCommonEmployeeService.getEmployeeByIds(ids, currentTenantKey); +// List allEmployees = hrmCommonEmployeeService.getEmployeeByIds(ids, currentTenantKey); // List listDTOS = JSONArray.parseArray(salaryTemplate.getSalaryItemSetting(), SalaryTemplateSalaryItemSetListDTO.class); // Optional optionalEmployeeInformation = listDTOS.stream().filter(e -> SalaryTemplateSalaryItemSetGroupConstant.EMPLOYEE_INFO_GROUP_ID.equals(e.getGroupId())).findFirst(); // SalaryTemplateSalaryItemSetListDTO employeeInformation = optionalEmployeeInformation.orElse(null); // Map employeeField = SalaryAcctResultBO.buildEmployeeFieldName(); // enableSendList.forEach(e -> { -// Optional optionalSimpleEmployee = allEmployees.stream().filter(f->f.getEmployeeId().equals(Long.valueOf(e.get("employeeId").toString()))).findFirst(); +// Optional optionalSimpleEmployee = allEmployees.stream().filter(f->f.getEmployeeId().equals(Long.valueOf(e.get("employeeId").toString()))).findFirst(); // if (optionalSimpleEmployee.isPresent()) { // buildEmployeeInfo(employeeInformation, optionalSimpleEmployee.get(), e.get("taxAgent").toString(), employeeField); // } diff --git a/src/com/engine/salary/service/impl/TaxDeclarationDetailServiceImpl.java b/src/com/engine/salary/service/impl/TaxDeclarationDetailServiceImpl.java index 1bf1bc94c..ec95ac03b 100644 --- a/src/com/engine/salary/service/impl/TaxDeclarationDetailServiceImpl.java +++ b/src/com/engine/salary/service/impl/TaxDeclarationDetailServiceImpl.java @@ -111,7 +111,7 @@ public class TaxDeclarationDetailServiceImpl extends Service implements TaxDecla List taxDeclarationDetailPOS = listByTaxDeclarationIdAndEmployeeIds(queryParam.getTaxDeclarationId(), employeeIdPage); // 查询人员 List simpleEmployees = getSalaryEmployeeService().listByIds(employeeIdPage); - // List simpleEmployees = hrmCommonEmployeeService.getEmployeeByIds(employeeIdPage.getRecords(), tenantKey); + // List simpleEmployees = hrmCommonEmployeeService.getEmployeeByIds(employeeIdPage.getRecords(), tenantKey); // 转换成列表dto TaxDeclarationBO.buildDetailListDTO(queryParam.getTaxDeclarationId(), dtoPage, taxDeclarationDetailPOS, simpleEmployees); } diff --git a/src/com/engine/salary/util/SalaryI18nUtil.java b/src/com/engine/salary/util/SalaryI18nUtil.java index a28a7124d..f7d9272ce 100644 --- a/src/com/engine/salary/util/SalaryI18nUtil.java +++ b/src/com/engine/salary/util/SalaryI18nUtil.java @@ -32,7 +32,7 @@ public class SalaryI18nUtil { // */ // public static String getI18nLabel(String tenantKey, Long employeeId, int labelId, String defaultLabel) { // int languageId = I18nLanguageUtil.getLangId(employeeId); -// return SystemEnv.getHtmlLabelName(labelId, languageId, tenantKey, defaultLabel); +// return SalaryI18nUtil.getI18nLabel(labelId, languageId, tenantKey, defaultLabel); // } // // /** @@ -43,8 +43,8 @@ public class SalaryI18nUtil { // * @param defaultLabel 默认中文 // * @return // */ -// public static String getI18nLabel(SimpleEmployee simpleEmployee, int labelId, String defaultLabel) { +// public static String getI18nLabel(DataCollectionEmployee simpleEmployee, int labelId, String defaultLabel) { // int languageId = I18nLanguageUtil.getLangId(simpleEmployee.getEmployeeId()); -// return SystemEnv.getHtmlLabelName(labelId, languageId, simpleEmployee.getTenantKey(), defaultLabel); +// return SalaryI18nUtil.getI18nLabel(labelId, languageId, simpleEmployee.getTenantKey(), defaultLabel); // } } diff --git a/src/com/engine/salary/web/SalaryAcctController.java b/src/com/engine/salary/web/SalaryAcctController.java index 51319b339..c1916b13f 100644 --- a/src/com/engine/salary/web/SalaryAcctController.java +++ b/src/com/engine/salary/web/SalaryAcctController.java @@ -606,7 +606,7 @@ public class SalaryAcctController { // @ApiOperation("校验异常导出") // @WeaPermission // public WeaResult> exportCheckResult(@RequestBody @Validated SalaryCheckResultExportParam exportParam) { -// SimpleEmployee simpleEmployee = UserContext.getCurrentUser(); +// DataCollectionEmployee simpleEmployee = UserContext.getCurrentUser(); // String tenantKey = TenantContext.getCurrentTenantKey(); // String eteamsId = TenantRpcContext.getEteamsId(); // Map map = salaryAcctExcelWrapper.exportCheckResult(exportParam, simpleEmployee, tenantKey, eteamsId); @@ -617,7 +617,7 @@ public class SalaryAcctController { // @ApiOperation("校验异常明细导出") // @WeaPermission // public WeaResult> exportCheckResultDetail(@RequestParam(value = "checkResultId") Long checkResultId) { -// SimpleEmployee simpleEmployee = UserContext.getCurrentUser(); +// DataCollectionEmployee simpleEmployee = UserContext.getCurrentUser(); // String tenantKey = TenantContext.getCurrentTenantKey(); // String eteamsId = TenantRpcContext.getEteamsId(); // Map map = salaryAcctExcelWrapper.exportCheckResultDetail(checkResultId, simpleEmployee, tenantKey, eteamsId); diff --git a/src/com/engine/salary/wrapper/OtherDeductionWrapper.java b/src/com/engine/salary/wrapper/OtherDeductionWrapper.java index 8270743ba..2494e6f45 100644 --- a/src/com/engine/salary/wrapper/OtherDeductionWrapper.java +++ b/src/com/engine/salary/wrapper/OtherDeductionWrapper.java @@ -108,7 +108,7 @@ public class OtherDeductionWrapper extends Service { // // //日期范围选项 // List dateOptions = new ArrayList(); -// dateOptions.add(new SearchConditionOption("6", SystemEnv.getHtmlLabelName(32530, user.getLanguage()), true));//指定日期范围(必须为6) +// dateOptions.add(new SearchConditionOption("6", SalaryI18nUtil.getI18nLabel(32530, user.getLanguage()), true));//指定日期范围(必须为6) // SearchConditionItem hiredate = conditionFactory.createCondition(ConditionType.RANGEPICKER, 18648, new String[]{"hiredate", "hiredate"}); // hiredate.setInputType("rangepicker"); // hiredate.setFormat("yyyy-MM-dd"); diff --git a/src/com/engine/salary/wrapper/SalaryAcctExcelWrapper.java b/src/com/engine/salary/wrapper/SalaryAcctExcelWrapper.java index a7fee0472..6c2db9bd7 100644 --- a/src/com/engine/salary/wrapper/SalaryAcctExcelWrapper.java +++ b/src/com/engine/salary/wrapper/SalaryAcctExcelWrapper.java @@ -102,7 +102,7 @@ public class SalaryAcctExcelWrapper extends Service { // * @return // */ // public Map exportCheckResult(SalaryCheckResultExportParam exportParam, -// SimpleEmployee simpleEmployee, String tenantKey, String eteamsId) { +// DataCollectionEmployee simpleEmployee, String tenantKey, String eteamsId) { // ExcelExportParam excelExportParam = new ExcelExportParam() // .setModule(EntityType.hrsa.name()) // .setFunction("salaryCheckResultHandler"); @@ -131,7 +131,7 @@ public class SalaryAcctExcelWrapper extends Service { // * @return // */ // public Map exportCheckResultDetail(Long checkResultId, -// SimpleEmployee simpleEmployee, String tenantKey, String eteamsId) { +// DataCollectionEmployee simpleEmployee, String tenantKey, String eteamsId) { // ExcelExportParam excelExportParam = new ExcelExportParam() // .setModule(EntityType.hrsa.name()) // .setFunction("salaryCheckResultDetailHandler"); diff --git a/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java b/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java index 1b4a210fd..4ddaf69b5 100644 --- a/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java +++ b/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java @@ -263,7 +263,7 @@ public class SalaryAcctResultWrapper extends Service { * @param simpleEmployee 当前登陆人员 * @param tenantKey 租户key */ -// public void check(SalaryAcctCheckParam checkParam, SimpleEmployee simpleEmployee, String tenantKey) { +// public void check(SalaryAcctCheckParam checkParam, DataCollectionEmployee simpleEmployee, String tenantKey) { // // 检查是否正在核算中 // SalaryAcctProgressDTO salaryAcctProgressDTO = salaryAcctProgressService.getProgress("" + checkParam.getSalaryAcctRecordId(), simpleEmployee.getEmployeeId(), tenantKey); // if (Objects.nonNull(salaryAcctProgressDTO) && salaryAcctProgressDTO.isStatus() && Optional.ofNullable(salaryAcctProgressDTO.getProgress()).orElse(BigDecimal.ZERO).compareTo(BigDecimal.ONE) < 0) { From 34f33d21d8f233b83d09b0729b9391c4e7a6361d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Wed, 19 Apr 2023 13:35:35 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../salary/component/SalaryWeaTable.java | 4 +- .../formlua/core/exception/ErrorType.java | 39 +- .../formlua/entity/parameter/DataType.java | 17 +- .../entity/standard/FormulaFilterData.java | 8 +- .../entity/standard/execute/ExclDataType.java | 12 + .../entity/standard/execute/ExclFixField.java | 68 + .../entity/standard/execute/FixFieldType.java | 11 + .../formlua/func/compare/Compareutils.java | 612 ++++----- .../formlua/func/compare/GreaterOperator.java | 2 +- .../formlua/func/compare/LessEqOperator.java | 2 +- .../formlua/func/compare/LessOperator.java | 2 +- .../formlua/func/compare/NotEqueOperator.java | 2 +- .../formlua/func/compare/WOperatorDiv.java | 97 +- .../func/date/DateTimeTestServiceImpl.java | 1208 ----------------- .../func/find/FindFuncsServiceImpl.java | 381 +++--- .../func/find/FindFuncsTestServiceImpl.java | 166 --- .../formlua/func/logic/LogicService.java | 29 +- .../formlua/func/logic/LogicServiceImpl.java | 8 +- .../salary/formlua/func/logic/LogicUtils.java | 1 - .../func/math/MathFuncsServiceImpl.java | 475 ++++--- .../func/math/MathFuncsServiceTestImpl.java | 486 ------- .../string/StringFormulaServiceTestImpl.java | 555 -------- .../engine/salary/formlua/util/DateUtil.java | 2 +- .../salary/formlua/util/ExcelParamUtil.java | 447 +++--- .../formlua/util/ExcelStandardUtil.java | 980 ++++++------- .../salary/formlua/util/ExecuteTest.java | 47 - .../engine/salary/formlua/util/TestUtil.java | 403 ------ .../remote/attend/cmd/GetKQReportCmd.java | 22 +- 28 files changed, 1653 insertions(+), 4433 deletions(-) create mode 100644 src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java create mode 100644 src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java create mode 100644 src/com/engine/salary/formlua/entity/standard/execute/FixFieldType.java delete mode 100644 src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java delete mode 100644 src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java delete mode 100644 src/com/engine/salary/formlua/func/math/MathFuncsServiceTestImpl.java delete mode 100644 src/com/engine/salary/formlua/func/string/StringFormulaServiceTestImpl.java delete mode 100644 src/com/engine/salary/formlua/util/ExecuteTest.java delete mode 100644 src/com/engine/salary/formlua/util/TestUtil.java diff --git a/src/com/engine/salary/component/SalaryWeaTable.java b/src/com/engine/salary/component/SalaryWeaTable.java index 98110f7ce..b4e41a76c 100644 --- a/src/com/engine/salary/component/SalaryWeaTable.java +++ b/src/com/engine/salary/component/SalaryWeaTable.java @@ -56,7 +56,7 @@ public class SalaryWeaTable extends WeaTable { Arrays.stream(operates).forEach(o -> { String text = o.text(); int labelId = o.labelId(); - String htmlLabelName = SalaryI18nUtil.getI18nLabel(labelId, user.getLanguage()); + String htmlLabelName = SystemEnv.getHtmlLabelName(labelId, user.getLanguage()); if (StringUtils.isNotBlank(htmlLabelName)) { text = htmlLabelName; } @@ -86,7 +86,7 @@ public class SalaryWeaTable extends WeaTable { SalaryTableColumn columnAnn = f.getAnnotation(SalaryTableColumn.class); String text = columnAnn.text(); int labelId = columnAnn.labelId(); - String htmlLabelName = SalaryI18nUtil.getI18nLabel(labelId, user.getLanguage()); + String htmlLabelName = SystemEnv.getHtmlLabelName(labelId, user.getLanguage()); if (StringUtils.isNotBlank(htmlLabelName)) { text = htmlLabelName; } diff --git a/src/com/engine/salary/formlua/core/exception/ErrorType.java b/src/com/engine/salary/formlua/core/exception/ErrorType.java index 58f97671a..c165c1964 100644 --- a/src/com/engine/salary/formlua/core/exception/ErrorType.java +++ b/src/com/engine/salary/formlua/core/exception/ErrorType.java @@ -4,66 +4,67 @@ import com.engine.salary.util.SalaryI18nUtil; public enum ErrorType { /** - *函数参数不能为空 + * 函数参数不能为空 */ - NOT_NULL(SalaryI18nUtil.getI18nLabel(91326,"函数参数不能为空")), + NOT_NULL(SalaryI18nUtil.getI18nLabel(91326, "函数参数不能为空")), /** * 参数不能为空 */ - VAR_NOT_NULL(SalaryI18nUtil.getI18nLabel(32804,"参数不能为空")), + VAR_NOT_NULL(SalaryI18nUtil.getI18nLabel(32804, "参数不能为空")), /** - *函数参数错误,参数类型需为数字字段 + * 函数参数错误,参数类型需为数字字段 */ - MUST_NUM(SalaryI18nUtil.getI18nLabel(91327,"函数参数错误,参数类型需为数字字段")), + MUST_NUM(SalaryI18nUtil.getI18nLabel(91327, "函数参数错误,参数类型需为数字字段")), /** - *函数参数类型错误,参数需为表格 + * 函数参数类型错误,参数需为表格 */ - MUST_FORM(SalaryI18nUtil.getI18nLabel(91330,"函数参数类型错误,参数需为表格")), + MUST_FORM(SalaryI18nUtil.getI18nLabel(91330, "函数参数类型错误,参数需为表格")), /** * */ - MUST_FORM_FIELD(SalaryI18nUtil.getI18nLabel(91331,"函数参数错误,参数类型需为表格字段")), - CANT_FORM_FIELD(SalaryI18nUtil.getI18nLabel(91427,"比较操作符参数不能是表格字段")), + MUST_FORM_FIELD(SalaryI18nUtil.getI18nLabel(91331, "函数参数错误,参数类型需为表格字段")), + CANT_FORM_FIELD(SalaryI18nUtil.getI18nLabel(91427, "比较操作符参数不能是表格字段")), /** * */ - CND_NOT_NULL(SalaryI18nUtil.getI18nLabel(11575,"条件不能为空")), + CND_NOT_NULL(SalaryI18nUtil.getI18nLabel(11575, "条件不能为空")), /** * */ - MIN_VAR_COUNT(SalaryI18nUtil.getI18nLabel(91332,"函数的最少参数个数")), + MIN_VAR_COUNT(SalaryI18nUtil.getI18nLabel(91332, "函数的最少参数个数")), /** * */ - MAX_VAR_COUNT(SalaryI18nUtil.getI18nLabel(91333,"函数的最多参数个数")), + MAX_VAR_COUNT(SalaryI18nUtil.getI18nLabel(91333, "函数的最多参数个数")), /** * */ - CANNOT_HAVE_VAR(SalaryI18nUtil.getI18nLabel(91334,"函数不能有参数")), + CANNOT_HAVE_VAR(SalaryI18nUtil.getI18nLabel(91334, "函数不能有参数")), /** * */ - RETURN_TYPE_DIFF(SalaryI18nUtil.getI18nLabel(91335,"函数多个条件的返回值必须一致")), + RETURN_TYPE_DIFF(SalaryI18nUtil.getI18nLabel(91335, "函数多个条件的返回值必须一致")), /** * */ - VAR_COUNT_MUST_Odd(SalaryI18nUtil.getI18nLabel(91336,"函数最后一个参数需为默认返回值")), + VAR_COUNT_MUST_Odd(SalaryI18nUtil.getI18nLabel(91336, "函数最后一个参数需为默认返回值")), /** * */ - VAR_TYPE_WRONG(SalaryI18nUtil.getI18nLabel(91337,"函数参数类型错误")), + VAR_TYPE_WRONG(SalaryI18nUtil.getI18nLabel(91337, "函数参数类型错误")), /** * */ - VAR_MUST_HAVE_DATE(SalaryI18nUtil.getI18nLabel(91338,"函数日期参数必须包含年月日")), + VAR_MUST_HAVE_DATE(SalaryI18nUtil.getI18nLabel(91338, "函数日期参数必须包含年月日")), /** * */ - VAR_TYPE_MUST_BE(SalaryI18nUtil.getI18nLabel(91339,"函数参数类型错误,参数类型需为")), + VAR_TYPE_MUST_BE(SalaryI18nUtil.getI18nLabel(91339, "函数参数类型错误,参数类型需为")), /** * */ - CANNOT_FIND_TEN(SalaryI18nUtil.getI18nLabel(91361,"函数未能获取到租户")); + CANNOT_FIND_TEN(SalaryI18nUtil.getI18nLabel(91361, "函数未能获取到租户")); + ErrorType(String name) { } } diff --git a/src/com/engine/salary/formlua/entity/parameter/DataType.java b/src/com/engine/salary/formlua/entity/parameter/DataType.java index 275e7d8f3..f049136a6 100644 --- a/src/com/engine/salary/formlua/entity/parameter/DataType.java +++ b/src/com/engine/salary/formlua/entity/parameter/DataType.java @@ -1,6 +1,7 @@ package com.engine.salary.formlua.entity.parameter; import com.engine.salary.entity.datacollection.DataCollectionEmployee; +import com.engine.salary.formlua.entity.standard.FormulaFilterData; import java.io.Serializable; import java.util.ArrayList; @@ -79,7 +80,7 @@ public class DataType implements Serializable { /** * 高级搜索条件,由函数的逻辑操作符和逻辑函数构建,模块不需要处理 */ -// List formulaFilterDataList=null; + List formulaFilterDataList=null; private List subLogic=new ArrayList<>(); public static boolean checkType(String dataTypeL,String dataTypeR){ if(returnType(dataTypeL).equalsIgnoreCase(dataTypeR)){ @@ -268,11 +269,11 @@ public class DataType implements Serializable { this.subFormData = subFormData; } -// public List getFormulaFilterDataList() { -// return formulaFilterDataList; -// } -// -// public void setFormulaFilterDataList(List formulaFilterDataList) { -// this.formulaFilterDataList = formulaFilterDataList; -// } + public List getFormulaFilterDataList() { + return formulaFilterDataList; + } + + public void setFormulaFilterDataList(List formulaFilterDataList) { + this.formulaFilterDataList = formulaFilterDataList; + } } diff --git a/src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java b/src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java index 06531e13f..a27498278 100644 --- a/src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java +++ b/src/com/engine/salary/formlua/entity/standard/FormulaFilterData.java @@ -1,9 +1,5 @@ package com.engine.salary.formlua.entity.standard; -import com.weaver.common.form.stat.FilterFormData; -import com.weaver.common.form.stat.domain.search.FilterFormDataIds; -import com.weaver.teams.domain.entity.BaseEntity; - import java.io.Serializable; import java.util.List; @@ -56,7 +52,7 @@ public class FormulaFilterData implements Serializable { * 选项条件的值 */ private List ids; - private List children; +// private List children; private List contents; private List idObjects; private String dateType; @@ -75,7 +71,7 @@ public class FormulaFilterData implements Serializable { private List selectIds; private String format; private boolean isFixed; - private List filterFormDataIdsList; +// private List filterFormDataIdsList; public String getFieldId() { return fieldId; diff --git a/src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java b/src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java new file mode 100644 index 000000000..a249eb261 --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java @@ -0,0 +1,12 @@ +package com.engine.salary.formlua.entity.standard.execute; + +/** + * @author 罗威 + */ + +public enum ExclDataType { + text("文本类型"),integral("整数类型"),decimal("小数类型"),datasource("数据源或选项类型"),bool("布尔类型"); + + ExclDataType(String name) { + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java b/src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java new file mode 100644 index 000000000..5b34bf6fd --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java @@ -0,0 +1,68 @@ +package com.engine.salary.formlua.entity.standard.execute; + +/** + * 固定字段标准类 + * @author 罗威 + */ +public class ExclFixField { + /** + * 固定字段或系统字段的类属性名 + */ + private String properName; + /** + * 数据类型 + */ + private ExclDataType exclDataType; + /** + * 固定字段或系统字段的值 + */ + private Object value; + /** + * 所属来源数据的ID + */ + private String sourceId; + /** + * 所属模块 + */ + private String module; + + public String getProperName() { + return properName; + } + + public void setProperName(String properName) { + this.properName = properName; + } + + public ExclDataType getExclDataType() { + return exclDataType; + } + + public void setExclDataType(ExclDataType exclDataType) { + this.exclDataType = exclDataType; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public String getSourceId() { + return sourceId; + } + + public void setSourceId(String sourceId) { + this.sourceId = sourceId; + } + + public String getModule() { + return module; + } + + public void setModule(String module) { + this.module = module; + } +} diff --git a/src/com/engine/salary/formlua/entity/standard/execute/FixFieldType.java b/src/com/engine/salary/formlua/entity/standard/execute/FixFieldType.java new file mode 100644 index 000000000..fcfcca5ee --- /dev/null +++ b/src/com/engine/salary/formlua/entity/standard/execute/FixFieldType.java @@ -0,0 +1,11 @@ +package com.engine.salary.formlua.entity.standard.execute; + +/** + * 固定字段分类 + */ +public enum FixFieldType { + Text("文本型"),Num("数字型"),Relate("关联型"),Select("选项型"),Employee("人员"),Department("部门"); + + FixFieldType(String name) { + } +} diff --git a/src/com/engine/salary/formlua/func/compare/Compareutils.java b/src/com/engine/salary/formlua/func/compare/Compareutils.java index 7c38fe2d0..086817cfa 100644 --- a/src/com/engine/salary/formlua/func/compare/Compareutils.java +++ b/src/com/engine/salary/formlua/func/compare/Compareutils.java @@ -1,310 +1,310 @@ -package com.engine.salary.formlua.func.compare; - -import com.alibaba.fastjson.JSON; -import com.engine.salary.formlua.entity.parameter.DataType; -import com.engine.salary.formlua.entity.standard.FormulaFilterData; -import com.weaver.common.form.component.base.ComponentConfig; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.common.form.excel.validator.Validator; -import com.weaver.common.form.metadata.field.FormField; -import com.weaver.common.form.stat.FilterFormData; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; - -/** - * 逻辑操作符的条件构建工具类 - */ -public class Compareutils { - protected static final Logger logger = LoggerFactory.getLogger(Compareutils.class); - - /** - * 构建不等于操作符的搜索条件 - * - * @param dataType - * @param obj1 - * @param obj2 - * @throws Exception - */ - public static void buildNotEqFilterParam(DataType dataType, Object obj1, Object obj2) throws Exception { - List filterFormDataList = new ArrayList<>(); - FormulaFilterData filterData = new FormulaFilterData(); - String content = null; - try { - if (obj1 instanceof DataType) { - DataType dataType1 = (DataType) obj1; - if (StringUtils.isEmpty(dataType1.getComponentKey())) { - dataType1.setComponentKey(dataType1.getDataType()); - } - if (obj2 instanceof DataType) { -// content = ((DataType) obj2).getContent()+""; - DataType paramDataType = (DataType) obj2; - if (paramDataType == null || paramDataType.getContent() == null) { - content = ""; - } else { - content = paramDataType.getContent() + ""; - } - } else { - content = obj2 + ""; - } - if (content != null) { - String componentKey = dataType1.getComponentKey(); - filterData.setFieldId(dataType1.getFieldId()); - if (dataType1.getSubFormId() != null) { - filterData.setSubFormId(dataType1.getSubFormId() + ""); - } - filterData.setComponentKey(componentKey); - if (StringUtils.isEmpty(content)) { -// filterData.setTerm(FilterFormData.TERM_NOT_NULL); - } else { -// //选项控件 -// if (ComponentConfig.isOptionComponent(componentKey)) { -// filterData.setTerm(FilterFormData.TERM_NOT_EQ); -// List ids = new ArrayList<>(); -// String[] idsArray = content.split(","); -// for (String idStr : idsArray) { -// if (StringUtils.isNotBlank(idStr)) { -// ids.add(idStr); -// } -// } -// filterData.setIds(ids); -// //其他 -// } else { -// filterData.setTerm(FilterFormData.TERM_NOT_EQ); -// filterData.setContent(content); -//// if(ComponentConfig.isNumberComponent(dataType1.getComponentKey()) || dataType1.getComponentKey().equalsIgnoreCase(DataType.NUMBER)){ -//// if(StringUtils.isEmpty(content)){ -//// filterData.setContent("0"); +//package com.engine.salary.formlua.func.compare; +// +//import com.alibaba.fastjson.JSON; +//import com.engine.salary.formlua.entity.parameter.DataType; +//import com.engine.salary.formlua.entity.standard.FormulaFilterData; +//import com.weaver.common.form.component.base.ComponentConfig; +//import com.weaver.common.form.component.base.ComponentType; +//import com.weaver.common.form.excel.validator.Validator; +//import com.weaver.common.form.metadata.field.FormField; +//import com.weaver.common.form.stat.FilterFormData; +//import org.apache.commons.lang3.StringUtils; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.util.ArrayList; +//import java.util.List; +// +///** +// * 逻辑操作符的条件构建工具类 +// */ +//public class Compareutils { +// protected static final Logger logger = LoggerFactory.getLogger(Compareutils.class); +// +// /** +// * 构建不等于操作符的搜索条件 +// * +// * @param dataType +// * @param obj1 +// * @param obj2 +// * @throws Exception +// */ +// public static void buildNotEqFilterParam(DataType dataType, Object obj1, Object obj2) throws Exception { +// List filterFormDataList = new ArrayList<>(); +// FormulaFilterData filterData = new FormulaFilterData(); +// String content = null; +// try { +// if (obj1 instanceof DataType) { +// DataType dataType1 = (DataType) obj1; +// if (StringUtils.isEmpty(dataType1.getComponentKey())) { +// dataType1.setComponentKey(dataType1.getDataType()); +// } +// if (obj2 instanceof DataType) { +//// content = ((DataType) obj2).getContent()+""; +// DataType paramDataType = (DataType) obj2; +// if (paramDataType == null || paramDataType.getContent() == null) { +// content = ""; +// } else { +// content = paramDataType.getContent() + ""; +// } +// } else { +// content = obj2 + ""; +// } +// if (content != null) { +// String componentKey = dataType1.getComponentKey(); +// filterData.setFieldId(dataType1.getFieldId()); +// if (dataType1.getSubFormId() != null) { +// filterData.setSubFormId(dataType1.getSubFormId() + ""); +// } +// filterData.setComponentKey(componentKey); +// if (StringUtils.isEmpty(content)) { +//// filterData.setTerm(FilterFormData.TERM_NOT_NULL); +// } else { +//// //选项控件 +//// if (ComponentConfig.isOptionComponent(componentKey)) { +//// filterData.setTerm(FilterFormData.TERM_NOT_EQ); +//// List ids = new ArrayList<>(); +//// String[] idsArray = content.split(","); +//// for (String idStr : idsArray) { +//// if (StringUtils.isNotBlank(idStr)) { +//// ids.add(idStr); //// } //// } +//// filterData.setIds(ids); +//// //其他 +//// } else { +//// filterData.setTerm(FilterFormData.TERM_NOT_EQ); +//// filterData.setContent(content); +////// if(ComponentConfig.isNumberComponent(dataType1.getComponentKey()) || dataType1.getComponentKey().equalsIgnoreCase(DataType.NUMBER)){ +////// if(StringUtils.isEmpty(content)){ +////// filterData.setContent("0"); +////// } +////// } +//// } +// } +// } +// filterFormDataList.add(filterData); +//// dataType.setFormulaFilterDataList(filterFormDataList); +// dataType.setComponentKey(dataType1.getComponentKey()); +// dataType.setSubFormId(dataType1.getSubFormId()); +// } +// } catch (Exception e) { +// logger.error("err", e); +// } +// +// } +// +// /** +// * 构建大于、小于、大于等于、小于等于的搜索条件 +// * +// * @param dataType +// * @param name +// * @param obj1 +// * @param obj2 +// */ +// public static void buildLessMoreFilterParam(DataType dataType, String name, Object obj1, Object obj2) { +// List filterFormDataList = new ArrayList<>(); +// FormulaFilterData filterData = new FormulaFilterData(); +// try { +// logger.info(name + "执行结果:" + JSON.toJSONString(dataType)); +// if (obj1 instanceof DataType) { +// DataType dataType1 = (DataType) obj1; +// if (StringUtils.isEmpty(dataType1.getComponentKey())) { +// dataType1.setComponentKey(dataType1.getDataType()); +// } +// String content = null; +// if (obj2 instanceof DataType) { +//// content = ((DataType) obj2).getContent()+""; +// DataType paramDataType = (DataType) obj2; +// if (paramDataType == null || paramDataType.getContent() == null) { +// content = ""; +// } else { +// content = paramDataType.getContent() + ""; +// } +// } else { +// content = obj2 + ""; +// } +// if (content != null) { +// String componentKey = dataType1.getComponentKey(); +// if (ComponentConfig.isNumberComponent(componentKey) +// || componentKey.equals(ComponentType.DateComponent.toString()) +// || componentKey.equals(ComponentType.TimeComponent.toString()) +// || dataType1.getComponentKey().equalsIgnoreCase(DataType.STRING) +// || dataType1.getComponentKey().equalsIgnoreCase(DataType.NUMBER) +// || dataType1.getComponentKey().equalsIgnoreCase(DataType.STRING) +// || dataType1.getComponentKey().equalsIgnoreCase(DataType.BOOL)) { +// +// filterData.setFieldId(dataType1.getFieldId() + ""); +// if (dataType1.getSubFormId() != null) { +// filterData.setSubFormId(dataType1.getSubFormId() + ""); // } - } - } - filterFormDataList.add(filterData); +// filterData.setComponentKey(componentKey); +// switch (name) { +// case ">=": +// filterData.setTerm(FilterFormData.TERM_GE); +// break; +// case ">": +// filterData.setTerm(FilterFormData.TERM_GT); +// break; +// case "<=": +// filterData.setTerm(FilterFormData.TERM_LE); +// break; +// case "<": +// filterData.setTerm(FilterFormData.TERM_LT); +// break; +// default: +// break; +// } +// filterData.setContent(content); +// } +// } +// filterFormDataList.add(filterData); // dataType.setFormulaFilterDataList(filterFormDataList); - dataType.setComponentKey(dataType1.getComponentKey()); - dataType.setSubFormId(dataType1.getSubFormId()); - } - } catch (Exception e) { - logger.error("err", e); - } - - } - - /** - * 构建大于、小于、大于等于、小于等于的搜索条件 - * - * @param dataType - * @param name - * @param obj1 - * @param obj2 - */ - public static void buildLessMoreFilterParam(DataType dataType, String name, Object obj1, Object obj2) { - List filterFormDataList = new ArrayList<>(); - FormulaFilterData filterData = new FormulaFilterData(); - try { - logger.info(name + "执行结果:" + JSON.toJSONString(dataType)); - if (obj1 instanceof DataType) { - DataType dataType1 = (DataType) obj1; - if (StringUtils.isEmpty(dataType1.getComponentKey())) { - dataType1.setComponentKey(dataType1.getDataType()); - } - String content = null; - if (obj2 instanceof DataType) { -// content = ((DataType) obj2).getContent()+""; - DataType paramDataType = (DataType) obj2; - if (paramDataType == null || paramDataType.getContent() == null) { - content = ""; - } else { - content = paramDataType.getContent() + ""; - } - } else { - content = obj2 + ""; - } - if (content != null) { - String componentKey = dataType1.getComponentKey(); - if (ComponentConfig.isNumberComponent(componentKey) - || componentKey.equals(ComponentType.DateComponent.toString()) - || componentKey.equals(ComponentType.TimeComponent.toString()) - || dataType1.getComponentKey().equalsIgnoreCase(DataType.STRING) - || dataType1.getComponentKey().equalsIgnoreCase(DataType.NUMBER) - || dataType1.getComponentKey().equalsIgnoreCase(DataType.STRING) - || dataType1.getComponentKey().equalsIgnoreCase(DataType.BOOL)) { - - filterData.setFieldId(dataType1.getFieldId() + ""); - if (dataType1.getSubFormId() != null) { - filterData.setSubFormId(dataType1.getSubFormId() + ""); - } - filterData.setComponentKey(componentKey); - switch (name) { - case ">=": - filterData.setTerm(FilterFormData.TERM_GE); - break; - case ">": - filterData.setTerm(FilterFormData.TERM_GT); - break; - case "<=": - filterData.setTerm(FilterFormData.TERM_LE); - break; - case "<": - filterData.setTerm(FilterFormData.TERM_LT); - break; - default: - break; - } - filterData.setContent(content); - } - } - filterFormDataList.add(filterData); - dataType.setFormulaFilterDataList(filterFormDataList); - dataType.setComponentKey(dataType1.getComponentKey()); - dataType.setSubFormId(dataType1.getSubFormId()); - } - } catch (Exception e) { - logger.error("err", e); - } - - } - - /** - * 校验大于、小于、小于等于、大于等于操作符的入参 - * - * @param name - * @param obj1 - * @param obj2 - * @return - */ - public static boolean checkLessMoreParam(String name, Object obj1, Object obj2) { - if (obj1 instanceof FormField) { - String componentKey = ((FormField) obj1).getComponentKey(); - if (ComponentConfig.isNumberComponent(componentKey)) { - if (obj2 instanceof Number) { - return true; - } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { - return true; - } else { - throw new RuntimeException("筛选条件[" + name + "]:数字控件右边必须是数字"); - } - } - if (componentKey.equals(ComponentType.DateComponent.toString())) { - if (obj2 instanceof String && Validator.isDate((String) obj2)) { - return true; - } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { - return true; - } else { - throw new RuntimeException("筛选条件[" + name + "]:日期控件右边必须是日期字符串"); - } - - } - if (componentKey.equals(ComponentType.TimeComponent.toString())) { - if (obj2 instanceof String && Validator.isTime((String) obj2)) { - return true; - } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { - return true; - } else { - throw new RuntimeException("筛选条件[" + name + "]:时间控件右边必须是时间字符串"); - } - } - } - throw new RuntimeException("筛选条件[" + name + "]:左边必须是数字控件或时间控件"); - } - - /** - * 校验等于号的入参 - * - * @param obj1 - * @param obj2 - * @return - */ - public static boolean checkEqParam(Object obj1, Object obj2) { - if (obj1 instanceof DataType) { - String componentKey = ((FormField) obj1).getComponentKey(); - if (ComponentConfig.isNumberComponent(componentKey)) { - if (obj2 instanceof DataType) { - if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { - return true; - } else { - throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); - } - } else if (StringUtils.isEmpty(obj2 + "") || Validator.isFloat(obj2 + "")) { - return true; - } else { - throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); - } - } else if (ComponentConfig.isOptionComponent(componentKey)) { - if (StringUtils.isEmpty(obj2 + "") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { - return true; - } else { - throw new RuntimeException("筛选条件[=]:选项控件右边必须是选项"); - } - } else { - if (StringUtils.isEmpty(obj2 + "") || obj2 instanceof String || obj2 instanceof Character) { - return true; - } else if (obj2 instanceof DataType) { - if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { - return true; - } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { - return true; - } else { - throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); - } - } else { - throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); - } - } - } - throw new RuntimeException("筛选条件[=]:左边必须是表单控件"); - } - - /** - * 校验不等于号的入参 - * - * @param obj1 - * @param obj2 - * @return - */ - public static boolean checkNotEqParam(Object obj1, Object obj2) { - if (obj1 instanceof FormField) { - String componentKey = ((FormField) obj1).getComponentKey(); - if (ComponentConfig.isNumberComponent(componentKey)) { - if (obj2 instanceof DataType) { - if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { - return true; - } else { - throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); - } - } else if (StringUtils.isEmpty(obj2 + "") || Validator.isFloat(obj2 + "")) { - return true; - } else { - throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); - } - } else if (ComponentConfig.isOptionComponent(componentKey)) { - if (StringUtils.isEmpty(obj2 + "") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { - return true; - } else { - throw new RuntimeException("筛选条件[!=]:选项控件右边必须是选项"); - } - } else { - if (StringUtils.isEmpty(obj2 + "") || obj2 instanceof String || obj2 instanceof Character) { - return true; - } else if (obj2 instanceof DataType) { - if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { - return true; - } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { - return true; - } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { - return true; - } else { - throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); - } - } else { - throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); - } - } - } - throw new RuntimeException("筛选条件[!=]:左边必须是表单控件"); - } -} +// dataType.setComponentKey(dataType1.getComponentKey()); +// dataType.setSubFormId(dataType1.getSubFormId()); +// } +// } catch (Exception e) { +// logger.error("err", e); +// } +// +// } +// +// /** +// * 校验大于、小于、小于等于、大于等于操作符的入参 +// * +// * @param name +// * @param obj1 +// * @param obj2 +// * @return +// */ +// public static boolean checkLessMoreParam(String name, Object obj1, Object obj2) { +// if (obj1 instanceof FormField) { +// String componentKey = ((FormField) obj1).getComponentKey(); +// if (ComponentConfig.isNumberComponent(componentKey)) { +// if (obj2 instanceof Number) { +// return true; +// } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[" + name + "]:数字控件右边必须是数字"); +// } +// } +// if (componentKey.equals(ComponentType.DateComponent.toString())) { +// if (obj2 instanceof String && Validator.isDate((String) obj2)) { +// return true; +// } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[" + name + "]:日期控件右边必须是日期字符串"); +// } +// +// } +// if (componentKey.equals(ComponentType.TimeComponent.toString())) { +// if (obj2 instanceof String && Validator.isTime((String) obj2)) { +// return true; +// } else if (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[" + name + "]:时间控件右边必须是时间字符串"); +// } +// } +// } +// throw new RuntimeException("筛选条件[" + name + "]:左边必须是数字控件或时间控件"); +// } +// +// /** +// * 校验等于号的入参 +// * +// * @param obj1 +// * @param obj2 +// * @return +// */ +// public static boolean checkEqParam(Object obj1, Object obj2) { +// if (obj1 instanceof DataType) { +// String componentKey = ((FormField) obj1).getComponentKey(); +// if (ComponentConfig.isNumberComponent(componentKey)) { +// if (obj2 instanceof DataType) { +// if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); +// } +// } else if (StringUtils.isEmpty(obj2 + "") || Validator.isFloat(obj2 + "")) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[=]:数字控件右边必须是数字"); +// } +// } else if (ComponentConfig.isOptionComponent(componentKey)) { +// if (StringUtils.isEmpty(obj2 + "") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[=]:选项控件右边必须是选项"); +// } +// } else { +// if (StringUtils.isEmpty(obj2 + "") || obj2 instanceof String || obj2 instanceof Character) { +// return true; +// } else if (obj2 instanceof DataType) { +// if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { +// return true; +// } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); +// } +// } else { +// throw new RuntimeException("筛选条件[=]:文本控件右边必须是字符"); +// } +// } +// } +// throw new RuntimeException("筛选条件[=]:左边必须是表单控件"); +// } +// +// /** +// * 校验不等于号的入参 +// * +// * @param obj1 +// * @param obj2 +// * @return +// */ +// public static boolean checkNotEqParam(Object obj1, Object obj2) { +// if (obj1 instanceof FormField) { +// String componentKey = ((FormField) obj1).getComponentKey(); +// if (ComponentConfig.isNumberComponent(componentKey)) { +// if (obj2 instanceof DataType) { +// if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.NUMBER)) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); +// } +// } else if (StringUtils.isEmpty(obj2 + "") || Validator.isFloat(obj2 + "")) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[!=]:数字控件右边必须是数字"); +// } +// } else if (ComponentConfig.isOptionComponent(componentKey)) { +// if (StringUtils.isEmpty(obj2 + "") || (obj2 instanceof DataType && ((DataType) obj2).getDataType().equalsIgnoreCase(DataType.OPTION))) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[!=]:选项控件右边必须是选项"); +// } +// } else { +// if (StringUtils.isEmpty(obj2 + "") || obj2 instanceof String || obj2 instanceof Character) { +// return true; +// } else if (obj2 instanceof DataType) { +// if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { +// return true; +// } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { +// return true; +// } else if (((DataType) obj2).getDataType().equalsIgnoreCase(DataType.STRING)) { +// return true; +// } else { +// throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); +// } +// } else { +// throw new RuntimeException("筛选条件[!=]:文本控件右边必须是字符"); +// } +// } +// } +// throw new RuntimeException("筛选条件[!=]:左边必须是表单控件"); +// } +//} diff --git a/src/com/engine/salary/formlua/func/compare/GreaterOperator.java b/src/com/engine/salary/formlua/func/compare/GreaterOperator.java index ba9f3050b..21df856fc 100644 --- a/src/com/engine/salary/formlua/func/compare/GreaterOperator.java +++ b/src/com/engine/salary/formlua/func/compare/GreaterOperator.java @@ -91,7 +91,7 @@ public class GreaterOperator extends OperatorEqualsLessMore { logger.error("err", e); result.setContent(false); } - Compareutils.buildLessMoreFilterParam(result, this.name, op1, op2); +// Compareutils.buildLessMoreFilterParam(result, this.name, op1, op2); return result; } diff --git a/src/com/engine/salary/formlua/func/compare/LessEqOperator.java b/src/com/engine/salary/formlua/func/compare/LessEqOperator.java index 13e0815d6..46ddcc38c 100644 --- a/src/com/engine/salary/formlua/func/compare/LessEqOperator.java +++ b/src/com/engine/salary/formlua/func/compare/LessEqOperator.java @@ -89,7 +89,7 @@ public class LessEqOperator extends OperatorEqualsLessMore { logger.error("err",e); result.setContent(false); } - Compareutils.buildLessMoreFilterParam(result,this.name,op1,op2); +// Compareutils.buildLessMoreFilterParam(result,this.name,op1,op2); return result; } diff --git a/src/com/engine/salary/formlua/func/compare/LessOperator.java b/src/com/engine/salary/formlua/func/compare/LessOperator.java index 5d5348889..ffe6b6b0c 100644 --- a/src/com/engine/salary/formlua/func/compare/LessOperator.java +++ b/src/com/engine/salary/formlua/func/compare/LessOperator.java @@ -89,7 +89,7 @@ public class LessOperator extends OperatorEqualsLessMore { logger.error("err",e); result.setContent(false); } - Compareutils.buildLessMoreFilterParam(result,this.name,op1,op2); +// Compareutils.buildLessMoreFilterParam(result,this.name,op1,op2); return result; } diff --git a/src/com/engine/salary/formlua/func/compare/NotEqueOperator.java b/src/com/engine/salary/formlua/func/compare/NotEqueOperator.java index 5b34a14bf..188e4812e 100644 --- a/src/com/engine/salary/formlua/func/compare/NotEqueOperator.java +++ b/src/com/engine/salary/formlua/func/compare/NotEqueOperator.java @@ -88,7 +88,7 @@ public class NotEqueOperator extends OperatorEqualsLessMore { logger.error("err", e); result.setContent(false); } - Compareutils.buildNotEqFilterParam(result, op1, op2); +// Compareutils.buildNotEqFilterParam(result, op1, op2); return result; } diff --git a/src/com/engine/salary/formlua/func/compare/WOperatorDiv.java b/src/com/engine/salary/formlua/func/compare/WOperatorDiv.java index 85b8c8be4..d4d612bf8 100644 --- a/src/com/engine/salary/formlua/func/compare/WOperatorDiv.java +++ b/src/com/engine/salary/formlua/func/compare/WOperatorDiv.java @@ -1,9 +1,9 @@ package com.engine.salary.formlua.func.compare; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.util.ExcelParamUtil; import com.ql.util.express.instruction.op.OperatorMultiDiv; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.util.ExcelParamUtil; -import com.weaver.teams.util.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,50 +17,51 @@ import java.util.List; * @date: */ public class WOperatorDiv extends OperatorMultiDiv { - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Override - public Object executeInner(Object[] list) throws Exception { - DataType result=new DataType(); - result.setDataType(DataType.NUMBER); - Object[] newList=new Object[2]; -// IgnoreParamFilter.checkNumberOper(list,"/"); - Object firstParam= ExcelParamUtil.getParamContent(list[0],""); - Object secondParam=ExcelParamUtil.getParamContent(list[1],""); - if(StringUtils.isEmpty(firstParam+"") || StringUtils.isEmpty(secondParam+"")){ - result.setContent(0); - return result; - }else if(firstParam.toString().equalsIgnoreCase("0") || secondParam.toString().equalsIgnoreCase("0")){ - result.setContent(0); - return result; - } - if(firstParam instanceof Object[] || secondParam instanceof Object[]){ - try { - List operList= CommonOper.operDivMultiList(firstParam,secondParam,"/"); - Object[] results=new Object[operList.size()]; - for (int i=0;i operList = CommonOper.operDivMultiList(firstParam, secondParam, "/"); + Object[] results = new Object[operList.size()]; + for (int i = 0; i < operList.size(); i++) { + Object[] excuteArray = operList.get(i); + results[i] = super.executeInner(excuteArray); + } + return results; + } catch (Exception e) { + logger.error("err", e); + return 0; + } + } + newList[0] = firstParam; + newList[1] = secondParam; + try { + Object r = super.executeInner(newList); + logger.info("乘法运算:" + r.toString()); + result.setContent(new BigDecimal(r + "")); + } catch (Exception e) { + logger.info("除法计算异常返回0:" + e.getMessage()); + result.setContent(0); + } + return result; + } + + public WOperatorDiv(String name) { + super(name); + } } diff --git a/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java b/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java deleted file mode 100644 index bbdc37dec..000000000 --- a/src/com/engine/salary/formlua/func/date/DateTimeTestServiceImpl.java +++ /dev/null @@ -1,1208 +0,0 @@ -package com.engine.salary.formlua.func.date; - -import com.alibaba.fastjson.JSONObject; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.entity.parameter.DateAndString; -import com.weaver.excel.formula.entity.parameter.FuncNames; -import com.weaver.excel.formula.util.*; -import com.weaver.teams.domain.user.DataCollectionEmployee; -import com.weaver.teams.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -@Service("dateTimeTestService") -public class DateTimeTestServiceImpl implements DateTimeService { - protected final Logger logger = LoggerFactory.getLogger(getClass()); - private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - private String format="yyyy-MM-dd HH:mm:ss"; - private Calendar calendar=Calendar.getInstance(); - - /** - * 返回当前日期时间 - * @return - */ - @Override - public DataType now(Object... objects) { - int number= IgnoreParamFilter.getSetFuncNumber(FuncNames.NOW.toString()); - if(objects.length>0){ - throw new RuntimeException("NOW函数不能有参数"); - } - formatter=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - String nowStr=formatter.format(new Date()); - return new DataType(DataType.STRING,nowStr); - } - - /** - * 返回当前日期 - * @return - */ - @Override - public DataType today(Object... objects) { - int number=IgnoreParamFilter.getSetFuncNumber(FuncNames.TODAY.toString()); - if(objects.length>0){ - throw new RuntimeException("TODAY函数不能有参数"); - } - formatter=new SimpleDateFormat("yyyy-MM-dd"); - String dateStr=formatter.format(new Date()); - return new DataType(DataType.STRING,dateStr); - } - - /** - * 格式化时间日期 - * @param objects - * @return - */ - @Override - public DataType dateFormat(Object... objects) { - Class[] typeObjects=new Class[]{DateAndString.class,String.class}; - String func="DATEFORMAT"; - IgnoreParamFilter.commonFilter(func,2,2,typeObjects,objects); - Object result=objects[0]; - String dateStr=""; - Object p1=objects[0]; - Object p2=objects[1]; - if(ExcelParamUtil.checkIsNull(p1,p2)){ - throw new RuntimeException("日期格式化函数参数不能为空"); - } - if(p1 instanceof DataType){ - DataType dataType=(DataType) p1; - if(dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE)){ - dateStr="2020-09-08 12:00"; - }else{ - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - number-=1; - throw new RuntimeException(func+"函数格式错误"); - } - - }else { - if(p1 instanceof Date){ - dateStr=formatter.format(p1); - }else { - dateStr=p1.toString(); - } - } - String formatStr=(ExcelParamUtil.getParamContent(p2,"string")!=null?ExcelParamUtil.getParamContent(p2,"string"):"").toString().replaceAll("D","d"); - try { - String formatterStr= DateUtil.buildFormat(dateStr); - formatter=new SimpleDateFormat(formatterStr); - Date sourceDate=formatter.parse(dateStr); - formatter= new SimpleDateFormat(formatStr); - dateStr=formatter.format(sourceDate); - result=dateStr; - } catch (ParseException e) { - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - number-=1; - JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数格式错误"); - throw new RuntimeException(errorJson.getString("msg")); - } - return new DataType(DataType.STRING,result); - } - - /** - * 两个日期加减 - * @param - * @param - * @return - */ - @Override - public DataType dateDiff(Object... objects){ - Class[] typeObjects=new Class[]{DateAndString.class,DateAndString.class,String.class}; - IgnoreParamFilter.commonFilter("DATEDIFF",2,3,typeObjects,objects); - Long secondsL=new Long(60*60*1000);//计算日期时间间距的单位,默认为小时 - - Long nd = buildSecondsFmt("D"); - Long nh = buildSecondsFmt("H"); - Long nm = buildSecondsFmt("I"); - Long ns = buildSecondsFmt("S"); - - - Double result=new Double(0); - String type="D"; - String sContent=DateUtil.getContent(objects[0],formatter); - String eContent=DateUtil.getContent(objects[1],formatter); - if(ExcelParamUtil.checkIsNull(sContent,eContent,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - Date startDate=null; - Date endDate=null; - - format= DateUtil.buildFormat(sContent); - startDate=formateDateStr(sContent,format); - format=DateUtil.buildFormat(eContent); - endDate=formateDateStr(eContent,format); - if(startDate==null||endDate==null){ - return new DataType(DataType.NUMBER,0); - } - Calendar cal1 = Calendar.getInstance(); - cal1.setTime(startDate); - //当前时间 - Calendar cal2 = Calendar.getInstance(); - cal2.setTime(endDate); - - - long diff = cal2.getTime().getTime() - cal1.getTime().getTime(); - - if(objects.length==3){ - type=ExcelParamUtil.getParamContent(objects[2],"string")!=null?ExcelParamUtil.getParamContent(objects[2],"string").toString():""; - secondsL=buildSecondsFmt(type); - } - Double time=new Double(0); - boolean checkType=true; - switch (type){ - case "Y": - time= getTime(startDate, endDate)/(nd.doubleValue())/365.0; - break; - case "M": - Long monthR=getByField(cal1, cal2, Calendar.YEAR)*12 + getByField(cal1, cal2, Calendar.MONTH); - time= monthR.doubleValue(); - break; - case "D": - double dayR=getTime(startDate, endDate)/(nd.doubleValue()); - time= dayR; - break; - case "H": - double hourH=getTime(startDate, endDate)/(nh.doubleValue()); - time= hourH; - break; - case "I": - double minuR= getTime(startDate, endDate)/(nm.doubleValue()); - time=minuR; - break; - case "S": - double seconR=getTime(startDate, endDate)/ns.doubleValue(); - time= seconR; - break; - default: - checkType=false; - break; - } - if(!checkType){ - String func="DATEDIFF"; - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson= ErrorUtil.buildError(func,number-1,number-1,func+"函数第3个参数不正确"); - throw new RuntimeException(errorJson.getString("msg")); - } - BigDecimal b = new BigDecimal(time); - double f1 = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); - result=f1; - return new DataType(DataType.NUMBER,result); - } - - /** - * 日期加减天数 - * @param objects - * @return - */ - @Override - public DataType dateAdd(Object... objects) { - Class[] typeObjects=new Class[]{DateAndString.class,Integer.class,String.class}; - IgnoreParamFilter.commonFilter("DATEADD",2,3,typeObjects,objects); - - String type="D"; - if(objects.length==3){ - type=objects[2].toString(); - } - - Object tcontent=DateUtil.getContent(objects[0],formatter); - Double numD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"")!=null?ExcelParamUtil.getParamContent(objects[1],"").toString():""); - - int num=numD.intValue(); - if(ExcelParamUtil.checkIsNull(tcontent,numD,type,ExcelParamUtil.CHECKLEVEL_STRING)){ - throw new RuntimeException("日期加减函数的参数不能为空"); - } - Object result=""; - - try { - Date date=null; - if(tcontent instanceof String || tcontent instanceof Character){ - format=DateUtil.buildFormat(tcontent.toString()); - if(null==format){ - throw new RuntimeException("日期加减函数的格式化参数不能为空"); - } - date=formateDateStr(tcontent.toString(),format); - }else { - date=(Date)tcontent; - } - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - boolean checkType=true; - switch (type){ - case "Y": - cal.add(Calendar.YEAR,num); - break; - case "M": - cal.add(Calendar.MONTH,num); - break; - case "D": - cal.add(Calendar.DAY_OF_MONTH,num); - break; - case "H": - cal.add(Calendar.HOUR_OF_DAY,num); - break; - case "I": - cal.add(Calendar.MINUTE,num); - break; - case "S": - cal.add(Calendar.SECOND,num); - break; - default: - checkType=false; - break; - } - if(!checkType){ - String func="DATEADD"; - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson= ErrorUtil.buildError(func,number-1,number-1,func+"函数第3个参数不正确"); - throw new RuntimeException(errorJson.getString("msg")); - } - Date newDate=cal.getTime(); - String nDate=formateDateStr(newDate,format); - result=nDate; - - } catch (ParseException e) { - logger.error("err",e); - } - return new DataType(DataType.STRING,result); - } - - /** - * 返回年份 - * @param objects - * @return - */ - @Override - public DataType year(Object... objects) { - Object reuslt=new Object(); - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("YEAR",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - int year=0; - try { - year=getDateTimeValue(date,"Y","YEAR"); - reuslt=year; - } catch (ParseException e) { - logger.error("err",e); - } - - return new DataType(DataType.NUMBER,reuslt); - } - - /** - * 返回是今年第几月 - * @param objects - * @return - */ - @Override - public DataType month(Object... objects) { - - Object reuslt=new Object(); - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("MONTH",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - boolean isDate=checkDateString(date!=null?date.toString():""); - if(!isDate){ - return new DataType(DataType.NUMBER,0); - } - int month=0; - try { - month=getDateTimeValue(date,"M","MONTH"); - reuslt=month+1; - } catch (ParseException e) { - logger.error("err",e); - } - - return new DataType(DataType.NUMBER,reuslt); - } - - /** - * 返回日期是本月几号 - * @param objects - * @return - */ - @Override - public DataType day(Object... objects) { - Object reuslt=new Object(); - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("DAY",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - int day=0; - try { - day=getDateTimeValue(date,"D","DAY"); - reuslt=day; - } catch (ParseException e) { - logger.error("err",e); - } - - return new DataType(DataType.NUMBER,reuslt); - - } - - /** - * 返回时钟位置 - * @param objects - * @return - */ - @Override - public DataType hour(Object... objects) { - - Object reuslt=new Object(); - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("HOUR",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - Integer hour=0; - try { - hour=getDateTimeValue(date,"H","HOUR"); - reuslt=hour; - } catch (ParseException e) { - logger.error("err",e); - } - - return new DataType(DataType.NUMBER,reuslt); - - } - - /** - * 返回分钟位置 - * @param objects - * @return - */ - @Override - public DataType minute(Object... objects) { - Object reuslt=new Object(); - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("MINUTE",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - int minute=0; - try { - minute=getDateTimeValue(date,"I","MINUTE"); - - reuslt=minute; - } catch (ParseException e) { - logger.error("err",e); - } - - return new DataType(DataType.NUMBER,reuslt); - } - - /*** - * 返回秒钟位置 - * @param objects - * @return - */ - @Override - public DataType seconds(Object... objects) { - Object reuslt=new Object(); - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("SECOND",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - int seconds=0; - try { - seconds=getDateTimeValue(date,"S","SECOND"); - reuslt=seconds; - } catch (ParseException e) { - logger.error("err",e); - } - - return new DataType(DataType.NUMBER,reuslt); - - } - - /** - * 计算是本月的第几周 - * @param objects - * @return - */ - @Override - public DataType weekNum(Object... objects) { - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("WEEKNUM",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - int weekNum=0; - try { - //在JDK中可能会把前一年末尾的几天判定为下一年的第一周 - weekNum=getDateTimeValue(date,"WM","WEEKNUM"); - - } catch (ParseException e) { - logger.error("err",e); - } - return new DataType(DataType.NUMBER,weekNum); - } - - /** - * 判断是周几,因为周几是从周天的0开始算,所以返回数据需要减1 - * @param objects - * @return - */ - @Override - public DataType weekDay(Object... objects) { - Class[] typeObjects=new Class[]{DateAndString.class}; - IgnoreParamFilter.commonFilter("WEEKDAY",1,1,typeObjects,objects); - Object obj=objects[0]; - Object date=DateUtil.getContent(obj,formatter); - if(ExcelParamUtil.checkIsNull(date,ExcelParamUtil.CHECKLEVEL_STRING)){ - return new DataType(DataType.NUMBER,0); - } - int weekDay=0; - try { - weekDay=getDateTimeValue(date,"DW","WEEKDAY"); - } catch (ParseException e) { - logger.error("err",e); - } - - return new DataType(DataType.NUMBER,weekDay>0?(weekDay-1):weekDay); - } - - @Override - public DataType dayOfMonth(Object... objects) { - String dayType=""; - if(objects!=null && objects.length>0 && objects[0]!=null){ - dayType=objects[0].toString(); - } - - // 获取当前年份、月份、日期 - Calendar cale = Calendar.getInstance(); - // 获取当月第一天和最后一天 - SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - String firstday="", lastday=""; - String date=""; - switch (dayType.toLowerCase()){ - case "first": - // 获取当前月的第一天 - cale = Calendar.getInstance(); - cale.add(Calendar.MONTH, 0); - cale.set(Calendar.DAY_OF_MONTH, 1); - cale.set(Calendar.HOUR_OF_DAY,0); - cale.set(Calendar.MINUTE,0); - firstday = formatTemp.format(cale.getTime()); - date=firstday; - break; - case "last": - // 获取当前月的最后一天 - cale = Calendar.getInstance(); - cale.add(Calendar.MONTH, 1); - cale.set(Calendar.DAY_OF_MONTH, 0); - cale.set(Calendar.HOUR_OF_DAY,0); - cale.set(Calendar.MINUTE,0); - lastday = formatTemp.format(cale.getTime()); - date=lastday; - break; - default: - // 获取指定的某一天 - if(dayType==null || dayType.trim().equalsIgnoreCase("")){ - dayType="0"; - } - cale = Calendar.getInstance(); - cale.add(Calendar.MONTH, 1); - cale.set(Calendar.HOUR_OF_DAY,0); - cale.set(Calendar.MINUTE,0); - cale.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dayType)); - lastday = formatTemp.format(cale.getTime()); - date=lastday; - break; - } - logger.info("firstday:"+firstday+" lastday:"+lastday); - return new DataType(DataType.STRING,date); - } - - @Override - public DataType monthOfYear(Object... objects) { - String dayType=""; - if(objects!=null && objects.length>0 && objects[0]!=null){ - dayType=objects[0].toString(); - } - if(dayType==null || dayType.equalsIgnoreCase("")){ - dayType="0"; - } - int month=Integer.parseInt(dayType); - if(month>0){ - month-=1; - } - SimpleDateFormat dayFormatTemp = new SimpleDateFormat("yyyy-MM-dd"); - SimpleDateFormat formatTemp = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - Calendar cale = Calendar.getInstance(); - cale.set(cale.get(Calendar.YEAR),month,1); - - String lastday = formatTemp.format(cale.getTime()); - System.out.println(lastday); - return new DataType(DataType.STRING,lastday); - } - - @Override - public DataType timeOfDay(Object... objects) { - String dayType=""; - if(objects!=null && objects.length>0 && objects[0]!=null){ - dayType=objects[0].toString(); - } - - SimpleDateFormat dayFormatTemp = new SimpleDateFormat("yyyy-MM-dd"); - SimpleDateFormat formatTemp = new SimpleDateFormat("HH:mm"); - Calendar cale = Calendar.getInstance(); - try { - cale.setTime(dayFormatTemp.parse("2021-01-17 13:22")); - } catch (ParseException e) { - logger.error("err",e); - } - cale.set(Calendar.HOUR_OF_DAY,Integer.parseInt(dayType)); - cale.set(Calendar.MINUTE,0); - String lastday = formatTemp.format(cale.getTime()); - return new DataType(DataType.STRING,lastday); - } - - @Override - public DataType eoMonth(Object... objects) { - //校验 - Class[] typeObjects = new Class[]{DateAndString.class, Integer.class}; - IgnoreParamFilter.commonFilter("EOMONTH",1,2, typeObjects, objects); - - //获取日期和加减参数 - Object dateObj = objects[0]; - Object dateContent = dateObj != null ? DateUtil.getContent(dateObj, formatter):null; - - //不支持变量 - if(objects.length > 1 && objects[1] instanceof DataType){ - throw new RuntimeException("EOMONTH函数第二个参数只能是常量"); - } - - Object tempObj = objects.length > 1 ? objects[1]:null; - Object numObj = tempObj != null && ExcelParamUtil.getParamContent(tempObj,"") != null ? ExcelParamUtil.getParamContent(tempObj,"").toString():null; - - int num = 0; - if(numObj != null){ - try{ - num = Integer.parseInt(numObj+""); - }catch (Exception e){ - throw new RuntimeException("EOMONTH函数第二个参数只能是整数"); - } - } - if(ExcelParamUtil.checkIsNull(dateContent, ExcelParamUtil.CHECKLEVEL_STRING)) throw new RuntimeException("日期参数不能为空"); - - Date date=null; - try { - if(dateContent instanceof String || dateContent instanceof Character){ - format = DateUtil.buildFormat(dateContent.toString()); - SimpleDateFormat sdf = new SimpleDateFormat(format); - date = sdf.parse(dateContent.toString()); - }else { - date = (Date)dateContent; - } - } catch (Exception e) { - throw new RuntimeException("EOMONTH函数参数类型错误"); - } - - //在传入日期上进行月份加减操作,并设置为当月第一天 - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.add(Calendar.MONTH, num); - cal.set(Calendar.DAY_OF_MONTH, 1); - - //取该月最后一天 - cal.add(Calendar.MONTH,1); - cal.add(Calendar.DAY_OF_MONTH,-1); - - Date newDate = cal.getTime(); - Object rtnStr = null; - try { - rtnStr = formateDateStr(newDate,format); - } catch (ParseException e) { - logger.error("err",e); - } - return new DataType(DataType.STRING,rtnStr); - } - - @Override - public DataType workdayIntl(Object... objects) { - //校验 - String func = "NETWORKDAYSPI"; - IgnoreParamFilter.commonFilter(func,3,3, null, objects); - - //获取开始日期 - Object startObj = objects[0]; - Object startDateObj = startObj != null ? DateUtil.getContent(startObj, formatter):null; - - Date startDate = null; - if(startDateObj != null){ - if(startDateObj instanceof String || startDateObj instanceof Character){ - format = DateUtil.buildFormat(startDateObj.toString()); - - if(StringUtils.isEmpty(format)) { - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数开始时间格式错误"); - throw new RuntimeException(errorJson.getString("msg")); - } - startDate = formateDateStr(startDateObj.toString(), format); - }else { - startDate = (Date)startDateObj; - } - } - - //结束日期 - Object endObj = objects[1]; - Object endDateObj = endObj != null ? DateUtil.getContent(endObj, formatter):null; - - Date endDate = null; - if(endDateObj != null){ - - if(endDateObj instanceof String || endDateObj instanceof Character){ - format = DateUtil.buildFormat(endDateObj.toString()); - if(StringUtils.isEmpty(format)) { - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数结束时间格式错误"); - throw new RuntimeException(errorJson.getString("msg")); - } - endDate = formateDateStr(endDateObj.toString(), format); - }else { - endDate = (Date)startDateObj; - } - } - - //人员参数 - Object employeeObj = objects[2]; - if(!IgnoreParamFilter.isEmployee(employeeObj)) throw new RuntimeException(func+"函数第三个参数必须是人员参数"); - - String empIdStr = employeeObj != null ? ((DataType)employeeObj).getContent()+"" : null; - DataCollectionEmployee currEmp = employeeObj != null ? ((DataType)employeeObj).getEmployee() : null; - String tenantKey = currEmp != null ? currEmp.getTenantKey() : null; - - if(ExcelParamUtil.checkIsNull(startDate, endDate, empIdStr, ExcelParamUtil.CHECKLEVEL_STRING)){ - throw new RuntimeException(func+"函数参数不能为空"); - } - - if(StringUtils.isEmpty(tenantKey)){ - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数未能获取到租户"); - throw new RuntimeException(errorJson.getString("msg")); - } - return new DataType(DataType.NUMBER, 1); - } - - @Override - public DataType maxDate(Object... objects) { - if(objects == null || objects.length == 0){ - throw new RuntimeException("MAXDATE函数的参数不能为空"); - } - Object dateObj = null; - Date date = null; - - for(int i=0; i0){ - throw new RuntimeException("CURRYEAR函数不允许有参数"); - } - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - int year=cal.get(Calendar.YEAR); - return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); - } - - @Override - public DataType currMonth(Object... objects) { - if(objects.length>0){ - throw new RuntimeException("CURRMONTH函数不允许有参数"); - } - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - int year=cal.get(Calendar.MONTH)+1; - return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); - } - - @Override - public DataType currDay(Object... objects) { - if(objects.length>0){ - throw new RuntimeException("CURRDAY函数不允许有参数"); - } - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - int year=cal.get(Calendar.DAY_OF_MONTH); - return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); - } - - @Override - public DataType currWeek(Object... objects) { - if(objects.length>0){ - throw new RuntimeException("CURRWEEK函数不允许有参数"); - } - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - int year=cal.get(Calendar.WEEK_OF_MONTH); - return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); - } - - @Override - public DataType currHour(Object... objects) { - if(objects.length>0){ - throw new RuntimeException("CURRHOUR函数不允许有参数"); - } - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - int year=cal.get(Calendar.HOUR_OF_DAY); - return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); - } - - @Override - public DataType currMinute(Object... objects) { - if(objects.length>0){ - throw new RuntimeException("CURRMINUTE函数不允许有参数"); - } - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - int year=cal.get(Calendar.MINUTE); - return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); - } - - @Override - public DataType currSecond(Object... objects) { - if(objects.length>0){ - throw new RuntimeException("CURRSECOND函数不允许有参数"); - } - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - int year=cal.get(Calendar.SECOND); - return new DataType(DataType.NUMBER,year, ComponentType.NumberComponent.toString()); - } - - /*******以下为日期函数的一些公共逻辑********/ - - - - - /** - * 获取日期时间的单位值,指定类型为Type,默认为 'D' 天数 - * @param date - * @param type - * @return - * @throws ParseException - */ - public Integer getDateTimeValue(Object date,String type,String func) throws ParseException { - int result=0; - try { - boolean isTime=false; - Date fDate=null; - if(date instanceof String){ - boolean isDate=checkDateString(date!=null?date.toString():""); - if(!isDate){ - return 0; - } - format=DateUtil.buildFormat(date.toString(),type); - if(format==null){ - format=DateUtil.buildFormat(date.toString()); - } - fDate=formateDateStr(date.toString(),format); - if(date.toString().indexOf(":")>0&&date.toString().indexOf("-")<0){ - isTime=true; - if(!type.equals("H")&&!type.equals("I")&&!type.equals("S")){ - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数参数错误"); - throw new RuntimeException(errorJson.getString("msg")); - } - } - }else { - fDate=(Date)date; - } - - int calendarType=0; - switch (type){ - case "Y": - calendarType=Calendar.YEAR; - break; - case "M": - calendarType=Calendar.MONTH; - break; - case "D": - calendarType=Calendar.DAY_OF_MONTH; - break; - case "H": - if(isTime){ - return Integer.parseInt(date.toString().split(":")[0]); - } - calendarType=Calendar.HOUR_OF_DAY; - break; - case "I": - if(isTime){ - return Integer.parseInt(date.toString().split(":")[1]); - } - calendarType=Calendar.MINUTE; - break; - case "S": - if(isTime){ - return Integer.parseInt(date.toString().split(":")[2]); - } - calendarType=Calendar.SECOND; - break; - case "WM": - calendarType=Calendar.WEEK_OF_YEAR; - long startTime1 = fDate.getTime(); - Calendar calendar = Calendar.getInstance(); - calendar.setFirstDayOfWeek(Calendar.SUNDAY);//设置星期一为一周开始的第一天 - calendar.setMinimalDaysInFirstWeek(4);//可以不用设置 - calendar.setTimeInMillis(startTime1);//获得当前的时间戳 - int weekOfYear = calendar.get(calendarType);//获得当前日期属于今年的第几周 - result=weekOfYear; - logger.info("当前是第"+result+"周"); - return result; - case "DW": - calendarType=Calendar.DAY_OF_WEEK; - break; - default: - calendarType=Calendar.HOUR_OF_DAY; - break; - } - calendar.setTime(fDate); - result=calendar.get(calendarType); - } catch (RuntimeException e) { - logger.error("err",e); - result=0; - } - return result; - } - /** - * 格式化日期时间 - * @param dateStr 日期时间原字符串 - * @param format 格式 - * @return - * @throws ParseException - */ - private Date formateDateStr(String dateStr,String format){ - SimpleDateFormat sdf = new SimpleDateFormat(format); - Date ndate= null; - try { - ndate = sdf.parse(dateStr); - } catch (ParseException e) { - logger.error("err",e); - } - return ndate; - } - - /** - * 格式日期时间为字符串 - * @param date - * @param format - * @return - * @throws ParseException - */ - private String formateDateStr(Date date,String format) throws ParseException { - SimpleDateFormat sdf = new SimpleDateFormat(format); - String ndate=sdf.format(date); - return ndate; - } - - - - - /** - * 判断时间间距的单位类型 - * @param type - * @return - */ - private Long buildSecondsFmt(String type){ - Long secondsL=null; - switch (type){ - case "Y": - secondsL=new Long(365*24*60*60*1000); - break; - case "M": - secondsL=new Long(30*24*60*60*1000); - break; - case "D": - secondsL=new Long(24*60*60*1000); - break; - case "H": - secondsL=new Long(60*60*1000); - break; - case "I": - secondsL=new Long(60*1000); - break; - case "S": - secondsL=new Long(1000); - break; - default: - secondsL=new Long(60*60*1000); - break; - } - return secondsL; - } - - static Calendar calendar2=Calendar.getInstance(); - public static SimpleDateFormat formatter2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - static String format2="yyyy-MM-dd HH:mm:ss"; - - - - public static Integer getDateTimeValue2(Object date,String type,String func) throws ParseException { - int result=0; - boolean isTime=false; - Date fDate=null; - if(date instanceof String){ - format2=DateUtil.buildFormat(date.toString()); - fDate=formateDateStr2(date.toString(),format2); - if(date.toString().indexOf(":")>0&&date.toString().indexOf("-")<0){ - isTime=true; - if(!type.equals("H")&&!type.equals("I")&&!type.equals("S")){ - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson=ErrorUtil.buildError(func,number,number,func+"函数参数错误"); - throw new RuntimeException(errorJson.getString("msg")); - } - } - }else { - fDate=(Date)date; - } - - int calendarType=0; - switch (type){ - case "Y": - calendarType=Calendar.YEAR; - break; - case "M": - calendarType=Calendar.MONTH; - break; - case "D": - calendarType=Calendar.DAY_OF_MONTH; - break; - case "H": - if(isTime){ - return Integer.parseInt(date.toString().split(":")[0]); - } - calendarType=Calendar.HOUR_OF_DAY; - break; - case "I": - if(isTime){ - return Integer.parseInt(date.toString().split(":")[1]); - } - calendarType=Calendar.MINUTE; - break; - case "S": - if(isTime){ - return Integer.parseInt(date.toString().split(":")[2]); - } - calendarType=Calendar.SECOND; - break; - case "WM": - calendarType=Calendar.WEEK_OF_MONTH; - break; - case "DW": - calendarType=Calendar.DAY_OF_WEEK; - break; - default: - calendarType=Calendar.HOUR_OF_DAY; - break; - } - calendar2.setTime(fDate); - result=calendar2.get(calendarType); - return result; - } - - private static Date formateDateStr2(String dateStr,String format) throws ParseException { - SimpleDateFormat sdf = new SimpleDateFormat(format); - Date ndate= null; - ndate = sdf.parse(dateStr); - return ndate; - } - private boolean checkDateString(String dateString){ - List datafList=new ArrayList(); - datafList.add("yyyyMMddHHmmss"); - datafList.add("yyyyMMdd"); - datafList.add("yyyyMMddHHmm"); - datafList.add("HH:mm"); - datafList.add("HH:mm:ss"); - if(RegularUtil.isNumber(dateString)){ - return false; - } - boolean r=false; - for(String s:datafList){ - SimpleDateFormat sdf = new SimpleDateFormat(s); - - Date ndate= null; - try { - ndate = sdf.parse(dateString); - r=true; - break; - } catch (ParseException e) { - logger.info(e.getMessage()); - r=false; - } - } - if(r){ - if(RegularUtil.isNumber(dateString)){ - r=false; - } - } - return r; - } - - - public static double getBetween(String beginTime, String endTime, String returnPattern) throws ParseException{ - - String format= DateUtil.buildFormat(beginTime); - SimpleDateFormat sdf = new SimpleDateFormat(format); - Date beginDate =sdf.parse(beginTime); - - format=DateUtil.buildFormat(endTime); - sdf = new SimpleDateFormat(format); - Date endDate =sdf.parse(endTime); - - Calendar beginCalendar = Calendar.getInstance(); - Calendar endCalendar = Calendar.getInstance(); - beginCalendar.setTime(beginDate); - endCalendar.setTime(endDate); - - double resutl; - switch (returnPattern) { - case "Y": - resutl= getTime(beginDate, endDate)/(24*60*60*1000)/365.0; - break; - case "M": - resutl= getByField(beginCalendar, endCalendar, Calendar.YEAR)*12 + getByField(beginCalendar, endCalendar, Calendar.MONTH); - break; - case "D": - resutl= getTime(beginDate, endDate)/(24*60*60*1000); - break; - case "H": - Long nd=new Long(60*60*1000); - resutl= getTime(beginDate, endDate)/(nd.doubleValue()); - break; - case "I": - resutl= getTime(beginDate, endDate)/(60*1000); - break; - case "S": - resutl= getTime(beginDate, endDate)/1000; - break; - default: - resutl= new Long(0); - break; - } - return resutl; - } - - - - private static Long getByField(Calendar beginCalendar, Calendar endCalendar, int calendarField){ - int r=endCalendar.get(calendarField) - beginCalendar.get(calendarField); - return new Long(r); - } - - private static long getTime(Date beginDate, Date endDate){ - return endDate.getTime() - beginDate.getTime(); - } - - -} diff --git a/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java b/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java index 7164fe9fd..8cc816f77 100644 --- a/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java +++ b/src/com/engine/salary/formlua/func/find/FindFuncsServiceImpl.java @@ -1,193 +1,188 @@ -package com.engine.salary.formlua.func.find; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.weaver.excel.formula.core.rpc.ExcelDubboInvoker; -import com.weaver.excel.formula.core.rpc.RpcMethod; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.entity.parameter.FuncNames; -import com.weaver.excel.formula.entity.parameter.standard.FormulaFilterData; -import com.weaver.excel.formula.util.ErrorUtil; -import com.weaver.excel.formula.util.ExcelParamUtil; -import com.weaver.excel.formula.util.IgnoreParamFilter; -import com.weaver.teams.domain.user.DataCollectionEmployee; -import org.apache.commons.beanutils.BeanUtils; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.Map; - -@Service("findFuncsService") -public class FindFuncsServiceImpl implements FindFuncsService{ - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - private ExcelDubboInvoker excelDubboInvoker; - - @Override - public Object chooseOne(Object... objects) { - DataType chooseResult=new DataType(); - if(objects != null && objects.length>=2){ - List dataList= ExcelParamUtil.getParamContent(objects); - Object firstData=dataList.get(0); - for (int i=1;i filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList(): Lists.newArrayList(); - DataCollectionEmployee user = formObj.getEmployee(); - - Object[] params = {formId, filterDatas, user}; - return excelDubboInvoker.invokeCommonDubbo(DataType.class,formObj.getModule()+"", RpcMethod.choose, params); - } - - @Override - public DataType match(Object... objects) { - //参数校验 - String func = FuncNames.MATCH.toString(); - IgnoreParamFilter.commonFilter(func,2,2, null, objects); - - Object valueObj = objects[0]; - Object[] arrayObj = null; - - //将第二个参数转数组 - try{ - arrayObj = (Object[]) objects[1]; - }catch (Exception e){ - Integer number = IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数必须是数组类型"); - throw new RuntimeException(errorJson.getString("msg")); - } - - //所在下标 - int index = ArrayUtils.indexOf(arrayObj, valueObj); - return new DataType(DataType.NUMBER, index); - } - - @Override - public Object vlookups(Object... objects) { - //参数校验 - String func = FuncNames.VLOOKUPS.toString(); - IgnoreParamFilter.commonFilter(func,3,3, null, objects); - - DataType formObj = (DataType)objects[0]; - DataType conditionObj = objects[1] != null ? (DataType)objects[1] : null; - //拿出返回数据 - Object returnObjs=objects[2]; - //初始化数组 - DataType[] rtnCols = null; - //判断是否是数组 - if(returnObjs!=null && returnObjs.getClass().isArray()){ - logger.info("执行器查找函数返回数据为DataType数组"+JSON.toJSONString(returnObjs)); - //获取数组长度 - int len= Array.getLength(returnObjs); - rtnCols=new DataType[len]; - //遍历并转换数据后放入rtnCols - for(int i=0;i fieldIds = Lists.newArrayList(); - if(ArrayUtils.isNotEmpty(rtnCols)){ - for (DataType item : rtnCols) { - if(item != null && StringUtils.isNotEmpty(item.getFieldId())) fieldIds.add(item.getFieldId()); - } - } - - Long formId = formObj.getFormId(); - List filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList() : Lists.newArrayList(); - DataCollectionEmployee user = formObj.getEmployee(); - - Object[] params = {formId+"", filterDatas, fieldIds, null,user}; - - DataType[] dataTypes=new DataType[1]; - Object dubboResult=excelDubboInvoker.invokeCommonDubbo(List.class,formObj.getModule()+"", RpcMethod.vlookups, params); - logger.info("返回结果:"+JSON.toJSONString(dubboResult)); - - if(dubboResult!=null && dubboResult instanceof List){ - try { - List resultObjectList=(List)dubboResult; - dataTypes=new DataType[resultObjectList.size()]; - for(int i =0;i classa=Class.forName(map.get("class").toString()) ; - Object typeObject=classa.newInstance(); - BeanUtils.populate(typeObject,map); - if(typeObject instanceof DataType){ - dataTypes[i]=(DataType) typeObject; - } - }else if(resultParam instanceof DataType){ - dataTypes[i]=(DataType) resultParam; - }else{ - logger.info("Dubbo接口返回异常数据类型:"+resultParam.getClass().getName()); - } - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - }catch (Exception e){ - e.printStackTrace(); - } - }else{ - DataType nomalData=new DataType(DataType.NUMBER, 0); - dataTypes[0]=nomalData; - } - return dataTypes.length==1?dataTypes[0]:dataTypes; - } -} +//package com.engine.salary.formlua.func.find; +// +//import com.alibaba.fastjson.JSON; +//import com.alibaba.fastjson.JSONObject; +//import com.engine.salary.entity.datacollection.DataCollectionEmployee; +//import com.engine.salary.formlua.entity.parameter.DataType; +//import com.engine.salary.formlua.entity.parameter.FuncNames; +//import com.engine.salary.formlua.entity.standard.FormulaFilterData; +//import com.engine.salary.formlua.util.ErrorUtil; +//import com.engine.salary.formlua.util.ExcelParamUtil; +//import com.engine.salary.formlua.util.IgnoreParamFilter; +//import com.weaver.excel.formula.core.rpc.RpcMethod; +//import org.apache.commons.beanutils.BeanUtils; +//import org.apache.commons.compress.utils.Lists; +//import org.apache.commons.lang.ArrayUtils; +//import org.apache.commons.lang.StringUtils; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.lang.reflect.Array; +//import java.lang.reflect.InvocationTargetException; +//import java.util.List; +//import java.util.Map; +// +//public class FindFuncsServiceImpl implements FindFuncsService{ +// protected final Logger logger = LoggerFactory.getLogger(this.getClass()); +// private ExcelDubboInvoker excelDubboInvoker; +// +// @Override +// public Object chooseOne(Object... objects) { +// DataType chooseResult=new DataType(); +// if(objects != null && objects.length>=2){ +// List dataList= ExcelParamUtil.getParamContent(objects); +// Object firstData=dataList.get(0); +// for (int i=1;i filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList(): Lists.newArrayList(); +// DataCollectionEmployee user = formObj.getEmployee(); +// +// Object[] params = {formId, filterDatas, user}; +// return excelDubboInvoker.invokeCommonDubbo(DataType.class,formObj.getModule()+"", RpcMethod.choose, params); +// } +// +// @Override +// public DataType match(Object... objects) { +// //参数校验 +// String func = FuncNames.MATCH.toString(); +// IgnoreParamFilter.commonFilter(func,2,2, null, objects); +// +// Object valueObj = objects[0]; +// Object[] arrayObj = null; +// +// //将第二个参数转数组 +// try{ +// arrayObj = (Object[]) objects[1]; +// }catch (Exception e){ +// Integer number = IgnoreParamFilter.getSetFuncNumber(func); +// JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数必须是数组类型"); +// throw new RuntimeException(errorJson.getString("msg")); +// } +// +// //所在下标 +// int index = ArrayUtils.indexOf(arrayObj, valueObj); +// return new DataType(DataType.NUMBER, index); +// } +// +// @Override +// public Object vlookups(Object... objects) { +// //参数校验 +// String func = FuncNames.VLOOKUPS.toString(); +// IgnoreParamFilter.commonFilter(func,3,3, null, objects); +// +// DataType formObj = (DataType)objects[0]; +// DataType conditionObj = objects[1] != null ? (DataType)objects[1] : null; +// //拿出返回数据 +// Object returnObjs=objects[2]; +// //初始化数组 +// DataType[] rtnCols = null; +// //判断是否是数组 +// if(returnObjs!=null && returnObjs.getClass().isArray()){ +// logger.info("执行器查找函数返回数据为DataType数组"+JSON.toJSONString(returnObjs)); +// //获取数组长度 +// int len= Array.getLength(returnObjs); +// rtnCols=new DataType[len]; +// //遍历并转换数据后放入rtnCols +// for(int i=0;i fieldIds = Lists.newArrayList(); +// if(!ArrayUtils.isEmpty(rtnCols)){ +// for (DataType item : rtnCols) { +// if(item != null && StringUtils.isNotEmpty(item.getFieldId())) fieldIds.add(item.getFieldId()); +// } +// } +// +// Long formId = formObj.getFormId(); +// List filterDatas = conditionObj != null ? conditionObj.getFormulaFilterDataList() : Lists.newArrayList(); +// DataCollectionEmployee user = formObj.getEmployee(); +// +// Object[] params = {formId+"", filterDatas, fieldIds, null,user}; +// +// DataType[] dataTypes=new DataType[1]; +// Object dubboResult=excelDubboInvoker.invokeCommonDubbo(List.class,formObj.getModule()+"", RpcMethod.vlookups, params); +// logger.info("返回结果:"+JSON.toJSONString(dubboResult)); +// +// if(dubboResult!=null && dubboResult instanceof List){ +// try { +// List resultObjectList=(List)dubboResult; +// dataTypes=new DataType[resultObjectList.size()]; +// for(int i =0;i classa=Class.forName(map.get("class").toString()) ; +// Object typeObject=classa.newInstance(); +// BeanUtils.populate(typeObject,map); +// if(typeObject instanceof DataType){ +// dataTypes[i]=(DataType) typeObject; +// } +// }else if(resultParam instanceof DataType){ +// dataTypes[i]=(DataType) resultParam; +// }else{ +// logger.info("Dubbo接口返回异常数据类型:"+resultParam.getClass().getName()); +// } +// } +// } catch (ClassNotFoundException e) { +// e.printStackTrace(); +// } catch (InstantiationException e) { +// e.printStackTrace(); +// } catch (IllegalAccessException e) { +// e.printStackTrace(); +// } catch (InvocationTargetException e) { +// e.printStackTrace(); +// }catch (Exception e){ +// e.printStackTrace(); +// } +// }else{ +// DataType nomalData=new DataType(DataType.NUMBER, 0); +// dataTypes[0]=nomalData; +// } +// return dataTypes.length==1?dataTypes[0]:dataTypes; +// } +//} diff --git a/src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java b/src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java deleted file mode 100644 index 4afb2fc0b..000000000 --- a/src/com/engine/salary/formlua/func/find/FindFuncsTestServiceImpl.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.engine.salary.formlua.func.find; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.engine.salary.formlua.entity.parameter.DataType; -import com.engine.salary.formlua.entity.parameter.FuncNames; -import com.engine.salary.formlua.util.ErrorUtil; -import com.engine.salary.formlua.util.ExcelParamUtil; -import com.engine.salary.formlua.util.IgnoreParamFilter; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.compress.utils.Lists; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; - - -public class FindFuncsTestServiceImpl implements FindFuncsService{ - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - @Override - public Object chooseOne(Object... objects) { - - if(objects==null || objects.length<2){ - throw new RuntimeException("CHOOSE函数的参数不能少于两个"); - } - DataType dataType=new DataType(); - boolean checkResult= IgnoreParamFilter.checkType(objects); - if(checkResult){ - int indexData=0; - Object firstObj=objects[0]; - try { - if(firstObj !=null){ - Double doubleValue=null; - if(firstObj instanceof DataType){ - DataType indexDataType=(DataType)firstObj; - if(ExcelParamUtil.findDataType(indexDataType.getDataType()).equalsIgnoreCase(DataType.NUMBER)){ - if(indexDataType.getContent()!=null){ - doubleValue=Double.parseDouble(indexDataType.getContent()+""); - } - } - }else{ - doubleValue=Double.parseDouble(firstObj+""); - } - indexData=doubleValue.intValue(); - }else{ - throw new RuntimeException("CHOOSE函数第一个参数不能为空"); - } - - } catch (NumberFormatException e) { - logger.error("err",e); - } - List dataList=ExcelParamUtil.getParamContent(objects); - if(indexData>=dataList.size()){ - indexData=dataList.size()-1; - } - Object resultObj=dataList.get(indexData); - if(resultObj!=null){ - if(resultObj instanceof DataType){ - dataType=(DataType)resultObj; - }else { - String type=ExcelParamUtil.getParamType(resultObj.getClass().getName()); - dataType.setDataType(type); - dataType.setContent(resultObj); - } - } - }else { - throw new RuntimeException("CHOOSE函数的参数类型不一致"); - } - logger.info("CHOOSE校验执行结果:"+ JSON.toJSONString(dataType)); - return dataType; - } - - @Override - public Object choose(Object... objects) { - //参数校验 - String func = FuncNames.CHOOSE.toString(); - IgnoreParamFilter.commonFilter(func,2,2, null, objects); - - //参数类型校验 - if(!(objects[0] instanceof DataType) || !DataType.FORM.equals(((DataType)objects[0]).getDataType())){ - Integer number = IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第一个参数必须是来源表"); - throw new RuntimeException(errorJson.getString("msg")); - } - - //第二个参数校验 - List conditionList = ExcelParamUtil.getParamContent(objects[1]); - if(CollectionUtils.isEmpty(conditionList)){ - Integer number = IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数返回值必须是boolean类型"); - throw new RuntimeException(errorJson.getString("msg")); - } - - DataType data = new DataType(DataType.NUMBER, 1); - List rtnList = Lists.newArrayList(); - rtnList.add(data); - return rtnList; - } - - @Override - public DataType match(Object... objects) { - //参数校验 - String func = FuncNames.MATCH.toString(); - IgnoreParamFilter.commonFilter(func,2,2, null, objects); - - Object valueObj = objects[0]; - List arrayList = ExcelParamUtil.getParamContent(objects[1]); - - if(valueObj instanceof DataType){ - valueObj = ((DataType) valueObj).getContent(); - } - - //将第二个参数转数组 - if(CollectionUtils.isEmpty(arrayList)){ - Integer number = IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数必须是数组类型"); - throw new RuntimeException(errorJson.getString("msg")); - } - - //所在下标 - int index = arrayList.indexOf(valueObj); - return new DataType(DataType.NUMBER, index); - } - - @Override - public Object vlookups(Object... objects) { - //参数校验 - String func = FuncNames.VLOOKUPS.toString(); - IgnoreParamFilter.commonFilter(func,3,3, null, objects); - - List conditionList = ExcelParamUtil.getParamContent(objects[1]); - DataType conditionObj=new DataType(); - if(conditionList!=null && conditionList.size()>1){ - conditionObj=(DataType) conditionList.get(0); - } - List rtnCols = ExcelParamUtil.getParamContent(objects[2]); - - //参数类型校验 -// if(!(objects[0] instanceof DataType) || !DataType.FORM.equals(((DataType)objects[0]).getDataType())){ -// Integer number = IgnoreParamFilter.getSetFuncNumber(func); -// JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第一个参数必须是数据源"); -// throw new RuntimeException(errorJson.getString("msg")); -// } - if(CollectionUtils.isEmpty(conditionList)){ - Integer number = IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第二个参数返回值必须是boolean类型"); - throw new RuntimeException(errorJson.getString("msg")); - } - if(conditionObj!=null && conditionObj.getSubLogic()!=null && conditionObj.getSubLogic().size()>1){ - throw new RuntimeException("VLOOKUPS函数的第二组参数不能嵌套使用逻辑函数(AND、OR)"); - } - if (CollectionUtils.isEmpty(rtnCols)){ - Integer number = IgnoreParamFilter.getSetFuncNumber(func); - JSONObject errorJson = ErrorUtil.buildError(func,number,number,func+"函数第三个参数返回值必须是集合类型"); - throw new RuntimeException(errorJson.getString("msg")); - } - - DataType data = new DataType(DataType.NUMBER, 1); -// List rtnList = Lists.newArrayList(); -// rtnList.add(data); - //函数中,涉及到集合,只解析数组类型,List识别不了 - DataType[] dataTypes=new DataType[1]; - dataTypes[0]=data; - return dataTypes.length==1?dataTypes[0]:dataTypes; - } -} diff --git a/src/com/engine/salary/formlua/func/logic/LogicService.java b/src/com/engine/salary/formlua/func/logic/LogicService.java index 722608ab3..d3811bfdb 100644 --- a/src/com/engine/salary/formlua/func/logic/LogicService.java +++ b/src/com/engine/salary/formlua/func/logic/LogicService.java @@ -4,14 +4,23 @@ import com.engine.salary.formlua.entity.parameter.DataType; public interface LogicService { - public DataType not(Object... object); - public DataType isEmpty(Object... objs); - public DataType isTrue(Object... objs); - public DataType isFalse(Object... objs); - public DataType and(Object... objs); - public DataType or(Object... objs); - public DataType likeFunc(Object... objects); - public DataType ifs(Object... objects); - public DataType find(Object... objects); - public DataType switchs(Object... objects); + public DataType not(Object... object); + + public DataType isEmpty(Object... objs); + + public DataType isTrue(Object... objs); + + public DataType isFalse(Object... objs); + + public DataType and(Object... objs); + + public DataType or(Object... objs); + + public DataType likeFunc(Object... objects); + + public DataType ifs(Object... objects); + + public DataType find(Object... objects); + + public DataType switchs(Object... objects); } diff --git a/src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java b/src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java index d8a9b1a81..0d0cb89a6 100644 --- a/src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java +++ b/src/com/engine/salary/formlua/func/logic/LogicServiceImpl.java @@ -2,10 +2,10 @@ package com.engine.salary.formlua.func.logic; import com.alibaba.fastjson.JSONObject; import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.entity.parameter.FuncNames; +import com.engine.salary.formlua.util.ErrorUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; import com.engine.salary.formlua.util.IgnoreParamFilter; -import com.weaver.excel.formula.entity.parameter.FuncNames; -import com.weaver.excel.formula.util.ErrorUtil; -import com.weaver.excel.formula.util.ExcelParamUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -242,7 +242,7 @@ public class LogicServiceImpl implements LogicService { if(testI%2>0 && testI!=objects.length){ Object cndObj=objects[testI-1]; if(!(cndObj instanceof Boolean) && !(cndObj instanceof DataType)){ - JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); + JSONObject errorJson= ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); throw new RuntimeException(errorJson.getString("msg")); }else if(cndObj instanceof DataType){ DataType boolDataType=(DataType)cndObj; diff --git a/src/com/engine/salary/formlua/func/logic/LogicUtils.java b/src/com/engine/salary/formlua/func/logic/LogicUtils.java index 0768e9b12..e1fc796f3 100644 --- a/src/com/engine/salary/formlua/func/logic/LogicUtils.java +++ b/src/com/engine/salary/formlua/func/logic/LogicUtils.java @@ -2,7 +2,6 @@ package com.engine.salary.formlua.func.logic; import com.engine.salary.formlua.entity.parameter.DataType; import com.engine.salary.formlua.entity.standard.FormulaFilterData; -import com.weaver.common.form.stat.FilterFormData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java b/src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java index f5a4362b3..22027195d 100644 --- a/src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java +++ b/src/com/engine/salary/formlua/func/math/MathFuncsServiceImpl.java @@ -1,14 +1,12 @@ package com.engine.salary.formlua.func.math; import com.alibaba.fastjson.JSONObject; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.entity.parameter.FuncNames; -import com.weaver.excel.formula.util.ErrorUtil; -import com.weaver.excel.formula.util.ExcelParamUtil; -import com.weaver.excel.formula.util.IgnoreParamFilter; -import com.weaver.excel.formula.util.RegularUtil; -import org.springframework.stereotype.Service; +import com.engine.salary.formlua.entity.parameter.DataType; +import com.engine.salary.formlua.entity.parameter.FuncNames; +import com.engine.salary.formlua.util.ErrorUtil; +import com.engine.salary.formlua.util.ExcelParamUtil; +import com.engine.salary.formlua.util.IgnoreParamFilter; +import com.engine.salary.formlua.util.RegularUtil; import java.math.BigDecimal; import java.util.ArrayList; @@ -16,16 +14,15 @@ import java.util.Collections; import java.util.List; import java.util.Random; -@Service("mathFuncsService") public class MathFuncsServiceImpl implements MathFuncsService { - private final String randomNumber="NUM"; - private final String randomChar="CHAR"; - private final String randomNumANDChar="FIX"; + private final String randomNumber = "NUM"; + private final String randomChar = "CHAR"; + private final String randomNumANDChar = "FIX"; @Override public DataType roundUp(Object... objects) { - Integer errorNumber= IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDUP.getName()); - Object number=null; + Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDUP.getName()); + Object number = null; Object object = objects[0]; //小数位 @@ -33,50 +30,50 @@ public class MathFuncsServiceImpl implements MathFuncsService { Object numDigitsObj = null; //获取小数点位数参数 - if(objects != null && objects.length > 1) { + if (objects != null && objects.length > 1) { numDigitsObj = objects[1]; - if(numDigitsObj != null && numDigitsObj instanceof DataType){ - numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj,""); + if (numDigitsObj != null && numDigitsObj instanceof DataType) { + numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj, ""); } } //整数校验 - if(numDigitsObj != null){ - try{ + if (numDigitsObj != null) { + try { numDigits = (int) numDigitsObj; - }catch (Exception e){ + } catch (Exception e) { throw new RuntimeException("小数点位数必须是整数"); } } - if(object instanceof DataType){ - DataType dataType=(DataType)object; - if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); + if (object instanceof DataType) { + DataType dataType = (DataType) object; + if (dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)) { + JSONObject errorJson = ErrorUtil.buildError(FuncNames.ROUNDUP.toString(), errorNumber, errorNumber, "ROUNDUP函数只接受数字参数"); throw new RuntimeException(errorJson.getString("msg")); } - number=dataType.getContent(); - }else{ + number = dataType.getContent(); + } else { BigDecimal db = new BigDecimal(object.toString()); - number=db; + number = db; } - if(!RegularUtil.isNumber(number)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); + if (!RegularUtil.isNumber(number)) { + JSONObject errorJson = ErrorUtil.buildError(FuncNames.ROUNDUP.toString(), errorNumber, errorNumber, "ROUNDUP函数只接受数字参数"); throw new RuntimeException(errorJson.getString("msg")); } - BigDecimal bigDecimal = new BigDecimal(number+""); + BigDecimal bigDecimal = new BigDecimal(number + ""); Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_CEILING).doubleValue(); - if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); - return new DataType(DataType.NUMBER, result, ComponentType.NumberComponent.toString()); + if (numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString()); } @Override public DataType roundDown(Object... objects) { - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDDOWN.getName()); - Object number=null; + Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDDOWN.getName()); + Object number = null; Object object = objects[0]; //小数位 @@ -84,49 +81,49 @@ public class MathFuncsServiceImpl implements MathFuncsService { Object numDigitsObj = null; //获取小数点位数参数 - if(objects != null && objects.length > 1) { + if (objects != null && objects.length > 1) { numDigitsObj = objects[1]; - if(numDigitsObj != null && numDigitsObj instanceof DataType){ - numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj,""); + if (numDigitsObj != null && numDigitsObj instanceof DataType) { + numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj, ""); } } //整数校验 - if(numDigitsObj != null){ - try{ + if (numDigitsObj != null) { + try { numDigits = (int) numDigitsObj; - }catch (Exception e){ + } catch (Exception e) { throw new RuntimeException("小数点位数必须是整数"); } } - if(object instanceof DataType){ - DataType dataType=(DataType)object; - if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ - return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + if (object instanceof DataType) { + DataType dataType = (DataType) object; + if (dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)) { + return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString()); } - number=dataType.getContent(); - }else{ + number = dataType.getContent(); + } else { BigDecimal db = new BigDecimal(object.toString()); - number=db; + number = db; } - if(!RegularUtil.isNumber(number)){ - return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + if (!RegularUtil.isNumber(number)) { + return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString()); } - BigDecimal bigDecimal = new BigDecimal(number+""); + BigDecimal bigDecimal = new BigDecimal(number + ""); Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_FLOOR).doubleValue(); - if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); - return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + if (numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString()); } @Override public DataType round(Object... objects) { - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUND.getName()); - Object number=null; + Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUND.getName()); + Object number = null; Object object = objects[0]; //小数位 @@ -134,257 +131,257 @@ public class MathFuncsServiceImpl implements MathFuncsService { Object numDigitsObj = null; //获取小数点位数参数 - if(objects != null && objects.length > 1) { + if (objects != null && objects.length > 1) { numDigitsObj = objects[1]; - if(numDigitsObj != null && numDigitsObj instanceof DataType){ - numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj,""); + if (numDigitsObj != null && numDigitsObj instanceof DataType) { + numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj, ""); } } //整数校验 - if(numDigitsObj != null){ - try{ + if (numDigitsObj != null) { + try { numDigits = (int) numDigitsObj; - }catch (Exception e){ + } catch (Exception e) { throw new RuntimeException("小数点位数必须是整数"); } } - if(object instanceof DataType){ - DataType dataType=(DataType)object; - if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ - return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + if (object instanceof DataType) { + DataType dataType = (DataType) object; + if (dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)) { + return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString()); } - number=dataType.getContent(); - }else{ + number = dataType.getContent(); + } else { BigDecimal db = new BigDecimal(object.toString()); - number=db; + number = db; } - if(!RegularUtil.isNumber(number)){ - return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + if (!RegularUtil.isNumber(number)) { + return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString()); } - BigDecimal bigDecimal = new BigDecimal(number+""); + BigDecimal bigDecimal = new BigDecimal(number + ""); Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_HALF_UP).doubleValue(); - if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); - return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + if (numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); + return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString()); } @Override public DataType aggregation(Object... objects) { - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.AGGREGATION.getName()); - Double result=0d; - if(objects.length==0||objects.length<2){ - return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); + Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.AGGREGATION.getName()); + Double result = 0d; + if (objects.length == 0 || objects.length < 2) { + return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString()); } - List dataList=new ArrayList(); - for (int i=0;i dataList = new ArrayList(); + for (int i = 0; i < objects.length - 1; i++) { + boolean isArray = false; String paramType; Object objectData; - if(objects[i] instanceof DataType){ - DataType dataType1=(DataType) objects[i]; - paramType=dataType1.getDataType(); - objectData= ExcelParamUtil.getParamContent(dataType1,"string"); - }else if(objects[i] instanceof Object[]){ - Object[] arrayObjs=(Object[])objects[i]; - String arrayType=null; - objectData=""; - for (Object arrayObj:arrayObjs){ - String lcoalType=""; - if(arrayObj instanceof DataType){ - lcoalType=ExcelParamUtil.getParamType(arrayObj); - objectData+=ExcelParamUtil.getParamContent((DataType)arrayObj,"string")+"#"; - }else{ - lcoalType=ExcelParamUtil.getParamType(arrayObj.getClass().getName()); - objectData+=arrayObj+"#"; + if (objects[i] instanceof DataType) { + DataType dataType1 = (DataType) objects[i]; + paramType = dataType1.getDataType(); + objectData = ExcelParamUtil.getParamContent(dataType1, "string"); + } else if (objects[i] instanceof Object[]) { + Object[] arrayObjs = (Object[]) objects[i]; + String arrayType = null; + objectData = ""; + for (Object arrayObj : arrayObjs) { + String lcoalType = ""; + if (arrayObj instanceof DataType) { + lcoalType = ExcelParamUtil.getParamType(arrayObj); + objectData += ExcelParamUtil.getParamContent((DataType) arrayObj, "string") + "#"; + } else { + lcoalType = ExcelParamUtil.getParamType(arrayObj.getClass().getName()); + objectData += arrayObj + "#"; } - if(arrayType==null){ - arrayType=lcoalType; - }else{ - if(!arrayType.equals(lcoalType)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.AGGREGATION.toString(),errorNumber,errorNumber,"操作符参数类型不一致"); + if (arrayType == null) { + arrayType = lcoalType; + } else { + if (!arrayType.equals(lcoalType)) { + JSONObject errorJson = ErrorUtil.buildError(FuncNames.AGGREGATION.toString(), errorNumber, errorNumber, "操作符参数类型不一致"); throw new RuntimeException(errorJson.getString("msg")); } } } - paramType=arrayType; - isArray=true; - }else{ - paramType= ExcelParamUtil.getParamType(objects[i].getClass().getName()); - objectData=objects[i]; + paramType = arrayType; + isArray = true; + } else { + paramType = ExcelParamUtil.getParamType(objects[i].getClass().getName()); + objectData = objects[i]; } - paramType=ExcelParamUtil.checkParamType(paramType); - if(!paramType.equalsIgnoreCase(DataType.NUMBER)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.AGGREGATION.toString(),errorNumber,errorNumber,"统计函数只允许数字"); + paramType = ExcelParamUtil.checkParamType(paramType); + if (!paramType.equalsIgnoreCase(DataType.NUMBER)) { + JSONObject errorJson = ErrorUtil.buildError(FuncNames.AGGREGATION.toString(), errorNumber, errorNumber, "统计函数只允许数字"); throw new RuntimeException(errorJson.getString("msg")); } - if(isArray){ - String[] arrayStrs=objectData.toString().split("#"); - for (String arrayStr:arrayStrs){ - Double data=Double.parseDouble(arrayStr); + if (isArray) { + String[] arrayStrs = objectData.toString().split("#"); + for (String arrayStr : arrayStrs) { + Double data = Double.parseDouble(arrayStr); dataList.add(data); } - }else { - Double data=Double.parseDouble(objectData.toString()); + } else { + Double data = Double.parseDouble(objectData.toString()); dataList.add(data); } } - String aggType=objects[objects.length-1].toString().toLowerCase(); + String aggType = objects[objects.length - 1].toString().toLowerCase(); Collections.sort(dataList); - switch (aggType){ + switch (aggType) { case "avg": - for (Double data:dataList){ - result+=data; + for (Double data : dataList) { + result += data; } - result=result/dataList.size(); + result = result / dataList.size(); break; case "max": - result=dataList.get(dataList.size()-1); + result = dataList.get(dataList.size() - 1); break; case "min": - result=dataList.get(0); + result = dataList.get(0); break; default: - JSONObject errorJson= ErrorUtil.buildError(FuncNames.AGGREGATION.toString(),errorNumber,errorNumber,"统计函数需要类型参数"); + JSONObject errorJson = ErrorUtil.buildError(FuncNames.AGGREGATION.toString(), errorNumber, errorNumber, "统计函数需要类型参数"); throw new RuntimeException(errorJson.getString("msg")); } - return new DataType(DataType.NUMBER,result,ComponentType.NumberComponent.toString()); + return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString()); } @Override public DataType mod(Object... objects) { - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.MOD.getName()); - if(objects.length!=2){ - return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); + Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.MOD.getName()); + if (objects.length != 2) { + return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString()); } - Double doubleOne=0d; - Double doubleTwo=0d; - for (int i=0;i5){ - digitsIntVal=5; + if (RegularUtil.isNumber(numberVal) && RegularUtil.isNumber(digitsVal)) { + Double d = Double.parseDouble(digitsVal.toString()); + int digitsIntVal = d.intValue(); + if (digitsIntVal > 5) { + digitsIntVal = 5; } - BigDecimal b = new BigDecimal(numberVal.toString()); - f1 = b.setScale(digitsIntVal, BigDecimal.ROUND_HALF_UP).doubleValue(); - if(digitsIntVal==0){ - f1=b.intValue(); + BigDecimal b = new BigDecimal(numberVal.toString()); + f1 = b.setScale(digitsIntVal, BigDecimal.ROUND_HALF_UP).doubleValue(); + if (digitsIntVal == 0) { + f1 = b.intValue(); } - }else { - JSONObject errorJson= ErrorUtil.buildError(FuncNames.TRUNC.toString(),errorNumber,errorNumber,"小数点格式化只允许数字"); + } else { + JSONObject errorJson = ErrorUtil.buildError(FuncNames.TRUNC.toString(), errorNumber, errorNumber, "小数点格式化只允许数字"); throw new RuntimeException(errorJson.getString("msg")); } - return new DataType(DataType.NUMBER,f1,ComponentType.NumberComponent.toString()); + return new DataType(DataType.NUMBER, f1, "ComponentType.NumberComponent".toString()); } @Override - public DataType randomNumber(Object length,Object type) { - String value=""; - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.RANDOMNUMBER.getName()); - Double numberLength=0.0; - Object param=10; - String dataValueType=""; - if(length!=null){ - if(length instanceof DataType){ - DataType dataType=(DataType)length; - dataValueType=ExcelParamUtil.checkParamType(dataType); - param=ExcelParamUtil.getParamContent(length,""); - }else{ - dataValueType=ExcelParamUtil.checkParamType(length); - param=length; + public DataType randomNumber(Object length, Object type) { + String value = ""; + Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.RANDOMNUMBER.getName()); + Double numberLength = 0.0; + Object param = 10; + String dataValueType = ""; + if (length != null) { + if (length instanceof DataType) { + DataType dataType = (DataType) length; + dataValueType = ExcelParamUtil.checkParamType(dataType); + param = ExcelParamUtil.getParamContent(length, ""); + } else { + dataValueType = ExcelParamUtil.checkParamType(length); + param = length; } } //判断length长度数据类型是否合规 - if(!dataValueType.equalsIgnoreCase("number")){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数只允许数字参数"); + if (!dataValueType.equalsIgnoreCase("number")) { + JSONObject errorJson = ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(), errorNumber, errorNumber, "随机数函数只允许数字参数"); throw new RuntimeException(errorJson.getString("msg")); } //判断用户设置的length是否大于0,生成的随机数长度必须是大于1的 - if(param!=null){ - numberLength=Double.parseDouble(param.toString()); - if(numberLength<=0){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数长度必须大于0"); + if (param != null) { + numberLength = Double.parseDouble(param.toString()); + if (numberLength <= 0) { + JSONObject errorJson = ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(), errorNumber, errorNumber, "随机数函数长度必须大于0"); throw new RuntimeException(errorJson.getString("msg")); } } - String typeString=randomNumber; - if(type !=null){ - if(type instanceof DataType){ - DataType dataType=(DataType)length; - typeString=ExcelParamUtil.getParamContent(type,"").toString(); - }else{ - typeString=type.toString(); + String typeString = randomNumber; + if (type != null) { + if (type instanceof DataType) { + DataType dataType = (DataType) length; + typeString = ExcelParamUtil.getParamContent(type, "").toString(); + } else { + typeString = type.toString(); } } - switch (typeString){ + switch (typeString) { case randomNumber: - value=randomFunc(numberLength,randomNumber); + value = randomFunc(numberLength, randomNumber); break; case randomChar: - value=randomFunc(numberLength,randomChar); + value = randomFunc(numberLength, randomChar); break; case randomNumANDChar: - value=randomFunc(numberLength,randomNumANDChar); + value = randomFunc(numberLength, randomNumANDChar); break; default: - JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数的返回值只允许数字、字符以及数字和字符的混合类型"); + JSONObject errorJson = ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(), errorNumber, errorNumber, "随机数的返回值只允许数字、字符以及数字和字符的混合类型"); throw new RuntimeException(errorJson.getString("msg")); } - return new DataType(DataType.NUMBER,value,ComponentType.NumberComponent.toString()); + return new DataType(DataType.NUMBER, value, "ComponentType.NumberComponent".toString()); } @Override @@ -394,70 +391,70 @@ public class MathFuncsServiceImpl implements MathFuncsService { @Override public DataType isInt(Object... objects) { - boolean isInt=false; - if(objects[0] instanceof DataType){ - DataType dataType=(DataType)objects[0]; - isInt=RegularUtil.isInteger(dataType.getContent()); - }else{ - isInt=RegularUtil.isInteger(objects[0]); + boolean isInt = false; + if (objects[0] instanceof DataType) { + DataType dataType = (DataType) objects[0]; + isInt = RegularUtil.isInteger(dataType.getContent()); + } else { + isInt = RegularUtil.isInteger(objects[0]); } - return new DataType(DataType.BOOL,isInt); + return new DataType(DataType.BOOL, isInt); } @Override public DataType isNumber(Object... objects) { - boolean isInt=false; - if(objects[0] instanceof DataType){ - DataType dataType=(DataType)objects[0]; - isInt=RegularUtil.isNumber(dataType.getContent()); - }else{ - isInt=RegularUtil.isNumber(objects[0]); + boolean isInt = false; + if (objects[0] instanceof DataType) { + DataType dataType = (DataType) objects[0]; + isInt = RegularUtil.isNumber(dataType.getContent()); + } else { + isInt = RegularUtil.isNumber(objects[0]); } - return new DataType(DataType.BOOL,isInt); + return new DataType(DataType.BOOL, isInt); } - private String randomFunc(Double length,String type){ + private String randomFunc(Double length, String type) { Random r = new Random(); - StringBuffer sbff=new StringBuffer(); + StringBuffer sbff = new StringBuffer(); //数字类型随机数 - if(type.equalsIgnoreCase("number")){ - for (double i=0;i0){ - charloop=(length-1)/2; - numloop=charloop+1; - }else{ - charloop=length/2; - numloop=charloop; + if (length % 2 > 0) { + charloop = (length - 1) / 2; + numloop = charloop + 1; + } else { + charloop = length / 2; + numloop = charloop; } } - for (double i=0;i 1) { - numDigitsObj = objects[1]; - if(numDigitsObj != null && numDigitsObj instanceof DataType) throw new RuntimeException("ROUNDUP函数第二个参数只能是常量"); - } - - //整数校验 - if(numDigitsObj != null){ - try{ - numDigits = (int) numDigitsObj; - }catch (Exception e){ - throw new RuntimeException("小数点位数必须是整数"); - } - } - - if(object instanceof DataType){ - DataType dataType=(DataType)object; - if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - number=dataType.getContent(); - }else{ - BigDecimal db = new BigDecimal(object.toString()); - number=db; - } - if(!RegularUtil.isNumber(number)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDUP.toString(),errorNumber,errorNumber,"ROUNDUP函数只接受数字参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - - BigDecimal bigDecimal = new BigDecimal(number+""); - Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_CEILING).doubleValue(); - - if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); - return new DataType(DataType.NUMBER, result); - } - - @Override - public DataType roundDown(Object... objects) { - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDDOWN.getName()); - Object number=null; - Object object = objects[0]; - - //小数位 - int numDigits = 0; - Object numDigitsObj = null; - - //获取小数点位数参数 - if(objects != null && objects.length > 1) { - numDigitsObj = objects[1]; - if(numDigitsObj != null && numDigitsObj instanceof DataType) throw new RuntimeException("ROUNDDOWN函数第二个参数只能是常量"); - } - - //整数校验 - if(numDigitsObj != null){ - try{ - numDigits = (int) numDigitsObj; - }catch (Exception e){ - throw new RuntimeException("小数点位数必须是整数"); - } - } - - if(object instanceof DataType){ - DataType dataType=(DataType)object; - if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUNDDOWN.toString(),errorNumber,errorNumber,"ROUNDDOWN函数只接受数字参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - number=dataType.getContent(); - }else{ - BigDecimal db = new BigDecimal(object.toString()); - number=db; - } - - if(!RegularUtil.isNumber(number)){ - return new DataType(DataType.NUMBER, 0,ComponentType.NumberComponent.toString()); - } - - BigDecimal bigDecimal = new BigDecimal(number+""); - Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_FLOOR).doubleValue(); - - if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); - return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); - } - - @Override - public DataType round(Object... objects) { - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUND.getName()); - Object number=null; - Object object = objects[0]; - - //小数位 - int numDigits = 0; - Object numDigitsObj = null; - - //获取小数点位数参数 - if(objects != null && objects.length > 1) { - numDigitsObj = objects[1]; - if(numDigitsObj != null && numDigitsObj instanceof DataType) throw new RuntimeException("ROUND函数第二个参数只能是常量"); - } - - //整数校验 - if(numDigitsObj != null){ - try{ - numDigits = (int) numDigitsObj; - }catch (Exception e){ - throw new RuntimeException("小数点位数必须是整数"); - } - } - - if(object instanceof DataType){ - DataType dataType=(DataType)object; - if(dataType.getDataType().equalsIgnoreCase(DataType.STRING)||dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUND.toString(),errorNumber,errorNumber,"ROUND函数只接受数字参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - number=dataType.getContent(); - }else{ - BigDecimal db = new BigDecimal(object.toString()); - number=db; - } - - if(!RegularUtil.isNumber(number)){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.ROUND.toString(),errorNumber,errorNumber,"ROUND函数只接受数字参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - - BigDecimal bigDecimal = new BigDecimal(number+""); - Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_HALF_UP).doubleValue(); - - if(numDigits == 0) return new DataType(DataType.NUMBER, result.intValue()); - return new DataType(DataType.NUMBER, result,ComponentType.NumberComponent.toString()); - } - - @Override - public DataType aggregation(Object... objects) { - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.AGGREGATION.getName()); - Double result=0d; - if(objects.length==0||objects.length<2){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.AGGREGATION.toString(),errorNumber,errorNumber,"统计函数至少需要两个参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - List dataList=new ArrayList(); - for (int i=0;i5){ - digitsIntVal=5; - } - BigDecimal b = new BigDecimal(numberVal.toString()); - f1 = b.setScale(digitsIntVal, BigDecimal.ROUND_HALF_UP).doubleValue(); - if(digitsIntVal==0){ - f1=b.intValue(); - } - }else { - JSONObject errorJson= ErrorUtil.buildError(FuncNames.TRUNC.toString(),errorNumber,errorNumber,"小数点格式化只允许数字"); - throw new RuntimeException(errorJson.getString("msg")); - } - return new DataType(DataType.NUMBER,f1,ComponentType.NumberComponent.toString()); - } - - @Override - public DataType randomNumber(Object length,Object type) { - String value=""; - Integer errorNumber=IgnoreParamFilter.getSetFuncNumber(FuncNames.RANDOMNUMBER.getName()); - Double numberLength=0.0; - Object param=10; - String dataValueType=""; - if(length!=null){ - if(length instanceof DataType){ - DataType dataType=(DataType)length; - dataValueType=ExcelParamUtil.checkParamType(dataType); - param=ExcelParamUtil.getParamContent(length,""); - }else{ - dataValueType=ExcelParamUtil.checkParamType(length); - param=length; - } - } - //判断length长度数据类型是否合规 - if(!dataValueType.equalsIgnoreCase("number")){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数只允许数字参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - //判断用户设置的length是否大于0,生成的随机数长度必须是大于1的 - if(param!=null){ - numberLength=Double.parseDouble(param.toString()); - if(numberLength<=0){ - JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数函数长度必须大于0"); - throw new RuntimeException(errorJson.getString("msg")); - } - } - - String typeString=randomNumber; - if(type !=null){ - if(type instanceof DataType){ - DataType dataType=(DataType)length; - typeString=ExcelParamUtil.getParamContent(type,"").toString(); - }else{ - typeString=type.toString(); - } - } - - switch (typeString){ - case randomNumber: - value=randomFunc(numberLength,randomNumber); - break; - case randomChar: - value=randomFunc(numberLength,randomChar); - break; - case randomNumANDChar: - value=randomFunc(numberLength,randomNumANDChar); - break; - default: - JSONObject errorJson= ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(),errorNumber,errorNumber,"随机数的返回值只允许数字、字符以及数字和字符的混合类型"); - throw new RuntimeException(errorJson.getString("msg")); - - } - - return new DataType(DataType.NUMBER,value,ComponentType.NumberComponent.toString()); - } - - @Override - public DataType group(Object... objects) { - return null; - } - - @Override - public DataType isInt(Object... objects) { - if(objects==null || objects.length==0){ - throw new RuntimeException("【ISINT】函数的参数不能为空"); - } - Object paramObj=objects[0]; - String type=""; - Object content; - if(paramObj instanceof DataType){ - DataType paramDataType=(DataType)paramObj; - type=paramDataType.getDataType(); - content=paramDataType.getContent(); - }else{ - type=ExcelParamUtil.getParamType(paramObj.getClass().getName()); - content=paramObj; - } - if(!type.equalsIgnoreCase("String") && !type.equalsIgnoreCase("number")){ - throw new RuntimeException("【ISINT】函数的参数必须为字符或者数字类型"); - } - - return new DataType(DataType.BOOL,true); - } - - @Override - public DataType isNumber(Object... objects) { - if(objects==null || objects.length==0){ - throw new RuntimeException("【ISNUMBER】函数的参数不能为空"); - } - Object paramObj=objects[0]; - String type=""; - Object content; - if(paramObj instanceof DataType){ - DataType paramDataType=(DataType)paramObj; - type=paramDataType.getDataType(); - content=paramDataType.getContent(); - }else{ - type=ExcelParamUtil.getParamType(paramObj.getClass().getName()); - content=paramObj; - } - if(!type.equalsIgnoreCase("String")){ - throw new RuntimeException("【ISNUMBER】函数的参数必须为字符类型"); - } - return new DataType(DataType.BOOL,false); - } - - private String randomFunc(Double length,String type){ - Random r = new Random(); - StringBuffer sbff=new StringBuffer(); - - //数字类型随机数 - if(type.equalsIgnoreCase("number")){ - for (double i=0;i0){ - charloop=(length-1)/2; - numloop=charloop+1; - }else{ - charloop=length/2; - numloop=charloop; - } - } - for (double i=0;i newObjs=new ArrayList<>(); - for (int i=0;i0){ - for(Object object:newObjs){ - newString.append(ExcelParamUtil.getParamContent(object,"string")); - } - } - return new DataType(DataType.STRING,newString.toString(), ComponentType.Text.toString()); - } - - @Override - public DataType text(Object... objs) { - String func="TEXT"; - Integer number=IgnoreParamFilter.getSetFuncNumber(func); - if(null==objs||objs.length>1){ - JSONObject errorJson= ErrorUtil.buildError(func,0,number,func+"函数参数只允许一个参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - Object obj=objs[0]; - if(null==obj){ - JSONObject errorJson= ErrorUtil.buildError(func,0,number,func+"函数参数为空"); - throw new RuntimeException(errorJson.getString("msg")); - } - Object result; - if(obj instanceof DataType){ - DataType dataType=(DataType)obj; - result=ExcelParamUtil.getParamContent(dataType,"string").toString(); - }else { - result=obj.toString(); - } - - return new DataType(DataType.STRING,result,ComponentType.Text.toString()); - } - - @Override - public DataType value(Object... objs) { - Object txt=objs[0]; - Object result; - Class[] typeObjects=new Class[]{}; - - IgnoreParamFilter.commonFilter("VALUE",1,1,typeObjects,objs); - String regEx="[^0-9]"; - Pattern p = Pattern.compile(regEx); - String paramContent=""; - if(ExcelParamUtil.getParamContent(txt,"string")!=null){ - paramContent=ExcelParamUtil.getParamContent(txt,"string")!=null?ExcelParamUtil.getParamContent(txt,"string").toString():""; - } - if(!RegularUtil.isNumber(paramContent)){ - paramContent="0"; - } - Matcher m = p.matcher(paramContent); - String numberStr=m.replaceAll("").trim(); - if(!numberStr.equals("")){ - if(numberStr.length()>19){ - numberStr=numberStr.substring(0,19); - } - Long txtTint=Long.parseLong(numberStr); - result=txtTint; - }else { - result=0; - } - return new DataType(DataType.NUMBER,result,ComponentType.Text.toString()); - } - - @Override - public DataType len(Object... txt) { - Class[] typeObjects=new Class[]{String.class}; - IgnoreParamFilter.commonFilter("LEN",1,1,typeObjects,txt); - int length=ExcelParamUtil.getParamContent(txt[0],"string").toString().length(); - - return new DataType(DataType.NUMBER,length,ComponentType.Text.toString()); - } - - @Override - public DataType search(Object... objects) { - Class[] typeObjects=new Class[]{String.class,String.class,Integer.class}; - int idx=0; - IgnoreParamFilter.commonFilter("SEARCH",2,3,typeObjects,objects); - return new DataType(DataType.NUMBER,0,ComponentType.NumberComponent.toString()); - } - - @Override - public DataType replace(Object... objects) { - Object result; - Class[] typeObjects=new Class[]{String.class,Integer.class,Integer.class,String.class}; - IgnoreParamFilter.commonFilter("REPLACE",4,4,typeObjects,objects); - return new DataType(DataType.STRING,"泛微网络",ComponentType.Text.toString()); - } - - @Override - public DataType repeat(Object... objects) { - Object result; - Class[] typeObjects=new Class[]{String.class,Integer.class}; - IgnoreParamFilter.commonFilter("REPEAT",2,2,typeObjects,objects); - String str=ExcelParamUtil.getParamContent(objects[0],"string").toString(); - Double repeatD=Double.parseDouble(ExcelParamUtil.getParamContent(objects[1],"string").toString()); - int repeat=repeatD.intValue(); - StringBuffer sbf=new StringBuffer(); - for(int i=0;i chars=new ArrayList<>(); - sourceStr=ExcelParamUtil.appendString(fillStr,sourceStr,sourceLength,fillPosition); - } - result=sourceStr; - return new DataType(DataType.STRING,result,ComponentType.Text.toString()); - } - - @Override - public DataType trim(Object... objects) { - Object result; - Class[] typeObjects=new Class[]{String.class}; - IgnoreParamFilter.commonFilter("TRIM",1,1,typeObjects,objects); - - String sourceStr=ExcelParamUtil.getParamContent(objects[0],"string").toString().trim(); - result=sourceStr; - return new DataType(DataType.STRING,result,ComponentType.Text.toString()); - } - - @Override - public DataType left(Object... objects) { - Object result; - Class[] typeObjects=new Class[]{String.class,Integer.class}; - IgnoreParamFilter.commonFilter("LEFT",2,2,typeObjects,objects); - result="泛微"; - return new DataType(DataType.STRING,result,ComponentType.Text.toString()); - } - - @Override - public DataType right(Object... objects) { - Object result; - Class[] typeObjects=new Class[]{String.class,Integer.class}; - IgnoreParamFilter.commonFilter("RIGHT",2,2,typeObjects,objects); - result="泛微"; - return new DataType(DataType.STRING,result,ComponentType.Text.toString()); - } - - @Override - public DataType mid(Object... objects) { - Object result; - Class[] typeObjects=new Class[]{String.class,Integer.class,Integer.class}; - IgnoreParamFilter.commonFilter("MID",3,3,typeObjects,objects); - result="泛微云"; - return new DataType(DataType.STRING,result,ComponentType.Text.toString()); - } - - @Override - public DataType score(Object... objs) { - Object result; - IgnoreParamFilter.checkFraction("SCORE",objs); - DataType fraction=(DataType)objs[0]; - result=fraction.getScore(); - if(result==null){ - result=0; - } - return new DataType(DataType.NUMBER,result,ComponentType.NumberComponent.toString()); - } - - @Override - public DataType idCard(Object... objects) { - Integer number=IgnoreParamFilter.getSetFuncNumber(FuncNames.IDCARD.getName()); - DataType result=new DataType(); - IgnoreParamFilter.checkValiIdCard("IDCARD",objects); - if(objects[0] instanceof DataType){ - DataType dataType=(DataType) objects[0]; - dataType.setContent("43070319900202665X"); - dataType.setText("43070319900202665X"); - } - RegularUtil.validateIDCard(ExcelParamUtil.getParamContent(objects[0],"string").toString()); - String operType=objects[1].toString(); - String idCard=objects[0].toString(); - if(operType.equalsIgnoreCase("BD")){ - result=bd(idCard); - }else if(operType.equalsIgnoreCase("NA")){ - result=nativePlace(idCard); - }else if(operType.equalsIgnoreCase("AGE")){ - result=age(idCard); - }else if(operType.equalsIgnoreCase("GENDER")){ - result=sex(idCard); - }else{ - JSONObject errorJson=ErrorUtil.buildError("IDCARD",number,number,"IDCARD函数参数错误"); - throw new RuntimeException(errorJson.getString("msg")); - } - return result; - } - - - @Override - public DataType sex(String idCard) { - return new DataType(DataType.STRING,"男",ComponentType.Text.toString()); - } - - @Override - public DataType nativePlace(String idCard) { - return new DataType(DataType.STRING,"上海市闵行区浦江",ComponentType.Text.toString()); - } - - @Override - public DataType age(String idCard) { - return new DataType(DataType.NUMBER,18,ComponentType.NumberComponent.toString()); - } - - @Override - public DataType bd(String idCard) { - return new DataType(DataType.STRING,"2020-11-11",ComponentType.Text.toString()); - } - - @Override - public DataType addressAnalysis(Object obj1, Object obj2) { - Integer number=IgnoreParamFilter.getSetFuncNumber(FuncNames.ADDRESS.getName()); - String addressType=ExcelParamUtil.checkParamType(obj1); - String levelType=ExcelParamUtil.checkParamType(obj2); - if(!addressType.equalsIgnoreCase("string") || !levelType.equalsIgnoreCase("string")){ - JSONObject errorJson=ErrorUtil.buildError(FuncNames.ADDRESS.toString(),number,number,"地址解析函数的参数只允许字符类型"); - throw new RuntimeException(errorJson.getString("msg")); - } - String level=""; - if(obj2 instanceof DataType){ - level=ExcelParamUtil.getParamContent(obj2,"").toString(); - }else { - level=obj2.toString(); - } - - String result=""; - switch (level){ - case PROVINCE: - break; - case CITY: - break; - case TOWN: - break; - case ADDR: - break; - default: - JSONObject errorJson=ErrorUtil.buildError(FuncNames.ADDRESS.toString(),number,number,"行政区块只支持省、市、区县"); - throw new RuntimeException(errorJson.getString("msg")); - - } - - return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); - } - - @Override - public DataType subString(Object... objects) { - if(objects==null || objects.length!=3){ - throw new RuntimeException("字符截取函数只允许3个参数:源字符、截取开始位置、截取结束位置"); - } - List paramTypeList=new ArrayList<>(); - paramTypeList.add(DataType.STRING); - paramTypeList.add(DataType.NUMBER); - paramTypeList.add(DataType.NUMBER); - List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); - if(errorIdxList!=null && errorIdxList.size()>0){ - String errorMsg=""; - switch (errorIdxList.get(0)){ - case 0: - errorMsg="【SUBSTRING 字符截取函数】的第一个参数只能是字符串"; - break; - case 1: - errorMsg="【SUBSTRING 字符截取函数】的第二个参数只能是数字"; - break; - case 2: - errorMsg="【SUBSTRING 字符截取函数】的第三个参数只能是数字"; - break; - default: - errorMsg="【SUBSTRING 字符截取函数】的参数异常"; - break; - } - throw new RuntimeException(errorMsg); - } - return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); - } - - @Override - public DataType substitue(Object... objects) { - if(objects==null || objects.length!=3){ - throw new RuntimeException("字符查找替换函数只允许3个参数:源字符、被替换字符、新字符"); - } - List paramTypeList=new ArrayList<>(); - paramTypeList.add(DataType.STRING); - paramTypeList.add(DataType.STRING); - paramTypeList.add(DataType.STRING); - List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); - if(errorIdxList!=null && errorIdxList.size()>0){ - String errorMsg=""; - switch (errorIdxList.get(0)){ - case 0: - errorMsg="【SUBSTITUE 字符查找替换函数】的第一个参数只能是字符串"; - break; - case 1: - errorMsg="【SUBSTITUE 字符查找替换函数】的第二个参数只能是字符串"; - break; - case 2: - errorMsg="【SUBSTITUE 字符查找替换函数】的第三个参数只能是字符串"; - break; - default: - errorMsg="【SUBSTITUE 字符查找替换函数】的参数异常"; - break; - } - throw new RuntimeException(errorMsg); - } - - return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); - } - - @Override - public DataType extract(Object... objects) { - if(objects==null || objects.length!=2){ - throw new RuntimeException("字符提取函数只允许2个参数:源字符、提取类型"); - } - List paramTypeList=new ArrayList<>(); - paramTypeList.add(DataType.STRING); - paramTypeList.add(DataType.STRING); - List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); - if(errorIdxList!=null && errorIdxList.size()>0){ - String errorMsg=""; - switch (errorIdxList.get(0)){ - case 0: - errorMsg="【EXTRACT 字符提取函数】的第一个参数只能是字符串"; - break; - case 1: - errorMsg="【EXTRACT 字符提取函数】的第二个参数只能是字符串"; - break; - default: - errorMsg="【EXTRACT 字符提取函数】的参数异常"; - break; - } - throw new RuntimeException(errorMsg); - } - return new DataType(DataType.STRING,"上海市",ComponentType.Text.toString()); - } - - @Override - public DataType lower(Object... objects) { - if(objects==null || objects.length!=1){ - throw new RuntimeException("字符小写函数只允许1个参数:源字符"); - } - List paramTypeList=new ArrayList<>(); - paramTypeList.add(DataType.STRING); - List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); - if(errorIdxList!=null && errorIdxList.size()>0){ - throw new RuntimeException("【LOWER 字符小写函数】的参数只能是字符串"); - } - return new DataType(DataType.STRING,"abc",ComponentType.Text.toString()); - } - - @Override - public DataType upper(Object... objects) { - if(objects==null || objects.length!=1){ - throw new RuntimeException("字符大写函数只允许1个参数:源字符"); - } - List paramTypeList=new ArrayList<>(); - paramTypeList.add(DataType.STRING); - List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); - if(errorIdxList!=null && errorIdxList.size()>0){ - throw new RuntimeException("【UPPER 字符大写函数】的参数只能是字符串"); - } - return new DataType(DataType.STRING,"ABC",ComponentType.Text.toString()); - } - - @Override - public DataType exact(Object... objects) { - if(objects==null || objects.length!=2){ - throw new RuntimeException("字符比较函数只允许2个参数:字符、字符"); - } - List paramTypeList=new ArrayList<>(); - paramTypeList.add(DataType.STRING); - paramTypeList.add(DataType.STRING); - List errorIdxList=IgnoreParamFilter.checkParamType(objects,paramTypeList); - if(errorIdxList!=null && errorIdxList.size()>0){ - String errorMsg=""; - switch (errorIdxList.get(0)){ - case 0: - errorMsg="【EXACT 字符比较函数】的第一个参数只能是字符串"; - break; - case 1: - errorMsg="【EXACT 字符比较函数】的第二个参数只能是字符串"; - break; - default: - errorMsg="【EXTRACT 字符比较函数】的参数异常"; - break; - } - throw new RuntimeException(errorMsg); - } - return new DataType(DataType.BOOL,true); - } - - @Override - public DataType isString(Object... objects) { - if(objects==null){ - throw new RuntimeException("ISSTRING函数的参数不能为空"); - } - if(objects.length!=1){ - throw new RuntimeException("ISSTRING函数只能有一个参数"); - } - Object object=objects[0]; - String fieldType=""; - DataType resultDataType; - if(object instanceof DataType){ - DataType dataType=(DataType)object; - fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); - }else { - fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); - } - if(fieldType.equalsIgnoreCase("string")){ - resultDataType=new DataType(DataType.BOOL,true); - }else{ - resultDataType=new DataType(DataType.BOOL,false); - } - return resultDataType; - } - - @Override - public DataType isJson(Object... objects) { - Object object=objects[0]; - String fieldType=""; - DataType resultDataType; - Object content=null; - if(object instanceof DataType){ - DataType dataType=(DataType)object; - content=dataType.getContent(); - fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); - }else { - fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); - content=object; - } - if(fieldType.equalsIgnoreCase("string")){ - if(content!=null){ - try { - logger.info("isJson函数的JSON字符转换:"+content+""); - resultDataType=new DataType(DataType.BOOL,true); - } catch (Exception e) { - logger.info("err",e); - logger.info("不是正常的JSON字符"); - resultDataType=new DataType(DataType.BOOL,false); - } - }else{ - resultDataType=new DataType(DataType.BOOL,false); - } - }else{ - resultDataType=new DataType(DataType.BOOL,false); - } - return resultDataType; - } - - @Override - public DataType getJSONValue(Object... objects) { - Object object=objects[0]; - String fieldType=""; - DataType resultDataType; - Object content=null; - if(object instanceof DataType){ - DataType dataType=(DataType)object; - content=dataType.getContent(); - fieldType= ExcelParamUtil.checkParamType(dataType.getDataType()); - }else { - fieldType= ExcelParamUtil.getParamType(object.getClass().getName()); - content=object; - } - if(fieldType.equalsIgnoreCase("string")){ - if(content!=null){ - try { - logger.info("isJson函数的JSON字符转换:"+content+""); - resultDataType=new DataType(DataType.STRING,"JSON字符"); - } catch (Exception e) { - logger.info("err",e); - logger.info("不是正常的JSON字符"); - throw new RuntimeException("GETJSONVALUE函数只能接收JSON字符"); - } - }else{ - throw new RuntimeException("GETJSONVALUE函数只能接收JSON字符"); - } - }else{ - throw new RuntimeException("GETJSONVALUE函数只能接收JSON字符"); - } - return resultDataType; - } -} diff --git a/src/com/engine/salary/formlua/util/DateUtil.java b/src/com/engine/salary/formlua/util/DateUtil.java index 9abbdeb30..64e97e2bd 100644 --- a/src/com/engine/salary/formlua/util/DateUtil.java +++ b/src/com/engine/salary/formlua/util/DateUtil.java @@ -1,6 +1,6 @@ package com.engine.salary.formlua.util; -import com.weaver.excel.formula.entity.parameter.DataType; +import com.engine.salary.formlua.entity.parameter.DataType; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.joda.time.DateTime; diff --git a/src/com/engine/salary/formlua/util/ExcelParamUtil.java b/src/com/engine/salary/formlua/util/ExcelParamUtil.java index 8d576c7b5..0e51fe919 100644 --- a/src/com/engine/salary/formlua/util/ExcelParamUtil.java +++ b/src/com/engine/salary/formlua/util/ExcelParamUtil.java @@ -1,15 +1,10 @@ package com.engine.salary.formlua.util; import com.alibaba.fastjson.JSONObject; -import com.engine.salary.entity.datacollection.DataCollectionEmployee; -import com.engine.salary.entity.salaryformula.po.FormulaVar; import com.engine.salary.formlua.entity.parameter.DataType; -import com.weaver.common.form.component.base.Component; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.common.form.conditionrule.FixedField; -import com.weaver.common.form.metadata.ModuleSource; -import com.weaver.excel.formula.entity.parameter.*; -import com.weaver.excel.formula.entity.standard.execute.FixFieldType; +import com.engine.salary.formlua.entity.parameter.IllegalList; +import com.engine.salary.formlua.entity.parameter.ParamType; +import com.engine.salary.formlua.entity.standard.execute.FixFieldType; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -306,26 +301,26 @@ public class ExcelParamUtil { } - public static void checkParamArrayDataType(List formulavars) { - for (FormulaVar formulaVar : formulavars) { - if (formulaVar.getComponentKey() != null && !formulaVar.getComponentKey().equals("")) { - String componentKey = formulaVar.getComponentKey(); - Arrays.sort(NUMBERCOMPONENTS); - int searchIdx = Arrays.binarySearch(NUMBERCOMPONENTS, componentKey); - if (searchIdx >= 0) { - formulaVar.setFieldType("Number"); - } - Arrays.sort(ReturnType.CHECK_TYPE); - if (Arrays.binarySearch(ReturnType.CHECK_TYPE, componentKey) >= 0) { - formulaVar.setFieldType("String"); - } - if (formulaVar.getOptionId() != null) { - formulaVar.setFieldType("String"); - } - } - - } - } +// public static void checkParamArrayDataType(List formulavars) { +// for (FormulaVar formulaVar : formulavars) { +// if (formulaVar.getComponentKey() != null && !formulaVar.getComponentKey().equals("")) { +// String componentKey = formulaVar.getComponentKey(); +// Arrays.sort(NUMBERCOMPONENTS); +// int searchIdx = Arrays.binarySearch(NUMBERCOMPONENTS, componentKey); +// if (searchIdx >= 0) { +// formulaVar.setFieldType("Number"); +// } +// Arrays.sort(ReturnType.CHECK_TYPE); +// if (Arrays.binarySearch(ReturnType.CHECK_TYPE, componentKey) >= 0) { +// formulaVar.setFieldType("String"); +// } +// if (formulaVar.getOptionId() != null) { +// formulaVar.setFieldType("String"); +// } +// } +// +// } +// } /** @@ -335,59 +330,59 @@ public class ExcelParamUtil { * @param formulaVars * @return */ - public static String replaceAllParam(String sql, List formulaVars) { - if (null == formulaVars) { - return sql; - } - //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 - String partternStr = "\\{.+?\\}{1}?"; - Pattern pt = Pattern.compile(partternStr); - Matcher matcher = pt.matcher(sql); - - int loop = 0; - //替换逻辑 - while (matcher.find()) { - String matherString = matcher.group(); - //替换特殊字符 - matherString = matherString.replace("{", ""); - matherString = matherString.replace("}", ""); - matherString = matherString.replace("(", "\\("); - matherString = matherString.replace(")", "\\)"); - matherString = matherString.replaceAll("\\+", "\\\\+"); - matherString = matherString.replaceAll("\\-", "\\\\-"); - matherString = matherString.replaceAll("\\*", "\\\\*"); - matherString = matherString.replaceAll("\\/", "\\\\/"); - if (formulaVars != null && loop < formulaVars.size()) { - FormulaVar formulaVar = formulaVars.get(loop); - //如果参数异常,获取Key为空,根据数据中相应的值做判断,判断是什么类型的控件 - if (formulaVar.getKey() == null) { - //表格类型变量替换 - if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null) { - sql = sql.replaceFirst(matherString, formulaVar.getFormId().toString()); - //普通变量的替换 - } else if (formulaVar.getFormId() != null && formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { - sql = sql.replaceFirst(matherString, formulaVar.getFieldId().toString()); - } else if (formulaVar.getOptionId() != null) { - //选项型变量的替换是用optionID - sql = sql.replaceFirst(matherString, formulaVar.getOptionId().toString()); - } else { - sql = sql.replaceFirst(matherString, formulaVar.getOptionId().toString()); - } - } else { - //普通变量的替换是用Key - sql = sql.replaceFirst(matherString, formulaVar.getKey()); - } - loop++; - } - } - - ExcelParamUtil.findAggParam(sql); - - if (loop != formulaVars.size()) { - throw new RuntimeException("参数列表与执行语句不一致"); - } - return sql; - } +// public static String replaceAllParam(String sql, List formulaVars) { +// if (null == formulaVars) { +// return sql; +// } +// //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 +// String partternStr = "\\{.+?\\}{1}?"; +// Pattern pt = Pattern.compile(partternStr); +// Matcher matcher = pt.matcher(sql); +// +// int loop = 0; +// //替换逻辑 +// while (matcher.find()) { +// String matherString = matcher.group(); +// //替换特殊字符 +// matherString = matherString.replace("{", ""); +// matherString = matherString.replace("}", ""); +// matherString = matherString.replace("(", "\\("); +// matherString = matherString.replace(")", "\\)"); +// matherString = matherString.replaceAll("\\+", "\\\\+"); +// matherString = matherString.replaceAll("\\-", "\\\\-"); +// matherString = matherString.replaceAll("\\*", "\\\\*"); +// matherString = matherString.replaceAll("\\/", "\\\\/"); +// if (formulaVars != null && loop < formulaVars.size()) { +// FormulaVar formulaVar = formulaVars.get(loop); +// //如果参数异常,获取Key为空,根据数据中相应的值做判断,判断是什么类型的控件 +// if (formulaVar.getKey() == null) { +// //表格类型变量替换 +// if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null) { +// sql = sql.replaceFirst(matherString, formulaVar.getFormId().toString()); +// //普通变量的替换 +// } else if (formulaVar.getFormId() != null && formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { +// sql = sql.replaceFirst(matherString, formulaVar.getFieldId().toString()); +// } else if (formulaVar.getOptionId() != null) { +// //选项型变量的替换是用optionID +// sql = sql.replaceFirst(matherString, formulaVar.getOptionId().toString()); +// } else { +// sql = sql.replaceFirst(matherString, formulaVar.getOptionId().toString()); +// } +// } else { +// //普通变量的替换是用Key +// sql = sql.replaceFirst(matherString, formulaVar.getKey()); +// } +// loop++; +// } +// } +// +// ExcelParamUtil.findAggParam(sql); +// +// if (loop != formulaVars.size()) { +// throw new RuntimeException("参数列表与执行语句不一致"); +// } +// return sql; +// } /** @@ -673,138 +668,138 @@ public class ExcelParamUtil { return typeName; } - /** - * 运行公式时的参数设置 - * - * @param formulavars - * @param expressMap - * @return - */ - public static Map buildParam(List formulavars, Map expressMap) { - checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 - for (FormulaVar formulaVar : formulavars) { - DataType dataType = new DataType(); - String key = null; - if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null) { - key = "form" + formulaVar.getFormId(); - } else if (formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { - String fieldId = formulaVar.getFieldId().toString(); - key = "field" + fieldId; - dataType.setFieldId(fieldId); - } else if (formulaVar.getOptionId() != null) { - key = "option" + formulaVar.getOptionId(); - dataType.setContent(formulaVar.getOptionId()); - } else { - key = "option" + formulaVar.getOptionId(); - } - - Arrays.sort(funcArray); - int sidx = Arrays.binarySearch(funcArray, key); - if (sidx >= 0) { - throw new RuntimeException("变量名非法"); - } - if (formulaVar.getOptionId() != null) { - dataType.setDataType(DataType.OPTION); - } - if (expressMap.containsKey(key)) { - String newKey = ExcelParamUtil.randomNumber() + "_" + key; - expressMap.put(newKey, dataType); - formulaVar.setKey(newKey); - } else { - expressMap.put(key, dataType); - } - } - - return expressMap; - } - - /*** - * 验证函数时构建参数设置参数值 - * 把FormulaVar类型的参数封装成DataType类型参数 - * @param formulavars 入参类型 - * @param expressMap 返回Map - * @return - */ - public static Map buildLocalParam(List formulavars, Map expressMap, DataCollectionEmployee employee) { - - checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 - for (FormulaVar formulaVar : formulavars) { - DataType dataType = new DataType(); - dataType.setScore(0d); - dataType.setName((null == formulaVar.getName() || formulaVar.getName().equals("")) ? formulaVar.getParent() : formulaVar.getName()); - dataType.setFieldId(formulaVar.getFieldId() != null ? formulaVar.getFieldId().toString() : null); - String key = null; - if (formulaVar.getModule() != null && !formulaVar.getModule().equals("")) { - try { - dataType.setModule(formulaVar.getModule()); - } catch (IllegalArgumentException e) { - logger.error("err", e); - dataType.setModule(formulaVar.getModule()); - } - } - dataType.setFormId(formulaVar.getFormId() != null ? Long.parseLong(formulaVar.getFormId()) : null); - if (formulaVar.getName() != null && formulaVar.getName().equals("当前操作人")) { - key = formulaVar.getKey(); - formulaVar.setContent(employee.getUserId().toString()); - dataType.setContent(formulaVar.getContent()); - dataType.setText(formulaVar.getContent()); - dataType.setDataType(DataType.OPTION); - } else { - if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null && formulaVar.getOptionId() == null) { - key = "form" + formulaVar.getFormId().toString(); - ThreadLocalData threadLocalData = new ThreadLocalData(); - threadLocalData.setEmployee(employee); - threadLocalData.setModuleSource(ModuleSource.biaoge); - ParamContext.get().setValue(formulaVar.getFormId().toString(), threadLocalData); - } else if (formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { - String fieldId = formulaVar.getFieldId().toString(); - key = "field" + fieldId; - dataType.setFieldId(fieldId); - } else if (formulaVar.getOptionId() != null) { - key = "option" + formulaVar.getOptionId().toString(); - dataType.setContent(formulaVar.getOptionId()); - dataType.setText(formulaVar.getName()); - dataType.setFormId(null); - } else { - key = "option" + formulaVar.getOptionId().toString(); - } - } - - Arrays.sort(funcArray); - int sidx = Arrays.binarySearch(funcArray, key); - if (sidx >= 0) { - throw new RuntimeException("变量名非法"); - } - if (formulaVar.getOptionId() != null) { - dataType.setDataType(DataType.OPTION); - } - - if (StringUtils.isEmpty(dataType.getDataType())) { - String typeKey = null; - if (StringUtils.isNotEmpty(formulaVar.getFieldType())) { - typeKey = formulaVar.getFieldType(); - } else if (StringUtils.isNotEmpty(formulaVar.getType())) { - typeKey = formulaVar.getType(); - } else if (StringUtils.isNotEmpty(formulaVar.getFieldType())) { - typeKey = formulaVar.getFieldType(); - } - dataType.setDataType(ExcelParamUtil.findTestDataType(typeKey)); - } - if (StringUtils.isEmpty(dataType.getComponentKey())) { - dataType.setComponentKey(formulaVar.getComponentKey()); - } - if (expressMap.containsKey(key)) { - String newKey = key + ExcelParamUtil.randomNumber(); - formulaVar.setKey(newKey); - dataType.setAggCndKey(key); - expressMap.put(newKey, dataType); - } else { - expressMap.put(key, dataType); - } - } - - return expressMap; - } +// /** +// * 运行公式时的参数设置 +// * +// * @param formulavars +// * @param expressMap +// * @return +// */ +// public static Map buildParam(List formulavars, Map expressMap) { +// checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 +// for (FormulaVar formulaVar : formulavars) { +// DataType dataType = new DataType(); +// String key = null; +// if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null) { +// key = "form" + formulaVar.getFormId(); +// } else if (formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { +// String fieldId = formulaVar.getFieldId().toString(); +// key = "field" + fieldId; +// dataType.setFieldId(fieldId); +// } else if (formulaVar.getOptionId() != null) { +// key = "option" + formulaVar.getOptionId(); +// dataType.setContent(formulaVar.getOptionId()); +// } else { +// key = "option" + formulaVar.getOptionId(); +// } +// +// Arrays.sort(funcArray); +// int sidx = Arrays.binarySearch(funcArray, key); +// if (sidx >= 0) { +// throw new RuntimeException("变量名非法"); +// } +// if (formulaVar.getOptionId() != null) { +// dataType.setDataType(DataType.OPTION); +// } +// if (expressMap.containsKey(key)) { +// String newKey = ExcelParamUtil.randomNumber() + "_" + key; +// expressMap.put(newKey, dataType); +// formulaVar.setKey(newKey); +// } else { +// expressMap.put(key, dataType); +// } +// } +// +// return expressMap; +// } +// +// /*** +// * 验证函数时构建参数设置参数值 +// * 把FormulaVar类型的参数封装成DataType类型参数 +// * @param formulavars 入参类型 +// * @param expressMap 返回Map +// * @return +// */ +// public static Map buildLocalParam(List formulavars, Map expressMap, DataCollectionEmployee employee) { +// +// checkParamArrayDataType(formulavars);//检查控件类型,设置相应控件对应的数据类型 +// for (FormulaVar formulaVar : formulavars) { +// DataType dataType = new DataType(); +// dataType.setScore(0d); +// dataType.setName((null == formulaVar.getName() || formulaVar.getName().equals("")) ? formulaVar.getParent() : formulaVar.getName()); +// dataType.setFieldId(formulaVar.getFieldId() != null ? formulaVar.getFieldId().toString() : null); +// String key = null; +// if (formulaVar.getModule() != null && !formulaVar.getModule().equals("")) { +// try { +// dataType.setModule(formulaVar.getModule()); +// } catch (IllegalArgumentException e) { +// logger.error("err", e); +// dataType.setModule(formulaVar.getModule()); +// } +// } +// dataType.setFormId(formulaVar.getFormId() != null ? Long.parseLong(formulaVar.getFormId()) : null); +// if (formulaVar.getName() != null && formulaVar.getName().equals("当前操作人")) { +// key = formulaVar.getKey(); +// formulaVar.setContent(employee.getUserId().toString()); +// dataType.setContent(formulaVar.getContent()); +// dataType.setText(formulaVar.getContent()); +// dataType.setDataType(DataType.OPTION); +// } else { +// if (formulaVar.getFormId() != null && formulaVar.getFieldId() == null && formulaVar.getOptionId() == null) { +// key = "form" + formulaVar.getFormId().toString(); +// ThreadLocalData threadLocalData = new ThreadLocalData(); +// threadLocalData.setEmployee(employee); +// threadLocalData.setModuleSource(ModuleSource.biaoge); +// ParamContext.get().setValue(formulaVar.getFormId().toString(), threadLocalData); +// } else if (formulaVar.getFieldId() != null && formulaVar.getOptionId() == null) { +// String fieldId = formulaVar.getFieldId().toString(); +// key = "field" + fieldId; +// dataType.setFieldId(fieldId); +// } else if (formulaVar.getOptionId() != null) { +// key = "option" + formulaVar.getOptionId().toString(); +// dataType.setContent(formulaVar.getOptionId()); +// dataType.setText(formulaVar.getName()); +// dataType.setFormId(null); +// } else { +// key = "option" + formulaVar.getOptionId().toString(); +// } +// } +// +// Arrays.sort(funcArray); +// int sidx = Arrays.binarySearch(funcArray, key); +// if (sidx >= 0) { +// throw new RuntimeException("变量名非法"); +// } +// if (formulaVar.getOptionId() != null) { +// dataType.setDataType(DataType.OPTION); +// } +// +// if (StringUtils.isEmpty(dataType.getDataType())) { +// String typeKey = null; +// if (StringUtils.isNotEmpty(formulaVar.getFieldType())) { +// typeKey = formulaVar.getFieldType(); +// } else if (StringUtils.isNotEmpty(formulaVar.getType())) { +// typeKey = formulaVar.getType(); +// } else if (StringUtils.isNotEmpty(formulaVar.getFieldType())) { +// typeKey = formulaVar.getFieldType(); +// } +// dataType.setDataType(ExcelParamUtil.findTestDataType(typeKey)); +// } +// if (StringUtils.isEmpty(dataType.getComponentKey())) { +// dataType.setComponentKey(formulaVar.getComponentKey()); +// } +// if (expressMap.containsKey(key)) { +// String newKey = key + ExcelParamUtil.randomNumber(); +// formulaVar.setKey(newKey); +// dataType.setAggCndKey(key); +// expressMap.put(newKey, dataType); +// } else { +// expressMap.put(key, dataType); +// } +// } +// +// return expressMap; +// } /** * 格式化变量为数字 @@ -1037,19 +1032,19 @@ public class ExcelParamUtil { return builder.toString(); } - public static FormulaVar getFixFieldVar(List list, String key) { - FormulaVar formulaVar = new FormulaVar(); - for (FixedField fixedField : list) { - if (fixedField.getKey().equals(key)) { - Component component = (Component) fixedField.getMatchs().get(0); - ComponentType componentType = component.getComponentKey(); - if (componentType.equals(ComponentType.Text)) { - - } - } - } - return formulaVar; - } +// public static FormulaVar getFixFieldVar(List list, String key) { +// FormulaVar formulaVar = new FormulaVar(); +// for (FixedField fixedField : list) { +// if (fixedField.getKey().equals(key)) { +// Component component = (Component) fixedField.getMatchs().get(0); +// ComponentType componentType = component.getComponentKey(); +// if (componentType.equals(ComponentType.Text)) { +// +// } +// } +// } +// return formulaVar; +// } public static String findAggCndStr(String sql, Map paramMap) { String partternStr = "(COUNT|SUM|MIN|MAX|AVG|count|sum|min|max)+\\(+(.)+\\)+"; diff --git a/src/com/engine/salary/formlua/util/ExcelStandardUtil.java b/src/com/engine/salary/formlua/util/ExcelStandardUtil.java index ba3cb6da8..fc6e95fab 100644 --- a/src/com/engine/salary/formlua/util/ExcelStandardUtil.java +++ b/src/com/engine/salary/formlua/util/ExcelStandardUtil.java @@ -1,492 +1,492 @@ -package com.engine.salary.formlua.util; - - -import com.alibaba.fastjson.JSON; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.excel.formula.api.entity.DataOption; -import com.weaver.excel.formula.api.entity.FormulaVar; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.entity.parameter.ParamFactory; -import com.weaver.excel.formula.entity.standard.front.CurrentVar; -import com.weaver.teams.domain.user.DataCollectionEmployee; -import com.weaver.teams.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ExcelStandardUtil { - protected static final Logger logger = LoggerFactory.getLogger(ExcelStandardUtil.class); - - public static Map replaceAllParam(String sql, List localVars,List dataVars, DataCollectionEmployee employee){ - if(null!=localVars){ - for (FormulaVar formulaVar:localVars){ - if(StringUtils.isNotEmpty(formulaVar.getDataId()) && StringUtils.isEmpty(formulaVar.getFormId())){ - formulaVar.setFormId(formulaVar.getDataId()); - } - if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_department")){ - formulaVar.setType("department"); - formulaVar.setComponentKey(ComponentType.Department.toString()); - } - if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_superior")){ - formulaVar.setType("employee"); - formulaVar.setComponentKey(ComponentType.Employee.toString()); - } - } - } - - Map dataMap=new HashMap<>(); - Map paramKeyMap=new HashMap<>(); - //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 - String partternStr="\\{.+?\\}{1}?"; - Pattern pt=Pattern.compile(partternStr); - Matcher matcher=pt.matcher(sql); - - int loop=0; - //替换逻辑 - while (matcher.find()){ - String matherString=matcher.group(); - //替换特殊字符 - matherString=matherString.replace("{",""); - matherString=matherString.replace("}",""); - matherString=matherString.replace("(","\\("); - matherString=matherString.replace(")","\\)"); - matherString=matherString.replaceAll("\\+","\\\\+"); - matherString=matherString.replaceAll("\\-","\\\\-"); - matherString=matherString.replaceAll("\\*","\\\\*"); - matherString=matherString.replaceAll("\\/","\\\\/"); - if(localVars!=null&&loop"+JSON.toJSONString(dataType)); - } - }else{ - String typeKey=localFormulaVar.getProperKey(); - if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ - typeKey=localFormulaVar.getFieldType(); - }else if(StringUtils.isNotEmpty(localFormulaVar.getType())){ - typeKey=localFormulaVar.getType(); - }else if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ - typeKey=localFormulaVar.getFieldType(); - localFormulaVar.setComponentKey(localFormulaVar.getFieldType()); - } - dataType.setDataType(ExcelParamUtil.findDataType(typeKey)); - dataType.setFieldId(localFormulaVar.getFieldId()); - dataType.setFormId(StringUtils.isNotEmpty(localFormulaVar.getFormId())?Long.parseLong(localFormulaVar.getFormId()):null); - try { - dataType.setModule(localFormulaVar.getModule()); - } catch (IllegalArgumentException e) { - logger.error("err",e); - dataType.setModule(localFormulaVar.getModule()); - } - dataType.setContent(""); - if(!paramKeyMap.containsKey(key)){ - paramKeyMap.put(key,dataType); - }else{ - logger.info("存在同名参数:"+key+"-->"+JSON.toJSONString(dataType)); - } - } - } - loop++; - } - } -// if(loop!=localVars.size()){ +//package com.engine.salary.formlua.util; +// +// +//import com.alibaba.fastjson.JSON; +//import com.weaver.common.form.component.base.ComponentType; +//import com.weaver.excel.formula.api.entity.DataOption; +//import com.weaver.excel.formula.api.entity.FormulaVar; +//import com.weaver.excel.formula.entity.parameter.DataType; +//import com.weaver.excel.formula.entity.parameter.ParamFactory; +//import com.weaver.excel.formula.entity.standard.front.CurrentVar; +//import com.weaver.teams.domain.user.DataCollectionEmployee; +//import com.weaver.teams.util.StringUtils; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +//import java.util.regex.Matcher; +//import java.util.regex.Pattern; +// +//public class ExcelStandardUtil { +// protected static final Logger logger = LoggerFactory.getLogger(ExcelStandardUtil.class); +// +// public static Map replaceAllParam(String sql, List localVars,List dataVars, DataCollectionEmployee employee){ +// if(null!=localVars){ +// for (FormulaVar formulaVar:localVars){ +// if(StringUtils.isNotEmpty(formulaVar.getDataId()) && StringUtils.isEmpty(formulaVar.getFormId())){ +// formulaVar.setFormId(formulaVar.getDataId()); +// } +// if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_department")){ +// formulaVar.setType("department"); +// formulaVar.setComponentKey(ComponentType.Department.toString()); +// } +// if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_superior")){ +// formulaVar.setType("employee"); +// formulaVar.setComponentKey(ComponentType.Employee.toString()); +// } +// } +// } +// +// Map dataMap=new HashMap<>(); +// Map paramKeyMap=new HashMap<>(); +// //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 +// String partternStr="\\{.+?\\}{1}?"; +// Pattern pt=Pattern.compile(partternStr); +// Matcher matcher=pt.matcher(sql); +// +// int loop=0; +// //替换逻辑 +// while (matcher.find()){ +// String matherString=matcher.group(); +// //替换特殊字符 +// matherString=matherString.replace("{",""); +// matherString=matherString.replace("}",""); +// matherString=matherString.replace("(","\\("); +// matherString=matherString.replace(")","\\)"); +// matherString=matherString.replaceAll("\\+","\\\\+"); +// matherString=matherString.replaceAll("\\-","\\\\-"); +// matherString=matherString.replaceAll("\\*","\\\\*"); +// matherString=matherString.replaceAll("\\/","\\\\/"); +// if(localVars!=null&&loop"+JSON.toJSONString(dataType)); +// } +// }else{ +// String typeKey=localFormulaVar.getProperKey(); +// if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ +// typeKey=localFormulaVar.getFieldType(); +// }else if(StringUtils.isNotEmpty(localFormulaVar.getType())){ +// typeKey=localFormulaVar.getType(); +// }else if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ +// typeKey=localFormulaVar.getFieldType(); +// localFormulaVar.setComponentKey(localFormulaVar.getFieldType()); +// } +// dataType.setDataType(ExcelParamUtil.findDataType(typeKey)); +// dataType.setFieldId(localFormulaVar.getFieldId()); +// dataType.setFormId(StringUtils.isNotEmpty(localFormulaVar.getFormId())?Long.parseLong(localFormulaVar.getFormId()):null); +// try { +// dataType.setModule(localFormulaVar.getModule()); +// } catch (IllegalArgumentException e) { +// logger.error("err",e); +// dataType.setModule(localFormulaVar.getModule()); +// } +// dataType.setContent(""); +// if(!paramKeyMap.containsKey(key)){ +// paramKeyMap.put(key,dataType); +// }else{ +// logger.info("存在同名参数:"+key+"-->"+JSON.toJSONString(dataType)); +// } +// } +// } +// loop++; +// } +// } +//// if(loop!=localVars.size()){ +//// throw new RuntimeException("参数列表与执行语句不一致"); +//// } +// dataMap.put("param",paramKeyMap); +// dataMap.put("sql",sql); +// return dataMap; +// } +// +// public static Map replaceAllParamForTest(String sql, List formulaVars, DataCollectionEmployee employee){ +// if(null==formulaVars){ +// return null; +// } +// for (FormulaVar formulaVar:formulaVars){ +// if(StringUtils.isNotEmpty(formulaVar.getDataId()) && StringUtils.isEmpty(formulaVar.getFormId())){ +// formulaVar.setFormId(formulaVar.getDataId()); +// if(StringUtils.isNotEmpty(formulaVar.getType()) && StringUtils.isEmpty(formulaVar.getComponentKey())){ +// if(formulaVar.getType().equalsIgnoreCase("operator") || formulaVar.getType().equalsIgnoreCase("employee")){ +// formulaVar.setComponentKey(""); +// } +// } +// } +// if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_department")){ +// formulaVar.setType("department"); +// formulaVar.setComponentKey("Department"); +// } +// if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_superior")){ +// formulaVar.setType("employee"); +// formulaVar.setComponentKey("Employee"); +// } +// } +// Map dataMap=new HashMap<>(); +// Map paramKeyMap=new HashMap<>(); +// //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 +// String partternStr="\\{.+?\\}{1}?"; +// Pattern pt=Pattern.compile(partternStr); +// Matcher matcher=pt.matcher(sql); +// +// int loop=0; +// //替换逻辑 +// while (matcher.find()){ +// String matherString=matcher.group(); +// //替换特殊字符 +// matherString=matherString.replace("{",""); +// matherString=matherString.replace("}",""); +// matherString=matherString.replace("(","\\("); +// matherString=matherString.replace(")","\\)"); +// matherString=matherString.replaceAll("\\+","\\\\+"); +// matherString=matherString.replaceAll("\\-","\\\\-"); +// matherString=matherString.replaceAll("\\*","\\\\*"); +// matherString=matherString.replaceAll("\\/","\\\\/"); +// if(formulaVars!=null&&loop replaceAllParamForTest(String sql, List formulaVars, DataCollectionEmployee employee){ - if(null==formulaVars){ - return null; - } - for (FormulaVar formulaVar:formulaVars){ - if(StringUtils.isNotEmpty(formulaVar.getDataId()) && StringUtils.isEmpty(formulaVar.getFormId())){ - formulaVar.setFormId(formulaVar.getDataId()); - if(StringUtils.isNotEmpty(formulaVar.getType()) && StringUtils.isEmpty(formulaVar.getComponentKey())){ - if(formulaVar.getType().equalsIgnoreCase("operator") || formulaVar.getType().equalsIgnoreCase("employee")){ - formulaVar.setComponentKey(""); - } - } - } - if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_department")){ - formulaVar.setType("department"); - formulaVar.setComponentKey("Department"); - } - if(StringUtils.isNotEmpty(formulaVar.getId()) && formulaVar.getId().equalsIgnoreCase("current_superior")){ - formulaVar.setType("employee"); - formulaVar.setComponentKey("Employee"); - } - } - Map dataMap=new HashMap<>(); - Map paramKeyMap=new HashMap<>(); - //正则表达式匹配所有用 { } 括号包起来的变量,然后跟参数列表中的参数一一对应做替换 - String partternStr="\\{.+?\\}{1}?"; - Pattern pt=Pattern.compile(partternStr); - Matcher matcher=pt.matcher(sql); - - int loop=0; - //替换逻辑 - while (matcher.find()){ - String matherString=matcher.group(); - //替换特殊字符 - matherString=matherString.replace("{",""); - matherString=matherString.replace("}",""); - matherString=matherString.replace("(","\\("); - matherString=matherString.replace(")","\\)"); - matherString=matherString.replaceAll("\\+","\\\\+"); - matherString=matherString.replaceAll("\\-","\\\\-"); - matherString=matherString.replaceAll("\\*","\\\\*"); - matherString=matherString.replaceAll("\\/","\\\\/"); - if(formulaVars!=null&&loop dataVars,DataCollectionEmployee employee){ - DataType dataType =new DataType(); - if(localFormulaVar == null){ - return null; - } - - String typeKey=localFormulaVar.getProperKey(); - if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ - typeKey=localFormulaVar.getFieldType(); - }else if(StringUtils.isNotEmpty(localFormulaVar.getType())){ - typeKey=localFormulaVar.getType(); - }else if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ - typeKey=localFormulaVar.getFieldType(); - localFormulaVar.setComponentKey(localFormulaVar.getFieldType()); - } - logger.info(localFormulaVar.getId()+"typeKey=:"+typeKey); - switch (ExcelParamUtil.findDataType(typeKey)){ - case DataType.DATE: - dataType.setDataType(DataType.STRING); - setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); - if(dataType.getContent()==null){ - dataType.setContent(""); - } - break; - case DataType.STRING: - dataType.setDataType(DataType.STRING); - setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); - if(dataType.getContent()==null){ - dataType.setContent(""); - } - break; - case DataType.NUMBER: - dataType.setDataType(DataType.NUMBER); - setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); - break; - case DataType.OPTION: - logger.info("函数构建选项型:"+JSON.toJSONString(localFormulaVar)); - dataType.setDataType(DataType.OPTION); - setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"option"); - if(dataType.getContent() == null){ - dataType.setContent(localFormulaVar.getId()!=null?localFormulaVar.getId():localFormulaVar.getOptionId()); - dataType.setText(dataType.getContent()+""); - } - //当前操作人赋值 - if(localFormulaVar.getId()!=null){ - switch (localFormulaVar.getId()){ - case "current_user": - dataType.setContent(employee.getId()); - dataType.setOptionContent(employee.getName()); - break; - case "current_superior": - dataType.setContent(employee.getSuperiorId()); - break; - case "current_department": - dataType.setContent(employee.getDepartmentId()); - break; - case "current_position": - dataType.setContent(employee.getPositionId()); - break; - default: - break; - } - logger.info("当前操作人赋值完成:"+JSON.toJSONString(dataType)); - } - break; - case DataType.DATASOURCE: - dataType.setDataType(DataType.DATASOURCE); - setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"option"); - break; - default: - logger.info("未匹配到参数类型:"+(JSON.toJSONString(localFormulaVar))); - break; - } - if(StringUtils.isNotEmpty(localFormulaVar.getDataType())){ - dataType.setDataType(localFormulaVar.getDataType()); - } - if(StringUtils.isEmpty(dataType.getComponentKey())){ - if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ - dataType.setComponentKey(localFormulaVar.getFieldType()); - }else if(StringUtils.isNotEmpty(localFormulaVar.getProperKey())){ - dataType.setComponentKey(localFormulaVar.getProperKey()); - }else if(StringUtils.isNotEmpty(localFormulaVar.getComponentKey())){ - dataType.setComponentKey(localFormulaVar.getComponentKey()); - } - } - dataType.setFieldId(localFormulaVar.getFieldId()+""); - dataType.setFormId(localFormulaVar.getFormId()!=null?Long.parseLong(localFormulaVar.getFormId()):null); - dataType.setEmployee(employee); - if(StringUtils.isNotEmpty(localFormulaVar.getModule())){ - try { - dataType.setModule(localFormulaVar.getModule()); - } catch (IllegalArgumentException e) { - logger.error("err",e); - dataType.setModule(localFormulaVar.getModule()); - } - } - dataType.setName(localFormulaVar.getTitle()!=null?localFormulaVar.getTitle():localFormulaVar.getName()); - logger.info("构建值完毕:"+JSON.toJSONString(dataType)); - return dataType; - } - private static void setContent(DataType dataType,String typeKey,String sourceVar,List targetVarList,String type){ - if(sourceVar==null){ - return ; - } - for (FormulaVar loopVar:targetVarList){ - switch (type){ - case "field": - if(sourceVar.equalsIgnoreCase(loopVar.getFieldId())){ - dataType.setContent(loopVar.getContent()!=null?loopVar.getContent():""); - dataType.setText(dataType.getContent()+""); - if(StringUtils.isNotEmpty(loopVar.getsFormId())){ - dataType.setSubFormId(Long.parseLong(loopVar.getsFormId())); - } - dataType.setComponentKey(loopVar.getComponentKey()); - }else{ - dataType.setComponentKey(typeKey); - } - break; - case "form": - if(sourceVar.equalsIgnoreCase(loopVar.getFormId())){ - dataType.setContent(loopVar.getContent()); - } - break; - case "option": - if(sourceVar.equalsIgnoreCase(loopVar.getFieldId())){ - dataType.setContent(loopVar.getContent()); - if(dataType.getContent()==null){ - dataType.setContent(loopVar.getOptionId()); - dataType.setText(loopVar.getOptionId()); - } - //常量 - if(StringUtils.isNotEmpty(loopVar.getOptionContent())){ - dataType.setOptionContent(loopVar.getOptionContent()); - }else if(loopVar.getDataOptionList()!=null && loopVar.getDataOptionList().size()>0){ - String optionContents=""; - List dataOptions=loopVar.getDataOptionList(); - for(DataOption dataOption:dataOptions){ - optionContents+=dataOption.getOptionContent()+","; - } - if(optionContents.lastIndexOf(",")>0){ - optionContents=optionContents.substring(0,optionContents.lastIndexOf(",")); - } - dataType.setOptionContent(optionContents); - }else {//变量 - dataType.setOptionContent(loopVar.getContent()); - } - - dataType.setScore(loopVar.getScore()); - if(StringUtils.isNotEmpty(loopVar.getsFormId())){ - dataType.setSubFormId(Long.parseLong(loopVar.getsFormId())); - } - dataType.setComponentKey(loopVar.getComponentKey()); - } - break; - default: - break; - } - } - } -} +// dataMap.put("param",paramKeyMap); +// dataMap.put("sql",sql); +// logger.info("函数校验参数:"+JSON.toJSONString(dataMap)); +// return dataMap; +// } +// +// private static DataType transFormulaVarToDataTypeTesy(FormulaVar formulaVar,DataCollectionEmployee employee){ +// DataType dataType =new DataType(); +// ParamFactory paramFactory=ParamFactory.getInstance(); +// dataType.setContent(formulaVar.getContent()); +// dataType.setText(formulaVar.getContent()); +// String typeKey=formulaVar.getProperKey(); +// if(StringUtils.isNotEmpty(formulaVar.getFieldType()) && StringUtils.isEmpty(typeKey)){//选项型取值 +// typeKey=formulaVar.getFieldType(); +// }else if(StringUtils.isNotEmpty(formulaVar.getType()) && StringUtils.isEmpty(typeKey)){//当前操作人取值 +// typeKey=formulaVar.getType(); +// }else if(StringUtils.isNotEmpty(formulaVar.getFieldType()) && StringUtils.isEmpty(typeKey)){ +// typeKey=formulaVar.getFieldType(); +// formulaVar.setComponentKey(formulaVar.getFieldType()); +// } +// switch (ExcelParamUtil.findDataType(typeKey)){ +// case DataType.DATE: +// dataType.setContent(paramFactory.getDateTimeValue()); +// dataType.setText(paramFactory.getDateTimeValue()); +// dataType.setDataType(DataType.STRING); +// dataType.setComponentKey("DateComponent"); +// break; +// case DataType.STRING: +// dataType.setContent(paramFactory.getCharValue()); +// dataType.setText(paramFactory.getCharValue()); +// dataType.setDataType(DataType.STRING); +// dataType.setComponentKey("Text"); +// break; +// case DataType.NUMBER: +// dataType.setContent(paramFactory.getDoubleValue()); +// dataType.setText(paramFactory.getDoubleValue()+""); +// dataType.setDataType(DataType.NUMBER); +// dataType.setComponentKey("NumberComponent"); +// break; +// case DataType.OPTION: +// dataType.setContent(paramFactory.getSelectValue()); +// dataType.setText(paramFactory.getSelectValue()); +// dataType.setScore(paramFactory.getDoubleValue()); +// dataType.setDataType(DataType.OPTION); +// +// if(formulaVar.getType()!=null && (formulaVar.getType().equalsIgnoreCase("employee") || formulaVar.getType().equalsIgnoreCase("operator")) || (formulaVar.getProperKey()!=null && formulaVar.getProperKey().equalsIgnoreCase("employee"))){ +// dataType.setContent(employee.getId()); +// dataType.setComponentKey("Employee"); +// if(formulaVar.getId()!=null && formulaVar.getId().equalsIgnoreCase("current_superior")){ +// dataType.setContent(employee.getSuperiorId()); +// } +// }else if(formulaVar.getType()!=null && (formulaVar.getType().equalsIgnoreCase(ComponentType.Department.toString()) || formulaVar.getType().equalsIgnoreCase(ComponentType.Department.toString())) || (formulaVar.getProperKey()!=null && formulaVar.getProperKey().equalsIgnoreCase(ComponentType.Department.toString()))){ +// dataType.setContent(employee.getDepartmentId()); +// dataType.setComponentKey("Department"); +// }else{ +// if(formulaVar.getFieldType()!=null && formulaVar.getFieldType().equalsIgnoreCase("Employee")){ +// formulaVar.setComponentKey("Employee"); +// dataType.setComponentKey("Employee"); +// }else{ +// dataType.setComponentKey("RadioBox"); +// } +// } +// +// break; +// case DataType.DATASOURCE: +// dataType.setContent(paramFactory.getSelectValue()); +// dataType.setText(paramFactory.getSelectValue()); +// dataType.setScore(paramFactory.getDoubleValue()); +// dataType.setDataType(DataType.OPTION); +// dataType.setComponentKey("RadioBox"); +// break; +// default: +// break; +// } +// if(StringUtils.isNotEmpty(formulaVar.getDataType())){ +// dataType.setDataType(formulaVar.getDataType()); +// } +// +// dataType.setFieldId(formulaVar.getFieldId()+""); +// dataType.setFormId(formulaVar.getFormId()!=null?Long.parseLong(formulaVar.getFormId()):null); +// dataType.setEmployee(employee); +// if(StringUtils.isNotEmpty(formulaVar.getModule())){ +// try { +// try { +// dataType.setModule(formulaVar.getModule()); +// } catch (IllegalArgumentException e) { +// logger.error("err",e); +// dataType.setModule(formulaVar.getModule()); +// } +// } catch (IllegalArgumentException e) { +// logger.error("err",e); +// dataType.setModule(formulaVar.getModule()); +// } +// +// } +// dataType.setName(formulaVar.getTitle()); +// if(StringUtils.isEmpty(dataType.getName())){ +// dataType.setName(formulaVar.getName()); +// } +// return dataType; +// } +// +// private static DataType transFormulaVarToDataType(FormulaVar localFormulaVar,List dataVars,DataCollectionEmployee employee){ +// DataType dataType =new DataType(); +// if(localFormulaVar == null){ +// return null; +// } +// +// String typeKey=localFormulaVar.getProperKey(); +// if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ +// typeKey=localFormulaVar.getFieldType(); +// }else if(StringUtils.isNotEmpty(localFormulaVar.getType())){ +// typeKey=localFormulaVar.getType(); +// }else if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ +// typeKey=localFormulaVar.getFieldType(); +// localFormulaVar.setComponentKey(localFormulaVar.getFieldType()); +// } +// logger.info(localFormulaVar.getId()+"typeKey=:"+typeKey); +// switch (ExcelParamUtil.findDataType(typeKey)){ +// case DataType.DATE: +// dataType.setDataType(DataType.STRING); +// setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); +// if(dataType.getContent()==null){ +// dataType.setContent(""); +// } +// break; +// case DataType.STRING: +// dataType.setDataType(DataType.STRING); +// setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); +// if(dataType.getContent()==null){ +// dataType.setContent(""); +// } +// break; +// case DataType.NUMBER: +// dataType.setDataType(DataType.NUMBER); +// setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"field"); +// break; +// case DataType.OPTION: +// logger.info("函数构建选项型:"+JSON.toJSONString(localFormulaVar)); +// dataType.setDataType(DataType.OPTION); +// setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"option"); +// if(dataType.getContent() == null){ +// dataType.setContent(localFormulaVar.getId()!=null?localFormulaVar.getId():localFormulaVar.getOptionId()); +// dataType.setText(dataType.getContent()+""); +// } +// //当前操作人赋值 +// if(localFormulaVar.getId()!=null){ +// switch (localFormulaVar.getId()){ +// case "current_user": +// dataType.setContent(employee.getId()); +// dataType.setOptionContent(employee.getName()); +// break; +// case "current_superior": +// dataType.setContent(employee.getSuperiorId()); +// break; +// case "current_department": +// dataType.setContent(employee.getDepartmentId()); +// break; +// case "current_position": +// dataType.setContent(employee.getPositionId()); +// break; +// default: +// break; +// } +// logger.info("当前操作人赋值完成:"+JSON.toJSONString(dataType)); +// } +// break; +// case DataType.DATASOURCE: +// dataType.setDataType(DataType.DATASOURCE); +// setContent(dataType,typeKey,localFormulaVar.getFieldId(),dataVars,"option"); +// break; +// default: +// logger.info("未匹配到参数类型:"+(JSON.toJSONString(localFormulaVar))); +// break; +// } +// if(StringUtils.isNotEmpty(localFormulaVar.getDataType())){ +// dataType.setDataType(localFormulaVar.getDataType()); +// } +// if(StringUtils.isEmpty(dataType.getComponentKey())){ +// if(StringUtils.isNotEmpty(localFormulaVar.getFieldType())){ +// dataType.setComponentKey(localFormulaVar.getFieldType()); +// }else if(StringUtils.isNotEmpty(localFormulaVar.getProperKey())){ +// dataType.setComponentKey(localFormulaVar.getProperKey()); +// }else if(StringUtils.isNotEmpty(localFormulaVar.getComponentKey())){ +// dataType.setComponentKey(localFormulaVar.getComponentKey()); +// } +// } +// dataType.setFieldId(localFormulaVar.getFieldId()+""); +// dataType.setFormId(localFormulaVar.getFormId()!=null?Long.parseLong(localFormulaVar.getFormId()):null); +// dataType.setEmployee(employee); +// if(StringUtils.isNotEmpty(localFormulaVar.getModule())){ +// try { +// dataType.setModule(localFormulaVar.getModule()); +// } catch (IllegalArgumentException e) { +// logger.error("err",e); +// dataType.setModule(localFormulaVar.getModule()); +// } +// } +// dataType.setName(localFormulaVar.getTitle()!=null?localFormulaVar.getTitle():localFormulaVar.getName()); +// logger.info("构建值完毕:"+JSON.toJSONString(dataType)); +// return dataType; +// } +// private static void setContent(DataType dataType,String typeKey,String sourceVar,List targetVarList,String type){ +// if(sourceVar==null){ +// return ; +// } +// for (FormulaVar loopVar:targetVarList){ +// switch (type){ +// case "field": +// if(sourceVar.equalsIgnoreCase(loopVar.getFieldId())){ +// dataType.setContent(loopVar.getContent()!=null?loopVar.getContent():""); +// dataType.setText(dataType.getContent()+""); +// if(StringUtils.isNotEmpty(loopVar.getsFormId())){ +// dataType.setSubFormId(Long.parseLong(loopVar.getsFormId())); +// } +// dataType.setComponentKey(loopVar.getComponentKey()); +// }else{ +// dataType.setComponentKey(typeKey); +// } +// break; +// case "form": +// if(sourceVar.equalsIgnoreCase(loopVar.getFormId())){ +// dataType.setContent(loopVar.getContent()); +// } +// break; +// case "option": +// if(sourceVar.equalsIgnoreCase(loopVar.getFieldId())){ +// dataType.setContent(loopVar.getContent()); +// if(dataType.getContent()==null){ +// dataType.setContent(loopVar.getOptionId()); +// dataType.setText(loopVar.getOptionId()); +// } +// //常量 +// if(StringUtils.isNotEmpty(loopVar.getOptionContent())){ +// dataType.setOptionContent(loopVar.getOptionContent()); +// }else if(loopVar.getDataOptionList()!=null && loopVar.getDataOptionList().size()>0){ +// String optionContents=""; +// List dataOptions=loopVar.getDataOptionList(); +// for(DataOption dataOption:dataOptions){ +// optionContents+=dataOption.getOptionContent()+","; +// } +// if(optionContents.lastIndexOf(",")>0){ +// optionContents=optionContents.substring(0,optionContents.lastIndexOf(",")); +// } +// dataType.setOptionContent(optionContents); +// }else {//变量 +// dataType.setOptionContent(loopVar.getContent()); +// } +// +// dataType.setScore(loopVar.getScore()); +// if(StringUtils.isNotEmpty(loopVar.getsFormId())){ +// dataType.setSubFormId(Long.parseLong(loopVar.getsFormId())); +// } +// dataType.setComponentKey(loopVar.getComponentKey()); +// } +// break; +// default: +// break; +// } +// } +// } +//} diff --git a/src/com/engine/salary/formlua/util/ExecuteTest.java b/src/com/engine/salary/formlua/util/ExecuteTest.java deleted file mode 100644 index cfd350d6c..000000000 --- a/src/com/engine/salary/formlua/util/ExecuteTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.engine.salary.formlua.util; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.ql.util.express.ExpressRunner; -import com.weaver.excel.formula.api.entity.ExpressFormula; -import com.weaver.excel.formula.api.entity.FormulaVar; -import com.weaver.teams.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; - -public class ExecuteTest { - protected static final Logger logger = LoggerFactory.getLogger(ExecuteTest.class); - public static ExpressRunner runner; - - public static void main(String[] args){ - String[] strs=new String[]{"1","2","3"}; - List obj1=new ArrayList<>(); - for (int i =1 ;i localVars=paramArray.toJavaList(FormulaVar.class); - ExcelStandardUtil.replaceAllParam(expressFormula.getFormula(),localVars,null,null); - } - } - } - } -} diff --git a/src/com/engine/salary/formlua/util/TestUtil.java b/src/com/engine/salary/formlua/util/TestUtil.java deleted file mode 100644 index 3e8e39ed2..000000000 --- a/src/com/engine/salary/formlua/util/TestUtil.java +++ /dev/null @@ -1,403 +0,0 @@ -package com.engine.salary.formlua.util; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.ql.util.express.DynamicParamsUtil; -import com.ql.util.express.ExpressRunner; -import com.ql.util.express.IExpressContext; -import com.weaver.common.form.component.base.ComponentType; -import com.weaver.common.form.stat.FilterFormData; -import com.weaver.excel.formula.api.entity.CustomFunc; -import com.weaver.excel.formula.core.QLExpressContext; -import com.weaver.excel.formula.entity.parameter.DataType; -import com.weaver.excel.formula.entity.parameter.FuncNames; -import com.weaver.excel.formula.entity.parameter.standard.FormulaFilterData; -import com.weaver.excel.formula.func.compare.EqOperator; -import com.weaver.excel.formula.func.compare.test.GreaterOperator; -import com.weaver.excel.formula.func.compare.test.LessOperator; -import com.weaver.excel.formula.func.custom.CustomService; -import com.weaver.excel.formula.func.custom.CustomServiceTestImpl; -import com.weaver.excel.formula.func.date.DateTimeService; -import com.weaver.excel.formula.func.date.DateTimeServiceImpl; -import com.weaver.excel.formula.func.extend.ExcelExtendFuncService; -import com.weaver.excel.formula.func.extend.ExcelExtendFuncServiceImpl; -import com.weaver.excel.formula.func.finance.FinanceService; -import com.weaver.excel.formula.func.finance.FinanceServiceImpl; -import com.weaver.excel.formula.func.logic.LogicUtils; -import com.weaver.excel.formula.func.math.MathFuncsService; -import com.weaver.excel.formula.func.math.MathFuncsServiceImpl; -import com.weaver.excel.formula.func.string.StringFormulaService; -import com.weaver.excel.formula.func.string.StringFormulaServiceImpl; -import com.weaver.excel.formula.util.standard.ExcelDataType; -import com.weaver.teams.domain.user.DataCollectionEmployee; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; - -import java.util.*; - -public class TestUtil { - protected static final Logger logger = LoggerFactory.getLogger(TestUtil.class); - @Autowired - ApplicationContext applicationContext; - public void test() throws Exception { - DynamicParamsUtil.supportDynamicParams = true; - ExpressRunner runner = new ExpressRunner(true,false); - initRunner(runner); - Map context=new HashMap<>(); - DataType dataType1=new DataType(); - dataType1.setContent(1); - dataType1.setFieldId("a"); - dataType1.setComponentKey(ComponentType.NumberComponent.toString()); - dataType1.setDataType(DataType.NUMBER); - - DataType dataType2=new DataType(); - dataType2.setFieldId("b"); - dataType2.setComponentKey(ComponentType.NumberComponent.toString()); - dataType2.setContent(2); - dataType2.setDataType(DataType.NUMBER); - - context.put("key111","2345.66"); - context.put("a",dataType1); - context.put("b",dataType2); - context.put("dateA",dataType1); - context.put("dateB",dataType2); - IExpressContext expressContext = new QLExpressContext(context,applicationContext); -// String expressSql="c=10;function add(int a,int b){return a+b+c;};add(a,b);"; -// String expressSql="import com.weaver.excel.formula.util.DateUtil;isdate=DateUtil.isDateComponent('a');System.out.println('是日期吗?'+(isdate?'是':'不是'));"; -// String expressSql="TEST(key111)=TEST(key111)"; - - String expressSql="CUSTOM1(dateA,function1());"; - - String [] varList=runner.getOutVarNames(expressSql); - String [] funcList=runner.getOutFunctionNames(expressSql); -// OperatorBase operatorBase=runner.getFunciton("TEST"); - Object result=runner.execute(expressSql, expressContext, null, false, false); - logger.info("执行结果:"+JSON.toJSONString(result)); - } - - private void initRunner(ExpressRunner runner) throws Exception { - ExcelExtendFuncService excelExtendFuncService=new ExcelExtendFuncServiceImpl("biaoge","TEST"); - ExcelExtendFuncService excelExtendFuncService2=new ExcelExtendFuncServiceImpl("workflow","TEST2"); - //加载自定义脚本函数 - CustomFunc customFunc=new CustomFunc(); - customFunc.setFuncContent("function add(int a,int b){return a+b;};add(a1,b1);"); - customFunc.setFuncName("CUSTOM1"); - customFunc.setFuncTitle("自定义函数1"); - customFunc.setExcelDataType(ExcelDataType.number.toString()); - CustomService customService=new CustomServiceTestImpl(customFunc); - - DateTimeService dateTimeService=new DateTimeServiceImpl(); -// DateTimeService dateTimeService=new DateTimeTestServiceImpl(); - MathFuncsService mathFuncsService=new MathFuncsServiceImpl(); - StringFormulaService stringFormulaService=new StringFormulaServiceImpl(); - FinanceService financeService=new FinanceServiceImpl(); - runner.replaceOperator("=",new EqOperator("=")); - runner.replaceOperator(">",new GreaterOperator(">")); - runner.replaceOperator("<",new LessOperator("<")); - runner.addFunctionOfServiceMethod( "TEST",excelExtendFuncService,"execute",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "TEST2",excelExtendFuncService2,"execute",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "ISINT",mathFuncsService,"isInt",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "ISNUMBER",mathFuncsService,"isNumber",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "ISJSON",stringFormulaService,"isJson",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "GETJSONVALUE",stringFormulaService,"getJSONValue",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "COMPAREDATE",dateTimeService,"compareDate",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "CURRYEAR",dateTimeService,"currYear",new Class[]{},""); - runner.addFunctionOfServiceMethod( "CURRMONTH",dateTimeService,"currMonth",new Class[]{},""); - runner.addFunctionOfServiceMethod( "CURRDAY",dateTimeService,"currDay",new Class[]{},""); - runner.addFunctionOfServiceMethod( "CURRWEEK",dateTimeService,"currWeek",new Class[]{},""); - runner.addFunctionOfServiceMethod( "CURRHOUR",dateTimeService,"currHour",new Class[]{},""); - runner.addFunctionOfServiceMethod( "CURRMINUTE",dateTimeService,"currMinute",new Class[]{},""); - runner.addFunctionOfServiceMethod( "CURRSECOND",dateTimeService,"currSecond",new Class[]{},""); - runner.addFunctionOfServiceMethod( "GETMONEY", financeService,"getMoney",new Class[]{Object[].class},""); - runner.addFunctionOfServiceMethod( "CUSTOM1", customService,"execute",new Class[]{Object[].class},""); - } - - - public static void parseJ(){ - JSONObject queryObj=JSON.parseObject("{\"expressSql\":\"VLOOKUPS({工资薪金税(居民)},AND({薪资项目.当前累计应纳税所得额}>{个税税表.应纳税所得额下限},{薪资项目.当前累计应纳税额}<={个税税表.应纳税所得额上限}),[{个税税表.税率}])\",\"parameters\":[{\"dataId\":\"60000000000000001\",\"title\":\"工资薪金税(居民)\",\"module\":\"hrmsalary\",\"name\":\"工资薪金税(居民)\",\"id\":\"60000000000000001\",\"action\":\"DataSource\"},{\"name\":\"当前累计应纳税所得额\",\"module\":\"hrmsalary\",\"fieldId\":\"1_addUpTaxableIncome\",\"formId\":\"1\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"当前累计应纳税所得额\"},{\"name\":\"应纳税所得额下限\",\"module\":\"hrmsalary\",\"fieldId\":\"10_taxableIncomeLLimit\",\"formId\":\"10\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"应纳税所得额下限\"},{\"name\":\"当前累计应纳税额\",\"module\":\"hrmsalary\",\"fieldId\":\"1_addUpTaxPayable\",\"formId\":\"1\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"当前累计应纳税额\"},{\"name\":\"应纳税所得额上限\",\"module\":\"hrmsalary\",\"fieldId\":\"10_taxableIncomeULimit\",\"formId\":\"10\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"应纳税所得额上限\"},{\"name\":\"税率\",\"module\":\"hrmsalary\",\"fieldId\":\"10_taxRate\",\"formId\":\"10\",\"properKey\":\"number\",\"sFormId\":\"\",\"dataTemplateId\":\"\",\"title\":\"税率\"}],\"returnType\":\"number\",\"validateType\":\"normal\"}"); - JSONArray jsonArray = queryObj.getJSONArray("parameters"); - List dataTypeList=new ArrayList<>(); - - for (Object obj : jsonArray) { - JSONObject jsonObj = (JSONObject) obj; - DataType paramData=new DataType(); - paramData.setComponentKey(DataType.STRING); - paramData.setFieldId(jsonObj.getString("fieldId")); - paramData.setContent("123"); - dataTypeList.add(paramData); - } - - DataType dataType1=dataTypeList.get(1); - DataType dataType2=dataTypeList.get(3); - FormulaFilterData formulaFilterData1=new FormulaFilterData(); - formulaFilterData1.setContent(dataType1.getContent()+""); - formulaFilterData1.setCondition(FilterFormData.TERM_GT); - formulaFilterData1.setFieldId(dataType1.getFieldId()); - formulaFilterData1.setCondition(FormulaFilterData.CONDITION_AND); - - FormulaFilterData formulaFilterData2=new FormulaFilterData(); - formulaFilterData2.setContent(dataType2.getContent()+""); - formulaFilterData2.setCondition(FilterFormData.TERM_GT); - formulaFilterData2.setFieldId(dataType2.getFieldId()); - formulaFilterData2.setCondition(FormulaFilterData.CONDITION_AND); - - - List filterDatas=new ArrayList<>(); - filterDatas.add(formulaFilterData1); - filterDatas.add(formulaFilterData2); - String dataId="60000000000000001"; - String[] cols=new String[]{"10_taxRate"}; - DataCollectionEmployee employee=new DataCollectionEmployee(); - employee.setTenantKey("tm7tozevws"); - employee.setUserId(5113514575963198048L); - employee.setId(3573514574891514361L); - employee.setUsername("顿顿"); - System.out.println(dataId); - System.out.println(JSON.toJSONString(filterDatas)); - System.out.println(JSON.toJSONString(cols)); - System.out.println(JSON.toJSONString(employee)); - } - public static Object executeInner(Object[] list) throws Exception { - DataType result=new DataType(); - result.setDataType(DataType.BOOL); - if(list.length<1||list[1]==null){ - Integer number= IgnoreParamFilter.getSetFuncNumber("IN"); - JSONObject errorJson= ErrorUtil.buildError("IN",number,number,"IN函数至少需要两个参数"); - throw new RuntimeException(errorJson.getString("msg")); - } - List paramList=new ArrayList<>(); - paramList.add(list[0]); - - Object[] objectArray=null; - if(list[1].getClass().isArray()){ - objectArray=(Object[])list[1]; - for (int i=0;i(); - paramList.add(null); - List dataArray=new ArrayList<>(); - if(list[0] instanceof DataType){ - DataType dataType=(DataType)list[0]; - if(dataType.getDataType().equals(DataType.OPTION)){ - if(dataType.getContent()!=null){ - String[] arrys=dataType.getContent().toString().split(","); - for (int i=0;i0 && testI!=objects.length){ - Object cndObj=objects[testI-1]; - if(!(cndObj instanceof Boolean) && !(cndObj instanceof DataType)){ - JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); - throw new RuntimeException(errorJson.getString("msg")); - }else if(cndObj instanceof DataType){ - DataType boolDataType=(DataType)cndObj; - if(boolDataType.getContent()!=null && !(boolDataType.getContent() instanceof Boolean)){ - JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数条件必须为真假值"); - throw new RuntimeException(errorJson.getString("msg")); - } - } - } - } - - boolean paramCheck=checkParamType(objects); - if(!paramCheck){ - JSONObject errorJson=ErrorUtil.buildError(FuncNames.IFS.toString(),number,number,"IFS函数多个条件的返回值必须一致"); - throw new RuntimeException(errorJson.getString("msg")); - } - - int i; - for(i=1;i<=objects.length;i++){ - if(i%2==0){ - Object cndObj=objects[i-2]; - if(cndObj instanceof Boolean){ - Boolean cnd=(Boolean)cndObj; - if(cnd){ - if(objects[i-1] instanceof DataType){ - return (DataType) objects[i-1]; - }else{ - return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i-1].getClass().getName())),objects[i-1]); - } -// return new DataType(DataType.BOOL,objects[i-1]); - } - }else if(cndObj instanceof DataType){ - DataType boolData=(DataType)cndObj; - Boolean cnd=boolData.getContent()!=null?( (Boolean)boolData.getContent() ) : false; - if(cnd){ - if(objects[i-1] instanceof DataType){ - return (DataType) objects[i-1]; - }else { - return new DataType(DataType.returnType(ExcelParamUtil.getParamType(objects[i-1].getClass().getName())),objects[i-1]); - } - - } - } - } - } - //如果没有条件符合,返回默认值,最后一个参数为默认值 - Object result=ExcelParamUtil.getParamContent(objects[objects.length-1],""); - if(result instanceof DataType){ - return (DataType)result; - }else{ - return new DataType(DataType.returnType(ExcelParamUtil.getParamType(result.getClass().getName())),result); - } - - } - private static boolean checkParamType(Object[] objects){ - boolean result=false; - String type=null; - for (int i=1;i<=objects.length;i++){ - if(i%2==0){ - Object obj=objects[i-1]; - String typeStr=ExcelParamUtil.getParamType(obj); - typeStr=ExcelParamUtil.checkParamType(typeStr); - logger.info(typeStr); - if(type==null){ - type=typeStr; - }else{ - result=typeStr.equalsIgnoreCase(type); - if(!result){ - return result; - } - - } - } - } - String typeStr=ExcelParamUtil.checkParamType(ExcelParamUtil.getParamType(objects[objects.length-1])); - result=type.equalsIgnoreCase(typeStr); - return result; - } - public static Object chooseOne(Object... objects) { - if(objects==null || objects.length<2){ - throw new RuntimeException("CHOOSE函数的参数不能少于两个"); - } - DataType dataType=new DataType(); - boolean checkResult=IgnoreParamFilter.checkType(objects); - if(checkResult){ - int indexData=0; - Object firstObj=objects[0]; - try { - if(firstObj !=null){ - Double doubleValue=null; - if(firstObj instanceof DataType){ - DataType indexDataType=(DataType)firstObj; - if(ExcelParamUtil.findDataType(indexDataType.getDataType()).equalsIgnoreCase(DataType.NUMBER)){ - if(indexDataType.getContent()!=null){ - doubleValue=Double.parseDouble(indexDataType.getContent()+""); - } - } - }else{ - doubleValue=Double.parseDouble(firstObj+""); - } - indexData=doubleValue.intValue(); - }else{ - throw new RuntimeException("CHOOSE函数第一个参数不能为空"); - } - - } catch (NumberFormatException e) { - logger.error("err",e); - } - List dataList=ExcelParamUtil.getParamContent(objects); - if(indexData>=dataList.size()){ - indexData=dataList.size()-1; - } - Object resultObj=dataList.get(indexData); - if(resultObj!=null){ - if(resultObj instanceof DataType){ - dataType=(DataType)resultObj; - }else { - String type=ExcelParamUtil.getParamType(resultObj.getClass().getName()); - dataType.setDataType(type); - dataType.setContent(resultObj); - } - } - }else { - throw new RuntimeException("CHOOSE函数的参数类型不一致"); - } - logger.info("CHOOSE校验执行结果:"+ JSON.toJSONString(dataType)); - return dataType; - } - private static void testOption(DataType dataType,DataType dataType2){ - //对option的特殊处理,获取option的字符串后根据逗号分割,然后排序数组,数组长度不一致返回false,一致则循环对比直到同样下标的数据不一致返回false,否则为true - String[] firstOptions=new String[]{}; - String[] secondOptions=new String[]{}; - firstOptions= CompareUtil.genArray(dataType,"option"); - secondOptions=CompareUtil.genArray(dataType2,"option"); - Arrays.sort(firstOptions); - Arrays.sort(secondOptions); - - logger.info("比较选项:"+JSON.toJSONString(firstOptions)+"-->"+JSON.toJSONString(secondOptions)); - if(firstOptions.length!=secondOptions.length){ - }else{ - int i=0; - for (;i> { if("leave".equalsIgnoreCase(kqReportFieldComInfo.getFieldname())&&leaveRules.size()==0)continue; column = new HashMap(); - column.put("title", SalaryI18nUtil.getI18nLabels(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); + column.put("title", SystemEnv.getHtmlLabelNames(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); column.put("unit", KQReportBiz.getUnitType(kqReportFieldComInfo, user)); column.put("dataIndex", kqReportFieldComInfo.getFieldname()); column.put("type", kqReportFieldComInfo.getFieldname()); @@ -143,7 +143,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { // } // column = new HashMap(); -// column.put("title", SalaryI18nUtil.getI18nLabel(386476, user.getLanguage())); +// column.put("title", SystemEnv.getHtmlLabelName(386476, user.getLanguage())); // column.put("dataIndex", "kqCalendar"); // column.put("key", "kqCalendar"); // if(childColumns.size()>0) {//跨列width取子列的width @@ -280,7 +280,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { // } // } // } else { - sql = " select " + sql; + sql = " select " + sql; // } Map flowData = kqReportBiz.getFlowData(params,user); rs.execute(sql); @@ -430,7 +430,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { if(DateUtil.compDate(today, date)>0){ data.put(date,""); }else{ - data.put(date,detialDatas.get(id+"|"+date)==null?SalaryI18nUtil.getI18nLabel(26593, user.getLanguage()):detialDatas.get(id+"|"+date)); + data.put(date,detialDatas.get(id+"|"+date)==null?SystemEnv.getHtmlLabelName(26593, user.getLanguage()):detialDatas.get(id+"|"+date)); } cal.setTime(DateUtil.parseToDate(date)); date = DateUtil.getDate(cal.getTime(), 1); @@ -489,7 +489,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { String unitType = Util.null2String(leaveRule.get("unitType")); column = new HashMap(); column.put("title", name); - column.put("unit", KQUnitBiz.isLeaveHour(unitType) ?SalaryI18nUtil.getI18nLabel(391, user.getLanguage()):SalaryI18nUtil.getI18nLabel(1925, user.getLanguage())); + column.put("unit", KQUnitBiz.isLeaveHour(unitType) ?SystemEnv.getHtmlLabelName(391, user.getLanguage()):SystemEnv.getHtmlLabelName(1925, user.getLanguage())); column.put("width", 65); column.put("dataIndex", id); column.put("key", id); @@ -517,16 +517,16 @@ public class GetKQReportCmd extends AbstractCommonCommand> { String unitTypeName = ""; if(Util.null2String(unitType).length()>0){ if(unitType.equals("1")){ - unitTypeName=SalaryI18nUtil.getI18nLabel(1925, user.getLanguage()); + unitTypeName=SystemEnv.getHtmlLabelName(1925, user.getLanguage()); }else if(unitType.equals("2")){ - unitTypeName=SalaryI18nUtil.getI18nLabel(391, user.getLanguage()); + unitTypeName=SystemEnv.getHtmlLabelName(391, user.getLanguage()); }else if(unitType.equals("3")){ - unitTypeName=SalaryI18nUtil.getI18nLabel(18083, user.getLanguage()); + unitTypeName=SystemEnv.getHtmlLabelName(18083, user.getLanguage()); } } column.put("unit", unitTypeName); } - column.put("title", SalaryI18nUtil.getI18nLabels(fieldlabel, user.getLanguage())); + column.put("title", SystemEnv.getHtmlLabelNames(fieldlabel, user.getLanguage())); column.put("dataIndex", id); column.put("key", id); column.put("rowSpan", 1); @@ -547,7 +547,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { if(kqReportFieldComInfo.getParentid().equals(parentid)) { if(!kqReportFieldComInfo.getReportType().equals("month"))continue; column = new HashMap(); - column.put("title", SalaryI18nUtil.getI18nLabels(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); + column.put("title", SystemEnv.getHtmlLabelNames(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); column.put("unit", KQReportBiz.getUnitType(kqReportFieldComInfo, user)); column.put("width", Util.getIntValue(kqReportFieldComInfo.getWidth())); column.put("dataIndex", kqReportFieldComInfo.getFieldname()); @@ -579,7 +579,7 @@ public class GetKQReportCmd extends AbstractCommonCommand> { if(!kqReportFieldComInfo.getReportType().equals("month"))continue; if (kqReportFieldComInfo.getFieldname().equals(lsCascadeKey.get(i))){ column = new HashMap(); - column.put("title", SalaryI18nUtil.getI18nLabels(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); + column.put("title", SystemEnv.getHtmlLabelNames(kqReportFieldComInfo.getFieldlabel(), user.getLanguage())); column.put("unit", KQReportBiz.getUnitType(kqReportFieldComInfo, user)); column.put("width", Util.getIntValue(kqReportFieldComInfo.getWidth())); column.put("dataIndex", kqReportFieldComInfo.getFieldname()); From 9994ae3df92a1bcf4421cd1a9f4d7cbca41f1bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Wed, 19 Apr 2023 15:22:42 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../formlua/core/AttendanceQlExpress.java | 39 +++++++++++----- .../salary/formlua/core/QLExpressContext.java | 9 ++-- .../func/finance/FinanceServiceTestImpl.java | 45 ------------------- 3 files changed, 32 insertions(+), 61 deletions(-) delete mode 100644 src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java diff --git a/src/com/engine/salary/formlua/core/AttendanceQlExpress.java b/src/com/engine/salary/formlua/core/AttendanceQlExpress.java index 4b7f07d34..07b5c4d9e 100644 --- a/src/com/engine/salary/formlua/core/AttendanceQlExpress.java +++ b/src/com/engine/salary/formlua/core/AttendanceQlExpress.java @@ -6,11 +6,16 @@ import com.engine.salary.formlua.entity.parameter.DataType; import com.engine.salary.formlua.entity.parameter.FuncNames; import com.engine.salary.formlua.func.compare.*; import com.engine.salary.formlua.func.date.DateTimeService; +import com.engine.salary.formlua.func.date.DateTimeServiceImpl; import com.engine.salary.formlua.func.finance.FinanceService; +import com.engine.salary.formlua.func.finance.FinanceServiceImpl; import com.engine.salary.formlua.func.find.FindFuncsService; import com.engine.salary.formlua.func.logic.LogicService; +import com.engine.salary.formlua.func.logic.LogicServiceImpl; import com.engine.salary.formlua.func.math.MathFuncsService; +import com.engine.salary.formlua.func.math.MathFuncsServiceImpl; import com.engine.salary.formlua.func.string.StringFormulaService; +import com.engine.salary.formlua.func.string.StringFormulaServiceImpl; import com.engine.salary.formlua.util.ExcelParamUtil; import com.engine.salary.formlua.util.ExpressRegularUtil; import com.ql.util.express.DynamicParamsUtil; @@ -20,13 +25,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; import java.util.Map; import java.util.regex.PatternSyntaxException; /** * 考勤执行业务类 */ -public class AttendanceQlExpress { +public class AttendanceQlExpress { public static ExpressRunner runner; @@ -39,13 +45,13 @@ public class AttendanceQlExpress { // AggregationFunc aggregationFunc; - LogicService logicService; + LogicService logicService = new LogicServiceImpl(); - DateTimeService dateTimeService; + DateTimeService dateTimeService = new DateTimeServiceImpl(); - StringFormulaService stringFormulaService; + StringFormulaService stringFormulaService = new StringFormulaServiceImpl(); - MathFuncsService mathFuncsService; + MathFuncsService mathFuncsService = new MathFuncsServiceImpl(); FindFuncsService findFuncsService; @@ -53,12 +59,23 @@ public class AttendanceQlExpress { // // private HrmDbService hrmDbService; - private FinanceService financeService; -// private RemoteExcelformulaService remoteExcelformulaService; + private FinanceService financeService = new FinanceServiceImpl(); + // private RemoteExcelformulaService remoteExcelformulaService; private String errorInfo; protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + public static void main(String[] args) throws Exception { + AttendanceQlExpress test = new AttendanceQlExpress(); + + String statement = "IFS(1>1,1,1=1,0,-1)"; + Map context = new HashMap<>(); + context.put("a", 10000); + context.put("b", 2); + Object execute = test.execute(statement, context); + System.out.println(execute); + } + /** * @param statement 执行语句 * @param context 上下文 @@ -218,7 +235,7 @@ public class AttendanceQlExpress { runner.addFunctionOfServiceMethod("DATEFORMAT", dateTimeService, "dateFormat", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("DAYOFMONTH", dateTimeService, "dayOfMonth", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("EOMONTH", dateTimeService, "eoMonth", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod("NETWORKDAYSPI", dateTimeService, "workdayIntl", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod("NETWORKDAYSPI", dateTimeService, "workdayIntl", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("CURRYEAR", dateTimeService, "currYear", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("CURRMONTH", dateTimeService, "currMonth", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("CURRDAY", dateTimeService, "currDay", new Class[]{Object[].class}, ""); @@ -264,9 +281,9 @@ public class AttendanceQlExpress { runner.addFunctionOfServiceMethod(FuncNames.ISNUMBER.toString(), mathFuncsService, FuncNames.ISNUMBER.getName(), new Class[]{Object[].class}, ""); //查找函数 - runner.addFunctionOfServiceMethod(FuncNames.CHOOSE.toString(), findFuncsService, "chooseOne", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod(FuncNames.MATCH.toString(), findFuncsService, "match", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod(FuncNames.VLOOKUPS.toString(), findFuncsService, "vlookups", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.CHOOSE.toString(), findFuncsService, "chooseOne", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.MATCH.toString(), findFuncsService, "match", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod(FuncNames.VLOOKUPS.toString(), findFuncsService, "vlookups", new Class[]{Object[].class}, ""); //数据库函数-hrm // runner.addFunctionOfServiceMethod(FuncNames.GETHRMNAME.toString(), hrmDbService, FuncNames.GETHRMNAME.getName(), new Class[]{Object[].class}, ""); diff --git a/src/com/engine/salary/formlua/core/QLExpressContext.java b/src/com/engine/salary/formlua/core/QLExpressContext.java index d9db4a6ff..4fa77597f 100644 --- a/src/com/engine/salary/formlua/core/QLExpressContext.java +++ b/src/com/engine/salary/formlua/core/QLExpressContext.java @@ -7,13 +7,12 @@ import java.util.Map; @SuppressWarnings("serial") public class QLExpressContext extends HashMap implements - IExpressContext { + IExpressContext { - - public QLExpressContext(Map aProperties) { - super(aProperties); - } + public QLExpressContext(Map aProperties) { + super(aProperties); + } } diff --git a/src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java b/src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java deleted file mode 100644 index ef169dbc5..000000000 --- a/src/com/engine/salary/formlua/func/finance/FinanceServiceTestImpl.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.engine.salary.formlua.func.finance; - -import com.engine.salary.formlua.entity.parameter.DataType; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author - */ -public class FinanceServiceTestImpl implements FinanceService{ - protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - String[] cnNums = new String[]{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; - @Override - public DataType getMoney(Object... objects) { - if(objects==null){ - throw new RuntimeException("GETMONEY函数的参数不能为空"); - }else if(objects.length!=1){ - throw new RuntimeException("GETMONEY函数只能允许一个参数"); - } - Object param=objects[0]; - Object content=null; - if(param instanceof DataType){ - DataType dataType=(DataType)param; - content=dataType.getContent(); - }else{ - content=param; - } - if(content!=null && !content.toString().equals("")){ - char[] chars=content.toString().toCharArray(); - String chineseNum=""; - for(char cstr:chars){ - String charstr=String.valueOf(cstr); - if(StringUtils.isNumeric(charstr)){ - int csNum=Integer.parseInt(charstr); - chineseNum+=cnNums[csNum]; - }else if(charstr.equalsIgnoreCase(".")){ - chineseNum+=""; - } - } - logger.info(chineseNum); - } - return null; - } -} From ef171db1287c0af42a9cf4858ac1371f1145f630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Wed, 19 Apr 2023 19:28:05 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ttendanceQlExpress.java => QlExpress.java} | 22 ++---- .../entity/standard/execute/ExclDataType.java | 4 -- .../entity/standard/execute/ExclFixField.java | 1 - .../service/impl/FormulaRunServiceImpl.java | 70 +++++++++++++++---- .../impl/SalaryFormulaServiceImpl.java | 30 ++++---- 5 files changed, 77 insertions(+), 50 deletions(-) rename src/com/engine/salary/formlua/core/{AttendanceQlExpress.java => QlExpress.java} (97%) diff --git a/src/com/engine/salary/formlua/core/AttendanceQlExpress.java b/src/com/engine/salary/formlua/core/QlExpress.java similarity index 97% rename from src/com/engine/salary/formlua/core/AttendanceQlExpress.java rename to src/com/engine/salary/formlua/core/QlExpress.java index 07b5c4d9e..16b716b7c 100644 --- a/src/com/engine/salary/formlua/core/AttendanceQlExpress.java +++ b/src/com/engine/salary/formlua/core/QlExpress.java @@ -25,14 +25,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; import java.util.Map; import java.util.regex.PatternSyntaxException; /** * 考勤执行业务类 */ -public class AttendanceQlExpress { +public class QlExpress { public static ExpressRunner runner; @@ -65,24 +64,12 @@ public class AttendanceQlExpress { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); - public static void main(String[] args) throws Exception { - AttendanceQlExpress test = new AttendanceQlExpress(); - - String statement = "IFS(1>1,1,1=1,0,-1)"; - Map context = new HashMap<>(); - context.put("a", 10000); - context.put("b", 2); - Object execute = test.execute(statement, context); - System.out.println(execute); - } - /** * @param statement 执行语句 * @param context 上下文 * @throws Exception */ - public Object execute(String statement, Map context) - throws Exception { + public Object execute(String statement, Map context) { String expressSql = statement; initRunner(runner); DynamicParamsUtil.supportDynamicParams = true; @@ -104,6 +91,7 @@ public class AttendanceQlExpress { if (obj instanceof DataType) { DataType dataType = (DataType) obj; resultObj.put("data", dataType.getContent()); + resultObj.put("dataType", dataType.getDataType()); resultObj.put("boolData", dataType.getContent()); } else { resultObj.put("data", obj); @@ -135,7 +123,7 @@ public class AttendanceQlExpress { JSONObject resultObj = new JSONObject(); resultObj.put("data", ""); - resultObj.put("excute", true); + resultObj.put("excute", false); return resultObj; } try { @@ -146,7 +134,7 @@ public class AttendanceQlExpress { JSONObject resultObj = new JSONObject(); resultObj.put("data", ""); - resultObj.put("excute", true); + resultObj.put("excute", false); return resultObj; } if (!(e instanceof PatternSyntaxException)) { diff --git a/src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java b/src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java index a249eb261..f12b32047 100644 --- a/src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java +++ b/src/com/engine/salary/formlua/entity/standard/execute/ExclDataType.java @@ -1,9 +1,5 @@ package com.engine.salary.formlua.entity.standard.execute; -/** - * @author 罗威 - */ - public enum ExclDataType { text("文本类型"),integral("整数类型"),decimal("小数类型"),datasource("数据源或选项类型"),bool("布尔类型"); diff --git a/src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java b/src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java index 5b34bf6fd..4ba17274f 100644 --- a/src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java +++ b/src/com/engine/salary/formlua/entity/standard/execute/ExclFixField.java @@ -2,7 +2,6 @@ package com.engine.salary.formlua.entity.standard.execute; /** * 固定字段标准类 - * @author 罗威 */ public class ExclFixField { /** diff --git a/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java b/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java index a4d41d813..ec8cf3bda 100644 --- a/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java +++ b/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java @@ -1,11 +1,13 @@ package com.engine.salary.service.impl; +import com.alibaba.fastjson.JSONObject; import com.engine.core.impl.Service; import com.engine.salary.encrypt.AESEncryptUtil; import com.engine.salary.entity.datacollection.DataCollectionEmployee; import com.engine.salary.entity.salaryformula.ExpressFormula; import com.engine.salary.entity.salaryformula.po.FormulaVar; import com.engine.salary.enums.salaryformula.ReferenceTypeEnum; +import com.engine.salary.formlua.core.QlExpress; import com.engine.salary.formlua.entity.parameter.DataType; import com.engine.salary.service.FormulaRunService; import com.engine.salary.sys.enums.OpenEnum; @@ -22,7 +24,9 @@ import weaver.conn.RecordSetDataSource; import weaver.general.BaseBean; import java.math.BigDecimal; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Slf4j public class FormulaRunServiceImpl extends Service implements FormulaRunService { @@ -35,6 +39,8 @@ public class FormulaRunServiceImpl extends Service implements FormulaRunService private final Boolean isLog = "true".equals(baseBean.getPropValue("hrmSalary", "log")); + QlExpress express = new QlExpress(); + @Override public Object run(ExpressFormula expressFormula, List formulaVars, DataCollectionEmployee simpleEmployee) throws Exception { @@ -96,7 +102,7 @@ public class FormulaRunServiceImpl extends Service implements FormulaRunService //外部数据源 if (StringUtils.isNotBlank(datasourceId)) { RecordSetDataSource rs = new RecordSetDataSource(datasourceId); - log.error("执行外部sql,{},datasourceId{}", sql,datasourceId); + log.error("执行外部sql,{},datasourceId{}", sql, datasourceId); if (rs.executeSql(sql)) { if (rs.next()) { result = rs.getString(sqlReturnKey); @@ -118,21 +124,59 @@ public class FormulaRunServiceImpl extends Service implements FormulaRunService } private Object runFormula(ExpressFormula expressFormula, List formulaVars) throws Exception { + + //是否是自定义函数 + boolean isCustomFunction = true; + + String extendParam = expressFormula.getExtendParam(); + String formulaType; + try { + JsonNode jsonNode = objectMapper.readTree(extendParam); + //返回值配置 + JsonNode isCustomFunctionNode = jsonNode.get("isCustomFunction"); + if (isCustomFunctionNode != null) { + isCustomFunction = StringUtils.equals(isCustomFunctionNode.asText().trim(), "true"); + } + } catch (JsonProcessingException e) { + log.error("express execute fail, sql extendParam parse fail", e); + } + if (isLog) { log.info("FORMULA ExpressFormula {} {}", expressFormula.getFormula(), expressFormula.getFormulaRunScript()); } - DefaultContext context = new DefaultContext(); - formulaVars.forEach(v -> { - if (isLog) { - log.info("FORMULA formulaVar {} - {}", v.getFieldId(), v.getContent()); - } - if (DataType.NUMBER.equals(v.getFieldType()) && NumberUtils.isCreatable(v.getContent())) { - context.put(v.getFieldId(), new BigDecimal(v.getContent())); - } else { - context.put(v.getFieldId(), v.getContent()); - } - }); + String formula = expressFormula.getFormulaRunScript(); - return runner.execute(formula, context, null, true, false); + + if(isCustomFunction){ + DefaultContext context = new DefaultContext(); + formulaVars.forEach(v -> { + if (isLog) { + log.info("FORMULA formulaVar {} - {}", v.getFieldId(), v.getContent()); + } + if (DataType.NUMBER.equals(v.getFieldType()) && NumberUtils.isCreatable(v.getContent())) { + context.put(v.getFieldId(), new BigDecimal(v.getContent())); + } else { + context.put(v.getFieldId(), v.getContent()); + } + }); + return runner.execute(formula, context, null, true, false); + }else{ + Map context = new HashMap<>(); + formulaVars.forEach(v -> { + if (isLog) { + log.info("FORMULA formulaVar {} - {}", v.getFieldId(), v.getContent()); + } + if (DataType.NUMBER.equals(v.getFieldType()) && NumberUtils.isCreatable(v.getContent())) { + context.put(v.getFieldId(), new BigDecimal(v.getContent())); + } else { + context.put(v.getFieldId(), v.getContent()); + } + }); + Object execute = express.execute(formula, context); + if(execute instanceof JSONObject){ + return ((JSONObject) execute).get("data"); + } + return execute; + } } } diff --git a/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java b/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java index 3b842a167..114c8a754 100644 --- a/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java +++ b/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java @@ -235,21 +235,21 @@ public class SalaryFormulaServiceImpl extends Service implements SalaryFormulaSe } //验证公式是否可运行 if (ReferenceTypeEnum.parseByValue(param.getReferenceType()) == ReferenceTypeEnum.FORMULA) { - ExpressFormula test = ExpressFormula.builder().formulaRunScript(formulaRunScript).extendParam(param.getExtendParam()).referenceType(param.getReferenceType()).build(); - Object run = null; - try { - run = getFormulaRunService(user).run(test, parameters, DataCollectionEmployee.builder().employeeId((long) user.getUID()).build()); - } catch (Exception e) { - log.error("express execute fail ", e); - throw new SalaryRunTimeException("公式模拟运行出错,请检查公式配置!", e); - } - - if (run != null && StringUtils.isNotBlank(String.valueOf(run)) && returnTypeEnum == ReturnTypeEnum.NUMBER) { - //返回结果不是数字 - if (!NumberUtils.isCreatable(String.valueOf(run))) { - throw new SalaryRunTimeException("返回结果不是数值"); - } - } +// ExpressFormula test = ExpressFormula.builder().formulaRunScript(formulaRunScript).extendParam(param.getExtendParam()).referenceType(param.getReferenceType()).build(); +// Object run = null; +// try { +// run = getFormulaRunService(user).run(test, parameters, DataCollectionEmployee.builder().employeeId((long) user.getUID()).build()); +// } catch (Exception e) { +// log.error("express execute fail ", e); +// throw new SalaryRunTimeException("公式模拟运行出错,请检查公式配置!", e); +// } +// +// if (run != null && StringUtils.isNotBlank(String.valueOf(run)) && returnTypeEnum == ReturnTypeEnum.NUMBER) { +// //返回结果不是数字 +// if (!NumberUtils.isCreatable(String.valueOf(run))) { +// throw new SalaryRunTimeException("返回结果不是数值"); +// } +// } } if (ReferenceTypeEnum.parseByValue(param.getReferenceType()) == ReferenceTypeEnum.SQL) { From f47ad2a7a3e37f36e9d5e8e32d82861984737723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Tue, 25 Apr 2023 18:04:05 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/engine/salary/web/SalaryFormulaController.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/com/engine/salary/web/SalaryFormulaController.java b/src/com/engine/salary/web/SalaryFormulaController.java index 7501bf837..44932a485 100644 --- a/src/com/engine/salary/web/SalaryFormulaController.java +++ b/src/com/engine/salary/web/SalaryFormulaController.java @@ -77,6 +77,7 @@ public class SalaryFormulaController { /** * 测试公式 + * * @param request * @param response * @param param @@ -90,4 +91,12 @@ public class SalaryFormulaController { return new ResponseResult(user).run(getSalaryFormulaWrapper(user)::mock, param); } + + @GET + @Path("/des") + @Produces(MediaType.APPLICATION_JSON) + public String mock(@Context HttpServletRequest request, @Context HttpServletResponse response) { + return "{\"data\":[{\"children\":[{\"name\":\"CONCAT\",\"chineseName\":\"链接多个文本\",\"description\":\"可用于连接多个任意类型的文本、日期、数字变量或常量。最后一个字符可使用'#分隔符#'标记为分隔符\",\"example\":\"CONCAT({总价}/10000, '万元')\",\"result\":\"100万元\",\"paramDescs\":[\"*文本1*(必选)\",\"*文本2*(可选)\",\"......\"],\"formatString\":\"CONCAT(文本1, 文本2, [文本3, …],[#分隔符#])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":true}]},{\"name\":\"TEXT\",\"chineseName\":\"将变量转为文本\",\"description\":\"将变量转为文本。\",\"example\":\"TEXT({当前数据.性别})\",\"result\":\"'男'\",\"paramDescs\":[\"*变量*(必选)\"],\"formatString\":\"TEXT(变量)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"VALUE\",\"chineseName\":\"将文本转为数字\",\"description\":\"将文本转为数字。\",\"example\":\"VALUE('23')\",\"result\":\"23\",\"paramDescs\":[\"*文本、数字、选项*(必选)\"],\"formatString\":\"VALUE([文本、数字、选项])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"LEN\",\"chineseName\":\"返回文本长度\",\"description\":\"返回文本的长度,中文、英文都算1个字符。\",\"example\":\"LEN('大家好dajiahao')\",\"result\":\"12\",\"paramDescs\":[\"*变量或常量*(必选)\"],\"formatString\":\"LEN(文本)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"SEARCH\",\"chineseName\":\"在文本中查找关键字\",\"description\":\"在指定文本中查找关键字,返回第一次出现关键字的字符位置,文本的第一个字记为1。未找到,返回0。搜索开始位置,表示从文本的第几个字符开始搜索,默认为1。\",\"example\":\"SEARCH('大家', '大家好大家好', 3)\",\"result\":\"4\",\"paramDescs\":[\"*文本关键字*(必选)\",\"*文本*(必选)\",\"*搜索开始位置*(可选)\"],\"formatString\":\"SEARCH(关键字, 文本, [搜索开始位置])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":false,\"infinite\":false}]},{\"name\":\"REPLACE\",\"chineseName\":\"替换文本中的字\",\"description\":\"在原文本中,从替换位置开始,往后数指定的替换字符数,将这段文本替换为新文本。\",\"example\":\"REPLACE('大家好大家好', 2, 3, 'dajia')\",\"result\":\"'大dajia家好'\",\"paramDescs\":[\"*文本*(必选)\"],\"formatString\":\"REPLACE(原文本, 替换开始位置, 替换字符数, 新文本)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":4,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"REPT\",\"chineseName\":\"将文本重复指定次数\",\"description\":\"将文本重复指定次数。\",\"example\":\"REPT('大家', 2)\",\"result\":\"'大家大家'\",\"paramDescs\":[\"*文本*(必选)\",\"*重复次数*(必选)\"],\"formatString\":\"REPT(文本, 重复次数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"PAD\",\"chineseName\":\"将文本填充至指定长度\",\"description\":\"将原文本填充到指定长度,如果文本长度大于设置的长度,则不做任何操作。填充位置可用参数:'LEFT'、'RIGHT'。\",\"example\":\"PAD('你好', 4, '你', 'LEFT')\",\"result\":\"'你你你好'\",\"paramDescs\":[\"*原文本*(必选)\",\"*长度*(必选)\",\"*填充用的文本*(必选)\",\"*填充位置*(可选)\"],\"formatString\":\"PAD(原文本, 长度, 填充用的文本, [填充位置])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":4,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"RIGHT\",\"LEFT\"],\"infinite\":false}]},{\"name\":\"TRIM\",\"chineseName\":\"清除前后空格\",\"description\":\"删除文本首尾的空格。\",\"example\":\"TRIM(' 大家好 ')\",\"result\":\"'大家好'\",\"paramDescs\":[\"*文本*(必选)\"],\"formatString\":\"TRIM(文本)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"LEFT\",\"chineseName\":\"返回文本左侧开始的文字\",\"description\":\"从文本左侧开始,返回指定字符数的文字。\",\"example\":\"LEFT('大家好', 2)\",\"result\":\"'大家'\",\"paramDescs\":[\"*文本*(必选)\",\"*截取字符数*(必选)\"],\"formatString\":\"LEFT(文本, 截取字符数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"RIGHT\",\"chineseName\":\"返回文本右侧开始的文字\",\"description\":\"从文本右侧开始,返回指定字符数的文字。\",\"example\":\"RIGHT('大家好', 2)\",\"result\":\"'家好'\",\"paramDescs\":[\"*文本*(必选)\",\"*截取字符数*(必选)\"],\"formatString\":\"RIGHT(文本, 截取字符数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"MID\",\"chineseName\":\"返回文本指定位置开始的文字\",\"description\":\"从文本指定位置之后开始,返回指定字符数的文字。\",\"example\":\"MID('大家好', 2, 1)\",\"result\":\"'家'\",\"paramDescs\":[\"*文本*(必选)\",\"*指定位置*(必选)\",\"*截取字符数*(必选)\"],\"formatString\":\"MID(文本, 指定位置, 截取字符数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"SCORE\",\"chineseName\":\"获取选项型控件分数\",\"description\":\"获取选项型控件(单选框、复选框、下拉菜单)分数。\",\"example\":\"SCORE({当前数据.单选框})\",\"result\":\"选项分数(注:未设置选项分数时,结果为0)\",\"paramDescs\":[\"*选项*(必选)\"],\"formatString\":\"SCORE({选项})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"option\",\"must\":true,\"infinite\":false}]},{\"name\":\"IDCARD\",\"chineseName\":\"身份证函数\",\"description\":\"从身份证号码中获取相关信息,比如:生日(BD)、年龄(AGE)、籍贯(NA)、性别(GENDER)。\",\"example\":\"IDCARD( ‘43070319980706334X’ , ‘BD’ )\",\"result\":\"'1998-07-06'\",\"paramDescs\":[\"*身份证号码*(必选)\",\"*查找类型*(必选)\"],\"formatString\":\"IDCARD({身份证号码}, {查找类型})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"BD\",\"NA\",\"AGE\",\"GENDER\"],\"infinite\":false}]},{\"name\":\"ISSTRING\",\"chineseName\":\"是否是字符串\",\"description\":\"判断是否是字符。\",\"example\":\"ISSTRING('泛微123456')\",\"result\":\"true\",\"paramDescs\":[\"*变量或常量*(必选)\"],\"formatString\":\"ISSTRING({任意控件})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISJSON\",\"chineseName\":\"JSON字符格式化\",\"description\":\"判断是不是JSON字符串,参数可以是数组,也可以是字符串,参数为数组时数组中必须只包含一个字符串。\",\"example\":\"假设文本控件={a:123},ISJSON({文本控件})\",\"result\":\"true\",\"paramDescs\":[\"*变量或常量*(必选)\"],\"formatString\":\"ISJSON({变量})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETJSONVALUE\",\"chineseName\":\"JSON字符取值\",\"description\":\"获取JSON值。第一个参数为json,可以是数组也可以是对象;第二个参数为json对象的键值,返回键值对应的值,json为数组时返回的多个值以逗号分隔\",\"example\":\"假设文本控件={a:123},GetJSONValue('{文本控件}','a')\",\"result\":\"123\",\"paramDescs\":[\"*变量或常量*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"GETJSONVALUE({变量1},变量2)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISINT\",\"chineseName\":\"字符内容是否是整数\",\"description\":\"判断字符内容是否是整数\",\"example\":\"ISINT( 2.123 )\",\"result\":\"false\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"ISINT({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISNUMBER\",\"chineseName\":\"字符内容是否是数字\",\"description\":\"判断字符内容是否是数字。\",\"example\":\"ISNUMBER('2.123')\",\"result\":\"true\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"ISNUMBER({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"SPLIT\",\"chineseName\":\"字符分割\",\"description\":\"字符分割函数,将字符以指定字符为依据分割字符为一组字符\",\"example\":\"假设文本控件=ABC#DEF,SPLIT('{文本控件}','#')\",\"result\":\"[ABC,DEF]\",\"paramDescs\":[\"*字符*(必选)\",\"*分割符*(必选)\"],\"formatString\":\"SPLIT({字符},{字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"LOWER\",\"chineseName\":\"字符转小写\",\"description\":\"将字符中的字母转为小写。\",\"example\":\"LOWER('ABC')\",\"result\":\"abc\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"LOWER({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"UPPER\",\"chineseName\":\"字符转大写\",\"description\":\"将字符中的字母转为大写。\",\"example\":\"UPPER('abc')\",\"result\":\"ABC\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"UPPER({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"TEXTBEFORE\",\"chineseName\":\"截取N个分割符之前的字符\",\"description\":\"截取N个分割符之前的字符\",\"example\":\"TEXTBEFORE('abc-12','-',1)\",\"result\":\"abc\",\"paramDescs\":[\"*字符*(必选)\",\"*字符*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"TEXTBEFORE({目标文本},{分隔符},{索引下标})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"TEXTAFTER\",\"chineseName\":\"截取N个分隔符之后的字符\",\"description\":\"截取N个分隔符之后的字符\",\"example\":\"TEXTAFTER('abc-12','-',1)\",\"result\":\"12\",\"paramDescs\":[\"*字符*(必选)\",\"*字符*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"TEXTAFTER({目标文本},{分隔符},{索引下标})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"char\",\"name\":\"字符函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"COUNT\",\"chineseName\":\"计数\",\"description\":\"返回指定表格中满足条件的数据条数。\",\"example\":\"COUNT({员工表})\",\"result\":\"1\",\"paramDescs\":[\"*表*(必选)\"],\"formatString\":\"COUNT(表)\",\"paramArray\":[\"Form\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"SUM\",\"chineseName\":\"求和\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的总和。统计条件中不可嵌套使用统计函数。\",\"example\":\"SUM({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"SUM(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"AVG\",\"chineseName\":\"平均值\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的平均值。统计条件中不可嵌套使用统计函数。\",\"example\":\"AVG({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"AVG(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"MIN\",\"chineseName\":\"最小值\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的最小值。统计条件中不可嵌套使用统计函数。\",\"example\":\"MIN({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"MIN(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"MAX\",\"chineseName\":\"最大值\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的最大值。统计条件中不可嵌套使用统计函数。\",\"example\":\"MAX({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"MAX(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3}],\"dataType\":\"agg\",\"name\":\"聚合函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"TODAY\",\"chineseName\":\"当前日期\",\"description\":\"返回当天日期。\",\"example\":\"TODAY()\",\"result\":\"'2020-01-01'\",\"formatString\":\"TODAY()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"NOW\",\"chineseName\":\"当前日期时间\",\"description\":\"返回当天日期+时间。\",\"example\":\"NOW()\",\"result\":\"'2016-12-24 12:05:38'\",\"formatString\":\"NOW()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"DATEADD\",\"chineseName\":\"对日期加减年、月、日\",\"description\":\"对日期加减按照单位加减。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。\",\"example\":\"DATEADD('2016-12-21', 3)
DATEADD('2016-12-24 20:00:00', 3, 'H')\",\"result\":\"'2016-12-24'
'2016-12-24 23:00:00'\",\"paramDescs\":[\"*日期*(必选)\",\"*数值*(必选)\",\"*单位*(可选)\"],\"formatString\":\"DATEADD(日期,数值 , [单位])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"Y\",\"M\",\"D\",\"H\",\"I\",\"S\"],\"infinite\":false}]},{\"name\":\"DATEDIFF\",\"chineseName\":\"返回两个日期的差值\",\"description\":\"根据指定的单位,返回日期2减去日期1的差值。当日期2小于日期1时,差值为负值。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。\",\"example\":\"DATEDIF('2016-12-21', '2016-12-24')
DATEDIF('2016-12-24 20:00:00', '2016-12-25 20:00:00', 'H')\",\"result\":\"3
24\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\",\"*单位*(可选)\"],\"formatString\":\"DATEDIFF(日期1, 日期2, [单位])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"Y\",\"M\",\"D\",\"H\",\"I\",\"S\"],\"infinite\":false}]},{\"name\":\"DATEFORMAT\",\"chineseName\":\"返回指定格式的日期\",\"description\":\"将日期转为指定格式返回。
yyyy 将年份显示为1900-9999
yy 将年份显示为00-99
mm 将月份显示为 01–12
dd 将日期显示为 01–31\",\"example\":\"DATEFORMAT('2016-12-24', 'YY-MM-DD')\",\"result\":\"2016-12-24\",\"paramDescs\":[\"*日期*(必选)\",\"*日期格式*(必选)\"],\"formatString\":\"DATEFORMAT(日期, 可选格式)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"YEAR\",\"chineseName\":\"返回日期中的年\",\"description\":\"返回指定日期中的年。\",\"example\":\"YEAR('2016-12-24')\",\"result\":\"2016\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"YEAR(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"MONTH\",\"chineseName\":\"返回日期中的月\",\"description\":\"返回指定日期中的月。\",\"example\":\"MONTH('2016-12-24')\",\"result\":\"12\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"MONTH(日期)\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"DAY\",\"chineseName\":\"返回日期中的日\",\"description\":\"返回指定日期中的日。\",\"example\":\"DAY('2016-12-24')\",\"result\":\"24\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"DAY(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"HOUR\",\"chineseName\":\"返回日期中的小时\",\"description\":\"返回指定日期中的小时。\",\"example\":\"HOUR('2016-12-24 20:30:56')\",\"result\":\"20\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"HOUR(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"MINUTE\",\"chineseName\":\"返回日期中的分钟\",\"description\":\"返回指定日期中的分钟。\",\"example\":\"MINUTE('2016-12-24 20:30:56')\",\"result\":\"30\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"MINUTE(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"SECOND\",\"chineseName\":\"返回日期中的秒\",\"description\":\"返回指定日期中的秒钟。\",\"example\":\"SECOND('2016-12-24 20:30:56')\",\"result\":\"56\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"SECOND(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"WEEKNUM\",\"chineseName\":\"返回日期为第几周\",\"description\":\"返回指定日期为第几周,从每年第1天开始算第1周。\",\"example\":\"WEEKNUM('2016-12-24')\",\"result\":\"52\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"WEEKNUM(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"WEEKDAY\",\"chineseName\":\"返回日期为星期几\",\"description\":\"返回指定日期为星期几。返回值为0~6,代表周日~周六。\",\"example\":\"WEEKDAY('2016-12-24')\",\"result\":\"6\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"WEEKDAY(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"NETWORKDAYSPI\",\"chineseName\":\"返回所选时间段内包含的工作日天数\",\"description\":\"查询类型为attend时,即按考勤制度查询,将截止当前日期之前(支持选到当前日期,最大支持跨度为365天)的所选时间段内包含的工作日天数返回。
注意:此函数只能选择过去的时间(可选到当前日期)才可使用,跨度不能超过365天。查询类型为statutory时,即按法定查询,没有限制。当日期2小于日期1时,差值为负值。单位默认为日。\",\"example\":\"想知道李四在2021-11-07和2021-11-12之间的工作日天数NETWORKDAYSPI('2021-11-07', '2021-11-12','李四')\",\"result\":\"5\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\",\"*人员*(必选)\",\"*类型*(可选,attend为考勤制度,statutory为法定,默认attend)\"],\"formatString\":\"NETWORKDAYSPI(日期1, 日期2, 成员, [类型])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":4,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"employee\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":false,\"infinite\":false}]},{\"name\":\"EOMONTH\",\"chineseName\":\"返回某月最后一天日期\",\"description\":\"将某月最后一天日期返回。日期可以为指定日期也可以是日期参数,之前的月数用负数表示,之后的月数用正数表示。所输入月数需为整数。\",\"example\":\"EOMONTH('2021-11-07', -2)\",\"result\":\"2021-09-30\",\"paramDescs\":[\"*日期*(必选)\",\"*数值*(必选)\"],\"formatString\":\"EOMONTH(日期,指定日期之前或之后的月数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"CURRYEAR\",\"chineseName\":\"返回当前年份\",\"description\":\"取当前日期的年份。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRYEAR()\",\"result\":\"2022\",\"formatString\":\"CURRYEAR()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRMONTH\",\"chineseName\":\"返回当前月份\",\"description\":\"取当前日期的月份。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRMONTH()\",\"result\":\"2\",\"formatString\":\"CURRMONTH()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRDAY\",\"chineseName\":\"返回当前第几日(当月)\",\"description\":\"取当前日期的天。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRDAY()\",\"result\":\"17\",\"formatString\":\"CURRDAY()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRWEEK\",\"chineseName\":\"返回当前是周几\",\"description\":\"取当前日期是周几。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRWEEK()\",\"result\":\"4\",\"formatString\":\"CURRWEEK()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRHOUR\",\"chineseName\":\"返回当前小时\",\"description\":\"取当前日期的小时。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRHOUR()\",\"result\":\"11\",\"formatString\":\"CURRHOUR()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRMINUTE\",\"chineseName\":\"返回当前分\",\"description\":\"取当前日期的分钟。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRMINUTE()\",\"result\":\"20\",\"formatString\":\"CURRMINUTE()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRSECOND\",\"chineseName\":\"返回当前秒\",\"description\":\"取当前日期的秒钟。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRSECOND()\",\"result\":\"30\",\"formatString\":\"CURRSECOND()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"MAXDATE\",\"chineseName\":\"返回一组日期中的最大值\",\"description\":\"取一组日期中的最大值。\",\"example\":\"MAXDATE('2016-12-24', '2022-12-24')\",\"result\":\"2022-12-24\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\"],\"formatString\":\"MAXDATE(日期1,日期2,……)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":true}]},{\"name\":\"MINDATE\",\"chineseName\":\"返回一组日期中的最小值\",\"description\":\"取一组日期中的最小值。\",\"example\":\"MINDATE('2016-12-24', '2022-12-24')\",\"result\":\"2016-12-24\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\"],\"formatString\":\"MINDATE(日期1,日期2,……)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":true}]},{\"name\":\"COMPAREDATE\",\"chineseName\":\"返回两个日期指定时间的差值\",\"description\":\"日期比较,返回两个日期指定时间域的差值。可比较的时间域包括'Y'-比较年;'M'-比较月;'D'-比较日;'H'-比较小时;'I'-比较分钟;'S'-比较秒。\",\"example\":\"假设 日期1=2022-04-03、日期2=2022-04-04,COMPAREDATE({日期1},{日期2},'D')\",\"result\":\"1\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\",\"*比较类型*(可选)\"],\"formatString\":\"COMPAREDATE(日期1,日期2,[比较类型])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"TIMESTAMPTODATE\",\"chineseName\":\"返回时间戳转换后的日期\",\"description\":\"将时间戳按指定格式转换成日期。\",\"example\":\"TIMESTAMPTODATE('1671172579', 'yyyy-MM-dd HH:mm:ss')\",\"result\":\"2022-12-16 14:36:19\",\"paramDescs\":[\"*时间戳*(必选)\",\"*日期格式*(可选,默认yyyy-MM-dd HH:mm:ss)\"],\"formatString\":\"TIMESTAMPTODATE(时间戳,日期格式)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":false,\"infinite\":false}]},{\"name\":\"DATETOTIMESTAMP\",\"chineseName\":\"返回日期转换后的时间戳\",\"description\":\"将日期转换成时间戳。\",\"example\":\"DATETOTIMESTAMP('2022-12-16 14:36:19'\",\"result\":\"'1671172579'\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"DATETOTIMESTAMP(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"DATE\",\"chineseName\":\"拼接日期字符串\",\"description\":\"拼接日期\",\"example\":\"DATE('2022','12','16')\",\"result\":\"'2022-12-16'\",\"paramDescs\":[\"*日期字符*(必选)\"],\"formatString\":\"DATE({年},{月},{日})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"DAYS\",\"chineseName\":\"计算两个日期自建的间隔天数\",\"description\":\"计算两个日期的间隔天数\",\"example\":\"DAYS('2022-12-16','2022-12-18')\",\"result\":\"2\",\"paramDescs\":[\"*日期字符*(必选)\"],\"formatString\":\"DAYS({日期},{日期})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"date\",\"name\":\"日期函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"IF\",\"chineseName\":\"如果条件为真,则...否则...\",\"description\":\"如果条件为真,则执行表达式1,为假则执行表达式2。条件中不可嵌套使用IF函数。\",\"example\":\"IF({员工表.年龄} > 60, '退休', '在职')
IF({员工表.年龄} > 60, IF({员工表.性别} = {员工表.性别.女}, '退休', '在职'), '在职')\",\"result\":\"'退休'
'在职'\",\"paramDescs\":[\"*条件*(必选)\",\"*表达式1*(必选)\",\"*表达式2*(必选)\"],\"formatString\":\"IF(条件, 表达式1, 表达式2)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"AND\",\"chineseName\":\"且\",\"description\":\"所有条件均为真,则返回真,否则返回假。逻辑操作AND的函数模式。\",\"example\":\"AND(2 = 2, 2 < 2)\",\"result\":\"false\",\"paramDescs\":[\"*条件1*(必选)\",\"*条件2*(可选,可输入多个参数)\"],\"formatString\":\"AND(条件1, 条件2, [条件3, …])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":true}]},{\"name\":\"OR\",\"chineseName\":\"或\",\"description\":\"任意一个条件为真,则返回真,否则返回假。逻辑操作OR的函数模式。\",\"example\":\"OR(2 = 2, 2 > 3)\",\"result\":\"true\",\"paramDescs\":[\"*条件1*(必选)\",\"*条件2*(可选,可输入多个参数)\"],\"formatString\":\"OR(条件1, 条件2, [条件3, …])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":true}]},{\"name\":\"NOT\",\"chineseName\":\"反转真假结果\",\"description\":\"对逻辑结果取反。\",\"example\":\"NOT(2 > 3)\",\"result\":\"true\",\"paramDescs\":[\"*逻辑结果*(必选)\"],\"formatString\":\"NOT(逻辑结果)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false}]},{\"name\":\"IN\",\"chineseName\":\"变量是否包含在一组结果中\",\"description\":\"任意类型的变量或常量等于一组同类型变量或常量结果中的任意一个,则返回真。\",\"example\":\"IN(2, [2, 3, 4])\",\"result\":\"true\",\"paramDescs\":[\"*变量*(必选)\",\"*变量数组*(必选)\"],\"formatString\":\"IN(变量, [变量1, 变量2, …])\",\"paramArray\":[],\"paramData\":[\"{}\",\"[]\"],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"LIKE\",\"chineseName\":\"文本是否包含任意一个关键字\",\"description\":\"文本类型的变量或常量包含一组文本类型变量或常量结果中的任意一个,则返回真。逻辑操作LIKE的函数模式。\",\"example\":\"LIKE('大家好', ['大家', '好'])\",\"result\":\"true\",\"paramDescs\":[\"*文本*(必选)\",\"*文本数组*(必选)\"],\"formatString\":\"LIKE(文本, [文本1, 文本2, …])\",\"paramArray\":[],\"paramData\":[\"{}\",\"[]\"],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISEMPTY\",\"chineseName\":\"是否为空\",\"description\":\"变量为空或未填写,则返回真。\",\"example\":\"ISEMPTY({员工表.电话})\",\"result\":\"true\",\"paramDescs\":[\"*变量或常量*(可选)\"],\"formatString\":\"ISEMPTY(变量)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"TRUE\",\"chineseName\":\"返回真\",\"description\":\"返回真。\",\"example\":\"TRUE()\",\"result\":\"true\",\"formatString\":\"TRUE()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"FALSE\",\"chineseName\":\"返回假\",\"description\":\"返回假。\",\"example\":\"FALSE()\",\"result\":\"false\",\"formatString\":\"FALSE()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"IFS\",\"chineseName\":\"多条件\",\"description\":\"多个条件判断,位于单数位置的参数设置为条件,位于双数位置的参数设置为结果,最后一个参数为默认返回值,当所有条件都不满足的时候返回默认参数。\",\"example\":\"IFS(1>1,1,1=1,2,0)\",\"result\":\"2\",\"paramDescs\":[\"*条件1*(必选)\",\"*变量或常量*(必选)\",\"*条件2*(必选)\",\"*变量或常量*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"IFS({条件1},{结果1},{条件2},{结果2}...{默认结果})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"SWITCH\",\"chineseName\":\"条件选择\",\"description\":\"条件选择。\",\"example\":\"SWITCH({字段1},1,'A',2,'B','C')\",\"result\":\"假设字段1为2,结果:'B'\",\"paramDescs\":[\"*变量或常量*(必选)\",\"*变量或常量*(必选)\",\"*变量或常量*(必选)\",\"*变量或常量*(可选)\",\"*变量或常量*(可选)\",\"*变量或常量*(必选)\"],\"formatString\":\"SWITCH({变量},{条件1},{结果1},{条件2},{结果2}...{默认结果})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"SORT\",\"chineseName\":\"条件排序\",\"description\":\"根据排序条件进行字符和数字的排序,UP为升序,DOWN为降序。\",\"example\":\"SORT(1,2,5,4,3,'UP')\",\"result\":\"[1,2,3,4,5]\",\"paramDescs\":[\"*字符或数字*(必选)\",\"*字符或数字*(可选)\",\"......\",\"*排序方式*\"],\"formatString\":\"SORT({变量1},{变量2},{变量3}...{排序方式})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"IFERROR\",\"chineseName\":\"异常处理\",\"description\":\"异常处理函数\",\"example\":\"IFERROR(10/0,'0')\",\"result\":\"0\",\"paramDescs\":[\"*公式内容*\"],\"formatString\":\"IFERROR({变量},{变量})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"logic\",\"name\":\"逻辑函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"ROUNDUP\",\"chineseName\":\"向上舍入\",\"description\":\"根据设置的小数位精确度,返回对数值向上舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向上舍入到指定的小数位。如果小数位精确度等于 0,则向上舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向上进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。\",\"example\":\"ROUNDUP(76.9,0)\",\"result\":\"77\",\"paramDescs\":[\"*数字*(必选)\",\"*小数位精确度*(可选)\"],\"formatString\":\"ROUNDUP(数字, [小数位精确度])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"ROUND\",\"chineseName\":\"四舍五入\",\"description\":\"根据设置的小数位精确度,返回对数值四舍五入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,针对小数点后的数据进行四舍五入;如果小数位精确度等于 0,返回最接近数值的整数;如果小数位精确度为负整数,针对小数点前的数据进行四舍五入,被舍掉的数据用0占位。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。\",\"example\":\"ROUND(123.456,2),ROUND(123.456,0),ROUND(123.456,-2)\",\"result\":\"依次为123.46,123,100\",\"paramDescs\":[\"*数字*(必选)\",\"*小数位精确度*(可选)\"],\"formatString\":\"ROUND(数字, [小数位精确度])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"ROUNDDOWN\",\"chineseName\":\"向下舍入\",\"description\":\"根据设置的小数位精确度,返回对数值向下舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向下舍入到指定的小数位。如果小数位精确度等于 0,则向下舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向下进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。\",\"example\":\"ROUNDDOWN(76.9,0)\",\"result\":\"76\",\"paramDescs\":[\"*数字*(必选)\",\"*小数位精确度*(可选)\"],\"formatString\":\"ROUNDDOWN(数字, [小数位精确度])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"AGGREGATION\",\"chineseName\":\"聚合运算\",\"description\":\"将一组数据进行统计计算,支持最大值(MAX)、最小值(MIN)、平均值(AVG)。\",\"example\":\"AGGREGATION(1 , 2,3,'AVG')\",\"result\":\"2\",\"paramDescs\":[\"*数字*(必选)\",\"*聚合运算类型*(必选)\"],\"formatString\":\"AGGREGATION({数字}...,{聚合运算类型})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":true},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"avg\",\"max\",\"min\"],\"infinite\":false}]},{\"name\":\"MOD\",\"chineseName\":\"求余\",\"description\":\"将两个参数进行除法运算然后得出余数返回。\",\"example\":\"MOD( 7 , 3 )\",\"result\":\"1\",\"paramDescs\":[\"*数字*(必选)\",\"*数字*(必选)\"],\"formatString\":\"ROUNDDOWN({数字},{数字})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"TRUNC\",\"chineseName\":\"数字格式化\",\"description\":\"将小数点格式化成指定位数。\",\"example\":\"TRUNC( 2.123 , 2 )\",\"result\":\"2.12\",\"paramDescs\":[\"*数字*(必选)\",\"*精度*(必选)\"],\"formatString\":\"ROUNDDOWN({数字},{精度})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"CALDTROW\",\"chineseName\":\"明细逐行计算函数\",\"description\":\"明细逐行计算\",\"example\":\"假设:明细有金额1、金额2、金额3等三个控件,明细行数为2,第一行值分别为:5、6、10,第二行的值分别为:1、1、9。CALDTROW({金额3}==10,{金额1}+{金额2})\",\"result\":\"当金额3等于10的时候运算加法,只有第一行的金额3等于10,明细第一行的金额3赋值为11\",\"paramDescs\":[\"*字段*(必选)\",\"*公式或字段*(必选)\"],\"formatString\":\"CALDTROW({字段},{公式或字段})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"ABS\",\"chineseName\":\"绝对值\",\"description\":\"绝对值\",\"example\":\"ABS(-9)\",\"result\":\"9\",\"paramDescs\":[\"*字段*(必选)\"],\"formatString\":\"ABS({字段})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"RANDOM\",\"chineseName\":\"随机数生成\",\"description\":\"随机数生成\",\"example\":\"RANDOM(5,'NUM')\",\"result\":\"26489\",\"paramDescs\":[\"*数字*(必选)\",\"*文本*(必选)[NUM(数字)、CHAR(字符)、FIX(字符与数字混合)]\"],\"formatString\":\"RANDOM({随机数长度},{随机类型})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"POWER\",\"chineseName\":\"N次方\",\"description\":\"计算数值的N次方\",\"example\":\"POWER(2, 2)
POWER(4, 1/2)\",\"result\":\"4
2\",\"paramDescs\":[\"*数字*(必选)\",\"*数字*(必选,N次方的N)\"],\"formatString\":\"POWER({数字}, {数字})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"SQRT\",\"chineseName\":\"根号\",\"description\":\"将数值开根号\",\"example\":\"SQRT(4)\",\"result\":\"2\",\"paramDescs\":[\"*数字*(必选)\"],\"formatString\":\"SQRT({数字})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"math\",\"name\":\"数学函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"GETMONEY\",\"chineseName\":\"获取所给定数字的金额大写\",\"description\":\"将金额转换成中文金额大写。\",\"example\":\"GETMONEY({1234})\",\"result\":\"壹仟贰佰叁拾肆元整\",\"paramDescs\":[\"*数字*(必选)\"],\"formatString\":\"GETMONEY({数字})\",\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"finance\",\"name\":\"财务函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"default\",\"chineseName\":\"default\",\"description\":\"暂无\",\"formatString\":\"default()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"text\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"extend\",\"name\":\"自定义拓展函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"CHOOSE\",\"chineseName\":\"返回索引范围内指定的值\",\"description\":\"根据索引位置获取数据。\",\"example\":\"假设:数字输入框1为0,数字输入框2为2,数字输入框3为3,数字输入框4为4。数字输入框1为检索位置的变量,后面3个为检索目标。 示例:CHOOSE({表A.数字输入框1}, {表A.数字输入框2}, {表A.数字输入框3}, {表A.数字输入框4})\",\"result\":\"2,从数字输入框2开始进行检索,数字输入框2的检索位置为0,后续数据位置依次累加1可以得出。\",\"paramDescs\":[\"*索引位置*(必选)\",\"*索引目标1*(必选)\",\"......\"],\"formatString\":\"CHOOSE(索引位置,索引目标1...索引目标N)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"Array\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"VLOOKUPS\",\"chineseName\":\"按列查找,返回所需值\",\"description\":\"按列查找,返回所需值。常用于薪酬模块。根据条件获取查询参数所在列的返回参数的值。返回参数可填写多个,用英文逗号隔开。若查询不到返回null。\",\"example\":\"VLOOKUPS({税表},{税表.收入},AND({税表.收入}>{税表.应纳税所得额下限},{税表.收入}<{税表.应纳税所得额上限}),[{税表.税率},{税表.速算扣除数}]) \",\"result\":\"按列查找返回税表中收入所在的收入区间所对应的税率和速算扣除数的数值\",\"paramDescs\":[\"*表*(必选)\",\"*条件*(必选)\",\"*返回参数*(必选)\"],\"formatString\":\"VLOOKUPS(表,[条件],[返回参数])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"Array\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"MATCH\",\"chineseName\":\"返回指定数值在指定数组区域中的位置\",\"description\":\"将指定数值在指定数组区域中的位置返回。若数组中无指定值,返回null。\",\"example\":\"MATCH(15000, [1000, 15000, 2000])\",\"result\":\"1\",\"paramDescs\":[\"*值*(必选)\",\"*数组*(必选)\"],\"formatString\":\"MATCH(值,[数组])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"FIND\",\"chineseName\":\"查找\",\"description\":\"用指定参数去另一个参数列表中查找匹配项,指定参数时,填写1则去第一个参数列表中查找,2则是第二个参数列表里匹配查找第一个参数,成功则返回true,失败返回false。\",\"example\":\"FIND([1,2,3],[1,2,3,4],1)\",\"result\":\"true\",\"paramDescs\":[\"*查找值1*(必选)\",\"......\",\"*查找值N*(可选)\",\"*查找目标1*(必选)\",\"......\",\"*查找目标N*(可选)\"],\"formatString\":\"FIND([{查找值1},{查找值2}...{查找值N}],[{查找目标1},{查找目标2}...{查找目标N}])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"INDEX\",\"chineseName\":\"数据索引\",\"description\":\"数据索引函数,根据索引位置返回一组数据中对应位置的数据。注意:索引位置是从0开始的。\",\"example\":\"假设:数字控件1=2,金额控件1=3,金额控件3=5,INDEX(1,[{数字控件1},{金额控件1},{金额控件2}]\",\"result\":\"3(索引下标为1,返回数组中第二个参数)\",\"paramDescs\":[\"*索引位置*(必选)\",\"*数组*(必选)\"],\"formatString\":\"INDEX({查找值},[{查找目标1},{查找目标2}...{查找目标N}])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"UNIQUE\",\"chineseName\":\"唯一值过滤\",\"description\":\"唯一值过滤函数,得到一组数据,然后去掉重复的值,返回所有去重后的一组数据。\",\"example\":\"假设:文本控件1='A',文本控件2='B',文本控件3='B',UNIQUE({文本控件1},{文本控件2},{文本控件3})\",\"result\":\"[{文本控件1},{文本控件2}]\",\"paramDescs\":[\"*数组*(必选)\"],\"formatString\":\"UNIQUE({过滤目标1},{过滤目标2}...{过滤目标N})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"FILTER\",\"chineseName\":\"条件过滤\",\"description\":\"过滤函数,通过一个或多个条件过滤参数中的数据,返回所有符合条件的一组数据。\",\"example\":\"假设:文本控件1='A',文本控件2='B',文本控件3='B',FILTER([{文本控件1},{文本控件2},{文本控件3}],'B')\",\"result\":\"[{文本控件2},{文本控件3}]\",\"paramDescs\":[\"*数组*(必选)\",\"*过滤字段*(必选)\"],\"formatString\":\"FILTER([{过滤目标1},{过滤目标2}...{过滤目标N}],{过滤字段}={过滤依据})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false},{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"find\",\"name\":\"查找函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"GETHRMLOGINID\",\"chineseName\":\"返回指定人员系统账号\",\"description\":\"获取指定人员系统账号。\",\"example\":\"GETHRMLOGINID({表单.张三})\",\"result\":\"'zhangsan@qq.com'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMLOGINID({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMWORKCODE\",\"chineseName\":\"返回指定人员编号\",\"description\":\"获取指定人员编号。\",\"example\":\"GETHRMWORKCODE({表单.张三})\",\"result\":\"'A001'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMWORKCODE({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMMANAGER\",\"chineseName\":\"返回指定人员直接上级\",\"description\":\"获取指定人员直接上级。返回值为对应人员直接上级的ID。\",\"example\":\"GETHRMMANAGER({表单.张三})\",\"result\":\"'1559563038252396708'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMMANAGER({人员}})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMEMAIL\",\"chineseName\":\"获取指定人员邮箱\",\"description\":\"获取指定人员邮箱。\",\"example\":\"GETHRMEMAIL({表单.张三})\",\"result\":\"'2345@163.com'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMEMAIL({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMSECLEVEL\",\"chineseName\":\"获取指定人员安全级别\",\"description\":\"获取指定人员安全级别。\",\"example\":\"张三安全级别为1;GETHRMSECLEVEL({表单.张三})\",\"result\":\"'1'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMSECLEVEL({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMALLMANAGER\",\"chineseName\":\"返回指定人员所有上级\",\"description\":\"获取指定人员所有上级。存在多个上级时,返回所有上级形成的数组。\",\"example\":\"GETHRMALLMANAGER({表单.张三})\",\"result\":\"返回张三的所有上级形成的数组\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMALLMANAGER({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMDEPARTMENT\",\"chineseName\":\"返回指定人员部门\",\"description\":\"获取指定人员部门。返回值为部门ID。\",\"example\":\"GETHRMDEPARTMENT({表单.张三})\",\"result\":\"'1560052731319352218'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMDEPARTMENT({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMSUBCOMPANY\",\"chineseName\":\"返回指定人员分部\",\"description\":\"取指定人员分部,返回值为分部ID。\",\"example\":\"GETHRMSUBCOMPANY({表单.张三})\",\"result\":\"'1560052731319352218'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMSUBCOMPANY({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETDEPARTMENTNAME\",\"chineseName\":\"返回指定部门名称\",\"description\":\"获取指定部门名称。\",\"example\":\"GETDEPARTMENTNAME({表单.A部门})\",\"result\":\"'A部门'\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETDEPARTMENTNAME({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETDEPARTMENTCODE\",\"chineseName\":\"返回指定部门编号\",\"description\":\"获取指定部门编号。\",\"example\":\"GETDEPARTMENTCODE({表单.A部门})\",\"result\":\"'A001'\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETDEPARTMENTCODE({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUPERDEPARTMENT\",\"chineseName\":\"返回指定部门直接上级部门\",\"description\":\"获取指定部门直接上级部门。返回值为对应部门直接上级部门的ID。\",\"example\":\"GETSUPERDEPARTMENT({表单.A部门})\",\"result\":\"'1559563038252396709'\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETSUPERDEPARTMENT({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETALLSUPERDEPARTMENT\",\"chineseName\":\"返回指定部门所有上级部门\",\"description\":\"获取指定部门所有上级部门。存在多个上级部门时,返回所有上级部门形成的数组。\",\"example\":\"GETALLSUPERDEPARTMENT({表单.A部门})\",\"result\":\"返回A部门的所有上级部门形成的数组\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETALLSUPERDEPARTMENT({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUBCOMPANYNAME\",\"chineseName\":\"返回指定分部名称\",\"description\":\"获取指定分部名称。\",\"example\":\"GETSUBCOMPANYNAME({表单.A分部})\",\"result\":\"'A分部'\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETSUBCOMPANYNAME({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUBCOMPANYCODE\",\"chineseName\":\"返回指定分部编号\",\"description\":\"获取指定分部编号。\",\"example\":\"GETSUBCOMPANYCODE({表单.A分部})\",\"result\":\"'B001'\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETSUBCOMPANYCODE({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUPERSUBCOMPANY\",\"chineseName\":\"返回指定分部直接上级分部\",\"description\":\"获取指定分部直接上级分部。返回值为对应部门直接上级分部的ID。\",\"example\":\"GETSUPERSUBCOMPANY({表单.A分部})\",\"result\":\"'1559563038252396705'\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETSUPERSUBCOMPANY({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETALLSUPERSUBCOMPANY\",\"chineseName\":\"返回指定分部所有上级分部\",\"description\":\"获取指定分部所有上级分部。存在多个上级分部时,返回所有上级分部形成的数组。\",\"example\":\"GETALLSUPERSUBCOMPANY({表单.A分部})\",\"result\":\"A分部的所有上级分部形成的数组\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETALLSUPERSUBCOMPANY({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMNAME\",\"chineseName\":\"获取人员名称\",\"description\":\"获取指定人员的姓名。\",\"example\":\"GETHRMNAME({U:张三})\",\"result\":\"'张三'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMNAME({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMMOBILE\",\"chineseName\":\"获取人员手机号码\",\"description\":\"获取指定人员的手机号码。\",\"example\":\"GETHRMMOBILE({U:张三})\",\"result\":\"13123232323\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMMOBILE({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETREQUESTMARK\",\"chineseName\":\"获取指定流程编号\",\"description\":\"获取指定流程编号\",\"example\":\"假设关联流程=流程数据A,编号为:2332323,GETREQUESTMARK({关联流程})\",\"result\":\"'2332323'\",\"paramDescs\":[\"*关联流程*(必选)\"],\"formatString\":\"GETREQUESTMARK({关联流程})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETDOCCODE\",\"chineseName\":\"获取指定文档编号\",\"description\":\"获取指定文档编号。\",\"example\":\"假设关联文档=文档A,文档A编号为:234567,GETDOCCODE({关联文档})\",\"result\":\"'234567'\",\"paramDescs\":[\"*关联文档*(必选)\"],\"formatString\":\"GETDOCCODE({关联文档})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETPRJCODE\",\"chineseName\":\"获取指定项目编号\",\"description\":\"获取指定项目编号。\",\"example\":\"假设关联项目=项目A,项目A编号为:2838383,GETPRJCODE({关联项目})\",\"result\":\"'2838383'\",\"paramDescs\":[\"*关联项目*(必选)\"],\"formatString\":\"GETPRJCODE({关联项目})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETCRMCODE\",\"chineseName\":\"获取指定客户编号\",\"description\":\"获取指定客户编号。\",\"example\":\"假设关联客户=客户A,客户A编号为:2838383,GETCRMCODE({关联客户})\",\"result\":\"'2838383'\",\"paramDescs\":[\"*关联客户*(必选)\"],\"formatString\":\"GETCRMCODE({关联客户})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"LANGUAGE\",\"chineseName\":\"当前语言\",\"description\":\"获取当前语言。\",\"example\":\"LANGUAGE()\",\"result\":\"简体中文\",\"formatString\":\"LANGUAGE()\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETREQUESTSTATUS\",\"chineseName\":\"流程状态\",\"description\":\"获取流程状态。示例:假设关联流程所选中的数据正在审批中;GETREQUESTSTATUS({表单.关联流程})
结果:'审批中'\",\"example\":\"假设关联流程所选中的数据正在审批中;GETREQUESTSTATUS({表单.关联流程})\",\"result\":\"'审批中'\",\"paramDescs\":[\"*关联流程*(必选)\"],\"formatString\":\"GETREQUESTSTATUS()\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETEMPIDBYMOBILE\",\"chineseName\":\"人员手机获取人员ID\",\"description\":\"人员手机获取人员ID\",\"example\":\"人员手机号码获取人员ID;GETEMPIDBYMOBILE({手机号})\",\"result\":\"'342143214234213'\",\"paramDescs\":[\"*手机号*(必选)\"],\"formatString\":\"GETEMPIDBYMOBILE()\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"database\",\"name\":\"数据库函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"DISTANCE\",\"chineseName\":\"返回两个位置间的直线距离\",\"description\":\"返回两个位置间的直线距离,单位m(米)。\",\"example\":\"DISTANCE({表A.地理位置1}, {表A.地理位置2})\",\"result\":\"23000\",\"paramDescs\":[\"*地理位置1*(必选)\",\"*地理位置2*(必选)\"],\"formatString\":\"DISTANCE({地理位置1}, {地理位置2})\",\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"option\",\"must\":true,\"infinite\":false},{\"dataType\":\"option\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETUSER\",\"chineseName\":\"返回用户的个人资料\",\"description\":\"返回用户的指定资料项:name、phone、mobile、email。\",\"example\":\"GETUSER({表A.人员选择}, 'mobile')\",\"result\":\"'18692108017'\",\"paramDescs\":[\"*人员选择*(必选)\",\"*文本*(必选,资料项)\"],\"formatString\":\"GETUSER({人员选择}, 文本)\",\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"option\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"FIELDS\",\"chineseName\":\"根据条件和排序获取指定表格中的全部数据(最多50条)或指定条数的数据的指定字段值的集合。\",\"description\":\"根据条件和排序获取指定表格中的全部数据(最多50条)或指定条数的数据的指定字段值的集合。\",\"example\":\"FIELDS({表A.负责人}, {表A.销售状态} = {C:已签约}, {表A.创建时间-倒序}, 'desc', 50})\",\"result\":\"返回销售状态为已签约的最新发布的50条数据中负责人的集合\",\"paramDescs\":[\"*字段*(必选)\",\"*条件*(可选)\",\"*排序字段*(可选)\",\"*排序类型*(可选,asc为升序,desc为降序。默认值asc)\",\"*返回条数*(可选)\"],\"formatString\":\"FIELDS({字段}, [条件], [排序字段], [排序类型], [返回条数])\",\"paramData\":[],\"returnType\":\"Array\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0}],\"dataType\":\"special\",\"name\":\"特殊函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"monthNumber\",\"chineseName\":\"月份差 +1\",\"description\":\" 计算两个日期相差的月份数 +1\",\"formatString\":\"monthNumber(date1,date2)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"getEndDate\",\"chineseName\":\"根据合同期限计算合同结束日期\",\"description\":\"需传入两个参数\\n参数1、合同开始日期\\n参数2、整年(如:1、2、3)\",\"formatString\":\"getEndDate(startDate,expirationDate)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0}],\"dataType\":\"custom\",\"name\":\"自定义JS脚本函数\",\"action\":\"DataSource\",\"type\":\"functions\"}]}"; + } + } From 3e8ac01049349921ac8fe35c7389fdbbec2fb900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Thu, 4 May 2023 18:07:35 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/WEB-INF/config/MyBatis.xml | 42 + resource/WEB-INF/lib/QLExpress-3.2.0.jar | Bin 0 -> 239182 bytes resource/WEB-INF/lib/pagehelper-5.0.0.jar | Bin 0 -> 64807 bytes resource/WEB-INF/prop/hrmSalary.properties | 5 + src/com/engine/salary/constant/des.json | 2127 +++++++++++++++++ .../engine/salary/formlua/core/QlExpress.java | 63 +- .../salary/formlua/core/QlExpressTest.java | 27 + .../service/impl/FormulaRunServiceImpl.java | 3 +- .../salary/web/SalaryFormulaController.java | 14 +- 9 files changed, 2221 insertions(+), 60 deletions(-) create mode 100644 resource/WEB-INF/config/MyBatis.xml create mode 100644 resource/WEB-INF/lib/QLExpress-3.2.0.jar create mode 100644 resource/WEB-INF/lib/pagehelper-5.0.0.jar create mode 100644 resource/WEB-INF/prop/hrmSalary.properties create mode 100644 src/com/engine/salary/constant/des.json create mode 100644 src/com/engine/salary/formlua/core/QlExpressTest.java diff --git a/resource/WEB-INF/config/MyBatis.xml b/resource/WEB-INF/config/MyBatis.xml new file mode 100644 index 000000000..31cc6f0dd --- /dev/null +++ b/resource/WEB-INF/config/MyBatis.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resource/WEB-INF/lib/QLExpress-3.2.0.jar b/resource/WEB-INF/lib/QLExpress-3.2.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..52f48b28979e94c7f852d64d475e6d32bc752377 GIT binary patch literal 239182 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

?%+RwhTGUug*70ai_^2A)*lgzxX( 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
>#DP(W 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 WV2Fl-DguAr2tq;G8GuO+)c*msIU7&_ literal 0 HcmV?d00001 diff --git a/resource/WEB-INF/lib/pagehelper-5.0.0.jar b/resource/WEB-INF/lib/pagehelper-5.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..187266c88e16a5edcc1bfe59dd26ac34198ba202 GIT binary patch literal 64807 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�w!i% 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

I>gysFLDtV8NO!7@O{V-^~ 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 Wg$BHsi@5_ASQ9YwRb09F>;C` DATEADD('2016-12-24 20:00:00', 3, 'H')", + "result": "'2016-12-24'
'2016-12-24 23:00:00'", + "paramDescs": [ + "*日期*(必选)", + "*数值*(必选)", + "*单位*(可选)" + ], + "formatString": "DATEADD(日期,数值 , [单位])", + "paramArray": [], + "paramData": [], + "returnType": "date", + "type": "function", + "validForm": "current_data", + "paramCount": 3, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": true, + "constType": [ + "Y", + "M", + "D", + "H", + "I", + "S" + ], + "infinite": false + } + ] + }, + { + "name": "DATEDIFF", + "chineseName": "返回两个日期的差值", + "description": "根据指定的单位,返回日期2减去日期1的差值。当日期2小于日期1时,差值为负值。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。", + "example": "DATEDIF('2016-12-21', '2016-12-24')
DATEDIF('2016-12-24 20:00:00', '2016-12-25 20:00:00', 'H')", + "result": "3
24", + "paramDescs": [ + "*日期1*(必选)", + "*日期2*(必选)", + "*单位*(可选)" + ], + "formatString": "DATEDIFF(日期1, 日期2, [单位])", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 3, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": true, + "constType": [ + "Y", + "M", + "D", + "H", + "I", + "S" + ], + "infinite": false + } + ] + }, + { + "name": "DATEFORMAT", + "chineseName": "返回指定格式的日期", + "description": "将日期转为指定格式返回。
yyyy 将年份显示为1900-9999
yy 将年份显示为00-99
mm 将月份显示为 01–12
dd 将日期显示为 01–31", + "example": "DATEFORMAT('2016-12-24', 'YY-MM-DD')", + "result": "2016-12-24", + "paramDescs": [ + "*日期*(必选)", + "*日期格式*(必选)" + ], + "formatString": "DATEFORMAT(日期, 可选格式)", + "paramArray": [], + "paramData": [], + "returnType": "date", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": true, + "infinite": false + } + ] + }, + { + "name": "YEAR", + "chineseName": "返回日期中的年", + "description": "返回指定日期中的年。", + "example": "YEAR('2016-12-24')", + "result": "2016", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "YEAR(日期)", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "MONTH", + "chineseName": "返回日期中的月", + "description": "返回指定日期中的月。", + "example": "MONTH('2016-12-24')", + "result": "12", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "MONTH(日期)", + "paramArray": [ + "String" + ], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "DAY", + "chineseName": "返回日期中的日", + "description": "返回指定日期中的日。", + "example": "DAY('2016-12-24')", + "result": "24", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "DAY(日期)", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "HOUR", + "chineseName": "返回日期中的小时", + "description": "返回指定日期中的小时。", + "example": "HOUR('2016-12-24 20:30:56')", + "result": "20", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "HOUR(日期)", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "MINUTE", + "chineseName": "返回日期中的分钟", + "description": "返回指定日期中的分钟。", + "example": "MINUTE('2016-12-24 20:30:56')", + "result": "30", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "MINUTE(日期)", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "SECOND", + "chineseName": "返回日期中的秒", + "description": "返回指定日期中的秒钟。", + "example": "SECOND('2016-12-24 20:30:56')", + "result": "56", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "SECOND(日期)", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "WEEKNUM", + "chineseName": "返回日期为第几周", + "description": "返回指定日期为第几周,从每年第1天开始算第1周。", + "example": "WEEKNUM('2016-12-24')", + "result": "52", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "WEEKNUM(日期)", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "WEEKDAY", + "chineseName": "返回日期为星期几", + "description": "返回指定日期为星期几。返回值为0~6,代表周日~周六。", + "example": "WEEKDAY('2016-12-24')", + "result": "6", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "WEEKDAY(日期)", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "EOMONTH", + "chineseName": "返回某月最后一天日期", + "description": "将某月最后一天日期返回。日期可以为指定日期也可以是日期参数,之前的月数用负数表示,之后的月数用正数表示。所输入月数需为整数。", + "example": "EOMONTH('2021-11-07', -2)", + "result": "2021-09-30", + "paramDescs": [ + "*日期*(必选)", + "*数值*(必选)" + ], + "formatString": "EOMONTH(日期,指定日期之前或之后的月数)", + "paramArray": [], + "paramData": [], + "returnType": "string", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "CURRYEAR", + "chineseName": "返回当前年份", + "description": "取当前日期的年份。", + "example": "假设当前时间为:2022年2月17日 11:20:30 ,CURRYEAR()", + "result": "2022", + "formatString": "CURRYEAR()", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "CURRMONTH", + "chineseName": "返回当前月份", + "description": "取当前日期的月份。", + "example": "假设当前时间为:2022年2月17日 11:20:30 ,CURRMONTH()", + "result": "2", + "formatString": "CURRMONTH()", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "CURRDAY", + "chineseName": "返回当前第几日(当月)", + "description": "取当前日期的天。", + "example": "假设当前时间为:2022年2月17日 11:20:30 ,CURRDAY()", + "result": "17", + "formatString": "CURRDAY()", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "CURRWEEK", + "chineseName": "返回当前是周几", + "description": "取当前日期是周几。", + "example": "假设当前时间为:2022年2月17日 11:20:30 ,CURRWEEK()", + "result": "4", + "formatString": "CURRWEEK()", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "CURRHOUR", + "chineseName": "返回当前小时", + "description": "取当前日期的小时。", + "example": "假设当前时间为:2022年2月17日 11:20:30 ,CURRHOUR()", + "result": "11", + "formatString": "CURRHOUR()", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "CURRMINUTE", + "chineseName": "返回当前分", + "description": "取当前日期的分钟。", + "example": "假设当前时间为:2022年2月17日 11:20:30 ,CURRMINUTE()", + "result": "20", + "formatString": "CURRMINUTE()", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "CURRSECOND", + "chineseName": "返回当前秒", + "description": "取当前日期的秒钟。", + "example": "假设当前时间为:2022年2月17日 11:20:30 ,CURRSECOND()", + "result": "30", + "formatString": "CURRSECOND()", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "MAXDATE", + "chineseName": "返回一组日期中的最大值", + "description": "取一组日期中的最大值。", + "example": "MAXDATE('2016-12-24', '2022-12-24')", + "result": "2022-12-24", + "paramDescs": [ + "*日期1*(必选)", + "*日期2*(必选)" + ], + "formatString": "MAXDATE(日期1,日期2,……)", + "paramArray": [], + "paramData": [], + "returnType": "date", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": true + } + ] + }, + { + "name": "MINDATE", + "chineseName": "返回一组日期中的最小值", + "description": "取一组日期中的最小值。", + "example": "MINDATE('2016-12-24', '2022-12-24')", + "result": "2016-12-24", + "paramDescs": [ + "*日期1*(必选)", + "*日期2*(必选)" + ], + "formatString": "MINDATE(日期1,日期2,……)", + "paramArray": [], + "paramData": [], + "returnType": "date", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": true + } + ] + }, + { + "name": "COMPAREDATE", + "chineseName": "返回两个日期指定时间的差值", + "description": "日期比较,返回两个日期指定时间域的差值。可比较的时间域包括'Y'-比较年;'M'-比较月;'D'-比较日;'H'-比较小时;'I'-比较分钟;'S'-比较秒。", + "example": "假设 日期1=2022-04-03、日期2=2022-04-04,COMPAREDATE({日期1},{日期2},'D')", + "result": "1", + "paramDescs": [ + "*日期1*(必选)", + "*日期2*(必选)", + "*比较类型*(可选)" + ], + "formatString": "COMPAREDATE(日期1,日期2,[比较类型])", + "paramArray": [], + "paramData": [], + "returnType": "date", + "type": "function", + "validForm": "current_data", + "paramCount": 3, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": true, + "infinite": false + } + ] + }, + { + "name": "TIMESTAMPTODATE", + "chineseName": "返回时间戳转换后的日期", + "description": "将时间戳按指定格式转换成日期。", + "example": "TIMESTAMPTODATE('1671172579', 'yyyy-MM-dd HH:mm:ss')", + "result": "2022-12-16 14:36:19", + "paramDescs": [ + "*时间戳*(必选)", + "*日期格式*(可选,默认yyyy-MM-dd HH:mm:ss)" + ], + "formatString": "TIMESTAMPTODATE(时间戳,日期格式)", + "paramArray": [], + "paramData": [], + "returnType": "string", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": false, + "infinite": false + } + ] + }, + { + "name": "DATETOTIMESTAMP", + "chineseName": "返回日期转换后的时间戳", + "description": "将日期转换成时间戳。", + "example": "DATETOTIMESTAMP('2022-12-16 14:36:19'", + "result": "'1671172579'", + "paramDescs": [ + "*日期*(必选)" + ], + "formatString": "DATETOTIMESTAMP(日期)", + "paramArray": [], + "paramData": [], + "returnType": "string", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "date", + "must": true, + "infinite": false + } + ] + }, + { + "name": "DATE", + "chineseName": "拼接日期字符串", + "description": "拼接日期", + "example": "DATE('2022','12','16')", + "result": "'2022-12-16'", + "paramDescs": [ + "*日期字符*(必选)" + ], + "formatString": "DATE({年},{月},{日})", + "paramArray": [], + "paramData": [], + "returnType": "string", + "type": "function", + "validForm": "current_data", + "paramCount": 3, + "paramStatuses": [ + { + "dataType": "string", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": true, + "infinite": false + } + ] + }, + { + "name": "DAYS", + "chineseName": "计算两个日期自建的间隔天数", + "description": "计算两个日期的间隔天数", + "example": "DAYS('2022-12-16','2022-12-18')", + "result": "2", + "paramDescs": [ + "*日期字符*(必选)" + ], + "formatString": "DAYS({日期},{日期})", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "string", + "must": true, + "infinite": false + }, + { + "dataType": "string", + "must": true, + "infinite": false + } + ] + } + ], + "dataType": "date", + "name": "日期函数", + "action": "DataSource", + "type": "functions" + }, + { + "children": [ + { + "name": "IF", + "chineseName": "如果条件为真,则...否则...", + "description": "如果条件为真,则执行表达式1,为假则执行表达式2。条件中不可嵌套使用IF函数。", + "example": "IF({员工表.年龄} > 60, '退休', '在职')
IF({员工表.年龄} > 60, IF({员工表.性别} = {员工表.性别.女}, '退休', '在职'), '在职')", + "result": "'退休'
'在职'", + "paramDescs": [ + "*条件*(必选)", + "*表达式1*(必选)", + "*表达式2*(必选)" + ], + "formatString": "IF(条件, 表达式1, 表达式2)", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": 3, + "paramStatuses": [ + { + "dataType": "boolean", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + } + ] + }, + { + "name": "AND", + "chineseName": "且", + "description": "所有条件均为真,则返回真,否则返回假。逻辑操作AND的函数模式。", + "example": "AND(2 = 2, 2 < 2)", + "result": "false", + "paramDescs": [ + "*条件1*(必选)", + "*条件2*(可选,可输入多个参数)" + ], + "formatString": "AND(条件1, 条件2, [条件3, …])", + "paramArray": [], + "paramData": [], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "boolean", + "must": true, + "infinite": true + } + ] + }, + { + "name": "OR", + "chineseName": "或", + "description": "任意一个条件为真,则返回真,否则返回假。逻辑操作OR的函数模式。", + "example": "OR(2 = 2, 2 > 3)", + "result": "true", + "paramDescs": [ + "*条件1*(必选)", + "*条件2*(可选,可输入多个参数)" + ], + "formatString": "OR(条件1, 条件2, [条件3, …])", + "paramArray": [], + "paramData": [], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "boolean", + "must": true, + "infinite": true + } + ] + }, + { + "name": "NOT", + "chineseName": "反转真假结果", + "description": "对逻辑结果取反。", + "example": "NOT(2 > 3)", + "result": "true", + "paramDescs": [ + "*逻辑结果*(必选)" + ], + "formatString": "NOT(逻辑结果)", + "paramArray": [], + "paramData": [], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "boolean", + "must": true, + "infinite": false + } + ] + }, + { + "name": "IN", + "chineseName": "变量是否包含在一组结果中", + "description": "任意类型的变量或常量等于一组同类型变量或常量结果中的任意一个,则返回真。", + "example": "IN(2, [2, 3, 4])", + "result": "true", + "paramDescs": [ + "*变量*(必选)", + "*变量数组*(必选)" + ], + "formatString": "IN(变量, [变量1, 变量2, …])", + "paramArray": [], + "paramData": [ + "{}", + "[]" + ], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "all", + "must": true, + "infinite": false + }, + { + "dataType": "array", + "must": true, + "infinite": false + } + ] + }, + { + "name": "LIKE", + "chineseName": "文本是否包含任意一个关键字", + "description": "文本类型的变量或常量包含一组文本类型变量或常量结果中的任意一个,则返回真。逻辑操作LIKE的函数模式。", + "example": "LIKE('大家好', ['大家', '好'])", + "result": "true", + "paramDescs": [ + "*文本*(必选)", + "*文本数组*(必选)" + ], + "formatString": "LIKE(文本, [文本1, 文本2, …])", + "paramArray": [], + "paramData": [ + "{}", + "[]" + ], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "string", + "must": true, + "infinite": false + }, + { + "dataType": "array", + "must": true, + "infinite": false + } + ] + }, + { + "name": "ISEMPTY", + "chineseName": "是否为空", + "description": "变量为空或未填写,则返回真。", + "example": "ISEMPTY({员工表.电话})", + "result": "true", + "paramDescs": [ + "*变量或常量*(可选)" + ], + "formatString": "ISEMPTY(变量)", + "paramArray": [], + "paramData": [], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "all", + "must": true, + "infinite": false + } + ] + }, + { + "name": "TRUE", + "chineseName": "返回真", + "description": "返回真。", + "example": "TRUE()", + "result": "true", + "formatString": "TRUE()", + "paramArray": [], + "paramData": [], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "FALSE", + "chineseName": "返回假", + "description": "返回假。", + "example": "FALSE()", + "result": "false", + "formatString": "FALSE()", + "paramArray": [], + "paramData": [], + "returnType": "boolean", + "type": "function", + "validForm": "current_data", + "paramCount": 0 + }, + { + "name": "IFS", + "chineseName": "多条件", + "description": "多个条件判断,位于单数位置的参数设置为条件,位于双数位置的参数设置为结果,最后一个参数为默认返回值,当所有条件都不满足的时候返回默认参数。", + "example": "IFS(1>1,1,1=1,2,0)", + "result": "2", + "paramDescs": [ + "*条件1*(必选)", + "*变量或常量*(必选)", + "*条件2*(必选)", + "*变量或常量*(必选)", + "*变量或常量*(必选)" + ], + "formatString": "IFS({条件1},{结果1},{条件2},{结果2}...{默认结果})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "boolean", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + } + ] + }, + { + "name": "SWITCH", + "chineseName": "条件选择", + "description": "条件选择。", + "example": "SWITCH({字段1},1,'A',2,'B','C')", + "result": "假设字段1为2,结果:'B'", + "paramDescs": [ + "*变量或常量*(必选)", + "*变量或常量*(必选)", + "*变量或常量*(必选)", + "*变量或常量*(可选)", + "*变量或常量*(可选)", + "*变量或常量*(必选)" + ], + "formatString": "SWITCH({变量},{条件1},{结果1},{条件2},{结果2}...{默认结果})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "all", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + } + ] + }, + { + "name": "SORT", + "chineseName": "条件排序", + "description": "根据排序条件进行字符和数字的排序,UP为升序,DOWN为降序。", + "example": "SORT(1,2,5,4,3,'UP')", + "result": "[1,2,3,4,5]", + "paramDescs": [ + "*字符或数字*(必选)", + "*字符或数字*(可选)", + "......", + "*排序方式*" + ], + "formatString": "SORT({变量1},{变量2},{变量3}...{排序方式})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "array", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "IFERROR", + "chineseName": "异常处理", + "description": "异常处理函数", + "example": "IFERROR(10/0,'0')", + "result": "0", + "paramDescs": [ + "*公式内容*" + ], + "formatString": "IFERROR({变量},{变量})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "all", + "must": true, + "infinite": false + } + ] + } + ], + "dataType": "logic", + "name": "逻辑函数", + "action": "DataSource", + "type": "functions" + }, + { + "children": [ + { + "name": "ROUNDUP", + "chineseName": "向上舍入", + "description": "根据设置的小数位精确度,返回对数值向上舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向上舍入到指定的小数位。如果小数位精确度等于 0,则向上舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向上进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。", + "example": "ROUNDUP(76.9,0)", + "result": "77", + "paramDescs": [ + "*数字*(必选)", + "*小数位精确度*(可选)" + ], + "formatString": "ROUNDUP(数字, [小数位精确度])", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "ROUND", + "chineseName": "四舍五入", + "description": "根据设置的小数位精确度,返回对数值四舍五入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,针对小数点后的数据进行四舍五入;如果小数位精确度等于 0,返回最接近数值的整数;如果小数位精确度为负整数,针对小数点前的数据进行四舍五入,被舍掉的数据用0占位。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。", + "example": "ROUND(123.456,2),ROUND(123.456,0),ROUND(123.456,-2)", + "result": "依次为123.46,123,100", + "paramDescs": [ + "*数字*(必选)", + "*小数位精确度*(可选)" + ], + "formatString": "ROUND(数字, [小数位精确度])", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "ROUNDDOWN", + "chineseName": "向下舍入", + "description": "根据设置的小数位精确度,返回对数值向下舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向下舍入到指定的小数位。如果小数位精确度等于 0,则向下舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向下进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。", + "example": "ROUNDDOWN(76.9,0)", + "result": "76", + "paramDescs": [ + "*数字*(必选)", + "*小数位精确度*(可选)" + ], + "formatString": "ROUNDDOWN(数字, [小数位精确度])", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "AGGREGATION", + "chineseName": "聚合运算", + "description": "将一组数据进行统计计算,支持最大值(MAX)、最小值(MIN)、平均值(AVG)。", + "example": "AGGREGATION(1 , 2,3,'AVG')", + "result": "2", + "paramDescs": [ + "*数字*(必选)", + "*聚合运算类型*(必选)" + ], + "formatString": "AGGREGATION({数字}...,{聚合运算类型})", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": -1, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": true + }, + { + "dataType": "string", + "must": true, + "constType": [ + "avg", + "max", + "min" + ], + "infinite": false + } + ] + }, + { + "name": "MOD", + "chineseName": "求余", + "description": "将两个参数进行除法运算然后得出余数返回。", + "example": "MOD( 7 , 3 )", + "result": "1", + "paramDescs": [ + "*数字*(必选)", + "*数字*(必选)" + ], + "formatString": "ROUNDDOWN({数字},{数字})", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "TRUNC", + "chineseName": "数字格式化", + "description": "将小数点格式化成指定位数。", + "example": "TRUNC( 2.123 , 2 )", + "result": "2.12", + "paramDescs": [ + "*数字*(必选)", + "*精度*(必选)" + ], + "formatString": "ROUNDDOWN({数字},{精度})", + "paramArray": [], + "paramData": [], + "returnType": "number", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "CALDTROW", + "chineseName": "明细逐行计算函数", + "description": "明细逐行计算", + "example": "假设:明细有金额1、金额2、金额3等三个控件,明细行数为2,第一行值分别为:5、6、10,第二行的值分别为:1、1、9。CALDTROW({金额3}==10,{金额1}+{金额2})", + "result": "当金额3等于10的时候运算加法,只有第一行的金额3等于10,明细第一行的金额3赋值为11", + "paramDescs": [ + "*字段*(必选)", + "*公式或字段*(必选)" + ], + "formatString": "CALDTROW({字段},{公式或字段})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "boolean", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + } + ] + }, + { + "name": "ABS", + "chineseName": "绝对值", + "description": "绝对值", + "example": "ABS(-9)", + "result": "9", + "paramDescs": [ + "*字段*(必选)" + ], + "formatString": "ABS({字段})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "RANDOM", + "chineseName": "随机数生成", + "description": "随机数生成", + "example": "RANDOM(5,'NUM')", + "result": "26489", + "paramDescs": [ + "*数字*(必选)", + "*文本*(必选)[NUM(数字)、CHAR(字符)、FIX(字符与数字混合)]" + ], + "formatString": "RANDOM({随机数长度},{随机类型})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "boolean", + "must": true, + "infinite": false + }, + { + "dataType": "all", + "must": true, + "infinite": false + } + ] + }, + { + "name": "POWER", + "chineseName": "N次方", + "description": "计算数值的N次方", + "example": "POWER(2, 2)
POWER(4, 1/2)", + "result": "4
2", + "paramDescs": [ + "*数字*(必选)", + "*数字*(必选,N次方的N)" + ], + "formatString": "POWER({数字}, {数字})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": 2, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + }, + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + }, + { + "name": "SQRT", + "chineseName": "根号", + "description": "将数值开根号", + "example": "SQRT(4)", + "result": "2", + "paramDescs": [ + "*数字*(必选)" + ], + "formatString": "SQRT({数字})", + "paramArray": [], + "paramData": [], + "returnType": "all", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + } + ], + "dataType": "math", + "name": "数学函数", + "action": "DataSource", + "type": "functions" + }, + { + "children": [ + { + "name": "GETMONEY", + "chineseName": "获取所给定数字的金额大写", + "description": "将金额转换成中文金额大写。", + "example": "GETMONEY({1234})", + "result": "壹仟贰佰叁拾肆元整", + "paramDescs": [ + "*数字*(必选)" + ], + "formatString": "GETMONEY({数字})", + "paramData": [], + "returnType": "", + "type": "function", + "validForm": "current_data", + "paramCount": 1, + "paramStatuses": [ + { + "dataType": "number", + "must": true, + "infinite": false + } + ] + } + ], + "dataType": "finance", + "name": "财务函数", + "action": "DataSource", + "type": "functions" + } + ] +} \ No newline at end of file diff --git a/src/com/engine/salary/formlua/core/QlExpress.java b/src/com/engine/salary/formlua/core/QlExpress.java index 16b716b7c..30ef2af57 100644 --- a/src/com/engine/salary/formlua/core/QlExpress.java +++ b/src/com/engine/salary/formlua/core/QlExpress.java @@ -1,6 +1,5 @@ package com.engine.salary.formlua.core; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.engine.salary.formlua.entity.parameter.DataType; import com.engine.salary.formlua.entity.parameter.FuncNames; @@ -16,7 +15,6 @@ import com.engine.salary.formlua.func.math.MathFuncsService; import com.engine.salary.formlua.func.math.MathFuncsServiceImpl; import com.engine.salary.formlua.func.string.StringFormulaService; import com.engine.salary.formlua.func.string.StringFormulaServiceImpl; -import com.engine.salary.formlua.util.ExcelParamUtil; import com.engine.salary.formlua.util.ExpressRegularUtil; import com.ql.util.express.DynamicParamsUtil; import com.ql.util.express.ExpressRunner; @@ -29,7 +27,7 @@ import java.util.Map; import java.util.regex.PatternSyntaxException; /** - * 考勤执行业务类 + * 执行业务类 */ public class QlExpress { @@ -79,12 +77,11 @@ public class QlExpress { // threadLocalData.setExpressContext(context); // ParamContext.get().setValue("formulaParam",threadLocalData); // ParamContext.get().setValue("currentUser",simpleEmployee); - Object obj = null; try { ExpressRegularUtil.checkFuncExpress(expressSql); expressSql = expressSql.replaceAll("\\{", ""); expressSql = expressSql.replaceAll("\\}", ""); - obj = runner.execute(expressSql, expressContext, null, true, false); + Object obj = runner.execute(expressSql, expressContext, null, true, false); JSONObject resultObj = new JSONObject(); if (obj != null) { resultObj.put("excute", true); @@ -116,58 +113,12 @@ public class QlExpress { } } } - JSONObject errorJSON = new JSONObject(); - if (null == jsonError) { - errorJSON.put("error", "参数为空"); - obj = errorJSON; - - JSONObject resultObj = new JSONObject(); - resultObj.put("data", ""); - resultObj.put("excute", false); - return resultObj; - } - try { - errorJSON = JSON.parseObject(jsonError); - } catch (Exception ex) { - errorJSON.put("error", "参数为空"); - obj = errorJSON; - - JSONObject resultObj = new JSONObject(); - resultObj.put("data", ""); - resultObj.put("excute", false); - return resultObj; - } - if (!(e instanceof PatternSyntaxException)) { - String func = errorJSON.getString("func"); - int funcIdx = errorJSON.getInteger("errorFunc"); - String[] funcSplit = statement.split(func); - int startError = 1; - int loopLength = funcSplit.length - funcIdx; - for (int i = 0; i < loopLength; i++) { - if (loopLength > 1 && i == 0) { - startError += funcSplit[i].length() + func.length(); - } else { - startError += funcSplit[i].length(); - } - } - int startIdx = startError; - int endIdx = startError + func.length() - 1; - Map replaceMap = ExcelParamUtil.replaceErrorPlace(startIdx, endIdx, func, expressSql, context); - errorJSON.put("errorIdx", replaceMap.get("startIdx")); - errorJSON.put("errorEndIdx", replaceMap.get("endIdx")); - - } - if (errorJSON.containsKey("error") && null != errorJSON.getString("msg") && !ExpressRegularUtil.isContainChinese(errorJSON.getString("msg"))) { - errorJSON.put("error", "校验失败或参数错误"); - } - - errorJSON.remove("errorFunc"); - errorJSON.remove("formula"); - errorJSON.remove("func"); - errorJSON.remove("errorData"); - obj = errorJSON; + JSONObject resultObj = new JSONObject(); + resultObj.put("excute", false); + resultObj.put("data", ""); + resultObj.put("err", jsonError); + return resultObj; } - return obj; } private void initRunner(ExpressRunner runner) { diff --git a/src/com/engine/salary/formlua/core/QlExpressTest.java b/src/com/engine/salary/formlua/core/QlExpressTest.java new file mode 100644 index 000000000..d981054d6 --- /dev/null +++ b/src/com/engine/salary/formlua/core/QlExpressTest.java @@ -0,0 +1,27 @@ +package com.engine.salary.formlua.core; + +import com.alibaba.fastjson.JSONObject; + +import java.util.HashMap; +import java.util.Map; + +/** + * 执行业务类 + */ +public class QlExpressTest { + + public static void main(String[] args) { + QlExpress express = new QlExpress(); + Map context = new HashMap<>(); + context.put("a", 1); + context.put("b", 2); + context.put("c", 3); + String formula = "AGGREGATION(a+b,0,'AVG')"; + + Object execute = express.execute(formula, context); + if(execute instanceof JSONObject){ + Object data = ((JSONObject) execute).get("data"); + System.out.println(data); + } + } +} diff --git a/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java b/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java index ec8cf3bda..a0ea79549 100644 --- a/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java +++ b/src/com/engine/salary/service/impl/FormulaRunServiceImpl.java @@ -129,13 +129,12 @@ public class FormulaRunServiceImpl extends Service implements FormulaRunService boolean isCustomFunction = true; String extendParam = expressFormula.getExtendParam(); - String formulaType; try { JsonNode jsonNode = objectMapper.readTree(extendParam); //返回值配置 JsonNode isCustomFunctionNode = jsonNode.get("isCustomFunction"); if (isCustomFunctionNode != null) { - isCustomFunction = StringUtils.equals(isCustomFunctionNode.asText().trim(), "true"); + isCustomFunction = StringUtils.equals(isCustomFunctionNode.asText().trim(), "1"); } } catch (JsonProcessingException e) { log.error("express execute fail, sql extendParam parse fail", e); diff --git a/src/com/engine/salary/web/SalaryFormulaController.java b/src/com/engine/salary/web/SalaryFormulaController.java index 44932a485..f3d611dcc 100644 --- a/src/com/engine/salary/web/SalaryFormulaController.java +++ b/src/com/engine/salary/web/SalaryFormulaController.java @@ -9,6 +9,8 @@ import com.engine.salary.entity.salaryformula.po.FormulaPO; import com.engine.salary.entity.salaryformula.po.FormulaVar; import com.engine.salary.util.ResponseResult; import com.engine.salary.wrapper.SalaryFormulaWrapper; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.annotations.parameters.RequestBody; import lombok.extern.slf4j.Slf4j; import weaver.hrm.HrmUserVarify; @@ -19,6 +21,7 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -28,7 +31,7 @@ public class SalaryFormulaController { private SalaryFormulaWrapper getSalaryFormulaWrapper(User user) { - return (SalaryFormulaWrapper) ServiceUtil.getService(SalaryFormulaWrapper.class, user); + return ServiceUtil.getService(SalaryFormulaWrapper.class, user); } //变量项 @@ -95,7 +98,14 @@ public class SalaryFormulaController { @GET @Path("/des") @Produces(MediaType.APPLICATION_JSON) - public String mock(@Context HttpServletRequest request, @Context HttpServletResponse response) { + public String des(@Context HttpServletRequest request, @Context HttpServletResponse response) { + ObjectMapper mapper = new ObjectMapper(); + try { + JsonNode jsonNode = mapper.readTree(this.getClass().getClassLoader().getResourceAsStream("com/engine/salary/constant/des.json")); + return jsonNode.toString(); + } catch (IOException e) { + e.printStackTrace(); + } return "{\"data\":[{\"children\":[{\"name\":\"CONCAT\",\"chineseName\":\"链接多个文本\",\"description\":\"可用于连接多个任意类型的文本、日期、数字变量或常量。最后一个字符可使用'#分隔符#'标记为分隔符\",\"example\":\"CONCAT({总价}/10000, '万元')\",\"result\":\"100万元\",\"paramDescs\":[\"*文本1*(必选)\",\"*文本2*(可选)\",\"......\"],\"formatString\":\"CONCAT(文本1, 文本2, [文本3, …],[#分隔符#])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":true}]},{\"name\":\"TEXT\",\"chineseName\":\"将变量转为文本\",\"description\":\"将变量转为文本。\",\"example\":\"TEXT({当前数据.性别})\",\"result\":\"'男'\",\"paramDescs\":[\"*变量*(必选)\"],\"formatString\":\"TEXT(变量)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"VALUE\",\"chineseName\":\"将文本转为数字\",\"description\":\"将文本转为数字。\",\"example\":\"VALUE('23')\",\"result\":\"23\",\"paramDescs\":[\"*文本、数字、选项*(必选)\"],\"formatString\":\"VALUE([文本、数字、选项])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"LEN\",\"chineseName\":\"返回文本长度\",\"description\":\"返回文本的长度,中文、英文都算1个字符。\",\"example\":\"LEN('大家好dajiahao')\",\"result\":\"12\",\"paramDescs\":[\"*变量或常量*(必选)\"],\"formatString\":\"LEN(文本)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"SEARCH\",\"chineseName\":\"在文本中查找关键字\",\"description\":\"在指定文本中查找关键字,返回第一次出现关键字的字符位置,文本的第一个字记为1。未找到,返回0。搜索开始位置,表示从文本的第几个字符开始搜索,默认为1。\",\"example\":\"SEARCH('大家', '大家好大家好', 3)\",\"result\":\"4\",\"paramDescs\":[\"*文本关键字*(必选)\",\"*文本*(必选)\",\"*搜索开始位置*(可选)\"],\"formatString\":\"SEARCH(关键字, 文本, [搜索开始位置])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":false,\"infinite\":false}]},{\"name\":\"REPLACE\",\"chineseName\":\"替换文本中的字\",\"description\":\"在原文本中,从替换位置开始,往后数指定的替换字符数,将这段文本替换为新文本。\",\"example\":\"REPLACE('大家好大家好', 2, 3, 'dajia')\",\"result\":\"'大dajia家好'\",\"paramDescs\":[\"*文本*(必选)\"],\"formatString\":\"REPLACE(原文本, 替换开始位置, 替换字符数, 新文本)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":4,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"REPT\",\"chineseName\":\"将文本重复指定次数\",\"description\":\"将文本重复指定次数。\",\"example\":\"REPT('大家', 2)\",\"result\":\"'大家大家'\",\"paramDescs\":[\"*文本*(必选)\",\"*重复次数*(必选)\"],\"formatString\":\"REPT(文本, 重复次数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"PAD\",\"chineseName\":\"将文本填充至指定长度\",\"description\":\"将原文本填充到指定长度,如果文本长度大于设置的长度,则不做任何操作。填充位置可用参数:'LEFT'、'RIGHT'。\",\"example\":\"PAD('你好', 4, '你', 'LEFT')\",\"result\":\"'你你你好'\",\"paramDescs\":[\"*原文本*(必选)\",\"*长度*(必选)\",\"*填充用的文本*(必选)\",\"*填充位置*(可选)\"],\"formatString\":\"PAD(原文本, 长度, 填充用的文本, [填充位置])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":4,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"RIGHT\",\"LEFT\"],\"infinite\":false}]},{\"name\":\"TRIM\",\"chineseName\":\"清除前后空格\",\"description\":\"删除文本首尾的空格。\",\"example\":\"TRIM(' 大家好 ')\",\"result\":\"'大家好'\",\"paramDescs\":[\"*文本*(必选)\"],\"formatString\":\"TRIM(文本)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"LEFT\",\"chineseName\":\"返回文本左侧开始的文字\",\"description\":\"从文本左侧开始,返回指定字符数的文字。\",\"example\":\"LEFT('大家好', 2)\",\"result\":\"'大家'\",\"paramDescs\":[\"*文本*(必选)\",\"*截取字符数*(必选)\"],\"formatString\":\"LEFT(文本, 截取字符数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"RIGHT\",\"chineseName\":\"返回文本右侧开始的文字\",\"description\":\"从文本右侧开始,返回指定字符数的文字。\",\"example\":\"RIGHT('大家好', 2)\",\"result\":\"'家好'\",\"paramDescs\":[\"*文本*(必选)\",\"*截取字符数*(必选)\"],\"formatString\":\"RIGHT(文本, 截取字符数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"MID\",\"chineseName\":\"返回文本指定位置开始的文字\",\"description\":\"从文本指定位置之后开始,返回指定字符数的文字。\",\"example\":\"MID('大家好', 2, 1)\",\"result\":\"'家'\",\"paramDescs\":[\"*文本*(必选)\",\"*指定位置*(必选)\",\"*截取字符数*(必选)\"],\"formatString\":\"MID(文本, 指定位置, 截取字符数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"SCORE\",\"chineseName\":\"获取选项型控件分数\",\"description\":\"获取选项型控件(单选框、复选框、下拉菜单)分数。\",\"example\":\"SCORE({当前数据.单选框})\",\"result\":\"选项分数(注:未设置选项分数时,结果为0)\",\"paramDescs\":[\"*选项*(必选)\"],\"formatString\":\"SCORE({选项})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"option\",\"must\":true,\"infinite\":false}]},{\"name\":\"IDCARD\",\"chineseName\":\"身份证函数\",\"description\":\"从身份证号码中获取相关信息,比如:生日(BD)、年龄(AGE)、籍贯(NA)、性别(GENDER)。\",\"example\":\"IDCARD( ‘43070319980706334X’ , ‘BD’ )\",\"result\":\"'1998-07-06'\",\"paramDescs\":[\"*身份证号码*(必选)\",\"*查找类型*(必选)\"],\"formatString\":\"IDCARD({身份证号码}, {查找类型})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"BD\",\"NA\",\"AGE\",\"GENDER\"],\"infinite\":false}]},{\"name\":\"ISSTRING\",\"chineseName\":\"是否是字符串\",\"description\":\"判断是否是字符。\",\"example\":\"ISSTRING('泛微123456')\",\"result\":\"true\",\"paramDescs\":[\"*变量或常量*(必选)\"],\"formatString\":\"ISSTRING({任意控件})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISJSON\",\"chineseName\":\"JSON字符格式化\",\"description\":\"判断是不是JSON字符串,参数可以是数组,也可以是字符串,参数为数组时数组中必须只包含一个字符串。\",\"example\":\"假设文本控件={a:123},ISJSON({文本控件})\",\"result\":\"true\",\"paramDescs\":[\"*变量或常量*(必选)\"],\"formatString\":\"ISJSON({变量})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETJSONVALUE\",\"chineseName\":\"JSON字符取值\",\"description\":\"获取JSON值。第一个参数为json,可以是数组也可以是对象;第二个参数为json对象的键值,返回键值对应的值,json为数组时返回的多个值以逗号分隔\",\"example\":\"假设文本控件={a:123},GetJSONValue('{文本控件}','a')\",\"result\":\"123\",\"paramDescs\":[\"*变量或常量*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"GETJSONVALUE({变量1},变量2)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISINT\",\"chineseName\":\"字符内容是否是整数\",\"description\":\"判断字符内容是否是整数\",\"example\":\"ISINT( 2.123 )\",\"result\":\"false\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"ISINT({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISNUMBER\",\"chineseName\":\"字符内容是否是数字\",\"description\":\"判断字符内容是否是数字。\",\"example\":\"ISNUMBER('2.123')\",\"result\":\"true\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"ISNUMBER({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"SPLIT\",\"chineseName\":\"字符分割\",\"description\":\"字符分割函数,将字符以指定字符为依据分割字符为一组字符\",\"example\":\"假设文本控件=ABC#DEF,SPLIT('{文本控件}','#')\",\"result\":\"[ABC,DEF]\",\"paramDescs\":[\"*字符*(必选)\",\"*分割符*(必选)\"],\"formatString\":\"SPLIT({字符},{字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"LOWER\",\"chineseName\":\"字符转小写\",\"description\":\"将字符中的字母转为小写。\",\"example\":\"LOWER('ABC')\",\"result\":\"abc\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"LOWER({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"UPPER\",\"chineseName\":\"字符转大写\",\"description\":\"将字符中的字母转为大写。\",\"example\":\"UPPER('abc')\",\"result\":\"ABC\",\"paramDescs\":[\"*字符*(必选)\"],\"formatString\":\"UPPER({字符})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"TEXTBEFORE\",\"chineseName\":\"截取N个分割符之前的字符\",\"description\":\"截取N个分割符之前的字符\",\"example\":\"TEXTBEFORE('abc-12','-',1)\",\"result\":\"abc\",\"paramDescs\":[\"*字符*(必选)\",\"*字符*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"TEXTBEFORE({目标文本},{分隔符},{索引下标})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"TEXTAFTER\",\"chineseName\":\"截取N个分隔符之后的字符\",\"description\":\"截取N个分隔符之后的字符\",\"example\":\"TEXTAFTER('abc-12','-',1)\",\"result\":\"12\",\"paramDescs\":[\"*字符*(必选)\",\"*字符*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"TEXTAFTER({目标文本},{分隔符},{索引下标})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"String\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"char\",\"name\":\"字符函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"COUNT\",\"chineseName\":\"计数\",\"description\":\"返回指定表格中满足条件的数据条数。\",\"example\":\"COUNT({员工表})\",\"result\":\"1\",\"paramDescs\":[\"*表*(必选)\"],\"formatString\":\"COUNT(表)\",\"paramArray\":[\"Form\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"SUM\",\"chineseName\":\"求和\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的总和。统计条件中不可嵌套使用统计函数。\",\"example\":\"SUM({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"SUM(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"AVG\",\"chineseName\":\"平均值\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的平均值。统计条件中不可嵌套使用统计函数。\",\"example\":\"AVG({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"AVG(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"MIN\",\"chineseName\":\"最小值\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的最小值。统计条件中不可嵌套使用统计函数。\",\"example\":\"MIN({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"MIN(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3},{\"name\":\"MAX\",\"chineseName\":\"最大值\",\"description\":\"返回指定表格中满足条件的数据,其指定数字字段值的最大值。统计条件中不可嵌套使用统计函数。\",\"example\":\"MAX({员工表.工资})\",\"result\":\"10000\",\"paramDescs\":[\"*表或字段*(必选)\"],\"formatString\":\"MAX(数字)\",\"paramArray\":[\"Number\",\"Number\",\"Boolean\"],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"all\",\"paramCount\":3}],\"dataType\":\"agg\",\"name\":\"聚合函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"TODAY\",\"chineseName\":\"当前日期\",\"description\":\"返回当天日期。\",\"example\":\"TODAY()\",\"result\":\"'2020-01-01'\",\"formatString\":\"TODAY()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"NOW\",\"chineseName\":\"当前日期时间\",\"description\":\"返回当天日期+时间。\",\"example\":\"NOW()\",\"result\":\"'2016-12-24 12:05:38'\",\"formatString\":\"NOW()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"DATEADD\",\"chineseName\":\"对日期加减年、月、日\",\"description\":\"对日期加减按照单位加减。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。\",\"example\":\"DATEADD('2016-12-21', 3)
DATEADD('2016-12-24 20:00:00', 3, 'H')\",\"result\":\"'2016-12-24'
'2016-12-24 23:00:00'\",\"paramDescs\":[\"*日期*(必选)\",\"*数值*(必选)\",\"*单位*(可选)\"],\"formatString\":\"DATEADD(日期,数值 , [单位])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"Y\",\"M\",\"D\",\"H\",\"I\",\"S\"],\"infinite\":false}]},{\"name\":\"DATEDIFF\",\"chineseName\":\"返回两个日期的差值\",\"description\":\"根据指定的单位,返回日期2减去日期1的差值。当日期2小于日期1时,差值为负值。单位默认为日,可选单位:年Y、月M、日D、时H、分I、秒S。\",\"example\":\"DATEDIF('2016-12-21', '2016-12-24')
DATEDIF('2016-12-24 20:00:00', '2016-12-25 20:00:00', 'H')\",\"result\":\"3
24\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\",\"*单位*(可选)\"],\"formatString\":\"DATEDIFF(日期1, 日期2, [单位])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"Y\",\"M\",\"D\",\"H\",\"I\",\"S\"],\"infinite\":false}]},{\"name\":\"DATEFORMAT\",\"chineseName\":\"返回指定格式的日期\",\"description\":\"将日期转为指定格式返回。
yyyy 将年份显示为1900-9999
yy 将年份显示为00-99
mm 将月份显示为 01–12
dd 将日期显示为 01–31\",\"example\":\"DATEFORMAT('2016-12-24', 'YY-MM-DD')\",\"result\":\"2016-12-24\",\"paramDescs\":[\"*日期*(必选)\",\"*日期格式*(必选)\"],\"formatString\":\"DATEFORMAT(日期, 可选格式)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"YEAR\",\"chineseName\":\"返回日期中的年\",\"description\":\"返回指定日期中的年。\",\"example\":\"YEAR('2016-12-24')\",\"result\":\"2016\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"YEAR(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"MONTH\",\"chineseName\":\"返回日期中的月\",\"description\":\"返回指定日期中的月。\",\"example\":\"MONTH('2016-12-24')\",\"result\":\"12\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"MONTH(日期)\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"DAY\",\"chineseName\":\"返回日期中的日\",\"description\":\"返回指定日期中的日。\",\"example\":\"DAY('2016-12-24')\",\"result\":\"24\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"DAY(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"HOUR\",\"chineseName\":\"返回日期中的小时\",\"description\":\"返回指定日期中的小时。\",\"example\":\"HOUR('2016-12-24 20:30:56')\",\"result\":\"20\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"HOUR(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"MINUTE\",\"chineseName\":\"返回日期中的分钟\",\"description\":\"返回指定日期中的分钟。\",\"example\":\"MINUTE('2016-12-24 20:30:56')\",\"result\":\"30\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"MINUTE(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"SECOND\",\"chineseName\":\"返回日期中的秒\",\"description\":\"返回指定日期中的秒钟。\",\"example\":\"SECOND('2016-12-24 20:30:56')\",\"result\":\"56\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"SECOND(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"WEEKNUM\",\"chineseName\":\"返回日期为第几周\",\"description\":\"返回指定日期为第几周,从每年第1天开始算第1周。\",\"example\":\"WEEKNUM('2016-12-24')\",\"result\":\"52\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"WEEKNUM(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"WEEKDAY\",\"chineseName\":\"返回日期为星期几\",\"description\":\"返回指定日期为星期几。返回值为0~6,代表周日~周六。\",\"example\":\"WEEKDAY('2016-12-24')\",\"result\":\"6\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"WEEKDAY(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"NETWORKDAYSPI\",\"chineseName\":\"返回所选时间段内包含的工作日天数\",\"description\":\"查询类型为attend时,即按考勤制度查询,将截止当前日期之前(支持选到当前日期,最大支持跨度为365天)的所选时间段内包含的工作日天数返回。
注意:此函数只能选择过去的时间(可选到当前日期)才可使用,跨度不能超过365天。查询类型为statutory时,即按法定查询,没有限制。当日期2小于日期1时,差值为负值。单位默认为日。\",\"example\":\"想知道李四在2021-11-07和2021-11-12之间的工作日天数NETWORKDAYSPI('2021-11-07', '2021-11-12','李四')\",\"result\":\"5\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\",\"*人员*(必选)\",\"*类型*(可选,attend为考勤制度,statutory为法定,默认attend)\"],\"formatString\":\"NETWORKDAYSPI(日期1, 日期2, 成员, [类型])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":4,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"employee\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":false,\"infinite\":false}]},{\"name\":\"EOMONTH\",\"chineseName\":\"返回某月最后一天日期\",\"description\":\"将某月最后一天日期返回。日期可以为指定日期也可以是日期参数,之前的月数用负数表示,之后的月数用正数表示。所输入月数需为整数。\",\"example\":\"EOMONTH('2021-11-07', -2)\",\"result\":\"2021-09-30\",\"paramDescs\":[\"*日期*(必选)\",\"*数值*(必选)\"],\"formatString\":\"EOMONTH(日期,指定日期之前或之后的月数)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"CURRYEAR\",\"chineseName\":\"返回当前年份\",\"description\":\"取当前日期的年份。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRYEAR()\",\"result\":\"2022\",\"formatString\":\"CURRYEAR()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRMONTH\",\"chineseName\":\"返回当前月份\",\"description\":\"取当前日期的月份。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRMONTH()\",\"result\":\"2\",\"formatString\":\"CURRMONTH()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRDAY\",\"chineseName\":\"返回当前第几日(当月)\",\"description\":\"取当前日期的天。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRDAY()\",\"result\":\"17\",\"formatString\":\"CURRDAY()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRWEEK\",\"chineseName\":\"返回当前是周几\",\"description\":\"取当前日期是周几。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRWEEK()\",\"result\":\"4\",\"formatString\":\"CURRWEEK()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRHOUR\",\"chineseName\":\"返回当前小时\",\"description\":\"取当前日期的小时。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRHOUR()\",\"result\":\"11\",\"formatString\":\"CURRHOUR()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRMINUTE\",\"chineseName\":\"返回当前分\",\"description\":\"取当前日期的分钟。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRMINUTE()\",\"result\":\"20\",\"formatString\":\"CURRMINUTE()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"CURRSECOND\",\"chineseName\":\"返回当前秒\",\"description\":\"取当前日期的秒钟。\",\"example\":\"假设当前时间为:2022年2月17日 11:20:30 ,CURRSECOND()\",\"result\":\"30\",\"formatString\":\"CURRSECOND()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"MAXDATE\",\"chineseName\":\"返回一组日期中的最大值\",\"description\":\"取一组日期中的最大值。\",\"example\":\"MAXDATE('2016-12-24', '2022-12-24')\",\"result\":\"2022-12-24\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\"],\"formatString\":\"MAXDATE(日期1,日期2,……)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":true}]},{\"name\":\"MINDATE\",\"chineseName\":\"返回一组日期中的最小值\",\"description\":\"取一组日期中的最小值。\",\"example\":\"MINDATE('2016-12-24', '2022-12-24')\",\"result\":\"2016-12-24\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\"],\"formatString\":\"MINDATE(日期1,日期2,……)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":true}]},{\"name\":\"COMPAREDATE\",\"chineseName\":\"返回两个日期指定时间的差值\",\"description\":\"日期比较,返回两个日期指定时间域的差值。可比较的时间域包括'Y'-比较年;'M'-比较月;'D'-比较日;'H'-比较小时;'I'-比较分钟;'S'-比较秒。\",\"example\":\"假设 日期1=2022-04-03、日期2=2022-04-04,COMPAREDATE({日期1},{日期2},'D')\",\"result\":\"1\",\"paramDescs\":[\"*日期1*(必选)\",\"*日期2*(必选)\",\"*比较类型*(可选)\"],\"formatString\":\"COMPAREDATE(日期1,日期2,[比较类型])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"date\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"TIMESTAMPTODATE\",\"chineseName\":\"返回时间戳转换后的日期\",\"description\":\"将时间戳按指定格式转换成日期。\",\"example\":\"TIMESTAMPTODATE('1671172579', 'yyyy-MM-dd HH:mm:ss')\",\"result\":\"2022-12-16 14:36:19\",\"paramDescs\":[\"*时间戳*(必选)\",\"*日期格式*(可选,默认yyyy-MM-dd HH:mm:ss)\"],\"formatString\":\"TIMESTAMPTODATE(时间戳,日期格式)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":false,\"infinite\":false}]},{\"name\":\"DATETOTIMESTAMP\",\"chineseName\":\"返回日期转换后的时间戳\",\"description\":\"将日期转换成时间戳。\",\"example\":\"DATETOTIMESTAMP('2022-12-16 14:36:19'\",\"result\":\"'1671172579'\",\"paramDescs\":[\"*日期*(必选)\"],\"formatString\":\"DATETOTIMESTAMP(日期)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"date\",\"must\":true,\"infinite\":false}]},{\"name\":\"DATE\",\"chineseName\":\"拼接日期字符串\",\"description\":\"拼接日期\",\"example\":\"DATE('2022','12','16')\",\"result\":\"'2022-12-16'\",\"paramDescs\":[\"*日期字符*(必选)\"],\"formatString\":\"DATE({年},{月},{日})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"DAYS\",\"chineseName\":\"计算两个日期自建的间隔天数\",\"description\":\"计算两个日期的间隔天数\",\"example\":\"DAYS('2022-12-16','2022-12-18')\",\"result\":\"2\",\"paramDescs\":[\"*日期字符*(必选)\"],\"formatString\":\"DAYS({日期},{日期})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"date\",\"name\":\"日期函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"IF\",\"chineseName\":\"如果条件为真,则...否则...\",\"description\":\"如果条件为真,则执行表达式1,为假则执行表达式2。条件中不可嵌套使用IF函数。\",\"example\":\"IF({员工表.年龄} > 60, '退休', '在职')
IF({员工表.年龄} > 60, IF({员工表.性别} = {员工表.性别.女}, '退休', '在职'), '在职')\",\"result\":\"'退休'
'在职'\",\"paramDescs\":[\"*条件*(必选)\",\"*表达式1*(必选)\",\"*表达式2*(必选)\"],\"formatString\":\"IF(条件, 表达式1, 表达式2)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":3,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"AND\",\"chineseName\":\"且\",\"description\":\"所有条件均为真,则返回真,否则返回假。逻辑操作AND的函数模式。\",\"example\":\"AND(2 = 2, 2 < 2)\",\"result\":\"false\",\"paramDescs\":[\"*条件1*(必选)\",\"*条件2*(可选,可输入多个参数)\"],\"formatString\":\"AND(条件1, 条件2, [条件3, …])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":true}]},{\"name\":\"OR\",\"chineseName\":\"或\",\"description\":\"任意一个条件为真,则返回真,否则返回假。逻辑操作OR的函数模式。\",\"example\":\"OR(2 = 2, 2 > 3)\",\"result\":\"true\",\"paramDescs\":[\"*条件1*(必选)\",\"*条件2*(可选,可输入多个参数)\"],\"formatString\":\"OR(条件1, 条件2, [条件3, …])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":true}]},{\"name\":\"NOT\",\"chineseName\":\"反转真假结果\",\"description\":\"对逻辑结果取反。\",\"example\":\"NOT(2 > 3)\",\"result\":\"true\",\"paramDescs\":[\"*逻辑结果*(必选)\"],\"formatString\":\"NOT(逻辑结果)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false}]},{\"name\":\"IN\",\"chineseName\":\"变量是否包含在一组结果中\",\"description\":\"任意类型的变量或常量等于一组同类型变量或常量结果中的任意一个,则返回真。\",\"example\":\"IN(2, [2, 3, 4])\",\"result\":\"true\",\"paramDescs\":[\"*变量*(必选)\",\"*变量数组*(必选)\"],\"formatString\":\"IN(变量, [变量1, 变量2, …])\",\"paramArray\":[],\"paramData\":[\"{}\",\"[]\"],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"LIKE\",\"chineseName\":\"文本是否包含任意一个关键字\",\"description\":\"文本类型的变量或常量包含一组文本类型变量或常量结果中的任意一个,则返回真。逻辑操作LIKE的函数模式。\",\"example\":\"LIKE('大家好', ['大家', '好'])\",\"result\":\"true\",\"paramDescs\":[\"*文本*(必选)\",\"*文本数组*(必选)\"],\"formatString\":\"LIKE(文本, [文本1, 文本2, …])\",\"paramArray\":[],\"paramData\":[\"{}\",\"[]\"],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"ISEMPTY\",\"chineseName\":\"是否为空\",\"description\":\"变量为空或未填写,则返回真。\",\"example\":\"ISEMPTY({员工表.电话})\",\"result\":\"true\",\"paramDescs\":[\"*变量或常量*(可选)\"],\"formatString\":\"ISEMPTY(变量)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"TRUE\",\"chineseName\":\"返回真\",\"description\":\"返回真。\",\"example\":\"TRUE()\",\"result\":\"true\",\"formatString\":\"TRUE()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"FALSE\",\"chineseName\":\"返回假\",\"description\":\"返回假。\",\"example\":\"FALSE()\",\"result\":\"false\",\"formatString\":\"FALSE()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"IFS\",\"chineseName\":\"多条件\",\"description\":\"多个条件判断,位于单数位置的参数设置为条件,位于双数位置的参数设置为结果,最后一个参数为默认返回值,当所有条件都不满足的时候返回默认参数。\",\"example\":\"IFS(1>1,1,1=1,2,0)\",\"result\":\"2\",\"paramDescs\":[\"*条件1*(必选)\",\"*变量或常量*(必选)\",\"*条件2*(必选)\",\"*变量或常量*(必选)\",\"*变量或常量*(必选)\"],\"formatString\":\"IFS({条件1},{结果1},{条件2},{结果2}...{默认结果})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"SWITCH\",\"chineseName\":\"条件选择\",\"description\":\"条件选择。\",\"example\":\"SWITCH({字段1},1,'A',2,'B','C')\",\"result\":\"假设字段1为2,结果:'B'\",\"paramDescs\":[\"*变量或常量*(必选)\",\"*变量或常量*(必选)\",\"*变量或常量*(必选)\",\"*变量或常量*(可选)\",\"*变量或常量*(可选)\",\"*变量或常量*(必选)\"],\"formatString\":\"SWITCH({变量},{条件1},{结果1},{条件2},{结果2}...{默认结果})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"SORT\",\"chineseName\":\"条件排序\",\"description\":\"根据排序条件进行字符和数字的排序,UP为升序,DOWN为降序。\",\"example\":\"SORT(1,2,5,4,3,'UP')\",\"result\":\"[1,2,3,4,5]\",\"paramDescs\":[\"*字符或数字*(必选)\",\"*字符或数字*(可选)\",\"......\",\"*排序方式*\"],\"formatString\":\"SORT({变量1},{变量2},{变量3}...{排序方式})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"IFERROR\",\"chineseName\":\"异常处理\",\"description\":\"异常处理函数\",\"example\":\"IFERROR(10/0,'0')\",\"result\":\"0\",\"paramDescs\":[\"*公式内容*\"],\"formatString\":\"IFERROR({变量},{变量})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"logic\",\"name\":\"逻辑函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"ROUNDUP\",\"chineseName\":\"向上舍入\",\"description\":\"根据设置的小数位精确度,返回对数值向上舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向上舍入到指定的小数位。如果小数位精确度等于 0,则向上舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向上进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。\",\"example\":\"ROUNDUP(76.9,0)\",\"result\":\"77\",\"paramDescs\":[\"*数字*(必选)\",\"*小数位精确度*(可选)\"],\"formatString\":\"ROUNDUP(数字, [小数位精确度])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"ROUND\",\"chineseName\":\"四舍五入\",\"description\":\"根据设置的小数位精确度,返回对数值四舍五入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,针对小数点后的数据进行四舍五入;如果小数位精确度等于 0,返回最接近数值的整数;如果小数位精确度为负整数,针对小数点前的数据进行四舍五入,被舍掉的数据用0占位。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。\",\"example\":\"ROUND(123.456,2),ROUND(123.456,0),ROUND(123.456,-2)\",\"result\":\"依次为123.46,123,100\",\"paramDescs\":[\"*数字*(必选)\",\"*小数位精确度*(可选)\"],\"formatString\":\"ROUND(数字, [小数位精确度])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"ROUNDDOWN\",\"chineseName\":\"向下舍入\",\"description\":\"根据设置的小数位精确度,返回对数值向下舍入后的值。小数位精确度取值可为正整数,0,负整数。如果小数位精确度为正整数,则向下舍入到指定的小数位。如果小数位精确度等于 0,则向下舍入到最接近的整数。如果小数位精确度为负整数,则在小数点左侧向下进行舍入。小数位精确度不支持变量。小数位精确度默认为0,即只保留整数。\",\"example\":\"ROUNDDOWN(76.9,0)\",\"result\":\"76\",\"paramDescs\":[\"*数字*(必选)\",\"*小数位精确度*(可选)\"],\"formatString\":\"ROUNDDOWN(数字, [小数位精确度])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"AGGREGATION\",\"chineseName\":\"聚合运算\",\"description\":\"将一组数据进行统计计算,支持最大值(MAX)、最小值(MIN)、平均值(AVG)。\",\"example\":\"AGGREGATION(1 , 2,3,'AVG')\",\"result\":\"2\",\"paramDescs\":[\"*数字*(必选)\",\"*聚合运算类型*(必选)\"],\"formatString\":\"AGGREGATION({数字}...,{聚合运算类型})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":true},{\"dataType\":\"string\",\"must\":true,\"constType\":[\"avg\",\"max\",\"min\"],\"infinite\":false}]},{\"name\":\"MOD\",\"chineseName\":\"求余\",\"description\":\"将两个参数进行除法运算然后得出余数返回。\",\"example\":\"MOD( 7 , 3 )\",\"result\":\"1\",\"paramDescs\":[\"*数字*(必选)\",\"*数字*(必选)\"],\"formatString\":\"ROUNDDOWN({数字},{数字})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"TRUNC\",\"chineseName\":\"数字格式化\",\"description\":\"将小数点格式化成指定位数。\",\"example\":\"TRUNC( 2.123 , 2 )\",\"result\":\"2.12\",\"paramDescs\":[\"*数字*(必选)\",\"*精度*(必选)\"],\"formatString\":\"ROUNDDOWN({数字},{精度})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"CALDTROW\",\"chineseName\":\"明细逐行计算函数\",\"description\":\"明细逐行计算\",\"example\":\"假设:明细有金额1、金额2、金额3等三个控件,明细行数为2,第一行值分别为:5、6、10,第二行的值分别为:1、1、9。CALDTROW({金额3}==10,{金额1}+{金额2})\",\"result\":\"当金额3等于10的时候运算加法,只有第一行的金额3等于10,明细第一行的金额3赋值为11\",\"paramDescs\":[\"*字段*(必选)\",\"*公式或字段*(必选)\"],\"formatString\":\"CALDTROW({字段},{公式或字段})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"ABS\",\"chineseName\":\"绝对值\",\"description\":\"绝对值\",\"example\":\"ABS(-9)\",\"result\":\"9\",\"paramDescs\":[\"*字段*(必选)\"],\"formatString\":\"ABS({字段})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"RANDOM\",\"chineseName\":\"随机数生成\",\"description\":\"随机数生成\",\"example\":\"RANDOM(5,'NUM')\",\"result\":\"26489\",\"paramDescs\":[\"*数字*(必选)\",\"*文本*(必选)[NUM(数字)、CHAR(字符)、FIX(字符与数字混合)]\"],\"formatString\":\"RANDOM({随机数长度},{随机类型})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false},{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]},{\"name\":\"POWER\",\"chineseName\":\"N次方\",\"description\":\"计算数值的N次方\",\"example\":\"POWER(2, 2)
POWER(4, 1/2)\",\"result\":\"4
2\",\"paramDescs\":[\"*数字*(必选)\",\"*数字*(必选,N次方的N)\"],\"formatString\":\"POWER({数字}, {数字})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]},{\"name\":\"SQRT\",\"chineseName\":\"根号\",\"description\":\"将数值开根号\",\"example\":\"SQRT(4)\",\"result\":\"2\",\"paramDescs\":[\"*数字*(必选)\"],\"formatString\":\"SQRT({数字})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"math\",\"name\":\"数学函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"GETMONEY\",\"chineseName\":\"获取所给定数字的金额大写\",\"description\":\"将金额转换成中文金额大写。\",\"example\":\"GETMONEY({1234})\",\"result\":\"壹仟贰佰叁拾肆元整\",\"paramDescs\":[\"*数字*(必选)\"],\"formatString\":\"GETMONEY({数字})\",\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"finance\",\"name\":\"财务函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"default\",\"chineseName\":\"default\",\"description\":\"暂无\",\"formatString\":\"default()\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"text\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"all\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"extend\",\"name\":\"自定义拓展函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"CHOOSE\",\"chineseName\":\"返回索引范围内指定的值\",\"description\":\"根据索引位置获取数据。\",\"example\":\"假设:数字输入框1为0,数字输入框2为2,数字输入框3为3,数字输入框4为4。数字输入框1为检索位置的变量,后面3个为检索目标。 示例:CHOOSE({表A.数字输入框1}, {表A.数字输入框2}, {表A.数字输入框3}, {表A.数字输入框4})\",\"result\":\"2,从数字输入框2开始进行检索,数字输入框2的检索位置为0,后续数据位置依次累加1可以得出。\",\"paramDescs\":[\"*索引位置*(必选)\",\"*索引目标1*(必选)\",\"......\"],\"formatString\":\"CHOOSE(索引位置,索引目标1...索引目标N)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"Array\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"VLOOKUPS\",\"chineseName\":\"按列查找,返回所需值\",\"description\":\"按列查找,返回所需值。常用于薪酬模块。根据条件获取查询参数所在列的返回参数的值。返回参数可填写多个,用英文逗号隔开。若查询不到返回null。\",\"example\":\"VLOOKUPS({税表},{税表.收入},AND({税表.收入}>{税表.应纳税所得额下限},{税表.收入}<{税表.应纳税所得额上限}),[{税表.税率},{税表.速算扣除数}]) \",\"result\":\"按列查找返回税表中收入所在的收入区间所对应的税率和速算扣除数的数值\",\"paramDescs\":[\"*表*(必选)\",\"*条件*(必选)\",\"*返回参数*(必选)\"],\"formatString\":\"VLOOKUPS(表,[条件],[返回参数])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"Array\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"MATCH\",\"chineseName\":\"返回指定数值在指定数组区域中的位置\",\"description\":\"将指定数值在指定数组区域中的位置返回。若数组中无指定值,返回null。\",\"example\":\"MATCH(15000, [1000, 15000, 2000])\",\"result\":\"1\",\"paramDescs\":[\"*值*(必选)\",\"*数组*(必选)\"],\"formatString\":\"MATCH(值,[数组])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"Number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"FIND\",\"chineseName\":\"查找\",\"description\":\"用指定参数去另一个参数列表中查找匹配项,指定参数时,填写1则去第一个参数列表中查找,2则是第二个参数列表里匹配查找第一个参数,成功则返回true,失败返回false。\",\"example\":\"FIND([1,2,3],[1,2,3,4],1)\",\"result\":\"true\",\"paramDescs\":[\"*查找值1*(必选)\",\"......\",\"*查找值N*(可选)\",\"*查找目标1*(必选)\",\"......\",\"*查找目标N*(可选)\"],\"formatString\":\"FIND([{查找值1},{查找值2}...{查找值N}],[{查找目标1},{查找目标2}...{查找目标N}])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"boolean\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"INDEX\",\"chineseName\":\"数据索引\",\"description\":\"数据索引函数,根据索引位置返回一组数据中对应位置的数据。注意:索引位置是从0开始的。\",\"example\":\"假设:数字控件1=2,金额控件1=3,金额控件3=5,INDEX(1,[{数字控件1},{金额控件1},{金额控件2}]\",\"result\":\"3(索引下标为1,返回数组中第二个参数)\",\"paramDescs\":[\"*索引位置*(必选)\",\"*数组*(必选)\"],\"formatString\":\"INDEX({查找值},[{查找目标1},{查找目标2}...{查找目标N}])\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"number\",\"must\":true,\"infinite\":false},{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"UNIQUE\",\"chineseName\":\"唯一值过滤\",\"description\":\"唯一值过滤函数,得到一组数据,然后去掉重复的值,返回所有去重后的一组数据。\",\"example\":\"假设:文本控件1='A',文本控件2='B',文本控件3='B',UNIQUE({文本控件1},{文本控件2},{文本控件3})\",\"result\":\"[{文本控件1},{文本控件2}]\",\"paramDescs\":[\"*数组*(必选)\"],\"formatString\":\"UNIQUE({过滤目标1},{过滤目标2}...{过滤目标N})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":-1,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false}]},{\"name\":\"FILTER\",\"chineseName\":\"条件过滤\",\"description\":\"过滤函数,通过一个或多个条件过滤参数中的数据,返回所有符合条件的一组数据。\",\"example\":\"假设:文本控件1='A',文本控件2='B',文本控件3='B',FILTER([{文本控件1},{文本控件2},{文本控件3}],'B')\",\"result\":\"[{文本控件2},{文本控件3}]\",\"paramDescs\":[\"*数组*(必选)\",\"*过滤字段*(必选)\"],\"formatString\":\"FILTER([{过滤目标1},{过滤目标2}...{过滤目标N}],{过滤字段}={过滤依据})\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"all\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"array\",\"must\":true,\"infinite\":false},{\"dataType\":\"boolean\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"find\",\"name\":\"查找函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"GETHRMLOGINID\",\"chineseName\":\"返回指定人员系统账号\",\"description\":\"获取指定人员系统账号。\",\"example\":\"GETHRMLOGINID({表单.张三})\",\"result\":\"'zhangsan@qq.com'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMLOGINID({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMWORKCODE\",\"chineseName\":\"返回指定人员编号\",\"description\":\"获取指定人员编号。\",\"example\":\"GETHRMWORKCODE({表单.张三})\",\"result\":\"'A001'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMWORKCODE({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMMANAGER\",\"chineseName\":\"返回指定人员直接上级\",\"description\":\"获取指定人员直接上级。返回值为对应人员直接上级的ID。\",\"example\":\"GETHRMMANAGER({表单.张三})\",\"result\":\"'1559563038252396708'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMMANAGER({人员}})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMEMAIL\",\"chineseName\":\"获取指定人员邮箱\",\"description\":\"获取指定人员邮箱。\",\"example\":\"GETHRMEMAIL({表单.张三})\",\"result\":\"'2345@163.com'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMEMAIL({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMSECLEVEL\",\"chineseName\":\"获取指定人员安全级别\",\"description\":\"获取指定人员安全级别。\",\"example\":\"张三安全级别为1;GETHRMSECLEVEL({表单.张三})\",\"result\":\"'1'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMSECLEVEL({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMALLMANAGER\",\"chineseName\":\"返回指定人员所有上级\",\"description\":\"获取指定人员所有上级。存在多个上级时,返回所有上级形成的数组。\",\"example\":\"GETHRMALLMANAGER({表单.张三})\",\"result\":\"返回张三的所有上级形成的数组\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMALLMANAGER({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMDEPARTMENT\",\"chineseName\":\"返回指定人员部门\",\"description\":\"获取指定人员部门。返回值为部门ID。\",\"example\":\"GETHRMDEPARTMENT({表单.张三})\",\"result\":\"'1560052731319352218'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMDEPARTMENT({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMSUBCOMPANY\",\"chineseName\":\"返回指定人员分部\",\"description\":\"取指定人员分部,返回值为分部ID。\",\"example\":\"GETHRMSUBCOMPANY({表单.张三})\",\"result\":\"'1560052731319352218'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMSUBCOMPANY({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETDEPARTMENTNAME\",\"chineseName\":\"返回指定部门名称\",\"description\":\"获取指定部门名称。\",\"example\":\"GETDEPARTMENTNAME({表单.A部门})\",\"result\":\"'A部门'\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETDEPARTMENTNAME({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETDEPARTMENTCODE\",\"chineseName\":\"返回指定部门编号\",\"description\":\"获取指定部门编号。\",\"example\":\"GETDEPARTMENTCODE({表单.A部门})\",\"result\":\"'A001'\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETDEPARTMENTCODE({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUPERDEPARTMENT\",\"chineseName\":\"返回指定部门直接上级部门\",\"description\":\"获取指定部门直接上级部门。返回值为对应部门直接上级部门的ID。\",\"example\":\"GETSUPERDEPARTMENT({表单.A部门})\",\"result\":\"'1559563038252396709'\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETSUPERDEPARTMENT({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETALLSUPERDEPARTMENT\",\"chineseName\":\"返回指定部门所有上级部门\",\"description\":\"获取指定部门所有上级部门。存在多个上级部门时,返回所有上级部门形成的数组。\",\"example\":\"GETALLSUPERDEPARTMENT({表单.A部门})\",\"result\":\"返回A部门的所有上级部门形成的数组\",\"paramDescs\":[\"*部门*(必选)\"],\"formatString\":\"GETALLSUPERDEPARTMENT({部门})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUBCOMPANYNAME\",\"chineseName\":\"返回指定分部名称\",\"description\":\"获取指定分部名称。\",\"example\":\"GETSUBCOMPANYNAME({表单.A分部})\",\"result\":\"'A分部'\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETSUBCOMPANYNAME({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUBCOMPANYCODE\",\"chineseName\":\"返回指定分部编号\",\"description\":\"获取指定分部编号。\",\"example\":\"GETSUBCOMPANYCODE({表单.A分部})\",\"result\":\"'B001'\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETSUBCOMPANYCODE({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETSUPERSUBCOMPANY\",\"chineseName\":\"返回指定分部直接上级分部\",\"description\":\"获取指定分部直接上级分部。返回值为对应部门直接上级分部的ID。\",\"example\":\"GETSUPERSUBCOMPANY({表单.A分部})\",\"result\":\"'1559563038252396705'\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETSUPERSUBCOMPANY({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETALLSUPERSUBCOMPANY\",\"chineseName\":\"返回指定分部所有上级分部\",\"description\":\"获取指定分部所有上级分部。存在多个上级分部时,返回所有上级分部形成的数组。\",\"example\":\"GETALLSUPERSUBCOMPANY({表单.A分部})\",\"result\":\"A分部的所有上级分部形成的数组\",\"paramDescs\":[\"*分部*(必选)\"],\"formatString\":\"GETALLSUPERSUBCOMPANY({分部})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMNAME\",\"chineseName\":\"获取人员名称\",\"description\":\"获取指定人员的姓名。\",\"example\":\"GETHRMNAME({U:张三})\",\"result\":\"'张三'\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMNAME({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETHRMMOBILE\",\"chineseName\":\"获取人员手机号码\",\"description\":\"获取指定人员的手机号码。\",\"example\":\"GETHRMMOBILE({U:张三})\",\"result\":\"13123232323\",\"paramDescs\":[\"*人员*(必选)\"],\"formatString\":\"GETHRMMOBILE({人员})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETREQUESTMARK\",\"chineseName\":\"获取指定流程编号\",\"description\":\"获取指定流程编号\",\"example\":\"假设关联流程=流程数据A,编号为:2332323,GETREQUESTMARK({关联流程})\",\"result\":\"'2332323'\",\"paramDescs\":[\"*关联流程*(必选)\"],\"formatString\":\"GETREQUESTMARK({关联流程})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETDOCCODE\",\"chineseName\":\"获取指定文档编号\",\"description\":\"获取指定文档编号。\",\"example\":\"假设关联文档=文档A,文档A编号为:234567,GETDOCCODE({关联文档})\",\"result\":\"'234567'\",\"paramDescs\":[\"*关联文档*(必选)\"],\"formatString\":\"GETDOCCODE({关联文档})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETPRJCODE\",\"chineseName\":\"获取指定项目编号\",\"description\":\"获取指定项目编号。\",\"example\":\"假设关联项目=项目A,项目A编号为:2838383,GETPRJCODE({关联项目})\",\"result\":\"'2838383'\",\"paramDescs\":[\"*关联项目*(必选)\"],\"formatString\":\"GETPRJCODE({关联项目})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETCRMCODE\",\"chineseName\":\"获取指定客户编号\",\"description\":\"获取指定客户编号。\",\"example\":\"假设关联客户=客户A,客户A编号为:2838383,GETCRMCODE({关联客户})\",\"result\":\"'2838383'\",\"paramDescs\":[\"*关联客户*(必选)\"],\"formatString\":\"GETCRMCODE({关联客户})\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"LANGUAGE\",\"chineseName\":\"当前语言\",\"description\":\"获取当前语言。\",\"example\":\"LANGUAGE()\",\"result\":\"简体中文\",\"formatString\":\"LANGUAGE()\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETREQUESTSTATUS\",\"chineseName\":\"流程状态\",\"description\":\"获取流程状态。示例:假设关联流程所选中的数据正在审批中;GETREQUESTSTATUS({表单.关联流程})
结果:'审批中'\",\"example\":\"假设关联流程所选中的数据正在审批中;GETREQUESTSTATUS({表单.关联流程})\",\"result\":\"'审批中'\",\"paramDescs\":[\"*关联流程*(必选)\"],\"formatString\":\"GETREQUESTSTATUS()\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETEMPIDBYMOBILE\",\"chineseName\":\"人员手机获取人员ID\",\"description\":\"人员手机获取人员ID\",\"example\":\"人员手机号码获取人员ID;GETEMPIDBYMOBILE({手机号})\",\"result\":\"'342143214234213'\",\"paramDescs\":[\"*手机号*(必选)\"],\"formatString\":\"GETEMPIDBYMOBILE()\",\"paramArray\":[\"String\"],\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":1,\"paramStatuses\":[{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]}],\"dataType\":\"database\",\"name\":\"数据库函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"DISTANCE\",\"chineseName\":\"返回两个位置间的直线距离\",\"description\":\"返回两个位置间的直线距离,单位m(米)。\",\"example\":\"DISTANCE({表A.地理位置1}, {表A.地理位置2})\",\"result\":\"23000\",\"paramDescs\":[\"*地理位置1*(必选)\",\"*地理位置2*(必选)\"],\"formatString\":\"DISTANCE({地理位置1}, {地理位置2})\",\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"option\",\"must\":true,\"infinite\":false},{\"dataType\":\"option\",\"must\":true,\"infinite\":false}]},{\"name\":\"GETUSER\",\"chineseName\":\"返回用户的个人资料\",\"description\":\"返回用户的指定资料项:name、phone、mobile、email。\",\"example\":\"GETUSER({表A.人员选择}, 'mobile')\",\"result\":\"'18692108017'\",\"paramDescs\":[\"*人员选择*(必选)\",\"*文本*(必选,资料项)\"],\"formatString\":\"GETUSER({人员选择}, 文本)\",\"paramData\":[],\"returnType\":\"string\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":2,\"paramStatuses\":[{\"dataType\":\"option\",\"must\":true,\"infinite\":false},{\"dataType\":\"string\",\"must\":true,\"infinite\":false}]},{\"name\":\"FIELDS\",\"chineseName\":\"根据条件和排序获取指定表格中的全部数据(最多50条)或指定条数的数据的指定字段值的集合。\",\"description\":\"根据条件和排序获取指定表格中的全部数据(最多50条)或指定条数的数据的指定字段值的集合。\",\"example\":\"FIELDS({表A.负责人}, {表A.销售状态} = {C:已签约}, {表A.创建时间-倒序}, 'desc', 50})\",\"result\":\"返回销售状态为已签约的最新发布的50条数据中负责人的集合\",\"paramDescs\":[\"*字段*(必选)\",\"*条件*(可选)\",\"*排序字段*(可选)\",\"*排序类型*(可选,asc为升序,desc为降序。默认值asc)\",\"*返回条数*(可选)\"],\"formatString\":\"FIELDS({字段}, [条件], [排序字段], [排序类型], [返回条数])\",\"paramData\":[],\"returnType\":\"Array\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0}],\"dataType\":\"special\",\"name\":\"特殊函数\",\"action\":\"DataSource\",\"type\":\"functions\"},{\"children\":[{\"name\":\"monthNumber\",\"chineseName\":\"月份差 +1\",\"description\":\" 计算两个日期相差的月份数 +1\",\"formatString\":\"monthNumber(date1,date2)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0},{\"name\":\"getEndDate\",\"chineseName\":\"根据合同期限计算合同结束日期\",\"description\":\"需传入两个参数\\n参数1、合同开始日期\\n参数2、整年(如:1、2、3)\",\"formatString\":\"getEndDate(startDate,expirationDate)\",\"paramArray\":[],\"paramData\":[],\"returnType\":\"number\",\"type\":\"function\",\"validForm\":\"current_data\",\"paramCount\":0}],\"dataType\":\"custom\",\"name\":\"自定义JS脚本函数\",\"action\":\"DataSource\",\"type\":\"functions\"}]}"; } From 0f38b6cbaa9c3fca9f1e3044501c1b20104ed7d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Thu, 4 May 2023 19:43:35 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E5=8E=BB=E9=99=A4mock=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../salary/service/impl/SalaryFormulaServiceImpl.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java b/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java index 068f67930..ba50bf39b 100644 --- a/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java +++ b/src/com/engine/salary/service/impl/SalaryFormulaServiceImpl.java @@ -368,12 +368,6 @@ public class SalaryFormulaServiceImpl extends Service implements SalaryFormulaSe log.error("express execute fail ", e); throw new SalaryRunTimeException("公式测试运行出错,请检查公式配置!", e); } - if (run != null && StringUtils.isNotBlank(String.valueOf(run)) && returnTypeEnum == ReturnTypeEnum.NUMBER) { - //返回结果不是数字 - if (!NumberUtils.isCreatable(String.valueOf(run))) { - throw new SalaryRunTimeException("返回结果不是数值"); - } - } return run; } From ccec800a75ed33048aafa360c9a4227da9ff3e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Mon, 8 May 2023 11:21:09 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/engine/salary/constant/des.json | 599 ------------------ .../engine/salary/formlua/core/QlExpress.java | 20 +- 2 files changed, 10 insertions(+), 609 deletions(-) diff --git a/src/com/engine/salary/constant/des.json b/src/com/engine/salary/constant/des.json index 047235f93..fe3b8ce5f 100644 --- a/src/com/engine/salary/constant/des.json +++ b/src/com/engine/salary/constant/des.json @@ -454,258 +454,6 @@ "infinite": false } ] - }, - { - "name": "ISJSON", - "chineseName": "JSON字符格式化", - "description": "判断是不是JSON字符串,参数可以是数组,也可以是字符串,参数为数组时数组中必须只包含一个字符串。", - "example": "假设文本控件={a:123},ISJSON({文本控件})", - "result": "true", - "paramDescs": [ - "*变量或常量*(必选)" - ], - "formatString": "ISJSON({变量})", - "paramArray": [], - "paramData": [], - "returnType": "boolean", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "GETJSONVALUE", - "chineseName": "JSON字符取值", - "description": "获取JSON值。第一个参数为json,可以是数组也可以是对象;第二个参数为json对象的键值,返回键值对应的值,json为数组时返回的多个值以逗号分隔", - "example": "假设文本控件={a:123},GetJSONValue('{文本控件}','a')", - "result": "123", - "paramDescs": [ - "*变量或常量*(必选)", - "*变量或常量*(必选)" - ], - "formatString": "GETJSONVALUE({变量1},变量2)", - "paramArray": [], - "paramData": [], - "returnType": "string", - "type": "function", - "validForm": "current_data", - "paramCount": 2, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "ISINT", - "chineseName": "字符内容是否是整数", - "description": "判断字符内容是否是整数", - "example": "ISINT( 2.123 )", - "result": "false", - "paramDescs": [ - "*字符*(必选)" - ], - "formatString": "ISINT({字符})", - "paramArray": [], - "paramData": [], - "returnType": "boolean", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "ISNUMBER", - "chineseName": "字符内容是否是数字", - "description": "判断字符内容是否是数字。", - "example": "ISNUMBER('2.123')", - "result": "true", - "paramDescs": [ - "*字符*(必选)" - ], - "formatString": "ISNUMBER({字符})", - "paramArray": [], - "paramData": [], - "returnType": "boolean", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "SPLIT", - "chineseName": "字符分割", - "description": "字符分割函数,将字符以指定字符为依据分割字符为一组字符", - "example": "假设文本控件=ABC#DEF,SPLIT('{文本控件}','#')", - "result": "[ABC,DEF]", - "paramDescs": [ - "*字符*(必选)", - "*分割符*(必选)" - ], - "formatString": "SPLIT({字符},{字符})", - "paramArray": [], - "paramData": [], - "returnType": "string", - "type": "function", - "validForm": "current_data", - "paramCount": 2, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "LOWER", - "chineseName": "字符转小写", - "description": "将字符中的字母转为小写。", - "example": "LOWER('ABC')", - "result": "abc", - "paramDescs": [ - "*字符*(必选)" - ], - "formatString": "LOWER({字符})", - "paramArray": [], - "paramData": [], - "returnType": "String", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "UPPER", - "chineseName": "字符转大写", - "description": "将字符中的字母转为大写。", - "example": "UPPER('abc')", - "result": "ABC", - "paramDescs": [ - "*字符*(必选)" - ], - "formatString": "UPPER({字符})", - "paramArray": [], - "paramData": [], - "returnType": "String", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "TEXTBEFORE", - "chineseName": "截取N个分割符之前的字符", - "description": "截取N个分割符之前的字符", - "example": "TEXTBEFORE('abc-12','-',1)", - "result": "abc", - "paramDescs": [ - "*字符*(必选)", - "*字符*(必选)", - "*变量或常量*(必选)" - ], - "formatString": "TEXTBEFORE({目标文本},{分隔符},{索引下标})", - "paramArray": [], - "paramData": [], - "returnType": "String", - "type": "function", - "validForm": "current_data", - "paramCount": 3, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "number", - "must": true, - "infinite": false - } - ] - }, - { - "name": "TEXTAFTER", - "chineseName": "截取N个分隔符之后的字符", - "description": "截取N个分隔符之后的字符", - "example": "TEXTAFTER('abc-12','-',1)", - "result": "12", - "paramDescs": [ - "*字符*(必选)", - "*字符*(必选)", - "*变量或常量*(必选)" - ], - "formatString": "TEXTAFTER({目标文本},{分隔符},{索引下标})", - "paramArray": [], - "paramData": [], - "returnType": "String", - "type": "function", - "validForm": "current_data", - "paramCount": 3, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "number", - "must": true, - "infinite": false - } - ] } ], "dataType": "char", @@ -1232,159 +980,6 @@ "infinite": true } ] - }, - { - "name": "COMPAREDATE", - "chineseName": "返回两个日期指定时间的差值", - "description": "日期比较,返回两个日期指定时间域的差值。可比较的时间域包括'Y'-比较年;'M'-比较月;'D'-比较日;'H'-比较小时;'I'-比较分钟;'S'-比较秒。", - "example": "假设 日期1=2022-04-03、日期2=2022-04-04,COMPAREDATE({日期1},{日期2},'D')", - "result": "1", - "paramDescs": [ - "*日期1*(必选)", - "*日期2*(必选)", - "*比较类型*(可选)" - ], - "formatString": "COMPAREDATE(日期1,日期2,[比较类型])", - "paramArray": [], - "paramData": [], - "returnType": "date", - "type": "function", - "validForm": "current_data", - "paramCount": 3, - "paramStatuses": [ - { - "dataType": "date", - "must": true, - "infinite": false - }, - { - "dataType": "date", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "TIMESTAMPTODATE", - "chineseName": "返回时间戳转换后的日期", - "description": "将时间戳按指定格式转换成日期。", - "example": "TIMESTAMPTODATE('1671172579', 'yyyy-MM-dd HH:mm:ss')", - "result": "2022-12-16 14:36:19", - "paramDescs": [ - "*时间戳*(必选)", - "*日期格式*(可选,默认yyyy-MM-dd HH:mm:ss)" - ], - "formatString": "TIMESTAMPTODATE(时间戳,日期格式)", - "paramArray": [], - "paramData": [], - "returnType": "string", - "type": "function", - "validForm": "current_data", - "paramCount": 2, - "paramStatuses": [ - { - "dataType": "date", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": false, - "infinite": false - } - ] - }, - { - "name": "DATETOTIMESTAMP", - "chineseName": "返回日期转换后的时间戳", - "description": "将日期转换成时间戳。", - "example": "DATETOTIMESTAMP('2022-12-16 14:36:19'", - "result": "'1671172579'", - "paramDescs": [ - "*日期*(必选)" - ], - "formatString": "DATETOTIMESTAMP(日期)", - "paramArray": [], - "paramData": [], - "returnType": "string", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "date", - "must": true, - "infinite": false - } - ] - }, - { - "name": "DATE", - "chineseName": "拼接日期字符串", - "description": "拼接日期", - "example": "DATE('2022','12','16')", - "result": "'2022-12-16'", - "paramDescs": [ - "*日期字符*(必选)" - ], - "formatString": "DATE({年},{月},{日})", - "paramArray": [], - "paramData": [], - "returnType": "string", - "type": "function", - "validForm": "current_data", - "paramCount": 3, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - } - ] - }, - { - "name": "DAYS", - "chineseName": "计算两个日期自建的间隔天数", - "description": "计算两个日期的间隔天数", - "example": "DAYS('2022-12-16','2022-12-18')", - "result": "2", - "paramDescs": [ - "*日期字符*(必选)" - ], - "formatString": "DAYS({日期},{日期})", - "paramArray": [], - "paramData": [], - "returnType": "number", - "type": "function", - "validForm": "current_data", - "paramCount": 2, - "paramStatuses": [ - { - "dataType": "string", - "must": true, - "infinite": false - }, - { - "dataType": "string", - "must": true, - "infinite": false - } - ] } ], "dataType": "date", @@ -1698,62 +1293,6 @@ "infinite": false } ] - }, - { - "name": "SORT", - "chineseName": "条件排序", - "description": "根据排序条件进行字符和数字的排序,UP为升序,DOWN为降序。", - "example": "SORT(1,2,5,4,3,'UP')", - "result": "[1,2,3,4,5]", - "paramDescs": [ - "*字符或数字*(必选)", - "*字符或数字*(可选)", - "......", - "*排序方式*" - ], - "formatString": "SORT({变量1},{变量2},{变量3}...{排序方式})", - "paramArray": [], - "paramData": [], - "returnType": "all", - "type": "function", - "validForm": "current_data", - "paramCount": -1, - "paramStatuses": [ - { - "dataType": "array", - "must": true, - "infinite": false - }, - { - "dataType": "number", - "must": true, - "infinite": false - } - ] - }, - { - "name": "IFERROR", - "chineseName": "异常处理", - "description": "异常处理函数", - "example": "IFERROR(10/0,'0')", - "result": "0", - "paramDescs": [ - "*公式内容*" - ], - "formatString": "IFERROR({变量},{变量})", - "paramArray": [], - "paramData": [], - "returnType": "all", - "type": "function", - "validForm": "current_data", - "paramCount": -1, - "paramStatuses": [ - { - "dataType": "all", - "must": true, - "infinite": false - } - ] } ], "dataType": "logic", @@ -1947,144 +1486,6 @@ "infinite": false } ] - }, - { - "name": "CALDTROW", - "chineseName": "明细逐行计算函数", - "description": "明细逐行计算", - "example": "假设:明细有金额1、金额2、金额3等三个控件,明细行数为2,第一行值分别为:5、6、10,第二行的值分别为:1、1、9。CALDTROW({金额3}==10,{金额1}+{金额2})", - "result": "当金额3等于10的时候运算加法,只有第一行的金额3等于10,明细第一行的金额3赋值为11", - "paramDescs": [ - "*字段*(必选)", - "*公式或字段*(必选)" - ], - "formatString": "CALDTROW({字段},{公式或字段})", - "paramArray": [], - "paramData": [], - "returnType": "all", - "type": "function", - "validForm": "current_data", - "paramCount": 2, - "paramStatuses": [ - { - "dataType": "boolean", - "must": true, - "infinite": false - }, - { - "dataType": "all", - "must": true, - "infinite": false - } - ] - }, - { - "name": "ABS", - "chineseName": "绝对值", - "description": "绝对值", - "example": "ABS(-9)", - "result": "9", - "paramDescs": [ - "*字段*(必选)" - ], - "formatString": "ABS({字段})", - "paramArray": [], - "paramData": [], - "returnType": "all", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "number", - "must": true, - "infinite": false - } - ] - }, - { - "name": "RANDOM", - "chineseName": "随机数生成", - "description": "随机数生成", - "example": "RANDOM(5,'NUM')", - "result": "26489", - "paramDescs": [ - "*数字*(必选)", - "*文本*(必选)[NUM(数字)、CHAR(字符)、FIX(字符与数字混合)]" - ], - "formatString": "RANDOM({随机数长度},{随机类型})", - "paramArray": [], - "paramData": [], - "returnType": "all", - "type": "function", - "validForm": "current_data", - "paramCount": 2, - "paramStatuses": [ - { - "dataType": "boolean", - "must": true, - "infinite": false - }, - { - "dataType": "all", - "must": true, - "infinite": false - } - ] - }, - { - "name": "POWER", - "chineseName": "N次方", - "description": "计算数值的N次方", - "example": "POWER(2, 2)
POWER(4, 1/2)", - "result": "4
2", - "paramDescs": [ - "*数字*(必选)", - "*数字*(必选,N次方的N)" - ], - "formatString": "POWER({数字}, {数字})", - "paramArray": [], - "paramData": [], - "returnType": "all", - "type": "function", - "validForm": "current_data", - "paramCount": 2, - "paramStatuses": [ - { - "dataType": "number", - "must": true, - "infinite": false - }, - { - "dataType": "number", - "must": true, - "infinite": false - } - ] - }, - { - "name": "SQRT", - "chineseName": "根号", - "description": "将数值开根号", - "example": "SQRT(4)", - "result": "2", - "paramDescs": [ - "*数字*(必选)" - ], - "formatString": "SQRT({数字})", - "paramArray": [], - "paramData": [], - "returnType": "all", - "type": "function", - "validForm": "current_data", - "paramCount": 1, - "paramStatuses": [ - { - "dataType": "number", - "must": true, - "infinite": false - } - ] } ], "dataType": "math", diff --git a/src/com/engine/salary/formlua/core/QlExpress.java b/src/com/engine/salary/formlua/core/QlExpress.java index 30ef2af57..91b3145ef 100644 --- a/src/com/engine/salary/formlua/core/QlExpress.java +++ b/src/com/engine/salary/formlua/core/QlExpress.java @@ -145,22 +145,25 @@ public class QlExpress { runner.replaceOperator("*", new WOperatorMulti("*")); runner.replaceOperator("/", new WOperatorDiv("/")); //逻辑函数 - runner.replaceOperator("IN", new InOperator("in")); runner.replaceOperator("IF", new InOperator("IF")); runner.addFunctionOfServiceMethod(FuncNames.AND.toString(), logicService, FuncNames.AND.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.OR.toString(), logicService, FuncNames.OR.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.NOT.toString(), logicService, FuncNames.NOT.getName(), new Class[]{Object[].class}, ""); + runner.replaceOperator("IN", new InOperator("in")); runner.addFunctionOfServiceMethod(FuncNames.LIKE.toString(), logicService, FuncNames.LIKE.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.ISEMPTY.toString(), logicService, FuncNames.ISEMPTY.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.TRUE.toString(), logicService, FuncNames.TRUE.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.FALSE.toString(), logicService, FuncNames.FALSE.getName(), new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod(FuncNames.ISEMPTY.toString(), logicService, FuncNames.ISEMPTY.getName(), new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod(FuncNames.NOT.toString(), logicService, FuncNames.NOT.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.IFS.toString(), logicService, FuncNames.IFS.getName(), new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod(FuncNames.FIND.toString(), logicService, FuncNames.FIND.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.SWITCH.toString(), logicService, FuncNames.SWITCH.getName(), new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod(FuncNames.FIND.toString(), logicService, FuncNames.FIND.getName(), new Class[]{Object[].class}, ""); //日期函数 - runner.addFunctionOfServiceMethod("DATEDIFF", dateTimeService, "dateDiff", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("TODAY", dateTimeService, "today", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("NOW", dateTimeService, "now", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("DATEADD", dateTimeService, "dateAdd", new Class[]{Object[].class}, errorInfo); + runner.addFunctionOfServiceMethod("DATEDIFF", dateTimeService, "dateDiff", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("DATEFORMAT", dateTimeService, "dateFormat", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("YEAR", dateTimeService, "year", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("MONTH", dateTimeService, "month", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("DAY", dateTimeService, "day", new Class[]{Object[].class}, ""); @@ -169,10 +172,6 @@ public class QlExpress { runner.addFunctionOfServiceMethod("SECOND", dateTimeService, "seconds", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("WEEKNUM", dateTimeService, "weekNum", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("WEEKDAY", dateTimeService, "weekDay", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod("NOW", dateTimeService, "now", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod("TODAY", dateTimeService, "today", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod("DATEFORMAT", dateTimeService, "dateFormat", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod("DAYOFMONTH", dateTimeService, "dayOfMonth", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("EOMONTH", dateTimeService, "eoMonth", new Class[]{Object[].class}, ""); // runner.addFunctionOfServiceMethod("NETWORKDAYSPI", dateTimeService, "workdayIntl", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("CURRYEAR", dateTimeService, "currYear", new Class[]{Object[].class}, ""); @@ -184,6 +183,7 @@ public class QlExpress { runner.addFunctionOfServiceMethod("CURRSECOND", dateTimeService, "currSecond", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("MAXDATE", dateTimeService, "maxDate", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("MINDATE", dateTimeService, "minDate", new Class[]{Object[].class}, ""); +// runner.addFunctionOfServiceMethod("DAYOFMONTH", dateTimeService, "dayOfMonth", new Class[]{Object[].class}, ""); //聚合函数 // runner.addFunctionOfServiceMethod("COUNT", aggregationFunc, "counts", new Class[]{Object[].class}, "COUNT参数错误"); @@ -211,8 +211,8 @@ public class QlExpress { //数学函数 runner.addFunctionOfServiceMethod("ROUNDUP", mathFuncsService, "roundUp", new Class[]{Object[].class}, ""); - runner.addFunctionOfServiceMethod("ROUNDDOWN", mathFuncsService, "roundDown", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod("ROUND", mathFuncsService, "round", new Class[]{Object[].class}, ""); + runner.addFunctionOfServiceMethod("ROUNDDOWN", mathFuncsService, "roundDown", new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.AGGREGATION.toString(), mathFuncsService, FuncNames.AGGREGATION.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.MOD.toString(), mathFuncsService, FuncNames.MOD.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.TRUNC.toString(), mathFuncsService, FuncNames.TRUNC.getName(), new Class[]{Object.class, Object.class}, ""); From 197506b72b3a495e89ccf159839c4bac59d1cfae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Mon, 8 May 2023 14:12:33 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E9=80=82=E9=85=8Dif?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/engine/salary/formlua/core/QlExpress.java | 3 ++- src/com/engine/salary/formlua/core/QlExpressTest.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/engine/salary/formlua/core/QlExpress.java b/src/com/engine/salary/formlua/core/QlExpress.java index 91b3145ef..8086f0000 100644 --- a/src/com/engine/salary/formlua/core/QlExpress.java +++ b/src/com/engine/salary/formlua/core/QlExpress.java @@ -9,6 +9,7 @@ import com.engine.salary.formlua.func.date.DateTimeServiceImpl; import com.engine.salary.formlua.func.finance.FinanceService; import com.engine.salary.formlua.func.finance.FinanceServiceImpl; import com.engine.salary.formlua.func.find.FindFuncsService; +import com.engine.salary.formlua.func.logic.IfOperator; import com.engine.salary.formlua.func.logic.LogicService; import com.engine.salary.formlua.func.logic.LogicServiceImpl; import com.engine.salary.formlua.func.math.MathFuncsService; @@ -145,7 +146,7 @@ public class QlExpress { runner.replaceOperator("*", new WOperatorMulti("*")); runner.replaceOperator("/", new WOperatorDiv("/")); //逻辑函数 - runner.replaceOperator("IF", new InOperator("IF")); + runner.replaceOperator("IF", new IfOperator("IF")); runner.addFunctionOfServiceMethod(FuncNames.AND.toString(), logicService, FuncNames.AND.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.OR.toString(), logicService, FuncNames.OR.getName(), new Class[]{Object[].class}, ""); runner.addFunctionOfServiceMethod(FuncNames.NOT.toString(), logicService, FuncNames.NOT.getName(), new Class[]{Object[].class}, ""); diff --git a/src/com/engine/salary/formlua/core/QlExpressTest.java b/src/com/engine/salary/formlua/core/QlExpressTest.java index d981054d6..25af7e339 100644 --- a/src/com/engine/salary/formlua/core/QlExpressTest.java +++ b/src/com/engine/salary/formlua/core/QlExpressTest.java @@ -16,7 +16,7 @@ public class QlExpressTest { context.put("a", 1); context.put("b", 2); context.put("c", 3); - String formula = "AGGREGATION(a+b,0,'AVG')"; + String formula = "IF(1=1,1,2)"; Object execute = express.execute(formula, context); if(execute instanceof JSONObject){ From c87db92ee8b56dd4e7a4e78d7e9083504a123964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Wed, 10 May 2023 14:26:39 +0800 Subject: [PATCH 11/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=A0=B8=E7=AE=97=E5=9F=BA=E6=9C=AC=E4=BF=A1=E6=81=AF=E5=92=8C?= =?UTF-8?q?=E6=A0=B8=E7=AE=97=E6=97=A5=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../salaryacct/bo/CalculateFormulaVarBO.java | 22 ++++++++++++++----- .../SalaryFormulaReferenceEnum.java | 6 +++-- .../service/impl/RemoteExcelServiceImpl.java | 10 +++++++++ src/com/engine/salary/util/JsonUtil.java | 12 ++++------ .../salary/web/SalaryAcctController.java | 12 +++++----- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/com/engine/salary/entity/salaryacct/bo/CalculateFormulaVarBO.java b/src/com/engine/salary/entity/salaryacct/bo/CalculateFormulaVarBO.java index 425c7715c..6ed15c5a7 100644 --- a/src/com/engine/salary/entity/salaryacct/bo/CalculateFormulaVarBO.java +++ b/src/com/engine/salary/entity/salaryacct/bo/CalculateFormulaVarBO.java @@ -38,6 +38,8 @@ import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; +import static com.engine.salary.util.SalaryDateUtil.DATE_TIME_FORMATTER_PATTERN; + /** * 薪资核算-将数据转换成公式中的变量 *

Copyright: Copyright (c) 2022

@@ -163,7 +165,12 @@ public class CalculateFormulaVarBO { String fieldId = SalarySQLReferenceEnum.SALARY_CYCLE.getValue() + SalaryFormulaFieldConstant.FIELD_ID_SEPARATOR + fieldName; - formulaVarValues.add(new FormulaVarValue().setFieldId(fieldId).setFieldValue(map.getOrDefault(fieldName, StringUtils.EMPTY))); + String fieldValue = map.getOrDefault(fieldName, StringUtils.EMPTY); + //日期值取yyyy-MM-dd + if (StringUtils.isNotBlank(fieldValue) && fieldValue.length() > 10 && SalaryDateUtil.parse(fieldValue, DATE_TIME_FORMATTER_PATTERN) != null) { + fieldValue = fieldValue.substring(0, 10); + } + formulaVarValues.add(new FormulaVarValue().setFieldId(fieldId).setFieldValue(fieldValue)); } } return formulaVarValues; @@ -210,8 +217,6 @@ public class CalculateFormulaVarBO { } - - /** * 处理薪资档案(会涉及调薪计薪规则)+处理核算日期 * @@ -228,7 +233,6 @@ public class CalculateFormulaVarBO { List formulaVarValues = resultMap.computeIfAbsent(key, k -> Lists.newArrayList()); // 将薪资档案的值转换成公式中的变量,填充到返回结果集中 formulaVarValues.addAll(handleSalaryArchiveItemVal(salaryAcctCalculateBO, salaryArchiveTaxAgentDataDTO.getSalaryItemValues(), salarySobAdjustRulePOMap)); - formulaVarValues.addAll(handleSalarySobCycleDTO(salaryAcctCalculateBO)); } } } @@ -511,8 +515,16 @@ public class CalculateFormulaVarBO { String fieldId = SalarySQLReferenceEnum.SALARY_ACCT_EMPLOYEE.getValue() + SalaryFormulaFieldConstant.FIELD_ID_SEPARATOR + fieldName; - return new FormulaVarValue().setFieldId(fieldId).setFieldValue(map.getOrDefault(fieldName, StringUtils.EMPTY)); + String fieldValue = map.getOrDefault(fieldName, StringUtils.EMPTY); + //判断是否是日期,日期值取yyyy-MM-dd + if (StringUtils.isNotBlank(fieldValue) && fieldValue.length() > 10 && SalaryDateUtil.parse(fieldValue, DATE_TIME_FORMATTER_PATTERN) != null) { + fieldValue = fieldValue.substring(0, 10); + } + return new FormulaVarValue().setFieldId(fieldId).setFieldValue(fieldValue); }).collect(Collectors.toList())); + + //将薪资周期转换成公式中的变量,填充到返回结果集中 + formulaVarValues.addAll(handleSalarySobCycleDTO(salaryAcctCalculateBO)); }); } diff --git a/src/com/engine/salary/enums/salaryformula/SalaryFormulaReferenceEnum.java b/src/com/engine/salary/enums/salaryformula/SalaryFormulaReferenceEnum.java index 80d48a5e5..8cf79c880 100644 --- a/src/com/engine/salary/enums/salaryformula/SalaryFormulaReferenceEnum.java +++ b/src/com/engine/salary/enums/salaryformula/SalaryFormulaReferenceEnum.java @@ -24,8 +24,10 @@ public enum SalaryFormulaReferenceEnum implements BaseEnum { ADD_UP_DEDUCTIONS("addUpDeductions", "累计专项附加扣除", 85380), WELFARE("welfare", "社保福利", 87522), OTHER_DEDUCTION("otherDeduction", "其他免税扣除", 93849), - ISSUED("ISSUED", "已发", 0),; - ; + SALARY_ACCT_EMPLOYEE("salaryAcctEmployee", "核算基本信息", 85368), + SALARY_CYCLE("SalaryCycle", "核算日期", 85368), + ISSUED("ISSUED", "已发", 0); + private String value; private String defaultLabel; diff --git a/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java b/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java index 790bf959c..d0c6a69eb 100644 --- a/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java +++ b/src/com/engine/salary/service/impl/RemoteExcelServiceImpl.java @@ -157,6 +157,12 @@ public class RemoteExcelServiceImpl extends Service implements RemoteExcelServic case ATTEND: vars = attendData2FormulaVar(referenceEnum); break; + case SALARY_ACCT_EMPLOYEE: + vars = convert2FormulaVar(SalaryAcctEmployeePO.class, referenceEnum.getValue() + ""); + break; + case SALARY_CYCLE: + vars = convert2FormulaVar(SalarySobCycleDTO.class, referenceEnum.getValue() + ""); + break; default: break; } @@ -236,6 +242,10 @@ public class RemoteExcelServiceImpl extends Service implements RemoteExcelServic welfare2FormulaVar(SalaryFormulaReferenceEnum.WELFARE)); result.put(SalaryFormulaReferenceEnum.ATTEND.getDefaultLabel(), attendData2FormulaVar(SalaryFormulaReferenceEnum.ATTEND)); + result.put(SalarySQLReferenceEnum.SALARY_ACCT_EMPLOYEE.getDefaultLabel(), + convert2FormulaVar(SalaryAcctEmployeePO.class, SalarySQLReferenceEnum.SALARY_ACCT_EMPLOYEE.getValue() + "")); + result.put(SalarySQLReferenceEnum.SALARY_CYCLE.getDefaultLabel(), + convert2FormulaVar(SalarySobCycleDTO.class, SalarySQLReferenceEnum.SALARY_CYCLE.getValue() + "")); return result; } return result; diff --git a/src/com/engine/salary/util/JsonUtil.java b/src/com/engine/salary/util/JsonUtil.java index 081ad3e78..1e6ce59ff 100644 --- a/src/com/engine/salary/util/JsonUtil.java +++ b/src/com/engine/salary/util/JsonUtil.java @@ -65,15 +65,11 @@ public class JsonUtil { if (map != null && map.size() > 0) { Iterator var4 = map.entrySet().iterator(); - while(var4.hasNext()) { - Entry entry = (Entry)var4.next(); + while (var4.hasNext()) { + Entry entry = (Entry) var4.next(); Object obj = entry.getValue(); - - try { - V value = JSON.parseObject(JSON.toJSONString(obj), valueCls); - result.put(entry.getKey(), value); - } catch (Exception var8) { - } + V value = JSON.parseObject(JSON.toJSONString(obj), valueCls); + result.put(entry.getKey(), value); } } diff --git a/src/com/engine/salary/web/SalaryAcctController.java b/src/com/engine/salary/web/SalaryAcctController.java index c1916b13f..1fdd0a7a6 100644 --- a/src/com/engine/salary/web/SalaryAcctController.java +++ b/src/com/engine/salary/web/SalaryAcctController.java @@ -49,28 +49,28 @@ public class SalaryAcctController { private SalaryAcctRecordWrapper salaryAcctRecordWrapper; private SalaryAcctRecordWrapper getSalaryAcctRecordWrapper(User user) { - return (SalaryAcctRecordWrapper) ServiceUtil.getService(SalaryAcctRecordWrapper.class, user); + return ServiceUtil.getService(SalaryAcctRecordWrapper.class, user); } private SalaryAcctEmployeeWrapper getSalaryAcctEmployeeWrapper(User user) { - return (SalaryAcctEmployeeWrapper) ServiceUtil.getService(SalaryAcctEmployeeWrapper.class, user); + return ServiceUtil.getService(SalaryAcctEmployeeWrapper.class, user); } private SalaryAcctResultWrapper getSalaryAcctResultWrapper(User user) { - return (SalaryAcctResultWrapper) ServiceUtil.getService(SalaryAcctResultWrapper.class, user); + return ServiceUtil.getService(SalaryAcctResultWrapper.class, user); } // private SalaryAcctCheckResultWrapper salaryAcctCheckResultWrapper; private SalaryComparisonResultWrapper getSalaryComparisonResultWrapper(User user) { - return (SalaryComparisonResultWrapper) ServiceUtil.getService(SalaryComparisonResultWrapper.class, user); + return ServiceUtil.getService(SalaryComparisonResultWrapper.class, user); } private SalaryAcctExcelWrapper getSalaryAcctExcelWrapper(User user) { - return (SalaryAcctExcelWrapper) ServiceUtil.getService(SalaryAcctExcelWrapper.class, user); + return ServiceUtil.getService(SalaryAcctExcelWrapper.class, user); } private SalaryAcctExcelService getSalaryAcctExcelService(User user) { - return (SalaryAcctExcelService) ServiceUtil.getService(SalaryAcctExcelServiceImpl.class, user); + return ServiceUtil.getService(SalaryAcctExcelServiceImpl.class, user); } // /**********************************薪资核算记录相关 start*********************************/ From 3840f264646a1b4404793f36b34a1ed8b11ee2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=92=B1=E6=B6=9B?= <15850646081@163.com> Date: Wed, 10 May 2023 18:55:23 +0800 Subject: [PATCH 12/12] =?UTF-8?q?=E5=85=AC=E5=BC=8F=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/engine/salary/formlua/core/QlExpress.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/engine/salary/formlua/core/QlExpress.java b/src/com/engine/salary/formlua/core/QlExpress.java index 8086f0000..cf90cab07 100644 --- a/src/com/engine/salary/formlua/core/QlExpress.java +++ b/src/com/engine/salary/formlua/core/QlExpress.java @@ -99,8 +99,11 @@ public class QlExpress { resultObj.put("excute", false); } return resultObj; - } catch (Exception e) { + } catch (Throwable e) { logger.error("err", e); + while (e != null) { + e = e.getCause(); + } String jsonError = e.getMessage(); if (e instanceof PatternSyntaxException) { PatternSyntaxException patternSyntaxException = (PatternSyntaxException) e;