BPM:新增 flowable expression 表达式,替代现有 BpmTaskAssignScript,更加灵活

This commit is contained in:
YunaiV 2024-03-14 12:54:16 +08:00
parent cdbcd4d673
commit 797fddfb3d
12 changed files with 59 additions and 90 deletions

View File

@ -18,7 +18,9 @@ public enum BpmTaskAssignRuleTypeEnum {
POST(22, "岗位"),
USER(30, "用户"),
USER_GROUP(40, "用户组"),
@Deprecated
SCRIPT(50, "自定义脚本"), // 例如说发起人所在部门的领导发起人所在部门的领导的领导
EXPRESS(60, "流程表达式"), // 表达式 ExpressionManager
;
/**

View File

@ -14,6 +14,7 @@ import java.util.Set;
*
* @author 芋道源码
*/
@Deprecated
public interface BpmTaskAssignScript {
/**
@ -30,5 +31,6 @@ public interface BpmTaskAssignScript {
* @return 枚举值
*/
BpmTaskRuleScriptEnum getEnum();
}

View File

@ -24,6 +24,7 @@ import static java.util.Collections.emptySet;
*
* @author 芋道源码
*/
@Deprecated
public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssignScript {
@Resource

View File

@ -11,6 +11,7 @@ import java.util.Set;
*
* @author 芋道源码
*/
@Deprecated
@Component
public class BpmTaskAssignLeaderX1Script extends BpmTaskAssignLeaderAbstractScript {

View File

@ -11,6 +11,7 @@ import java.util.Set;
*
* @author 芋道源码
*/
@Deprecated
@Component
public class BpmTaskAssignLeaderX2Script extends BpmTaskAssignLeaderAbstractScript {

View File

@ -18,6 +18,7 @@ import java.util.Set;
*
* @author 芋道源码
*/
@Deprecated
@Component
public class BpmTaskAssignStartUserScript implements BpmTaskAssignScript {

View File

@ -1,76 +0,0 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.handler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
// TODO @芋艿bpmn 分配人融合时需要搞下这块
/**
* 多实例处理类
*/
@AllArgsConstructor
@Component("multiInstanceHandler")
public class MultiInstanceHandler {
@Resource
private AdminUserApi userApi;
@Resource
private PermissionApi permissionApi;
/**
* 流程发起人那种情况不需要处理
* flowable 完成
*
* @param execution flowable的执行对象
* @return 用户ID
*/
public Set<String> getUserIds(DelegateExecution execution) {
Set<String> candidateUserIds = new LinkedHashSet<>();
FlowElement flowElement = execution.getCurrentFlowElement();
if (ObjectUtil.isNotEmpty(flowElement) && flowElement instanceof UserTask userTask) {
String dataType = userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, BpmnModelConstants.PROCESS_CUSTOM_DATA_TYPE);
if ("USERS".equals(dataType) && CollUtil.isNotEmpty(userTask.getCandidateUsers())) {
// 添加候选用户id
candidateUserIds.addAll(userTask.getCandidateUsers());
} else if (CollUtil.isNotEmpty(userTask.getCandidateGroups())) {
// 获取组的ID角色ID集合或部门ID集合
List<Long> groups = userTask.getCandidateGroups().stream()
// 例如部门DEPT100100才是部门id
.map(item -> Long.parseLong(item.substring(4)))
.collect(Collectors.toList());
List<Long> userIds = new ArrayList<>();
if ("ROLES".equals(dataType)) {
// 通过角色id获取所有用户id集合
Set<Long> userRoleIdListByRoleIds = permissionApi.getUserRoleIdListByRoleIds(groups);
userIds = new ArrayList<>(userRoleIdListByRoleIds);
} else if ("DEPTS".equals(dataType)) {
// 通过部门id获取所有用户id集合
List<AdminUserRespDTO> userListByDeptIds = userApi.getUserListByDeptIds(groups);
userIds = convertList(userListByDeptIds, AdminUserRespDTO::getId);
}
// 添加候选用户id
userIds.forEach(id -> candidateUserIds.add(String.valueOf(id)));
}
}
return candidateUserIds;
}
}

View File

@ -171,9 +171,10 @@ public class BpmModelServiceImpl implements BpmModelService {
// 1.5 校验模型是否发生修改如果未修改则不允许创建
BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form)
.setBpmnBytes(bpmnBytes);
if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等
throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS);
}
// TODO @芋艿这里比较可能有点问题
// if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等
// throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS);
// }
// 2.1 创建流程定义
String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO);

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
@ -10,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants;
import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
@ -26,6 +28,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.google.common.annotations.VisibleForTesting;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.convert.Convert;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
@ -57,6 +60,9 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
@Lazy // 解决循环依赖
private BpmProcessInstanceService processInstanceService;
// @Resource
// private ExpressionManager expressionManager;
@Resource
private RoleApi roleApi;
@Resource
@ -93,6 +99,10 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
if (type == null || StrUtil.isBlank(options)) {
throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, userTask.getName());
}
// TODO 芋艿校验 options
if (ObjectUtil.equal(type, BpmTaskAssignRuleTypeEnum.EXPRESS.getType())) {
return;
}
validTaskAssignRuleOptions(type, StrUtils.splitToLong(options, ","));
});
}
@ -117,6 +127,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
}
}
public Long test(DelegateExecution execution) {
return 1L;
}
public Long test2(DelegateExecution execution, Long id) {
return id;
}
@Override
@DataPermission(enable = false) // 忽略数据权限不然分配会存在问题
public Set<Long> calculateTaskCandidateUsers(DelegateExecution execution) {
@ -137,7 +155,11 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
// TODO 芋艿assignType/assignOptions/, 枚举
FlowElement flowElement = execution.getCurrentFlowElement();
Integer type = NumberUtils.parseInt(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType"));
Set<Long> options = StrUtils.splitToLongSet(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"), ",");
String optionStr = flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions");
Set<Long> options = null;
if (ObjectUtil.notEqual(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) {
options = StrUtils.splitToLongSet(optionStr, ",");
}
// 计算审批人
Set<Long> assigneeUserIds = null;
@ -155,6 +177,9 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
assigneeUserIds = calculateTaskCandidateUsersByUserGroup(options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByScript(execution, options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) {
Object result = FlowableUtils.getExpressionValue(execution, optionStr);
assigneeUserIds = Convert.toSet(Long.class, result);
}
// 移除被禁用的用户

View File

@ -14,9 +14,4 @@ public interface BpmnModelConstants {
*/
String NAMESPACE = "http://flowable.org/bpmn";
/**
* 自定义属性 dataType
*/
String PROCESS_CUSTOM_DATA_TYPE = "dataType";
}

View File

@ -1,6 +1,11 @@
package cn.iocoder.yudao.framework.flowable.core.util;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.api.variable.VariableContainer;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
/**
* Flowable 相关的工具方法
@ -29,4 +34,15 @@ public class FlowableUtils {
return activityId + "_assignee";
}
// ========== Expression 相关的工具方法 ==========
public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) {
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
assert processEngineConfiguration != null;
ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
assert expressionManager != null;
Expression expression = expressionManager.createExpression(expressionString);
return expression.getValue(variableContainer);
}
}

View File

@ -46,11 +46,11 @@
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
<!-- 工作流。默认注释,保证编译速度 -->
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.boot</groupId>-->
<!-- <artifactId>yudao-module-bpm-biz</artifactId>-->
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-bpm-biz</artifactId>
<version>${revision}</version>
</dependency>
<!-- 支付服务。默认注释,保证编译速度 -->
<!-- <dependency>-->
<!-- <groupId>cn.iocoder.boot</groupId>-->