Merge branch 'feature/REQ-3383' into feature/REQ-3004

# Conflicts:
#	workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomAbortProcessInstanceCmd.java
#	workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCancelProcessInstanceCmd.java
#	workflow-engine-core/src/main/java/cn/axzo/workflow/core/engine/cmd/CustomCompleteDummyTaskCmd.java
#	workflow-engine-core/src/main/java/cn/axzo/workflow/core/service/impl/BpmnProcessTaskServiceImpl.java
This commit is contained in:
wangli 2024-12-10 11:31:10 +08:00
commit e04d4995a8
28 changed files with 530 additions and 96 deletions

View File

@ -0,0 +1,72 @@
package cn.axzo.workflow.common.constraint;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.List;
/**
* 附件校验器
*
* @author wangli
* @since 2024/4/22 15:15
*/
public class AttachmentConstraintValidator implements ConstraintValidator<AttachmentValidator, List<AttachmentDTO>> {
private AttachmentTypeValidator[] typeConstraints;
@Override
public void initialize(AttachmentValidator constraintAnnotation) {
this.typeConstraints = constraintAnnotation.types();
}
@Override
public boolean isValid(List<AttachmentDTO> attachments, ConstraintValidatorContext context) {
if (attachments == null || attachments.isEmpty()) {
return true; // No attachments, so no validation needed
}
boolean isValid = true;
for (AttachmentTypeValidator typeConstraint : typeConstraints) {
AttachmentTypeEnum type = typeConstraint.type();
int minAllowed = typeConstraint.min();
int maxAllowed = typeConstraint.max();
int count = getCountOfType(attachments, type);
// Check if min or max is not limited
boolean minNotLimited = minAllowed == -1;
boolean maxNotLimited = maxAllowed == Integer.MAX_VALUE;
if (!minNotLimited && count < minAllowed) {
addErrorMessage(context, typeConstraint.type().getDesc() + "数量最小支持" + minAllowed + "");
isValid = false; // Validation failed due to min limit
}
if (!maxNotLimited && count > maxAllowed) {
addErrorMessage(context, typeConstraint.type().getDesc() + "数量最大支持" + maxAllowed + "");
isValid = false; // Validation failed due to max limit
}
}
return isValid; // Validation passed
}
// Helper method to count attachments of a specific type
private int getCountOfType(List<AttachmentDTO> attachments, AttachmentTypeEnum type) {
int count = 0;
for (AttachmentDTO attachment : attachments) {
if (attachment.getType().equals(type)) {
count++;
}
}
return count;
}
private void addErrorMessage(ConstraintValidatorContext context, String message) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addConstraintViolation();
}
}

View File

@ -0,0 +1,41 @@
package cn.axzo.workflow.common.constraint;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 工作流主要操作时, 附件的校验
*
* @author wangli
* @since 2024/4/22 15:17
*/
@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AttachmentTypeValidator {
/**
* 指定的附件类型
*
* @return
*/
AttachmentTypeEnum type();
/**
* 最小个数: -1 不限制
*
* @return
*/
int min() default -1;
/**
* 最大个数: -1 不限制
*
* @return
*/
int max() default Integer.MAX_VALUE;
}

View File

@ -0,0 +1,31 @@
package cn.axzo.workflow.common.constraint;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 工作流主要操作时, 附件的校验
*
* @author wangli
* @since 2024/4/22 15:17
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = AttachmentConstraintValidator.class)
@Documented
public @interface AttachmentValidator {
String message() default "附件校验不通过";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
AttachmentTypeValidator[] types();
}

View File

@ -0,0 +1,26 @@
package cn.axzo.workflow.common.model.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 简单的任务模型
*
* @author wangli
* @since 2024-12-09 14:30
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SimpleTaskDTO {
/**
* 流程实例 ID
*/
private String processInstanceId;
/**
* 任务 ID
*/
private String taskId;
}

View File

@ -1,5 +1,10 @@
package cn.axzo.workflow.common.model.request.bpmn.process;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@ -9,6 +14,8 @@ import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.List;
/**
* 中止流程实例的入参模型
@ -45,6 +52,40 @@ public class BpmnProcessInstanceAbortDTO {
@Length(max = 100, message = "中止原因长度不能超过 100 个字符")
private String reason;
/**
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
/**
* 中止节点的名称
* 为空时则默认展示为系统中止
*/
@ApiModelProperty(value = "中止节点名称")
private String nodeName;
/**
* 指定中止的操作人信息
* <p>
* 只能是 axzo 平台存在的人
*/
@ApiModelProperty(value = "指定该动作的操作人")
private BpmnTaskDelegateAssigner assigner;
/**
* 暂不生效
* 手写签名图片地址
*/
@ApiModelProperty(value = "手写签名url")
@Deprecated
private String signatureUrl;
/**
* 是否异步执行
*/

