feat: 基本完成流程抄送

This commit is contained in:
kyle 2024-01-09 18:39:51 +08:00
parent e21c262bd7
commit 555bac151d
23 changed files with 859 additions and 53 deletions

View File

@ -14,7 +14,7 @@ import java.util.Set;
* @see BpmTaskAssignRuleBaseVO
*/
@Data
public class BpmTaskCandidateVO {
public class BpmTaskCandidateRuleVO {
@Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bpm_task_assign_rule_type")
@NotNull(message = "规则类型不能为空")

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -17,4 +18,7 @@ public class BpmTaskApproveReqVO {
@NotEmpty(message = "审批意见不能为空")
private String reason;
@Schema(description = "审批时流程抄送人", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private BpmTaskCandidateRuleVO ccCandidateRule;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.bpm.convert.cc;
import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 动态表单 Convert
*
* @author 芋艿
*/
@Mapper
public interface BpmProcessInstanceCopyConvert {
BpmProcessInstanceCopyConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceCopyConvert.class);
BpmProcessInstanceCopyDO copy(BpmProcessInstanceCopyDO bean);
BpmProcessInstanceCopyVO convert(BpmProcessInstanceCopyDO bean);
List<BpmProcessInstanceCopyVO> convertList2(List<BpmProcessInstanceCopyDO> list);
}

View File

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.bpm.dal.dataobject.cc;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 流程抄送对象
*
* @author kyle
* @date 2022-05-19
*/
@TableName(value = "bpm_process_instance_copy", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BpmProcessInstanceCopyDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 发起人Id
*/
private Long startUserId;
/**
* 表单名
*/
private String name;
/**
* 流程主键
*/
private String processInstanceId;
/**
* 任务主键
*/
private String taskId;
/**
* 用户主键
*/
private Long userId;
}

View File

@ -0,0 +1,9 @@
package cn.iocoder.yudao.module.bpm.dal.mysql.cc;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BpmProcessInstanceCopyMapper extends BaseMapperX<BpmProcessInstanceCopyDO> {
}

View File

@ -41,7 +41,7 @@ public class BpmCandidateProcessorConfiguration {
/**
* 可以自己定制脚本然后通过这里设置到处理器里面去
* @param scriptsOp
* @param scriptsOp 脚本包装对象
* @return
*/
@Bean

View File

@ -1,13 +1,13 @@
package cn.iocoder.yudao.module.bpm.service.candidate;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleBaseVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.flowable.engine.delegate.DelegateExecution;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.HashSet;
import java.util.Set;
@ -20,21 +20,20 @@ import java.util.Set;
public class BpmCandidateSourceInfo {
@Schema(description = "流程id")
@NotNull
private String processInstanceId;
@Schema(description = "当前任务ID")
@NotNull
private String taskId;
/**
* 通过这些规则生成最终需要生成的用户
*/
@Schema(description = "当前任务预选规则")
private Set<BpmTaskCandidateVO> rules;
@NotEmpty(message = "不允许空规则")
private Set<BpmTaskCandidateRuleVO> rules;
@Schema(description = "源执行流程")
private DelegateExecution execution;
public void addRule(BpmTaskCandidateVO vo) {
public void addRule(BpmTaskCandidateRuleVO vo) {
assert vo != null;
if (rules == null) {
rules = new HashSet<>();

View File

@ -1,8 +1,9 @@
package cn.iocoder.yudao.module.bpm.service.candidate;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import org.flowable.engine.delegate.DelegateExecution;
import java.util.Collections;
import java.util.HashSet;
@ -29,24 +30,24 @@ public interface BpmCandidateSourceInfoProcessor {
* 默认的处理
* 如果想去操作所有的规则则可以覆盖此方法
*
* @param request
* @param chain
* @param request 原始请求
* @param delegateExecution 审批过程中的对象
* @return 必须包含的是用户ID而不是其他的ID
* @throws Exception
*/
default Set<Long> process(BpmCandidateSourceInfo request, BpmCandidateSourceInfoProcessorChain chain) throws Exception {
Set<BpmTaskCandidateVO> rules = request.getRules();
default Set<Long> process(BpmCandidateSourceInfo request, DelegateExecution delegateExecution) throws Exception {
Set<BpmTaskCandidateRuleVO> rules = request.getRules();
Set<Long> results = new HashSet<>();
for (BpmTaskCandidateVO rule : rules) {
for (BpmTaskCandidateRuleVO rule : rules) {
// 每个处理器都有机会处理自己支持的事件
if (CollUtil.contains(getSupportedTypes(), rule.getType())) {
results.addAll(doProcess(request, rule));
results.addAll(doProcess(request, rule, delegateExecution));
}
}
return results;
}
default Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateVO rule) {
default Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) {
return Collections.emptySet();
}
}

View File

@ -1,8 +1,9 @@
package cn.iocoder.yudao.module.bpm.service.candidate;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.delegate.DelegateExecution;
@ -11,7 +12,6 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class BpmCandidateSourceInfoProcessorChain {
@ -31,7 +31,7 @@ public class BpmCandidateSourceInfoProcessorChain {
@Resource
// 动态扩展处理节点
public BpmCandidateSourceInfoProcessorChain addProcessor(ObjectProvider<BpmCandidateSourceInfoProcessor> processorOp) {
List<BpmCandidateSourceInfoProcessor> processor = processorOp.orderedStream().collect(Collectors.toList());
List<BpmCandidateSourceInfoProcessor> processor = ListUtil.toList(processorOp.iterator());
if (null == processorList) {
processorList = new ArrayList<>(processor.size());
}
@ -40,14 +40,14 @@ public class BpmCandidateSourceInfoProcessorChain {
}
// 获取处理器处理
public Set<Long> process(BpmCandidateSourceInfo sourceInfo) throws Exception {
public Set<Long> process(BpmCandidateSourceInfo sourceInfo, DelegateExecution execution) throws Exception {
// Verify our parameters
if (sourceInfo == null) {
throw new IllegalArgumentException();
}
for (BpmCandidateSourceInfoProcessor processor : processorList) {
try {
for (BpmTaskCandidateVO vo : sourceInfo.getRules()) {
for (BpmTaskCandidateRuleVO vo : sourceInfo.getRules()) {
processor.validRuleOptions(vo.getType(), vo.getOptions());
}
} catch (Exception e) {
@ -59,7 +59,7 @@ public class BpmCandidateSourceInfoProcessorChain {
Exception saveException = null;
for (BpmCandidateSourceInfoProcessor processor : processorList) {
try {
saveResult = processor.process(sourceInfo, this);
saveResult = processor.process(sourceInfo, execution);
if (CollUtil.isNotEmpty(saveResult)) {
removeDisableUsers(saveResult);
break;
@ -78,10 +78,9 @@ public class BpmCandidateSourceInfoProcessorChain {
}
public Set<Long> calculateTaskCandidateUsers(DelegateExecution execution, BpmCandidateSourceInfo sourceInfo) {
sourceInfo.setExecution(execution);
Set<Long> results = Collections.emptySet();
try {
results = process(sourceInfo);
results = process(sourceInfo, execution);
} catch (Exception e) {
e.printStackTrace();
}
@ -90,6 +89,7 @@ public class BpmCandidateSourceInfoProcessorChain {
/**
* 移除禁用用户
*
* @param assigneeUserIds
*/
public void removeDisableUsers(Set<Long> assigneeUserIds) {

View File

@ -1,11 +1,12 @@
package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import org.flowable.engine.delegate.DelegateExecution;
import javax.annotation.Resource;
import java.util.Set;
@ -25,7 +26,7 @@ public class BpmCandidateAdminUserApiSourceInfoProcessor implements BpmCandidate
}
@Override
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateVO rule) {
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) {
return rule.getOptions();
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor;
@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.delegate.DelegateExecution;
import javax.annotation.Resource;
import java.util.Collections;
@ -36,7 +37,7 @@ public class BpmCandidateDeptApiSourceInfoProcessor implements BpmCandidateSourc
}
@Override
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateVO rule) {
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) {
if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) {
List<AdminUserRespDTO> users = adminUserApi.getUserListByDeptIds(rule.getOptions());
return convertSet(users, AdminUserRespDTO::getId);

View File

@ -1,13 +1,14 @@
package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor;
import cn.iocoder.yudao.module.system.api.dept.PostApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.delegate.DelegateExecution;
import javax.annotation.Resource;
import java.util.List;
@ -32,7 +33,7 @@ public class BpmCandidatePostApiSourceInfoProcessor implements BpmCandidateSourc
}
@Override
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateVO rule) {
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) {
List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(rule.getOptions());
return convertSet(users, AdminUserRespDTO::getId);
}

View File

@ -1,12 +1,13 @@
package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import org.flowable.engine.delegate.DelegateExecution;
import javax.annotation.Resource;
import java.util.Set;
@ -29,7 +30,7 @@ public class BpmCandidateRoleApiSourceInfoProcessor implements BpmCandidateSourc
}
@Override
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateVO rule) {
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) {
return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions());
}

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
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;
@ -51,8 +51,8 @@ public class BpmCandidateScriptApiSourceInfoProcessor implements BpmCandidateSou
}
@Override
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateVO rule) {
return calculateTaskCandidateUsersByScript(request.getExecution(), rule.getOptions());
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) {
return calculateTaskCandidateUsersByScript(delegateExecution, rule.getOptions());
}
private Set<Long> calculateTaskCandidateUsersByScript(DelegateExecution execution, Set<Long> options) {

View File

@ -1,12 +1,13 @@
package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor;
import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
import org.flowable.engine.delegate.DelegateExecution;
import javax.annotation.Resource;
import java.util.HashSet;
@ -30,7 +31,7 @@ public class BpmCandidateUserGroupApiSourceInfoProcessor implements BpmCandidate
}
@Override
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateVO rule) {
public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) {
List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions());
Set<Long> userIds = new HashSet<>();
userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds()));

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.bpm.service.cc;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
/**
* 流程抄送Service接口
*
* 现在是在审批的时候进行流程抄送
*/
public interface BpmProcessInstanceCopyService {
/**
* 查询流程抄送
*
* @param copyId 流程抄送主键
* @return 流程抄送
*/
BpmProcessInstanceCopyVO queryById(Long copyId);
/**
* 抄送
* @param sourceInfo 抄送源信息方便抄送处理
* @return
*/
boolean makeCopy(BpmCandidateSourceInfo sourceInfo);
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.yudao.module.bpm.service.cc;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.bpm.convert.cc.BpmProcessInstanceCopyConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessorChain;
import cn.iocoder.yudao.module.bpm.service.cc.dto.BpmDelegateExecutionDTO;
import cn.iocoder.yudao.module.bpm.util.FlowableUtils;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Slf4j
@Service
@Validated
public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService {
@Resource
private BpmProcessInstanceCopyMapper processInstanceCopyMapper;
/**
* 和flowable有关的查询流程名用的
*/
@Resource
private RuntimeService runtimeService;
/**
* 找抄送人用的
*/
@Resource
private BpmCandidateSourceInfoProcessorChain processorChain;
@Override
public BpmProcessInstanceCopyVO queryById(Long copyId) {
BpmProcessInstanceCopyDO bpmProcessInstanceCopyDO = processInstanceCopyMapper.selectById(copyId);
return BpmProcessInstanceCopyConvert.INSTANCE.convert(bpmProcessInstanceCopyDO);
}
@Override
public boolean makeCopy(BpmCandidateSourceInfo sourceInfo) {
if (null == sourceInfo) {
return false;
}
DelegateExecution executionEntity = new BpmDelegateExecutionDTO(sourceInfo.getProcessInstanceId());
Set<Long> ccCandidates = processorChain.calculateTaskCandidateUsers(executionEntity, sourceInfo);
if (CollUtil.isEmpty(ccCandidates)) {
log.warn("相关抄送人不存在 {}", sourceInfo.getTaskId());
return false;
} else {
BpmProcessInstanceCopyDO copyDO = new BpmProcessInstanceCopyDO();
// 调用
//设置任务id
copyDO.setTaskId(sourceInfo.getTaskId());
copyDO.setProcessInstanceId(sourceInfo.getProcessInstanceId());
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(sourceInfo.getProcessInstanceId())
.singleResult();
if (null == processInstance) {
log.warn("相关流程实例不存在 {}", sourceInfo.getTaskId());
return false;
}
copyDO.setStartUserId(FlowableUtils.getStartUserIdFromProcessInstance(processInstance));
copyDO.setName(FlowableUtils.getFlowName(processInstance.getProcessDefinitionId()));
List<BpmProcessInstanceCopyDO> copyList = new ArrayList<>(ccCandidates.size());
for (Long userId : ccCandidates) {
BpmProcessInstanceCopyDO copy = BpmProcessInstanceCopyConvert.INSTANCE.copy(copyDO);
copy.setUserId(userId);
copyList.add(copy);
}
return processInstanceCopyMapper.insertBatch(copyList);
}
}
public List<BpmProcessInstanceCopyVO> queryByProcessId() {
return null;
}
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.bpm.service.cc;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 流程抄送视图对象 wf_copy
*
* @author ruoyi
* @date 2022-05-19
*/
@Data
public class BpmProcessInstanceCopyVO {
/**
* 编号
*/
@Schema(description = "抄送主键")
private Long id;
/**
* 发起人Id
*/
@Schema(description = "发起人Id")
private Long startUserId;
/**
* 表单名
*/
@Schema(description = "流程实例的名字")
private String name;
/**
* 流程主键
*/
@Schema(description = "流程实例的主键")
private String processInstanceId;
/**
* 任务主键
*/
@Schema(description = "发起抄送的任务编号")
private String taskId;
/**
* 用户主键
*/
@Schema(description = "用户编号")
private Long userId;
}

View File

@ -0,0 +1,439 @@
package cn.iocoder.yudao.module.bpm.service.cc.dto;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.FlowableListener;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ReadOnlyDelegateExecution;
import org.flowable.variable.api.persistence.entity.VariableInstance;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 仅为了传输processInstanceId
*/
public class BpmDelegateExecutionDTO implements DelegateExecution {
public BpmDelegateExecutionDTO(String getProcessInstanceId) {
this.getProcessInstanceId = getProcessInstanceId;
}
private final String getProcessInstanceId;
@Override
public String getId() {
return null;
}
@Override
public String getProcessInstanceId() {
return null;
}
@Override
public String getRootProcessInstanceId() {
return null;
}
@Override
public String getEventName() {
return null;
}
@Override
public void setEventName(String eventName) {
}
@Override
public String getProcessInstanceBusinessKey() {
return null;
}
@Override
public String getProcessInstanceBusinessStatus() {
return null;
}
@Override
public String getProcessDefinitionId() {
return null;
}
@Override
public String getPropagatedStageInstanceId() {
return null;
}
@Override
public String getParentId() {
return null;
}
@Override
public String getSuperExecutionId() {
return null;
}
@Override
public String getCurrentActivityId() {
return null;
}
@Override
public String getTenantId() {
return null;
}
@Override
public FlowElement getCurrentFlowElement() {
return null;
}
@Override
public void setCurrentFlowElement(FlowElement flowElement) {
}
@Override
public FlowableListener getCurrentFlowableListener() {
return null;
}
@Override
public void setCurrentFlowableListener(FlowableListener currentListener) {
}
@Override
public ReadOnlyDelegateExecution snapshotReadOnly() {
return null;
}
@Override
public DelegateExecution getParent() {
return null;
}
@Override
public List<? extends DelegateExecution> getExecutions() {
return null;
}
@Override
public void setActive(boolean isActive) {
}
@Override
public boolean isActive() {
return false;
}
@Override
public boolean isEnded() {
return false;
}
@Override
public void setConcurrent(boolean isConcurrent) {
}
@Override
public boolean isConcurrent() {
return false;
}
@Override
public boolean isProcessInstanceType() {
return false;
}
@Override
public void inactivate() {
}
@Override
public boolean isScope() {
return false;
}
@Override
public void setScope(boolean isScope) {
}
@Override
public boolean isMultiInstanceRoot() {
return false;
}
@Override
public void setMultiInstanceRoot(boolean isMultiInstanceRoot) {
}
@Override
public Map<String, Object> getVariables() {
return null;
}
@Override
public Map<String, VariableInstance> getVariableInstances() {
return null;
}
@Override
public Map<String, Object> getVariables(Collection<String> collection) {
return null;
}
@Override
public Map<String, VariableInstance> getVariableInstances(Collection<String> collection) {
return null;
}
@Override
public Map<String, Object> getVariables(Collection<String> collection, boolean b) {
return null;
}
@Override
public Map<String, VariableInstance> getVariableInstances(Collection<String> collection, boolean b) {
return null;
}
@Override
public Map<String, Object> getVariablesLocal() {
return null;
}
@Override
public Map<String, VariableInstance> getVariableInstancesLocal() {
return null;
}
@Override
public Map<String, Object> getVariablesLocal(Collection<String> collection) {
return null;
}
@Override
public Map<String, VariableInstance> getVariableInstancesLocal(Collection<String> collection) {
return null;
}
@Override
public Map<String, Object> getVariablesLocal(Collection<String> collection, boolean b) {
return null;
}
@Override
public Map<String, VariableInstance> getVariableInstancesLocal(Collection<String> collection, boolean b) {
return null;
}
@Override
public Object getVariable(String s) {
return null;
}
@Override
public VariableInstance getVariableInstance(String s) {
return null;
}
@Override
public Object getVariable(String s, boolean b) {
return null;
}
@Override
public VariableInstance getVariableInstance(String s, boolean b) {
return null;
}
@Override
public Object getVariableLocal(String s) {
return null;
}
@Override
public VariableInstance getVariableInstanceLocal(String s) {
return null;
}
@Override
public Object getVariableLocal(String s, boolean b) {
return null;
}
@Override
public VariableInstance getVariableInstanceLocal(String s, boolean b) {
return null;
}
@Override
public <T> T getVariable(String s, Class<T> aClass) {
return null;
}
@Override
public <T> T getVariableLocal(String s, Class<T> aClass) {
return null;
}
@Override
public Set<String> getVariableNames() {
return null;
}
@Override
public Set<String> getVariableNamesLocal() {
return null;
}
@Override
public void setVariable(String s, Object o) {
}
@Override
public void setVariable(String s, Object o, boolean b) {
}
@Override
public Object setVariableLocal(String s, Object o) {
return null;
}
@Override
public Object setVariableLocal(String s, Object o, boolean b) {
return null;
}
@Override
public void setVariables(Map<String, ?> map) {
}
@Override
public void setVariablesLocal(Map<String, ?> map) {
}
@Override
public boolean hasVariables() {
return false;
}
@Override
public boolean hasVariablesLocal() {
return false;
}
@Override
public boolean hasVariable(String s) {
return false;
}
@Override
public boolean hasVariableLocal(String s) {
return false;
}
@Override
public void removeVariable(String s) {
}
@Override
public void removeVariableLocal(String s) {
}
@Override
public void removeVariables(Collection<String> collection) {
}
@Override
public void removeVariablesLocal(Collection<String> collection) {
}
@Override
public void removeVariables() {
}
@Override
public void removeVariablesLocal() {
}
@Override
public void setTransientVariable(String s, Object o) {
}
@Override
public void setTransientVariableLocal(String s, Object o) {
}
@Override
public void setTransientVariables(Map<String, Object> map) {
}
@Override
public Object getTransientVariable(String s) {
return null;
}
@Override
public Map<String, Object> getTransientVariables() {
return null;
}
@Override
public void setTransientVariablesLocal(Map<String, Object> map) {
}
@Override
public Object getTransientVariableLocal(String s) {
return null;
}
@Override
public Map<String, Object> getTransientVariablesLocal() {
return null;
}
@Override
public void removeTransientVariableLocal(String s) {
}
@Override
public void removeTransientVariable(String s) {
}
@Override
public void removeTransientVariables() {
}
@Override
public void removeTransientVariablesLocal() {
}
}

View File

@ -19,6 +19,8 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
@ -94,6 +96,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
@Resource
private ManagementService managementService;
@Resource
private BpmProcessInstanceCopyService processInstanceCopyService;
@Override
public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
// 查询待办任务
@ -237,6 +242,17 @@ public class BpmTaskServiceImpl implements BpmTaskService {
.setReason(reqVO.getReason()));
// 处理加签任务
handleParentTask(task);
// 在能正常审批的情况下抄送流程
if (null != reqVO.getCcCandidateRule()) {
BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo();
sourceInfo.setTaskId(reqVO.getId());
sourceInfo.setProcessInstanceId(instance.getId());
sourceInfo.addRule(reqVO.getCcCandidateRule());
if (!processInstanceCopyService.makeCopy(sourceInfo)) {
throw new RuntimeException("抄送任务失败");
}
}
}

View File

@ -0,0 +1,78 @@
package cn.iocoder.yudao.module.bpm.util;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import java.util.List;
import java.util.Map;
/**
* 流程引擎工具类封装
*
* @author: linjinp
* @create: 2019-12-24 13:51
**/
public class FlowableUtils {
/**
* 获取流程名称
*
* @param processDefinitionId
* @return
*/
public static String getFlowName(String processDefinitionId) {
RepositoryService repositoryService = SpringUtil.getBean(RepositoryService.class);
ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
return processDefinition.getName();
}
/**
* 获取节点数据
*
* @param processInstanceId
* @param nodeId
* @return
*/
public static FlowNode getFlowNode(String processInstanceId, String nodeId) {
RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class);
RepositoryService repositoryService = SpringUtil.getBean(RepositoryService.class);
String definitionld = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionId(); //获取bpm模型对象
BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionld);
//传节点定义key获取当前节点
FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(nodeId);
return flowNode;
}
public static ExtensionElement generateFlowNodeIdExtension(String nodeId) {
ExtensionElement extensionElement = new ExtensionElement();
extensionElement.setElementText(nodeId);
extensionElement.setName("nodeId");
extensionElement.setNamespacePrefix("flowable");
extensionElement.setNamespace("nodeId");
return extensionElement;
}
public static String getNodeIdFromExtension(FlowElement flowElement) {
Map<String, List<ExtensionElement>> extensionElements = flowElement.getExtensionElements();
return extensionElements.get("nodeId").get(0).getElementText();
}
public static Long getStartUserIdFromProcessInstance(ProcessInstance instance) {
if (null == instance) {
return null;
}
return NumberUtils.parseLong(instance.getStartUserId());
}
}

View File

@ -4,8 +4,7 @@ import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum;
@ -13,10 +12,7 @@ import cn.iocoder.yudao.module.bpm.framework.bpm.config.BpmCandidateProcessorCon
import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX1Script;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX2Script;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessorChain;
import cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor.BpmCandidateScriptApiSourceInfoProcessor;
import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleServiceImpl;
import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.PostApi;
@ -28,7 +24,6 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.delegate.DelegateExecution;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
@ -72,7 +67,7 @@ public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest {
@Test
public void testCalculateTaskCandidateUsers_Role() {
// 准备参数
BpmTaskCandidateVO rule = new BpmTaskCandidateVO().setOptions(asSet(1L, 2L))
BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L))
.setType(BpmTaskAssignRuleTypeEnum.ROLE.getType());
// mock 方法
when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions())))
@ -90,7 +85,7 @@ public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest {
@Test
public void testCalculateTaskCandidateUsers_DeptMember() {
// 准备参数
BpmTaskCandidateVO rule = new BpmTaskCandidateVO().setOptions(asSet(1L, 2L))
BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L))
.setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType());
// mock 方法
List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L),
@ -109,7 +104,7 @@ public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest {
@Test
public void testCalculateTaskCandidateUsers_DeptLeader() {
// 准备参数
BpmTaskCandidateVO rule = new BpmTaskCandidateVO().setOptions(asSet(1L, 2L))
BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L))
.setType(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType());
// mock 方法
DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L));
@ -128,7 +123,7 @@ public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest {
@Test
public void testCalculateTaskCandidateUsers_Post() {
// 准备参数
BpmTaskCandidateVO rule = new BpmTaskCandidateVO().setOptions(asSet(1L, 2L))
BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L))
.setType(BpmTaskAssignRuleTypeEnum.POST.getType());
// mock 方法
List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L),
@ -147,7 +142,7 @@ public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest {
@Test
public void testCalculateTaskCandidateUsers_User() {
// 准备参数
BpmTaskCandidateVO rule = new BpmTaskCandidateVO().setOptions(asSet(1L, 2L))
BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L))
.setType(BpmTaskAssignRuleTypeEnum.USER.getType());
// mock 方法
mockGetUserMap(asSet(1L, 2L));
@ -163,7 +158,7 @@ public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest {
@Test
public void testCalculateTaskCandidateUsers_UserGroup() {
// 准备参数
BpmTaskCandidateVO rule = new BpmTaskCandidateVO().setOptions(asSet(1L, 2L))
BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L))
.setType(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType());
// mock 方法
BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L)));
@ -188,7 +183,7 @@ public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest {
@Test
public void testCalculateTaskCandidateUsers_Script() {
// 准备参数
BpmTaskCandidateVO rule = new BpmTaskCandidateVO().setOptions(asSet(20L, 21L))
BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(20L, 21L))
.setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType());
// mock 方法
BpmTaskAssignScript script1 = new BpmTaskAssignScript() {

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.bpm.service.cc;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
@Import({BpmProcessInstanceCopyServiceImpl.class})
class BpmProcessInstanceCopyServiceTest extends BaseDbUnitTest {
@Resource
private BpmProcessInstanceCopyServiceImpl service;
@Test
void queryById() {
}
}