BPM:重构审批人的分配规则实现,移除 bpm_task_assign_rule 表,存储在 bpmn 的 userTask 中

This commit is contained in:
YunaiV 2024-03-13 21:18:07 +08:00
parent dda0909843
commit cdbcd4d673
19 changed files with 110 additions and 624 deletions

View File

@ -16,6 +16,10 @@ public class NumberUtils {
return StrUtil.isNotEmpty(str) ? Long.valueOf(str) : null;
}
public static Integer parseInt(String str) {
return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null;
}
/**
* 通过经纬度获取地球上两点之间的距离
*

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -45,6 +46,11 @@ public class StrUtils {
return Arrays.stream(longs).boxed().collect(Collectors.toList());
}
public static Set<Long> splitToLongSet(String value, CharSequence separator) {
long[] longs = StrUtil.splitToLong(value, separator);
return Arrays.stream(longs).boxed().collect(Collectors.toSet());
}
public static List<Integer> splitToInteger(String value, CharSequence separator) {
int[] integers = StrUtil.splitToInt(value, separator);
return Arrays.stream(integers).boxed().collect(Collectors.toList());

View File

@ -27,7 +27,7 @@ public interface ErrorCodeConstants {
ErrorCode MODEL_KEY_VALID = new ErrorCode(1_009_002_002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!");
ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置");
ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," +
"原因:用户任务({})未配置分配规则,请点击【修改流程】按钮进行配置");
"原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置");
ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1_009_003_005, "流程定义部署失败,原因:信息未发生变化");
// ========== 流程定义 1-009-003-000 ==========

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleBaseVO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -10,8 +9,6 @@ import java.util.Set;
/**
* 流程任务分配规则 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*
* @see BpmTaskAssignRuleBaseVO
*/
@Data
public class BpmTaskCandidateRuleVO {

View File

@ -1,58 +0,0 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 任务分配规则")
@RestController
@RequestMapping("/bpm/task-assign-rule")
@Validated
public class BpmTaskAssignRuleController {
@Resource
private BpmTaskAssignRuleService taskAssignRuleService;
@GetMapping("/list")
@Operation(summary = "获得任务分配规则列表")
@Parameters({
@Parameter(name = "modelId", description = "模型编号", example = "1024"),
@Parameter(name = "processDefinitionId", description = "流程定义的编号", example = "2048")
})
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:query')")
public CommonResult<List<BpmTaskAssignRuleRespVO>> getTaskAssignRuleList(
@RequestParam(value = "modelId", required = false) String modelId,
@RequestParam(value = "processDefinitionId", required = false) String processDefinitionId) {
return success(taskAssignRuleService.getTaskAssignRuleList(modelId, processDefinitionId));
}
@PostMapping("/create")
@Operation(summary = "创建任务分配规则")
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:create')")
public CommonResult<Long> createTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleCreateReqVO reqVO) {
return success(taskAssignRuleService.createTaskAssignRule(reqVO));
}
@PutMapping("/update")
@Operation(summary = "更新任务分配规则")
@PreAuthorize("@ss.hasPermission('bpm:task-assign-rule:update')")
public CommonResult<Boolean> updateTaskAssignRule(@Valid @RequestBody BpmTaskAssignRuleUpdateReqVO reqVO) {
taskAssignRuleService.updateTaskAssignRule(reqVO);
return success(true);
}
}

View File

