diff --git a/pom.xml b/pom.xml index e75deb2f5..fd3624845 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ Workflow Engine - 1.5.2-SNAPSHOT + 1.5.3-SNAPSHOT 2.0.0-SNAPSHOT 2.0.0-SNAPSHOT 1.0.0-SNAPSHOT diff --git a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java index a01f507c1..f6f7b072c 100644 --- a/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java +++ b/workflow-engine-api/src/main/java/cn/axzo/workflow/client/feign/bpmn/ProcessTaskApi.java @@ -3,10 +3,27 @@ package cn.axzo.workflow.client.feign.bpmn; import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient; import cn.axzo.workflow.common.annotation.InvokeMode; import cn.axzo.workflow.common.annotation.Manageable; -import cn.axzo.workflow.common.model.request.bpmn.task.*; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnNodeBackSystemOperateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAttachmentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditWithFormDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskBackAuditDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCommentDTO; +import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO; +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.response.BpmPageResult; import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO; -import cn.axzo.workflow.common.model.response.bpmn.task.*; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO; +import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO; import cn.azxo.framework.common.model.CommonResponse; import io.swagger.v3.oas.annotations.Operation; import org.springframework.validation.annotation.Validated; @@ -160,6 +177,16 @@ public interface ProcessTaskApi { @PostMapping("/api/process/task/countersign") CommonResponse countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto); + /** + * 重置节点审批人(提级审批) + * + * @param dto + * @return + */ + @Operation(summary = "重置节点审批人(提级审批)") + @PostMapping("/api/process/task/approvers/reset") + CommonResponse resetTaskApprovers(@Validated @RequestBody BpmnTaskResetApproversDTO dto); + /** * 催办 * diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java index b74f7a3f3..eae75fd51 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java @@ -80,6 +80,9 @@ public interface BpmnConstants { String TEMPLATE_SIGN_PENDING_MESSAGE_ID = "signPendingMessageId"; String TEMPLATE_CARBON_COPY_MESSAGE_ID = "carbonCopyMessageId"; String TEMPLATE_SMS_MESSAGE_ID = "smsMessageId"; + String TEMPLATE_UPGRADE_APPROVAL_CONF = "upgradeApprovalConf"; + String TEMPLATE_UPGRADE_APPROVAL_LIMIT_CONF = "limitConfig"; + String TEMPLATE_UPGRADE_APPROVAL_SPECIFY_VALUE = "specifyValue"; String APPROVE_SUPPORT_BATCH_OPERATION = "supportBatchOperation"; String APPROVE_USER_AGREE_SIGNATURE = "userAgreeSignature"; String CONFIG_BUTTON = "buttonConfig"; @@ -117,6 +120,8 @@ public interface BpmnConstants { String ELEMENT_ATTRIBUTE_CHECKED = "checked"; String ELEMENT_ATTRIBUTE_DISABLED = "disabled"; String ELEMENT_ATTRIBUTE_TYPE = "type"; + String ELEMENT_ATTRIBUTE_ORG_LIMIT = "orgLimit"; + String ELEMENT_ATTRIBUTE_APPROVER_SPECIFY = "approverSpecify"; String START_EVENT_ID = "startEventNode"; String SEQUENCE_FLOW_ID = "SequenceFlowId"; String END_EVENT_ID = "endEventNode"; @@ -197,6 +202,10 @@ public interface BpmnConstants { * 加签显示人员数量 */ Integer COUNTERSIGN_ASSIGNER_SHOW_NUMBER = 2; + /** + * 重置任务审批人显示人员数量 + */ + Integer RESET_TASK_ASSIGNER_SHOW_NUMBER = 2; /** * 回退操作次数上限 @@ -236,4 +245,8 @@ public interface BpmnConstants { */ String SIGNATORIES = "[_SIGNATORIES_]"; String TASK_SUBMIT_FORM_VARIABLE = "[_TASK_SUBMIT_FORM_VARIABLE_]"; + /** + * 提级审批变量标识 + */ + String SUPPORT_UPGRADE_VARIABLE = "[_SUPPORT_UPGRADE_]"; } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java index dae4550d9..b8dea2f0f 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnButtonEnum.java @@ -24,9 +24,9 @@ public enum BpmnButtonEnum { */ BPMN_REJECT(2, "BPMN_REJECT", "驳回", Lists.newArrayList(APPROVAL, SIGN)), /** - * 确认签署 + * 确认签字 */ - BPMN_CONFIRM_SIGN(3, "BPMN_CONFIRM_SIGN", "确认签署", Lists.newArrayList(SIGN)), + BPMN_CONFIRM_SIGN(3, "BPMN_CONFIRM_SIGN", "确认签字", Lists.newArrayList(SIGN)), /** * 查看文档 */ @@ -55,6 +55,10 @@ public enum BpmnButtonEnum { * 抄送按钮 */ BPMN_COPY(10, "BPMN_COPY", "抄送", Lists.newArrayList(APPROVAL, SIGN)), + /** + * 提级审批按钮 + */ + BPMN_UPGRADE(12, "BPMN_UPGRADE", "提级审批", Lists.newArrayList(APPROVAL, SIGN)), /** * 催办按钮 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java index eaa621a2e..e0f2ce964 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/BpmnProcessInstanceResultEnum.java @@ -11,6 +11,7 @@ public enum BpmnProcessInstanceResultEnum { ABORTED("ABORTED", "已中止"), TRANSFER("TRANSFER", "已转交"), COUNTERSIGN("COUNTERSIGN", "已加签"), + UPGRADED("UPGRADED", "已提级"), COMMENTED("COMMENTED", "已评论"), DELETED("DELETED", "已删除"), ; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/SignApproverOrgLimitEnum.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/SignApproverOrgLimitEnum.java index 922a108ea..e0f65da15 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/SignApproverOrgLimitEnum.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/enums/SignApproverOrgLimitEnum.java @@ -16,6 +16,7 @@ public enum SignApproverOrgLimitEnum { LV_3("LV_3", "上3级组织", 3), LV_4("LV_4", "上4级组织", 4), LV_5("LV_5", "上5级组织", 5), + LV_ALL("LV_ALL", "所有组织", -1), ; private final String type; diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/JobInfo.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/JobInfo.java new file mode 100644 index 000000000..35a2bac82 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/JobInfo.java @@ -0,0 +1,34 @@ +package cn.axzo.workflow.common.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 岗位信息 + * + * @author wangli + * @since 2025-06-23 19:35 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class JobInfo implements Serializable { + + private static final long serialVersionUID = -6092011348559752255L; + /** + * 岗位名称 + */ + private String jobName; + + /** + * 岗位编码 + */ + private String jobCode; +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/OrgSnapshotInfo.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/OrgSnapshotInfo.java new file mode 100644 index 000000000..c30513d85 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/OrgSnapshotInfo.java @@ -0,0 +1,66 @@ +package cn.axzo.workflow.common.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; + +/** + * 组织架构中的项目快照信息 + * + * @author wangli + * @since 2025-06-23 18:31 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class OrgSnapshotInfo implements Serializable { + private static final long serialVersionUID = -2898438378034300663L; + + /** + * 工作台名称 + */ + private String workspaceName; + + /** + * 工作台 ID + */ + private String workspaceId; + + /** + * 工作台类型 + */ + private Integer workspaceType; + + /** + * 参建单位类型 + */ + private Integer cooperationType; + + /** + * 参建单位名称 + */ + private String ouName; + + /** + * 参建单位 ID + */ + private String ouId; + + /** + * 顶级节点 ID + */ + private String topNodeId; + + /** + * 岗位快照信息集合 + */ + private List jobInfos; + +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/OrgStructureSnapshotInfo.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/OrgStructureSnapshotInfo.java new file mode 100644 index 000000000..b165d7454 --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/dto/OrgStructureSnapshotInfo.java @@ -0,0 +1,56 @@ +package cn.axzo.workflow.common.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.List; + +/** + * 审批人员的组织架构信息 + * + * @author wangli + * @since 2025-06-23 18:23 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class OrgStructureSnapshotInfo implements Serializable { + private static final long serialVersionUID = 4199079714585922731L; + + /** + * 审批人姓名 + */ + private String personName; + + /** + * 头像 + */ + private String avatarUrl; + + /** + * 手机号 + */ + private String phone; + + /** + * 审批人顶级节点 ID + */ + private Long topNodeId; + + /** + * 工作台类型 + */ + private int workspaceType; + + /** + * 项目快照信息 + */ + private OrgSnapshotInfo snapshotInfo; + +} \ No newline at end of file diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java index 61f052ac0..99fbe54e0 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonConf.java @@ -9,6 +9,9 @@ import lombok.experimental.Accessors; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Objects; + +import static cn.axzo.workflow.common.enums.BpmnButtonEnum.BPMN_UPGRADE; /** * 流程定义中的按钮配置 @@ -78,4 +81,11 @@ public class BpmnButtonConf implements Serializable { this.carbonCopy = carbonCopy; } + public void removeUpGradeButton() { + // 移除升级按钮 + this.initiator.removeIf(button -> Objects.equals(BPMN_UPGRADE.getBtnKey(), button.getType())); + this.current.removeIf(button -> Objects.equals(BPMN_UPGRADE.getBtnKey(), button.getType())); + this.history.removeIf(button -> Objects.equals(BPMN_UPGRADE.getBtnKey(), button.getType())); + this.carbonCopy.removeIf(button -> Objects.equals(BPMN_UPGRADE.getBtnKey(), button.getType())); + } } diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonMetaInfo.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonMetaInfo.java index 2b7ea5f75..579f99a21 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonMetaInfo.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnButtonMetaInfo.java @@ -47,6 +47,10 @@ public class BpmnButtonMetaInfo implements Serializable { * 是否禁用勾选 */ private Boolean disabled; + /** + * 是否隐藏按钮 + */ + private Boolean hidden = false; /** * 按钮类型 SYSTEM/CUSTOM diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java index c9eeb68ef..28c72e325 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnJsonNodeProperty.java @@ -106,6 +106,12 @@ public class BpmnJsonNodeProperty { @ApiModelProperty(value = "电子签名") private Boolean signature; + /** + * 提级审批配置 + */ + @ApiModelProperty(value = "提级审批配置") + private BpmnUpgradeApprovalConf upgradeApprovalConf; + /** * 按钮权限 */ diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnUpgradeApprovalConf.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnUpgradeApprovalConf.java new file mode 100644 index 000000000..cda97deaa --- /dev/null +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/BpmnUpgradeApprovalConf.java @@ -0,0 +1,45 @@ +package cn.axzo.workflow.common.model.request.bpmn; + +import cn.axzo.workflow.common.enums.ApproverSpecifyEnum; +import cn.axzo.workflow.common.enums.SignApproverOrgLimitEnum; +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * JSON 版本的 BPMN 协议模型中的提级审批配置模型 + * + * @author wangli + * @since 2025-06-20 11:32 + */ +@ApiModel("JSON 版本的 BPMN 协议模型中的提级审批配置模型") +@Data +@NoArgsConstructor +@Accessors(chain = true) +public class BpmnUpgradeApprovalConf implements Serializable { + private static final long serialVersionUID = 36282987684860776L; + + /** + * 是否已开启 + */ + private Boolean enabled; + + /** + * 提级审批的审批人层级范围限制 + */ + private SignApproverOrgLimitEnum orgLimit; + + /** + * 提级审批的审批人指定方式 + */ + private ApproverSpecifyEnum approverSpecify; + + /** + * 提级审批的审批人指定具体值 + */ + private String specifyValue; + +} diff --git a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java index 2c1a7e542..1b57e3a1a 100644 --- a/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java +++ b/workflow-engine-common/src/main/java/cn/axzo/workflow/common/model/request/bpmn/process/BpmnProcessInstanceCreateDTO.java @@ -9,6 +9,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.math.NumberUtils; import javax.validation.Valid; import javax.validation.constraints.NotBlank; @@ -125,4 +126,10 @@ public class BpmnProcessInstanceCreateDTO extends BpmnProcessInstanceCreateWithF @ApiModelProperty(value = "签署业务,最终签署人") private List 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; + } + } } +