View File

@ -1,5 +1,9 @@
package cn.axzo.workflow.common.model.request.bpmn.process;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -11,6 +15,8 @@ import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
/**
* 取消流程实例的入参模型
@ -45,6 +51,25 @@ public class BpmnProcessInstanceCancelDTO {
@ApiModelProperty(value = "撤回的原因", example = "主动撤回")
private String reason;
/**
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
/**
* 撤回节点的名称
* 为空时则默认展示为发起人撤回
*/
@ApiModelProperty(value = "撤回节点名称")
private String nodeName;
/**
* 发起人的信息
*/

View File

@ -1,5 +1,8 @@
package cn.axzo.workflow.common.model.request.bpmn.process;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import io.swagger.annotations.ApiModel;
@ -11,6 +14,7 @@ import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.util.List;
/**
@ -43,6 +47,12 @@ public class BpmnProcessInstanceCarbonCopyDTO {
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
/**

View File

@ -1,5 +1,8 @@
package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@ -9,6 +12,8 @@ import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.List;
/**
* 完成机器人节点的入参模型
@ -40,11 +45,9 @@ public class BpmnRobotTaskCompleteDTO {
/**
* 完成机器人节点的人信息
*
* @since 1.3.0 版本后不支持传人员信息
* @since 不支持传人员信息
*/
@ApiModelProperty(value = "当前审核人信息", notes = "可为空,则该任务不验证用户归属")
// @Valid
// @NotNull(message = "审批人不能为空")
@Deprecated
private BpmnTaskDelegateAssigner approver;
@ -52,6 +55,18 @@ public class BpmnRobotTaskCompleteDTO {
@Valid
private BpmnFlowNodeDTO robotNode;
/**
* 图片附件
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
/**
* 是否异步执行
*/

View File

@ -33,11 +33,10 @@ public class BpmnRobotTaskCreateDTO {
/**
* 当前审核人信息
*
* @since 1.3.0 版本不支持传人员信息
* @since 不支持传人员信息
*/
@ApiModelProperty(value = "当前审核人信息", notes = "可为空,则该任务不验证用户归属", hidden = true)
// @Valid
// @NotNull(message = "审批人不能为空")
@Deprecated
private BpmnTaskDelegateAssigner approver;
/**

View File

@ -1,5 +1,8 @@
package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -12,6 +15,7 @@ import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
/**
@ -41,6 +45,12 @@ public class BpmnTaskAuditDTO {
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
/**

View File

@ -1,5 +1,8 @@
package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@ -11,6 +14,7 @@ import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.List;
@ -60,6 +64,12 @@ public class BpmnTaskCommentDTO implements Serializable {
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
@Valid
private List<AttachmentDTO> attachmentList;

View File

@ -1,5 +1,8 @@
package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@ -11,6 +14,7 @@ import lombok.experimental.Accessors;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.List;
@ -58,6 +62,12 @@ public class BpmnTaskCountersignDTO implements Serializable {
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
/**

View File

@ -1,5 +1,8 @@
package cn.axzo.workflow.common.model.request.bpmn.task;
import cn.axzo.workflow.common.constraint.AttachmentTypeValidator;
import cn.axzo.workflow.common.constraint.AttachmentValidator;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
@ -9,6 +12,7 @@ import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.List;
@ -44,6 +48,12 @@ public class BpmnTaskTransferDTO implements Serializable {
* 附件列表
*/
@ApiModelProperty(value = "附件列表")
@Size(max = 11, message = "附件数量超过限制")
@AttachmentValidator(types = {
@AttachmentTypeValidator(type = AttachmentTypeEnum.image, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.file, max = 5),
@AttachmentTypeValidator(type = AttachmentTypeEnum.signature, max = 1)}
)
private List<AttachmentDTO> attachmentList;
/**

View File

@ -1,7 +1,9 @@
package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.engine.model.AddComment;
import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
@ -13,14 +15,18 @@ import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_ABORT;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_TENANT_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_ID;
@ -32,9 +38,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERA
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_ABORT;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.ABORTED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.CANCELLED;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_ABORT;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask;
@ -48,13 +52,21 @@ public class CustomAbortProcessInstanceCmd extends AbstractCommand<Void> impleme
private final String processInstanceId;
private final String tenantId;
private final String reason;
private final List<AttachmentDTO> attachmentList;
private final String nodeName;
private BpmnTaskDelegateAssigner assigner;
private final String signatureUrl;
private final ExtAxHiTaskInstService extAxHiTaskInstService;
public CustomAbortProcessInstanceCmd(String processInstanceId, String tenantId, String reason,
ExtAxHiTaskInstService extAxHiTaskInstService) {
this.processInstanceId = processInstanceId;
this.tenantId = tenantId;
this.reason = reason;
public CustomAbortProcessInstanceCmd(BpmnProcessInstanceAbortDTO dto, ExtAxHiTaskInstService extAxHiTaskInstService) {
this.processInstanceId = dto.getProcessInstanceId();
this.tenantId = dto.getTenantId();
this.reason = dto.getReason();
this.attachmentList = dto.getAttachmentList();
this.nodeName = StringUtils.hasText(dto.getNodeName()) ? dto.getNodeName() : "系统中止";
this.assigner = Objects.nonNull(dto.getAssigner()) ? dto.getAssigner() :
BpmnTaskDelegateAssigner.buildDummyAssigner("system", TASK_ASSIGNEE_SKIP_FLAT, "");
this.signatureUrl = dto.getSignatureUrl();
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@ -64,6 +76,10 @@ public class CustomAbortProcessInstanceCmd extends AbstractCommand<Void> impleme
params.put("processInstanceId", processInstanceId);
params.put("tenantId", tenantId);
params.put("reason", reason);
params.put("attachmentList", JSON.toJSONString(attachmentList));
params.put("nodeName", nodeName);
params.put("assigner", assigner);
params.put("signatureUrl", signatureUrl);
return JSON.toJSONString(params);
}
@ -91,24 +107,25 @@ public class CustomAbortProcessInstanceCmd extends AbstractCommand<Void> impleme
throw new WorkflowEngineException(PROCESS_INSTANCE_CANT_ABORT);
}
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
Map<String, Object> variables = new HashMap<>();
variables.put(INTERNAL_END_TENANT_ID, tenantId);
variables.put(INTERNAL_END_USER_ID, "system");
variables.put(INTERNAL_END_USER_NAME, "系统");
variables.put(INTERNAL_DELETE_PROCESS_FLAG, INTERNAL_PROCESS_TYPE_ABORT);
variables.put(INTERNAL_PROCESS_DELETE_REASON, reason);
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
variables.put(INTERNAL_END_TENANT_ID, assigner.getTenantId());
variables.put(INTERNAL_END_USER_ID, assigner.buildAssigneeId());
variables.put(INTERNAL_END_USER_NAME, assigner.getAssignerName());
runtimeService.setVariables(instance.getId(), variables);
CommandContextUtil.getAgenda(commandContext).planOperation(new DeleteProcessInstanceOperation(commandContext,
processInstanceId, extAxHiTaskInstService, ABORTED));
processInstanceId, extAxHiTaskInstService, ABORTED));
// 添加自定义的节点,用于展示最后的操作
Task task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId,
"系统中止", NODE_ABORT.getType(), null, BpmnTaskDelegateAssigner.buildDummyAssigner("system",
TASK_ASSIGNEE_SKIP_FLAT, "系统"), ABORTED.getStatus(), new AddComment(reason));
TaskEntity task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId,
nodeName, NODE_ABORT.getType(), null, assigner, ABORTED.getStatus(), new AddComment(reason));
runtimeService.setVariable(task.getProcessInstanceId(), TASK_COMPLETE_OPERATION_TYPE + task.getId(), ABORTED);
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, assigner);
completeVirtualTask(commandContext, task);
return null;
}

View File

@ -1,7 +1,9 @@
package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.engine.model.AddComment;
import cn.axzo.workflow.core.engine.operation.DeleteProcessInstanceOperation;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
@ -12,13 +14,19 @@ import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_CANCEL;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_DELETE_PROCESS_FLAG;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_TENANT_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_END_USER_ID;
@ -28,10 +36,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_TY
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CANCEL;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.ABORTED;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.CANCELLED;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_CANT_CANCEL;
import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_NOT_EXISTS;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask;
@ -46,15 +51,18 @@ public class CustomCancelProcessInstanceCmd extends AbstractCommand<Void> implem
private final String tenantId;
private final String reason;
private final BpmnTaskDelegateAssigner initiator;
private final String nodeName;
private final List<AttachmentDTO> attachmentList;
private final ExtAxHiTaskInstService extAxHiTaskInstService;
public CustomCancelProcessInstanceCmd(String processInstanceId, String tenantId, String reason,
BpmnTaskDelegateAssigner initiator,
public CustomCancelProcessInstanceCmd(BpmnProcessInstanceCancelDTO dto,
ExtAxHiTaskInstService extAxHiTaskInstService) {
this.processInstanceId = processInstanceId;
this.tenantId = tenantId;
this.reason = reason;
this.initiator = initiator;
this.processInstanceId = dto.getProcessInstanceId();
this.tenantId = dto.getTenantId();
this.reason = dto.getReason();
this.initiator = dto.getInitiator();
this.nodeName = StringUtils.hasText(dto.getNodeName()) ? dto.getNodeName() : "发起人撤回";
this.attachmentList = dto.getAttachmentList();
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@ -94,6 +102,7 @@ public class CustomCancelProcessInstanceCmd extends AbstractCommand<Void> implem
throw new WorkflowEngineException(PROCESS_INSTANCE_CANT_CANCEL);
}
Map<String, Object> variables = new HashMap<>();
variables.put(INTERNAL_END_TENANT_ID, tenantId);
variables.put(INTERNAL_END_USER_ID, initiator.buildAssigneeId());
@ -107,8 +116,11 @@ public class CustomCancelProcessInstanceCmd extends AbstractCommand<Void> implem
processInstanceId, extAxHiTaskInstService, CANCELLED));
// 添加自定义的节点,用于展示最后的操作
Task task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId,
"发起人撤回", NODE_CANCEL.getType(), reason, initiator, CANCELLED.getStatus(), new AddComment(CANCELLED.getDesc()));
TaskEntity task = createVirtualTask(commandContext, extAxHiTaskInstService, processInstanceId,
nodeName, NODE_CANCEL.getType(), reason, initiator, CANCELLED.getStatus(), new AddComment(CANCELLED.getDesc()));
batchAddAttachment(commandContext, processInstanceId, task, attachmentList, initiator);
completeVirtualTask(commandContext, task);
return null;
}

View File

@ -1,15 +1,22 @@
package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.dto.SimpleTaskDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
import cn.axzo.workflow.core.engine.tx.listener.RobotTaskTransactionListener;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
import com.alibaba.fastjson.JSON;
import org.flowable.common.engine.impl.cfg.TransactionState;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.context.Context;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
@ -17,15 +24,20 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_FLAT;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_ROBOT;
import static cn.axzo.workflow.common.code.BpmnTaskRespCode.DUMMY_TASK_NOT_EXISTS;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_FLAT;
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_ROBOT;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.APPROVED;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
/**
* 自定义的完成虚拟任务命令实现
@ -36,17 +48,26 @@ import static cn.axzo.workflow.common.code.BpmnTaskRespCode.DUMMY_TASK_NOT_EXIST
public class CustomCompleteDummyTaskCmd extends AbstractCommand<Void> implements Serializable {
private final String processInstanceId;
private final String taskId;
private final String flowNodeName;
private final String operationDesc;
private String flowNodeName;
private String operationDesc;
private final List<AttachmentDTO> attachmentList;
private final BpmnTaskDelegateAssigner operator;
private final ExtAxHiTaskInstService extAxHiTaskInstService;
private final ExtAxProcessLogService extAxProcessLogService;
public CustomCompleteDummyTaskCmd(String processInstanceId, String taskId, String flowNodeName,
String operationDesc, ExtAxHiTaskInstService extAxHiTaskInstService) {
this.processInstanceId = processInstanceId;
this.taskId = taskId;
this.flowNodeName = flowNodeName;
this.operationDesc = operationDesc;
public CustomCompleteDummyTaskCmd(BpmnRobotTaskCompleteDTO dto,
ExtAxHiTaskInstService extAxHiTaskInstService,
ExtAxProcessLogService extAxProcessLogService) {
this.processInstanceId = dto.getProcessInstanceId();
this.taskId = dto.getTaskId();
if (Objects.nonNull(dto.getRobotNode())) {
this.flowNodeName = dto.getRobotNode().getFlowNodeName();
this.operationDesc = dto.getRobotNode().getOperationDesc();
}
this.attachmentList = dto.getAttachmentList();
this.operator = dto.getApprover();
this.extAxHiTaskInstService = extAxHiTaskInstService;
this.extAxProcessLogService = extAxProcessLogService;
}
@Override
@ -81,13 +102,17 @@ public class CustomCompleteDummyTaskCmd extends AbstractCommand<Void> implements
Authentication.setAuthenticatedUserId(null);
}
BpmnTaskDelegateAssigner assignee = BpmnTaskDelegateAssigner.buildDummyAssigner("system",
TASK_ASSIGNEE_SKIP_FLAT, "系统");
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, assignee);
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + taskId, APPROVED.getStatus());
taskService.complete(task.getId());
continueProcessingTask(commandContext);
CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, processInstanceId, task.getId(),
NODE_ROBOT.getType(), BpmnTaskDelegateAssigner.buildDummyAssigner("system",
TASK_ASSIGNEE_SKIP_FLAT, "系统"), BpmnProcessInstanceResultEnum.APPROVED.getStatus());
NODE_ROBOT.getType(), assignee, BpmnProcessInstanceResultEnum.APPROVED.getStatus());
return null;
}
@ -99,12 +124,18 @@ public class CustomCompleteDummyTaskCmd extends AbstractCommand<Void> implements
if (CollectionUtils.isEmpty(taskList)) {
return;
}
List<SimpleTaskDTO> restoreTasks = new ArrayList<>();
taskList.stream().filter(i -> !Objects.equals(i.getTaskDefinitionKey(), NODE_ROBOT.getType()))
.filter(i -> Objects.nonNull(i.getOwner()))
.filter(i -> Objects.equals(i.getAssignee(), HIDDEN_ASSIGNEE_ID))
.forEach(i -> {
taskService.setAssignee(i.getId(), i.getOwner());
taskService.setOwner(i.getId(), null);
restoreTasks.add(new SimpleTaskDTO(i.getProcessInstanceId(), i.getId()));
});
Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED, new RobotTaskTransactionListener(restoreTasks, extAxProcessLogService));
}
}

View File

@ -1,6 +1,7 @@
package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper;
@ -50,12 +51,11 @@ public class CustomCreateDummyTaskCmd extends AbstractCommand<String> implements
private final BpmnTaskDelegateAssigner operator;
private final ExtAxHiTaskInstService extAxHiTaskInstService;
public CustomCreateDummyTaskCmd(String processInstanceId, String flowNodeName, String operationDesc,
BpmnTaskDelegateAssigner operator, ExtAxHiTaskInstService extAxHiTaskInstService) {
this.processInstanceId = processInstanceId;
this.flowNodeName = flowNodeName;
this.operationDesc = operationDesc;
this.operator = operator;
public CustomCreateDummyTaskCmd(BpmnRobotTaskCreateDTO dto, ExtAxHiTaskInstService extAxHiTaskInstService) {
this.processInstanceId = dto.getProcessInstanceId();
this.flowNodeName = dto.getRobotNode().getFlowNodeName();
this.operationDesc = dto.getRobotNode().getOperationDesc();
this.operator = dto.getApprover();
this.extAxHiTaskInstService = extAxHiTaskInstService;
}
@ -116,30 +116,32 @@ public class CustomCreateDummyTaskCmd extends AbstractCommand<String> implements
task.setTaskDefinitionKey(NODE_ROBOT.getType());
task.setPriority(DEFAULT_PRIORITY);
task.setCreateTime(new Date());
// 创建临时节点
taskService.saveTask(task);
Authentication.setAuthenticatedUserId("system");
CustomTaskHelper.addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, operationDesc);
Authentication.setAuthenticatedUserId(null);
// 创建临时节点
taskService.saveTask(task);
if (Objects.nonNull(operator)) {
CommandContextUtil.getEntityCache().findInCache(HistoricTaskInstanceEntity.class).stream()
.filter(i -> Objects.equals(i.getId(), task.getId())).findAny()
.ifPresent(i -> i.setAssignee(operator.buildAssigneeId()));
}
completeProcessingTask(commandContext);
pauseProcessingTask(commandContext);
CustomTaskHelper.createExtTaskInst(extAxHiTaskInstService, processInstanceId, task.getId(),
NODE_ROBOT.getType(),
Objects.isNull(operator) ? BpmnTaskDelegateAssigner.buildDummyAssigner("system",
TASK_ASSIGNEE_SKIP_FLAT, "系统") : operator,
TASK_ASSIGNEE_SKIP_FLAT, "") : operator,
BpmnProcessInstanceResultEnum.PROCESSING.getStatus());
return task.getId();
}
private void completeProcessingTask(CommandContext commandContext) {
// 将正执行的任务切换为能被隐藏的标识
private void pauseProcessingTask(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
TaskService taskService = processEngineConfiguration.getTaskService();

View File

@ -1,5 +1,6 @@
package cn.axzo.workflow.core.engine.job;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
import cn.axzo.workflow.core.engine.cmd.CustomAbortProcessInstanceCmd;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
@ -31,8 +32,7 @@ public class AsyncAbortProcessInstanceJobHandler extends AbstractExecuteWithLock
log.info("AsyncAbortProcessInstanceHandler executing...,jobInfo:{}", JSONUtil.toJsonStr(job));
log(job);
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
BpmnProcessInstanceCancelDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnProcessInstanceCancelDTO.class);
processEngineConfiguration.getCommandExecutor().execute(new CustomAbortProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(),
dto.getReason(), extAxHiTaskInstService));
BpmnProcessInstanceAbortDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnProcessInstanceAbortDTO.class);
processEngineConfiguration.getCommandExecutor().execute(new CustomAbortProcessInstanceCmd(dto, extAxHiTaskInstService));
}
}

View File

@ -34,7 +34,6 @@ public class AsyncCancelProcessInstanceJobHandler extends AbstractJobHandler imp
log(job);
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
BpmnProcessInstanceCancelDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnProcessInstanceCancelDTO.class);
processEngineConfiguration.getCommandExecutor().execute(new CustomCancelProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(),
dto.getReason(), dto.getInitiator(), extAxHiTaskInstService));
processEngineConfiguration.getCommandExecutor().execute(new CustomCancelProcessInstanceCmd(dto, extAxHiTaskInstService));
}
}

View File

@ -90,7 +90,8 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
log.setNodeType((getNodeType(flowElement).orElse(BpmnFlowNodeType.NODE_EMPTY)).getType());
log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType());
log.setTaskId(taskEntity.getId());
log.setOperationDesc(PENDING.getDesc());
String operationDesc = taskEntity.getVariable(COMMENT_TYPE_OPERATION_DESC, String.class);
log.setOperationDesc(StringUtils.hasText(operationDesc) ? operationDesc : PENDING.getDesc());
log.setStartTime(taskEntity.getCreateTime());
log.setStatus(PROCESSING.getStatus());

View File

@ -0,0 +1,28 @@
package cn.axzo.workflow.core.engine.tx.listener;
import cn.axzo.workflow.common.model.dto.SimpleTaskDTO;
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.cfg.TransactionListener;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import java.util.List;
/**
* 恢复创建机器人节点时暂停的审批人任务
*
* @author wangli
* @since 2024-12-09 14:26
*/
@Slf4j
@AllArgsConstructor
public class RobotTaskTransactionListener implements TransactionListener {
private final List<SimpleTaskDTO> tasks;
private final ExtAxProcessLogService processLogService;
@Override
public void execute(CommandContext commandContext) {
processLogService.batchRestore(tasks);
}
}

View File

@ -2,7 +2,12 @@ package cn.axzo.workflow.core.repository.mapper;
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;
@Mapper
public interface ExtAxProcessLogMapper extends BaseMapperX<ExtAxProcessLog> {
@Update("UPDATE ext_ax_process_log SET is_delete = 0, start_time = NOW() WHERE process_instance_id = #{processInstanceId} and task_id = #{taskId}")
void restore(String processInstanceId, String taskId);
}

View File

@ -1,5 +1,6 @@
package cn.axzo.workflow.core.service;
import cn.axzo.workflow.common.model.dto.SimpleTaskDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
@ -53,4 +54,13 @@ public interface ExtAxProcessLogService {
void updateAssignee(ExtAxProcessLog updateLog, BpmnTaskDelegateAssigner assignee, String operationDesc);
List<ExtAxProcessLog> genericQuery(ExtAxProcessLog query);
/**
* 机器人节点会删除日志这里仅仅为了恢复日志都删除标识并更新时间
* @param processInstanceId
* @param taskId
*/
void restore(String processInstanceId, String taskId);
void batchRestore(List<SimpleTaskDTO> tasks);
}

View File

@ -2,6 +2,7 @@ package cn.axzo.workflow.core.service.impl;
import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutCallbackDTO;
import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutTriggerDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
@ -62,11 +63,14 @@ public class BpmnProcessActivityServiceImpl implements BpmnProcessActivityServic
if (Objects.isNull(execution)) {
throw new WorkflowEngineException(ACTIVITY_TRIGGER_NOT_EXISTS, dto.getTriggerId());
}
commandExecutor.execute(new CustomAbortProcessInstanceCmd(execution.getProcessInstanceId(), null, "业务未指定审批人", extAxHiTaskInstService));
BpmnProcessInstanceAbortDTO abortDTO = new BpmnProcessInstanceAbortDTO();
abortDTO.setProcessInstanceId(execution.getProcessInstanceId());
abortDTO.setReason("业务未指定审批人");
commandExecutor.execute(new CustomAbortProcessInstanceCmd(abortDTO, extAxHiTaskInstService));
return;
}
if(Boolean.TRUE.equals(dto.getAsync())) {
if (Boolean.TRUE.equals(dto.getAsync())) {
commandExecutor.execute(new CustomBizSpecifyAssigneeToTaskAsyncCmd(dto));
} else {
commandExecutor.execute(new CustomBizSpecifyAssigneeToTaskCmd(dto.getTriggerId(), dto.getAssigners()));

View File

@ -157,6 +157,8 @@ import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.GENERAL;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeMode.OR;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_BUSINESS;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CARBON_COPY;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_COMMENT;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_ROBOT;
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;
@ -422,8 +424,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
if (dto.getAsync() != null && dto.getAsync()) {
commandExecutor.execute(new CustomCancelProcessInstanceAsyncCmd(dto));
} else {
commandExecutor.execute(new CustomCancelProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(),
dto.getReason(), dto.getInitiator(), extAxHiTaskInstService));
commandExecutor.execute(new CustomCancelProcessInstanceCmd(dto, extAxHiTaskInstService));
}
return true;
}
@ -435,8 +436,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
if (dto.getAsync() != null && dto.getAsync()) {
commandExecutor.execute(new CustomAbortProcessInstanceAsyncCmd(dto));
} else {
commandExecutor.execute(new CustomAbortProcessInstanceCmd(dto.getProcessInstanceId(), dto.getTenantId(),
dto.getReason(), extAxHiTaskInstService));
commandExecutor.execute(new CustomAbortProcessInstanceCmd(dto, extAxHiTaskInstService));
}
return true;
}
@ -1037,9 +1037,10 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
.processInstanceId(dto.getProcessInstanceId())
.includeProcessVariables()
.singleResult();
logs.stream().reduce((f, s) -> s).ifPresent(e -> forecasting.addAll(
getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(dto.getProcessInstanceId(), instance, e.getActivityId(), false, false))
);
logs.stream().reduce((f, s) -> Objects.equals(s.getActivityId(), NODE_ROBOT.getType()) || Objects.equals(s.getActivityId(), NODE_COMMENT.getType()) ? f : s)
.ifPresent(e -> forecasting.addAll(
getProcessInstanceNodeForecastWithSpecifyTaskDefinitionKey(dto.getProcessInstanceId(), instance, e.getActivityId(), false, false))
);
}
BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
@ -1304,6 +1305,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
Optional<BpmnTaskInstanceLogVO> processingTask = tasks.stream().filter(i -> Objects.equals(PROCESSING, i.getResult()))
.filter(i -> Objects.equals(i.getTaskDefinitionKey(), e.getActivityId())).findAny();
BpmnTaskDelegateAssigner assigner = BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0));
if (processingTask.isPresent()) {
// 多实例的情况需要合并节点
processingTask.ifPresent(i -> {
@ -1313,7 +1315,9 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
assigners.add(i.getAssigneeSnapshot());
}
}
assigners.add(BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0)));
if (Objects.nonNull(assigner)) {
assigners.add(assigner);
}
switch (i.getNodeMode()) {
case AND:
i.setOperationDesc(assigners.size() + "人会签,需要全部同意");
@ -1351,7 +1355,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
.fileList(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.file))
.signatureUrl(getAttachmentByType(attachmentByTaskMap, e.getTaskId(), AttachmentTypeEnum.signature).stream().findFirst().orElse(new AttachmentDTO()).getUrl())
.assigneeSnapshot(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? null :
BpmnTaskDelegateAssigner.toObjectCompatible(CollectionUtils.isEmpty(ListUtils.emptyIfNull(e.getAssigneeFull())) ? null : e.getAssigneeFull().get(0)))
assigner)
.forecastAssignees(Objects.equals(e.getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType()) ? ListUtils.emptyIfNull(e.getAssigneeFull()) : Collections.emptyList())
.build());
}

View File

@ -52,6 +52,7 @@ import cn.axzo.workflow.core.service.BpmnProcessDefinitionService;
import cn.axzo.workflow.core.service.BpmnProcessTaskService;
import cn.axzo.workflow.core.service.ExtAxBpmnFormRelationService;
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
import cn.axzo.workflow.core.service.converter.BpmnHistoricAttachmentConverter;
import cn.axzo.workflow.core.service.converter.BpmnHistoricTaskInstanceConverter;
import cn.axzo.workflow.core.service.converter.BpmnTaskConverter;
@ -183,6 +184,8 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
private BpmnProcessTaskService bpmnProcessTaskService;
@Resource
private BpmnProcessDefinitionService bpmnProcessModelService;
@Resource
private ExtAxProcessLogService extAxProcessLogService;
@Override
public BpmPageResult<BpmnTaskTodoPageItemVO> getTodoTaskPage(BpmnTaskPageSearchDTO dto) {
@ -820,19 +823,14 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
@Transactional(rollbackFor = Exception.class)
public String createRobotTask(BpmnRobotTaskCreateDTO dto) {
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
return commandExecutor.execute(new CustomCreateDummyTaskCmd(dto.getProcessInstanceId(),
dto.getRobotNode().getFlowNodeName(), dto.getRobotNode().getOperationDesc(), dto.getApprover(),
extAxHiTaskInstService));
return commandExecutor.execute(new CustomCreateDummyTaskCmd(dto, extAxHiTaskInstService));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void completeRobotTask(BpmnRobotTaskCompleteDTO dto) {
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
commandExecutor.execute(new CustomCompleteDummyTaskCmd(dto.getProcessInstanceId(), dto.getTaskId(),
Objects.isNull(dto.getRobotNode()) ? null : dto.getRobotNode().getFlowNodeName(),
Objects.isNull(dto.getRobotNode()) ? null : dto.getRobotNode().getOperationDesc(),
extAxHiTaskInstService));
commandExecutor.execute(new CustomCompleteDummyTaskCmd(dto, extAxHiTaskInstService, extAxProcessLogService));
}
@Override

View File

@ -1,5 +1,6 @@
package cn.axzo.workflow.core.service.impl;
import cn.axzo.workflow.common.model.dto.SimpleTaskDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
import cn.axzo.workflow.core.repository.mapper.ExtAxProcessLogMapper;
@ -8,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
@ -59,7 +61,7 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService {
@Override
public void updateAssignee(ExtAxProcessLog queryLog, BpmnTaskDelegateAssigner assignee, String operationDesc) {
List<String> filterAssignee = Lists.newArrayList(NO_ASSIGNEE, HIDDEN_ASSIGNEE_ID, ROBOT_ASSIGNEE_ID,
DUMMY_ASSIGNEE_ID);
DUMMY_ASSIGNEE_ID);
if (Objects.isNull(assignee) || filterAssignee.contains(assignee.buildAssigneeId())) {
return;
}
@ -78,14 +80,31 @@ public class ExtAxProcessLogServiceImpl implements ExtAxProcessLogService {
return extAxProcessLogMapper.selectList(buildQueryWrapper(query));
}
@Override
public void restore(String processInstanceId, String taskId) {
batchRestore(Lists.newArrayList(new SimpleTaskDTO(processInstanceId, taskId)));
}
@Override
public void batchRestore(List<SimpleTaskDTO> tasks) {
if (CollectionUtils.isEmpty(tasks)) {
return;
}
tasks.forEach(task -> {
if (StringUtils.hasText(task.getProcessInstanceId()) && StringUtils.hasText(task.getTaskId())) {
extAxProcessLogMapper.restore(task.getProcessInstanceId(), task.getTaskId());
}
});
}
LambdaQueryWrapper<ExtAxProcessLog> buildQueryWrapper(ExtAxProcessLog log) {
return new LambdaQueryWrapper<ExtAxProcessLog>()
.eq(Objects.nonNull(log.getId()), ExtAxProcessLog::getId, log.getId())
.eq(StringUtils.hasText(log.getProcessInstanceId()), ExtAxProcessLog::getProcessInstanceId, log.getProcessInstanceId())
.eq(StringUtils.hasText(log.getActivityId()), ExtAxProcessLog::getActivityId, log.getActivityId())
.eq(StringUtils.hasText(log.getActivityName()), ExtAxProcessLog::getActivityName, log.getActivityName())
.eq(StringUtils.hasText(log.getTaskId()), ExtAxProcessLog::getTaskId, log.getTaskId())
.eq(StringUtils.hasText(log.getTenantId()), ExtAxProcessLog::getTenantId, log.getTenantId())
.eq(ExtAxProcessLog::getIsDelete, 0);
.eq(Objects.nonNull(log.getId()), ExtAxProcessLog::getId, log.getId())
.eq(StringUtils.hasText(log.getProcessInstanceId()), ExtAxProcessLog::getProcessInstanceId, log.getProcessInstanceId())
.eq(StringUtils.hasText(log.getActivityId()), ExtAxProcessLog::getActivityId, log.getActivityId())
.eq(StringUtils.hasText(log.getActivityName()), ExtAxProcessLog::getActivityName, log.getActivityName())
.eq(StringUtils.hasText(log.getTaskId()), ExtAxProcessLog::getTaskId, log.getTaskId())
.eq(StringUtils.hasText(log.getTenantId()), ExtAxProcessLog::getTenantId, log.getTenantId())
.eq(ExtAxProcessLog::getIsDelete, log.getIsDelete());
}
}

View File

@ -4,6 +4,7 @@ import cn.axzo.oss.http.api.ServerFileServiceApi;
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi;
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
@ -15,6 +16,7 @@ import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLog
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.HistoricProcessInstanceSearchDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.common.model.response.BpmPageResult;
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
@ -54,6 +56,7 @@ import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -144,6 +147,7 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
@RepeatSubmit
public CommonResponse<Boolean> abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto) {
log.info("中止流程实例abortProcessInstant===>>>参数:{}", JSONUtil.toJsonStr(dto));
populateUsersAvatar(dto.getAssigner());
return success(bpmnProcessInstanceService.abortProcessInstance(dto));
}