diff --git a/@rbv b/@rbv index 0632edc28c..55386d909e 160000 --- a/@rbv +++ b/@rbv @@ -1 +1 @@ -Subproject commit 0632edc28ced726d01dcc7d949932aca976db5f7 +Subproject commit 55386d909e5ed6afe1fe7a0793c460451b491296 diff --git a/Dockerfile b/Dockerfile index ea89fee2b2..b1ef765821 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ FROM amazoncorretto:11-alpine +#docker pull amazoncorretto:11-alpine RUN apk add ttf-dejavu EXPOSE 18080 COPY ./target/rebuild.jar /app/rebuild/rebuild-boot.jar - #COPY ./.deploy/SourceHanSansK-Regular.ttf /app/rebuild/.rebuild/ WORKDIR /app/rebuild/ diff --git a/pom.xml b/pom.xml index f9f488bbad..5945c2c155 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ </parent> <groupId>com.rebuild</groupId> <artifactId>rebuild</artifactId> - <version>3.9.0-beta3</version> + <version>3.9.0</version> <name>rebuild</name> <description>Building your business-systems freely!</description> <url>https://getrebuild.com/</url> diff --git a/src/main/java/com/rebuild/core/Application.java b/src/main/java/com/rebuild/core/Application.java index 6859a830f8..c85dcce519 100644 --- a/src/main/java/com/rebuild/core/Application.java +++ b/src/main/java/com/rebuild/core/Application.java @@ -74,11 +74,11 @@ public class Application implements ApplicationListener<ApplicationStartedEvent> /** * Rebuild Version */ - public static final String VER = "3.9.0-beta3"; + public static final String VER = "3.9.0"; /** * Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2} */ - public static final int BUILD = 3090003; + public static final int BUILD = 3090005; static { // Driver for DB diff --git a/src/main/java/com/rebuild/core/metadata/impl/EasyFieldConfigProps.java b/src/main/java/com/rebuild/core/metadata/impl/EasyFieldConfigProps.java index fdf53193d5..dee5cc809b 100644 --- a/src/main/java/com/rebuild/core/metadata/impl/EasyFieldConfigProps.java +++ b/src/main/java/com/rebuild/core/metadata/impl/EasyFieldConfigProps.java @@ -102,6 +102,10 @@ public class EasyFieldConfigProps { * 允许上传文件类型 */ public static final String FILE_SUFFIX = "fileSuffix"; + /** + * 指定上传路径 + */ + public static final String FILE_UPDIR = "fileUpdir"; /** * 允许上传数量 diff --git a/src/main/java/com/rebuild/core/service/dashboard/charts/builtin/ApprovalList.java b/src/main/java/com/rebuild/core/service/dashboard/charts/builtin/ApprovalList.java index 4994aae621..ed129ae969 100644 --- a/src/main/java/com/rebuild/core/service/dashboard/charts/builtin/ApprovalList.java +++ b/src/main/java/com/rebuild/core/service/dashboard/charts/builtin/ApprovalList.java @@ -121,6 +121,7 @@ public JSON build() { Map<String, Object> ret = new HashMap<>(); ret.put("data", rearray); ret.put("stats", stats); + ret.put("overLimit", array.length >= 500); return (JSON) JSON.toJSON(ret); } } diff --git a/src/main/java/com/rebuild/core/service/general/QuickCodeReindexTask.java b/src/main/java/com/rebuild/core/service/general/QuickCodeReindexTask.java index 3c65259dd5..0c72f2b0e8 100644 --- a/src/main/java/com/rebuild/core/service/general/QuickCodeReindexTask.java +++ b/src/main/java/com/rebuild/core/service/general/QuickCodeReindexTask.java @@ -168,7 +168,7 @@ public static String generateQuickCode(String nameVal) { try { quickCode = HanLP.convertToPinyinString(nameVal, "", Boolean.FALSE); } catch (Exception e) { - log.error("QuickCode shorting error : " + nameVal, e); + log.error("QuickCode shorting error : {}", nameVal, e); quickCode = StringUtils.EMPTY; } } diff --git a/src/main/java/com/rebuild/core/support/integration/QiniuCloud.java b/src/main/java/com/rebuild/core/support/integration/QiniuCloud.java index 362d0cbe94..65022034a2 100644 --- a/src/main/java/com/rebuild/core/support/integration/QiniuCloud.java +++ b/src/main/java/com/rebuild/core/support/integration/QiniuCloud.java @@ -344,8 +344,8 @@ public static String formatFileKey(String fileName, boolean keepName, String upd String dt = CalendarUtils.getDateFormat("yyyyMMddHHmmssSSS").format(CalendarUtils.now()); String subdir = dt.substring(0, 8); String filePrefix = dt.substring(8); - // remove unsafe /\. - if (StringUtils.isNotBlank(updir)) subdir = updir.replaceAll("[./\\\\\\s]", ""); + // remove unsafe flags + if (StringUtils.isNotBlank(updir)) subdir = updir.replaceAll("[%./\\\\\\s]", ""); return String.format("rb/%s/%s__%s", subdir, filePrefix, fileName); } diff --git a/src/main/java/com/rebuild/web/robot/trigger/TriggerAdminController.java b/src/main/java/com/rebuild/web/robot/trigger/TriggerAdminController.java index d2a311d6b4..4514c1e34b 100644 --- a/src/main/java/com/rebuild/web/robot/trigger/TriggerAdminController.java +++ b/src/main/java/com/rebuild/web/robot/trigger/TriggerAdminController.java @@ -18,6 +18,7 @@ import com.rebuild.core.metadata.MetadataSorter; import com.rebuild.core.metadata.easymeta.EasyMetaFactory; import com.rebuild.core.service.approval.RobotApprovalManager; +import com.rebuild.core.service.datareport.DataReportManager; import com.rebuild.core.service.trigger.ActionFactory; import com.rebuild.core.service.trigger.ActionType; import com.rebuild.core.service.trigger.TriggerAction; @@ -158,24 +159,32 @@ public static String[] tryParseTargetEntity(String config, String sourceEntity) // 自动记录转换 String useTransform = configJson.getString("useTransform"); if (ID.isId(useTransform)) { - ConfigBean cb; try { - cb = TransformManager.instance.getTransformConfig(ID.valueOf(useTransform), sourceEntity); - } catch (Exception ignored) { - return null; + ConfigBean cb = TransformManager.instance.getTransformConfig(ID.valueOf(useTransform), sourceEntity); + return new String[]{ useTransform, cb.getString("name") }; + } catch (Exception deleted) { + return new String[]{ null, String.format("[%s]", useTransform.toUpperCase()) }; } - return new String[]{ useTransform, cb.getString("name") }; } // 自动审批 String useApproval = configJson.getString("useApproval"); if (ID.isId(useApproval)) { - ConfigBean cb; try { - cb = RobotApprovalManager.instance.getFlowDefinition(ID.valueOf(useApproval)); - } catch (Exception ignored) { - return null; + ConfigBean cb = RobotApprovalManager.instance.getFlowDefinition(ID.valueOf(useApproval)); + return new String[]{ useApproval, cb.getString("name") }; + } catch (Exception deleted) { + return new String[]{ null, String.format("[%s]", useApproval.toUpperCase()) }; + } + } + // 导出报表 + String useTemplate = configJson.getString("useTemplate"); + if (ID.isId(useTemplate)) { + try { + ConfigBean cb = DataReportManager.instance.getReportRaw(ID.valueOf(useTemplate)); + return new String[]{ useTemplate, cb.getString("name") }; + } catch (Exception deleted) { + return new String[]{ null, String.format("[%s]", useTemplate.toUpperCase()) }; } - return new String[]{ useApproval, cb.getString("name") }; } return null; diff --git a/src/main/resources/i18n/lang.zh_CN.json b/src/main/resources/i18n/lang.zh_CN.json index f4b5bd9ac3..9cc251da0a 100644 --- a/src/main/resources/i18n/lang.zh_CN.json +++ b/src/main/resources/i18n/lang.zh_CN.json @@ -3343,5 +3343,7 @@ "立即备份":"立即备份", "数据库":"数据库", "未备份":"未备份", - "选择要备份哪些数据":"选择要备份哪些数据" + "选择要备份哪些数据":"选择要备份哪些数据", + "分配与共享":"分配与共享", + "最多显示最近 500 条记录":"最多显示最近 500 条记录" } \ No newline at end of file diff --git a/src/main/resources/web/admin/metadata/field-edit.html b/src/main/resources/web/admin/metadata/field-edit.html index 236eb99448..1d4158dbad 100644 --- a/src/main/resources/web/admin/metadata/field-edit.html +++ b/src/main/resources/web/admin/metadata/field-edit.html @@ -171,6 +171,12 @@ <h5>[[${bundle.L('常用')}]]</h5> </label> </div> </div> + <div th:if="${fieldType == 'FILE'}" class="form-group row J_for-FILE bosskey-show"> + <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 type="text" class="form-control form-control-sm" id="fileUpdir" th:placeholder="${bundle.L('默认')}" /> + </div> + </div> <div th:if="${fieldType == 'PICKLIST' or fieldType == 'MULTISELECT'}" class="form-group row J_for-PICKLIST J_for-MULTISELECT"> <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"> diff --git a/src/main/resources/web/assets/css/chart-design.css b/src/main/resources/web/assets/css/chart-design.css index b5d3c474ce..02a84e7443 100644 --- a/src/main/resources/web/assets/css/chart-design.css +++ b/src/main/resources/web/assets/css/chart-design.css @@ -101,12 +101,6 @@ See LICENSE and COMMERCIAL in the project root for license information. cursor: default; } -.axis .axis-head > a { - display: inline-block; - padding: 0 3px; - cursor: default; -} - .axis .axis-target { margin-left: 80px; min-height: 30px; diff --git a/src/main/resources/web/assets/js/admin/system-cfg.js b/src/main/resources/web/assets/js/admin/system-cfg.js index 36d1aeb63f..9073b15c58 100644 --- a/src/main/resources/web/assets/js/admin/system-cfg.js +++ b/src/main/resources/web/assets/js/admin/system-cfg.js @@ -358,7 +358,7 @@ class DlgBackup extends RbAlert { <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} disabled={this.state.disable}> + <button type="button" className="btn btn-space btn-primary" onClick={this.confirm} ref={(c) => (this._$btn = c)} data-spinner> {$L('开始备份')} </button> </div> @@ -371,6 +371,7 @@ class DlgBackup extends RbAlert { 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 || {} @@ -380,6 +381,7 @@ class DlgBackup extends RbAlert { RbHighbar.error(res.error_msg) } this.disabled(false, false) + $btn.button('reset') }) } } diff --git a/src/main/resources/web/assets/js/charts/charts.js b/src/main/resources/web/assets/js/charts/charts.js index 163abde834..9c9cb8690c 100644 --- a/src/main/resources/web/assets/js/charts/charts.js +++ b/src/main/resources/web/assets/js/charts/charts.js @@ -413,12 +413,18 @@ const ECHART_LEGEND_VOPT = { textStyle: { fontSize: 12 }, } -// K=千 M=百万 +// K=千 M=百万 B=亿 const shortNumber = function (num) { - if (rb.locale === 'zh_CN' && (num > 10000 || num < -10000)) return (num / 10000).toFixed(1) + '万' - if (num > 1000000 || num < -1000000) return (num / 1000000).toFixed(1) + 'M' + if (rb.locale === 'zh_CN') { + if (num > 100000000 || num < -100000000) return (num / 100000000).toFixed(1) + '亿' + else if (num > 1000000 || num < -1000000) return (num / 1000000).toFixed(1) + '百万' + else if (num > 10000 || num < -10000) return (num / 10000).toFixed(1) + '万' + return num + } + if (num > 100000000 || num < -100000000) return (num / 100000000).toFixed(1) + 'B' + else if (num > 1000000 || num < -1000000) return (num / 1000000).toFixed(1) + 'M' else if (num > 10000 || num < -10000) return (num / 1000).toFixed(1) + 'K' - else return num + return num } // 千分位 @@ -918,6 +924,11 @@ class ApprovalList extends BaseChart { })} </tbody> </table> + {data.overLimit && ( + <div className="m-2 text-center text-warning"> + <i className="mdi mdi-information-outline" /> {$L('最多显示最近 500 条记录')} + </div> + )} </div> ) 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 e6d92c8387..74a4af4d51 100644 --- a/src/main/resources/web/assets/js/general/rb-forms.js +++ b/src/main/resources/web/assets/js/general/rb-forms.js @@ -1857,7 +1857,15 @@ class RbFormFile extends RbFormImage { ) })} <div className={`file-select ${showUpload ? '' : 'hide'}`}> - <input type="file" className="inputfile" ref={(c) => (this._fieldValue__input = c)} id={this._htmlid} accept={this.props.fileSuffix || null} multiple /> + <input + type="file" + className="inputfile" + ref={(c) => (this._fieldValue__input = c)} + id={this._htmlid} + accept={this.props.fileSuffix || null} + multiple + data-updir={this.props.fileUpdir || null} + /> <label htmlFor={this._htmlid} title={$L('拖动或点击选择文件。需要 %s 个', `${this.__minUpload}~${this.__maxUpload}`)} className="btn-secondary" onClick={(e) => this._fileClick(e)}> {this._captureType === 2 ? <span className="mdi mdi-camera" /> : <span className="zmdi zmdi-upload" />} <span className="ml-1">{$L('上传文件')}</span> diff --git a/src/main/resources/web/assets/js/rb-base.js b/src/main/resources/web/assets/js/rb-base.js index 9e17d85687..f8b4e83702 100644 --- a/src/main/resources/web/assets/js/rb-base.js +++ b/src/main/resources/web/assets/js/rb-base.js @@ -192,6 +192,8 @@ See LICENSE and COMMERCIAL in the project root for license information. this.$search.closest('.select2-search--inline').css('width', widthParent) } })(jQuery) +// fix:select2:https://stackoverflow.com/questions/18487056/select2-doesnt-work-when-embedded-in-a-bootstrap-modal +$.fn.modal.Constructor.prototype._enforceFocus = function () {} // extends Array Array.prototype.remove = function (item) { diff --git a/src/main/resources/web/assets/js/trigger/trigger-list.js b/src/main/resources/web/assets/js/trigger/trigger-list.js index f7d9cc269f..4affc8f926 100644 --- a/src/main/resources/web/assets/js/trigger/trigger-list.js +++ b/src/main/resources/web/assets/js/trigger/trigger-list.js @@ -70,19 +70,28 @@ class TriggerList extends ConfigList { <RF> {(this.state.data || []).map((item) => { let targetRef = item[9] + // [ID, NAME] if (targetRef) { - if (targetRef[0] && targetRef[0].startsWith('028-')) { + if (!targetRef[0]) { + targetRef = <a className="text-danger">{targetRef[1]}</a> + } else if (targetRef[0].startsWith('028-')) { targetRef = ( <a href={`${rb.baseUrl}/admin/robot/approval/${targetRef[0]}`} className="light-link" target={`_${targetRef[0]}`}> {targetRef[1]} </a> ) - } else if (targetRef[0] && targetRef[0].startsWith('037-')) { + } else if (targetRef[0].startsWith('037-')) { targetRef = ( <a href={`${rb.baseUrl}/admin/robot/transform/${targetRef[0]}`} className="light-link" target={`_${targetRef[0]}`}> {targetRef[1]} </a> ) + } else if (targetRef[0].startsWith('032-')) { + targetRef = ( + <a href={`${rb.baseUrl}/admin/data/report-templates#gs=${targetRef[0]}`} className="light-link" target={`_${targetRef[0]}`}> + {targetRef[1]} + </a> + ) } else { targetRef = ( <a href={`${rb.baseUrl}/admin/entity/${targetRef[0]}/base`} className="light-link" target={`_${targetRef[0]}`}> diff --git a/src/main/resources/web/assets/js/trigger/trigger.FIELDAGGREGATION.js b/src/main/resources/web/assets/js/trigger/trigger.FIELDAGGREGATION.js index 2c80d86d39..c3962deb6d 100644 --- a/src/main/resources/web/assets/js/trigger/trigger.FIELDAGGREGATION.js +++ b/src/main/resources/web/assets/js/trigger/trigger.FIELDAGGREGATION.js @@ -347,26 +347,26 @@ class ContentFieldAggregation extends ActionContentSpec { $s2sf.trigger('change') // 回填 - const $fbf = $(this._$fillbackField).select2({ placeholder: $L('(可选)'), allowClear: true }) - this.__select2.push($fbf) + const $fbField = $(this._$fillbackField).select2({ placeholder: $L('(可选)'), allowClear: true }) + $fbField.val(null).trigger('change') + this.__select2.push($fbField) this.__select2.push($s2sf) this.__select2.push($s2cm) this.__select2.push($s2tf) - }) - const content = this.props.content - if (content) { - this.setState({ items: content.items || [] }) - if (content.targetEntityMatchFields) { - setTimeout(() => this._MatchFields && this._MatchFields.setState({ groupFields: content.targetEntityMatchFields }), 200) - } - setTimeout(() => { + // init + const content = this.props.content + if (content) { + this.setState({ items: content.items || [] }) + if (content.targetEntityMatchFields) { + this._MatchFields && this._MatchFields.setState({ groupFields: content.targetEntityMatchFields }) + } $(this._$fillbackField) .val(content.fillbackField || null) .trigger('change') - }, 200) - } + } + }) } // v3.7 diff --git a/src/main/resources/web/dashboard/chart-design.html b/src/main/resources/web/dashboard/chart-design.html index 9b71f3946c..9cdc91b157 100644 --- a/src/main/resources/web/dashboard/chart-design.html +++ b/src/main/resources/web/dashboard/chart-design.html @@ -214,14 +214,12 @@ <h5>[[${bundle.L('图表选项')}]]</h5> <div class="axis J_dimension"> <div class="axis-head"> <span>[[${bundle.L('维度')}]]</span> - <a><i class="zmdi zmdi-edit"></i></a> </div> <div class="axis-target J_axis-dim"></div> </div> <div class="axis J_numerical"> <div class="axis-head"> <span>[[${bundle.L('数值')}]]</span> - <a><i class="zmdi zmdi-edit"></i></a> </div> <div class="axis-target J_axis-num"></div> </div> diff --git a/src/main/resources/web/entity/approval/approval-view.html b/src/main/resources/web/entity/approval/approval-view.html index d25640d1a7..4fba28e20d 100644 --- a/src/main/resources/web/entity/approval/approval-view.html +++ b/src/main/resources/web/entity/approval/approval-view.html @@ -23,7 +23,6 @@ <h3 class="title">[[${bundle.L('审批流程')}]]</h3> <span> <a class="close J_close" th:title="${bundle.L('关闭')}"><i class="zmdi zmdi-close"></i></a> - <a class="close sm J_reload" th:title="${bundle.L('刷新')}"><i class="zmdi zmdi-refresh"></i></a> <a class="close sm J_back hide" th:title="${bundle.L('回退')}"><i class="zmdi zmdi-arrow-left"></i></a> </span> </div> diff --git a/src/main/resources/web/notification/messages.html b/src/main/resources/web/notification/messages.html index 0e6d76464f..f05564fb3f 100644 --- a/src/main/resources/web/notification/messages.html +++ b/src/main/resources/web/notification/messages.html @@ -131,9 +131,6 @@ </a> </div> <div class="list-group"> - <a href="#read" data-type="2" class="hide list-group-item d-flex list-group-item-action"> - <span class="text">[[${bundle.L('已读消息')}]]</span> - </a> <a href="#feeds" data-type="30" class="list-group-item d-flex list-group-item-action"> <span class="text">[[${bundle.L('动态')}]]</span> </a> @@ -144,7 +141,7 @@ <span class="text">[[${bundle.L('审批')}]]</span> </a> <a href="#assigns" data-type="10" class="list-group-item d-flex list-group-item-action"> - <span class="text">[[${bundle.L('分配&共享')}]]</span> + <span class="text">[[${bundle.L('分配与共享')}]]</span> </a> </div> </div>