Merge remote-tracking branch 'refs/remotes/origin/feature/REQ-2596' into feature/merge-all
# Conflicts: # pom.xml # workflow-engine-common/src/main/java/cn/axzo/workflow/common/constant/BpmnConstants.java # workflow-engine-core/src/main/java/cn/axzo/workflow/core/common/code/BpmnTaskRespCode.java # workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomBizSpecifyAssigneeToTaskCmd.java # workflow-engine-core/src/main/java/cn/axzo/workflow/core/repository/entity/ExtAxProperty.java # workflow-engine-server/src/main/java/cn/axzo/workflow/server/controller/listener/notice/RocketMqMessagePushEventListener.java
This commit is contained in:
commit
00c7fa6812
2
pom.xml
2
pom.xml
@ -16,7 +16,7 @@
|
|||||||
<name>workflow-engine</name>
|
<name>workflow-engine</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<revision>1.4.0-SNAPSHOT</revision>
|
<revision>1.4.1-SNAPSHOT</revision>
|
||||||
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
|
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
|
||||||
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
|
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
|
||||||
<feign-httpclient.version>11.8</feign-httpclient.version>
|
<feign-httpclient.version>11.8</feign-httpclient.version>
|
||||||
|
|||||||
@ -107,6 +107,7 @@ public interface BpmnConstants {
|
|||||||
String END_EVENT_ID = "endEventNode";
|
String END_EVENT_ID = "endEventNode";
|
||||||
String BPM_MODEL_CATEGORY = "bpm_model_category";
|
String BPM_MODEL_CATEGORY = "bpm_model_category";
|
||||||
String BPM_ALLOW_SKIP_USER_TASK = "_INTERNAL_SKIP_USER_TASK_";
|
String BPM_ALLOW_SKIP_USER_TASK = "_INTERNAL_SKIP_USER_TASK_";
|
||||||
|
String AUTO_APPROVAL_TYPE = "autoApprovalType";
|
||||||
/**
|
/**
|
||||||
* 用于国内审批节点填写审批建议
|
* 用于国内审批节点填写审批建议
|
||||||
* <p>
|
* <p>
|
||||||
@ -157,4 +158,24 @@ public interface BpmnConstants {
|
|||||||
*/
|
*/
|
||||||
String MQ_OWNERSHIP_APPLICATION = "MQ_OWNERSHIP_APPLICATION";
|
String MQ_OWNERSHIP_APPLICATION = "MQ_OWNERSHIP_APPLICATION";
|
||||||
String MQ_OWNERSHIP_PROCESS_DEFINITION_KEY = "MQ_OWNERSHIP_PROCESS_DEFINITION_KEY";
|
String MQ_OWNERSHIP_PROCESS_DEFINITION_KEY = "MQ_OWNERSHIP_PROCESS_DEFINITION_KEY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批人数量限制
|
||||||
|
*/
|
||||||
|
Integer APPROVAL_ASSIGNER_LIMIT_NUMBER = 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 抄送人员数量限制
|
||||||
|
*/
|
||||||
|
Integer CARBON_ASSIGNER_LIMIT_NUMBER = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQ消息每批次人员数量
|
||||||
|
*/
|
||||||
|
Integer MQ_ASSIGNER_BATCH_SIZE = 20;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加签显示人员数量
|
||||||
|
*/
|
||||||
|
Integer COUNTERSIGN_ASSIGNER_SHOW_NUMBER = 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
package cn.axzo.workflow.common.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动过审参数
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public enum AutoApprovalTypeEnum {
|
||||||
|
|
||||||
|
NO_AUTO_APPROVAL("noAutoApproval", "不自动过审"),
|
||||||
|
CONTINUOUS_NODES_AUTO_APPROVAL("continuousNodesAutoApproval", "连续节点自动过审");
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
AutoApprovalTypeEnum(String type, String desc) {
|
||||||
|
this.type = type;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AutoApprovalTypeEnum fromType(String type) {
|
||||||
|
if (!StringUtils.hasText(type)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (AutoApprovalTypeEnum typeEnum : AutoApprovalTypeEnum.values()) {
|
||||||
|
if (typeEnum.type.equals(type)) {
|
||||||
|
return typeEnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.axzo.workflow.common.model.request;
|
package cn.axzo.workflow.common.model.request;
|
||||||
|
|
||||||
|
import cn.axzo.workflow.common.enums.AutoApprovalTypeEnum;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -27,4 +28,10 @@ public class BpmnApproveConf {
|
|||||||
@ApiModelProperty(value = "审批同意录入手写签名")
|
@ApiModelProperty(value = "审批同意录入手写签名")
|
||||||
@Valid
|
@Valid
|
||||||
private Boolean userAgreeSignature;
|
private Boolean userAgreeSignature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批自动过审配置
|
||||||
|
*/
|
||||||
|
@ApiModelProperty(value = "同一审批人自动过审类型,默认不自动过审,枚举类型为'NO_AUTO_APPROVAL'")
|
||||||
|
private AutoApprovalTypeEnum autoApprovalType = AutoApprovalTypeEnum.NO_AUTO_APPROVAL;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
|||||||
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
||||||
import cn.axzo.workflow.common.enums.ApproverScopeEnum;
|
import cn.axzo.workflow.common.enums.ApproverScopeEnum;
|
||||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||||
|
import cn.axzo.workflow.common.enums.AutoApprovalTypeEnum;
|
||||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
|
|||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +54,7 @@ public class BpmnActivitySetAssigneeDTO {
|
|||||||
*/
|
*/
|
||||||
@ApiModelProperty(value = "审批人集合信息", notes = "业务传参时,需要注意去重")
|
@ApiModelProperty(value = "审批人集合信息", notes = "业务传参时,需要注意去重")
|
||||||
@Valid
|
@Valid
|
||||||
|
@Size(max = 60, message = "指定审批人数量限制为60")
|
||||||
private List<BpmnTaskDelegateAssigner> assigners;
|
private List<BpmnTaskDelegateAssigner> assigners;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -18,8 +18,8 @@ public enum AsyncJobRespCode implements IModuleRespCode {
|
|||||||
JOB_NOT_EXISTS_PROC_INST_ID("003", "流程实例id为【{}】对应任务不存在"),
|
JOB_NOT_EXISTS_PROC_INST_ID("003", "流程实例id为【{}】对应任务不存在"),
|
||||||
RESUME_JOB_REQUEST_PARAM_ERROR("004", "恢复任务请求参数错误,jobId 和 procInstId 不能同时为空"),
|
RESUME_JOB_REQUEST_PARAM_ERROR("004", "恢复任务请求参数错误,jobId 和 procInstId 不能同时为空"),
|
||||||
;
|
;
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -30,13 +30,4 @@ public enum AsyncJobRespCode implements IModuleRespCode {
|
|||||||
public String getProjectCode() {
|
public String getProjectCode() {
|
||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,8 +27,8 @@ public enum BpmnInstanceRespCode implements IModuleRespCode {
|
|||||||
TASK_CANT_COMMENT_INSTANCE_NOT_EXISTS("012", "流程实例【{}】不存在, 不能评论"),
|
TASK_CANT_COMMENT_INSTANCE_NOT_EXISTS("012", "流程实例【{}】不存在, 不能评论"),
|
||||||
RUNNING_INSTANCE_ONLY_FORECAST("013", "仅运行中的实例可以推测"),
|
RUNNING_INSTANCE_ONLY_FORECAST("013", "仅运行中的实例可以推测"),
|
||||||
;
|
;
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -40,12 +40,4 @@ public enum BpmnInstanceRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,8 +20,8 @@ public enum BpmnModelRespCode implements IModuleRespCode {
|
|||||||
BPMN_BYTES_NOT_EXISTS("005", "模型定义内容字节码不存在"),
|
BPMN_BYTES_NOT_EXISTS("005", "模型定义内容字节码不存在"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -33,13 +33,5 @@ public enum BpmnModelRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,8 +24,8 @@ public enum BpmnProcessDefinitionRespCode implements IModuleRespCode {
|
|||||||
PROCESS_DEFINITION_HAS_DIRTY_DATA("009", "流程定义KEY【{}】存在脏数据,当前模型没有流程定义内容"),
|
PROCESS_DEFINITION_HAS_DIRTY_DATA("009", "流程定义KEY【{}】存在脏数据,当前模型没有流程定义内容"),
|
||||||
PROCESS_DEFINITION_IS_INVALID("010", "暂时无法发起,请先配置流程模型")
|
PROCESS_DEFINITION_IS_INVALID("010", "暂时无法发起,请先配置流程模型")
|
||||||
;
|
;
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -37,12 +37,4 @@ public enum BpmnProcessDefinitionRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,8 @@ import cn.axzo.framework.domain.web.code.IModuleRespCode;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ASSIGNER_LIMIT_NUMBER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程模型响应码
|
* 流程模型响应码
|
||||||
*
|
*
|
||||||
@ -34,10 +36,11 @@ public enum BpmnTaskRespCode implements IModuleRespCode {
|
|||||||
PROCESS_INSTANCE_IS_NOT_EXIST("019", "Execution:{} 对应流程实例不存在,流程状态异常!"),
|
PROCESS_INSTANCE_IS_NOT_EXIST("019", "Execution:{} 对应流程实例不存在,流程状态异常!"),
|
||||||
TASK_TYPE_MISMATCH("020", "节点类型不匹配,当前节点类型:【{}】,指定节点类型:【{}】!"),
|
TASK_TYPE_MISMATCH("020", "节点类型不匹配,当前节点类型:【{}】,指定节点类型:【{}】!"),
|
||||||
PROCESS_CANT_SET_ASSIGNEE("021", "当前审批状态不允许设置审批人"),
|
PROCESS_CANT_SET_ASSIGNEE("021", "当前审批状态不允许设置审批人"),
|
||||||
|
ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT("022", String.format("人员数量超过限制,节点审批人限制数量为: %d!", APPROVAL_ASSIGNER_LIMIT_NUMBER)),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -49,13 +52,4 @@ public enum BpmnTaskRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,8 @@ public enum CategoryRespCode implements IModuleRespCode {
|
|||||||
CATEGORY_CONFIG_EXISTS("006", "分类【{}】的【{}】配置中已存在重复数据"),
|
CATEGORY_CONFIG_EXISTS("006", "分类【{}】的【{}】配置中已存在重复数据"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -34,13 +34,5 @@ public enum CategoryRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,8 +23,8 @@ public enum ConvertorRespCode implements IModuleRespCode {
|
|||||||
CONVERTOR_OPERATION_CHECKBOX_TYPE_ERROR("008", "条件节点(复选)运算符【{}】暂不支持"),
|
CONVERTOR_OPERATION_CHECKBOX_TYPE_ERROR("008", "条件节点(复选)运算符【{}】暂不支持"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -36,13 +36,4 @@ public enum ConvertorRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,8 @@ public enum FlowableEngineRespCode implements IModuleRespCode {
|
|||||||
ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现异常, 将放弃"),
|
ENGINE_ASYNC_COMMAND_EXECUTION_RETRY_GIVE_UP("007", "命令重试尝试【{}】次仍然失败,并出现异常, 将放弃"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -35,13 +35,4 @@ public enum FlowableEngineRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,8 +17,8 @@ public enum FormDefinitionRespCode implements IModuleRespCode {
|
|||||||
FORM_DEFINITION_PARSER_ERROR("002", "表单定义内容解析出错"),
|
FORM_DEFINITION_PARSER_ERROR("002", "表单定义内容解析出错"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -30,13 +30,4 @@ public enum FormDefinitionRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,8 +17,8 @@ public enum FormModelRespCode implements IModuleRespCode {
|
|||||||
FORM_MODEL_ID_NOT_EXISTS("002", "表单模型ID【{}】不存在"),
|
FORM_MODEL_ID_NOT_EXISTS("002", "表单模型ID【{}】不存在"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -30,13 +30,4 @@ public enum FormModelRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,8 @@ public enum OtherRespCode implements IModuleRespCode {
|
|||||||
MESSAGE_PUSH_EVENT_BUILD_ERROR("006", "不能使用 createEvent 函数创建`发送待办`的事件, 请调用 createPendingPushEvent 函数"),
|
MESSAGE_PUSH_EVENT_BUILD_ERROR("006", "不能使用 createEvent 函数创建`发送待办`的事件, 请调用 createPendingPushEvent 函数"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String code;
|
private final String code;
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getModuleCode() {
|
public String getModuleCode() {
|
||||||
@ -34,12 +34,4 @@ public enum OtherRespCode implements IModuleRespCode {
|
|||||||
return "998";
|
return "998";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCode(String code) {
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessage(String message) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,6 +69,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_SUPPORT_BATCH_OPERATION;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_SUPPORT_BATCH_OPERATION;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_USER_AGREE_SIGNATURE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_USER_AGREE_SIGNATURE;
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.AUTO_APPROVAL_TYPE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_META;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_BUTTON_META;
|
||||||
@ -506,6 +507,15 @@ public final class BpmnJsonConverterUtil {
|
|||||||
config.addAttribute(configAttribute);
|
config.addAttribute(configAttribute);
|
||||||
approveConfigElement.addChildElement(config);
|
approveConfigElement.addChildElement(config);
|
||||||
}
|
}
|
||||||
|
if (Objects.nonNull(approveConf.getAutoApprovalType())) {
|
||||||
|
ExtensionElement config = new ExtensionElement();
|
||||||
|
config.setName(AUTO_APPROVAL_TYPE);
|
||||||
|
ExtensionAttribute configAttribute = new ExtensionAttribute();
|
||||||
|
configAttribute.setName(ELEMENT_ATTRIBUTE_VALUE);
|
||||||
|
configAttribute.setValue(approveConf.getAutoApprovalType().getType());
|
||||||
|
config.addAttribute(configAttribute);
|
||||||
|
approveConfigElement.addChildElement(config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] transformBytes(BpmnModel bpmnModel) {
|
public static byte[] transformBytes(BpmnModel bpmnModel) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
|||||||
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
||||||
import cn.axzo.workflow.common.enums.ApproverScopeEnum;
|
import cn.axzo.workflow.common.enums.ApproverScopeEnum;
|
||||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||||
|
import cn.axzo.workflow.common.enums.AutoApprovalTypeEnum;
|
||||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||||
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
|
||||||
import cn.axzo.workflow.common.enums.CarbonCopyObjectType;
|
import cn.axzo.workflow.common.enums.CarbonCopyObjectType;
|
||||||
@ -41,6 +42,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_SUPPORT_BATCH_OPERATION;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_SUPPORT_BATCH_OPERATION;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_USER_AGREE_SIGNATURE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVE_USER_AGREE_SIGNATURE;
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.AUTO_APPROVAL_TYPE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE;
|
||||||
@ -104,6 +106,7 @@ public final class BpmnMetaParserHelper {
|
|||||||
if (CollectionUtils.isEmpty(elements)) {
|
if (CollectionUtils.isEmpty(elements)) {
|
||||||
conf.setUserAgreeSignature(USER_AGREE_SIGNATURE_DEFAULT_VALUE);
|
conf.setUserAgreeSignature(USER_AGREE_SIGNATURE_DEFAULT_VALUE);
|
||||||
conf.setSupportBatchOperation(SUPPORT_BATCH_OPERATION_DEFAULT_VALUE);
|
conf.setSupportBatchOperation(SUPPORT_BATCH_OPERATION_DEFAULT_VALUE);
|
||||||
|
conf.setAutoApprovalType(AutoApprovalTypeEnum.NO_AUTO_APPROVAL);
|
||||||
} else {
|
} else {
|
||||||
elements.get(0).getChildElements().forEach((k, v) -> {
|
elements.get(0).getChildElements().forEach((k, v) -> {
|
||||||
if (APPROVE_SUPPORT_BATCH_OPERATION.equals(k)) {
|
if (APPROVE_SUPPORT_BATCH_OPERATION.equals(k)) {
|
||||||
@ -112,6 +115,10 @@ public final class BpmnMetaParserHelper {
|
|||||||
} else if (APPROVE_USER_AGREE_SIGNATURE.equals(k)) {
|
} else if (APPROVE_USER_AGREE_SIGNATURE.equals(k)) {
|
||||||
String value = v.get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE);
|
String value = v.get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE);
|
||||||
conf.setUserAgreeSignature(Boolean.valueOf(value));
|
conf.setUserAgreeSignature(Boolean.valueOf(value));
|
||||||
|
} else if (AUTO_APPROVAL_TYPE.equals(k)) {
|
||||||
|
String value = v.get(0).getAttributeValue(null, ELEMENT_ATTRIBUTE_VALUE);
|
||||||
|
AutoApprovalTypeEnum typeEnum = AutoApprovalTypeEnum.fromType(value);
|
||||||
|
conf.setAutoApprovalType(typeEnum == null ? AutoApprovalTypeEnum.NO_AUTO_APPROVAL : typeEnum);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -377,7 +384,6 @@ public final class BpmnMetaParserHelper {
|
|||||||
return defaultValid(userTask, CONFIG_APPROVER_EMPTY_HANDLE_TYPE).map(element -> StringUtils.hasLength(element.getElementText()) ? element.getElementText() : "[]");
|
return defaultValid(userTask, CONFIG_APPROVER_EMPTY_HANDLE_TYPE).map(element -> StringUtils.hasLength(element.getElementText()) ? element.getElementText() : "[]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Optional<ExtensionElement> defaultValid(FlowElement flowElement, String elementName) {
|
private static Optional<ExtensionElement> defaultValid(FlowElement flowElement, String elementName) {
|
||||||
if (Objects.isNull(flowElement)) {
|
if (Objects.isNull(flowElement)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
package cn.axzo.workflow.core.common.utils;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SpringContextUtils {
|
||||||
|
|
||||||
|
private static SpringContextUtils.SpringContext springContext;
|
||||||
|
|
||||||
|
public SpringContextUtils(SpringContextUtils.SpringContext springContext) {
|
||||||
|
SpringContextUtils.springContext = springContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getBean(Class<T> clazz) {
|
||||||
|
return springContext.getBean(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) {
|
||||||
|
return springContext.getBeansOfType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface SpringContext {
|
||||||
|
<T> T getBean(Class<T> var1);
|
||||||
|
|
||||||
|
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.axzo.workflow.core.conf;
|
package cn.axzo.workflow.core.conf;
|
||||||
|
|
||||||
|
import cn.axzo.workflow.core.common.utils.SpringContextUtils;
|
||||||
import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory;
|
import cn.axzo.workflow.core.engine.behavior.CustomActivityBehaviorFactory;
|
||||||
import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory;
|
import cn.axzo.workflow.core.engine.cmd.CustomCommandContextFactory;
|
||||||
import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator;
|
import cn.axzo.workflow.core.engine.id.BasedNacosSnowflakeIdGenerator;
|
||||||
@ -27,14 +28,20 @@ import org.flowable.form.spring.SpringFormEngineConfiguration;
|
|||||||
import org.flowable.job.service.JobProcessor;
|
import org.flowable.job.service.JobProcessor;
|
||||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||||
import org.flowable.spring.boot.EngineConfigurationConfigurer;
|
import org.flowable.spring.boot.EngineConfigurationConfigurer;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.flowable.common.engine.impl.AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE;
|
import static org.flowable.common.engine.impl.AbstractEngineConfiguration.DB_SCHEMA_UPDATE_TRUE;
|
||||||
|
|
||||||
@ -111,4 +118,30 @@ public class FlowableConfiguration {
|
|||||||
return new CustomActivityBehaviorFactory();
|
return new CustomActivityBehaviorFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order
|
||||||
|
public SpringContextUtils springContextUtils(SpringContext springContext) {
|
||||||
|
return new SpringContextUtils(springContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static class SpringContext implements SpringContextUtils.SpringContext, ApplicationContextAware {
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public SpringContext() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getBean(Class<T> clazz) {
|
||||||
|
return this.applicationContext.getBean(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type){
|
||||||
|
return this.applicationContext.getBeansOfType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApplicationContext(@Nullable ApplicationContext applicationContext) throws BeansException {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.AUTO_APPROVAL_TYPE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_ALLOW_SKIP_USER_TASK;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_ALLOW_SKIP_USER_TASK;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVAL_METHOD;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CONFIG_APPROVER_EMPTY_HANDLE_TYPE;
|
||||||
@ -71,8 +72,8 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
|||||||
setApprovalExtensionElement(node, userTask);
|
setApprovalExtensionElement(node, userTask);
|
||||||
// "权限设置"
|
// "权限设置"
|
||||||
setFieldExtensionElement(node, userTask);
|
setFieldExtensionElement(node, userTask);
|
||||||
// "高级设置"
|
// "高级设置",包含按钮配置,自动过审配置
|
||||||
setButtonExtensionElement(node, userTask);
|
setAdvancedExtensionElement(node, userTask);
|
||||||
// "待办消息模板配置"
|
// "待办消息模板配置"
|
||||||
setPendingMessageExtensionElement(node, userTask);
|
setPendingMessageExtensionElement(node, userTask);
|
||||||
|
|
||||||
@ -130,7 +131,7 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setButtonExtensionElement(BpmnJsonNode node, UserTask userTask) {
|
private static void setAdvancedExtensionElement(BpmnJsonNode node, UserTask userTask) {
|
||||||
if (Objects.isNull(node.getProperty())) {
|
if (Objects.isNull(node.getProperty())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -146,6 +147,13 @@ public class UserTaskJsonConverter extends AbstractBpmnJsonConverter<UserTask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userTask.addExtensionElement(buttonConfigElement);
|
userTask.addExtensionElement(buttonConfigElement);
|
||||||
|
|
||||||
|
//添加自动审批配置
|
||||||
|
ExtensionElement autoApprovalExtensionElement = new ExtensionElement();
|
||||||
|
ExtensionAttribute pendingMessageAttribute = new ExtensionAttribute();
|
||||||
|
pendingMessageAttribute.setName(AUTO_APPROVAL_TYPE);
|
||||||
|
autoApprovalExtensionElement.addAttribute(pendingMessageAttribute);
|
||||||
|
userTask.addExtensionElement(autoApprovalExtensionElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setFieldExtensionElement(BpmnJsonNode node, UserTask userTask) {
|
private static void setFieldExtensionElement(BpmnJsonNode node, UserTask userTask) {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
|||||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||||
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
|
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import org.flowable.common.engine.impl.interceptor.Command;
|
|
||||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||||
import org.flowable.engine.HistoryService;
|
import org.flowable.engine.HistoryService;
|
||||||
import org.flowable.engine.RuntimeService;
|
import org.flowable.engine.RuntimeService;
|
||||||
@ -32,6 +31,7 @@ import static cn.axzo.workflow.core.common.code.BpmnInstanceRespCode.PROCESS_INS
|
|||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_ERROR;
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_BIZ_SET_ASSIGNEE_ERROR;
|
||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_CANT_SET_ASSIGNEE;
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ACTIVITY_CANT_SET_ASSIGNEE;
|
||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.PROCESS_CANT_SET_ASSIGNEE;
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.PROCESS_CANT_SET_ASSIGNEE;
|
||||||
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定的业务指定审批人命令实现
|
* 自定的业务指定审批人命令实现
|
||||||
@ -57,17 +57,33 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand<Boolean>
|
|||||||
return JSON.toJSONString(params);
|
return JSON.toJSONString(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Task getOperateTask(TaskService taskService, String executionId) {
|
||||||
|
return taskService.createTaskQuery().executionId(executionId)
|
||||||
|
.taskAssignee(NO_ASSIGNEE)
|
||||||
|
.singleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验
|
||||||
|
*
|
||||||
|
* @param runtimeService
|
||||||
|
* @param task
|
||||||
|
* @param assigners
|
||||||
|
*/
|
||||||
|
public static void validate(RuntimeService runtimeService, String executionId, Task task, List<BpmnTaskDelegateAssigner> assigners) {
|
||||||
|
validTask(task, executionId);
|
||||||
|
//校验审批人数量是否超过限制
|
||||||
|
validTaskAssignerCount(runtimeService, (TaskEntity) task, assigners);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean execute(CommandContext commandContext) {
|
public Boolean execute(CommandContext commandContext) {
|
||||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||||
TaskService taskService = processEngineConfiguration.getTaskService();
|
TaskService taskService = processEngineConfiguration.getTaskService();
|
||||||
|
Task task = getOperateTask(taskService, executionId);
|
||||||
Task task = taskService.createTaskQuery().executionId(executionId)
|
//校验
|
||||||
.taskAssignee(NO_ASSIGNEE)
|
validate(processEngineConfiguration.getRuntimeService(), executionId, task, addedAssigners);
|
||||||
.singleResult();
|
|
||||||
|
|
||||||
validTask(task);
|
|
||||||
|
|
||||||
validProcessInstance(commandContext, task);
|
validProcessInstance(commandContext, task);
|
||||||
|
|
||||||
@ -124,7 +140,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand<Boolean>
|
|||||||
CustomTaskHelper.deleteMultiTask(commandContext, (TaskEntity) task);
|
CustomTaskHelper.deleteMultiTask(commandContext, (TaskEntity) task);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validTask(Task task) {
|
private static void validTask(Task task, String executionId) {
|
||||||
if (Objects.isNull(task)) {
|
if (Objects.isNull(task)) {
|
||||||
throw new WorkflowEngineException(ACTIVITY_BIZ_SET_ASSIGNEE_ERROR, executionId);
|
throw new WorkflowEngineException(ACTIVITY_BIZ_SET_ASSIGNEE_ERROR, executionId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,11 +35,13 @@ import java.util.Objects;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.CARBON_ASSIGNER_LIMIT_NUMBER;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
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.NO_ASSIGNEE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_TASK_RELATION_ASSIGNEE_INFO_SNAPSHOT;
|
||||||
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getLimitedElementList;
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId;
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,7 +159,7 @@ public class CustomCarbonCopyUserSelectorCmd extends AbstractCommand<List<BpmnTa
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return removeDuplicateByPersonId(assigners);
|
return getLimitedElementList(removeDuplicateByPersonId(assigners), CARBON_ASSIGNER_LIMIT_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<BpmnTaskDelegateAssigner> getApproverRelationUser(BpmnCarbonCopyConf carbon,
|
private List<BpmnTaskDelegateAssigner> getApproverRelationUser(BpmnCarbonCopyConf carbon,
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
|
|||||||
import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler;
|
import cn.axzo.workflow.core.engine.job.AsyncCountersignUserTaskJobHandler;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import org.flowable.common.engine.impl.interceptor.Command;
|
|
||||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||||
import org.flowable.engine.TaskService;
|
import org.flowable.engine.TaskService;
|
||||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||||
@ -17,10 +16,9 @@ import org.flowable.task.api.history.HistoricTaskInstanceQuery;
|
|||||||
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
|
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
|
||||||
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount;
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
|
||||||
|
|
||||||
public class CustomCountersignUserTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
|
public class CustomCountersignUserTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
|
||||||
@ -50,6 +48,8 @@ public class CustomCountersignUserTaskAsyncCmd extends AbstractCommand<Void> imp
|
|||||||
|
|
||||||
validTaskAssignerDuplicated(commandContext, (TaskEntity) task, dto.getTargetAssignerList());
|
validTaskAssignerDuplicated(commandContext, (TaskEntity) task, dto.getTargetAssignerList());
|
||||||
|
|
||||||
|
validTaskAssignerCount(processEngineConfiguration.getRuntimeService(), (TaskEntity) task, dto.getTargetAssignerList());
|
||||||
|
|
||||||
startAsync(processEngineConfiguration, task);
|
startAsync(processEngineConfiguration, task);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
|||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.common.engine.impl.interceptor.Command;
|
import org.apache.commons.lang3.math.NumberUtils;
|
||||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||||
import org.flowable.engine.RuntimeService;
|
import org.flowable.engine.RuntimeService;
|
||||||
import org.flowable.engine.TaskService;
|
import org.flowable.engine.TaskService;
|
||||||
@ -25,12 +25,14 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN;
|
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN;
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment;
|
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.batchAddAttachment;
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask;
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask;
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
|
||||||
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount;
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,6 +92,8 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
|||||||
|
|
||||||
validTask(historicTaskInstance, (TaskEntity) task, originTaskAssignee, null);
|
validTask(historicTaskInstance, (TaskEntity) task, originTaskAssignee, null);
|
||||||
|
|
||||||
|
validTaskAssignerCount(processEngineConfiguration.getRuntimeService(), (TaskEntity) task, targetTaskAssigneeList);
|
||||||
|
|
||||||
List<BpmnTaskDelegateAssigner> taskDelegateAssigners =
|
List<BpmnTaskDelegateAssigner> taskDelegateAssigners =
|
||||||
validTaskAssignerDuplicated(commandContext, (TaskEntity) task, targetTaskAssigneeList);
|
validTaskAssignerDuplicated(commandContext, (TaskEntity) task, targetTaskAssigneeList);
|
||||||
|
|
||||||
@ -142,7 +146,9 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
|||||||
TaskService taskService, Task task) {
|
TaskService taskService, Task task) {
|
||||||
// 构建评论内容
|
// 构建评论内容
|
||||||
StringBuilder message = new StringBuilder("添加");
|
StringBuilder message = new StringBuilder("添加");
|
||||||
for (int i = 0; i < targetTaskAssigneeList.size(); i++) {
|
int end = NumberUtils.min(targetTaskAssigneeList.size(), COUNTERSIGN_ASSIGNER_SHOW_NUMBER);
|
||||||
|
//加签人员数量显示指定个数
|
||||||
|
for (int i = 0; i < end; i++) {
|
||||||
message.append(targetTaskAssigneeList.get(i).getAssignerName());
|
message.append(targetTaskAssigneeList.get(i).getAssignerName());
|
||||||
if (i < targetTaskAssigneeList.size() - 1) {
|
if (i < targetTaskAssigneeList.size() - 1) {
|
||||||
message.append("、");
|
message.append("、");
|
||||||
|
|||||||
@ -23,7 +23,9 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ASSIGNER_LIMIT_NUMBER;
|
||||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify;
|
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify;
|
||||||
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getLimitedElementList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义的推测用户任务的审批人的命令实现
|
* 自定义的推测用户任务的审批人的命令实现
|
||||||
@ -88,7 +90,7 @@ public class CustomForecastUserTaskAssigneeCmd extends AbstractCommand<List<Bpmn
|
|||||||
}
|
}
|
||||||
log.info("流程实例: {} , UserTask: {}推测的最终审批人为: {}", processInstanceId, userTask.getId(),
|
log.info("流程实例: {} , UserTask: {}推测的最终审批人为: {}", processInstanceId, userTask.getId(),
|
||||||
JSONUtil.toJsonStr(forecastAssigners));
|
JSONUtil.toJsonStr(forecastAssigners));
|
||||||
return forecastAssigners;
|
return getLimitedElementList(forecastAssigners, APPROVAL_ASSIGNER_LIMIT_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ASSIGNER_LIMIT_NUMBER;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
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.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
||||||
@ -58,10 +59,10 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERA
|
|||||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
|
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
|
||||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ASSIGNEE_HAS_BEEN_EXISTS;
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ASSIGNEE_HAS_BEEN_EXISTS;
|
||||||
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT;
|
||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF;
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF;
|
||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS;
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS;
|
||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE;
|
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_HAS_BEEN_COMPLETE;
|
||||||
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TASK_TYPE_MISMATCH;
|
|
||||||
import static org.flowable.task.api.Task.DEFAULT_PRIORITY;
|
import static org.flowable.task.api.Task.DEFAULT_PRIORITY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -153,7 +154,7 @@ public class CustomTaskHelper {
|
|||||||
//不包含对应的任务
|
//不包含对应的任务
|
||||||
if (!nodeTypes.contains(nodeType)) {
|
if (!nodeTypes.contains(nodeType)) {
|
||||||
// log.warn(TASK_TYPE_MISMATCH.getMessage(), nodeType.getDesc(), nodeTypes.stream().map(BpmnFlowNodeType::getDesc).collect(Collectors.joining(",")));
|
// log.warn(TASK_TYPE_MISMATCH.getMessage(), nodeType.getDesc(), nodeTypes.stream().map(BpmnFlowNodeType::getDesc).collect(Collectors.joining(",")));
|
||||||
throw new WorkflowEngineException(TASK_TYPE_MISMATCH, nodeType.getDesc(), nodeTypes.stream().map(BpmnFlowNodeType::getDesc).collect(Collectors.joining(",")));
|
throw new WorkflowEngineException(ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT, nodeType.getDesc(), nodeTypes.stream().map(BpmnFlowNodeType::getDesc).collect(Collectors.joining(",")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,6 +194,26 @@ public class CustomTaskHelper {
|
|||||||
return taskAssignerListSnapshot;
|
return taskAssignerListSnapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验人员数量是否超过限制
|
||||||
|
*
|
||||||
|
* @param runtimeService
|
||||||
|
* @param taskEntity
|
||||||
|
* @param targetAssigneeList
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<BpmnTaskDelegateAssigner> validTaskAssignerCount(RuntimeService runtimeService,
|
||||||
|
TaskEntity taskEntity,
|
||||||
|
List<BpmnTaskDelegateAssigner> targetAssigneeList) {
|
||||||
|
// 这个节点下所有审批人快照
|
||||||
|
String activityListSnapshot = INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey();
|
||||||
|
List<BpmnTaskDelegateAssigner> taskAssignerListSnapshot = runtimeService.getVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, List.class);
|
||||||
|
if (taskAssignerListSnapshot.size() + targetAssigneeList.size() > APPROVAL_ASSIGNER_LIMIT_NUMBER) {
|
||||||
|
throw new WorkflowEngineException(ASSIGNER_NUMBER_EXCEEDS_NUMBER_LIMIT);
|
||||||
|
}
|
||||||
|
return taskAssignerListSnapshot;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存附件
|
* 保存附件
|
||||||
*
|
*
|
||||||
@ -379,6 +400,22 @@ public class CustomTaskHelper {
|
|||||||
.values());
|
.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定数量元素
|
||||||
|
*
|
||||||
|
* @param assigners 原始列表列表
|
||||||
|
* @return 截取后的列表
|
||||||
|
*/
|
||||||
|
public static <T> List<T> getLimitedElementList(List<T> assigners, Integer limitNumber) {
|
||||||
|
if (limitNumber == null || limitNumber <= 0) {
|
||||||
|
throw new IllegalArgumentException("limit number must be greater than 0");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(assigners) || assigners.size() <= limitNumber) {
|
||||||
|
return assigners;
|
||||||
|
}
|
||||||
|
return new ArrayList<>(assigners.subList(0, limitNumber));
|
||||||
|
}
|
||||||
|
|
||||||
public static List<BpmnTaskDelegateAssigner> getHistoryOperationUsers(CommandContext commandContext, String processInstanceId,
|
public static List<BpmnTaskDelegateAssigner> getHistoryOperationUsers(CommandContext commandContext, String processInstanceId,
|
||||||
BpmnHistoricTaskInstanceConverter historicTaskInstanceConverter,
|
BpmnHistoricTaskInstanceConverter historicTaskInstanceConverter,
|
||||||
String serviceVersion) {
|
String serviceVersion) {
|
||||||
|
|||||||
@ -38,9 +38,10 @@ public class CustomRetryInterceptor extends AbstractCommandInterceptor {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// try to execute the command
|
// try to execute the command
|
||||||
|
log.info("assignableFrom result: {}", AbstractCommand.class.isAssignableFrom(command.getClass()));
|
||||||
if (AbstractCommand.class.isAssignableFrom(command.getClass())) {
|
if (AbstractCommand.class.isAssignableFrom(command.getClass())) {
|
||||||
// 如果在以后,重试三次也不能解决的话, 可以利用这里的拿到的参数,重新自动构造CMD,并执行.
|
// 如果在以后,重试三次也不能解决的话, 可以利用这里的拿到的参数,重新自动构造CMD,并执行.
|
||||||
log.info("traceId:{} Executing command params: {}", TraceUtil.traceId(),
|
log.info("Executing command params: {} traceId:{} ", TraceUtil.traceId(),
|
||||||
((AbstractCommand<T>) command).paramToJsonString());
|
((AbstractCommand<T>) command).paramToJsonString());
|
||||||
}
|
}
|
||||||
return next.execute(config, command, commandExecutor);
|
return next.execute(config, command, commandExecutor);
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
package cn.axzo.workflow.core.engine.job;
|
||||||
|
|
||||||
|
import cn.axzo.workflow.core.common.utils.SpringContextUtils;
|
||||||
|
import cn.axzo.workflow.core.repository.entity.ExtAxProperty;
|
||||||
|
import cn.axzo.workflow.core.service.ExtAxPropertyService;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||||
|
import org.flowable.job.service.JobHandler;
|
||||||
|
import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
||||||
|
import org.flowable.variable.api.delegate.VariableScope;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
|
||||||
|
public abstract class AbstractExecuteWithLockJobHandler extends AbstractJobHandler implements JobHandler {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AbstractExecuteWithLockJobHandler.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
|
||||||
|
ExtAxPropertyService extAxPropertyService = SpringContextUtils.getBean(ExtAxPropertyService.class);
|
||||||
|
String processInstanceId = job.getProcessInstanceId(), jobId = job.getId();
|
||||||
|
if (StringUtils.isBlank(processInstanceId) || StringUtils.isBlank(jobId)) {
|
||||||
|
log.warn("processInstanceId or lockOwner is empty,cannot execute with lock,jobId:{},processInstanceId:{}", job.getId(), job.getProcessInstanceId());
|
||||||
|
executeInternal(job, configuration, variableScope, commandContext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//todo 处理超时时间,超过一定时间,锁还存在,删除锁
|
||||||
|
try {
|
||||||
|
ExtAxProperty extAxProperty = new ExtAxProperty();
|
||||||
|
extAxProperty.setName(processInstanceId);
|
||||||
|
extAxProperty.setValue(jobId);
|
||||||
|
extAxPropertyService.add(extAxProperty);
|
||||||
|
log.info("job acquire lock success,processInstanceId:{},jobId:{}", processInstanceId, jobId);
|
||||||
|
executeInternal(job, configuration, variableScope, commandContext);
|
||||||
|
} catch (DuplicateKeyException e) {
|
||||||
|
log.error("executeWithLock error,lock by another job,jobId:{},processInstanceId:{}", job.getId(), job.getProcessInstanceId(), e);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
extAxPropertyService.delete(processInstanceId, jobId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void executeInternal(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext);
|
||||||
|
}
|
||||||
@ -12,13 +12,6 @@ import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
|||||||
import org.flowable.task.api.Task;
|
import org.flowable.task.api.Task;
|
||||||
import org.flowable.variable.api.delegate.VariableScope;
|
import org.flowable.variable.api.delegate.VariableScope;
|
||||||
|
|
||||||
import java.net.Inet4Address;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.NetworkInterface;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||||
@ -30,7 +23,7 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
|||||||
* @since 2024/4/15 22:41
|
* @since 2024/4/15 22:41
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AsyncApproveTaskJobHandler extends AbstractJobHandler implements JobHandler {
|
public class AsyncApproveTaskJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler {
|
||||||
public static final String TYPE = "async-approve-task";
|
public static final String TYPE = "async-approve-task";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -39,7 +32,7 @@ public class AsyncApproveTaskJobHandler extends AbstractJobHandler implements Jo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
|
public void executeInternal(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
|
||||||
log.info("AsyncApproveTaskJobHandler executing...");
|
log.info("AsyncApproveTaskJobHandler executing...");
|
||||||
log(job);
|
log(job);
|
||||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import org.flowable.variable.api.delegate.VariableScope;
|
|||||||
* @since 2024/4/16 11:11
|
* @since 2024/4/16 11:11
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AsyncRejectTaskJobHandler extends AbstractJobHandler implements JobHandler {
|
public class AsyncRejectTaskJobHandler extends AbstractExecuteWithLockJobHandler implements JobHandler {
|
||||||
public static final String TYPE = "async-reject-task";
|
public static final String TYPE = "async-reject-task";
|
||||||
private final ExtAxHiTaskInstService extAxHiTaskInstService;
|
private final ExtAxHiTaskInstService extAxHiTaskInstService;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ public class AsyncRejectTaskJobHandler extends AbstractJobHandler implements Job
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
|
public void executeInternal(JobEntity job, String configuration, VariableScope variableScope, CommandContext commandContext) {
|
||||||
log.info("AsyncRejectTaskJobHandler executing...");
|
log.info("AsyncRejectTaskJobHandler executing...");
|
||||||
log(job);
|
log(job);
|
||||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||||
|
|||||||
@ -108,7 +108,6 @@ public class EngineCarbonCopyEventListener implements JavaDelegate {
|
|||||||
}
|
}
|
||||||
return conf;
|
return conf;
|
||||||
}).orElse(null);
|
}).orElse(null);
|
||||||
|
|
||||||
MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.CARBON_COPY,
|
MessagePushEventImpl event = MessagePushEventBuilder.createEvent(MessagePushEventType.CARBON_COPY,
|
||||||
carbonUsers, bpmnNoticeConf, execution.getProcessInstanceId(),
|
carbonUsers, bpmnNoticeConf, execution.getProcessInstanceId(),
|
||||||
parseProcessDefinitionKey(execution.getProcessDefinitionId()),
|
parseProcessDefinitionKey(execution.getProcessDefinitionId()),
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ASSIGNER_LIMIT_NUMBER;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_ALLOW_SKIP_USER_TASK;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_ALLOW_SKIP_USER_TASK;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE_TYPE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE_TYPE;
|
||||||
@ -53,6 +54,7 @@ import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprove
|
|||||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify;
|
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify;
|
||||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType;
|
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType;
|
||||||
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getProcessServerVersion;
|
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getProcessServerVersion;
|
||||||
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getLimitedElementList;
|
||||||
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId;
|
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId;
|
||||||
|
|
||||||
|
|
||||||
@ -148,13 +150,13 @@ public class EngineExecutionStartListener implements ExecutionListener {
|
|||||||
|
|
||||||
// 审批候选人为空时的兜底
|
// 审批候选人为空时的兜底
|
||||||
emptyAssigneeHandle(assigners, userTask, execution);
|
emptyAssigneeHandle(assigners, userTask, execution);
|
||||||
|
List<BpmnTaskDelegateAssigner> resultAssigners = getLimitedElementList(assigners, APPROVAL_ASSIGNER_LIMIT_NUMBER);
|
||||||
for (BpmnTaskDelegateAssigner user : assigners) {
|
for (BpmnTaskDelegateAssigner user : resultAssigners) {
|
||||||
assigneeIdList.add(user.buildAssigneeId());
|
assigneeIdList.add(user.buildAssigneeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
execution.setVariable(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + currentActivityId,
|
execution.setVariable(INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + currentActivityId,
|
||||||
assigners);
|
resultAssigners);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// UserTask 多实例, 该变量用于引擎
|
// UserTask 多实例, 该变量用于引擎
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
package cn.axzo.workflow.core.repository.entity;
|
package cn.axzo.workflow.core.repository.entity;
|
||||||
|
|
||||||
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,6 +20,8 @@ import lombok.ToString;
|
|||||||
@TableName(value = "ext_ax_property", autoResultMap = true)
|
@TableName(value = "ext_ax_property", autoResultMap = true)
|
||||||
@Data
|
@Data
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class ExtAxProperty extends BaseEntity<ExtAxProperty> {
|
public class ExtAxProperty extends BaseEntity<ExtAxProperty> {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -39,4 +44,7 @@ public class ExtAxProperty extends BaseEntity<ExtAxProperty> {
|
|||||||
*/
|
*/
|
||||||
@TableField("manageable")
|
@TableField("manageable")
|
||||||
private Boolean manageable;
|
private Boolean manageable;
|
||||||
|
|
||||||
|
@TableField(value = "is_delete", fill = FieldFill.INSERT)
|
||||||
|
private Long isDelete = 0L;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package cn.axzo.workflow.core.service;
|
|||||||
import cn.axzo.workflow.core.repository.entity.ExtAxProperty;
|
import cn.axzo.workflow.core.repository.entity.ExtAxProperty;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 引擎服务持久配置信息表操作 Service
|
* 引擎服务持久配置信息表操作 Service
|
||||||
@ -17,4 +18,17 @@ public interface ExtAxPropertyService {
|
|||||||
ExtAxProperty update(ExtAxProperty property);
|
ExtAxProperty update(ExtAxProperty property);
|
||||||
|
|
||||||
Optional<ExtAxProperty> getByName(String name);
|
Optional<ExtAxProperty> getByName(String name);
|
||||||
|
|
||||||
|
int delete(String name, String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定时间段之前创建的数据
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param timeOut
|
||||||
|
* @param timeUnit
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int deleteByNameWithDuration(String name, Long timeOut, TimeUnit timeUnit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import org.flowable.engine.runtime.ProcessInstance;
|
|||||||
import org.flowable.job.service.JobService;
|
import org.flowable.job.service.JobService;
|
||||||
import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
||||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||||
|
import org.flowable.task.api.Task;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
@ -95,6 +96,10 @@ public class BpmnProcessActivityServiceImpl implements BpmnProcessActivityServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAssigneeAsync(BpmnActivitySetAssigneeDTO dto) {
|
public void setAssigneeAsync(BpmnActivitySetAssigneeDTO dto) {
|
||||||
|
//查询任务
|
||||||
|
Task task = CustomBizSpecifyAssigneeToTaskCmd.getOperateTask(processEngineConfiguration.getTaskService(), dto.getTriggerId());
|
||||||
|
//先校验
|
||||||
|
CustomBizSpecifyAssigneeToTaskCmd.validate(processEngineConfiguration.getRuntimeService(), dto.getTriggerId(), task, dto.getAssigners());
|
||||||
validateAndStartAsyncJob(dto.getTriggerId(), dto, JOB_ASSIGNEE_ASYNC_NAME);
|
validateAndStartAsyncJob(dto.getTriggerId(), dto, JOB_ASSIGNEE_ASYNC_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,10 +9,17 @@ import org.springframework.cache.annotation.CacheEvict;
|
|||||||
import org.springframework.cache.annotation.CachePut;
|
import org.springframework.cache.annotation.CachePut;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 引擎服务持久配置信息表操作 Service 实现
|
* 引擎服务持久配置信息表操作 Service 实现
|
||||||
@ -28,6 +35,7 @@ public class ExtAxPropertyServiceImpl implements ExtAxPropertyService {
|
|||||||
|
|
||||||
@CacheEvict(value = "property", key = "#property.name")
|
@CacheEvict(value = "property", key = "#property.name")
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
public ExtAxProperty add(ExtAxProperty property) {
|
public ExtAxProperty add(ExtAxProperty property) {
|
||||||
mapper.insert(property);
|
mapper.insert(property);
|
||||||
return property;
|
return property;
|
||||||
@ -50,4 +58,30 @@ public class ExtAxPropertyServiceImpl implements ExtAxPropertyService {
|
|||||||
.eq("name", name);
|
.eq("name", name);
|
||||||
return Optional.ofNullable(mapper.selectOne(queryWrapper));
|
return Optional.ofNullable(mapper.selectOne(queryWrapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public int delete(String name, String value) {
|
||||||
|
if (!StringUtils.hasText(name)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Map<String, Object> deleteMap = new HashMap<>();
|
||||||
|
deleteMap.put("name", name);
|
||||||
|
if (StringUtils.hasText(value)) {
|
||||||
|
deleteMap.put("value", value);
|
||||||
|
}
|
||||||
|
return mapper.deleteByMap(deleteMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteByNameWithDuration(String name, Long timeOut, TimeUnit timeUnit) {
|
||||||
|
if (!StringUtils.hasText(name) || timeOut == null || timeUnit == null) {
|
||||||
|
log.error("argument not valid,name:{},timeOut:{},timeUnit:{}", name, timeOut, timeUnit);
|
||||||
|
throw new IllegalArgumentException("argument not valid");
|
||||||
|
}
|
||||||
|
LocalDateTime startTime = LocalDateTime.now().minus(timeUnit.toMillis(timeOut), ChronoUnit.MILLIS);
|
||||||
|
QueryWrapper<ExtAxProperty> queryWrapper = new QueryWrapper<ExtAxProperty>()
|
||||||
|
.eq("name", name)
|
||||||
|
.le("create_at", startTime);
|
||||||
|
return mapper.delete(queryWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,53 @@
|
|||||||
|
package cn.axzo.workflow.core.version;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.axzo.workflow.core.common.utils.SpringContextUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.axzo.workflow.core.version.Versioned.UNKNOWN_VERSION;
|
||||||
|
|
||||||
|
public class MultiVersionBeanUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取支持指定版本的bean
|
||||||
|
*
|
||||||
|
* @param clazz 类型
|
||||||
|
* @param version 版本号
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T extends Versioned> T getSpecifiedVersionBean(Class<T> clazz, String version) {
|
||||||
|
Map<String, T> beans = SpringContextUtils.getBeansOfType(clazz);
|
||||||
|
if (CollectionUtils.isEmpty(beans)) {
|
||||||
|
throw new NullPointerException("no beans of type " + clazz.getName());
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(version)) {
|
||||||
|
T t = beans.values().stream().filter(bean -> bean.getVersion() == null || bean.getVersion() == UNKNOWN_VERSION).findFirst().orElse(null);
|
||||||
|
if (t != null) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("no default version bean found for version: " + version);
|
||||||
|
}
|
||||||
|
//根据版本号排序
|
||||||
|
List<T> sortedList = beans.values().stream().sorted((o1, o2) -> {
|
||||||
|
DefaultArtifactVersion version1 = o1.getVersion() == null ? UNKNOWN_VERSION : o1.getVersion();
|
||||||
|
DefaultArtifactVersion version2 = o2.getVersion() == null ? UNKNOWN_VERSION : o2.getVersion();
|
||||||
|
return version1.compareTo(version2);
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
DefaultArtifactVersion targetVersion = new DefaultArtifactVersion(version);
|
||||||
|
for (int i = sortedList.size() - 1; i >= 0; i--) {
|
||||||
|
DefaultArtifactVersion classVersion = sortedList.get(i).getVersion() == null ? UNKNOWN_VERSION : sortedList.get(i).getVersion();
|
||||||
|
int flag = classVersion.compareTo(targetVersion);
|
||||||
|
if (flag <= 0) {
|
||||||
|
return sortedList.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NullPointerException("no beans of type " + clazz.getName() + " and version " + version);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package cn.axzo.workflow.core.version;
|
||||||
|
|
||||||
|
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||||
|
|
||||||
|
public interface Versioned {
|
||||||
|
|
||||||
|
DefaultArtifactVersion getVersion();
|
||||||
|
|
||||||
|
DefaultArtifactVersion UNKNOWN_VERSION = new DefaultArtifactVersion("0.0.0");
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE ext_ax_property ADD UNIQUE INDEX name_unique_index (name);
|
||||||
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package cn.axzo.workflow.server.common.aspectj;
|
package cn.axzo.workflow.server.common.aspectj;
|
||||||
|
|
||||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||||
|
import cn.axzo.workflow.core.common.utils.TraceUtil;
|
||||||
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
|
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
|
||||||
import cn.axzo.workflow.server.common.config.RepeatSubmitResolver;
|
import cn.axzo.workflow.server.common.config.RepeatSubmitResolver;
|
||||||
import cn.axzo.workflow.server.common.util.RedisUtils;
|
import cn.axzo.workflow.server.common.util.RedisUtils;
|
||||||
@ -81,7 +82,7 @@ public class RepeatSubmitAspect implements Ordered {
|
|||||||
|
|
||||||
String key = RedisUtils.getCacheObject(cacheRepeatKey);
|
String key = RedisUtils.getCacheObject(cacheRepeatKey);
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofMillis(interval));
|
RedisUtils.setCacheObject(cacheRepeatKey, TraceUtil.traceId(), Duration.ofMillis(interval));
|
||||||
KEY_CACHE.set(cacheRepeatKey);
|
KEY_CACHE.set(cacheRepeatKey);
|
||||||
} else {
|
} else {
|
||||||
log.warn("{}", repeatSubmit.message());
|
log.warn("{}", repeatSubmit.message());
|
||||||
|
|||||||
@ -139,7 +139,7 @@ public class RocketMqBpmActivityEventListener extends AbstractBpmnEventListener<
|
|||||||
// 这个 ID 等于 ExecutionId
|
// 这个 ID 等于 ExecutionId
|
||||||
dto.setTriggerId(execution.getId());
|
dto.setTriggerId(execution.getId());
|
||||||
dto.setActivityId(execution.getCurrentActivityId());
|
dto.setActivityId(execution.getCurrentActivityId());
|
||||||
dto.setActivityName(((ExecutionEntityImpl) execution).getCurrentActivityName());
|
dto.setActivityName(execution.getCurrentFlowElement().getName());
|
||||||
ProcessInstance processInstance = getContext().getProcessInstance(() ->
|
ProcessInstance processInstance = getContext().getProcessInstance(() ->
|
||||||
runtimeService.createProcessInstanceQuery().processInstanceId(execution.getProcessInstanceId())
|
runtimeService.createProcessInstanceQuery().processInstanceId(execution.getProcessInstanceId())
|
||||||
.includeProcessVariables().singleResult());
|
.includeProcessVariables().singleResult());
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package cn.axzo.workflow.server.controller.listener.notice;
|
package cn.axzo.workflow.server.controller.listener.notice;
|
||||||
|
|
||||||
|
import cn.axzo.core.utils.converter.BeanConverter;
|
||||||
import cn.axzo.framework.rocketmq.Event;
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
import cn.axzo.framework.rocketmq.EventProducer;
|
import cn.axzo.framework.rocketmq.EventProducer;
|
||||||
import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum;
|
import cn.axzo.workflow.common.enums.ProcessMessagePushEventEnum;
|
||||||
@ -12,6 +13,7 @@ import cn.axzo.workflow.core.common.context.NoticeOperationContext;
|
|||||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||||
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
|
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
|
||||||
import cn.axzo.workflow.core.engine.event.MessagePushEvent;
|
import cn.axzo.workflow.core.engine.event.MessagePushEvent;
|
||||||
|
import cn.axzo.workflow.core.engine.event.MessagePushEventImpl;
|
||||||
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
|
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
|
||||||
import cn.axzo.workflow.core.listener.BpmnMessagePushEventListener;
|
import cn.axzo.workflow.core.listener.BpmnMessagePushEventListener;
|
||||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
|
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
|
||||||
@ -55,6 +57,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_SPECIFY_NE
|
|||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_OWNERSHIP_PROCESS_DEFINITION_KEY;
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.MQ_ASSIGNER_BATCH_SIZE;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.MULTI_INSTANCE_LOOP_COUNTER;
|
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.NUMBER_OF_INSTANCES;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
|
||||||
@ -135,9 +138,7 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
|||||||
log.info("RocketMqMessagePushEventListener#onNotice...msgTemplateId: {}, receivePerson: {}, processInstanceId: {}",
|
log.info("RocketMqMessagePushEventListener#onNotice...msgTemplateId: {}, receivePerson: {}, processInstanceId: {}",
|
||||||
event.getNoticeConfig().getNotice().getNoticeMessageId(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
event.getNoticeConfig().getNotice().getNoticeMessageId(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
||||||
if (Objects.nonNull(event.getNoticeConfig().getNotice())) {
|
if (Objects.nonNull(event.getNoticeConfig().getNotice())) {
|
||||||
MessagePushDTO dto = build(noticeTemplateCode,
|
getMessagePushDtoSlice(event, noticeTemplateCode, PROCESS_PUSH_NOTICE).forEach(dto -> sendMessageQueue(dto, PROCESS_PUSH_NOTICE));
|
||||||
PROCESS_PUSH_NOTICE, event, collectionVariable(event));
|
|
||||||
sendMessageQueue(dto, PROCESS_PUSH_NOTICE);
|
|
||||||
}
|
}
|
||||||
log.info("RocketMqMessagePushEventListener#onNotice...end, msgTemplateId: {}, receivePerson: {}, processInstanceId: {}",
|
log.info("RocketMqMessagePushEventListener#onNotice...end, msgTemplateId: {}, receivePerson: {}, processInstanceId: {}",
|
||||||
event.getNoticeConfig().getNotice().getNoticeMessageId(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
event.getNoticeConfig().getNotice().getNoticeMessageId(), JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
||||||
@ -245,20 +246,47 @@ public class RocketMqMessagePushEventListener extends AbstractBpmnEventListener<
|
|||||||
|| !StringUtils.hasText(event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId())) {
|
|| !StringUtils.hasText(event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO 这里的抄送人,不建议使用一个 MQ 事件来承载,而是一个人一个事件
|
|
||||||
log.info("RocketMqMessagePushEventListener#onCarbonCopy... cc' templateId: {}, receivePerson: {}, processInstanceId: {}",
|
log.info("RocketMqMessagePushEventListener#onCarbonCopy... cc' templateId: {}, receivePerson: {}, processInstanceId: {}",
|
||||||
event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(),
|
event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(),
|
||||||
JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
||||||
if (Objects.nonNull(event.getNoticeConfig().getCarbonCopy())) {
|
if (Objects.nonNull(event.getNoticeConfig().getCarbonCopy())) {
|
||||||
MessagePushDTO dto = build(event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(),
|
//按人员拆分为多个批次发送消息
|
||||||
PROCESS_CARBON_COPY, event, collectionVariable(event));
|
getMessagePushDtoSlice(event, event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(), PROCESS_CARBON_COPY).forEach(dto -> sendMessageQueue(dto, PROCESS_CARBON_COPY));
|
||||||
sendMessageQueue(dto, PROCESS_CARBON_COPY);
|
|
||||||
}
|
}
|
||||||
log.info("RocketMqMessagePushEventListener#onCarbonCopy...end, cc' templateId: {}, receivePerson: {}, processInstanceId: {}",
|
log.info("RocketMqMessagePushEventListener#onCarbonCopy...end, cc' templateId: {}, receivePerson: {}, processInstanceId: {}",
|
||||||
event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(),
|
event.getNoticeConfig().getCarbonCopy().getCarbonCopyMessageId(),
|
||||||
JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
JSONUtil.toJsonStr(event.getAssigners()), event.getProcessInstanceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据人员数量,拆分消息发送
|
||||||
|
*
|
||||||
|
* @param event 事件消息
|
||||||
|
* @return 发送mq消息列表
|
||||||
|
*/
|
||||||
|
private List<MessagePushDTO> getMessagePushDtoSlice(MessagePushEvent event, String templateId, ProcessMessagePushEventEnum type) {
|
||||||
|
if (event == null) {
|
||||||
|
throw new NullPointerException("event不能为空");
|
||||||
|
}
|
||||||
|
List<BpmnTaskDelegateAssigner> assigners = event.getAssigners();
|
||||||
|
if (CollectionUtils.isEmpty(assigners) || assigners.size() <= MQ_ASSIGNER_BATCH_SIZE) {
|
||||||
|
return Collections.singletonList(build(templateId, type, event, collectionVariable(event)));
|
||||||
|
}
|
||||||
|
List<MessagePushDTO> slice = new ArrayList<>();
|
||||||
|
Map<String, Object> objectMap = collectionVariable(event);
|
||||||
|
int startIndex = 0;
|
||||||
|
do {
|
||||||
|
List<BpmnTaskDelegateAssigner> batchAssigners = assigners.subList(startIndex, Integer.min(startIndex + MQ_ASSIGNER_BATCH_SIZE, assigners.size()));
|
||||||
|
MessagePushEventImpl messagePushEvent = new MessagePushEventImpl(event.getType());
|
||||||
|
BeanConverter.convert(event, messagePushEvent);
|
||||||
|
messagePushEvent.setAssigner(batchAssigners);
|
||||||
|
MessagePushDTO dto = build(templateId, type, messagePushEvent, objectMap);
|
||||||
|
slice.add(dto);
|
||||||
|
startIndex = startIndex + MQ_ASSIGNER_BATCH_SIZE;
|
||||||
|
} while (startIndex < assigners.size());
|
||||||
|
return slice;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 完成抄送
|
* 完成抄送
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package cn.axzo.workflow.server.controller.listener.task;
|
package cn.axzo.workflow.server.controller.listener.task;
|
||||||
|
|
||||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
import cn.axzo.workflow.common.enums.AutoApprovalTypeEnum;
|
||||||
|
import cn.axzo.workflow.common.model.request.BpmnApproveConf;
|
||||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
|
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskAuditDTO;
|
||||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||||
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
|
|
||||||
import cn.axzo.workflow.core.common.context.TaskOperationContext;
|
import cn.axzo.workflow.core.common.context.TaskOperationContext;
|
||||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||||
import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd;
|
import cn.axzo.workflow.core.engine.cmd.CustomApproveTaskCmd;
|
||||||
@ -11,22 +11,20 @@ import cn.axzo.workflow.core.engine.job.AsyncApproveTaskJobHandler;
|
|||||||
import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation;
|
import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation;
|
||||||
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
|
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
|
||||||
import cn.axzo.workflow.core.listener.BpmnTaskEventListener;
|
import cn.axzo.workflow.core.listener.BpmnTaskEventListener;
|
||||||
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
|
|
||||||
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||||
|
import cn.axzo.workflow.core.version.MultiVersionBeanUtils;
|
||||||
|
import cn.axzo.workflow.server.controller.listener.task.service.CheckApproverService;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.bpmn.model.FlowElement;
|
|
||||||
import org.flowable.bpmn.model.Process;
|
import org.flowable.bpmn.model.Process;
|
||||||
import org.flowable.bpmn.model.UserTask;
|
import org.flowable.bpmn.model.UserTask;
|
||||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||||
import org.flowable.engine.HistoryService;
|
|
||||||
import org.flowable.engine.RepositoryService;
|
import org.flowable.engine.RepositoryService;
|
||||||
import org.flowable.engine.RuntimeService;
|
import org.flowable.engine.RuntimeService;
|
||||||
import org.flowable.engine.TaskService;
|
import org.flowable.engine.TaskService;
|
||||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||||
import org.flowable.engine.impl.persistence.entity.ActivityInstanceEntity;
|
|
||||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||||
import org.flowable.job.service.JobService;
|
import org.flowable.job.service.JobService;
|
||||||
import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
import org.flowable.job.service.impl.persistence.entity.JobEntity;
|
||||||
@ -37,11 +35,10 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
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.COMMENT_TYPE_OPERATION_DESC;
|
||||||
@ -53,10 +50,8 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
|||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TYPE_REJECT;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
||||||
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
|
||||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
|
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
|
||||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK;
|
|
||||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
|
|
||||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED;
|
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.REJECTED;
|
||||||
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.REJECTION_AUTO_COMPLETED;
|
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.REJECTION_AUTO_COMPLETED;
|
||||||
|
|
||||||
@ -79,7 +74,6 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
|||||||
private final TaskService taskService;
|
private final TaskService taskService;
|
||||||
private final RuntimeService runtimeService;
|
private final RuntimeService runtimeService;
|
||||||
private final RepositoryService repositoryService;
|
private final RepositoryService repositoryService;
|
||||||
private final HistoryService historyService;
|
|
||||||
private final ExtAxHiTaskInstService extAxHiTaskInstService;
|
private final ExtAxHiTaskInstService extAxHiTaskInstService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -94,14 +88,20 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
|||||||
Process mainProcess = repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()).getMainProcess();
|
Process mainProcess = repositoryService.getBpmnModel(delegateTask.getProcessDefinitionId()).getMainProcess();
|
||||||
UserTask userTask = (UserTask) mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey());
|
UserTask userTask = (UserTask) mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey());
|
||||||
|
|
||||||
boolean exists = checkApproverExists(delegateTask, userTask, mainProcess);
|
Optional<BpmnApproveConf> processApproveConf = BpmnMetaParserHelper.getProcessApproveConf(mainProcess);
|
||||||
log.info("是否需要自动过程判断 exists:{}", exists);
|
//自动过审配置连续节点自动过审才处理,历史数据默认不自动过审
|
||||||
if (exists) {
|
if (processApproveConf.isPresent() && AutoApprovalTypeEnum.CONTINUOUS_NODES_AUTO_APPROVAL == processApproveConf.get().getAutoApprovalType()) {
|
||||||
taskService.addComment(delegateTask.getId(), delegateTask.getProcessInstanceId(), COMMENT_TYPE_ADVICE,
|
Object versionVar = delegateTask.getVariable(WORKFLOW_ENGINE_VERSION);
|
||||||
"同一审批人,自动过审");
|
String version = versionVar == null ? null : String.valueOf(versionVar);
|
||||||
autoPass(delegateTask);
|
CheckApproverService checkApproverService = MultiVersionBeanUtils.getSpecifiedVersionBean(CheckApproverService.class, version);
|
||||||
|
boolean exists = checkApproverService.checkApproverExists(delegateTask, userTask, mainProcess, getContext());
|
||||||
|
log.info("是否需要自动过程判断 exists:{},processInstId:{},taskDefinitionKey:{}", exists, delegateTask.getProcessInstanceId(), delegateTask.getTaskDefinitionKey());
|
||||||
|
if (exists) {
|
||||||
|
taskService.addComment(delegateTask.getId(), delegateTask.getProcessInstanceId(), COMMENT_TYPE_ADVICE,
|
||||||
|
"同一审批人,自动过审");
|
||||||
|
autoPass(delegateTask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测节点自身配置是否有自动操作
|
// 检测节点自身配置是否有自动操作
|
||||||
checkApprovalMethod(delegateTask, userTask);
|
checkApprovalMethod(delegateTask, userTask);
|
||||||
|
|
||||||
@ -140,72 +140,6 @@ public class AutoOperatorEvent_101_Listener extends AbstractBpmnEventListener<Ta
|
|||||||
jobService.scheduleAsyncJob(job);
|
jobService.scheduleAsyncJob(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验当前的审批人是否存在过前一个节点
|
|
||||||
*
|
|
||||||
* @param delegateTask
|
|
||||||
* @param userTask
|
|
||||||
* @param mainProcess
|
|
||||||
*/
|
|
||||||
private boolean checkApproverExists(DelegateTask delegateTask, UserTask userTask, Process mainProcess) {
|
|
||||||
AtomicBoolean exists = new AtomicBoolean(false);
|
|
||||||
FlowElement currentFlowElement = mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey());
|
|
||||||
BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(currentFlowElement).orElse(NODE_EMPTY);
|
|
||||||
if (!Objects.equals(currentNodeType, NODE_TASK)) {
|
|
||||||
return exists.get();
|
|
||||||
}
|
|
||||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
|
||||||
processEngineConfiguration.getActivityInstanceEntityManager()
|
|
||||||
.findActivityInstancesByProcessInstanceId(delegateTask.getProcessInstanceId(), false)
|
|
||||||
.stream()
|
|
||||||
.filter(i -> !Objects.equals(i.getActivityId(), userTask.getId()))
|
|
||||||
.filter(i -> !Objects.equals(i.getActivityType(), "exclusiveGateway"))
|
|
||||||
.filter(i -> !Objects.equals(i.getActivityType(), "sequenceFlow"))
|
|
||||||
.max(Comparator.comparing(ActivityInstanceEntity::getStartTime))
|
|
||||||
.ifPresent(i -> {
|
|
||||||
// 与发起人比对
|
|
||||||
if (Objects.equals(NODE_STARTER.getType(), i.getActivityId())) {
|
|
||||||
BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR));
|
|
||||||
if (Objects.nonNull(initiator) && initiator.comparePersonIdToOther(delegateTask.getAssignee())) {
|
|
||||||
exists.compareAndSet(false, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FlowElement flowElement = mainProcess.getFlowElement(i.getActivityId());
|
|
||||||
BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(j -> {
|
|
||||||
if (Objects.equals(NODE_TASK, j)) {
|
|
||||||
ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO();
|
|
||||||
searchDTO.setProcessInstanceId(delegateTask.getProcessInstanceId());
|
|
||||||
searchDTO.setTaskDefinitionKey(i.getActivityId());
|
|
||||||
getContext().getExtAxHiTaskInsts(() -> extAxHiTaskInstService.queryList(searchDTO))
|
|
||||||
.stream().filter(e -> Objects.equals(e.getStatus(), APPROVED.getStatus()))
|
|
||||||
.map(ExtAxHiTaskInst::getAssignee)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.filter(StringUtils::hasText)
|
|
||||||
.filter(k -> specialApproverComparison(k, delegateTask.getAssignee()))
|
|
||||||
.findAny().ifPresent(k -> exists.compareAndSet(false, true));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return exists.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 特殊审批人字段的比对, 兼容旧迭代导致的数据格式
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean specialApproverComparison(String compareAssignee, String currentAssignee) {
|
|
||||||
if (StringUtils.hasText(compareAssignee) && StringUtils.hasText(currentAssignee)) {
|
|
||||||
String[] compareSplit = compareAssignee.split("\\|");
|
|
||||||
String[] currentSplit = currentAssignee.split("\\|");
|
|
||||||
if (compareSplit.length == 2 || currentSplit.length == 2) {
|
|
||||||
return Objects.equals(compareSplit[1], currentSplit[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 如果审批人为空时, 读取 approverEmptyHandleType = 自动通过或自动驳回
|
* 如果审批人为空时, 读取 approverEmptyHandleType = 自动通过或自动驳回
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
package cn.axzo.workflow.server.controller.listener.task.service;
|
||||||
|
|
||||||
|
import cn.axzo.workflow.core.common.context.TaskOperationContext;
|
||||||
|
import cn.axzo.workflow.core.version.Versioned;
|
||||||
|
import org.flowable.bpmn.model.Process;
|
||||||
|
import org.flowable.bpmn.model.UserTask;
|
||||||
|
import org.flowable.task.service.delegate.DelegateTask;
|
||||||
|
|
||||||
|
public interface CheckApproverService extends Versioned {
|
||||||
|
|
||||||
|
boolean checkApproverExists(DelegateTask delegateTask, UserTask userTask, Process mainProcess, TaskOperationContext taskOperationContext);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,141 @@
|
|||||||
|
package cn.axzo.workflow.server.controller.listener.task.service.impl;
|
||||||
|
|
||||||
|
import cn.axzo.workflow.common.enums.BpmnButtonEnum;
|
||||||
|
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||||
|
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonConf;
|
||||||
|
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
|
||||||
|
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||||
|
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
|
||||||
|
import cn.axzo.workflow.core.common.context.TaskOperationContext;
|
||||||
|
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||||
|
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
|
||||||
|
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||||
|
import cn.axzo.workflow.server.controller.listener.task.service.CheckApproverService;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||||
|
import org.flowable.bpmn.model.FlowElement;
|
||||||
|
import org.flowable.bpmn.model.Process;
|
||||||
|
import org.flowable.bpmn.model.UserTask;
|
||||||
|
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||||
|
import org.flowable.engine.impl.persistence.entity.ActivityInstanceEntity;
|
||||||
|
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||||
|
import org.flowable.task.service.delegate.DelegateTask;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||||
|
import static cn.axzo.workflow.common.constant.BpmnConstants.NO_ASSIGNEE;
|
||||||
|
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_BUSINESS;
|
||||||
|
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_EMPTY;
|
||||||
|
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
|
||||||
|
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK;
|
||||||
|
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REQ-2596. 自动过审规则:
|
||||||
|
* a. 审批人=发起人/历史审批人
|
||||||
|
* b. 连续节点
|
||||||
|
* c. 当前节点有同意按钮
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CheckApproverServiceImpl implements CheckApproverService {
|
||||||
|
|
||||||
|
private final ExtAxHiTaskInstService extAxHiTaskInstService;
|
||||||
|
|
||||||
|
public boolean checkApproverExists(DelegateTask delegateTask, UserTask userTask, Process mainProcess, TaskOperationContext taskOperationContext) {
|
||||||
|
AtomicBoolean exists = new AtomicBoolean(false);
|
||||||
|
FlowElement currentFlowElement = mainProcess.getFlowElement(delegateTask.getTaskDefinitionKey());
|
||||||
|
BpmnFlowNodeType currentNodeType = BpmnMetaParserHelper.getNodeType(currentFlowElement).orElse(NODE_EMPTY);
|
||||||
|
//业务节点,指定业务审批人,或者业务设置了审批人,也要参与自动过审,node_type为NODE_BUSINESS,节点元素类型为UserTask
|
||||||
|
//业务节点审批人为空,或者人员未指定,此时不进行自动过审操作,需要再业务指定审批人后,再做自动过审动作
|
||||||
|
if (!(Objects.equals(currentNodeType, NODE_TASK) || Objects.equals(currentNodeType, NODE_BUSINESS)) ||
|
||||||
|
!StringUtils.hasText(delegateTask.getAssignee()) ||
|
||||||
|
delegateTask.getAssignee().equals(NO_ASSIGNEE)) {
|
||||||
|
return exists.get();
|
||||||
|
}
|
||||||
|
Optional<BpmnButtonConf> optConfig = BpmnMetaParserHelper.getButtonConfig(mainProcess, delegateTask.getTaskDefinitionKey());
|
||||||
|
if (!optConfig.isPresent()) {
|
||||||
|
return exists.get();
|
||||||
|
}
|
||||||
|
BpmnButtonConf bpmnButtonConf = optConfig.get();
|
||||||
|
List<BpmnButtonMetaInfo> currentButtons = bpmnButtonConf.getCurrent();
|
||||||
|
if (CollectionUtils.isEmpty(currentButtons)) {
|
||||||
|
return exists.get();
|
||||||
|
}
|
||||||
|
Optional<BpmnButtonMetaInfo> agreeButton = currentButtons.stream()
|
||||||
|
.filter(button -> button.getType().equals("SYSTEM") //系统按钮
|
||||||
|
&& button.getChecked() != null && button.getChecked() //选中
|
||||||
|
&& (button.getDisabled() == null || !button.getDisabled()) //没用禁用
|
||||||
|
&& button.getBtnKey().equals(BpmnButtonEnum.BPMN_APPROVE.getBtnKey())) //类型为同意
|
||||||
|
.findFirst();
|
||||||
|
//不存在同意按钮
|
||||||
|
if (!agreeButton.isPresent()) {
|
||||||
|
return exists.get();
|
||||||
|
}
|
||||||
|
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||||
|
processEngineConfiguration.getActivityInstanceEntityManager()
|
||||||
|
.findActivityInstancesByProcessInstanceId(delegateTask.getProcessInstanceId(), false)
|
||||||
|
.stream()
|
||||||
|
.filter(i -> !Objects.equals(i.getActivityId(), userTask.getId()))
|
||||||
|
.filter(i -> !Objects.equals(i.getActivityType(), "exclusiveGateway"))
|
||||||
|
.filter(i -> !Objects.equals(i.getActivityType(), "sequenceFlow"))
|
||||||
|
.max(Comparator.comparing(ActivityInstanceEntity::getStartTime))
|
||||||
|
.ifPresent(i -> {
|
||||||
|
// 与发起人比对
|
||||||
|
if (Objects.equals(NODE_STARTER.getType(), i.getActivityId())) {
|
||||||
|
BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(delegateTask.getVariable(INTERNAL_INITIATOR));
|
||||||
|
if (Objects.nonNull(initiator) && initiator.comparePersonIdToOther(delegateTask.getAssignee())) {
|
||||||
|
exists.compareAndSet(false, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FlowElement flowElement = mainProcess.getFlowElement(i.getActivityId());
|
||||||
|
BpmnMetaParserHelper.getNodeType(flowElement).ifPresent(j -> {
|
||||||
|
//上一节点如果是业务节点,但是是人员审批,也需要加入到自动过审
|
||||||
|
if (Objects.equals(NODE_TASK, j) || (Objects.equals(NODE_BUSINESS, j) && flowElement.getClass().isAssignableFrom(UserTask.class))) {
|
||||||
|
ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO();
|
||||||
|
searchDTO.setProcessInstanceId(delegateTask.getProcessInstanceId());
|
||||||
|
searchDTO.setTaskDefinitionKey(i.getActivityId());
|
||||||
|
taskOperationContext.getExtAxHiTaskInsts(() -> extAxHiTaskInstService.queryList(searchDTO))
|
||||||
|
.stream().filter(e -> Objects.equals(e.getStatus(), APPROVED.getStatus()))
|
||||||
|
.map(ExtAxHiTaskInst::getAssignee)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(StringUtils::hasText)
|
||||||
|
.filter(k -> specialApproverComparison(k, delegateTask.getAssignee()))
|
||||||
|
.findAny().ifPresent(k -> exists.compareAndSet(false, true));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return exists.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 特殊审批人字段的比对, 兼容旧迭代导致的数据格式
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean specialApproverComparison(String compareAssignee, String currentAssignee) {
|
||||||
|
if (StringUtils.hasText(compareAssignee) && StringUtils.hasText(currentAssignee)) {
|
||||||
|
String[] compareSplit = compareAssignee.split("\\|");
|
||||||
|
String[] currentSplit = currentAssignee.split("\\|");
|
||||||
|
if (compareSplit.length == 2 || currentSplit.length == 2) {
|
||||||
|
return Objects.equals(compareSplit[1], currentSplit[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DefaultArtifactVersion getVersion() {
|
||||||
|
// return new DefaultArtifactVersion(FLOW_SERVER_VERSION_130);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -23,6 +23,7 @@ import cn.axzo.workflow.core.service.BpmnProcessTaskService;
|
|||||||
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
|
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
|
||||||
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
|
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
|
||||||
import cn.azxo.framework.common.model.CommonResponse;
|
import cn.azxo.framework.common.model.CommonResponse;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.ListUtils;
|
import org.apache.commons.collections4.ListUtils;
|
||||||
@ -186,7 +187,7 @@ public class BpmnProcessTaskController implements ProcessTaskApi {
|
|||||||
@PostMapping("/countersign")
|
@PostMapping("/countersign")
|
||||||
@RepeatSubmit
|
@RepeatSubmit
|
||||||
public CommonResponse<Boolean> countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO countersignDTO) {
|
public CommonResponse<Boolean> countersignTask(@Validated @RequestBody BpmnTaskCountersignDTO countersignDTO) {
|
||||||
log.info("加签任务 countersignTask===>>>参数:{}", countersignDTO);
|
log.info("加签任务 countersignTask===>>>参数:{}", JSON.toJSONString(countersignDTO));
|
||||||
bpmnProcessTaskService.countersignTask(countersignDTO);
|
bpmnProcessTaskService.countersignTask(countersignDTO);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user