diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/BpmModelConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/BpmModelConvert.java index 17343f106..25c643a90 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/BpmModelConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/model/BpmModelConvert.java @@ -80,6 +80,7 @@ public interface BpmModelConvert { default BpmDefinitionCreateReqDTO convert2(Model model) { BpmDefinitionCreateReqDTO createReqDTO = new BpmDefinitionCreateReqDTO(); + createReqDTO.setModelId(model.getId()); createReqDTO.setName(model.getName()); createReqDTO.setKey(model.getKey()); createReqDTO.setCategory(model.getCategory()); diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java index 63b5e3382..80f3073f7 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmProcessDefinitionExtDO.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; +import org.activiti.engine.repository.Model; import org.activiti.engine.repository.ProcessDefinition; /** @@ -33,6 +34,12 @@ public class BpmProcessDefinitionExtDO extends BaseDO { * 关联 {@link ProcessDefinition#getId()} */ private String processDefinitionId; + /** + * 流程模型的编号 + * + * 关联 {@link Model#getId()} + */ + private String modelId; /** * 描述 */ diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskRuleDO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskRuleDO.java index 3494c79b1..0f91a64f2 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskRuleDO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/dataobject/definition/BpmTaskRuleDO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition; import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleScriptEnum; import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleTypeEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -13,9 +14,14 @@ import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.task.Task; import java.util.List; +import java.util.Set; /** - * Bpm 任务规则表 + * Bpm 任务规则表,用于自定义配置每个任务的负责人的分配规则。 + * 也就是说,废弃 BPMN 原本的 UserTask 设置的 assignee、candidateUsers 等配置,而是通过使用该规则进行计算对应的负责人。 + * + * 1. 默认情况下,{@link #processDefinitionId} 为 {@link #PROCESS_DEFINITION_ID_NULL} 值,表示贵改则与流程模型关联 + * 2. 在流程模型部署后,会将他的所有规则记录,复制出一份新部署出来的流程定义,通过设置 {@link #processDefinitionId} 为新的流程定义的编号进行关联 * * @author 芋道源码 */ @@ -28,6 +34,11 @@ import java.util.List; @AllArgsConstructor public class BpmTaskRuleDO extends BaseDO { + /** + * {@link #processDefinitionId} 空串,用于标识属于流程模型,而不属于流程定义 + */ + private static final String PROCESS_DEFINITION_ID_NULL = ""; + /** * 编号 */ @@ -58,6 +69,7 @@ public class BpmTaskRuleDO extends BaseDO { * * 枚举 {@link BpmTaskRuleTypeEnum} */ + @TableField("`type`") private Integer type; /** * 规则值数组,一般关联指定表的编号 @@ -70,7 +82,7 @@ public class BpmTaskRuleDO extends BaseDO { * 5. {@link BpmTaskRuleTypeEnum#USER_GROUP} 时:用户组编号 * 6. {@link BpmTaskRuleTypeEnum#SCRIPT} 时:脚本编号,目前通过 {@link BpmTaskRuleScriptEnum#getId()} 标识 */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List values; + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set options; } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmTaskRuleMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmTaskRuleMapper.java new file mode 100644 index 000000000..4ba2c282c --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/dal/mysql/definition/BpmTaskRuleMapper.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition; + +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskRuleDO; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.lang.Nullable; + +import java.util.List; + +@Mapper +public interface BpmTaskRuleMapper extends BaseMapperX { + + default List selectListByProcessDefinitionId(String processDefinitionId, + @Nullable String taskDefinitionKey) { + return selectList(new QueryWrapperX() + .eq("process_definition_id", processDefinitionId) + .eqIfPresent("task_definition_key", taskDefinitionKey)); + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java index 9a02efc6d..5f7918424 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/config/BpmActivitiConfiguration.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.config; import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.BpmActivityBehaviorFactory; import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.listener.BpmTackActivitiEventListener; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskRuleService; import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -44,8 +45,10 @@ public class BpmActivitiConfiguration { } @Bean - public BpmActivityBehaviorFactory bpmActivityBehaviorFactory() { - return new BpmActivityBehaviorFactory(); + public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskRuleService taskRuleService) { + BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); + bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); + return bpmActivityBehaviorFactory; } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmActivityBehaviorFactory.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmActivityBehaviorFactory.java index bbf652833..a6b9e5fae 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmActivityBehaviorFactory.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmActivityBehaviorFactory.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior; import cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior.BpmUserTaskActivitiBehavior; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskRuleService; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.Setter; import lombok.ToString; import org.activiti.bpmn.model.UserTask; import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior; @@ -19,9 +21,14 @@ import org.activiti.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFacto @ToString(callSuper = true) public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { + @Setter + private BpmTaskRuleService bpmTaskRuleService; + @Override public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { - return new BpmUserTaskActivitiBehavior(userTask); + BpmUserTaskActivitiBehavior userTaskActivityBehavior = new BpmUserTaskActivitiBehavior(userTask); + userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService); + return userTaskActivityBehavior; } // TODO 芋艿:并行任务 ParallelMultiInstanceBehavior diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehavior.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehavior.java index e66b4b336..71f76e207 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehavior.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/behavior/BpmUserTaskActivitiBehavior.java @@ -1,6 +1,16 @@ package cn.iocoder.yudao.adminserver.modules.bpm.framework.activiti.core.behavior; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskRuleDO; +import cn.iocoder.yudao.adminserver.modules.bpm.enums.definition.BpmTaskRuleTypeEnum; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskRuleService; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; +import lombok.Setter; import org.activiti.bpmn.model.UserTask; +import org.activiti.engine.ActivitiException; import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior; import org.activiti.engine.impl.el.ExpressionManager; @@ -8,6 +18,8 @@ import org.activiti.engine.impl.persistence.entity.TaskEntity; import org.activiti.engine.impl.persistence.entity.TaskEntityManager; import java.util.List; +import java.util.Objects; +import java.util.Set; /** * 自定义的流程任务的 assignee 负责人的分配 @@ -16,6 +28,9 @@ import java.util.List; */ public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior { + @Setter + private BpmTaskRuleService bpmTaskRuleService; + public BpmUserTaskActivitiBehavior(UserTask userTask) { super(userTask); } @@ -24,8 +39,86 @@ public class BpmUserTaskActivitiBehavior extends UserTaskActivityBehavior { protected void handleAssignments(TaskEntityManager taskEntityManager, String assignee, String owner, List candidateUsers, List candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution) { - System.out.println(""); - taskEntityManager.changeTaskAssignee(task, "1"); + // 获得任务的规则 + BpmTaskRuleDO rule = getTaskRule(task); + // 获得任务的候选用户们 + Set candidateUserIds = calculateTaskCandidateUsers(task, rule); + // 设置负责人 + Long assigneeUserId = chooseTaskAssignee(candidateUserIds); + taskEntityManager.changeTaskAssignee(task, String.valueOf(assigneeUserId)); + // 设置候选人们 + candidateUserIds.remove(assigneeUserId); // 已经成为负责人了,就不要在扮演候选人了 + if (CollUtil.isNotEmpty(candidateUserIds)) { + task.addCandidateUsers(CollectionUtils.convertSet(candidateUserIds, String::valueOf)); + } + } + + private BpmTaskRuleDO getTaskRule(TaskEntity task) { + List taskRules = bpmTaskRuleService.getTaskRulesByProcessDefinitionId(task.getProcessDefinitionId(), + task.getTaskDefinitionKey()); + if (CollUtil.isEmpty(taskRules)) { + throw new ActivitiException(StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则", + task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey())); + } + if (taskRules.size() > 1) { + throw new ActivitiException(StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})", + task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey(), taskRules.size())); + } + return taskRules.get(0); + } + + private Long chooseTaskAssignee(Set candidateUserIds) { + // TODO 芋艿:未来可以优化下,改成轮询的策略 + int index = RandomUtil.randomInt(candidateUserIds.size()); + return CollUtil.get(candidateUserIds, index); + } + + private Set calculateTaskCandidateUsers(TaskEntity task, BpmTaskRuleDO rule) { + Set assigneeUserIds = null; + if (Objects.equals(BpmTaskRuleTypeEnum.ROLE.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule); + } else if (Objects.equals(BpmTaskRuleTypeEnum.DEPT.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByDept(task, rule); + } else if (Objects.equals(BpmTaskRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByDept(task, rule); + } else if (Objects.equals(BpmTaskRuleTypeEnum.USER.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); + } else if (Objects.equals(BpmTaskRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { + assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); + } + + // TODO 芋艿:统一过滤掉被禁用的用户 + // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人 + if (CollUtil.isEmpty(assigneeUserIds)) { + throw new ActivitiException(StrUtil.format("流程任务({}/{}/{}) 任务规则({}) 找不到候选人", + task.getId(), task.getProcessDefinitionId(), task.getTaskDefinitionKey())); + } + return assigneeUserIds; + } + + private Set calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskRuleDO rule) { + throw new UnsupportedOperationException("暂不支持该任务规则"); + } + + + private Set calculateTaskCandidateUsersByDept(TaskEntity task, BpmTaskRuleDO rule) { + throw new UnsupportedOperationException("暂不支持该任务规则"); + } + + private Set calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskRuleDO rule) { + throw new UnsupportedOperationException("暂不支持该任务规则"); + } + + private Set calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskRuleDO rule) { + return rule.getOptions(); + } + + private Set calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskRuleDO rule) { + throw new UnsupportedOperationException("暂不支持该任务规则"); + } + + private Set calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskRuleDO rule) { + throw new UnsupportedOperationException("暂不支持该任务规则"); } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmTaskRuleService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmTaskRuleService.java new file mode 100644 index 000000000..6e93903a8 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/BpmTaskRuleService.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.definition; + +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskRuleDO; +import org.springframework.lang.Nullable; + +import java.util.List; + +/** + * BPM 任务规则 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmTaskRuleService { + + /** + * 获得流程定义的任务规则数组 + * + * @param processDefinitionId 流程定义的编号 + * @param taskDefinitionKey 流程任务定义的 Key。允许空 + * @return 任务规则数组 + */ + List getTaskRulesByProcessDefinitionId(String processDefinitionId, + @Nullable String taskDefinitionKey); + + /** + * 获得流程模型的任务规则数组 + * + * @param modelId 流程模型的编号 + * @return 任务规则数组 + */ + List getTaskRulesByModelId(Long modelId); + + // TODO 芋艿:创建任务规则 + // TODO 芋艿:复制任务规则 + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java index 69948366f..501157af3 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/dto/BpmDefinitionCreateReqDTO.java @@ -10,6 +10,11 @@ import javax.validation.constraints.NotEmpty; @Data public class BpmDefinitionCreateReqDTO { + /** + * 流程模型的编号 + */ + @NotEmpty(message = "流程模型编号不能为空") + private String modelId; /** * 流程标识 */ diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmModelServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmModelServiceImpl.java index bf0654377..d27ac9460 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmModelServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmModelServiceImpl.java @@ -214,11 +214,11 @@ public class BpmModelServiceImpl implements BpmModelService { } } - public static void main(String[] args) { - // 创建转换对象 - BpmnXMLConverter converter = new BpmnXMLConverter(); - BpmnModel bpmnModel = converter.convertToBpmnModel(new StringStreamSource(""), true, true); - bpmnModel.getProcesses().get(0).getId() - } +// public static void main(String[] args) { +// // 创建转换对象 +// BpmnXMLConverter converter = new BpmnXMLConverter(); +// BpmnModel bpmnModel = converter.convertToBpmnModel(new StringStreamSource(""), true, true); +// bpmnModel.getProcesses().get(0).getId() +// } } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmTaskRuleServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmTaskRuleServiceImpl.java new file mode 100644 index 000000000..89f655381 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/definition/impl/BpmTaskRuleServiceImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.definition.impl; + +import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.definition.BpmTaskRuleDO; +import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.definition.BpmTaskRuleMapper; +import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmTaskRuleService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; + +/** + * BPM 任务规则 Service 实现类 + */ +@Service +@Validated +@Slf4j +public class BpmTaskRuleServiceImpl implements BpmTaskRuleService { + + @Resource + private BpmTaskRuleMapper taskRuleMapper; + + @Override + public List getTaskRulesByProcessDefinitionId(String processDefinitionId, + String taskDefinitionKey) { + return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey); + } + + @Override + public List getTaskRulesByModelId(Long modelId) { + return null; + } + +}