Skip to content

Commit

Permalink
__calcFormula
Browse files Browse the repository at this point in the history
  • Loading branch information
getrebuild committed Dec 6, 2023
1 parent 4e606f3 commit 10ec510
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public static Object eval(String expression, Map<String, Object> env, boolean qu
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;
Expand Down
60 changes: 57 additions & 3 deletions src/main/java/com/rebuild/web/general/ModelExtrasController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
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;
Expand All @@ -21,6 +23,7 @@
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;
Expand All @@ -30,13 +33,15 @@
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;
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;
Expand All @@ -46,7 +51,9 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
* 表单/视图 功能扩展
Expand Down Expand Up @@ -208,11 +215,58 @@ public RespBody evalCalcFormula(@EntityParam Entity entity, HttpServletRequest r
String targetField = getParameterNotNull(request, "field");
if (!entity.containsField(targetField)) return RespBody.error();

JSONObject vars = (JSONObject) ServletUtils.getRequestJson(request);
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);
Object evalVal = AviatorUtils.eval(formula, vars.getInnerMap(), true);

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();
Expand All @@ -228,7 +282,7 @@ public RespBody evalCalcFormula(@EntityParam Entity entity, HttpServletRequest r
}
}

log.warn("Bad eval value : {}", evalVal);
log.warn("Bad eval value `{}` for field : {}", evalVal, easyField.getRawMeta());
return RespBody.ok();
}
}
2 changes: 1 addition & 1 deletion src/main/resources/web/admin/metadata/field-edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
131 changes: 55 additions & 76 deletions src/main/resources/web/assets/js/general/rb-forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -1165,82 +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
const evalUrl = `/app/entity/extras/eval-calc-formula?entity=${this.props.$$$parent.props.entity}&field=${this.props.field}`
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)
}

if ($emptyNum(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) => {
console.log(res)
if (res.data) this.setValue(res.data)
else this.setValue(null)
})
}, 200)

// let formula = calcFormula
// for (let key in calcFormulaValues) {
// formula = formula.replace(new RegExp(`{${key}}`, 'ig'), calcFormulaValues[key] || 0)
// }

// // 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) setTimeout(() => __calcFormula(this), 200)
}

// 移除千分为位
Expand Down Expand Up @@ -1498,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) setTimeout(() => __calcFormula(this), 200)
}
}

class RbFormTime extends RbFormDateTime {
Expand Down Expand Up @@ -3004,3 +2936,50 @@ const __addRecentlyUse = function (id) {
$.post(`/commons/search/recently-add?id=${id}`)
}
}

// 表单计算(视图下无效)
const __calcFormula = function (_this) {
// init
const watchFields = _this.props.calcFormula.match(/\{([a-z0-9]+)}/gi) || []
const calcFormulaValues = {}
const $$$parent = _this.props.$$$parent
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
}
})

const evalUrl = `/app/entity/extras/eval-calc-formula?entity=${$$$parent.props.entity}&field=${_this.props.field}`
// calc
let _timer
$$$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)
})
}, 500)
return true
})
}

0 comments on commit 10ec510

Please sign in to comment.