signatories;
-}
+ public String getTenantId() {
+ if (NumberUtils.isDigits(tenantId)) {
+ return tenantId;
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BaseBpmnTaskDelegateAssigner.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BaseBpmnTaskDelegateAssigner.java
new file mode 100644
index 000000000..a50fff4aa
--- /dev/null
+++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BaseBpmnTaskDelegateAssigner.java
@@ -0,0 +1,30 @@
+package cn.axzo.workflow.common.model.request.bpmn.task;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+/**
+ * 一些审批人模型的扩展信息
+ *
+ * @author wangli
+ * @since 2025-06-28 13:17
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public abstract class BaseBpmnTaskDelegateAssigner {
+
+ /**
+ * 人员标签
+ * 0: 注销 1:离场 2: 离职
+ */
+ private Integer tag;
+
+ /**
+ * 是否能提级审批
+ */
+ private Boolean supportUpgradeApproval;
+}
diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java
index 286bf2b1f..cbeb86c51 100644
--- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java
+++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskDelegateAssigner.java
@@ -6,6 +6,7 @@ import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
@@ -36,6 +37,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.ROBOT_ASSIGNEE_ID;
*
* @author wangli
*/
+@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@NoArgsConstructor
@@ -43,7 +45,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.ROBOT_ASSIGNEE_ID;
@Accessors(chain = true)
@Validated
@Slf4j
-public class BpmnTaskDelegateAssigner implements Serializable {
+public class BpmnTaskDelegateAssigner extends BaseBpmnTaskDelegateAssigner implements Serializable {
private static final long serialVersionUID = -8106887960942113552L;
@@ -114,13 +116,6 @@ public class BpmnTaskDelegateAssigner implements Serializable {
*/
private String nodeId;
- /**
- * 扩展字段, 业务无需关系
- *
- * 仅用于日志展示人的一些状态信息
- */
- private JSONObject ext;
-
public final String buildAssigneeId_1_2_1() {
if (StringUtils.hasLength(assigneeType)) {
return tenantId + "|" + assignee + "|" + assigneeType;
@@ -149,7 +144,7 @@ public class BpmnTaskDelegateAssigner implements Serializable {
this.tenantId = tenantId;
}
- public BpmnTaskDelegateAssigner(String assignee, String assigneeType, String assignerName, String personId, String tenantId, String ouId, String avatar, String nodeId) {
+ public BpmnTaskDelegateAssigner(String assignee, String assigneeType, String assignerName, String personId, String tenantId) {
this.assignerName = assignerName;
this.personId = personId;
this.tenantId = tenantId;
diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskResetApproversDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskResetApproversDTO.java
new file mode 100644
index 000000000..c8f2e9305
--- /dev/null
+++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/task/BpmnTaskResetApproversDTO.java
@@ -0,0 +1,80 @@
+package cn.axzo.workflow.common.model.request.bpmn.task;
+
+import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
+import cn.axzo.workflow.common.constraint.AttachmentValidator;
+import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 重置指定节点下的所有审批人
+ *
+ * @author wangli
+ * @since 2025-06-24 17:07
+ */
+@Data
+@Accessors(chain = true)
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class BpmnTaskResetApproversDTO implements Serializable {
+ private static final long serialVersionUID = 4570922472032531513L;
+
+ /**
+ * 审批任务ID
+ */
+ @ApiModelProperty(value = "审批任务ID")
+ @NotEmpty(message = "任务ID不能为空")
+ private String taskId;
+
+ /**
+ * 加签意见
+ */
+ @ApiModelProperty(value = "提级意见")
+ private String advice;
+
+ /**
+ * 附件列表
+ */
+ @ApiModelProperty(value = "附件列表")
+ @Size(max = 11, message = "附件数量超过限制")
+ @AttachmentValidator(types = {
+ @AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
+ @AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
+ @AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
+ )
+ private List attachmentList;
+
+ /**
+ * 任务提级给谁审批
+ */
+ @ApiModelProperty(value = "任务提级给谁审批")
+ @NotEmpty(message = "任务接收人不能为空")
+ private List targetAssignerList;
+
+ /**
+ * 任务操作人
+ */
+ @ApiModelProperty(value = "任务原发起人")
+ @Valid
+ @NotNull(message = "任务发起人不能为空")
+ private BpmnTaskDelegateAssigner originAssigner;
+
+ /**
+ * 是否异步执行
+ */
+ @ApiModelProperty(value = "是否异步", notes = "异步时,只接收请求便返回数据")
+ @Builder.Default
+ private Boolean async = true;
+}
diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/ProcessNodeDetailVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/ProcessNodeDetailVO.java
index 0080dabd2..145e113eb 100644
--- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/ProcessNodeDetailVO.java
+++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/process/ProcessNodeDetailVO.java
@@ -4,6 +4,7 @@ import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
+import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -56,4 +57,13 @@ public class ProcessNodeDetailVO {
*/
private List forecastAssigners;
+ /**
+ * 提级审批配置
+ */
+ private BpmnUpgradeApprovalConf upgradeApprovalConf;
+
+ /**
+ * 是未来节点
+ */
+ private Boolean futureNode;
}
diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java
index 6671f6e11..d4322ce5f 100644
--- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java
+++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/response/bpmn/task/BpmnTaskInstanceLogVO.java
@@ -5,6 +5,7 @@ import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
+import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel;
@@ -124,6 +125,12 @@ public class BpmnTaskInstanceLogVO {
@ApiModelProperty(value = "未完成节点多实例模式的审批人信息")
private List forecastAssignees;
+ /**
+ * 提级审批配置
+ */
+ @ApiModelProperty(value = "提级审批配置")
+ private BpmnUpgradeApprovalConf upgradeApprovalConf;
+
@ApiModelProperty(value = "程序计算按钮使用,非对外使用", hidden = true)
private transient BpmnButtonConf buttonConf;
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java
index d5fc06b04..fe050478b 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnJsonConverterUtil.java
@@ -12,6 +12,7 @@ import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
import cn.axzo.workflow.common.model.request.bpmn.BpmnNoticeConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignApproverLimit;
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignConf;
+import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf;
import cn.axzo.workflow.common.model.request.bpmn.model.BpmnModelCreateDTO;
import cn.axzo.workflow.core.converter.json.AbstractBpmnJsonConverter;
import cn.axzo.workflow.core.converter.json.BoundaryEventJsonConverter;
@@ -125,6 +126,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNoticeC
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getProcessApproveConf;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSignApproverLimit;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSignConfig;
+import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getUpgradeApprovalConf;
/**
* BPMN json 格式转换工具
@@ -821,8 +823,9 @@ public final class BpmnJsonConverterUtil {
getSignConfig(bpmnModel.getMainProcess());
BpmnJsonModel bpmnJsonModel = convertToJson(bpmnModel);
- FlowElement flowElement = bpmnModel.getFlowElement("node_350811186561");
- Optional signApproverLimit = getSignApproverLimit(flowElement);
+ FlowElement flowElement = bpmnModel.getFlowElement("node_350687681316");
+ Optional upgradeApprovalConf = getUpgradeApprovalConf(flowElement);
+// Optional signApproverLimit = getSignApproverLimit(flowElement);
// ServiceTask serviceTask = (ServiceTask) bpmnModel.getFlowElement("node_946990365785");
// Optional> carbonCopyConfigs = BpmnMetaParserHelper.getCarbonCopyConfigs
// (serviceTask);
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java
index 379805f64..9a6cc1f19 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/utils/BpmnMetaParserHelper.java
@@ -26,6 +26,7 @@ import cn.axzo.workflow.common.model.request.bpmn.BpmnSignApproverLimit;
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignPendingProperty;
import cn.axzo.workflow.common.model.request.bpmn.BpmnSmsProperty;
+import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf;
import cn.axzo.workflow.common.model.request.form.FormPermissionMetaInfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
@@ -83,12 +84,14 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVE
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ORG_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ROLE_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_TYPE;
+import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_APPROVER_SPECIFY;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CHECKED;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CODE;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_DISABLED;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_KEY;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_NAME;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_ORDER;
+import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_ORG_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE;
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION;
@@ -105,6 +108,9 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_NOTICE_MES
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_PENDING_MESSAGE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_SIGN_PENDING_MESSAGE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_SMS_MESSAGE_ID;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_CONF;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE;
import static cn.axzo.workflow.common.constant.BpmnConstants.USER_AGREE_SIGNATURE_DEFAULT_VALUE;
/**
@@ -570,6 +576,26 @@ public final class BpmnMetaParserHelper {
return permissionResult;
}
+ public static Optional getUpgradeApprovalConf(FlowElement flowElement) {
+ if (Objects.isNull(flowElement) || !(flowElement instanceof UserTask)) {
+ return Optional.empty();
+ }
+ return getUpgradeApprovalConf((UserTask) flowElement);
+ }
+
+ public static Optional getUpgradeApprovalConf(UserTask userTask) {
+ return defaultValid(userTask, TEMPLATE_UPGRADE_APPROVAL_CONF).map(element -> {
+ BpmnUpgradeApprovalConf conf = new BpmnUpgradeApprovalConf();
+ Boolean enabled = Boolean.valueOf(element.getAttributeValue(null, ELEMENT_ATTRIBUTE_CHECKED));
+ conf.setEnabled(enabled);
+ if(Objects.equals(Boolean.TRUE, enabled)) {
+ conf.setOrgLimit(SignApproverOrgLimitEnum.valueOfType(element.getChildElements().get(TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF).get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_ORG_LIMIT)));
+ conf.setApproverSpecify(ApproverSpecifyEnum.valueOf(element.getChildElements().get(TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF).get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_APPROVER_SPECIFY)));
+ conf.setSpecifyValue(element.getChildElements().get(TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE).get(0).getElementText());
+ }
+ return conf;
+ });
+ }
private static int performBitwiseOr(int... numbers) {
int result = 0;
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java
index 46cbff211..c9eac3ff6 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/conf/FlowableConfiguration.java
@@ -19,6 +19,7 @@ import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncExtTaskInstJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncRejectTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncRemindTaskJobHandler;
+import cn.axzo.workflow.core.engine.job.AsyncResetApproversUserTaskJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncTermNodeAlterJobHandler;
import cn.axzo.workflow.core.engine.job.AsyncTransferUserTaskJobHandler;
import cn.axzo.workflow.core.engine.job.exception.handle.CustomAsyncJobLogClearTraceExceptionHandler;
@@ -118,6 +119,7 @@ public class FlowableConfiguration {
configuration.addCustomJobHandler(new AsyncActivityCallbackJobHandler());
configuration.addCustomJobHandler(new AsyncApproveTaskWithFormJobHandler());
configuration.addCustomJobHandler(new AsyncRemindTaskJobHandler(refreshProperties));
+ configuration.addCustomJobHandler(new AsyncResetApproversUserTaskJobHandler(extAxHiTaskInstService));
configurers.forEach(i -> configuration.addCustomJobHandler(i.getJobHandler()));
// 异步任务异常重试时间间隔
configuration.setDefaultFailedJobWaitTime(30);
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java
index a95c1459a..e84adf3ce 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/converter/json/UserTaskJsonConverter.java
@@ -9,6 +9,7 @@ import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNode;
import cn.axzo.workflow.common.model.request.bpmn.BpmnJsonNodeProperty;
import cn.axzo.workflow.common.model.request.bpmn.BpmnSignApproverLimit;
+import cn.axzo.workflow.common.model.request.bpmn.BpmnUpgradeApprovalConf;
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowableListener;
@@ -41,11 +42,17 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_FIELD_PERMIS
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ORG_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_SIGN_APPROVER_ROLE_LIMIT;
+import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_APPROVER_SPECIFY;
+import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_CHECKED;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_DESC;
+import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_ORG_LIMIT;
import static cn.axzo.workflow.common.constant.BpmnConstants.ELEMENT_ATTRIBUTE_VALUE;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.OR_SIGN_EXPRESSION_ONLY_ONE;
import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_PENDING_MESSAGE_ID;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_CONF;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_SIGN;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
import static cn.axzo.workflow.core.common.utils.BpmnJsonConverterUtil.buildMetaButton;
@@ -323,6 +330,37 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter {
userTask.addExtensionElement(signatureElement);
}
+
+ // “提级审批配置”
+ BpmnUpgradeApprovalConf upgradeApprovalConf = property.getUpgradeApprovalConf();
+ if(Objects.nonNull(upgradeApprovalConf) && Objects.equals(Boolean.TRUE, upgradeApprovalConf.getEnabled())){
+ ExtensionElement upgradeApprovalElement = new ExtensionElement();
+ upgradeApprovalElement.setName(TEMPLATE_UPGRADE_APPROVAL_CONF);
+ ExtensionAttribute upgradeApprovalEnabledAttribute = new ExtensionAttribute();
+ upgradeApprovalEnabledAttribute.setName(ELEMENT_ATTRIBUTE_CHECKED);
+ upgradeApprovalEnabledAttribute.setValue(String.valueOf(Boolean.TRUE.equals(property.getUpgradeApprovalConf().getEnabled())));
+ upgradeApprovalElement.addAttribute(upgradeApprovalEnabledAttribute);
+
+
+ ExtensionElement upgradeApprovalLimitElement = new ExtensionElement();
+ upgradeApprovalLimitElement.setName(TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF);
+
+ ExtensionAttribute upgradeApprovalLimitOrgAttribute = new ExtensionAttribute();
+ upgradeApprovalLimitOrgAttribute.setName(ELEMENT_ATTRIBUTE_ORG_LIMIT);
+ upgradeApprovalLimitOrgAttribute.setValue(property.getUpgradeApprovalConf().getOrgLimit().getType());
+ upgradeApprovalLimitElement.addAttribute(upgradeApprovalLimitOrgAttribute);
+ ExtensionAttribute upgradeApprovalLimitSpecifyTypeAttribute = new ExtensionAttribute();
+ upgradeApprovalLimitSpecifyTypeAttribute.setName(ELEMENT_ATTRIBUTE_APPROVER_SPECIFY);
+ upgradeApprovalLimitSpecifyTypeAttribute.setValue(property.getUpgradeApprovalConf().getApproverSpecify().getType());
+ upgradeApprovalLimitElement.addAttribute(upgradeApprovalLimitSpecifyTypeAttribute);
+ upgradeApprovalElement.addChildElement(upgradeApprovalLimitElement);
+
+ ExtensionElement upgradeApprovalSpecifyElement = new ExtensionElement();
+ upgradeApprovalSpecifyElement.setName(TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE);
+ upgradeApprovalSpecifyElement.setElementText(property.getUpgradeApprovalConf().getSpecifyValue());
+ upgradeApprovalElement.addChildElement(upgradeApprovalSpecifyElement);
+ userTask.addExtensionElement(upgradeApprovalElement);
+ }
}
/**
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java
index c727eb2a5..c6fef6634 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskCmd.java
@@ -155,9 +155,9 @@ public class CustomApproveTaskCmd extends AbstractCommand implements Seria
// 记录电子签名的图片
recordSignature(task, runtimeService);
- executeSynchronous(task, taskService, runtimeService);
-
runtimeService.setVariable(task.getProcessInstanceId(), CLOSE_PROCESS_ASSIGNER, approver);
+
+ executeSynchronous(task, taskService, runtimeService);
return null;
}
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java
index c33bc5473..a78912c29 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomApproveTaskWithFormCmd.java
@@ -44,6 +44,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.workflow.common.code.FormInstanceRespCode.FORM_FIELD_VALIDATOR_ERROR;
+import static cn.axzo.workflow.common.constant.BpmnConstants.CLOSE_PROCESS_ASSIGNER;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NEXT_APPROVER;
@@ -177,6 +178,8 @@ public class CustomApproveTaskWithFormCmd extends AbstractCommand implemen
// 记录电子签名的图片
recordSignature(task, runtimeService);
+ runtimeService.setVariable(task.getProcessInstanceId(), CLOSE_PROCESS_ASSIGNER, approver);
+
executeSynchronous(task, taskService, runtimeService, commandContext, historicTaskInstance.getTenantId());
return null;
}
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java
index 3a9b88a04..e734d6f33 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBackTaskCmd.java
@@ -4,6 +4,8 @@ import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.utils.BpmnModelUtils;
+import cn.axzo.workflow.core.common.utils.SpringContextUtils;
+import cn.axzo.workflow.core.service.support.FlowNodeForecastService;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -13,6 +15,7 @@ import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.RuntimeService;
@@ -31,6 +34,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.BACK_NODE_CANNOT_REACHABLE;
@@ -146,7 +150,8 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), BACKED.getStatus());
});
// 移除回退到的指定节点的变量,让 EngineExecutionStartListener 重新计算该节点的人
- runtimeService.removeVariable(processInstanceId, INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + toActivityId);
+ List removeActivityIds = collectorThoughtFlowElement(processInstanceId, toActivityId, currentActivityId, true);
+ runtimeService.removeVariables(processInstanceId, removeActivityIds.stream().map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + i).collect(Collectors.toList()));
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(processInstanceId)
.moveActivityIdsToSingleActivityId(Collections.singletonList(currentActivityId), toActivityId)
@@ -154,6 +159,22 @@ public class CustomBackTaskCmd extends AbstractCommand implements Serializ
return null;
}
+ private List collectorThoughtFlowElement(String processInstanceId, String startActivityId, String currentActivityId, Boolean containsStart) {
+ FlowNodeForecastService forecastService = SpringContextUtils.getBean(FlowNodeForecastService.class);
+ List flowElements = forecastService.performProcessForecasting(processInstanceId, null, startActivityId, containsStart);
+ AtomicBoolean flag = new AtomicBoolean(true);
+ return flowElements.stream()
+ .map(FlowElement::getId)
+ .filter(id -> StringUtils.startsWithIgnoreCase(id, "node_"))
+ .filter(id -> {
+ if (Objects.equals(id, currentActivityId) && flag.get()) {
+ flag.set(false);
+ return true;
+ }
+ return flag.get();
+ }).collect(Collectors.toList());
+ }
+
@Data
@AllArgsConstructor
@NoArgsConstructor
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomResetTaskApproversAsyncCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomResetTaskApproversAsyncCmd.java
new file mode 100644
index 000000000..c563f1cc9
--- /dev/null
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomResetTaskApproversAsyncCmd.java
@@ -0,0 +1,81 @@
+package cn.axzo.workflow.core.engine.cmd;
+
+import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskResetApproversDTO;
+import cn.axzo.workflow.core.engine.job.AsyncResetApproversUserTaskJobHandler;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
+import org.flowable.engine.impl.util.CommandContextUtil;
+import org.flowable.job.service.JobService;
+import org.flowable.job.service.impl.persistence.entity.JobEntity;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.api.history.HistoricTaskInstanceQuery;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+
+import java.io.Serializable;
+
+import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
+
+/**
+ * 重置节点下的所有审批人
+ *
+ * @author wangli
+ * @since 2025-06-24 17:17
+ */
+@Slf4j
+public class CustomResetTaskApproversAsyncCmd extends AbstractCommand implements Serializable {
+
+ private static final long serialVersionUID = 6231755400617981273L;
+ private final BpmnTaskResetApproversDTO dto;
+
+ public CustomResetTaskApproversAsyncCmd(BpmnTaskResetApproversDTO dto) {
+ this.dto = dto;
+ }
+
+ @Override
+ public String paramToJsonString() {
+ return JSON.toJSONString(dto);
+ }
+
+ @Override
+ public Void executeInternal(CommandContext commandContext) {
+ ProcessEngineConfigurationImpl processEngineConfiguration =
+ CommandContextUtil.getProcessEngineConfiguration(commandContext);
+ HistoricTaskInstanceQuery taskQuery =
+ processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
+ HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult();
+
+ TaskService taskService = processEngineConfiguration.getTaskService();
+ TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
+
+ validTask(historicTaskInstance, task, dto.getOriginAssigner(), null);
+
+ startAsync(processEngineConfiguration, task);
+ return null;
+ }
+
+ private void startAsync(ProcessEngineConfigurationImpl processEngineConfiguration, TaskEntity task) {
+ JobService jobService = processEngineConfiguration.getJobServiceConfiguration().getJobService();
+
+ JobEntity job = jobService.createJob();
+ // 这里的 executionId 可为 null
+ job.setExecutionId(task.getExecutionId());
+ job.setProcessInstanceId(task.getProcessInstanceId());
+ job.setProcessDefinitionId(task.getProcessDefinitionId());
+ job.setElementId(task.getTaskDefinitionKey());
+ job.setElementName(task.getName());
+ job.setJobHandlerType(AsyncResetApproversUserTaskJobHandler.TYPE);
+ job.setTenantId(task.getTenantId());
+
+ // 携带自定义的数据
+ job.setCustomValues(JSONUtil.toJsonStr(dto));
+
+ // 创建异步任务并调度
+ jobService.createAsyncJob(job, false);
+ jobService.scheduleAsyncJob(job);
+ }
+
+}
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomResetTaskApproversCmd.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomResetTaskApproversCmd.java
new file mode 100644
index 000000000..ea73cc903
--- /dev/null
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomResetTaskApproversCmd.java
@@ -0,0 +1,154 @@
+package cn.axzo.workflow.core.engine.cmd;
+
+import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
+import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
+import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
+import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.common.engine.impl.identity.Authentication;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
+import org.flowable.engine.impl.util.CommandContextUtil;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.api.history.HistoricTaskInstanceQuery;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
+import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
+import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
+import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
+import static cn.axzo.workflow.common.constant.BpmnConstants.RESET_TASK_ASSIGNER_SHOW_NUMBER;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_FLAT;
+import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
+import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.UPGRADED;
+import static cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner.buildDummyAssigner;
+import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment;
+import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
+import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
+
+/**
+ * 重置节点下的所有审批人
+ *
+ * @author wangli
+ * @since 2025-06-24 17:17
+ */
+@Slf4j
+public class CustomResetTaskApproversCmd extends AbstractCommand implements Serializable {
+
+ private final String originTaskId;
+ private final String advice;
+ private final List attachmentList;
+ private final BpmnTaskDelegateAssigner originTaskAssignee;
+ private final List targetTaskAssigneeList;
+ private final ExtAxHiTaskInstService extAxHiTaskInstService;
+
+ public CustomResetTaskApproversCmd(String originTaskId, String advice, List attachmentList, BpmnTaskDelegateAssigner originTaskAssignee, List targetTaskAssigneeList, ExtAxHiTaskInstService extAxHiTaskInstService) {
+ this.originTaskId = originTaskId;
+ this.advice = advice;
+ this.attachmentList = attachmentList;
+ this.originTaskAssignee = originTaskAssignee;
+ this.targetTaskAssigneeList = targetTaskAssigneeList;
+ this.extAxHiTaskInstService = extAxHiTaskInstService;
+ }
+
+ @Override
+ public String paramToJsonString() {
+ Map params = new HashMap<>();
+ params.put("originTaskId", originTaskId);
+ params.put("advice", advice);
+ params.put("attachmentList", JSON.toJSONString(attachmentList));
+ params.put("originTaskAssignee", originTaskAssignee);
+ params.put("targetTaskAssigneeList", JSON.toJSONString(targetTaskAssigneeList));
+ return JSON.toJSONString(params);
+ }
+
+ @Override
+ public Void executeInternal(CommandContext commandContext) {
+ ProcessEngineConfigurationImpl processEngineConfiguration =
+ CommandContextUtil.getProcessEngineConfiguration(commandContext);
+ HistoricTaskInstanceQuery taskQuery =
+ processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
+ HistoricTaskInstance historicTaskInstance = taskQuery.taskId(originTaskId).singleResult();
+
+ TaskService taskService = processEngineConfiguration.getTaskService();
+ TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(originTaskId).singleResult();
+
+ validTask(historicTaskInstance, task, originTaskAssignee, null);
+
+ resolveOriginTask(commandContext, taskService, task);
+ batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList,
+ originTaskAssignee);
+ resetActivityApprovers(commandContext, task, targetTaskAssigneeList, taskService);
+
+ return null;
+ }
+
+ private void resetActivityApprovers(CommandContext commandContext, TaskEntity taskEntity, List taskDelegateAssigners, TaskService taskService) {
+ ProcessEngineConfigurationImpl processEngineConfiguration =
+ CommandContextUtil.getProcessEngineConfiguration(commandContext);
+ RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
+
+ // 提前查询正在待审批的任务, 用于最后移除
+ List tasks = taskService.createTaskQuery().processInstanceId(taskEntity.getProcessInstanceId()).active().list();
+
+ // 这个节点下所有审批人快照
+ String activityListSnapshot =
+ INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey();
+ Map variables = new HashMap<>();
+ variables.put(activityListSnapshot, taskDelegateAssigners);
+ variables.put(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + taskEntity.getTaskDefinitionKey(), taskDelegateAssigners.stream().map(BpmnTaskDelegateAssigner::buildAssigneeId).collect(Collectors.toList()));
+ runtimeService.setVariables(taskEntity.getProcessInstanceId(), variables);
+ log.info("正在进行提级任务:{},提级审批人列表:{}", taskEntity.getId(), JSONUtil.toJsonStr(taskDelegateAssigners));
+
+ // 将提级审批人加签
+ taskDelegateAssigners.forEach(assigner -> CustomTaskHelper.addMultiTask(commandContext, taskEntity, assigner));
+
+ taskEntity.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), UPGRADED.getStatus());
+
+ CustomTaskHelper.deleteMultiTasks(commandContext, tasks);
+ // 移除引擎内部用于确定人的快照变量
+// runtimeService.removeVariables(taskEntity.getProcessInstanceId(), variables.keySet());
+ }
+
+ private void resolveOriginTask(CommandContext commandContext, TaskService taskService, TaskEntity task) {
+ BpmnTaskDelegateAssigner assigner = buildDummyAssigner("upgrade", TASK_ASSIGNEE_SKIP_FLAT, "dummyApprover");
+ task.setAssignee(assigner.buildAssigneeId());
+ task.setScopeType("UPGRADE");
+
+ Authentication.setAuthenticatedUserId(originTaskAssignee.buildAssigneeId());
+
+ // 构建评论内容
+ StringBuilder message = new StringBuilder("提级给");
+ int end = Math.min(targetTaskAssigneeList.size(), RESET_TASK_ASSIGNER_SHOW_NUMBER);
+ //加签人员数量显示指定个数
+ for (int i = 0; i < end; i++) {
+ message.append(targetTaskAssigneeList.get(i).getAssignerName());
+ if (i < end - 1) {
+ message.append("、");
+ }
+ }
+ if (targetTaskAssigneeList.size() > end) {
+ message.append("等")
+ .append(targetTaskAssigneeList.size())
+ .append("人");
+ }
+ message.append("审批");
+ addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, message.toString());
+ addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice);
+ Authentication.setAuthenticatedUserId(null);
+
+ taskService.saveTask(task);
+ }
+
+}
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncResetApproversUserTaskJobHandler.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncResetApproversUserTaskJobHandler.java
new file mode 100644
index 000000000..984435e79
--- /dev/null
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/job/AsyncResetApproversUserTaskJobHandler.java
@@ -0,0 +1,45 @@
+package cn.axzo.workflow.core.engine.job;
+
+import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskResetApproversDTO;
+import cn.axzo.workflow.core.engine.cmd.CustomResetTaskApproversCmd;
+import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
+import org.flowable.engine.impl.util.CommandContextUtil;
+import org.flowable.job.service.JobHandler;
+import org.flowable.job.service.impl.persistence.entity.JobEntity;
+import org.flowable.variable.api.delegate.VariableScope;
+
+@Slf4j
+public class AsyncResetApproversUserTaskJobHandler extends AbstractJobHandler implements JobHandler {
+
+ public static final String TYPE = "async-reset-approves-task";
+
+ private final ExtAxHiTaskInstService extAxHiTaskInstService;
+
+ public AsyncResetApproversUserTaskJobHandler(ExtAxHiTaskInstService extAxHiTaskInstService) {
+ this.extAxHiTaskInstService = extAxHiTaskInstService;
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
+ log.info("AsyncCountersignUserTaskJobHandler executing...");
+ log(job);
+ ProcessEngineConfigurationImpl processEngineConfiguration =
+ CommandContextUtil.getProcessEngineConfiguration(commandContext);
+ BpmnTaskResetApproversDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnTaskResetApproversDTO.class);
+ processEngineConfiguration.getCommandExecutor().execute(new CustomResetTaskApproversCmd(dto.getTaskId(),
+ dto.getAdvice(),
+ dto.getAttachmentList(),
+ dto.getOriginAssigner(),
+ dto.getTargetAssignerList(),
+ extAxHiTaskInstService));
+ }
+}
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java
index b64841110..a72a4a268 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/listener/impl/InternalBpmnActivityEventListener_lo_Listener.java
@@ -120,7 +120,6 @@ public class InternalBpmnActivityEventListener_lo_Listener extends AbstractBpmnE
// if (Objects.nonNull(timerJob)) {
// CommandContextUtil.getTimerJobService().deleteTimerJob((TimerJobEntity) timerJob);
// }
-
TermNodePausingDTO dto = new TermNodePausingDTO();
dto.setActivityId(execution.getCurrentActivityId());
dto.setProcessInstanceId(execution.getProcessInstanceId());
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java
index 11c1db248..478ef04be 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProcessLog.java
@@ -1,6 +1,7 @@
package cn.axzo.workflow.core.repository.entity;
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
+import cn.axzo.workflow.common.model.dto.OrgStructureSnapshotInfo;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.request.form.FormPermissionMetaInfo;
@@ -10,6 +11,7 @@ import cn.axzo.workflow.core.conf.handler.ListFormFieldPermissionTypeHandler;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -123,6 +125,6 @@ public class ExtAxProcessLog extends BaseEntity {
/**
* 扩展字段
*/
- @TableField(typeHandler = JacksonTypeHandler.class)
- private JSONObject extra;
+ @TableField(typeHandler = FastjsonTypeHandler.class)
+ private OrgStructureSnapshotInfo extra;
}
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java
index 94cbfdc4a..b03b43964 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/BpmnProcessTaskService.java
@@ -141,6 +141,8 @@ public interface BpmnProcessTaskService {
*/
void countersignTask(BpmnTaskCountersignDTO countersignDTO);
+ void resetTaskApprovers(BpmnTaskResetApproversDTO dto);
+
void remindTask(BpmnTaskRemindDTO dto);
String createRobotTask(BpmnRobotTaskCreateDTO dto);
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java
index 1271f1ed8..a267d7e4a 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/ExtAxProcessLogService.java
@@ -1,5 +1,6 @@
package cn.axzo.workflow.core.service;
+import cn.axzo.workflow.common.model.dto.OrgStructureSnapshotInfo;
import cn.axzo.workflow.common.model.dto.SimpleTaskDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
@@ -49,9 +50,9 @@ public interface ExtAxProcessLogService {
* @param updateLog
* @param assignee
*/
- void updateAssignee(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee);
+ void updateAssigneeAndSnapshot(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee, OrgStructureSnapshotInfo snapshotInfo);
- void updateAssignee(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee, String operationDesc);
+ void updateAssigneeAndSnapshot(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee, OrgStructureSnapshotInfo snapshotInfo, String operationDesc);
List genericQuery(ExtAxProcessLog query);
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java
index 040de2efe..d5a5b5b52 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessInstanceServiceImpl.java
@@ -149,6 +149,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -192,6 +193,7 @@ import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoRejection;
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.autoRejection_empty;
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.human;
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.transferToAdmin;
+import static cn.axzo.workflow.common.enums.BpmnButtonEnum.BPMN_UPGRADE;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.EXCEPTIONAL;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL;
@@ -222,6 +224,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeTyp
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getProcessApproveConf;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSignApproverLimit;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getSupportInitiatorSpecified;
+import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getUpgradeApprovalConf;
@Service
@Slf4j
@@ -983,8 +986,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
}
@Override
- public List getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(String
- processInstanceId,
+ public List getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(String processInstanceId,
ProcessInstance instance,
String startNodeDefinitionKey,
Boolean containSelf,
@@ -1003,7 +1005,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
List flowElements = forecastService.performProcessForecasting(instance.getProcessInstanceId(), instance, startNodeDefinitionKey, containSelf);
- return buildNodeDetailVos(processInstanceId, Collections.emptyList(), instance, flowElements);
+ return buildNodeDetailVos(processInstanceId, Collections.emptyList(), instance, flowElements, startNodeDefinitionKey, containSelf);
}
@@ -1021,12 +1023,15 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
}
List flowElements = forecastService.performProcessForecasting(processInstanceId, instance);
- return buildNodeDetailVos(processInstanceId, nodeDefinitionKeys, instance, flowElements);
+ return buildNodeDetailVos(processInstanceId, nodeDefinitionKeys, instance, flowElements, null, false);
}
- private List buildNodeDetailVos(String
- processInstanceId, List nodeDefinitionKeys, ProcessInstance
- instance, List flowElements) {
+ private List buildNodeDetailVos(String processInstanceId,
+ List nodeDefinitionKeys,
+ ProcessInstance instance,
+ List flowElements,
+ String startNodeDefinitionKey,
+ Boolean containSelf) {
BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
List resultList = new ArrayList<>(flowElements.size());
// 发起人节点,也是一个 UserTask 节点, 所以这里默认就包含了发起人节点
@@ -1039,6 +1044,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
getButtonConfig(bpmnModel.getMainProcess(), i.getId()).ifPresent(node::setButtonConf);
// 设置审批方式
getApprovalMethod(i).ifPresent(node::setApprovalMethod);
+ node.setFutureNode(Objects.equals(Boolean.TRUE, containSelf) && !Objects.equals(i.getId(), startNodeDefinitionKey));
+ // 提级审批配置
+ getUpgradeApprovalConf(i).ifPresent(node::setUpgradeApprovalConf);
getNodeType(i).ifPresent(node::setNodeType);
if (Objects.equals(NODE_STARTER.getType(), i.getId())) {
node.setNodeType(NODE_STARTER);
@@ -1161,7 +1169,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
.singleResult();
logs.stream().reduce((f, s) -> Objects.equals(s.getActivityId(), NODE_ROBOT.getType()) || Objects.equals(s.getActivityId(), NODE_COMMENT.getType()) ? f : s)
.ifPresent(e -> forecasting.addAll(
- getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(dto.getProcessInstanceId(), instance, e.getActivityId(), false, false))
+ getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(dto.getProcessInstanceId(), instance, e.getActivityId(), true, false))
);
}
@@ -1367,6 +1375,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
authorizedButtons.addAll(logVO.getDefaultButtonConf().getCarbonCopy());
}
+ AtomicBoolean supportUpgrade = new AtomicBoolean(false);
if (Objects.nonNull(visitor)) {
String ge130Assignee = getGe130Assignee(visitor);
String le130Assignee = getLe130Assignee(visitor);
@@ -1377,7 +1386,6 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
.findFirst()
.ifPresent(i -> logVO.setCalculatingButtonConf(i.getButtonConf()));
-
// 比对发起人
if (Objects.nonNull(logVO.getInitiator()) && Objects.equals(logVO.getResult(), PROCESSING) &&
(Objects.equals(logVO.getInitiator().buildAssigneeId_1_2_1(), le130Assignee)
@@ -1405,7 +1413,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
.filter(Objects::nonNull)
.filter(i -> i.buildAssigneeId().contains(ge130Assignee) || Objects.equals(i.buildAssigneeId_1_2_1(), le130Assignee))
.findAny()
- .ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CURRENT)));
+ .ifPresent(i -> {
+ authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CURRENT));
+ supportUpgrade.set(Objects.equals(Boolean.TRUE,i.getSupportUpgradeApproval()));
+ });
// 比对历史审批人
@@ -1428,6 +1439,12 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
.findAny()
.ifPresent(i -> authorizedButtons.addAll(chooseButtons(logVO, CONFIG_BUTTON_TYPE_CARBON_COPY)));
}
+ // 提级审批按钮特殊处理
+
+ if (!supportUpgrade.get()) {
+ authorizedButtons.removeIf(button -> Objects.equals(BPMN_UPGRADE.getBtnKey(), button.getBtnKey()));
+ }
+
logVO.setCurrentUserButtons(authorizedButtons);
// 有权限访问的自定义按钮
@@ -1523,7 +1540,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
taskService.getProcessInstanceAttachments(processInstanceId).stream()
.collect(Collectors.groupingBy(Attachment::getTaskId));
// 已完成的和进行中的
- getHistoricTasks(logs, tasks, attachmentByTaskMap, dto.getVisitor());
+ getHistoricTasks(logs, forecasting, tasks, attachmentByTaskMap, dto.getVisitor());
// 未来节点
getFutureTasks(forecasting, tasks);
// 处理是否加密
@@ -1566,7 +1583,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
private static void getFutureTasks
(List forecasting, List tasks) {
- ListUtils.emptyIfNull(forecasting).forEach(e -> {
+ ListUtils.emptyIfNull(forecasting).stream()
+ .filter(i -> Objects.equals(Boolean.TRUE, i.getFutureNode()))
+ .forEach(e -> {
BpmnTaskInstanceLogVO build = BpmnTaskInstanceLogVO.builder()
.taskDefinitionKey(e.getId())
.name(e.getName())
@@ -1615,11 +1634,13 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
if (Objects.equals(e.getNodeType(), NODE_CARBON_COPY)) {
build.setOperationDesc("抄送" + e.getForecastAssigners().size() + "人");
}
+ build.setUpgradeApprovalConf(e.getUpgradeApprovalConf());
tasks.add(build);
});
}
private void getHistoricTasks(List logs,
+ List forecasting,
List tasks,
Map> attachmentByTaskMap,
BpmnTaskDelegateAssigner visitor) {
@@ -1682,6 +1703,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
.assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null :
assigner)
.forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? ListUtils.emptyIfNull(e.getAssigneeFull()) : Collections.emptyList())
+ .upgradeApprovalConf(forecasting.stream().filter(i -> Objects.equals(i.getId(), e.getActivityId())).findAny().orElse(new ProcessNodeDetailVO()).getUpgradeApprovalConf())
.build());
}
});
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java
index 16e3bc22b..2fb5ac129 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java
@@ -19,6 +19,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
+import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskResetApproversDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
import cn.axzo.workflow.common.model.response.BpmPageResult;
@@ -46,6 +47,8 @@ import cn.axzo.workflow.core.engine.cmd.CustomRejectionTaskAsyncCmd;
import cn.axzo.workflow.core.engine.cmd.CustomRejectionTaskCmd;
import cn.axzo.workflow.core.engine.cmd.CustomRemindTaskAsyncCmd;
import cn.axzo.workflow.core.engine.cmd.CustomRemindTaskCmd;
+import cn.axzo.workflow.core.engine.cmd.CustomResetTaskApproversAsyncCmd;
+import cn.axzo.workflow.core.engine.cmd.CustomResetTaskApproversCmd;
import cn.axzo.workflow.core.engine.cmd.CustomTransferUserTaskAsyncCmd;
import cn.axzo.workflow.core.engine.cmd.CustomTransferUserTaskCmd;
import cn.axzo.workflow.core.engine.event.MessagePushEventBuilder;
@@ -875,6 +878,18 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
}
}
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void resetTaskApprovers(BpmnTaskResetApproversDTO dto) {
+ CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
+ if(dto.getAsync() != null && dto.getAsync()) {
+ commandExecutor.execute(new CustomResetTaskApproversAsyncCmd(dto));
+ } else {
+ commandExecutor.execute(new CustomResetTaskApproversCmd(dto.getTaskId(), dto.getAdvice(),
+ dto.getAttachmentList(), dto.getOriginAssigner(), dto.getTargetAssignerList(), extAxHiTaskInstService));
+ }
+ }
+
@Override
public void remindTask(BpmnTaskRemindDTO dto) {
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java
index 7791a9bb7..3db0ef683 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java
+++ b/workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/ExtAxProcessLogServiceImpl.java
@@ -1,10 +1,12 @@
package cn.axzo.workflow.core.service.impl;
+import cn.axzo.workflow.common.model.dto.OrgStructureSnapshotInfo;
import cn.axzo.workflow.common.model.dto.SimpleTaskDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
import cn.axzo.workflow.core.repository.mapper.ExtAxProcessLogMapper;
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
+import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
@@ -54,15 +56,15 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService {
}
@Override
- public void updateAssignee(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee) {
- updateAssignee(queryLog, assignee, assignee.getAssignerName() + HANDLING.getDesc());
+ public void updateAssigneeAndSnapshot(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee, OrgStructureSnapshotInfo snapshotInfo) {
+ updateAssigneeAndSnapshot(queryLog, assignee, snapshotInfo, assignee.getAssignerName() + HANDLING.getDesc());
}
@Override
- public void updateAssignee(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee, String operationDesc) {
+ public void updateAssigneeAndSnapshot(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee, OrgStructureSnapshotInfo snapshotInfo, String operationDesc) {
List filterAssignee = Lists.newArrayList(NO_ASSIGNEE, HIDDEN_ASSIGNEE_ID, ROBOT_ASSIGNEE_ID,
- DUMMY_ASSIGNEE_ID);
+ DUMMY_ASSIGNEE_ID, "system");
if (Objects.isNull(assignee) || filterAssignee.contains(assignee.buildAssigneeId())) {
return;
}
@@ -73,6 +75,7 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService {
update.setAssigneeTenantId(assignee.getTenantId());
update.setAssigneeOuId(assignee.getOuId());
update.setAssigneeName(assignee.getAssignerName());
+ update.setExtra(snapshotInfo);
extAxProcessLogMapper.update(update, buildQueryWrapper(queryLog));
}
diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java
index 4906d2cee..abc275bbb 100644
--- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java
+++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java
@@ -23,9 +23,12 @@ import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.HistoryService;
+import org.flowable.engine.TaskService;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
+import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.core.Ordered;
@@ -62,6 +65,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCES
import static cn.axzo.workflow.common.constant.BpmnConstants.MULTI_INSTANCE_LOOP_COUNTER;
import static cn.axzo.workflow.common.constant.BpmnConstants.NUMBER_OF_INSTANCES;
import static cn.axzo.workflow.common.constant.BpmnConstants.PROCESS_OWNERSHIP_APPLICATION;
+import static cn.axzo.workflow.common.constant.BpmnConstants.SUPPORT_UPGRADE_VARIABLE;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.constant.VariableConstants.VAR_ACTIVITY_ID;
import static cn.axzo.workflow.common.constant.VariableConstants.VAR_ACTIVITY_NAME;
@@ -78,6 +82,7 @@ import static cn.axzo.workflow.common.constant.VariableConstants.VAR_PROCESS_TEN
import static cn.axzo.workflow.common.constant.VariableConstants.VAR_TASK_ID;
import static cn.axzo.workflow.common.constant.VariableConstants.VAR_TASK_START_TIME;
import static cn.axzo.workflow.common.constant.VariableConstants.VAR_TASK_USER_NAME;
+import static cn.axzo.workflow.common.enums.BpmnButtonEnum.BPMN_UPGRADE;
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_CARBON_COPY;
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_CARBON_COPY_COMPLETE;
import static cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum.PROCESS_PUSH_IM;
@@ -103,6 +108,8 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
private BpmnProcessInstanceService processInstanceService;
@Resource
private HistoryService historyService;
+ @Resource
+ private TaskService taskService;
@Value("${sendMq:true}")
private Boolean sendMQ;
@Resource
@@ -185,6 +192,13 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
}
});
}
+
+ // 如果提级审批的变量未 false
+ TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(event.getTaskId()).singleResult();
+ Boolean supportUpgrade = (Boolean) task.getTransientVariablesLocal().getOrDefault(SUPPORT_UPGRADE_VARIABLE, false);
+ if (!supportUpgrade) {
+ buttons.removeIf(button-> Objects.equals(button.getBtnKey(), BPMN_UPGRADE.getBtnKey()));
+ }
dto.setButtons(buttons);
sendMessageQueue(dto, PROCESS_PUSH_PENDING);
}
diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java
index cbc527af5..6ee7bef47 100644
--- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java
+++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/bpmn/BpmnProcessTaskController.java
@@ -255,6 +255,22 @@ public class BpmnProcessTaskController extends BasicPopulateAvatarController imp
return success(true);
}
+ /**
+ * 提级审批
+ * @param dto
+ * @return
+ */
+ @Operation(summary = "重置审批人")
+ @Override
+ @PostMapping("/approvers/reset")
+ @RepeatSubmit
+ public CommonResponse resetTaskApprovers(@Validated @RequestBody BpmnTaskResetApproversDTO dto) {
+ populateUsersAvatar(dto.getOriginAssigner());
+ populateUsersAvatar(dto.getTargetAssignerList());
+ bpmnProcessTaskService.resetTaskApprovers(dto);
+ return success(true);
+ }
+
/**
* 催办
*
diff --git a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/ProcessConfigController.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/ProcessConfigController.java
index 4d7a12b62..ada0b84a9 100644
--- a/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/ProcessConfigController.java
+++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/web/manage/ProcessConfigController.java
@@ -47,6 +47,7 @@ public class ProcessConfigController implements ProcessConfigApi {
.setBtnName(buttonEnum.getBtnName())
.setChecked(false)
.setDisabled(false)
+ .setHidden(false)
.setSupportBizType(buttonEnum.getSupportBizType())
)
.collect(Collectors.toList()));
diff --git a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java
similarity index 59%
rename from workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java
rename to workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java
index 41c30fd3c..ac1ad14e8 100644
--- a/workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/listener/entity/type/TaskEntityEventHandle.java
+++ b/workflow-engine-server/src/main/java/cn/axzo/workflow/server/engine/ext/listener/TaskEntityEventHandle.java
@@ -1,12 +1,26 @@
-package cn.axzo.workflow.core.engine.listener.entity.type;
+package cn.axzo.workflow.server.engine.ext.listener;
+import cn.axzo.foundation.page.PageResp;
+import cn.axzo.orggateway.api.cooperateship.CooperateShipHierarchicalQueryApi;
+import cn.axzo.orggateway.api.cooperateship.req.ListCooperateShipAncestorReq;
+import cn.axzo.orggateway.api.cooperateship.resp.ListCooperateShipResp;
+import cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi;
+import cn.axzo.orggateway.api.nodeuser.dto.OrgNodeUserDTO;
+import cn.axzo.orggateway.api.nodeuser.req.ListOrgNodeUserReq;
+import cn.axzo.orgmanax.dto.common.WorkspaceOuPair;
+import cn.axzo.orgmanax.dto.nodeuser.req.ListNodeUserReq;
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
+import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum;
+import cn.axzo.workflow.common.model.dto.JobInfo;
+import cn.axzo.workflow.common.model.dto.OrgSnapshotInfo;
+import cn.axzo.workflow.common.model.dto.OrgStructureSnapshotInfo;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import cn.axzo.workflow.core.engine.listener.entity.EntityEventHandle;
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
+import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -26,9 +40,11 @@ import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
@@ -37,6 +53,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
+import static cn.axzo.workflow.common.constant.BpmnConstants.SUPPORT_UPGRADE_VARIABLE;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.ApprovalMethodEnum.nobody;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.AND;
@@ -64,6 +81,8 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeTyp
@AllArgsConstructor
public class TaskEntityEventHandle implements EntityEventHandle {
private final ExtAxProcessLogService processLogService;
+ private final OrgNodeUserApi orgNodeUserApi;
+ private final CooperateShipHierarchicalQueryApi cooperateShipHierarchicalQueryApi;
@Override
public boolean support(Object entity) {
@@ -133,11 +152,70 @@ public class TaskEntityEventHandle implements EntityEventHandle {
ExtAxProcessLog queryLog = new ExtAxProcessLog();
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
queryLog.setTaskId(taskEntity.getId());
- processLogService.updateAssignee(queryLog, assignee);
+
+ // 快照审批人的组织架构信息
+ OrgStructureSnapshotInfo snapshotInfo = buildApproverOrgStructureInfo(assignee, taskEntity);
+
+ processLogService.updateAssigneeAndSnapshot(queryLog, assignee, snapshotInfo);
});
}
}
+ private OrgStructureSnapshotInfo buildApproverOrgStructureInfo(BpmnTaskDelegateAssigner assignee, TaskEntity taskEntity) {
+ // 先将审批人的提级审批重置为 false
+ assignee.setSupportUpgradeApproval(false);
+ List nodeUsers = fetchUserExtInfo(assignee);
+ OrgStructureSnapshotInfo.OrgStructureSnapshotInfoBuilder builder = OrgStructureSnapshotInfo.builder();
+ if (CollectionUtils.isEmpty(nodeUsers)) {
+ return builder.build();
+ }
+ OrgNodeUserDTO firstNodeUser = nodeUsers.get(0);
+ assignee.setNodeId(String.valueOf(firstNodeUser.getTopNodeId()));
+
+ OrgStructureSnapshotInfo snapshotInfo = builder.personName(firstNodeUser.getRealName())
+ .avatarUrl(Objects.nonNull(firstNodeUser.getPersonProfile()) ? firstNodeUser.getPersonProfile().getAvatarUrl() : "")
+ .phone(firstNodeUser.getPhone())
+ .topNodeId(firstNodeUser.getTopNodeId())
+ .workspaceType(firstNodeUser.getWorkspace().getType())
+ .snapshotInfo(Objects.nonNull(firstNodeUser.getCooperateShip()) ? OrgSnapshotInfo.builder()
+ .workspaceName(firstNodeUser.getCooperateShip().getWorkspaceName())
+ .workspaceId(String.valueOf(firstNodeUser.getCooperateShip().getWorkspaceId()))
+ .workspaceType(firstNodeUser.getCooperateShip().getWorkspaceType())
+ .cooperationType(firstNodeUser.getCooperateShip().getCooperateType())
+ .ouName(firstNodeUser.getCooperateShip().getOrganizationalUnitName())
+ .ouId(String.valueOf(firstNodeUser.getCooperateShip().getOrganizationalUnitId()))
+ .topNodeId(String.valueOf(firstNodeUser.getTopNodeId()))
+ .jobInfos(ListUtils.emptyIfNull(nodeUsers).stream()
+ .filter(i -> Objects.nonNull(i.getJob()))
+ .map(i -> JobInfo.builder()
+ .jobCode(i.getJob().getCode())
+ .jobName(i.getJob().getName())
+ .build()).collect(Collectors.toList()))
+ .build() : null)
+ .build();
+
+ FlowElement flowElement = ProcessDefinitionUtil.getBpmnModel(taskEntity.getProcessDefinitionId()).getFlowElement(taskEntity.getTaskDefinitionKey());
+ BpmnMetaParserHelper.getUpgradeApprovalConf(flowElement).ifPresent(conf -> {
+ Boolean supportUpgradeApproval;
+ if (Objects.equals(Boolean.TRUE, conf.getEnabled())) {
+ if (Objects.equals(SignApproverOrgLimitEnum.LV_ALL, conf.getOrgLimit())) {
+ supportUpgradeApproval = true;
+ } else {
+ ListCooperateShipAncestorReq build = ListCooperateShipAncestorReq.builder()
+ .upLevel(conf.getOrgLimit().getCode())
+ .organizationNodeId(Long.parseLong(assignee.getNodeId()))
+ .includeCurrentNode(false)
+ .build();
+ List result = listAncestors(build);
+ supportUpgradeApproval = !CollectionUtils.isEmpty(result);
+ }
+ assignee.setSupportUpgradeApproval(supportUpgradeApproval);
+ taskEntity.setTransientVariableLocal(SUPPORT_UPGRADE_VARIABLE, supportUpgradeApproval);
+ }
+ });
+ return snapshotInfo;
+ }
+
@Override
public void onDeleted(TaskEntity taskEntity) {
ExtAxProcessLog queryLog = new ExtAxProcessLog();
@@ -231,4 +309,68 @@ public class TaskEntityEventHandle implements EntityEventHandle {
return node;
}
+ private List fetchUserExtInfo(BpmnTaskDelegateAssigner assigner) {
+ String personId = assigner.getPersonId();
+ String tenantId = assigner.getTenantId();
+ String ouId = assigner.getOuId();
+ String nodeId = assigner.getNodeId();
+ if (NumberUtils.isDigits(personId) && NumberUtils.isDigits(tenantId) && NumberUtils.isDigits(ouId)) {
+ ListOrgNodeUserReq build = ListOrgNodeUserReq.builder()
+ .personIds(Lists.newArrayList(Long.parseLong(personId)))
+ .workspaceOuPairs(Lists.newArrayList(WorkspaceOuPair.builder()
+ .workspaceId(Long.parseLong(tenantId))
+ .ouId(Long.parseLong(ouId))
+ .build()))
+ .needs(ListNodeUserReq.Needs.builder()
+ .job(true)
+ .unit(true)
+ .cooperateShip(true)
+ .personProfile(true)
+ .workspace(true)
+ .build())
+ .pageSize(Integer.MAX_VALUE)
+ .build();
+
+ if(NumberUtils.isDigits(nodeId)) {
+ build.setAncestorNodeIds(Lists.newArrayList(Long.parseLong(nodeId)));
+ }
+ return orgNodeUserList(build).getData();
+ }
+ return Collections.emptyList();
+
+ }
+
+ /**
+ * 查询orgNodeUser
+ */
+ public PageResp orgNodeUserList(ListOrgNodeUserReq listOrgNodeUserReq) {
+ try {
+ log.info("orgNodeUserList,params:{}", JSON.toJSONString(listOrgNodeUserReq));
+ cn.axzo.foundation.result.ApiResult> apiResult = orgNodeUserApi.list(listOrgNodeUserReq);
+ log.info("orgNodeUserList,result:{}", JSON.toJSONString(apiResult));
+ if (Objects.isNull(apiResult) || !apiResult.isSuccess() || Objects.isNull(apiResult.getData()) || org.apache.commons.collections.CollectionUtils.isEmpty(apiResult.getData().getData())) {
+ return new PageResp<>(0, listOrgNodeUserReq.getPageSize(), listOrgNodeUserReq.getPage(), org.apache.commons.compress.utils.Lists.newArrayList());
+ }
+ return apiResult.getData();
+ } catch (Exception e) {
+ log.warn("orgNodeUserList,exception", e);
+ throw e;
+ }
+ }
+
+ public List listAncestors(ListCooperateShipAncestorReq req) {
+ try {
+ log.info("listAncestors,params:{}", JSON.toJSONString(req));
+ cn.axzo.foundation.result.ApiResult> listApiResult = cooperateShipHierarchicalQueryApi.listAncestors(req);
+ log.info("listAncestors,result:{}", JSON.toJSONString(listApiResult));
+ if (Objects.isNull(listApiResult) || !listApiResult.isSuccess() || Objects.isNull(listApiResult.getData()) || org.apache.commons.collections.CollectionUtils.isEmpty(listApiResult.getData())) {
+ return org.apache.commons.compress.utils.Lists.newArrayList();
+ }
+ return listApiResult.getData();
+ } catch (Exception e) {
+ log.warn("orgNodeUserList,exception", e);
+ throw e;
+ }
+ }
}
+