mirror of
https://github.com/getrebuild/rebuild.git
synced 2025-09-10 00:33:34 +08:00
Fix 3.9.1 (#855)
* fix: 表单回填ID无效 * feat: check-state st * fix: tel/mailto pdf for dd/wx * fix: 刷新导致标题变化 * 3.9.1 * be:变量匹配 {} * fix: AnyRecordSelector * style:_backup * enh: filter date EQ * OSC * Update rb-forms.js
This commit is contained in:
parent
8c9e831d26
commit
0a9fbcdde1
20 changed files with 157 additions and 58 deletions
|
@ -151,5 +151,6 @@ module.exports = {
|
|||
$clearSelection: true,
|
||||
DlgTransform: true,
|
||||
$select2OpenTemplateResult: true,
|
||||
$env: true,
|
||||
},
|
||||
}
|
||||
|
|
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 55386d909e5ed6afe1fe7a0793c460451b491296
|
||||
Subproject commit 9a6c91abe293077d0ef39b7b22834ba9bd22add8
|
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
|||
</parent>
|
||||
<groupId>com.rebuild</groupId>
|
||||
<artifactId>rebuild</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<version>3.9.1</version>
|
||||
<name>rebuild</name>
|
||||
<description>Building your business-systems freely!</description>
|
||||
<url>https://getrebuild.com/</url>
|
||||
|
|
|
@ -74,11 +74,11 @@ public class Application implements ApplicationListener<ApplicationStartedEvent>
|
|||
/**
|
||||
* Rebuild Version
|
||||
*/
|
||||
public static final String VER = "3.9.0";
|
||||
public static final String VER = "3.9.1";
|
||||
/**
|
||||
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
|
||||
*/
|
||||
public static final int BUILD = 3090005;
|
||||
public static final int BUILD = 3090106;
|
||||
|
||||
static {
|
||||
// Driver for DB
|
||||
|
|
|
@ -24,10 +24,7 @@ import com.rebuild.core.configuration.ConfigManager;
|
|||
import com.rebuild.core.metadata.MetadataHelper;
|
||||
import com.rebuild.core.metadata.easymeta.DisplayType;
|
||||
import com.rebuild.core.metadata.easymeta.EasyField;
|
||||
import com.rebuild.core.metadata.easymeta.EasyFile;
|
||||
import com.rebuild.core.metadata.easymeta.EasyID;
|
||||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.metadata.easymeta.EasyN2NReference;
|
||||
import com.rebuild.core.metadata.easymeta.MixValue;
|
||||
import com.rebuild.core.metadata.impl.EasyFieldConfigProps;
|
||||
import com.rebuild.core.support.general.CalcFormulaSupport;
|
||||
|
@ -313,17 +310,20 @@ public class AutoFillinManager implements ConfigManager {
|
|||
|
||||
// 转换成前端可接受的值
|
||||
|
||||
if (sourceEasy.getDisplayType() == targetEasy.getDisplayType()
|
||||
&& sourceEasy.getDisplayType() == DisplayType.MULTISELECT) {
|
||||
DisplayType sourceEasyType = sourceEasy.getDisplayType();
|
||||
DisplayType targetEasyType = targetEasy.getDisplayType();
|
||||
|
||||
if (sourceEasyType == targetEasyType && sourceEasyType == DisplayType.MULTISELECT) {
|
||||
return newValue; // Long
|
||||
}
|
||||
|
||||
if (sourceEasy instanceof EasyID && targetEasy instanceof EasyN2NReference) {
|
||||
if (sourceEasyType == DisplayType.ID
|
||||
&& (targetEasyType == DisplayType.REFERENCE || targetEasyType == DisplayType.N2NREFERENCE || targetEasyType == DisplayType.ANYREFERENCE)) {
|
||||
newValue = FieldValueHelper.wrapFieldValue(newValue, targetEasy);
|
||||
} else if (targetEasy instanceof EasyN2NReference) {
|
||||
} else if (targetEasyType == DisplayType.N2NREFERENCE) {
|
||||
newValue = targetEasy.wrapValue(newValue);
|
||||
} else if (sourceEasy instanceof MixValue) {
|
||||
if (!(newValue instanceof String) || sourceEasy instanceof EasyFile) {
|
||||
if (!(newValue instanceof String) || sourceEasyType == DisplayType.FILE) {
|
||||
newValue = sourceEasy.wrapValue(newValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -524,6 +524,29 @@ public class AdvFilterParser extends SetUser {
|
|||
op = ParseHelper.BW;
|
||||
}
|
||||
|
||||
// v3.9.1 日期查询年月日 0000-00-00
|
||||
if (ParseHelper.EQ.equals(op) && (value.startsWith("0000-") || value.contains("-00-") || value.endsWith("-00"))) {
|
||||
final String[] ymd = value.split("-");
|
||||
String format;
|
||||
if (ymd[0].equals("0000") && ymd[1].equals("00")) { // 0000-00-XX
|
||||
format = "%d";
|
||||
value = ymd[2];
|
||||
} else if (ymd[0].equals("0000") && ymd[2].equals("00")) { // 0000-XX-00
|
||||
format = "%m";
|
||||
value = ymd[1];
|
||||
} else if (ymd[1].equals("00") && ymd[2].equals("00")) { // XXXX-00-00
|
||||
format = "%Y";
|
||||
value = ymd[0];
|
||||
} else if (ymd[1].equals("00")) { // XXXX-00-XX
|
||||
format = "%Y%d";
|
||||
value = ymd[0] + ymd[2];
|
||||
} else { // 0000-XX-XX
|
||||
format = "%m%d";
|
||||
value = ymd[1] + ymd[2];
|
||||
}
|
||||
field = String.format("DATE_FORMAT(%s, '%s')", field, format);
|
||||
}
|
||||
|
||||
} else if (dt == DisplayType.TIME) {
|
||||
// 前端输入 HH:mm
|
||||
if (value != null && value.length() == 5) {
|
||||
|
@ -662,13 +685,13 @@ public class AdvFilterParser extends SetUser {
|
|||
.append(" )");
|
||||
}
|
||||
|
||||
// 当前审批人
|
||||
if (VF_ACU.equals(field)) {
|
||||
return String.format(
|
||||
"(exists (select recordId from RobotApprovalStep where ^%s = recordId and state = 1 and isCanceled = 'F' and %s) and approvalState = 2)",
|
||||
specRootEntity.getPrimaryField().getName(), sb.toString().replace(VF_ACU, "approver"));
|
||||
} else {
|
||||
return sb.toString();
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,7 +75,7 @@ public final class License {
|
|||
if ((error = auth.getString("error")) != null) {
|
||||
auth = JSONUtils.toJSONObject(
|
||||
new String[] { "sn", "authType", "authObject", "authExpires" },
|
||||
new String[] { SN(), "开源社区版", "GitHub", "无" });
|
||||
new String[] { SN(), "开源社区版", "OSC", "无" });
|
||||
}
|
||||
if ("BLOCKED".equals(error)) System.exit(110);
|
||||
return auth;
|
||||
|
|
|
@ -41,7 +41,7 @@ public class ContentWithFieldVars {
|
|||
/**
|
||||
* 通过 `{}` 包裹的变量或字段
|
||||
*/
|
||||
public static final Pattern PATT_VAR = Pattern.compile("\\{([0-9a-zA-Z._$]+)}");
|
||||
public static final Pattern PATT_VAR = Pattern.compile("\\{([0-9a-zA-Z._$]{4,})}");
|
||||
|
||||
/**
|
||||
* 替换文本中的字段变量
|
||||
|
@ -82,9 +82,7 @@ public class ContentWithFieldVars {
|
|||
* @return
|
||||
*/
|
||||
public static String replaceWithRecord(String content, Record record) {
|
||||
if (StringUtils.isBlank(content) || record == null) {
|
||||
return content;
|
||||
}
|
||||
if (StringUtils.isBlank(content) || record == null) return content;
|
||||
|
||||
// 主键占位符
|
||||
content = content.replace("{ID}",
|
||||
|
@ -147,25 +145,19 @@ public class ContentWithFieldVars {
|
|||
}
|
||||
|
||||
/**
|
||||
* 提取内容中的变量 {xxx}
|
||||
* 提取内容中的变量 {xxxx}
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
*/
|
||||
public static Set<String> matchsVars(String content) {
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
if (StringUtils.isBlank(content)) return Collections.emptySet();
|
||||
|
||||
Set<String> vars = new HashSet<>();
|
||||
Matcher m = PATT_VAR.matcher(content);
|
||||
while (m.find()) {
|
||||
String varName = m.group(1);
|
||||
if (StringUtils.isBlank(varName)) {
|
||||
log.warn("Blank `\\{\\}` found in `{}`", content);
|
||||
} else {
|
||||
vars.add(varName);
|
||||
}
|
||||
vars.add(varName);
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ public class NotificationController extends BaseController {
|
|||
|
||||
JSON mm = buildMM();
|
||||
if (mm != null) state.put("mm", mm);
|
||||
state.put("st", CalendarUtils.now());
|
||||
|
||||
// v3.8 手机版利用通知检查做最近活跃信息存储
|
||||
String h5referer = getParameter(request, "h5referer");
|
||||
|
|
|
@ -3345,5 +3345,6 @@
|
|||
"未备份":"未备份",
|
||||
"选择要备份哪些数据":"选择要备份哪些数据",
|
||||
"分配与共享":"分配与共享",
|
||||
"最多显示最近 500 条记录":"最多显示最近 500 条记录"
|
||||
"最多显示最近 500 条记录":"最多显示最近 500 条记录",
|
||||
"失败时的提示内容。内容支持字段变量,如 `{createdOn}` (其中 createdOn 为源实体的字段内部标识)":"失败时的提示内容。内容支持字段变量,如 `{createdOn}` (其中 createdOn 为源实体的字段内部标识)"
|
||||
}
|
|
@ -33,3 +33,6 @@
|
|||
<script th:src="@{/assets/js/rebuild-tour.js}" type="text/babel"></script>
|
||||
</th:block>
|
||||
</th:block>
|
||||
<!--
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
-->
|
||||
|
|
|
@ -542,11 +542,11 @@
|
|||
/>
|
||||
<div class="dropdown-menu common-texts J_advPattern">
|
||||
<h5>[[${bundle.L('常用')}]]</h5>
|
||||
<a class="badge" data-patt="^([0-9A-Z]{15}|[0-9A-Z]{17}|[0-9A-Z]{18}|[0-9A-Z]{20})$">[[${bundle.L('税号')}]]</a>
|
||||
<a class="badge" data-patt="^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$">[[${bundle.L('身份证')}]]</a>
|
||||
<a class="badge" data-patt="^1[3456789]\d{9}$">[[${bundle.L('手机号')}]]</a>
|
||||
<a class="badge" data-patt="^[1-9][0-9]{4,10}$">[[${bundle.L('QQ号')}]]</a>
|
||||
<a class="badge" data-patt="^[1-9][0-9]{5}$">[[${bundle.L('邮编')}]]</a>
|
||||
<a class="badge" data-patt="^([0-9A-Z]{15}|[0-9A-Z]{17}|[0-9A-Z]{18}|[0-9A-Z]{20})$">[[${bundle.L('税号')}]]</a>
|
||||
<a class="badge" data-patt="^[\u4e00-\u9fa5]{0,}$">[[${bundle.L('仅中文')}]]</a>
|
||||
<a class="badge" data-patt="^[A-Za-z]{0,}$">[[${bundle.L('仅英文')}]]</a>
|
||||
<a class="badge" data-patt="^[0-9]{0,}$">[[${bundle.L('仅数字')}]]</a>
|
||||
|
|
|
@ -74,6 +74,12 @@
|
|||
button.J_MobileAppPath + button.J_MobileAppPath-del {
|
||||
margin-left: 70px;
|
||||
}
|
||||
.backup-box {
|
||||
background-color: #eee;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 2px;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -339,6 +339,7 @@ class DlgBackup extends RbAlert {
|
|||
state = { ...this.props }
|
||||
|
||||
renderContent() {
|
||||
const _backup = this.state.db || this.state.file
|
||||
return (
|
||||
<form className="rbalert-form-sm">
|
||||
<div className="form-group mb-0">
|
||||
|
@ -355,9 +356,26 @@ class DlgBackup extends RbAlert {
|
|||
</div>
|
||||
</div>
|
||||
<div className="form-group mb-1">
|
||||
<div className="text-warning mb-1" ref={(c) => (this._$tips = c)}>
|
||||
<i className="mdi-alert-outline mdi" /> {$L('请勿在业务高峰时段执行备份')}
|
||||
</div>
|
||||
{_backup ? (
|
||||
<div className="backup-box">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="text-ellipsis pr-1">{$L('数据库')}</td>
|
||||
<td>{this.state.db ? <code>{this.state.db}</code> : <span className="text-muted">{$L('未备份')}</span>}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="text-ellipsis pr-1">{$L('数据目录文件')}</td>
|
||||
<td>{this.state.file ? <code>{this.state.file}</code> : <span className="text-muted">{$L('未备份')}</span>}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-warning mb-1" ref={(c) => (this._$tips = c)}>
|
||||
<i className="mdi-alert-outline mdi" /> {$L('请勿在业务高峰时段执行备份')}
|
||||
</div>
|
||||
)}
|
||||
<button type="button" className="btn btn-space btn-primary" onClick={this.confirm} ref={(c) => (this._$btn = c)} data-spinner>
|
||||
{$L('开始备份')}
|
||||
</button>
|
||||
|
@ -367,19 +385,15 @@ class DlgBackup extends RbAlert {
|
|||
}
|
||||
|
||||
confirm = () => {
|
||||
let type = ($(this._$bkType).find('input:eq(0)').prop('checked') ? 1 : 0) + ($(this._$bkType).find('input:eq(1)').prop('checked') ? 2 : 0)
|
||||
const type = ($(this._$bkType).find('input:eq(0)').prop('checked') ? 1 : 0) + ($(this._$bkType).find('input:eq(1)').prop('checked') ? 2 : 0)
|
||||
if (type === 0) return
|
||||
|
||||
this.disabled(true, true)
|
||||
const $btn = $(this._$btn).button('loading')
|
||||
$.post(`systems/backup?type=${type}`, (res) => {
|
||||
if (res.error_code === 0) {
|
||||
const data = res.data || {}
|
||||
const tips = [$L('数据库'), ' <code>', data.db || $L('未备份'), '</code><br>', $L('数据目录文件'), ' <code>', data.file || $L('未备份'), '</code>']
|
||||
$(this._$tips).html(tips.join(''))
|
||||
} else {
|
||||
RbHighbar.error(res.error_msg)
|
||||
}
|
||||
if (res.error_code === 0) this.setState({ ...res.data })
|
||||
else RbHighbar.error(res.error_msg)
|
||||
|
||||
this.disabled(false, false)
|
||||
$btn.button('reset')
|
||||
})
|
||||
|
|
|
@ -1391,7 +1391,7 @@ class DataList extends BaseChart {
|
|||
}
|
||||
|
||||
const extconfig = this.state.config.extconfig
|
||||
extconfig && this.setState({ title: extconfig.title || $L('数据列表') })
|
||||
// extconfig && this.setState({ title: extconfig.title || $L('数据列表') })
|
||||
|
||||
const listFields = data.fields
|
||||
const listData = data.data
|
||||
|
|
|
@ -210,6 +210,13 @@ class RbPreview extends React.Component {
|
|||
previewUrl = `${rb.baseUrl}/filex/` + url.split('/filex/')[1]
|
||||
}
|
||||
}
|
||||
|
||||
// fix:3.9.1 PC钉钉预览PDF
|
||||
if ($env.isDingTalk()) {
|
||||
window.open(previewUrl)
|
||||
that.hide()
|
||||
return
|
||||
}
|
||||
}
|
||||
that.setState({ previewUrl: previewUrl, errorMsg: null })
|
||||
}
|
||||
|
|
|
@ -1739,9 +1739,13 @@ CellRenders.addRender('EMAIL', (v, s, k) => {
|
|||
return (
|
||||
<td key={k}>
|
||||
<div style={s} title={v}>
|
||||
<a href={`mailto:${v}`} className="column-url" onClick={(e) => $stopEvent(e)}>
|
||||
{v}
|
||||
</a>
|
||||
{$env.isDingTalk() ? (
|
||||
<a>{v}</a>
|
||||
) : (
|
||||
<a href={`mailto:${v}`} className="column-url" onClick={(e) => $stopEvent(e)}>
|
||||
{v}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
)
|
||||
|
@ -1750,9 +1754,13 @@ CellRenders.addRender('PHONE', (v, s, k) => {
|
|||
return (
|
||||
<td key={k}>
|
||||
<div style={s} title={v}>
|
||||
<a href={`tel:${v}`} className="column-url" onClick={(e) => $stopEvent(e)}>
|
||||
{v}
|
||||
</a>
|
||||
{$env.isDingTalk() || $env.isWxWork() ? (
|
||||
<a>{v}</a>
|
||||
) : (
|
||||
<a href={`tel:${v}`} className="column-url" onClick={(e) => $stopEvent(e)}>
|
||||
{v}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
)
|
||||
|
|
|
@ -712,7 +712,7 @@ class RbForm extends React.Component {
|
|||
|
||||
const fieldComp = _refs[key]
|
||||
let v = fieldComp.getValue()
|
||||
if (v && typeof v === 'object') v = v.id
|
||||
if (v && typeof v === 'object') v = v.id || v // array
|
||||
if (v) data[fieldComp.props.field] = v
|
||||
}
|
||||
return data
|
||||
|
@ -1232,9 +1232,13 @@ class RbFormEMail extends RbFormText {
|
|||
|
||||
return (
|
||||
<div className="form-control-plaintext">
|
||||
<a title={$L('发送邮件')} href={`mailto:${this.state.value}`} className="link">
|
||||
{this.state.value}
|
||||
</a>
|
||||
{$env.isDingTalk() ? (
|
||||
<a>{this.state.value}</a>
|
||||
) : (
|
||||
<a title={$L('发送邮件')} href={`mailto:${this.state.value}`} className="link">
|
||||
{this.state.value}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1252,9 +1256,13 @@ class RbFormPhone extends RbFormText {
|
|||
|
||||
return (
|
||||
<div className="form-control-plaintext">
|
||||
<a title={$L('拨打电话')} href={`tel:${this.state.value}`} className="link">
|
||||
{this.state.value}
|
||||
</a>
|
||||
{$env.isDingTalk() || $env.isWxWork() ? (
|
||||
<a>{this.state.value}</a>
|
||||
) : (
|
||||
<a title={$L('拨打电话')} href={`tel:${this.state.value}`} className="link">
|
||||
{this.state.value}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -990,8 +990,10 @@ class AnyRecordSelector extends RecordSelector {
|
|||
const iv = this.props.initValue
|
||||
if (iv) {
|
||||
$(this._$entity).val(iv.entity).trigger('change')
|
||||
const option = new Option(iv.text, iv.id, true, true)
|
||||
$(this._$select).append(option)
|
||||
setTimeout(() => {
|
||||
const o = new Option(iv.text, iv.id, true, true)
|
||||
$(this._$select).append(o)
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -209,6 +209,8 @@ $(window).on('load', () => {
|
|||
if (($(this).attr('href') || '').indexOf('getrebuild.com') > -1) $(this).removeAttr('href')
|
||||
})
|
||||
}
|
||||
// vConsole
|
||||
if (window.VConsole) new window.VConsole()
|
||||
})
|
||||
|
||||
// 取消管理中心访问
|
||||
|
@ -387,6 +389,7 @@ var _checkMessage = function () {
|
|||
}
|
||||
|
||||
_showStateMM(res.data.mm)
|
||||
_showStateST(res.data.st)
|
||||
setTimeout(_checkMessage, rb.env === 'dev' ? 9000 : 2000)
|
||||
})
|
||||
}
|
||||
|
@ -446,7 +449,6 @@ var _showNotification = function (state) {
|
|||
}
|
||||
var _showStateMM = function (mm) {
|
||||
if ($.cookie('mm_gritter_cancel')) return
|
||||
|
||||
if (mm) {
|
||||
var $mm = $('#mm_gritter')
|
||||
if ($mm[0]) {
|
||||
|
@ -471,6 +473,25 @@ var _showStateMM = function (mm) {
|
|||
RbGritter.remove('mm_gritter')
|
||||
}
|
||||
}
|
||||
var _showStateST = function (st) {
|
||||
if ($.cookie('st_gritter_cancel')) return
|
||||
st = Math.abs(moment().diff(st, 'seconds'))
|
||||
if (st > 60) {
|
||||
if (!$('#gritter-item-st_gritter')[0]) {
|
||||
RbGritter.create($L('本地计算机与服务器时间存在加大差异,建议立即校正。'), {
|
||||
timeout: 60 * 1000,
|
||||
type: 'danger',
|
||||
icon: 'mdi-clock-remove-outline',
|
||||
onCancel: function () {
|
||||
$.cookie('st_gritter_cancel', st, { expires: 1 })
|
||||
},
|
||||
id: 'st_gritter',
|
||||
})
|
||||
}
|
||||
} else {
|
||||
RbGritter.remove('st_gritter')
|
||||
}
|
||||
}
|
||||
// 全局搜索
|
||||
var _initGlobalSearch = function () {
|
||||
$('.global-search2>a').on('click', function () {
|
||||
|
@ -1336,3 +1357,15 @@ function $select2OpenTemplateResult(res) {
|
|||
}
|
||||
return $span
|
||||
}
|
||||
|
||||
// 环境 @see LoginChannel.java
|
||||
var $env = {
|
||||
// 钉钉
|
||||
isDingTalk: function () {
|
||||
return navigator.userAgent.match(/(DINGTALK)/i) || true
|
||||
},
|
||||
// 企微
|
||||
isWxWork: function () {
|
||||
return navigator.userAgent.match(/(WXWORK)/i)
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue