From 8f8b01bb7bd50556914ecffd4e1e01b55153f27a Mon Sep 17 00:00:00 2001
From: RB <42044143+getrebuild@users.noreply.github.com>
Date: Sun, 27 Apr 2025 21:53:03 +0800
Subject: [PATCH 1/7] Update @rbv
---
@rbv | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/@rbv b/@rbv
index 07ba14147..0626bc08d 160000
--- a/@rbv
+++ b/@rbv
@@ -1 +1 @@
-Subproject commit 07ba14147145a9fb9646563605427f680ac82d13
+Subproject commit 0626bc08d5e04b24764baefff8317d60f172ff25
From 9fdf863ce358a539d172486ce86089f67030cebb Mon Sep 17 00:00:00 2001
From: RB <42044143+getrebuild@users.noreply.github.com>
Date: Sun, 27 Apr 2025 21:53:39 +0800
Subject: [PATCH 2/7] 4.0.4
---
pom.xml | 2 +-
src/main/java/com/rebuild/core/Application.java | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pom.xml b/pom.xml
index 9b9525e24..59c99f3be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
com.rebuild
rebuild
- 4.0.3
+ 4.0.4
rebuild
Building your business-systems freely!
https://getrebuild.com/
diff --git a/src/main/java/com/rebuild/core/Application.java b/src/main/java/com/rebuild/core/Application.java
index 193fc7666..f4ad60bb1 100644
--- a/src/main/java/com/rebuild/core/Application.java
+++ b/src/main/java/com/rebuild/core/Application.java
@@ -75,11 +75,11 @@ public class Application implements ApplicationListener
/**
* Rebuild Version
*/
- public static final String VER = "4.0.3";
+ public static final String VER = "4.0.4";
/**
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
*/
- public static final int BUILD = 4000309;
+ public static final int BUILD = 4000410;
static {
// Driver for DB
From 312ee3a2d7fb77d0260e56ac9ce5221d988a320c Mon Sep 17 00:00:00 2001
From: RB <42044143+getrebuild@users.noreply.github.com>
Date: Mon, 28 Apr 2025 21:01:48 +0800
Subject: [PATCH 3/7] =?UTF-8?q?be:=20=E8=87=AA=E5=8A=A8=E7=BC=96=E5=8F=B7?=
=?UTF-8?q?=E8=A7=84=E5=88=99=E6=97=A0=E6=95=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../general/series/SeriesGenerator.java | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java b/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java
index f16a75de9..c3802cb5f 100644
--- a/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java
+++ b/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java
@@ -10,6 +10,7 @@
import cn.devezhao.persist4j.Field;
import cn.devezhao.persist4j.Record;
import com.alibaba.fastjson.JSONObject;
+import com.rebuild.core.DefinedException;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyField;
import org.apache.commons.lang.StringUtils;
@@ -67,15 +68,20 @@ public String generate(Record record) {
seriesFormat = DisplayType.SERIES.getDefaultFormat();
}
- List vars = explainVars(seriesFormat, record);
- for (SeriesVar var : vars) {
- seriesFormat = seriesFormat.replace("{" + var.getSymbols() + "}", var.generate());
- }
+ try {
+ List vars = explainVars(seriesFormat, record);
+ for (SeriesVar var : vars) {
+ seriesFormat = seriesFormat.replace("{" + var.getSymbols() + "}", var.generate());
+ }
+
+ if (seriesFormat.contains(CHECKSUM)) {
+ seriesFormat = seriesFormat.replace(CHECKSUM, String.valueOf(mod10(seriesFormat)));
+ }
+ return seriesFormat;
- if (seriesFormat.contains(CHECKSUM)) {
- seriesFormat = seriesFormat.replace(CHECKSUM, String.valueOf(mod10(seriesFormat)));
+ } catch (Exception ex) {
+ throw new DefinedException("自动编号规则无效:" + seriesFormat);
}
- return seriesFormat;
}
private static final Pattern VAR_PATTERN = Pattern.compile("\\{(@?[\\w.]+)}");
From 8a76aaa7bba9b039b3f06edc7816b80f217cc23f Mon Sep 17 00:00:00 2001
From: RB <42044143+getrebuild@users.noreply.github.com>
Date: Tue, 29 Apr 2025 17:57:31 +0800
Subject: [PATCH 4/7] feat:targetRecordId404
---
.../service/trigger/impl/FieldWriteback.java | 108 +++++++++++++-----
.../trigger/impl/FieldWritebackRefresh.java | 2 +-
2 files changed, 79 insertions(+), 31 deletions(-)
diff --git a/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java b/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java
index 361947f1d..d44488226 100644
--- a/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java
+++ b/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java
@@ -10,6 +10,7 @@
import cn.devezhao.bizz.privileges.impl.BizzPermission;
import cn.devezhao.commons.CalendarUtils;
import cn.devezhao.commons.ObjectUtils;
+import cn.devezhao.persist4j.Entity;
import cn.devezhao.persist4j.Field;
import cn.devezhao.persist4j.Record;
import cn.devezhao.persist4j.dialect.FieldType;
@@ -86,9 +87,11 @@ public class FieldWriteback extends FieldAggregation {
private static final String DATE_EXPR = "#";
private static final String CODE_PREFIX = "{{{{"; // ends with }}}}
+ private static final String SOURCE_FIELD_VAR_PREFIX = "$";
protected Set targetRecordIds;
protected Record targetRecordData;
+ private boolean targetRecordDataHasSourceFieldVar;
public FieldWriteback(ActionContext context) {
super(context, Boolean.TRUE);
@@ -168,7 +171,12 @@ private Object execute38(OperatingContext operatingContext) throws TriggerExcept
continue;
}
- Record targetRecord = targetRecordData.clone();
+ Record targetRecord;
+ if (targetRecordDataHasSourceFieldVar) {
+ targetRecord = buildTargetRecordData(operatingContext, targetRecordId, false);
+ } else {
+ targetRecord = targetRecordData.clone();
+ }
targetRecord.setID(targetEntity.getPrimaryField().getName(), targetRecordId);
targetRecord.setDate(EntityHelper.ModifiedOn, CalendarUtils.now());
targetRecord.setID(EntityHelper.ModifiedBy, UserService.SYSTEM_USER);
@@ -306,7 +314,7 @@ else if (isOne2One) {
if (targetRecordIds.isEmpty()) {
log.debug("Target record(s) are empty.");
} else {
- targetRecordData = buildTargetRecordData(operatingContext, false);
+ targetRecordData = buildTargetRecordData(operatingContext, null, false);
}
}
@@ -314,10 +322,11 @@ else if (isOne2One) {
* 构建目标记录
*
* @param operatingContext
+ * @param targetRecordId404
* @param fromRefresh
* @return
*/
- protected Record buildTargetRecordData(OperatingContext operatingContext, Boolean fromRefresh) {
+ protected Record buildTargetRecordData(OperatingContext operatingContext, ID targetRecordId404, boolean fromRefresh) {
// v3.3 源字段为空时置空目标字段
final boolean clearFields = ((JSONObject) actionContext.getActionContent()).getBooleanValue("clearFields");
final boolean forceVNull = fromRefresh || (clearFields && operatingContext.getAction() == InternalPermission.DELETE_BEFORE);
@@ -329,6 +338,9 @@ protected Record buildTargetRecordData(OperatingContext operatingContext, Boolea
final Set fieldVarsN2NPath = new HashSet<>();
// 变量值
Record useSourceData = null;
+ // v4.0.4 使用目标记录数据参与运算
+ Record useTargetData = null;
+ final Set fieldVarsInTarget = new HashSet<>();
if (!forceVNull) {
for (Object o : items) {
@@ -348,7 +360,13 @@ protected Record buildTargetRecordData(OperatingContext operatingContext, Boolea
} else {
Set matchsVars = ContentWithFieldVars.matchsVars(sourceField);
for (String field : matchsVars) {
- if (N2NReferenceSupport.isN2NMixPath(field, sourceEntity)) {
+ if (field.startsWith(SOURCE_FIELD_VAR_PREFIX)) {
+ field = field.substring(1);
+ if (MetadataHelper.getLastJoinField(targetEntity, field) == null) {
+ throw new MissingMetaExcetion(field, targetEntity.getName());
+ }
+ fieldVarsInTarget.add(SOURCE_FIELD_VAR_PREFIX + field);
+ } else if (N2NReferenceSupport.isN2NMixPath(field, sourceEntity)) {
fieldVarsN2NPath.add(field);
} else {
if (MetadataHelper.getLastJoinField(sourceEntity, field) == null) {
@@ -377,6 +395,17 @@ protected Record buildTargetRecordData(OperatingContext operatingContext, Boolea
useSourceData.setObjectValue(field, n2nVal);
}
}
+ if (!fieldVarsInTarget.isEmpty()) {
+ this.targetRecordDataHasSourceFieldVar = true;
+ if (targetRecordId404 != null) {
+ String sql = MessageFormat.format("select {0},{1} from {2} where {1} = ?",
+ StringUtils.join(fieldVarsInTarget, ","),
+ targetEntity.getPrimaryField().getName(),
+ targetEntity.getName());
+ sql = sql.replace(SOURCE_FIELD_VAR_PREFIX, ""); // Remove `^`
+ useTargetData = Application.createQueryNoFilter(sql).setParameter(1, targetRecordId404).record();
+ }
+ }
}
for (Object o : items) {
@@ -452,7 +481,9 @@ else if ("FORMULA".equalsIgnoreCase(updateMode)) {
Map envMap = new HashMap<>();
- for (String fieldName : fieldVars) {
+ Set fieldVarsMix = new HashSet<>(fieldVars);
+ fieldVarsMix.addAll(fieldVarsInTarget);
+ for (String fieldName : fieldVarsMix) {
String replace = "{" + fieldName + "}";
String replaceWhitQuote = "\"" + replace + "\"";
String replaceWhitQuoteSingle = "'" + replace + "'";
@@ -470,54 +501,71 @@ else if ("FORMULA".equalsIgnoreCase(updateMode)) {
continue;
}
- Object value = useSourceData.getObjectValue(fieldName);
+ Entity useEntity;
+ Field useVarField;
+ Object useValue = null;
+ if (fieldName.startsWith(SOURCE_FIELD_VAR_PREFIX)) {
+ String fieldName2 = fieldName.substring(1);
+ if (useTargetData == null) log.debug("No `useTargetData` for var : {}", fieldName);
+ else useValue = useTargetData.getObjectValue(fieldName2);
+ useEntity = this.targetEntity;
+ useVarField = MetadataHelper.getLastJoinField(useEntity, fieldName2);
+ } else {
+ useValue = useSourceData.getObjectValue(fieldName);
+ useEntity = this.sourceEntity;
+ useVarField = MetadataHelper.getLastJoinField(useEntity, fieldName);
+ }
- // fix: 3.5.4
- Field varField = MetadataHelper.getLastJoinField(sourceEntity, fieldName);
- EasyField easyVarField = varField == null ? null : EasyMetaFactory.valueOf(varField);
- boolean isMultiField = easyVarField != null && (easyVarField.getDisplayType() == DisplayType.MULTISELECT
- || easyVarField.getDisplayType() == DisplayType.TAG || easyVarField.getDisplayType() == DisplayType.N2NREFERENCE);
- // fix: 3.8
- boolean isStateField = easyVarField != null && easyVarField.getDisplayType() == DisplayType.STATE;
+ EasyField easyVarField = null;
+ boolean isMultiField = false;
+ boolean isStateField = false;
+ boolean isNumberField = false;
+ if (useVarField != null) {
+ easyVarField = EasyMetaFactory.valueOf(useVarField);
+ isMultiField = easyVarField.getDisplayType() == DisplayType.MULTISELECT
+ || easyVarField.getDisplayType() == DisplayType.TAG
+ || easyVarField.getDisplayType() == DisplayType.N2NREFERENCE;
+ isStateField = easyVarField.getDisplayType() == DisplayType.STATE;
+ isNumberField = useVarField.getType() == FieldType.LONG || useVarField.getType() == FieldType.DECIMAL;
+ }
if (isStateField) {
- value = value == null ? "" : StateHelper.getLabel(varField, (Integer) value);
- } else if (value instanceof Date) {
- value = CalendarUtils.getUTCDateTimeFormat().format(value);
- } else if (value == null) {
+ useValue = useValue == null ? "" : StateHelper.getLabel(useVarField, (Integer) useValue);
+ } else if (useValue instanceof Date) {
+ useValue = CalendarUtils.getUTCDateTimeFormat().format(useValue);
+ } else if (useValue == null) {
// N2N 保持 `NULL`
- Field isN2NField = sourceEntity.containsField(fieldName) ? sourceEntity.getField(fieldName) : null;
+ Field isN2NField = useEntity.containsField(fieldName) ? useEntity.getField(fieldName) : null;
// 数字字段置 `0`
- if (varField != null
- && (varField.getType() == FieldType.LONG || varField.getType() == FieldType.DECIMAL)) {
- value = 0L;
+ if (isNumberField) {
+ useValue = 0L;
} else if (fieldVarsN2NPath.contains(fieldName)
|| (isN2NField != null && isN2NField.getType() == FieldType.REFERENCE_LIST)) {
- // Keep NULL
+ log.debug("Keep NULL for N2N");
} else {
- value = StringUtils.EMPTY;
+ useValue = StringUtils.EMPTY;
}
} else if (isMultiField) {
// v3.5.5: 目标值为多引用时保持 `ID[]`
if (easyVarField.getDisplayType() == DisplayType.N2NREFERENCE
&& targetFieldEasy.getDisplayType() == DisplayType.N2NREFERENCE) {
- value = StringUtils.join((ID[]) value, MultiValue.MV_SPLIT);
+ useValue = StringUtils.join((ID[]) useValue, MultiValue.MV_SPLIT);
} else {
// force `TEXT`
EasyField fakeTextField = EasyMetaFactory.valueOf(MetadataHelper.getField("User", "fullName"));
- value = easyVarField.convertCompatibleValue(value, fakeTextField);
+ useValue = easyVarField.convertCompatibleValue(useValue, fakeTextField);
}
- } else if (value instanceof ID || forceUseQuote) {
- value = value.toString();
+ } else if (useValue instanceof ID || forceUseQuote) {
+ useValue = useValue.toString();
}
// v3.6.3 整数/小数强制使用 BigDecimal 高精度
- if (value instanceof Long) value = BigDecimal.valueOf((Long) value);
+ if (useValue instanceof Long) useValue = BigDecimal.valueOf((Long) useValue);
- envMap.put(fieldName, value);
+ envMap.put(fieldName, useValue);
}
- Object newValue = AviatorUtils.eval(clearFormula, envMap, Boolean.FALSE);
+ Object newValue = AviatorUtils.eval(clearFormula, envMap, false);
if (newValue != null) {
DisplayType targetType = targetFieldEasy.getDisplayType();
diff --git a/src/main/java/com/rebuild/core/service/trigger/impl/FieldWritebackRefresh.java b/src/main/java/com/rebuild/core/service/trigger/impl/FieldWritebackRefresh.java
index 6869e2e0a..b7ccefe9d 100644
--- a/src/main/java/com/rebuild/core/service/trigger/impl/FieldWritebackRefresh.java
+++ b/src/main/java/com/rebuild/core/service/trigger/impl/FieldWritebackRefresh.java
@@ -59,7 +59,7 @@ public void refresh() {
ID fakeSourceId = EntityHelper.newUnsavedId(fa.sourceEntity.getEntityCode());
Record fakeSourceRecord = EntityHelper.forUpdate(fakeSourceId, triggerUser, false);
OperatingContext oCtx = OperatingContext.create(triggerUser, BizzPermission.NONE, fakeSourceRecord, fakeSourceRecord);
- fa.targetRecordData = fa.buildTargetRecordData(oCtx, true);
+ fa.targetRecordData = fa.buildTargetRecordData(oCtx, null, true);
try {
fa.execute(oCtx);
From c7cd10fde8c6b7edaba28de1ebf03bc2ddc88235 Mon Sep 17 00:00:00 2001
From: RB <42044143+getrebuild@users.noreply.github.com>
Date: Tue, 29 Apr 2025 20:46:11 +0800
Subject: [PATCH 5/7] Update SeriesGenerator.java
---
.../rebuild/core/service/general/series/SeriesGenerator.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java b/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java
index c3802cb5f..74eda13e1 100644
--- a/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java
+++ b/src/main/java/com/rebuild/core/service/general/series/SeriesGenerator.java
@@ -13,6 +13,7 @@
import com.rebuild.core.DefinedException;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyField;
+import com.rebuild.core.support.i18n.Language;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
@@ -80,7 +81,7 @@ public String generate(Record record) {
return seriesFormat;
} catch (Exception ex) {
- throw new DefinedException("自动编号规则无效:" + seriesFormat);
+ throw new DefinedException(Language.L("自动编号规则无效") + "(" + seriesFormat + ")");
}
}
From 89873e12e4594179d6fab944d9069a3bff27d2c4 Mon Sep 17 00:00:00 2001
From: RB <42044143+getrebuild@users.noreply.github.com>
Date: Tue, 29 Apr 2025 20:51:29 +0800
Subject: [PATCH 6/7] BE
---
.../core/service/trigger/impl/FieldWriteback.java | 10 ++++++----
.../core/support/general/ContentWithFieldVars.java | 2 +-
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java b/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java
index d44488226..9c7bd9d6a 100644
--- a/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java
+++ b/src/main/java/com/rebuild/core/service/trigger/impl/FieldWriteback.java
@@ -87,11 +87,11 @@ public class FieldWriteback extends FieldAggregation {
private static final String DATE_EXPR = "#";
private static final String CODE_PREFIX = "{{{{"; // ends with }}}}
- private static final String SOURCE_FIELD_VAR_PREFIX = "$";
+ private static final String SOURCE_FIELD_VAR_PREFIX = "^";
protected Set targetRecordIds;
protected Record targetRecordData;
- private boolean targetRecordDataHasSourceFieldVar;
+ private boolean targetRecordDataHasSourceFieldVars;
public FieldWriteback(ActionContext context) {
super(context, Boolean.TRUE);
@@ -172,7 +172,7 @@ private Object execute38(OperatingContext operatingContext) throws TriggerExcept
}
Record targetRecord;
- if (targetRecordDataHasSourceFieldVar) {
+ if (targetRecordDataHasSourceFieldVars) {
targetRecord = buildTargetRecordData(operatingContext, targetRecordId, false);
} else {
targetRecord = targetRecordData.clone();
@@ -396,7 +396,7 @@ protected Record buildTargetRecordData(OperatingContext operatingContext, ID tar
}
}
if (!fieldVarsInTarget.isEmpty()) {
- this.targetRecordDataHasSourceFieldVar = true;
+ this.targetRecordDataHasSourceFieldVars = true;
if (targetRecordId404 != null) {
String sql = MessageFormat.format("select {0},{1} from {2} where {1} = ?",
StringUtils.join(fieldVarsInTarget, ","),
@@ -562,9 +562,11 @@ else if ("FORMULA".equalsIgnoreCase(updateMode)) {
// v3.6.3 整数/小数强制使用 BigDecimal 高精度
if (useValue instanceof Long) useValue = BigDecimal.valueOf((Long) useValue);
+ fieldName = fieldName.replace(SOURCE_FIELD_VAR_PREFIX, "_");
envMap.put(fieldName, useValue);
}
+ clearFormula = clearFormula.replace(SOURCE_FIELD_VAR_PREFIX, "_");
Object newValue = AviatorUtils.eval(clearFormula, envMap, false);
if (newValue != null) {
diff --git a/src/main/java/com/rebuild/core/support/general/ContentWithFieldVars.java b/src/main/java/com/rebuild/core/support/general/ContentWithFieldVars.java
index 668d7d0ec..9ae28d645 100644
--- a/src/main/java/com/rebuild/core/support/general/ContentWithFieldVars.java
+++ b/src/main/java/com/rebuild/core/support/general/ContentWithFieldVars.java
@@ -42,7 +42,7 @@ public class ContentWithFieldVars {
/**
* 通过 `{}` 包裹的变量或字段
*/
- public static final Pattern PATT_VAR = Pattern.compile("\\{([0-9a-zA-Z._$]{3,})}");
+ public static final Pattern PATT_VAR = Pattern.compile("\\{(\\^?[0-9a-zA-Z._$]{3,})}");
/**
* 替换文本中的字段变量
From 4efc9f5c05de2352462cb3909127767a4a9861fd Mon Sep 17 00:00:00 2001
From: RB <42044143+getrebuild@users.noreply.github.com>
Date: Wed, 7 May 2025 21:42:28 +0800
Subject: [PATCH 7/7] =?UTF-8?q?fix:=E8=A1=A8=E5=8D=95=E5=9B=9E=E5=A1=AB?=
=?UTF-8?q?=E6=AD=BB=E5=BE=AA=E7=8E=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../resources/web/assets/js/general/rb-forms.js | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/main/resources/web/assets/js/general/rb-forms.js b/src/main/resources/web/assets/js/general/rb-forms.js
index 2851db4e3..c51d6b789 100644
--- a/src/main/resources/web/assets/js/general/rb-forms.js
+++ b/src/main/resources/web/assets/js/general/rb-forms.js
@@ -671,7 +671,6 @@ class RbForm extends React.Component {
setAutoFillin(data) {
if (!data || data.length === 0) return
- this._inAutoFillin = true
data.forEach((item) => {
const fieldComp = this.getFieldComp(item.target)
if (fieldComp) {
@@ -680,7 +679,6 @@ class RbForm extends React.Component {
if ((this.isNew && item.whenCreate) || (!this.isNew && item.whenUpdate)) fieldComp.setValue(item.value)
}
})
- this._inAutoFillin = false
}
// 设置字段值
@@ -2259,6 +2257,17 @@ class RbFormReference extends RbFormElement {
if (this.props.onView) return
const id = value && typeof value === 'object' ? value.id : value
+ // fix:4.0.4 死循环
+ this.__infiniteLoop = this.__infiniteLoop || {}
+ this.__infiniteLoop[id] = (this.__infiniteLoop[id] || 0) + 1
+ if (this.__infiniteLoop[id] > 2) {
+ console.log('Infinite loop [triggerAutoFillin] ...', id)
+ return
+ }
+ setTimeout(() => {
+ this.__infiniteLoop = {}
+ }, 2000)
+
const $$$form = this.props.$$$parent
let formData = null
if (this.props.fillinWithFormData) {