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) {