Merge branch 'feature/REQ-4468' into feature/REQ-4586

This commit is contained in:
wangli 2025-07-07 15:56:07 +08:00
commit 0fe5787975
39 changed files with 1024 additions and 41 deletions

View File

@ -16,7 +16,7 @@
<name>Workflow Engine</name>
<properties>
<revision>1.5.2-SNAPSHOT</revision>
<revision>1.5.3-SNAPSHOT</revision>
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
<axzo-dependencies.org.version>1.0.0-SNAPSHOT</axzo-dependencies.org.version>

View File

@ -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<Boolean> countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO dto);
/**
* 重置节点审批人提级审批
*
* @param dto
* @return
*/
@Operation(summary = "重置节点审批人(提级审批)")
@PostMapping("/api/process/task/approvers/reset")
CommonResponse<Boolean> resetTaskApprovers(@Validated @RequestBody BpmnTaskResetApproversDTO dto);
/**
* 催办
*

View File

@ -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_]";
}

View File

@ -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)),
/**
* 催办按钮
*/

View File

@ -11,6 +11,7 @@ public enum BpmnProcessInstanceResultEnum {
ABORTED("ABORTED", "已中止"),
TRANSFER("TRANSFER", "已转交"),
COUNTERSIGN("COUNTERSIGN", "已加签"),
UPGRADED("UPGRADED", "已提级"),
COMMENTED("COMMENTED", "已评论"),
DELETED("DELETED", "已删除"),
;

View File

@ -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;

View File

@ -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;
}

View File

@ -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<JobInfo> jobInfos;
}

View File

@ -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;
}

View File

@ -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()));
}
}

View File

@ -47,6 +47,10 @@ public class BpmnButtonMetaInfo implements Serializable {
* 是否禁用勾选
*/
private Boolean disabled;
/**
* 是否隐藏按钮
*/
private Boolean hidden = false;
/**
* 按钮类型 SYSTEM/CUSTOM

View File

@ -106,6 +106,12 @@ public class BpmnJsonNodeProperty {
@ApiModelProperty(value = "电子签名")
private Boolean signature;
/**
* 提级审批配置
*/
@ApiModelProperty(value = "提级审批配置")
private BpmnUpgradeApprovalConf upgradeApprovalConf;
/**
* 按钮权限
*/

View File

@ -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;
}

View File

@ -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<BpmnTaskDelegateAssigner> signatories;
}
public String getTenantId() {
if (NumberUtils.isDigits(tenantId)) {
return tenantId;
}
return null;
}
}

View File

@ -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;
}

View File

@ -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;
@ -35,6 +36,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.ROBOT_ASSIGNEE_ID;
*
* @author wangli
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@NoArgsConstructor
@ -42,7 +44,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;
@ -111,13 +113,6 @@ public class BpmnTaskDelegateAssigner implements Serializable {
*/
private String nodeId;
/**
* 扩展字段, 业务无需关系
* <p>
* 仅用于日志展示人的一些状态信息
*/
private JSONObject ext;
public final String buildAssigneeId_1_2_1() {
if (StringUtils.hasLength(assigneeType)) {
return tenantId + "|" + assignee + "|" + assigneeType;
@ -146,7 +141,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;

View File

@ -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<AttachmentDTO> attachmentList;
/**
* 任务提级给谁审批
*/
@ApiModelProperty(value = "任务提级给谁审批")
@NotEmpty(message = "任务接收人不能为空")
private List<BpmnTaskDelegateAssigner> targetAssignerList;
/**
* 任务操作人
*/
@ApiModelProperty(value = "任务原发起人")
@Valid
@NotNull(message = "任务发起人不能为空")
private BpmnTaskDelegateAssigner originAssigner;
/**
* 是否异步执行
*/
@ApiModelProperty(value = "是否异步", notes = "异步时,只接收请求便返回数据")
@Builder.Default
private Boolean async = true;
}

View File

@ -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<BpmnTaskDelegateAssigner> forecastAssigners;
/**
* 提级审批配置
*/
private BpmnUpgradeApprovalConf upgradeApprovalConf;
/**
* 是未来节点
*/
private Boolean futureNode;
}

View File

@ -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<BpmnTaskDelegateAssigner> forecastAssignees;
/**
* 提级审批配置
*/
@ApiModelProperty(value = "提级审批配置")
private BpmnUpgradeApprovalConf upgradeApprovalConf;
@ApiModelProperty(value = "程序计算按钮使用,非对外使用", hidden = true)
private transient BpmnButtonConf buttonConf;

View File

@ -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<BpmnSignApproverLimit> signApproverLimit = getSignApproverLimit(flowElement);
FlowElement flowElement = bpmnModel.getFlowElement("node_350687681316");
Optional<BpmnUpgradeApprovalConf> upgradeApprovalConf = getUpgradeApprovalConf(flowElement);
// Optional<BpmnSignApproverLimit> signApproverLimit = getSignApproverLimit(flowElement);
// ServiceTask serviceTask = (ServiceTask) bpmnModel.getFlowElement("node_946990365785");
// Optional<List<BpmnCarbonCopyConf>> carbonCopyConfigs = BpmnMetaParserHelper.getCarbonCopyConfigs
// (serviceTask);

View File

@ -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<BpmnUpgradeApprovalConf> getUpgradeApprovalConf(FlowElement flowElement) {
if (Objects.isNull(flowElement) || !(flowElement instanceof UserTask)) {
return Optional.empty();
}
return getUpgradeApprovalConf((UserTask) flowElement);
}
public static Optional<BpmnUpgradeApprovalConf> 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;

View File

@ -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);

View File

