From e03c73338bc1c47e94489c10237d243b95dcc351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?REBUILD=20=E4=BC=81=E4=B8=9A=E7=AE=A1=E7=90=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= <42044143+getrebuild@users.noreply.github.com> Date: Thu, 16 Jan 2025 21:53:48 +0800 Subject: [PATCH] Approval edit details 111 (#860) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * task-num show * feat: 审批可修改字段明细支持 * trigger job cron * entity-truncate --- @rbv | 2 +- .../general/LiteFormBuilder.java | 7 +- .../service/approval/ApprovalStepService.java | 2 +- .../core/service/approval/EditableFields.java | 104 ++++++++++++++++++ .../service/general/GeneralEntityService.java | 2 +- .../GeneralEntityServiceContextHolder.java | 11 +- .../admin/metadata/MetaEntityController.java | 20 ++++ .../robot/approval/ApprovalController.java | 40 ++++--- .../web/admin/bizuser/role-privileges.html | 14 +-- .../web/admin/metadata/entity-advanced.html | 3 + .../web/admin/robot/trigger-design.html | 27 +++-- .../resources/web/assets/css/approvals.css | 7 ++ src/main/resources/web/assets/css/rb-page.css | 11 +- .../resources/web/assets/css/view-page.css | 6 + .../web/assets/js/admin/approval-design.js | 53 ++++++--- .../web/assets/js/bizuser/role-privileges.js | 2 +- .../web/assets/js/general/rb-approval.js | 90 ++++++++++++--- .../web/assets/js/general/rb-forms.append.js | 8 +- .../web/assets/js/metadata/entity-advanced.js | 34 +++++- .../web/assets/js/metadata/field-formula.js | 8 +- .../web/assets/js/project/task-view.js | 1 + .../resources/web/assets/js/rb-components.js | 10 +- .../web/assets/js/trigger/trigger-design.js | 43 +++++--- .../js/trigger/trigger.FIELDAGGREGATION.js | 4 +- 24 files changed, 404 insertions(+), 105 deletions(-) create mode 100644 src/main/java/com/rebuild/core/service/approval/EditableFields.java diff --git a/@rbv b/@rbv index 3e4b5e06e6..fd2547369b 160000 --- a/@rbv +++ b/@rbv @@ -1 +1 @@ -Subproject commit 3e4b5e06e60615f158b71a68e1d52c805a52bf50 +Subproject commit fd2547369b05a1b5e6733772112db14b5328c993 diff --git a/src/main/java/com/rebuild/core/configuration/general/LiteFormBuilder.java b/src/main/java/com/rebuild/core/configuration/general/LiteFormBuilder.java index db14ecb9e2..885fe7c97b 100644 --- a/src/main/java/com/rebuild/core/configuration/general/LiteFormBuilder.java +++ b/src/main/java/com/rebuild/core/configuration/general/LiteFormBuilder.java @@ -15,6 +15,7 @@ import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.service.NoRecordFoundException; import com.rebuild.utils.JSONUtils; +import org.apache.commons.collections4.CollectionUtils; /** * 轻量级表单 @@ -60,9 +61,11 @@ public LiteFormBuilder(Entity entity, ID user) { * @return */ public JSONArray build(JSONArray fieldElements) { - if (fieldElements == null || fieldElements.isEmpty()) { + if (CollectionUtils.isEmpty(fieldElements)) { throw new DefinedException("No field elements"); } + // Use clone + fieldElements = (JSONArray) JSONUtils.clone(fieldElements); Record recordData = null; if (recordId != null) { @@ -85,7 +88,7 @@ public JSONArray build(String[] fields) { for (String field : fields) { if (entity.containsField(field)) { fieldElements.add(JSONUtils.toJSONObject( - new String[] { "field", "colspan" }, new Object[] { field, 4 })); + new String[]{"field", "colspan"}, new Object[]{field, 4})); } } return build(fieldElements); diff --git a/src/main/java/com/rebuild/core/service/approval/ApprovalStepService.java b/src/main/java/com/rebuild/core/service/approval/ApprovalStepService.java index 52e065b753..983796405a 100644 --- a/src/main/java/com/rebuild/core/service/approval/ApprovalStepService.java +++ b/src/main/java/com/rebuild/core/service/approval/ApprovalStepService.java @@ -145,7 +145,7 @@ public void txApprove(Record stepRecord, String signMode, Set ccUsers, Set and/or its owners. All rights reserved. + +rebuild is dual-licensed under commercial and open source licenses (GPLv3). +See LICENSE and COMMERCIAL in the project root for license information. +*/ + +package com.rebuild.core.service.approval; + +import cn.devezhao.persist4j.Entity; +import cn.devezhao.persist4j.engine.ID; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.rebuild.core.configuration.general.LiteFormBuilder; +import com.rebuild.core.metadata.MetadataHelper; +import com.rebuild.core.metadata.easymeta.EasyMetaFactory; +import com.rebuild.core.service.query.QueryHelper; +import com.rebuild.utils.JSONUtils; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 可编辑字段 + * + * @author ZiXin + * @since 2015/1/15 + */ +public class EditableFields { + + private final JSONArray editableFields; + + public EditableFields(JSONArray editableFields) { + this.editableFields = editableFields; + } + + /** + * @param recordId + * @param user + * @return + */ + public JSONObject buildForms(ID recordId, ID user) { + final Entity entity = MetadataHelper.getEntity(recordId.getEntityCode()); + + Map fieldsByEntity = getEditableFieldsByEntity(entity.getName()); + JSONObject aforms = new JSONObject(); + + JSONArray mFields = fieldsByEntity.remove(entity.getName()); + if (CollectionUtils.isNotEmpty(mFields)) { + JSONArray aform = new LiteFormBuilder(recordId, user).build(mFields); + if (CollectionUtils.isNotEmpty(aform)) { + aforms.put("aform", aform); + aforms.put("aentity", entity.getName()); + } + } + + List detailsByEntity = new ArrayList<>(); + for (Map.Entry e : fieldsByEntity.entrySet()) { + Entity dEntity = MetadataHelper.getEntity(e.getKey()); + JSONArray dFields = e.getValue(); + + JSONArray dForms = new JSONArray(); + for (ID did : QueryHelper.detailIdsNoFilter(recordId, dEntity)) { + JSONArray aform = new LiteFormBuilder(did, user).build(dFields); + if (CollectionUtils.isNotEmpty(aform)) { + aform.add(did); // Last is ID + dForms.add(aform); + } + } + + if (!dForms.isEmpty()) { + JSONObject d = JSONUtils.toJSONObject( + new String[]{"aentity", "aentityLabel", "aforms"}, + new Object[]{dEntity.getName(), EasyMetaFactory.getLabel(dEntity), dForms}); + detailsByEntity.add(d); + } + } + + if (!detailsByEntity.isEmpty()) { + aforms.put("aform_details", detailsByEntity); + } + + return aforms; + } + + private Map getEditableFieldsByEntity(String entityName) { + Map fieldsByEntity = new HashMap<>(); + for (Object o : editableFields) { + JSONObject item = (JSONObject) o; + String fieldName = item.getString("field"); + String[] ef; + if (fieldName.contains(".")) ef = fieldName.split("\\."); + else ef = new String[]{entityName, fieldName}; + + JSONArray fields = fieldsByEntity.computeIfAbsent(ef[0], k -> new JSONArray()); + item.put("field", ef[1]); + fields.add(item); + } + return fieldsByEntity; + } +} diff --git a/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java b/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java index 7377255188..bed81ae096 100644 --- a/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java +++ b/src/main/java/com/rebuild/core/service/general/GeneralEntityService.java @@ -648,7 +648,7 @@ protected boolean checkModifications(Record record, Permission action) throws Da // 审批时/已通过强制修改 if (unallow) { - boolean forceUpdate = GeneralEntityServiceContextHolder.isAllowForceUpdateOnce(); + boolean forceUpdate = GeneralEntityServiceContextHolder.isAllowForceUpdate(false); if (forceUpdate) unallow = false; } } diff --git a/src/main/java/com/rebuild/core/service/general/GeneralEntityServiceContextHolder.java b/src/main/java/com/rebuild/core/service/general/GeneralEntityServiceContextHolder.java index e0e8f57563..90c4475a5a 100644 --- a/src/main/java/com/rebuild/core/service/general/GeneralEntityServiceContextHolder.java +++ b/src/main/java/com/rebuild/core/service/general/GeneralEntityServiceContextHolder.java @@ -63,8 +63,17 @@ public static void setAllowForceUpdate(ID recordId) { * @see #setAllowForceUpdate(ID) */ public static boolean isAllowForceUpdateOnce() { + return isAllowForceUpdate(true); + } + + /** + * @param once + * @return + * @see #setAllowForceUpdate(ID) + */ + public static boolean isAllowForceUpdate(boolean once) { ID recordId = ALLOW_FORCE_UPDATE.get(); - if (recordId != null) ALLOW_FORCE_UPDATE.remove(); + if (recordId != null && once) ALLOW_FORCE_UPDATE.remove(); return recordId != null; } diff --git a/src/main/java/com/rebuild/web/admin/metadata/MetaEntityController.java b/src/main/java/com/rebuild/web/admin/metadata/MetaEntityController.java index 7156382eab..08b942c776 100644 --- a/src/main/java/com/rebuild/web/admin/metadata/MetaEntityController.java +++ b/src/main/java/com/rebuild/web/admin/metadata/MetaEntityController.java @@ -37,6 +37,7 @@ import com.rebuild.core.privileges.UserHelper; import com.rebuild.core.rbstore.MetaschemaExporter; import com.rebuild.core.service.general.QuickCodeReindexTask; +import com.rebuild.core.service.general.series.SeriesGeneratorFactory; import com.rebuild.core.support.RebuildConfiguration; import com.rebuild.core.support.general.FieldValueHelper; import com.rebuild.core.support.task.TaskExecutors; @@ -262,6 +263,25 @@ public RespBody entityDrop(HttpServletRequest request) { } } + @RequestMapping("entity/entity-truncate") + public RespBody entityTruncate(HttpServletRequest request) { + final Entity entity = getEntityById(getIdParameterNotNull(request, "id")); + + try { + String dsql = String.format("TRUNCATE TABLE `%s`", entity.getPhysicalName()); + Application.getSqlExecutor().execute(dsql); + // 置零 + for (Field s : MetadataSorter.sortFields(entity, DisplayType.SERIES)) { + SeriesGeneratorFactory.zero(s); + } + return RespBody.ok(); + + } catch (Exception ex) { + log.error("entity-truncate", ex); + return RespBody.error(ex.getLocalizedMessage()); + } + } + @GetMapping("entity/entity-export") public void entityExport(HttpServletRequest request, HttpServletResponse response) throws IOException { final Entity entity = getEntityById(getIdParameterNotNull(request, "id")); diff --git a/src/main/java/com/rebuild/web/robot/approval/ApprovalController.java b/src/main/java/com/rebuild/web/robot/approval/ApprovalController.java index 1f77727cf3..279f621a1a 100644 --- a/src/main/java/com/rebuild/web/robot/approval/ApprovalController.java +++ b/src/main/java/com/rebuild/web/robot/approval/ApprovalController.java @@ -17,7 +17,6 @@ import com.rebuild.api.RespBody; import com.rebuild.core.Application; import com.rebuild.core.DefinedException; -import com.rebuild.core.configuration.general.LiteFormBuilder; import com.rebuild.core.metadata.EntityHelper; import com.rebuild.core.metadata.MetadataHelper; import com.rebuild.core.privileges.UserHelper; @@ -29,16 +28,19 @@ import com.rebuild.core.service.approval.ApprovalState; import com.rebuild.core.service.approval.ApprovalStatus; import com.rebuild.core.service.approval.ApprovalStepService; +import com.rebuild.core.service.approval.EditableFields; import com.rebuild.core.service.approval.FlowDefinition; import com.rebuild.core.service.approval.FlowNode; import com.rebuild.core.service.approval.FlowNodeGroup; import com.rebuild.core.service.approval.RobotApprovalManager; +import com.rebuild.core.service.general.GeneralEntityService; import com.rebuild.core.service.trigger.DataValidateException; import com.rebuild.utils.CommonsUtils; import com.rebuild.utils.JSONUtils; import com.rebuild.web.BaseController; import com.rebuild.web.IdParam; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.transaction.UnexpectedRollbackException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -48,7 +50,9 @@ import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Set; import static com.rebuild.core.privileges.bizz.ZeroEntry.AllowRevokeApproval; @@ -173,11 +177,7 @@ public JSON fetchNextStep(HttpServletRequest request, // 可修改字段 JSONArray editableFields = currentFlowNode.getEditableFields(); if (editableFields != null && !editableFields.isEmpty()) { - JSONArray aform = new LiteFormBuilder(recordId, user).build(editableFields); - if (aform != null && !aform.isEmpty()) { - data.put("aform", aform); - data.put("aentity", MetadataHelper.getEntityName(recordId)); - } + data.putAll(new EditableFields(editableFields).buildForms(recordId, user)); } return data; @@ -185,9 +185,7 @@ public JSON fetchNextStep(HttpServletRequest request, private JSONArray formatUsers(Collection users) { JSONArray array = new JSONArray(); - for (ID u : users) { - array.add(new Object[] { u, UserHelper.getName(u) }); - } + for (ID u : users) array.add(new Object[]{u, UserHelper.getName(u)}); return array; } @@ -227,13 +225,22 @@ public RespBody doApprove(HttpServletRequest request, @IdParam(name = "record") String useGroup = post.getString("useGroup"); // 可编辑字段 - JSONObject aformData = post.getJSONObject("aformData"); + JSONArray aformData = post.getJSONArray("aformData"); Record addedRecord = null; // v3.9 弱校验 final ID weakMode = getIdParameter(request, "weakMode"); - if (aformData != null && aformData.size() > 1) { + if (CollectionUtils.isNotEmpty(aformData)) { + List details = new ArrayList<>(); try { - addedRecord = EntityHelper.parse(aformData, getRequestUser(request)); + for (Object o : aformData) { + Record a = EntityHelper.parse((JSONObject) o, approver); + if (a.getEntity().getEntityCode().equals(recordId.getEntityCode())) addedRecord = a; + else details.add(a); + } + + if (addedRecord == null) addedRecord = EntityHelper.forUpdate(recordId, approver); + if (!details.isEmpty()) addedRecord.setObjectValue(GeneralEntityService.HAS_DETAILS, details); + } catch (DataSpecificationException known) { log.warn(">>>>> {}", known.getLocalizedMessage()); return RespBody.error(known.getLocalizedMessage()); @@ -349,12 +356,11 @@ public RespBody getFlowDefinition(@IdParam ID approvalId) { return RespBody.errorl("无效审批流程,可能已被删除"); } - FlowDefinition def = RobotApprovalManager.instance - .getFlowDefinition(MetadataHelper.getEntity((String) belongEntity[0]), approvalId); - + Entity applyEntity = MetadataHelper.getEntity((String) belongEntity[0]); + FlowDefinition def = RobotApprovalManager.instance.getFlowDefinition(applyEntity, approvalId); JSONObject data = JSONUtils.toJSONObject( - new String[] { "applyEntity", "flowDefinition" }, - new Object[] { belongEntity[0], def.getJSON("flowDefinition") }); + new String[]{"applyEntity", "flowDefinition"}, + new Object[]{applyEntity.getName(), def.getJSON("flowDefinition")}); return RespBody.ok(data); } diff --git a/src/main/resources/web/admin/bizuser/role-privileges.html b/src/main/resources/web/admin/bizuser/role-privileges.html index 35bf204c24..9adab0d729 100644 --- a/src/main/resources/web/admin/bizuser/role-privileges.html +++ b/src/main/resources/web/admin/bizuser/role-privileges.html @@ -77,7 +77,7 @@ margin-left: 15px; margin-top: 2px; font-size: 15px; - color: #999; + color: #999 !important; display: none; } .table.table-priv tr:hover > td > a.cp, @@ -174,29 +174,29 @@ [[${entity[2]}]] - + - + - + - + - + - + diff --git a/src/main/resources/web/admin/metadata/entity-advanced.html b/src/main/resources/web/admin/metadata/entity-advanced.html index 074b4541f9..2c74be121a 100644 --- a/src/main/resources/web/admin/metadata/entity-advanced.html +++ b/src/main/resources/web/admin/metadata/entity-advanced.html @@ -132,6 +132,9 @@
[[${bundle.L('卡片模式')}]]
+
[[${bundle.L('系统内置,不允许删除')}]]
diff --git a/src/main/resources/web/admin/robot/trigger-design.html b/src/main/resources/web/admin/robot/trigger-design.html index e6bd69548e..8a4bbd07ef 100644 --- a/src/main/resources/web/admin/robot/trigger-design.html +++ b/src/main/resources/web/admin/robot/trigger-design.html @@ -100,17 +100,24 @@ + - [[${bundle.L('执行')}]] - - [[${bundle.L('次')}]] - [[${bundle.L('执行时段')}]] - - ~ - - - [[${bundle.L('执行日期')}]] (LAB) - + + [[${bundle.L('执行')}]] + + [[${bundle.L('次')}]] + [[${bundle.L('执行时段')}]] + + ~ + + + [[${bundle.L('执行日期')}]] (LAB) + + + + + [[${bundle.L('CRON 表达式')}]] +

[[${bundle.L('具体执行时间将在你设定的周期内平均分布。例如每天执行 2 次,其执行时间为 00:00 和 12:00')}]]

diff --git a/src/main/resources/web/assets/css/approvals.css b/src/main/resources/web/assets/css/approvals.css index 8ec0c7eba4..9a9ddcc786 100644 --- a/src/main/resources/web/assets/css/approvals.css +++ b/src/main/resources/web/assets/css/approvals.css @@ -724,3 +724,10 @@ See LICENSE and COMMERCIAL in the project root for license information. .expires-notify-set select { width: 232px; } + +.updatable-fields h4 { + font-size: 1rem; + font-weight: bold; + border-bottom: 1px solid #eee; + padding-bottom: 10px; +} diff --git a/src/main/resources/web/assets/css/rb-page.css b/src/main/resources/web/assets/css/rb-page.css index afe682d4c9..73c82855ce 100644 --- a/src/main/resources/web/assets/css/rb-page.css +++ b/src/main/resources/web/assets/css/rb-page.css @@ -3280,7 +3280,7 @@ a.user-show:not([href]) { margin-top: 2px; } -.form.approval-form .rbform { +.form.approval-form .aforms { background-color: #f5f5f5; border-radius: 2px; padding: 15px; @@ -3288,6 +3288,15 @@ a.user-show:not([href]) { box-shadow: inset 0 0 10px rgba(230, 230, 230, 0.6); } +.form.approval-form .aforms .aforms-detail > h5 { + font-size: 14px; + font-weight: bold; + background-color: #eceff1; + padding: 12px 15px; + margin: 10px 0; + border-radius: 2px; +} + .form.approval-form .approval-list { padding: 5px 0; } diff --git a/src/main/resources/web/assets/css/view-page.css b/src/main/resources/web/assets/css/view-page.css index e6c4d8ce45..1ca4fdf1f1 100644 --- a/src/main/resources/web/assets/css/view-page.css +++ b/src/main/resources/web/assets/css/view-page.css @@ -74,6 +74,12 @@ body { max-width: 80%; } +.view-header .title > .badge { + position: absolute; + margin-left: 6px; + margin-top: 5px; +} + .view-header > span > .close { font-size: 1.638rem; opacity: 0.6; diff --git a/src/main/resources/web/assets/js/admin/approval-design.js b/src/main/resources/web/assets/js/admin/approval-design.js index 6c234026f2..fe7aee0914 100644 --- a/src/main/resources/web/assets/js/admin/approval-design.js +++ b/src/main/resources/web/assets/js/admin/approval-design.js @@ -22,7 +22,12 @@ $(document).ready(() => { if (rb.env === 'dev') console.log(wpc.flowDefinition) // 备用 - $.get(`/commons/metadata/fields?entity=${wpc.applyEntity}`, (res) => (fieldsCache = res.data)) + $.get(`/commons/metadata/entity-and-details?entity=${wpc.applyEntity}`, (res) => { + fieldsCache = [...res.data] + fieldsCache.forEach((e) => { + $.get(`/commons/metadata/fields?entity=${e.entity}`, (res2) => (e.fields = res2.data || [])) + }) + }) renderRbcomp(, 'rbflow') @@ -940,8 +945,12 @@ class ApproverNodeConfig extends StartNodeConfig { } __fieldLabel(name) { - const field = fieldsCache.find((x) => x.name === name) - return field ? field.label : `[${name.toUpperCase()}]` + const s = name.includes('.') ? name.split('.') : [wpc.applyEntity, name] + const fsMeta = fieldsCache.find((x) => x.entity === s[0]) + + let field = fsMeta.fields.find((x) => x.name === s[1]) + field = field ? field.label : `[${name.toUpperCase()}]` + return name.includes('.') ? `${fsMeta.entityLabel}.${field}` : field } } @@ -1151,27 +1160,37 @@ class DlgFields extends RbModalHandler { render() { return ( - (this._dlg = c)} disposeOnHide onHide={() => (donotCloseSidebar = false)}> -
(this._fields = c)}> - {fieldsCache.map((item) => { - if (item.type === 'BARCODE') return null + (this._dlg = c)} disposeOnHide onHide={() => (donotCloseSidebar = false)} width="780"> +
(this._fields = c)}> + {fieldsCache.map((e) => { return ( -
- -
+ +

{e.entityLabel}

+
+ {e.fields.map((item) => { + if (item.type === 'BARCODE' || item.updatable === false) return null + const name = e.mainEntity ? `${e.entity}.${item.name}` : item.name + return ( +
+ +
+ ) + })} +
+
) })}
- - +
) diff --git a/src/main/resources/web/assets/js/bizuser/role-privileges.js b/src/main/resources/web/assets/js/bizuser/role-privileges.js index 268a2a0c13..41a9521814 100644 --- a/src/main/resources/web/assets/js/bizuser/role-privileges.js +++ b/src/main/resources/web/assets/js/bizuser/role-privileges.js @@ -451,7 +451,7 @@ class FieldsPrivileges extends RbModalHandler { ) })} -
+
{this.state.entityAndDetails && this.state.entityAndDetails.map((item, idx) => { return ( diff --git a/src/main/resources/web/assets/js/general/rb-approval.js b/src/main/resources/web/assets/js/general/rb-approval.js index 5b05b72216..9c071e23d9 100644 --- a/src/main/resources/web/assets/js/general/rb-approval.js +++ b/src/main/resources/web/assets/js/general/rb-approval.js @@ -482,7 +482,7 @@ class ApprovalApproveForm extends ApprovalUsersForm {
)} - {this.state.aform && this.renderLiteForm()} + {(this.state.aform || this.state.aform_details) && this.renderLiteForm()}
@@ -539,23 +539,10 @@ class ApprovalApproveForm extends ApprovalUsersForm { } renderLiteForm() { - const fake = { - state: { id: this.props.id }, - } - - // @see rb-forms.append.js LiteFormModal#create - return (
- (this._LiteForm = c)}> - {this.state.aform.map((item) => { - item.isFull = true - delete item.referenceQuickNew // v35 - // eslint-disable-next-line no-undef - return detectElement(item) - })} - + (this._EditableFieldForms = c)} />
) } @@ -610,9 +597,10 @@ class ApprovalApproveForm extends ApprovalUsersForm { } _post(state, rejectNode, _alert, weakMode) { - let aformData = {} - if (this.state.aform && state === 10) { - aformData = this._LiteForm.buildFormData() + let aformData = [] + if ((this.state.aform || this.state.aform_details) && state === 10) { + // aformData = this._LiteForm.buildFormData() + aformData = this._EditableFieldForms.buildFormsData() if (aformData === false) return } @@ -982,6 +970,72 @@ class ApprovalStepViewer extends React.Component { } } +class EditableFieldForms extends React.Component { + constructor(props) { + super(props) + + this._fakeParent = { + state: { id: props._this.props.id }, + } + this._LiteForms = [] + } + + render() { + const _this = this.props._this + const _details = _this.state.aform_details + return ( +
+ {_this.state.aform && this._renderLiteForm(_this.props.entity, _this.props.id, _this.state.aform)} + {_details && this._renderDetails(_details)} +
+ ) + } + + _renderDetails(details) { + return details.map((d) => { + return ( +
+
+ {d.aentityLabel} ({d.aforms.length}) +
+ {d.aforms.map((aform) => { + const id = aform[aform.length - 1] + aform.pop() + return this._renderLiteForm(d.aentity, id, aform) + })} +
+ ) + }) + } + + _renderLiteForm(entity, id, aform) { + // @see rb-forms.append.js LiteFormModal#create + return ( + this._LiteForms.push(c)} key={id}> + {aform.map((item) => { + item.isFull = true + delete item.referenceQuickNew // v35 + // eslint-disable-next-line no-undef + return detectElement(item) + })} + + ) + } + + buildFormsData() { + let datas = [] + for (let i = 0; i < this._LiteForms.length; i++) { + const aformData = this._LiteForms[i].buildFormData() + if (aformData === false) { + datas = false + break + } + datas.push(aformData) + } + return datas + } +} + // 刷新页面 const _reloadAndTips = function (dlg, msg) { dlg && dlg.hide(true) diff --git a/src/main/resources/web/assets/js/general/rb-forms.append.js b/src/main/resources/web/assets/js/general/rb-forms.append.js index 38a892c622..36d073a777 100644 --- a/src/main/resources/web/assets/js/general/rb-forms.append.js +++ b/src/main/resources/web/assets/js/general/rb-forms.append.js @@ -1017,6 +1017,9 @@ const EasyFilterEval = { __timer: null, evalAndEffect: function (form) { + // LiteForm or others + if (!form.props.rawModel.layoutId) return + if (this.__timer) { clearTimeout(this.__timer) this.__timer = null @@ -1028,9 +1031,8 @@ const EasyFilterEval = { const _this = form $.post(`/app/entity/extras/easyfilter-eval?layout=${_this.props.rawModel.layoutId}`, JSON.stringify(_this.getFormData()), (res) => { const attrs = res.data || [] - const attrsLast = form.__lastEasyFilterEval || [] - form.__lastEasyFilterEval = attrs // 绑定到表单对象 - console.log('Eval ...', JSON.stringify(attrs)) + const attrsLast = _this.__lastEasyFilterEval || [] + _this.__lastEasyFilterEval = attrs // 绑定到表单对象 attrs.forEach((a) => { const fieldComp = _this.getFieldComp(a.field) diff --git a/src/main/resources/web/assets/js/metadata/entity-advanced.js b/src/main/resources/web/assets/js/metadata/entity-advanced.js index 1e0ff299c2..305bbe57c4 100644 --- a/src/main/resources/web/assets/js/metadata/entity-advanced.js +++ b/src/main/resources/web/assets/js/metadata/entity-advanced.js @@ -16,15 +16,17 @@ $(document).ready(() => { if (!metaid) { $('.J_drop-confirm').next().removeClass('hide') $('.J_drop-confirm').remove() + $('.J_truncate-confirm').remove() $('.J_drop-check').parent().parent().remove() return } + const $confirm = $('.J_drop-confirm, .J_truncate-confirm') $('.J_drop-check').on('click', function () { - $('.J_drop-confirm').attr('disabled', !$(this).prop('checked')) + $confirm.attr('disabled', !$(this).prop('checked')) }) - const $drop = $('.J_drop-confirm').on('click', () => { + $('.J_drop-confirm').on('click', () => { if (!$('.J_drop-check').prop('checked')) return if (!window.__PageConfig.isSuperAdmin) { RbHighbar.error($L('仅超级管理员可删除实体')) @@ -35,7 +37,7 @@ $(document).ready(() => { type: 'danger', confirmText: $L('删除'), confirm: function () { - $drop.button('loading') + $confirm.button('loading') this.disabled(true) $.post(`../entity-drop?id=${metaid}&force=${$('.J_drop-force').prop('checked')}`, (res) => { if (res.error_code === 0) { @@ -50,6 +52,32 @@ $(document).ready(() => { countdown: 5, }) }) + $('.J_truncate-confirm').on('click', () => { + if (!$('.J_drop-check').prop('checked')) return + if (!window.__PageConfig.isSuperAdmin) { + RbHighbar.error($L('仅超级管理员可清空数据')) + return + } + + RbAlert.create($L('此操作将直接清空数据,不会保留在回收站及触发相关业务规则。'), $L('清空数据'), { + type: 'danger', + confirmText: $L('清空'), + confirm: function () { + $confirm.button('loading') + this.disabled(true) + $.post(`../entity-truncate?id=${metaid}`, (res) => { + if (res.error_code === 0) { + RbHighbar.success($L('数据已清空')) + setTimeout(() => location.reload(), 1500) + } else { + RbHighbar.error(res.error_msg) + this.disabled() + } + }) + }, + countdown: 5, + }) + }) }) // 列表模式 diff --git a/src/main/resources/web/assets/js/metadata/field-formula.js b/src/main/resources/web/assets/js/metadata/field-formula.js index 3bb70003e1..80fccef0e7 100644 --- a/src/main/resources/web/assets/js/metadata/field-formula.js +++ b/src/main/resources/web/assets/js/metadata/field-formula.js @@ -335,11 +335,11 @@ class MatchFields extends React.Component { // fix:3.8.2 _groupFields38() { - let groupFields = this.state.groupFields - if (groupFields && typeof groupFields === 'string') { - eval(`groupFields = ${groupFields}`) + let _groupFields = this.state.groupFields + if (_groupFields && typeof _groupFields === 'string') { + eval(`_groupFields = ${_groupFields}`) } - return groupFields + return _groupFields } render() { diff --git a/src/main/resources/web/assets/js/project/task-view.js b/src/main/resources/web/assets/js/project/task-view.js index a3e478152d..99202bcc6f 100644 --- a/src/main/resources/web/assets/js/project/task-view.js +++ b/src/main/resources/web/assets/js/project/task-view.js @@ -138,6 +138,7 @@ class TaskForm extends React.Component { $.get(`/project/tasks/details?task=${this.props.id}`, (res) => { if (res.error_code === 0) { this.setState({ ...res.data }, () => $(this._status).prop('checked', this.state.status === 1)) + $(`${res.data.taskNumber}`).appendTo('.view-header .title') } else { RbHighbar.error(res.error_msg) } diff --git a/src/main/resources/web/assets/js/rb-components.js b/src/main/resources/web/assets/js/rb-components.js index e3fe625e57..09604245fb 100644 --- a/src/main/resources/web/assets/js/rb-components.js +++ b/src/main/resources/web/assets/js/rb-components.js @@ -473,14 +473,16 @@ class RbAlertBox extends React.Component { if (!icon) icon = type === 'success' ? 'check' : type === 'danger' ? 'close-circle-o' : 'info-outline' return ( -
(this._element = c)}> + diff --git a/src/main/resources/web/assets/js/trigger/trigger-design.js b/src/main/resources/web/assets/js/trigger/trigger-design.js index 5240f78895..9fb18b38a5 100644 --- a/src/main/resources/web/assets/js/trigger/trigger-design.js +++ b/src/main/resources/web/assets/js/trigger/trigger-design.js @@ -32,6 +32,21 @@ $(document).ready(() => { }) $('.J_startHour2').val('23') + $('.J_whenTimer1').on('change', function (e) { + if (e.target.value === 'cron') { + $('.J_timerSimple').addClass('hide') + $('.J_timerCron').removeClass('hide') + } else { + $('.J_timerSimple').removeClass('hide') + $('.J_timerCron').addClass('hide') + } + }) + function _buildWhenTimer() { + let wt = $('.J_whenTimer1').val() || 'D' + if (wt === 'cron') return wt + ':' + ($('.J_whenTimer9').val() || '0 0 * * * ?') + return wt + `:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}:${$('.J_whenTimer4').val() || ''}` + } + if (wpc.when > 0) { $([1, 2, 4, 16, 32, 64, 128, 256, 512, 1024, 2048]).each(function () { let mask = this @@ -42,13 +57,17 @@ $(document).ready(() => { $('.on-timers').removeClass('hide') const wt = (wpc.whenTimer || 'D:1').split(':') $('.J_whenTimer1').val(wt[0]) - $('.J_whenTimer2').val(wt[1]) - // v2.9 - if (wt[2]) $('.J_startHour1').val(wt[2]) - if (wt[3]) $('.J_startHour2').val(wt[3]) - // v3.8 - if (wt[4]) $('.J_whenTimer4').val(wt[4]).parents('.bosskey-show').removeClass('bosskey-show') - + // v4.0 + if (wt[0] === 'cron') { + $('.J_whenTimer9').val(wt[1]) + } else { + $('.J_whenTimer2').val(wt[1]) + // v2.9 + if (wt[2]) $('.J_startHour1').val(wt[2]) + if (wt[3]) $('.J_startHour2').val(wt[3]) + // v3.8 + if (wt[4]) $('.J_whenTimer4').val(wt[4]).parents('.bosskey-show').removeClass('bosskey-show') + } $('.J_whenTimer1').trigger('change') } } @@ -57,15 +76,15 @@ $(document).ready(() => { // 评估具体执行时间 function evalTriggerTimes() { - const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}:${$('.J_whenTimer4').val() || ''}` - $.get(`/admin/robot/trigger/eval-trigger-times?whenTimer=${whenTimer}`, (res) => { + $.get(`/admin/robot/trigger/eval-trigger-times?whenTimer=${_buildWhenTimer()}`, (res) => { renderRbcomp( {$L('预计执行时间 (最多显示近 9 次)')} : - {res.data.slice(0, 9).join(', ')} + {res.data.length > 0 ? res.data.slice(0, 9).join(', ') : $L('无')}
} />, @@ -143,8 +162,6 @@ $(document).ready(() => { return } - const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}:${$('.J_whenTimer4').val() || ''}` - const content = contentComp.buildContent() if (content === false) return @@ -152,7 +169,7 @@ $(document).ready(() => { if (window.whenApproveNodes) content.whenApproveNodes = window.whenApproveNodes const data = { when: when, - whenTimer: whenTimer, + whenTimer: _buildWhenTimer(), whenFilter: wpc.whenFilter || null, actionContent: content, metadata: { 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 c3962deb6d..5a12e613bc 100644 --- a/src/main/resources/web/assets/js/trigger/trigger.FIELDAGGREGATION.js +++ b/src/main/resources/web/assets/js/trigger/trigger.FIELDAGGREGATION.js @@ -360,7 +360,9 @@ class ContentFieldAggregation extends ActionContentSpec { if (content) { this.setState({ items: content.items || [] }) if (content.targetEntityMatchFields) { - this._MatchFields && this._MatchFields.setState({ groupFields: content.targetEntityMatchFields }) + setTimeout(() => { + this._MatchFields && this._MatchFields.setState({ groupFields: content.targetEntityMatchFields }) + }, 200) } $(this._$fillbackField) .val(content.fillbackField || null)