mirror of
https://github.com/getrebuild/rebuild.git
synced 2025-09-28 09:36:37 +08:00
feat: Type cast (#702)
* bcc * feat: field-type-cast * feat: aviator DateCompare * tf.nullable
This commit is contained in:
parent
30ddd5528a
commit
b6530c7938
15 changed files with 305 additions and 26 deletions
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 791d6f665c9e937b4503459cc68958f4c266b4cd
|
||||
Subproject commit 031039036ba44f47b61a2b81bcaa70922ef3656a
|
|
@ -411,4 +411,54 @@ public class Field2Schema extends SetUser {
|
|||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型转换
|
||||
*
|
||||
* @param field
|
||||
* @param toType
|
||||
* @param force
|
||||
* @return
|
||||
*/
|
||||
public boolean castType(Field field, DisplayType toType, boolean force) {
|
||||
EasyField easyMeta = EasyMetaFactory.valueOf(field);
|
||||
ID metaRecordId = easyMeta.getMetaId();
|
||||
if (easyMeta.isBuiltin() || metaRecordId == null) {
|
||||
throw new MetadataModificationException(Language.L("系统内置,不允许转换"));
|
||||
}
|
||||
|
||||
if (!force) {
|
||||
long count;
|
||||
if ((count = checkRecordCount(field.getOwnEntity())) > 100000) {
|
||||
throw new MetadataModificationException(Language.L("实体记录过多 (%d),转换字段可能导致表损坏", count));
|
||||
}
|
||||
}
|
||||
|
||||
Record meta = EntityHelper.forUpdate(metaRecordId, getUser(), false);
|
||||
meta.setString("displayType", toType.name());
|
||||
Application.getCommonsService().update(meta, false);
|
||||
|
||||
Dialect dialect = Application.getPersistManagerFactory().getDialect();
|
||||
final Table table = new Table(field.getOwnEntity(), dialect);
|
||||
StringBuilder ddl = new StringBuilder();
|
||||
table.generateFieldDDL(field, ddl);
|
||||
|
||||
String alterSql = String.format("alter table `%s` change column `%s` ",
|
||||
field.getOwnEntity().getPhysicalName(), field.getPhysicalName());
|
||||
alterSql += ddl.toString().trim();
|
||||
|
||||
try {
|
||||
Application.getSqlExecutor().executeBatch(new String[]{alterSql}, DDL_TIMEOUT);
|
||||
} catch (Throwable ex) {
|
||||
// 还原
|
||||
meta.setString("displayType", EasyMetaFactory.getDisplayType(field).name());
|
||||
Application.getCommonsService().update(meta, false);
|
||||
|
||||
log.error("DDL ERROR : \n" + alterSql, ex);
|
||||
throw new MetadataModificationException(ThrowableUtils.getRootCause(ex).getLocalizedMessage());
|
||||
}
|
||||
|
||||
MetadataHelper.getMetadataFactory().refresh();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,12 @@ public class AviatorUtils {
|
|||
|
||||
AVIATOR.addOpFunction(OperatorType.ADD, new OverOperatorType.DateAdd());
|
||||
AVIATOR.addOpFunction(OperatorType.SUB, new OverOperatorType.DateSub());
|
||||
AVIATOR.addOpFunction(OperatorType.LE, new OverOperatorType.DateCompareLE());
|
||||
AVIATOR.addOpFunction(OperatorType.LT, new OverOperatorType.DateCompareLT());
|
||||
AVIATOR.addOpFunction(OperatorType.GE, new OverOperatorType.DateCompareGE());
|
||||
AVIATOR.addOpFunction(OperatorType.GT, new OverOperatorType.DateCompareGT());
|
||||
AVIATOR.addOpFunction(OperatorType.EQ, new OverOperatorType.DateCompareEQ());
|
||||
AVIATOR.addOpFunction(OperatorType.NEQ, new OverOperatorType.DateCompareNEQ());
|
||||
|
||||
addCustomFunction(new DateDiffFunction());
|
||||
addCustomFunction(new DateAddFunction());
|
||||
|
|
|
@ -10,6 +10,7 @@ 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.AviatorBoolean;
|
||||
import com.googlecode.aviator.runtime.type.AviatorLong;
|
||||
import com.googlecode.aviator.runtime.type.AviatorObject;
|
||||
|
||||
|
@ -26,6 +27,8 @@ public class OverOperatorType {
|
|||
|
||||
private OverOperatorType() {}
|
||||
|
||||
// -- 计算
|
||||
|
||||
/**
|
||||
* 日期加
|
||||
*/
|
||||
|
@ -83,4 +86,102 @@ public class OverOperatorType {
|
|||
Date d = CalendarUtils.addDay(date, num);
|
||||
return new AviatorDate(d);
|
||||
}
|
||||
|
||||
// -- 比较
|
||||
|
||||
/**
|
||||
* 日期比较
|
||||
*/
|
||||
static abstract class DateCompare extends AbstractFunction {
|
||||
private static final long serialVersionUID = -4160230503581309424L;
|
||||
@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 Date) {
|
||||
long v1 = ((Date) $argv1).getTime();
|
||||
long v2 = ((Date) $argv2).getTime();
|
||||
boolean b = compare(v1, v2);
|
||||
return AviatorBoolean.valueOf(b);
|
||||
} else {
|
||||
return arg1.add(arg2, env); // Use default
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected boolean compare(long v1, long v2);
|
||||
}
|
||||
|
||||
// LE `<=`
|
||||
static class DateCompareLE extends DateCompare {
|
||||
private static final long serialVersionUID = 1321662048697121893L;
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.LE.getToken();
|
||||
}
|
||||
@Override
|
||||
protected boolean compare(long v1, long v2) {
|
||||
return v1 <= v2;
|
||||
}
|
||||
}
|
||||
// LT `<`
|
||||
static class DateCompareLT extends DateCompare {
|
||||
private static final long serialVersionUID = 8197857653882782806L;
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.LT.getToken();
|
||||
}
|
||||
@Override
|
||||
protected boolean compare(long v1, long v2) {
|
||||
return v1 < v2;
|
||||
}
|
||||
}
|
||||
// GE `>=`
|
||||
static class DateCompareGE extends DateCompare {
|
||||
private static final long serialVersionUID = -7966630104916265372L;
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.GE.getToken();
|
||||
}
|
||||
@Override
|
||||
protected boolean compare(long v1, long v2) {
|
||||
return v1 >= v2;
|
||||
}
|
||||
}
|
||||
// GT `>`
|
||||
static class DateCompareGT extends DateCompare {
|
||||
private static final long serialVersionUID = 5214573679573440753L;
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.GT.getToken();
|
||||
}
|
||||
@Override
|
||||
protected boolean compare(long v1, long v2) {
|
||||
return v1 > v2;
|
||||
}
|
||||
}
|
||||
// EQ `==`
|
||||
static class DateCompareEQ extends DateCompare {
|
||||
private static final long serialVersionUID = -6142749075506832977L;
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.EQ.getToken();
|
||||
}
|
||||
@Override
|
||||
protected boolean compare(long v1, long v2) {
|
||||
return v1 == v2;
|
||||
}
|
||||
}
|
||||
// NEQ `!=`
|
||||
static class DateCompareNEQ extends DateCompare {
|
||||
private static final long serialVersionUID = -838391653977975466L;
|
||||
@Override
|
||||
public String getName() {
|
||||
return OperatorType.NEQ.getToken();
|
||||
}
|
||||
@Override
|
||||
protected boolean compare(long v1, long v2) {
|
||||
return v1 != v2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public enum ConfigurationItem {
|
|||
StorageURL, StorageApiKey, StorageApiSecret, StorageBucket,
|
||||
|
||||
// 邮件
|
||||
MailUser, MailPassword, MailAddr, MailName(AppName), MailCc,
|
||||
MailUser, MailPassword, MailAddr, MailName(AppName), MailCc, MailBcc,
|
||||
MailSmtpServer,
|
||||
|
||||
// 短信
|
||||
|
|
|
@ -115,7 +115,7 @@ public class RebuildConfiguration extends KVStorage {
|
|||
/**
|
||||
* 邮件账号
|
||||
*
|
||||
* @return returns [MailUser, MailPassword, MailAddr, MailName, MailCc, MailSmtpServer]
|
||||
* @return returns [MailUser, MailPassword, MailAddr, MailName, MailCc, MailBcc, MailSmtpServer]
|
||||
*/
|
||||
public static String[] getMailAccount() {
|
||||
String[] set = getsNoUnset(false,
|
||||
|
@ -123,11 +123,13 @@ public class RebuildConfiguration extends KVStorage {
|
|||
if (set == null) return null;
|
||||
|
||||
String cc = get(ConfigurationItem.MailCc);
|
||||
String bcc = get(ConfigurationItem.MailBcc);
|
||||
String smtpServer = get(ConfigurationItem.MailSmtpServer);
|
||||
|
||||
return new String[] {
|
||||
set[0], set[1], set[2], set[3],
|
||||
StringUtils.defaultIfBlank(cc, null),
|
||||
StringUtils.defaultIfBlank(bcc, null),
|
||||
StringUtils.defaultIfBlank(smtpServer, null)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -89,16 +89,16 @@ public class SMSender {
|
|||
* @throws ConfigurationException If mail-account unset
|
||||
*/
|
||||
public static String sendMail(String to, String subject, String content, boolean useTemplate, String[] specAccount) throws ConfigurationException {
|
||||
if (specAccount == null || specAccount.length < 5
|
||||
if (specAccount == null || specAccount.length < 6
|
||||
|| StringUtils.isBlank(specAccount[0]) || StringUtils.isBlank(specAccount[1])
|
||||
|| StringUtils.isBlank(specAccount[2]) || StringUtils.isBlank(specAccount[3])) {
|
||||
throw new ConfigurationException(Language.L("邮件账户未配置或配置错误"));
|
||||
}
|
||||
|
||||
if (Application.devMode()) {
|
||||
log.info("[dev] Fake send email to : {} / {} / {}", to, subject, content);
|
||||
return null;
|
||||
}
|
||||
// if (Application.devMode()) {
|
||||
// log.info("[dev] Fake send email to : {} / {} / {}", to, subject, content);
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// 使用邮件模板
|
||||
if (useTemplate) {
|
||||
|
@ -133,7 +133,7 @@ public class SMSender {
|
|||
final String logContent = "【" + subject + "】" + content;
|
||||
|
||||
// Use SMTP
|
||||
if (specAccount.length >= 6 && StringUtils.isNotBlank(specAccount[5])) {
|
||||
if (specAccount.length >= 7 && StringUtils.isNotBlank(specAccount[6])) {
|
||||
try {
|
||||
String emailId = sendMailViaSmtp(to, subject, content, specAccount);
|
||||
createLog(to, logContent, TYPE_EMAIL, emailId, null);
|
||||
|
@ -150,6 +150,7 @@ public class SMSender {
|
|||
params.put("signature", specAccount[1]);
|
||||
params.put("to", to);
|
||||
if (StringUtils.isNotBlank(specAccount[4])) params.put("cc", specAccount[4]);
|
||||
if (StringUtils.isNotBlank(specAccount[5])) params.put("bcc", specAccount[5]);
|
||||
params.put("from", specAccount[2]);
|
||||
params.put("from_name", specAccount[3]);
|
||||
params.put("subject", subject);
|
||||
|
@ -196,6 +197,7 @@ public class SMSender {
|
|||
HtmlEmail email = new HtmlEmail();
|
||||
email.addTo(to);
|
||||
if (StringUtils.isNotBlank(specAccount[4])) email.addCc(specAccount[4]);
|
||||
if (StringUtils.isNotBlank(specAccount[5])) email.addBcc(specAccount[5]);
|
||||
email.setSubject(subject);
|
||||
email.setHtmlMsg(htmlContent);
|
||||
|
||||
|
@ -203,7 +205,7 @@ public class SMSender {
|
|||
email.setAuthentication(specAccount[0], specAccount[1]);
|
||||
|
||||
// HOST[:PORT:SSL|TLS]
|
||||
String[] hostPortSsl = specAccount[5].split(":");
|
||||
String[] hostPortSsl = specAccount[6].split(":");
|
||||
email.setHostName(hostPortSsl[0]);
|
||||
if (hostPortSsl.length > 1) email.setSmtpPort(Integer.parseInt(hostPortSsl[1]));
|
||||
if (hostPortSsl.length > 2) {
|
||||
|
|
|
@ -245,6 +245,7 @@ public class ConfigurationController extends BaseController {
|
|||
data.getString("MailUser"), data.getString("MailPassword"),
|
||||
data.getString("MailAddr"), data.getString("MailName"),
|
||||
data.getString("MailCc"),
|
||||
data.getString("MailBcc"),
|
||||
data.getString("MailSmtpServer")
|
||||
};
|
||||
if (specAccount[1].contains("*")) {
|
||||
|
@ -277,7 +278,7 @@ public class ConfigurationController extends BaseController {
|
|||
|
||||
Object[] smsCount = Application.createQueryNoFilter(sqlCount)
|
||||
.setParameter(1, 1)
|
||||
.setParameter(1, xday)
|
||||
.setParameter(2, xday)
|
||||
.unique();
|
||||
|
||||
Object[][] email = Application.createQueryNoFilter(sql)
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
<tbody>
|
||||
<tr class="smtp-show">
|
||||
<td width="40%">[[${bundle.L('SMTP 服务器地址')}]]</td>
|
||||
<td data-id="MailSmtpServer" data-ignore="true" th:data-value="${mailAccount == null ? '' : mailAccount[5]}">
|
||||
[[${mailAccount == null ? bundle.L('未设置') : mailAccount[5]}]]
|
||||
<td data-id="MailSmtpServer" data-ignore="true" th:data-value="${mailAccount == null ? '' : mailAccount[6]}">
|
||||
[[${mailAccount == null ? bundle.L('未设置') : mailAccount[6]}]]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -78,6 +78,12 @@
|
|||
[[${mailAccount == null || mailAccount[4] == null ? bundle.L('无') : mailAccount[4]}]]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('密送地址')}]]</td>
|
||||
<td data-id="MailBcc" th:data-value="${mailAccount == null || mailAccount[5] == null ? '' : mailAccount[5]}" data-optional="true">
|
||||
[[${mailAccount == null || mailAccount[5] == null ? bundle.L('无') : mailAccount[5]}]]
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="show-on-edit">
|
||||
<td></td>
|
||||
<td>
|
||||
|
|
|
@ -66,7 +66,12 @@
|
|||
<div class="form-group row">
|
||||
<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 class="form-control form-control-sm" type="text" readonly th:value="${fieldTypeLabel}" />
|
||||
<div class="input-group">
|
||||
<input class="form-control form-control-sm" type="text" readonly th:value="${fieldTypeLabel}" />
|
||||
<div class="input-group-append hide">
|
||||
<button type="button" class="btn btn-secondary J_cast-type" th:title="${bundle.L('转换字段类型')}"><i class="zmdi zmdi-swap icon"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:if="${fieldType == 'DECIMAL'}">
|
||||
|
@ -531,6 +536,7 @@
|
|||
<script th:src="@{/assets/js/general/rb-forms.append.js}" type="text/babel"></script>
|
||||
<script th:src="@{/assets/js/metadata/field-formula.js}" type="text/babel"></script>
|
||||
<script th:src="@{/assets/js/metadata/field-edit.js}" type="text/babel"></script>
|
||||
<script th:src="@{/assets/js/metadata/field-type.js}" type="text/babel"></script>
|
||||
<script th:src="@{/assets/js/metadata/entity-switch.js}" type="text/babel"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -321,6 +321,9 @@ class DlgAddChart extends RbFormHandler {
|
|||
<button className="btn btn-primary" type="button" onClick={() => this.next()}>
|
||||
{$L('下一步')}
|
||||
</button>
|
||||
<button className="btn btn-link" type="button" onClick={() => this.hide()}>
|
||||
{$L('取消')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -340,12 +343,6 @@ class DlgAddChart extends RbFormHandler {
|
|||
this.__select2 = $(this._$entity).select2({
|
||||
allowClear: false,
|
||||
placeholder: $L('选择数据来源'),
|
||||
// templateResult: function (res) {
|
||||
// const $span = $('<span class="icon-append"></span>').attr('title', res.text).text(res.text)
|
||||
// const found = _data.find((x) => x.entity === res.id)
|
||||
// if (found) $(`<i class="icon zmdi zmdi-${found.icon}"></i>`).appendTo($span)
|
||||
// return $span
|
||||
// },
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ Copyright (c) REBUILD <https://getrebuild.com/> and/or its owners. All rights re
|
|||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
/* global FormulaDate, FormulaCalc */
|
||||
/* global FormulaDate, FormulaCalc, FIELD_TYPES */
|
||||
|
||||
const wpc = window.__PageConfig
|
||||
const __gExtConfig = {}
|
||||
|
@ -25,6 +25,8 @@ $(document).ready(function () {
|
|||
if (wpc.fieldBuildin) {
|
||||
$('.J_fieldAttrs, .J_advOpt, .J_for-STATE').remove()
|
||||
$('#referenceCascadingField, #referenceQuickNew, #referenceDataFilter').parents('.form-group').remove()
|
||||
} else {
|
||||
$('.J_cast-type').parent().removeClass('hide')
|
||||
}
|
||||
// 显示重复值选项
|
||||
if (SHOW_REPEATABLE.includes(dt) && wpc.fieldName !== 'approvalId') {
|
||||
|
@ -299,6 +301,14 @@ $(document).ready(function () {
|
|||
},
|
||||
})
|
||||
})
|
||||
|
||||
$('.J_cast-type').on('click', () => {
|
||||
if (rb.commercial < 10) {
|
||||
RbHighbar.error(WrapHtml($L('免费版不支持此功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)')))
|
||||
return
|
||||
}
|
||||
renderRbcomp(<FieldTypeCast entity={wpc.entityName} field={wpc.fieldName} fromType={wpc.fieldType} />)
|
||||
})
|
||||
})
|
||||
|
||||
// Check incorrect?
|
||||
|
@ -732,3 +742,87 @@ const _handleAnyReference = function (es) {
|
|||
if (es) $s2.val(es.split(',')).trigger('change')
|
||||
})
|
||||
}
|
||||
|
||||
// 字段类型转换
|
||||
const __TYPE2TYPE = {
|
||||
'NUMBER': ['DECIMAL'],
|
||||
'DECIMAL': ['NUMBER'],
|
||||
'DATE': ['DATETIME'],
|
||||
'DATETIME': ['DATE'],
|
||||
'TEXT': ['NTEXT', 'PHONE', 'EMAIL', 'URL'],
|
||||
'PHONE': ['TEXT'],
|
||||
'EMAIL': ['TEXT'],
|
||||
'URL': ['TEXT'],
|
||||
'NTEXT': ['TEXT'],
|
||||
'IMAGE': ['FILE'],
|
||||
'FILE': ['IMAGE'],
|
||||
}
|
||||
class FieldTypeCast extends RbFormHandler {
|
||||
render() {
|
||||
const toTypes = __TYPE2TYPE[this.props.fromType] || []
|
||||
|
||||
return (
|
||||
<RbModal title={$L('转换字段类型')} ref={(c) => (this._dlg = c)} disposeOnHide>
|
||||
<div className="form">
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('当前字段类型')}</label>
|
||||
<div className="col-sm-7">
|
||||
<div className="form-control-plaintext text-bold">{FIELD_TYPES[this.props.fromType][0]}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('新字段类型')}</label>
|
||||
<div className="col-sm-7">
|
||||
<select className="form-control form-control-sm" ref={(c) => (this._$toType = c)}>
|
||||
{toTypes.map((t) => {
|
||||
return (
|
||||
<option value={t} key={t}>
|
||||
{(FIELD_TYPES[t] || [t])[0]}
|
||||
</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
<p className="form-text">{$L('转换可能导致一定的精度损失,请谨慎进行')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row footer" ref={(c) => (this._$btns = c)}>
|
||||
<div className="col-sm-7 offset-sm-3">
|
||||
<button className="btn btn-primary" type="button" onClick={() => this.post()}>
|
||||
{$L('确定')}
|
||||
</button>
|
||||
<button className="btn btn-link" type="button" onClick={() => this.hide()}>
|
||||
{$L('取消')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</RbModal>
|
||||
)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$(this._$toType).select2({
|
||||
placeholder: $L('不可转换'),
|
||||
templateResult: function (res) {
|
||||
const $span = $('<span class="icon-append"></span>').attr('title', res.text).text(res.text)
|
||||
$(`<i class="icon mdi ${(FIELD_TYPES[res.id] || [])[1]}"></i>`).appendTo($span)
|
||||
return $span
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
post() {
|
||||
const toType = $(this._$toType).val()
|
||||
if (!toType) return RbHighbar.create($L('不可转换'))
|
||||
|
||||
const $btn = $(this._$btns).find('.btn').button('loading')
|
||||
$.post(`/admin/entity/field-type-cast?entity=${this.props.entity}&field=${this.props.field}&toType=${toType}`, (res) => {
|
||||
if (res.error_code === 0) {
|
||||
location.reload()
|
||||
} else {
|
||||
$btn.button('reset')
|
||||
RbHighbar.error(res.error_msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,12 +181,12 @@ class RbModalHandler extends React.Component {
|
|||
this.state = { ...props }
|
||||
}
|
||||
|
||||
show = (state, call) => {
|
||||
show = (state, cb) => {
|
||||
const callback = () => {
|
||||
// eslint-disable-next-line react/no-string-refs
|
||||
const dlg = this._dlg || this.refs['dlg']
|
||||
if (dlg) dlg.show()
|
||||
typeof call === 'function' && call(this)
|
||||
typeof cb === 'function' && cb(this)
|
||||
}
|
||||
if (state && $.type(state) === 'object') this.setState(state, callback)
|
||||
else callback()
|
||||
|
@ -1243,7 +1243,7 @@ const renderRbcomp = function (jsx, target, callback) {
|
|||
target = target[0]
|
||||
}
|
||||
|
||||
// ReactDOM.render(<React.StrictMode>{jsx}</React.StrictMode>, target, call)
|
||||
// ReactDOM.render(<React.StrictMode>{jsx}</React.StrictMode>, target, callback)
|
||||
ReactDOM.render(jsx, target, callback)
|
||||
return target
|
||||
}
|
||||
|
|
|
@ -339,8 +339,9 @@ class ContentFieldWriteback extends ActionContentSpec {
|
|||
sourceField = this._$sourceValue.val()
|
||||
if (!sourceField) return
|
||||
} else if (mode === 'VNULL') {
|
||||
const tf = this.state.targetFields.find((x) => x.name === targetField)
|
||||
if (!tf.nullable) return RbHighbar.create($L('目标字段 %s 不能为空', `[ ${tf.label} ]`))
|
||||
// v3.6 不校验
|
||||
// const tf = this.state.targetFields.find((x) => x.name === targetField)
|
||||
// if (!tf.nullable) return RbHighbar.create($L('目标字段 %s 不能为空', tf.label))
|
||||
}
|
||||
|
||||
const items = this.state.items || []
|
||||
|
|
|
@ -92,4 +92,17 @@ class AviatorUtilsTest {
|
|||
Assertions.assertThrows(ExpressionRuntimeException.class,
|
||||
() -> AviatorUtils.eval("date1 + date1", env, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDateCompare() {
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
env.put("date1", CalendarUtils.now());
|
||||
env.put("date2", CalendarUtils.addDay(1));
|
||||
AviatorUtils.eval("p(date1 == date1)", env, true);
|
||||
AviatorUtils.eval("p(date1 != date2)", env, true);
|
||||
AviatorUtils.eval("p(date1 > date2)", env, true);
|
||||
AviatorUtils.eval("p(date1 < date2)", env, true);
|
||||
AviatorUtils.eval("p(date1 <= date1)", env, true);
|
||||
AviatorUtils.eval("p(date2 <= date2)", env, true);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue