mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 07:25:54 +08:00
Form calc date 109 (#689)
* feat: eval-calc-formula --------- Co-authored-by: devezhao <zhaofang123@gmail.com>
This commit is contained in:
parent
3f7feaf90b
commit
2690f0791d
|
@ -49,11 +49,19 @@ public class EasyFieldConfigProps {
|
|||
* 日期格式
|
||||
*/
|
||||
public static final String DATE_FORMAT = "dateFormat";
|
||||
/**
|
||||
* 表单公式
|
||||
*/
|
||||
public static final String DATE_CALCFORMULA = NUMBER_CALCFORMULA;
|
||||
|
||||
/**
|
||||
* 日期格式
|
||||
*/
|
||||
public static final String DATETIME_FORMAT = "datetimeFormat";
|
||||
/**
|
||||
* 表单公式
|
||||
*/
|
||||
public static final String DATETIME_CALCFORMULA = NUMBER_CALCFORMULA;
|
||||
|
||||
/**
|
||||
* 时间格式
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.googlecode.aviator.AviatorEvaluator;
|
|||
import com.googlecode.aviator.AviatorEvaluatorInstance;
|
||||
import com.googlecode.aviator.Options;
|
||||
import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
|
||||
import com.googlecode.aviator.lexer.token.OperatorType;
|
||||
import com.googlecode.aviator.runtime.function.system.AssertFunction;
|
||||
import com.googlecode.aviator.runtime.type.AviatorFunction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -20,7 +21,7 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* // https://www.yuque.com/boyan-avfmj/aviatorscript
|
||||
* https://www.yuque.com/boyan-avfmj/aviatorscript
|
||||
*
|
||||
* @author devezhao
|
||||
* @since 2021/4/12
|
||||
|
@ -43,6 +44,9 @@ public class AviatorUtils {
|
|||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
AVIATOR.addOpFunction(OperatorType.ADD, new OverOperatorType.DateAdd());
|
||||
AVIATOR.addOpFunction(OperatorType.SUB, new OverOperatorType.DateSub());
|
||||
|
||||
addCustomFunction(new DateDiffFunction());
|
||||
addCustomFunction(new DateAddFunction());
|
||||
addCustomFunction(new DateSubFunction());
|
||||
|
@ -55,13 +59,21 @@ public class AviatorUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* 表达式计算
|
||||
*
|
||||
* @param expression
|
||||
* @return
|
||||
* @see #eval(String, Map, boolean)
|
||||
*/
|
||||
public static Object evalQuietly(String expression) {
|
||||
return eval(expression, null, true);
|
||||
public static Object eval(String expression) {
|
||||
return eval(expression, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expression
|
||||
* @return
|
||||
* @see #eval(String, Map, boolean)
|
||||
*/
|
||||
public static Object eval(String expression, Map<String, Object> env) {
|
||||
return eval(expression, env, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,13 +86,13 @@ public class AviatorUtils {
|
|||
*/
|
||||
public static Object eval(String expression, Map<String, Object> env, boolean quietly) {
|
||||
try {
|
||||
return AVIATOR.execute(expression, env);
|
||||
return AVIATOR.execute(expression, env == null ? Collections.emptyMap() : env);
|
||||
} catch (Exception ex) {
|
||||
if (ex instanceof AssertFunction.AssertFailed) {
|
||||
throw new AssertFailedException((AssertFunction.AssertFailed) ex);
|
||||
}
|
||||
|
||||
log.error("Bad aviator expression : \n{}\n<< {}", expression, env, ex);
|
||||
log.error("Bad aviator expression : \n>> {}\n>> {}\n>> {}", expression, env, ex.getLocalizedMessage());
|
||||
if (!quietly) throw ex;
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*!
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and/or its owners. All rights reserved.
|
||||
|
||||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
package com.rebuild.core.service.trigger.aviator;
|
||||
|
||||
import cn.devezhao.commons.CalendarUtils;
|
||||
import com.googlecode.aviator.lexer.token.OperatorType;
|
||||
import com.googlecode.aviator.runtime.function.AbstractFunction;
|
||||
import com.googlecode.aviator.runtime.type.AviatorLong;
|
||||
import com.googlecode.aviator.runtime.type.AviatorObject;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 操作符重载
|
||||
*
|
||||
* @author RB
|
||||
* @since 2023/12/6
|
||||
*/
|
||||
public class OverOperatorType {
|
||||
|
||||
private OverOperatorType() {}
|
||||
|
||||
/**
|
||||
* 日期加
|
||||
*/
|
||||
static class DateAdd extends AbstractFunction {
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.ADD.getToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
|
||||
Object $argv1 = arg1.getValue(env);
|
||||
Object $argv2 = arg2.getValue(env);
|
||||
|
||||
if ($argv1 instanceof Date && $argv2 instanceof Number) {
|
||||
return opDate((Date) $argv1, ((Number) $argv2).intValue());
|
||||
} else if ($argv2 instanceof Date && $argv1 instanceof Number) {
|
||||
return opDate((Date) $argv2, ((Number) $argv1).intValue());
|
||||
} else {
|
||||
return arg1.add(arg2, env); // Use default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期减
|
||||
*/
|
||||
static class DateSub extends AbstractFunction {
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.SUB.getToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
|
||||
Object $argv1 = arg1.getValue(env);
|
||||
Object $argv2 = arg2.getValue(env);
|
||||
|
||||
if ($argv1 instanceof Date && $argv2 instanceof Number) {
|
||||
return opDate((Date) $argv1, -((Number) $argv2).intValue());
|
||||
} else if ($argv2 instanceof Date && $argv1 instanceof Number) {
|
||||
return opDate((Date) $argv2, -((Number) $argv1).intValue());
|
||||
} else if ($argv1 instanceof Date && $argv2 instanceof Date) {
|
||||
int diff = CalendarUtils.getDayLeft((Date) $argv1, (Date) $argv2);
|
||||
return AviatorLong.valueOf(diff);
|
||||
} else {
|
||||
return arg1.add(arg2, env); // Use default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AviatorDate opDate(Date date, int num) {
|
||||
Date d = CalendarUtils.addDay(date, num);
|
||||
return new AviatorDate(d);
|
||||
}
|
||||
}
|
|
@ -8,22 +8,32 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
package com.rebuild.web.general;
|
||||
|
||||
import cn.devezhao.bizz.privileges.impl.BizzPermission;
|
||||
import cn.devezhao.commons.CalendarUtils;
|
||||
import cn.devezhao.commons.ObjectUtils;
|
||||
import cn.devezhao.commons.web.ServletUtils;
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONAware;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.api.RespBody;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.configuration.general.AutoFillinManager;
|
||||
import com.rebuild.core.metadata.MetadataHelper;
|
||||
import com.rebuild.core.metadata.easymeta.DisplayType;
|
||||
import com.rebuild.core.metadata.easymeta.EasyDecimal;
|
||||
import com.rebuild.core.metadata.easymeta.EasyEntity;
|
||||
import com.rebuild.core.metadata.easymeta.EasyField;
|
||||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.metadata.impl.EasyFieldConfigProps;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.privileges.bizz.User;
|
||||
import com.rebuild.core.service.general.RepeatedRecordsException;
|
||||
import com.rebuild.core.service.general.transform.RecordTransfomer;
|
||||
import com.rebuild.core.service.trigger.aviator.AviatorUtils;
|
||||
import com.rebuild.core.support.general.ContentWithFieldVars;
|
||||
import com.rebuild.core.support.i18n.I18nUtils;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
|
@ -31,7 +41,9 @@ import com.rebuild.web.BaseController;
|
|||
import com.rebuild.web.EntityParam;
|
||||
import com.rebuild.web.IdParam;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
@ -39,7 +51,9 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 表单/视图 功能扩展
|
||||
|
@ -195,4 +209,80 @@ public class ModelExtrasController extends BaseController {
|
|||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
@PostMapping("eval-calc-formula")
|
||||
public RespBody evalCalcFormula(@EntityParam Entity entity, HttpServletRequest request) {
|
||||
String targetField = getParameterNotNull(request, "field");
|
||||
if (!entity.containsField(targetField)) return RespBody.error();
|
||||
|
||||
JSONObject post = (JSONObject) ServletUtils.getRequestJson(request);
|
||||
Map<String, Object> varsInFormula = post.getInnerMap();
|
||||
for (Object value : varsInFormula.values()) {
|
||||
if (value == null || StringUtils.isBlank(value.toString())) {
|
||||
return RespBody.ok();
|
||||
}
|
||||
}
|
||||
|
||||
EasyField easyField = EasyMetaFactory.valueOf(entity.getField(targetField));
|
||||
String formula = easyField.getExtraAttr(EasyFieldConfigProps.DATE_CALCFORMULA);
|
||||
|
||||
boolean canCalc = true;
|
||||
Set<String> fieldVars = ContentWithFieldVars.matchsVars(formula);
|
||||
for (String field : fieldVars) {
|
||||
if (!entity.containsField(field)) {
|
||||
canCalc = false;
|
||||
break;
|
||||
}
|
||||
|
||||
Object fieldValue = varsInFormula.get(field);
|
||||
if (fieldValue == null) {
|
||||
canCalc = false;
|
||||
break;
|
||||
}
|
||||
|
||||
String fieldValue2 = fieldValue.toString();
|
||||
DisplayType dt = EasyMetaFactory.valueOf(entity.getField(field)).getDisplayType();
|
||||
if (dt == DisplayType.DATE || dt == DisplayType.DATETIME) {
|
||||
fieldValue = CalendarUtils.parse(fieldValue2, CalendarUtils.UTC_DATETIME_FORMAT.substring(0, fieldValue2.length()));
|
||||
} else if (dt == DisplayType.NUMBER || dt == DisplayType.DECIMAL) {
|
||||
fieldValue = EasyDecimal.clearFlaged(fieldValue2);
|
||||
if (StringUtils.isNotBlank((String) fieldValue)) {
|
||||
if (dt == DisplayType.NUMBER) fieldValue = ObjectUtils.toLong(fieldValue);
|
||||
else fieldValue = ObjectUtils.toDouble(fieldValue);
|
||||
} else {
|
||||
fieldValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldValue == null) {
|
||||
canCalc = false;
|
||||
break;
|
||||
}
|
||||
varsInFormula.put(field, fieldValue);
|
||||
}
|
||||
if (!canCalc) return RespBody.ok();
|
||||
|
||||
formula = formula
|
||||
.replace("{", "").replace("}", "")
|
||||
.replace("×", "*").replace("÷", "/");
|
||||
|
||||
Object evalVal = AviatorUtils.eval(formula, varsInFormula, true);
|
||||
if (evalVal == null) return RespBody.ok();
|
||||
|
||||
DisplayType dt = easyField.getDisplayType();
|
||||
if (dt == DisplayType.DATE || dt == DisplayType.DATETIME) {
|
||||
if (evalVal instanceof Date) {
|
||||
evalVal = easyField.wrapValue(evalVal);
|
||||
return RespBody.ok(evalVal);
|
||||
}
|
||||
} else if (dt == DisplayType.NUMBER || dt == DisplayType.DECIMAL) {
|
||||
if (evalVal instanceof Number) {
|
||||
evalVal = easyField.wrapValue(evalVal);
|
||||
return RespBody.ok(evalVal);
|
||||
}
|
||||
}
|
||||
|
||||
log.warn("Bad eval value `{}` for field : {}", evalVal, easyField.getRawMeta());
|
||||
return RespBody.ok();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
</label>
|
||||
<label class="custom-control custom-control-sm custom-radio custom-control-inline mb-0 mr-1">
|
||||
<input class="custom-control-input" type="radio" name="decimalType" value="¥" />
|
||||
<span class="custom-control-label">[[${bundle.L('货币')}]]</span>
|
||||
<span class="custom-control-label">[[${bundle.L('符号')}]]</span>
|
||||
</label>
|
||||
<span>
|
||||
<select class="underline-sm J_decimalTypeFlag">
|
||||
|
@ -359,14 +359,17 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div th:if="${fieldType == 'DECIMAL' or fieldType == 'NUMBER'}" class="form-group row J_for-DECIMAL J_for-NUMBER">
|
||||
<div
|
||||
th:if="${fieldType == 'DECIMAL' or fieldType == 'NUMBER' or fieldType == 'DATE' or fieldType == 'DATETIME'}"
|
||||
class="form-group row J_for-DECIMAL J_for-NUMBER J_for-DATE J_for-DATETIME"
|
||||
>
|
||||
<label class="col-md-12 col-xl-3 col-lg-4 col-form-label text-lg-right">[[${bundle.L('表单计算公式')}]]</label>
|
||||
<div class="col-md-12 col-xl-6 col-lg-8">
|
||||
<input type="hidden" class="form-control" id="calcFormula" />
|
||||
<div class="form-control-plaintext formula" id="calcFormula2" th:_title="${bundle.L('无')}">[[${calcFormula ?: calcFormula}]]</div>
|
||||
<p
|
||||
class="form-text"
|
||||
th:utext="${bundle.L('本公式仅做前端计算,如公式中所用字段未布局/未显示,则无法进行计算。你也可以通过 [触发器 (字段更新)](/admin/robot/triggers) 实现更强大的计算规则')}"
|
||||
th:utext="${bundle.L('如公式中所用字段未布局/未显示,则无法进行计算。本公式适用前端简单计算,你可以通过 [触发器 (字段更新)](/admin/robot/triggers) 实现更强大的计算规则')}"
|
||||
></p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1165,80 +1165,8 @@ class RbFormNumber extends RbFormText {
|
|||
|
||||
componentDidMount() {
|
||||
super.componentDidMount()
|
||||
|
||||
// 表单计算(视图下无效)
|
||||
if (this.props.calcFormula && !this.props.onView) {
|
||||
const calcFormula = this.props.calcFormula.replace(new RegExp('×', 'ig'), '*').replace(new RegExp('÷', 'ig'), '/')
|
||||
const fixed = this.props.decimalFormat ? (this.props.decimalFormat.split('.')[1] || '').length : 0
|
||||
|
||||
// 等待字段初始化完毕
|
||||
setTimeout(() => {
|
||||
const calcFormulaValues = {}
|
||||
const watchFields = calcFormula.match(/\{([a-z0-9]+)}/gi) || []
|
||||
|
||||
watchFields.forEach((item) => {
|
||||
const name = item.substr(1, item.length - 2)
|
||||
const fieldComp = this.props.$$$parent.refs[`fieldcomp-${name}`]
|
||||
if (fieldComp && !$emptyNum(fieldComp.state.value)) {
|
||||
calcFormulaValues[name] = this._removeComma(fieldComp.state.value)
|
||||
}
|
||||
})
|
||||
|
||||
// 表单计算
|
||||
let _timer
|
||||
this.props.$$$parent.onFieldValueChange((s) => {
|
||||
if (!watchFields.includes(`{${s.name}}`)) {
|
||||
if (rb.env === 'dev') console.log('onFieldValueChange ignored :', s, this.props.field)
|
||||
return false
|
||||
} else if (rb.env === 'dev') {
|
||||
console.log('onFieldValueChange for calcFormula :', s, this.props.field)
|
||||
}
|
||||
|
||||
// // fix: 3.2 字段相互使用导致死循环
|
||||
// this.__fixUpdateDepth = (this.__fixUpdateDepth || 0) + 1
|
||||
// if (this.__fixUpdateDepth > 9) {
|
||||
// console.log(`Maximum update depth exceeded : ${this.props.field}=${this.props.calcFormula}`)
|
||||
// setTimeout(() => (this.__fixUpdateDepth = 0), 100)
|
||||
// return false
|
||||
// }
|
||||
|
||||
if ($emptyNum(s.value)) {
|
||||
delete calcFormulaValues[s.name]
|
||||
} else {
|
||||
calcFormulaValues[s.name] = this._removeComma(s.value)
|
||||
}
|
||||
|
||||
let formula = calcFormula
|
||||
for (let key in calcFormulaValues) {
|
||||
formula = formula.replace(new RegExp(`{${key}}`, 'ig'), calcFormulaValues[key] || 0)
|
||||
}
|
||||
|
||||
if (_timer) {
|
||||
clearTimeout(_timer)
|
||||
_timer = null
|
||||
}
|
||||
|
||||
// v34 延迟执行
|
||||
_timer = setTimeout(() => {
|
||||
// 还有变量无值
|
||||
if (formula.includes('{')) {
|
||||
this.setValue(null)
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
let calcv = null
|
||||
eval(`calcv = ${formula}`)
|
||||
if (!isNaN(calcv)) this.setValue(calcv.toFixed(fixed))
|
||||
} catch (err) {
|
||||
if (rb.env === 'dev') console.log(err)
|
||||
}
|
||||
return true
|
||||
}, 200)
|
||||
// _timer end
|
||||
})
|
||||
}, 200) // init
|
||||
}
|
||||
// 表单计算
|
||||
if (this.props.calcFormula && !this.props.onView) __calcFormula(this)
|
||||
}
|
||||
|
||||
// 移除千分为位
|
||||
|
@ -1496,6 +1424,12 @@ class RbFormDateTime extends RbFormElement {
|
|||
wt = $(this._fieldValue).offset().top
|
||||
return wt + 280 < wh ? 'bottom-right' : 'top-right'
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
super.componentDidMount()
|
||||
// 表单计算
|
||||
if (this.props.calcFormula && !this.props.onView) __calcFormula(this)
|
||||
}
|
||||
}
|
||||
|
||||
class RbFormTime extends RbFormDateTime {
|
||||
|
@ -3002,3 +2936,59 @@ const __addRecentlyUse = function (id) {
|
|||
$.post(`/commons/search/recently-add?id=${id}`)
|
||||
}
|
||||
}
|
||||
|
||||
// 表单计算(视图下无效)
|
||||
const __calcFormula = function (_this) {
|
||||
const watchFields = _this.props.calcFormula.match(/\{([a-z0-9]+)}/gi) || []
|
||||
const $$$parent = _this.props.$$$parent
|
||||
|
||||
const evalUrl = `/app/entity/extras/eval-calc-formula?entity=${$$$parent.props.entity}&field=${_this.props.field}`
|
||||
setTimeout(() => {
|
||||
const calcFormulaValues = {}
|
||||
let _timer
|
||||
|
||||
// init
|
||||
watchFields.forEach((item) => {
|
||||
const name = item.substr(1, item.length - 2)
|
||||
const fieldComp = $$$parent.refs[`fieldcomp-${name}`]
|
||||
if (fieldComp && !$empty(fieldComp.state.value)) {
|
||||
calcFormulaValues[name] = fieldComp.state.value
|
||||
}
|
||||
})
|
||||
|
||||
// onchange
|
||||
$$$parent.onFieldValueChange((s) => {
|
||||
if (!watchFields.includes(`{${s.name}}`)) {
|
||||
if (rb.env === 'dev') console.log('onFieldValueChange ignored :', s, _this.props.field)
|
||||
return false
|
||||
} else if (rb.env === 'dev') {
|
||||
console.log('onFieldValueChange for calcFormula :', s, _this.props.field)
|
||||
}
|
||||
|
||||
if ($empty(s.value)) delete calcFormulaValues[s.name]
|
||||
else calcFormulaValues[s.name] = s.value
|
||||
|
||||
if (_timer) {
|
||||
clearTimeout(_timer)
|
||||
_timer = null
|
||||
}
|
||||
|
||||
// v36
|
||||
_timer = setTimeout(() => {
|
||||
$.post(evalUrl, JSON.stringify(calcFormulaValues), (res) => {
|
||||
if (res.data) _this.setValue(res.data)
|
||||
else _this.setValue(null)
|
||||
})
|
||||
}, 400)
|
||||
return true
|
||||
})
|
||||
|
||||
// 新建时
|
||||
if (_this._isNew) {
|
||||
$.post(evalUrl, JSON.stringify(calcFormulaValues), (res) => {
|
||||
if (res.data) _this.setValue(res.data)
|
||||
else _this.setValue(null)
|
||||
})
|
||||
}
|
||||
}, 400) // delay for init
|
||||
}
|
||||
|
|
|
@ -232,6 +232,7 @@ $(document).ready(function () {
|
|||
} else if (dt === 'SERIES') {
|
||||
_handleSeries()
|
||||
} else if (dt === 'DATE' || dt === 'DATETIME' || dt === 'TIME') {
|
||||
if (dt === 'DATE' || dt === 'DATETIME') _handleCalcFormula(extConfig.calcFormula)
|
||||
_handleDatetime(dt)
|
||||
} else if (dt === 'FILE' || dt === 'IMAGE') {
|
||||
_handleFile(extConfig.uploadNumber)
|
||||
|
@ -247,8 +248,7 @@ $(document).ready(function () {
|
|||
} else if (dt === 'BARCODE') {
|
||||
$('.J_fieldAttrs input').attr('disabled', true)
|
||||
} else if (dt === 'NUMBER' || dt === 'DECIMAL') {
|
||||
_handleNumber(extConfig.calcFormula)
|
||||
|
||||
_handleCalcFormula(extConfig.calcFormula)
|
||||
if (dt === 'DECIMAL') {
|
||||
if (!extConfig.decimalType || extConfig.decimalType === 0 || extConfig.decimalType === '0' || extConfig.decimalType === '%') {
|
||||
// 数字、百分比
|
||||
|
@ -580,7 +580,7 @@ const _loadRefsLabel = function ($dv, $dvClear) {
|
|||
}
|
||||
|
||||
let FIELDS_CACHE
|
||||
const _handleNumber = function (calcFormula) {
|
||||
const _handleCalcFormula = function (formula) {
|
||||
const $el = $('#calcFormula2')
|
||||
function _call(s) {
|
||||
$('#calcFormula').val(s || '')
|
||||
|
@ -591,13 +591,13 @@ const _handleNumber = function (calcFormula) {
|
|||
$.get(`/commons/metadata/fields?entity=${wpc.entityName}`, (res) => {
|
||||
const fs = []
|
||||
res.data.forEach((item) => {
|
||||
if ((item.type === 'NUMBER' || item.type === 'DECIMAL') && item.name !== wpc.fieldName) {
|
||||
if (['NUMBER', 'DECIMAL', 'DATE', 'DATETIME'].includes(item.type) && !['approvalLastTime', 'modifiedOn'].includes(item.name) && item.name !== wpc.fieldName) {
|
||||
fs.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
FIELDS_CACHE = fs
|
||||
if (calcFormula) _call(calcFormula)
|
||||
if (formula) _call(formula)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,13 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
package com.rebuild.core.service.trigger.aviator;
|
||||
|
||||
import cn.devezhao.commons.CalendarUtils;
|
||||
import com.googlecode.aviator.exception.ExpressionRuntimeException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -22,7 +24,7 @@ class AviatorUtilsTest {
|
|||
|
||||
@Test
|
||||
void eval() {
|
||||
System.out.println(AviatorUtils.evalQuietly("123*123"));
|
||||
System.out.println(AviatorUtils.eval("123*123"));
|
||||
|
||||
System.out.println(AviatorUtils.eval(
|
||||
"abc12_.abc+123", Collections.singletonMap("abc12_.abc", 100), true));
|
||||
|
@ -36,30 +38,30 @@ class AviatorUtilsTest {
|
|||
|
||||
@Test
|
||||
void func() {
|
||||
AviatorUtils.evalQuietly("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'D'))");
|
||||
AviatorUtils.evalQuietly("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'M'))");
|
||||
AviatorUtils.evalQuietly("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-09 23:59:59', 'Y'))");
|
||||
AviatorUtils.eval("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'D'))");
|
||||
AviatorUtils.eval("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-05 23:59:59', 'M'))");
|
||||
AviatorUtils.eval("p(DATEDIFF('2021-03-04 00:00:00', '2022-03-09 23:59:59', 'Y'))");
|
||||
|
||||
AviatorUtils.evalQuietly("p(DATEADD('2021-01-01 18:17:00', '2H'))");
|
||||
AviatorUtils.eval("p(DATEADD('2021-01-01 18:17:00', '2H'))");
|
||||
|
||||
AviatorUtils.evalQuietly("p(DATESUB('2021-01-01 18:17:00', '1'))");
|
||||
AviatorUtils.eval("p(DATESUB('2021-01-01 18:17:00', '1'))");
|
||||
}
|
||||
|
||||
@Test
|
||||
void funcComplex() {
|
||||
AviatorUtils.evalQuietly("p(100 + DATEDIFF('2021-01-01 18:17:00', '2021-01-01 16:17:00', 'H'))");
|
||||
AviatorUtils.evalQuietly("p(DATEADD(DATEADD('2021-01-01 18:17:00', '2H'), '1D'))");
|
||||
AviatorUtils.eval("p(100 + DATEDIFF('2021-01-01 18:17:00', '2021-01-01 16:17:00', 'H'))");
|
||||
AviatorUtils.eval("p(DATEADD(DATEADD('2021-01-01 18:17:00', '2H'), '1D'))");
|
||||
}
|
||||
|
||||
@Test
|
||||
void funcRequestFunction() {
|
||||
AviatorUtils.evalQuietly("p(REQUEST('https://www.baidu.com/'))");
|
||||
AviatorUtils.evalQuietly("p(REQUEST('https://www.google.com/', 'imdefault'))");
|
||||
AviatorUtils.eval("p(REQUEST('https://www.baidu.com/'))");
|
||||
AviatorUtils.eval("p(REQUEST('https://www.google.com/', 'imdefault'))");
|
||||
}
|
||||
|
||||
@Test
|
||||
void funcLocationDistanceFunction() {
|
||||
AviatorUtils.evalQuietly("p(LOCATIONDISTANCE('123.456789,123.456789', '地址$$$$123.456789,123.456789'))");
|
||||
AviatorUtils.eval("p(LOCATIONDISTANCE('123.456789,123.456789', '地址$$$$123.456789,123.456789'))");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -75,6 +77,19 @@ class AviatorUtilsTest {
|
|||
|
||||
@Test
|
||||
void testJava() {
|
||||
AviatorUtils.evalQuietly("p(StringUtils.upperCase('abcd'));");
|
||||
AviatorUtils.eval("p(StringUtils.upperCase('abcd'));");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDateOp() {
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("date1", CalendarUtils.now());
|
||||
AviatorUtils.eval("p(date1 + 8)", env, true);
|
||||
AviatorUtils.eval("p(date1 - 8)", env, true);
|
||||
AviatorUtils.eval("p(date1 - date1)", env, true);
|
||||
|
||||
// BAD
|
||||
Assertions.assertThrows(ExpressionRuntimeException.class,
|
||||
() -> AviatorUtils.eval("date1 + date1", env, false));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue