mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-19 03:30:06 +08:00
【功能新增】工作流:支持审批人为空时,根据配置进行自动通过、自动拒绝、指定人审批的效果
This commit is contained in:
parent
d4306846f9
commit
0d738fa397
@ -0,0 +1,29 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.enums.definition;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPM 用户任务的审批人为空时,处理类型枚举
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Getter
|
||||||
|
public enum BpmUserTaskAssignEmptyHandlerTypeEnum implements IntArrayValuable {
|
||||||
|
|
||||||
|
APPROVE(1), // 自动通过
|
||||||
|
REJECT(2), // 自动拒绝
|
||||||
|
ASSIGN_USER(3), // 指定人员审批
|
||||||
|
ASSIGN_ADMIN(4), // 转交给流程管理员
|
||||||
|
;
|
||||||
|
|
||||||
|
private final Integer type;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] array() {
|
||||||
|
return new int[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -28,6 +28,8 @@ public enum BpmReasonEnum {
|
|||||||
ASSIGN_START_USER_APPROVE_WHEN_SKIP("审批人与提交人为同一人时,自动通过"),
|
ASSIGN_START_USER_APPROVE_WHEN_SKIP("审批人与提交人为同一人时,自动通过"),
|
||||||
ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"),
|
ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND("审批人与提交人为同一人时,找不到部门负责人,自动通过"),
|
||||||
ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"),
|
ASSIGN_START_USER_TRANSFER_DEPT_LEADER("审批人与提交人为同一人时,转交给部门负责人审批"),
|
||||||
|
ASSIGN_EMPTY_APPROVE("审批人为空,自动通过"),
|
||||||
|
ASSIGN_EMPTY_REJECT("审批人为空,自动不通过"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String reason;
|
private final String reason;
|
||||||
|
@ -86,6 +86,11 @@ public class BpmSimpleModelNodeVO {
|
|||||||
@InEnum(BpmUserTaskAssignStartUserHandlerTypeEnum.class)
|
@InEnum(BpmUserTaskAssignStartUserHandlerTypeEnum.class)
|
||||||
private Integer assignStartUserHandlerType;
|
private Integer assignStartUserHandlerType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空处理策略
|
||||||
|
*/
|
||||||
|
private AssignEmptyHandler assignEmptyHandler;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "审批节点拒绝处理策略")
|
@Schema(description = "审批节点拒绝处理策略")
|
||||||
public static class RejectHandler {
|
public static class RejectHandler {
|
||||||
@ -121,6 +126,21 @@ public class BpmSimpleModelNodeVO {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "空处理策略")
|
||||||
|
@Valid
|
||||||
|
public static class AssignEmptyHandler {
|
||||||
|
|
||||||
|
@Schema(description = "空处理类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "空处理类型不能为空")
|
||||||
|
@InEnum(BpmUserTaskAssignEmptyHandlerTypeEnum.class)
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
@Schema(description = "指定人员审批的用户编号数组", example = "1")
|
||||||
|
private List<Long> userIds;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Schema(description = "操作按钮设置")
|
@Schema(description = "操作按钮设置")
|
||||||
public static class OperationButtonSetting {
|
public static class OperationButtonSetting {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -49,6 +51,10 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav
|
|||||||
|
|
||||||
// 第二步,获取任务的所有处理人
|
// 第二步,获取任务的所有处理人
|
||||||
Set<Long> assigneeUserIds = taskCandidateInvoker.calculateUsers(execution);
|
Set<Long> assigneeUserIds = taskCandidateInvoker.calculateUsers(execution);
|
||||||
|
if (CollUtil.isEmpty(assigneeUserIds)) {
|
||||||
|
// 特殊:如果没有处理人的情况下,至少有一个 null 空元素,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务,避免自动通过!
|
||||||
|
assigneeUserIds = SetUtils.asSet((Long) null);
|
||||||
|
}
|
||||||
execution.setVariable(super.collectionVariable, assigneeUserIds);
|
execution.setVariable(super.collectionVariable, assigneeUserIds);
|
||||||
return assigneeUserIds.size();
|
return assigneeUserIds.size();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -43,6 +45,10 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB
|
|||||||
|
|
||||||
// 第二步,获取任务的所有处理人
|
// 第二步,获取任务的所有处理人
|
||||||
Set<Long> assigneeUserIds = new LinkedHashSet<>(taskCandidateInvoker.calculateUsers(execution)); // 保证有序!!!
|
Set<Long> assigneeUserIds = new LinkedHashSet<>(taskCandidateInvoker.calculateUsers(execution)); // 保证有序!!!
|
||||||
|
if (CollUtil.isEmpty(assigneeUserIds)) {
|
||||||
|
// 特殊:如果没有处理人的情况下,至少有一个 null 空元素,保证在 BpmUserTaskActivityBehavior 至少创建出一个 Task 任务,避免自动通过!
|
||||||
|
assigneeUserIds = SetUtils.asSet((Long) null);
|
||||||
|
}
|
||||||
execution.setVariable(super.collectionVariable, assigneeUserIds);
|
execution.setVariable(super.collectionVariable, assigneeUserIds);
|
||||||
return assigneeUserIds.size();
|
return assigneeUserIds.size();
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRejectReqVO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.bpmn.model.UserTask;
|
import org.flowable.bpmn.model.UserTask;
|
||||||
@ -14,6 +21,8 @@ import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
|||||||
import org.flowable.engine.impl.util.TaskHelper;
|
import org.flowable.engine.impl.util.TaskHelper;
|
||||||
import org.flowable.task.service.TaskService;
|
import org.flowable.task.service.TaskService;
|
||||||
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
|
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -41,9 +50,29 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
|
|||||||
DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
|
DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
|
||||||
// 第一步,获得任务的候选用户
|
// 第一步,获得任务的候选用户
|
||||||
Long assigneeUserId = calculateTaskCandidateUsers(execution);
|
Long assigneeUserId = calculateTaskCandidateUsers(execution);
|
||||||
Assert.notNull(assigneeUserId, "任务处理人不能为空");
|
|
||||||
// 第二步,设置作为负责人
|
// 第二步,设置作为负责人
|
||||||
TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
|
if (assigneeUserId != null) {
|
||||||
|
TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊:审批人为空,根据配置是否要自动通过、自动拒绝
|
||||||
|
Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(userTask);
|
||||||
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCommit() {
|
||||||
|
if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.APPROVE.getType())) {
|
||||||
|
SpringUtil.getBean(BpmTaskService.class).approveTask(null, new BpmTaskApproveReqVO()
|
||||||
|
.setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_APPROVE.getReason()));
|
||||||
|
} else if (ObjectUtil.equal(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.REJECT.getType())) {
|
||||||
|
SpringUtil.getBean(BpmTaskService.class).rejectTask(null, new BpmTaskRejectReqVO()
|
||||||
|
.setId(task.getId()).setReason(BpmReasonEnum.ASSIGN_EMPTY_REJECT.getReason()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long calculateTaskCandidateUsers(DelegateExecution execution) {
|
private Long calculateTaskCandidateUsers(DelegateExecution execution) {
|
||||||
@ -56,6 +85,9 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
|
|||||||
// 情况二,如果非多实例的任务,则计算任务处理人
|
// 情况二,如果非多实例的任务,则计算任务处理人
|
||||||
// 第一步,先计算可处理该任务的处理人们
|
// 第一步,先计算可处理该任务的处理人们
|
||||||
Set<Long> candidateUserIds = taskCandidateInvoker.calculateUsers(execution);
|
Set<Long> candidateUserIds = taskCandidateInvoker.calculateUsers(execution);
|
||||||
|
if (CollUtil.isEmpty(candidateUserIds)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
// 第二步,后随机选择一个任务的处理人
|
// 第二步,后随机选择一个任务的处理人
|
||||||
// 疑问:为什么一定要选择一个任务处理人?
|
// 疑问:为什么一定要选择一个任务处理人?
|
||||||
// 解答:项目对 bpm 的任务是责任到人,所以每个任务有且仅有一个处理人。
|
// 解答:项目对 bpm 的任务是责任到人,所以每个任务有且仅有一个处理人。
|
||||||
|
@ -27,7 +27,6 @@ import java.util.Set;
|
|||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG;
|
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG;
|
||||||
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link BpmTaskCandidateStrategy} 的调用者,用于调用对应的策略,实现任务的候选人的计算
|
* {@link BpmTaskCandidateStrategy} 的调用者,用于调用对应的策略,实现任务的候选人的计算
|
||||||
@ -89,17 +88,16 @@ public class BpmTaskCandidateInvoker {
|
|||||||
String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
|
String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
|
||||||
// 1.1 计算任务的候选人
|
// 1.1 计算任务的候选人
|
||||||
Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
|
Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
|
||||||
// 1.2 移除被禁用的用户
|
// 1.2 候选人为空时,根据“审批人为空”的配置补充
|
||||||
removeDisableUsers(userIds);
|
if (CollUtil.isEmpty(userIds)) {
|
||||||
|
userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
|
||||||
|
.calculateUsers(execution, param);
|
||||||
|
}
|
||||||
// 1.3 移除发起人的用户
|
// 1.3 移除发起人的用户
|
||||||
removeStartUserIfSkip(execution, userIds);
|
removeStartUserIfSkip(execution, userIds);
|
||||||
|
|
||||||
// 2. 校验是否有候选人
|
// 2. 移除被禁用的用户
|
||||||
if (CollUtil.isEmpty(userIds)) {
|
removeDisableUsers(userIds);
|
||||||
log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(),
|
|
||||||
execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param);
|
|
||||||
throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
|
|
||||||
}
|
|
||||||
return userIds;
|
return userIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.flowable.engine.delegate.DelegateExecution;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批人为空 {@link BpmTaskCandidateStrategy} 实现类
|
||||||
|
*
|
||||||
|
* @author kyle
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class BpmTaskCandidateAssignEmptyStrategy implements BpmTaskCandidateStrategy {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BpmTaskCandidateStrategyEnum getStrategy() {
|
||||||
|
return BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateParam(String param) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
|
||||||
|
// 情况一:指定人员审批
|
||||||
|
Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(execution.getCurrentFlowElement());
|
||||||
|
if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_USER.getType())) {
|
||||||
|
return new HashSet<>(BpmnModelUtils.parseAssignEmptyHandlerUserIds(execution.getCurrentFlowElement()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 情况二:流程管理员
|
||||||
|
if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_ADMIN.getType())) {
|
||||||
|
// TODO 芋艿:需要等待流程实例的管理员支持
|
||||||
|
throw new UnsupportedOperationException("暂时实现!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 都不满足,还是返回空
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,6 +30,7 @@ public enum BpmTaskCandidateStrategyEnum implements IntArrayValuable {
|
|||||||
START_USER_MULTI_LEVEL_DEPT_LEADER(38, "发起人连续多级部门的负责人"),
|
START_USER_MULTI_LEVEL_DEPT_LEADER(38, "发起人连续多级部门的负责人"),
|
||||||
USER_GROUP(40, "用户组"),
|
USER_GROUP(40, "用户组"),
|
||||||
EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager
|
EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager
|
||||||
|
ASSIGN_EMPTY(1, "审批人为空"),
|
||||||
;
|
;
|
||||||
|
|
||||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmTaskCandidateStrategyEnum::getStrategy).toArray();
|
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BpmTaskCandidateStrategyEnum::getStrategy).toArray();
|
||||||
|
@ -38,6 +38,15 @@ public interface BpmnModelConstants {
|
|||||||
*/
|
*/
|
||||||
String USER_TASK_ASSIGN_START_USER_HANDLER_TYPE = "assignStartUserHandlerType";
|
String USER_TASK_ASSIGN_START_USER_HANDLER_TYPE = "assignStartUserHandlerType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPMN ExtensionElement 的扩展属性,用于标记用户任务的空处理类型
|
||||||
|
*/
|
||||||
|
String USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE = "assignEmptyHandlerType";
|
||||||
|
/**
|
||||||
|
* BPMN ExtensionElement 的扩展属性,用于标记用户任务的空处理的指定用户编号数组
|
||||||
|
*/
|
||||||
|
String USER_TASK_ASSIGN_USER_IDS = "assignEmptyUserIds";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型
|
* BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型
|
||||||
*/
|
*/
|
||||||
|
@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
|
|||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskRejectHandlerType;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
||||||
@ -45,16 +46,24 @@ public class BpmnModelUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static BpmUserTaskRejectHandlerType parseRejectHandlerType(FlowElement userTask) {
|
public static BpmUserTaskRejectHandlerType parseRejectHandlerType(FlowElement userTask) {
|
||||||
Integer rejectHandlerType = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE));
|
Integer rejectHandlerType = NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_REJECT_HANDLER_TYPE));
|
||||||
return BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
|
return BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String parseReturnTaskId(FlowElement flowElement) {
|
public static String parseReturnTaskId(FlowElement flowElement) {
|
||||||
return BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID);
|
return parseExtensionElement(flowElement, USER_TASK_REJECT_RETURN_TASK_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer parseAssignStartUserHandlerType(FlowElement userTask) {
|
public static Integer parseAssignStartUserHandlerType(FlowElement userTask) {
|
||||||
return NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE));
|
return NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer parseAssignEmptyHandlerType(FlowElement userTask) {
|
||||||
|
return NumberUtils.parseInt(parseExtensionElement(userTask, USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Long> parseAssignEmptyHandlerUserIds(FlowElement userTask) {
|
||||||
|
return StrUtils.splitToLong(parseExtensionElement(userTask, USER_TASK_ASSIGN_USER_IDS), ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String parseExtensionElement(FlowElement flowElement, String elementName) {
|
public static String parseExtensionElement(FlowElement flowElement, String elementName) {
|
||||||
|
@ -19,10 +19,7 @@ import org.flowable.bpmn.BpmnAutoLayout;
|
|||||||
import org.flowable.bpmn.model.Process;
|
import org.flowable.bpmn.model.Process;
|
||||||
import org.flowable.bpmn.model.*;
|
import org.flowable.bpmn.model.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.OperationButtonSetting;
|
import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.OperationButtonSetting;
|
||||||
import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler;
|
import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler;
|
||||||
@ -456,7 +453,6 @@ public class SimpleModelUtils {
|
|||||||
userTask.setDueDate(node.getTimeoutHandler().getTimeDuration());
|
userTask.setDueDate(node.getTimeoutHandler().getTimeDuration());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @jason:addCandidateElements、processMultiInstanceLoopCharacteristics 建议一起搞哈?
|
|
||||||
// 添加候选人元素
|
// 添加候选人元素
|
||||||
addCandidateElements(node.getCandidateStrategy(), node.getCandidateParam(), userTask);
|
addCandidateElements(node.getCandidateStrategy(), node.getCandidateParam(), userTask);
|
||||||
// 添加表单字段权限属性元素
|
// 添加表单字段权限属性元素
|
||||||
@ -469,6 +465,8 @@ public class SimpleModelUtils {
|
|||||||
addTaskRejectElements(node.getRejectHandler(), userTask);
|
addTaskRejectElements(node.getRejectHandler(), userTask);
|
||||||
// 添加用户任务的审批人与发起人相同时的处理元素
|
// 添加用户任务的审批人与发起人相同时的处理元素
|
||||||
addAssignStartUserHandlerType(node.getAssignStartUserHandlerType(), userTask);
|
addAssignStartUserHandlerType(node.getAssignStartUserHandlerType(), userTask);
|
||||||
|
// 添加用户任务的空处理元素
|
||||||
|
addAssignEmptyHandlerType(node.getAssignEmptyHandler(), userTask);
|
||||||
return userTask;
|
return userTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,6 +485,14 @@ public class SimpleModelUtils {
|
|||||||
addExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE, assignStartUserHandlerType.toString());
|
addExtensionElement(userTask, USER_TASK_ASSIGN_START_USER_HANDLER_TYPE, assignStartUserHandlerType.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addAssignEmptyHandlerType(BpmSimpleModelNodeVO.AssignEmptyHandler emptyHandler, UserTask userTask) {
|
||||||
|
if (emptyHandler == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addExtensionElement(userTask, USER_TASK_ASSIGN_EMPTY_HANDLER_TYPE, StrUtil.toStringOrNull(emptyHandler.getType()));
|
||||||
|
addExtensionElement(userTask, USER_TASK_ASSIGN_USER_IDS, StrUtil.join(",", emptyHandler.getUserIds()));
|
||||||
|
}
|
||||||
|
|
||||||
private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
|
private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
|
||||||
BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod);
|
BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod);
|
||||||
if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.RANDOM) {
|
if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.RANDOM) {
|
||||||
@ -496,7 +502,7 @@ public class SimpleModelUtils {
|
|||||||
addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_METHOD,
|
addExtensionElement(userTask, BpmnModelConstants.USER_TASK_APPROVE_METHOD,
|
||||||
approveMethod == null ? null : approveMethod.toString());
|
approveMethod == null ? null : approveMethod.toString());
|
||||||
MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics();
|
MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics();
|
||||||
// 设置 collectionVariable。本系统用不到。会在 仅仅为了校验。
|
// 设置 collectionVariable。本系统用不到。仅仅为了 Flowable 校验不报错。
|
||||||
multiInstanceCharacteristics.setInputDataItem("${coll_userList}");
|
multiInstanceCharacteristics.setInputDataItem("${coll_userList}");
|
||||||
if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY) {
|
if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY) {
|
||||||
multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION);
|
multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION);
|
||||||
|
@ -191,7 +191,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||||||
*/
|
*/
|
||||||
private Task validateTask(Long userId, String taskId) {
|
private Task validateTask(Long userId, String taskId) {
|
||||||
Task task = validateTaskExist(taskId);
|
Task task = validateTaskExist(taskId);
|
||||||
if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
|
// 为什么判断 assignee 非空的情况下?
|
||||||
|
// 例如说:在审批人为空时,我们会有“自动审批通过”的策略,此时 userId 为 null,允许通过
|
||||||
|
if (StrUtil.isNotBlank(task.getAssignee())
|
||||||
|
&& ObjectUtil.notEqual(userId, NumberUtils.parseLong(task.getAssignee()))) {
|
||||||
throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF);
|
throw exception(TASK_OPERATE_FAIL_ASSIGN_NOT_SELF);
|
||||||
}
|
}
|
||||||
return task;
|
return task;
|
||||||
|
Loading…
Reference in New Issue
Block a user