@ -1,24 +0,0 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
import java.util.Set;
/**
* 流程任务分配规则 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class BpmTaskAssignRuleBaseVO {
@Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bpm_task_assign_rule_type")
@NotNull(message = "规则类型不能为空")
private Integer type;
@Schema(description = "规则值数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
@NotNull(message = "规则值数组不能为空")
private Set<Long> options;
}

View File

@ -1,24 +0,0 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import jakarta.validation.constraints.NotEmpty;
@Schema(description = "管理后台 - 流程任务分配规则的创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmTaskAssignRuleCreateReqVO extends BpmTaskAssignRuleBaseVO {
@Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotEmpty(message = "流程模型的编号不能为空")
private String modelId;
@Schema(description = "流程任务定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
@NotEmpty(message = "流程任务定义的编号不能为空")
private String taskDefinitionKey;
}

View File

@ -1,28 +0,0 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 流程任务分配规则的 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmTaskAssignRuleRespVO extends BpmTaskAssignRuleBaseVO {
@Schema(description = "任务分配规则的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
@Schema(description = "流程模型的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
private String modelId;
@Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
private String processDefinitionId;
@Schema(description = "流程任务定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
private String taskDefinitionKey;
@Schema(description = "流程任务定义的名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "关注芋道")
private String taskDefinitionName;
}

View File

@ -1,20 +0,0 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import jakarta.validation.constraints.NotNull;
@Schema(description = "管理后台 - 流程任务分配规则的更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BpmTaskAssignRuleUpdateReqVO extends BpmTaskAssignRuleBaseVO {
@Schema(description = "任务分配规则的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "任务分配规则的编号不能为空")
private Long id;
}

View File

@ -1,40 +0,0 @@
package cn.iocoder.yudao.module.bpm.convert.definition;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import org.flowable.bpmn.model.UserTask;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
@Mapper
public interface BpmTaskAssignRuleConvert {
BpmTaskAssignRuleConvert INSTANCE = Mappers.getMapper(BpmTaskAssignRuleConvert.class);
default List<BpmTaskAssignRuleRespVO> convertList(List<UserTask> tasks, List<BpmTaskAssignRuleDO> rules) {
Map<String, BpmTaskAssignRuleDO> ruleMap = CollectionUtils.convertMap(rules, BpmTaskAssignRuleDO::getTaskDefinitionKey);
// UserTask 为主维度原因是流程图编辑后一些规则实际就没用了
return CollectionUtils.convertList(tasks, task -> {
BpmTaskAssignRuleRespVO respVO = convert(ruleMap.get(task.getId()));
if (respVO == null) {
respVO = new BpmTaskAssignRuleRespVO();
respVO.setTaskDefinitionKey(task.getId());
}
respVO.setTaskDefinitionName(task.getName());
return respVO;
});
}
BpmTaskAssignRuleRespVO convert(BpmTaskAssignRuleDO bean);
BpmTaskAssignRuleDO convert(BpmTaskAssignRuleCreateReqVO bean);
BpmTaskAssignRuleDO convert(BpmTaskAssignRuleUpdateReqVO bean);
List<BpmTaskAssignRuleDO> convertList2(List<BpmTaskAssignRuleRespVO> list);
}

View File

@ -1,83 +0,0 @@
package cn.iocoder.yudao.module.bpm.dal.dataobject.definition;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.util.Set;
/**
* Bpm 任务分配的规则表用于自定义配置每个任务的负责人候选人的分配规则
* 也就是说废弃 BPMN 原本的 UserTask 设置的 assigneecandidateUsers 等配置而是通过使用该规则进行计算对应的负责人
*
* 1. 默认情况下{@link #processDefinitionId} {@link #PROCESS_DEFINITION_ID_NULL} 表示贵改则与流程模型关联
* 2. 在流程模型部署后会将他的所有规则记录复制出一份新部署出来的流程定义通过设置 {@link #processDefinitionId} 为新的流程定义的编号进行关联
*
* @author 芋道源码
*/
@TableName(value = "bpm_task_assign_rule", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BpmTaskAssignRuleDO extends BaseDO {
/**
* {@link #processDefinitionId} 空串用于标识属于流程模型而不属于流程定义
*/
public static final String PROCESS_DEFINITION_ID_NULL = "";
/**
* 编号
*/
@TableId
private Long id;
/**
* 流程模型编号
*
* 关联 Model id 属性
*/
private String modelId;
/**
* 流程定义编号
*
* 关联 ProcessDefinition id 属性
*/
private String processDefinitionId;
/**
* 流程任务的定义 Key
*
* 关联 Task taskDefinitionKey 属性
*/
private String taskDefinitionKey;
/**
* 规则类型
*
* 枚举 {@link BpmTaskAssignRuleTypeEnum}
*/
@TableField("`type`")
private Integer type;
/**
* 规则值数组一般关联指定表的编号
* 根据 type 不同对应的值是不同的
*
* 1. {@link BpmTaskAssignRuleTypeEnum#ROLE} 角色编号
* 2. {@link BpmTaskAssignRuleTypeEnum#DEPT_MEMBER} 部门编号
* 3. {@link BpmTaskAssignRuleTypeEnum#DEPT_LEADER} 部门编号
* 4. {@link BpmTaskAssignRuleTypeEnum#USER} 用户编号
* 5. {@link BpmTaskAssignRuleTypeEnum#USER_GROUP} 用户组编号
* 6. {@link BpmTaskAssignRuleTypeEnum#SCRIPT} 脚本编号目前通过 {@link BpmTaskRuleScriptEnum#getId()} 标识
*/
@TableField(typeHandler = JsonLongSetTypeHandler.class)
private Set<Long> options;
}

View File

@ -1,37 +0,0 @@
package cn.iocoder.yudao.module.bpm.dal.mysql.definition;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
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 BpmTaskAssignRuleMapper extends BaseMapperX<BpmTaskAssignRuleDO> {
default List<BpmTaskAssignRuleDO> selectListByProcessDefinitionId(String processDefinitionId,
@Nullable String taskDefinitionKey) {
return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
.eq("process_definition_id", processDefinitionId)
.eqIfPresent("task_definition_key", taskDefinitionKey));
}
default List<BpmTaskAssignRuleDO> selectListByModelId(String modelId) {
return selectList(new QueryWrapperX<BpmTaskAssignRuleDO>()
.eq("model_id", modelId)
.eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL));
}
default BpmTaskAssignRuleDO selectListByModelIdAndTaskDefinitionKey(String modelId,
String taskDefinitionKey) {
return selectOne(new QueryWrapperX<BpmTaskAssignRuleDO>()
.eq("model_id", modelId)
.eq("process_definition_id", BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL)
.eq("task_definition_key", taskDefinitionKey));
}
}

View File

@ -1,12 +1,12 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert;
@ -17,10 +17,8 @@ import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCr
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
@ -168,15 +166,13 @@ public class BpmModelServiceImpl implements BpmModelService {
// 1.3 校验表单已配
BpmFormDO form = checkFormConfig(model.getMetaInfo());
// 1.4 校验任务分配规则已配置
taskAssignRuleService.checkTaskAssignRuleAllConfig(id);
taskAssignRuleService.checkTaskAssignRuleAllConfig(bpmnBytes);
// 1.5 校验模型是否发生修改如果未修改则不允许创建
BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form).setBpmnBytes(bpmnBytes);
BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form)
.setBpmnBytes(bpmnBytes);
if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等
ProcessDefinition oldProcessDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
if (oldProcessDefinition != null && taskAssignRuleService.isTaskAssignRulesEquals(model.getId(), oldProcessDefinition.getId())) {
throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS);
}
throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS);
}
// 2.1 创建流程定义
@ -189,12 +185,8 @@ public class BpmModelServiceImpl implements BpmModelService {
ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId);
model.setDeploymentId(definition.getDeploymentId());
repositoryService.saveModel(model);
// 2.4 复制任务分配规则
taskAssignRuleService.copyTaskAssignRules(id, definition.getId());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteModel(String id) {
@ -229,11 +221,7 @@ public class BpmModelServiceImpl implements BpmModelService {
@Override
public BpmnModel getBpmnModel(String id) {
byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
if (ArrayUtil.isEmpty(bpmnBytes)) {
return null;
}
BpmnXMLConverter converter = new BpmnXMLConverter();
return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true);
return BpmnModelUtils.getBpmnModel(bpmnBytes);
}
@Override

View File

@ -23,7 +23,6 @@ import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
@ -124,6 +123,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
.key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory())
.addBytes(createReqDTO.getKey() + BpmnModelConstants.BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes())
.tenantId(TenantContextHolder.getTenantIdStr())
.disableSchemaValidation() // 禁用 XML Schema 验证因为有自定义的属性
.deploy();
// 设置 ProcessDefinition category 分类
@ -197,7 +197,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
return false;
}
// 校验 BPMN XML 信息
BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes());
BpmnModel newModel = BpmnModelUtils.getBpmnModel(createReqDTO.getBpmnBytes());
BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId());
// 对比字节变化
if (!BpmnModelUtils.equals(oldModel, newModel)) {
@ -207,18 +207,6 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
return true;
}
/**
* 构建对应的 BPMN Model
*
* @param bpmnBytes 原始的 BPMN XML 字节数组
* @return BPMN Model
*/
private BpmnModel buildBpmnModel(byte[] bpmnBytes) {
// 转换成 BpmnModel 对象
BpmnXMLConverter converter = new BpmnXMLConverter();
return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true);
}
@Override
public BpmProcessDefinitionExtDO getProcessDefinitionExt(String id) {
return processDefinitionMapper.selectByProcessDefinitionId(id);

View File

@ -1,14 +1,7 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.lang.Nullable;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Set;
/**
@ -18,73 +11,13 @@ import java.util.Set;
*/
public interface BpmTaskAssignRuleService {
/**
* 获得流程定义的任务分配规则数组
*
* @param processDefinitionId 流程定义的编号
* @param taskDefinitionKey 流程任务定义的 Key允许空
* @return 任务规则数组
*/
List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
@Nullable String taskDefinitionKey);
/**
* 获得流程模型的任务规则数组
*
* @param modelId 流程模型的编号
* @return 任务规则数组
*/
List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId);
/**
* 获得流程定义的任务分配规则数组
*
* @param modelId 流程模型的编号
* @param processDefinitionId 流程定义的编号
* @return 任务规则数组
*/
List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId);
/**
* 创建任务分配规则
*
* @param reqVO 创建信息
* @return 规则编号
*/
Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO);
/**
* 更新任务分配规则
*
* @param reqVO 创建信息
*/
void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO);
/**
* 判断指定流程模型和流程定义的分配规则是否相等
*
* @param modelId 流程模型编号
* @param processDefinitionId 流程定义编号
* @return 是否相等
*/
boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId);
/**
* 将流程流程模型的任务分配规则复制一份给流程定义
* 目的每次流程模型部署时都会生成一个新的流程定义此时考虑到每次部署的流程不可变性所以需要复制一份给该流程定义
*
* @param fromModelId 流程模型编号
* @param toProcessDefinitionId 流程定义编号
*/
void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId);
/**
* 校验流程模型的任务分配规则全部都配置了
* 目的如果有规则未配置会导致流程任务找不到负责人进而流程无法进行下去
*
* @param id 流程模型编号
* @param bpmnBytes BPMN XML
*/
void checkTaskAssignRuleAllConfig(String id);
void checkTaskAssignRuleAllConfig(byte[] bpmnBytes);
/**
* 计算当前执行任务的处理人

View File

@ -1,20 +1,16 @@
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;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
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.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
@ -28,17 +24,16 @@ import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
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.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.*;
import java.util.function.Function;
@ -46,7 +41,6 @@ import static cn.hutool.core.text.CharSequenceUtil.format;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
/**
@ -57,16 +51,12 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
@Slf4j
public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
@Resource
private BpmTaskAssignRuleMapper taskRuleMapper;
@Resource
@Lazy // 解决循环依赖
private BpmModelService modelService;
@Resource
@Lazy // 解决循环依赖
private BpmProcessDefinitionService processDefinitionService;
@Resource
private BpmUserGroupService userGroupService;
@Resource
@Lazy // 解决循环依赖
private BpmProcessInstanceService processInstanceService;
@Resource
private RoleApi roleApi;
@Resource
@ -79,9 +69,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
private DictDataApi dictDataApi;
@Resource
private PermissionApi permissionApi;
@Resource
@Lazy // 解决循环依赖
private BpmProcessInstanceService processInstanceService;
/**
* 任务分配脚本
*/
@ -93,130 +81,23 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
}
@Override
public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
String taskDefinitionKey) {
return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
}
@Override
public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId) {
return taskRuleMapper.selectListByModelId(modelId);
}
@Override
public List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId) {
// 获得规则
List<BpmTaskAssignRuleDO> rules = Collections.emptyList();
BpmnModel model = null;
if (StrUtil.isNotEmpty(modelId)) {
rules = getTaskAssignRuleListByModelId(modelId);
model = modelService.getBpmnModel(modelId);
} else if (StrUtil.isNotEmpty(processDefinitionId)) {
rules = getTaskAssignRuleListByProcessDefinitionId(processDefinitionId, null);
model = processDefinitionService.getBpmnModel(processDefinitionId);
}
if (model == null) {
return Collections.emptyList();
}
// 获得用户任务只有用户任务才可以设置分配规则
List<UserTask> userTasks = BpmnModelUtils.getBpmnModelElements(model, UserTask.class);
if (CollUtil.isEmpty(userTasks)) {
return Collections.emptyList();
}
// 转换数据
return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules);
}
@Override
public Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO) {
// 校验参数
validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
// 校验是否已经配置
BpmTaskAssignRuleDO existRule =
taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey());
if (existRule != null) {
throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey());
}
// 存储
BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)
.setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型才允许新建
taskRuleMapper.insert(rule);
return rule.getId();
}
@Override
public void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO) {
// 校验参数
validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
// 校验是否存在
BpmTaskAssignRuleDO existRule = taskRuleMapper.selectById(reqVO.getId());
if (existRule == null) {
throw exception(TASK_ASSIGN_RULE_NOT_EXISTS);
}
// 只允许修改流程模型的规则
if (!Objects.equals(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL, existRule.getProcessDefinitionId())) {
throw exception(TASK_UPDATE_FAIL_NOT_MODEL);
}
// 执行更新
taskRuleMapper.updateById(BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO));
}
@Override
public boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId) {
// 调用 VO 接口的原因是过滤掉流程模型不需要的规则保持和 copyTaskAssignRules 方法的一致性
List<BpmTaskAssignRuleRespVO> modelRules = getTaskAssignRuleList(modelId, null);
List<BpmTaskAssignRuleRespVO> processInstanceRules = getTaskAssignRuleList(null, processDefinitionId);
if (modelRules.size() != processInstanceRules.size()) {
return false;
}
// 遍历匹配对应的规则
Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap =
CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
for (BpmTaskAssignRuleRespVO modelRule : modelRules) {
BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey());
if (processInstanceRule == null) {
return false;
}
if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal(
modelRule.getOptions(), processInstanceRule.getOptions())) {
return false;
}
}
return true;
}
@Override
public void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId) {
List<BpmTaskAssignRuleRespVO> rules = getTaskAssignRuleList(fromModelId, null);
if (CollUtil.isEmpty(rules)) {
return;
}
// 开始复制
List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules);
newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null)
.setUpdateTime(null));
taskRuleMapper.insertBatch(newRules);
}
@Override
public void checkTaskAssignRuleAllConfig(String id) {
// 一个用户任务都没配置所以无需配置规则
List<BpmTaskAssignRuleRespVO> taskAssignRules = getTaskAssignRuleList(id, null);
if (CollUtil.isEmpty(taskAssignRules)) {
return;
}
// 校验未配置规则的任务
taskAssignRules.forEach(rule -> {
if (CollUtil.isEmpty(rule.getOptions())) {
throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, rule.getTaskDefinitionName());
public void checkTaskAssignRuleAllConfig(byte[] bpmnBytes) {
BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes);
assert bpmnModel != null;
List<UserTask> userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class);
// 遍历所有的 UserTask校验审批人配置
userTaskList.forEach(userTask -> {
// TODO 芋艿assignType/assignOptions/, 枚举
Integer type = NumberUtils.parseInt(userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType"));
String options = userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions");
if (type == null || StrUtil.isBlank(options)) {
throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, userTask.getName());
}
validTaskAssignRuleOptions(type, StrUtils.splitToLong(options, ","));
});
}
private void validTaskAssignRuleOptions(Integer type, Set<Long> options) {
private void validTaskAssignRuleOptions(Integer type, Collection<Long> options) {
if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) {
roleApi.validRoleList(options);
} else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
@ -247,92 +128,83 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
return convertSet(assignee, Function.identity());
}
// 2. 通过分配规则计算审批人
BpmTaskAssignRuleDO rule = getTaskRule(execution);
return calculateTaskCandidateUsers(execution, rule);
return calculateTaskCandidateUsers0(execution);
}
@VisibleForTesting
BpmTaskAssignRuleDO getTaskRule(DelegateExecution execution) {
List<BpmTaskAssignRuleDO> taskRules = getTaskAssignRuleListByProcessDefinitionId(
execution.getProcessDefinitionId(), execution.getCurrentActivityId());
if (CollUtil.isEmpty(taskRules)) {
throw new FlowableException(format("流程任务({}/{}/{}) 找不到符合的任务规则",
execution.getId(), execution.getProcessDefinitionId(), execution.getCurrentActivityId()));
}
if (taskRules.size() > 1) {
throw new FlowableException(format("流程任务({}/{}/{}) 找到过多任务规则({})",
execution.getId(), execution.getProcessDefinitionId(), execution.getCurrentActivityId()));
}
return taskRules.get(0);
}
Set<Long> calculateTaskCandidateUsers0(DelegateExecution execution) {
// 获得审批人配置
// 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"), ",");
@VisibleForTesting
Set<Long> calculateTaskCandidateUsers(DelegateExecution execution, BpmTaskAssignRuleDO rule) {
// 计算审批人
Set<Long> assigneeUserIds = null;
if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByRole(rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByDeptMember(rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByPost(rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByUser(rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByUserGroup(rule);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) {
assigneeUserIds = calculateTaskCandidateUsersByScript(execution, rule);
if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByRole(options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByDeptMember(options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByPost(options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByUser(options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByUserGroup(options);
} else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), type)) {
assigneeUserIds = calculateTaskCandidateUsersByScript(execution, options);
}
// 移除被禁用的用户
removeDisableUsers(assigneeUserIds);
// 如果候选人为空抛出异常
if (CollUtil.isEmpty(assigneeUserIds)) {
log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", execution.getId(),
execution.getProcessDefinitionId(), execution.getCurrentActivityId(), toJsonString(rule));
log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(),
execution.getProcessDefinitionId(), execution.getCurrentActivityId(), type, options);
throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
}
return assigneeUserIds;
}
private Set<Long> calculateTaskCandidateUsersByRole(BpmTaskAssignRuleDO rule) {
return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions());
private Set<Long> calculateTaskCandidateUsersByRole(Set<Long> roleIds) {
return permissionApi.getUserRoleIdListByRoleIds(roleIds);
}
private Set<Long> calculateTaskCandidateUsersByDeptMember(BpmTaskAssignRuleDO rule) {
List<AdminUserRespDTO> users = adminUserApi.getUserListByDeptIds(rule.getOptions());
private Set<Long> calculateTaskCandidateUsersByDeptMember(Set<Long> deptIds) {
List<AdminUserRespDTO> users = adminUserApi.getUserListByDeptIds(deptIds);
return convertSet(users, AdminUserRespDTO::getId);
}
private Set<Long> calculateTaskCandidateUsersByDeptLeader(BpmTaskAssignRuleDO rule) {
List<DeptRespDTO> depts = deptApi.getDeptList(rule.getOptions());
private Set<Long> calculateTaskCandidateUsersByDeptLeader(Set<Long> deptIds) {
List<DeptRespDTO> depts = deptApi.getDeptList(deptIds);
return convertSet(depts, DeptRespDTO::getLeaderUserId);
}
private Set<Long> calculateTaskCandidateUsersByPost(BpmTaskAssignRuleDO rule) {
List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(rule.getOptions());
private Set<Long> calculateTaskCandidateUsersByPost(Set<Long> postIds) {
List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(postIds);
return convertSet(users, AdminUserRespDTO::getId);
}
private Set<Long> calculateTaskCandidateUsersByUser(BpmTaskAssignRuleDO rule) {
return rule.getOptions();
private Set<Long> calculateTaskCandidateUsersByUser(Set<Long> userIds) {
return userIds;
}
private Set<Long> calculateTaskCandidateUsersByUserGroup(BpmTaskAssignRuleDO rule) {
List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
private Set<Long> calculateTaskCandidateUsersByUserGroup(Set<Long> groupIds) {
List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(groupIds);
Set<Long> userIds = new HashSet<>();
userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds()));
return userIds;
}
private Set<Long> calculateTaskCandidateUsersByScript(DelegateExecution execution, BpmTaskAssignRuleDO rule) {
private Set<Long> calculateTaskCandidateUsersByScript(DelegateExecution execution, Set<Long> scriptIds) {
// 获得对应的脚本
List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size());
rule.getOptions().forEach(id -> {
BpmTaskAssignScript script = scriptMap.get(id);
List<BpmTaskAssignScript> scripts = new ArrayList<>(scriptIds.size());
scriptIds.forEach(scriptId -> {
BpmTaskAssignScript script = scriptMap.get(scriptId);
if (script == null) {
throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id);
throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, scriptId);
}
scripts.add(script);
});

View File

@ -1,13 +1,14 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import jakarta.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
* 用户组 Service 接口
@ -77,6 +78,6 @@ public interface BpmUserGroupService {
*
* @param ids 用户组编号数组
*/
void validUserGroups(Set<Long> ids);
void validUserGroups(Collection<Long> ids);
}

View File

@ -1,27 +1,27 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.group.BpmUserGroupUpdateReqVO;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmUserGroupConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmUserGroupMapper;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_IS_DISABLE;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.USER_GROUP_NOT_EXISTS;
/**
* 用户组 Service 实现类
@ -89,7 +89,7 @@ public class BpmUserGroupServiceImpl implements BpmUserGroupService {
}
@Override
public void validUserGroups(Set<Long> ids) {
public void validUserGroups(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return;
}

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.framework.flowable.core.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import java.util.*;
@ -91,6 +93,15 @@ public class BpmnModelUtils {
return converter.convertToXML(model);
}
public static BpmnModel getBpmnModel(byte[] bpmnBytes) {
if (ArrayUtil.isEmpty(bpmnBytes)) {
return null;
}
BpmnXMLConverter converter = new BpmnXMLConverter();
// 补充说明由于在 Flowable 中自定义了属性所以 validateSchema 传递 false
return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), false, false);
}
// ========== 遍历相关的方法 ==========
/**