@ -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> {
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);
}
}
/**

View File

@ -155,9 +155,9 @@ public class CustomApproveTaskCmd extends AbstractCommand<Void> implements Seria
// 记录电子签名的图片
recordSignature(task, runtimeService);
executeSynchronous(task, taskService, runtimeService);
runtimeService.setVariable(task.getProcessInstanceId(), CLOSE_PROCESS_ASSIGNER, approver);
executeSynchronous(task, taskService, runtimeService);
return null;
}

View File

@ -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<Void> implements Serializ
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), BACKED.getStatus());
});
// 移除回退到的指定节点的变量 EngineExecutionStartListener 重新计算该节点的人
runtimeService.removeVariable(processInstanceId, INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + toActivityId);
List<String> 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<Void> implements Serializ
return null;
}
private List<String> collectorThoughtFlowElement(String processInstanceId, String startActivityId, String currentActivityId, Boolean containsStart) {
FlowNodeForecastService forecastService = SpringContextUtils.getBean(FlowNodeForecastService.class);
List<FlowElement> 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

View File

@ -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<Void> 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);
}
}

View File

@ -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<Void> implements Serializable {
private final String originTaskId;
private final String advice;
private final List<AttachmentDTO> attachmentList;
private final BpmnTaskDelegateAssigner originTaskAssignee;
private final List<BpmnTaskDelegateAssigner> targetTaskAssigneeList;
private final ExtAxHiTaskInstService extAxHiTaskInstService;
public CustomResetTaskApproversCmd(String originTaskId, String advice, List<AttachmentDTO> attachmentList, BpmnTaskDelegateAssigner originTaskAssignee, List<BpmnTaskDelegateAssigner> 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<String, Object> 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<BpmnTaskDelegateAssigner> taskDelegateAssigners, TaskService taskService) {
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
// 提前查询正在待审批的任务 用于最后移除
List<Task> tasks = taskService.createTaskQuery().processInstanceId(taskEntity.getProcessInstanceId()).active().list();
// 这个节点下所有审批人快照
String activityListSnapshot =
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey();
Map<String, Object> 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);
}
}

View File

@ -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));
}
}

View File

@ -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());

View File

@ -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<ExtAxProcessLog> {
/**
* 扩展字段
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private JSONObject extra;
@TableField(typeHandler = FastjsonTypeHandler.class)
private OrgStructureSnapshotInfo extra;
}

View File

@ -141,6 +141,8 @@ public interface BpmnProcessTaskService {
*/
void countersignTask(BpmnTaskCountersignDTO countersignDTO);
void resetTaskApprovers(BpmnTaskResetApproversDTO dto);
void remindTask(BpmnTaskRemindDTO dto);
String createRobotTask(BpmnRobotTaskCreateDTO dto);

View File

@ -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<ExtAxProcessLog> genericQuery(ExtAxProcessLog query);

View File

@ -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<ProcessNodeDetailVO> getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(String
processInstanceId,
public List<ProcessNodeDetailVO> getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(String processInstanceId,
ProcessInstance instance,
String startNodeDefinitionKey,
Boolean containSelf,
@ -1003,7 +1005,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
List<FlowElement> 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<FlowElement> flowElements = forecastService.performProcessForecasting(processInstanceId, instance);
return buildNodeDetailVos(processInstanceId, nodeDefinitionKeys, instance, flowElements);
return buildNodeDetailVos(processInstanceId, nodeDefinitionKeys, instance, flowElements, null, false);
}
private List<ProcessNodeDetailVO> buildNodeDetailVos(String
processInstanceId, List<String> nodeDefinitionKeys, ProcessInstance
instance, List<FlowElement> flowElements) {
private List<ProcessNodeDetailVO> buildNodeDetailVos(String processInstanceId,
List<String> nodeDefinitionKeys,
ProcessInstance instance,
List<FlowElement> flowElements,
String startNodeDefinitionKey,
Boolean containSelf) {
BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
List<ProcessNodeDetailVO> 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<ProcessNodeDetailVO> forecasting, List<BpmnTaskInstanceLogVO> 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<ExtAxProcessLog> logs,
List<ProcessNodeDetailVO> forecasting,
List<BpmnTaskInstanceLogVO> tasks,
Map<String, List<Attachment>> 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());
}
});

View File

@ -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();

View File

@ -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<String> 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));
}

View File

@ -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);
}

View File

@ -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<Boolean> resetTaskApprovers(@Validated @RequestBody BpmnTaskResetApproversDTO dto) {
populateUsersAvatar(dto.getOriginAssigner());
populateUsersAvatar(dto.getTargetAssignerList());
bpmnProcessTaskService.resetTaskApprovers(dto);
return success(true);
}
/**
* 催办
*

View File

@ -47,6 +47,7 @@ public class ProcessConfigController implements ProcessConfigApi {
.setBtnName(buttonEnum.getBtnName())
.setChecked(false)
.setDisabled(false)
.setHidden(false)
.setSupportBizType(buttonEnum.getSupportBizType())
)
.collect(Collectors.toList()));

View File

@ -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<TaskEntity> {
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<TaskEntity> {
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<OrgNodeUserDTO> 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<ListCooperateShipResp> 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<TaskEntity> {
return node;
}
private List<OrgNodeUserDTO> 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<OrgNodeUserDTO> orgNodeUserList(ListOrgNodeUserReq listOrgNodeUserReq) {
try {
log.info("orgNodeUserList,params:{}", JSON.toJSONString(listOrgNodeUserReq));
cn.axzo.foundation.result.ApiResult<PageResp<OrgNodeUserDTO>> 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<ListCooperateShipResp> listAncestors(ListCooperateShipAncestorReq req) {
try {
log.info("listAncestors,params:{}", JSON.toJSONString(req));
cn.axzo.foundation.result.ApiResult<List<ListCooperateShipResp>> 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;
}
}
}