diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java index 5db58ab71b..5094084574 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmActivityConvert.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.bpm.convert.task; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO; import org.flowable.engine.history.HistoricActivityInstance; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -20,11 +19,11 @@ public interface BpmActivityConvert { BpmActivityConvert INSTANCE = Mappers.getMapper(BpmActivityConvert.class); - List convertList(List list); + List convertList(List list); @Mappings({ @Mapping(source = "activityId", target = "key"), @Mapping(source = "activityType", target = "type") }) - BpmActivityRespVO convert(BpmActivityDO bean); + BpmActivityRespVO convert(HistoricActivityInstance bean); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmActivityMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmActivityMapper.java index 9041248ff7..7e93b240f5 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmActivityMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/task/BpmActivityMapper.java @@ -7,20 +7,9 @@ import org.apache.ibatis.annotations.Param; import java.util.List; -/** - * @author kemengkai - * @create 2022-05-09 09:26 TODO @ke:@date 哈。ps:一般这种类,可以不用谢类注释和方法注释。因为是 dao 是通用操作,所以都是通过方法名,可以指导它的用途 - */ @Mapper public interface BpmActivityMapper extends BaseMapperX { - // TODO @ke:这个方法,是不是暂时用不到呀。如果是的话,可以删除哈 - /** - * 获取所有历史任务 - * - * @return 返回历史任务 - */ - List listAll(); // TODO @ke:可以试试,把 activiti 的表,映射成对应的实体,然后读取下。我们尽量避免 xml 操作,因为要做多 db 类型的支持,例如说 oracle 等。通过 mybatis plus 帮助我们生成不同数据库的表操作 /** diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/domain/vo/ApproveProcInstVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/domain/vo/ApproveProcInstVO.java deleted file mode 100644 index 2fb56a9eb6..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/domain/vo/ApproveProcInstVO.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.bpm.domain.vo; - -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.time.LocalDate; - -/** - * 审批流程VO - * - * @author kemengkai - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -// TODO @ke:这个类是不是没用呀 -public class ApproveProcInstVO { - - @ApiModelProperty("任务id") - private String id; - @ApiModelProperty("任务部署key") - private String taskDefKey; - @ApiModelProperty("任务名称") - private String name; - @ApiModelProperty("审批人登录名") - private String assignee; - @ApiModelProperty("审批人姓名") - private String assigneeName; - @ApiModelProperty("审批回复") - private String taskComment; - @ApiModelProperty("审批完成时间") - private LocalDate endTime; -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java index 0921f72047..a5bfc8a1fc 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java @@ -1,12 +1,9 @@ package cn.iocoder.yudao.module.bpm.service.task; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.activity.BpmActivityRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmActivityConvert; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper; import lombok.extern.slf4j.Slf4j; - import org.flowable.engine.HistoryService; import org.flowable.engine.history.HistoricActivityInstance; import org.springframework.stereotype.Service; @@ -32,13 +29,10 @@ public class BpmActivityServiceImpl implements BpmActivityService { private BpmActivityMapper bpmActivityMapper; @Override - @TenantIgnore - public List getActivityListByProcessInstanceId(String procInstId) { -// List activityList = historyService.createHistoricActivityInstanceQuery() -// .processInstanceId(procInstId).list(); - // TODO @ke:这个是想要过滤掉 aha.act_type_ != 'sequenceFlow' 类型么? - List bpmActivityDOList = bpmActivityMapper.listAllByProcInstIdAndDelete(procInstId); - return BpmActivityConvert.INSTANCE.convertList(bpmActivityDOList); + public List getActivityListByProcessInstanceId(String processInstanceId) { + List activityList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId).list(); + return BpmActivityConvert.INSTANCE.convertList(activityList); } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index f5738ed7d5..def4301006 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; 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.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 //TODO startProcessInstance流程里面修改了 BpmProcessInstanceExt,没有提交,和下面的更新 锁持有冲突了,异步更新这个表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()).setFormVariables(variables)); BpmProcessInstanceExtDO bpmProcessInstanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()).setFormVariables(variables); asyncUpdateProcesInstance(bpmProcessInstanceExtDO); return instance.getId(); } @Async public void asyncUpdateProcesInstance(BpmProcessInstanceExtDO bpmProcessInstanceExtDO){ log.info("asyncUpdateProcesInstance ,cause MySQL Dead Lock"); processInstanceExtMapper.updateByProcessInstanceId(bpmProcessInstanceExtDO); } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; 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.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; 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 lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. * * HistoricProcessInstance & ProcessInstance 的关系: * 1. * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.startProcessInstanceById(definition.getId(), businessKey, variables); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 //TODO startProcessInstance流程里面修改了 BpmProcessInstanceExt,没有提交,和下面的更新 锁持有冲突了,异步更新这个表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()).setFormVariables(variables)); BpmProcessInstanceExtDO bpmProcessInstanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()).setFormVariables(variables); asyncUpdateProcesInstance(bpmProcessInstanceExtDO); return instance.getId(); } @Async public void asyncUpdateProcesInstance(BpmProcessInstanceExtDO bpmProcessInstanceExtDO){ log.info("asyncUpdateProcesInstance ,cause MySQL Dead Lock"); processInstanceExtMapper.updateByProcessInstanceId(bpmProcessInstanceExtDO); } } \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 7367594b2a..e35a6626db 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -18,8 +18,8 @@ import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; -import cn.iocoder.yudao.module.business.hi.task.inst.service.HiTaskInstService; 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 lombok.extern.slf4j.Slf4j; @@ -78,8 +78,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { private BpmTaskAssignRuleMapper taskAssignRuleMapper; @Resource private BpmActivityMapper bpmActivityMapper; - @Resource - private HiTaskInstService hiTaskInstService; @Override public PageResult getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { @@ -161,22 +159,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public List getTaskListByProcessInstanceId(String processInstanceId) { // 获得任务列表 - /* List tasks = - historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId) + List tasks = historyService.createHistoricTaskInstanceQuery() + .processInstanceId(processInstanceId) .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序 .list(); if (CollUtil.isEmpty(tasks)) { return Collections.emptyList(); - }*/ + } + // 获得 TaskExtDO Map - // List bpmTaskExtDOList = - // taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); - -// List bpmTaskExtDOList = taskExtMapper.listByProcInstId(processInstanceId); - // List bpmTaskExtDOList = BpmTaskConvert.INSTANCE.distinct(tmpBpmTaskExtDOList); - // bpmTaskExtDOList.forEach(var -> log.info("var = " + var)); - - /*Map bpmTaskExtDoMap = convertMap(bpmTaskExtDOList, BpmTaskExtDO::getTaskId); + List bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId)); + Map bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId); // 获得 ProcessInstance Map HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId); // 获得 User Map @@ -184,14 +177,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { userIds.add(NumberUtils.parseLong(processInstance.getStartUserId())); Map userMap = adminUserApi.getUserMap(userIds); // 获得 Dept Map - Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));*/ + Map deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); // 拼接数据 -// List tmpBpmTaskExtDOList = taskExtMapper.listByProcInstId(processInstanceId); - // TODO @ke:这个钉钉是咋处理的?得讨论下流程预测的需要程度哈。 - List tmpBpmTaskExtDOList = taskExtMapper.selectListByProcessInstanceId(processInstanceId); - tmpBpmTaskExtDOList.sort(Comparator.comparing(BpmTaskExtDO::getCreateTime)); - return hiTaskInstService.taskGetComment(tmpBpmTaskExtDOList, ""); + return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap); } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/domain/HistoricApproveTaskDTO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/domain/HistoricApproveTaskDTO.java deleted file mode 100644 index 0bb580d684..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/domain/HistoricApproveTaskDTO.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.yudao.module.business.hi.task.inst.domain; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * @author kemengkai - * @create 2022-01-11 15:09 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -public class HistoricApproveTaskDTO { - - private String procInstId; - private String name; - private String assignee; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/domain/vo/HiTaskinstVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/domain/vo/HiTaskinstVO.java deleted file mode 100644 index b8547c6bb6..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/domain/vo/HiTaskinstVO.java +++ /dev/null @@ -1,105 +0,0 @@ -package cn.iocoder.yudao.module.business.hi.task.inst.domain.vo; - -import lombok.Data; -import java.util.Date; -import com.fasterxml.jackson.annotation.JsonFormat; -import io.swagger.annotations.ApiModelProperty; - -/** - * [ ] - * - * @author 孟凯 - * @version 1.0 - * @company 1024创新实验室( www.1024lab.net ) - * @copyright (c) 1024创新实验室( www.1024lab.net )Inc. All rights reserved. - * @date 2022-01-17 15:14:27 - * @since JDK1.8 - */ -@Data -public class HiTaskinstVO { - @ApiModelProperty("ID_") - private String id; - - @ApiModelProperty("TASK_DEF_KEY_") - private String taskDefKey; - - @ApiModelProperty("PROC_DEF_KEY_") - private String procDefKey; - - @ApiModelProperty("PROC_DEF_ID_") - private String procDefId; - - @ApiModelProperty("ROOT_PROC_INST_ID_") - private String rootProcInstId; - - @ApiModelProperty("PROC_INST_ID_") - private String procInstId; - - @ApiModelProperty("EXECUTION_ID_") - private String executionId; - - @ApiModelProperty("CASE_DEF_KEY_") - private String caseDefKey; - - @ApiModelProperty("CASE_DEF_ID_") - private String caseDefId; - - @ApiModelProperty("CASE_INST_ID_") - private String caseInstId; - - @ApiModelProperty("CASE_EXECUTION_ID_") - private String caseExecutionId; - - @ApiModelProperty("ACT_INST_ID_") - private String actInstId; - - @ApiModelProperty("NAME_") - private String name; - - @ApiModelProperty("PARENT_TASK_ID_") - private String parentTaskId; - - @ApiModelProperty("DESCRIPTION_") - private String description; - - @ApiModelProperty("OWNER_") - private String owner; - - @ApiModelProperty("ASSIGNEE_") - private String assignee; - - @ApiModelProperty("START_TIME_") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - private Date startTime; - - @ApiModelProperty("END_TIME_") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - private Date endTime; - - @ApiModelProperty("DURATION_") - private Long duration; - - @ApiModelProperty("DELETE_REASON_") - private String deleteReason; - - @ApiModelProperty("PRIORITY_") - private Integer priority; - - @ApiModelProperty("DUE_DATE_") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - private Date dueDate; - - @ApiModelProperty("FOLLOW_UP_DATE_") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - private Date followUpDate; - - @ApiModelProperty("TENANT_ID_") - private String tenantId; - - @ApiModelProperty("REMOVAL_TIME_") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - private Date removalTime; - - - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/service/HiTaskInstService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/service/HiTaskInstService.java deleted file mode 100644 index 5e24819c74..0000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/business/hi/task/inst/service/HiTaskInstService.java +++ /dev/null @@ -1,354 +0,0 @@ -package cn.iocoder.yudao.module.business.hi.task.inst.service; - -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; -import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; -import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; -import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; -import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; -import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper; -import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper; -import lombok.extern.slf4j.Slf4j; -import org.flowable.bpmn.model.*; -import org.flowable.common.engine.impl.de.odysseus.el.ExpressionFactoryImpl; -import org.flowable.common.engine.impl.de.odysseus.el.util.SimpleContext; -import org.flowable.common.engine.impl.javax.el.ExpressionFactory; -import org.flowable.common.engine.impl.javax.el.ValueExpression; -import org.flowable.engine.HistoryService; -import org.flowable.engine.RepositoryService; -import org.flowable.engine.history.HistoricProcessInstance; -import org.flowable.task.api.history.HistoricTaskInstance; -import org.flowable.variable.api.history.HistoricVariableInstance; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * [ ] - * - * @author 孟凯 - * @version 1.0 - */ -@Slf4j -@Service -public class HiTaskInstService { - - @Resource - private HistoryService historyService; - @Resource - private RepositoryService repositoryService; - @Resource - private BpmTaskAssignRuleMapper bpmTaskAssignRuleMapper; - @Resource - private BpmProcessInstanceService processInstanceService; - @Resource - private AdminUserMapper adminUserApi; - @Resource - private DeptMapper deptMapper; - - /** - * 获取任务具体流程信息 - * - * @param taskList 任务信息 - * @param approved 任意选择条件 - * - * @return 返回流程信息 - */ - @TenantIgnore - public List taskGetComment(List taskList, Object approved) { - BpmTaskExtDO task = taskList.get(taskList.size() - 1); - Map bpmTaskMap = - taskList.stream().collect(Collectors.toMap(BpmTaskExtDO::getTaskId, Function.identity())); - // 获得 ProcessInstance Map - HistoricProcessInstance procInst = - processInstanceService.getHistoricProcessInstance(task.getProcessInstanceId()); - Map userDoMap = - adminUserApi.selectList().stream().collect(Collectors.toMap(AdminUserDO::getId, Function.identity())); - Map deptMap = - deptMapper.selectList().stream().collect(Collectors.toMap(DeptDO::getId, Function.identity())); - List hisTaskInstList = - historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()) - .orderByHistoricTaskInstanceStartTime().desc().list(); - LinkedList bpmTaskRespVOList = - nowTaskFormat(procInst, hisTaskInstList, bpmTaskMap, userDoMap, deptMap); - - //ProcessInstanceId流程实例 - String procInstId = task.getProcessInstanceId(); - List tmpBpmTaskAssignRuleDOList = - bpmTaskAssignRuleMapper.selectListByProcessDefinitionId(task.getProcessDefinitionId(), null); - List hisVarInstList = - historyService.createHistoricVariableInstanceQuery().processInstanceId(procInstId).list(); - Map hisVarInstMap = new HashMap<>(); - for (HistoricVariableInstance hisVarInst : hisVarInstList) { - hisVarInstMap.put(hisVarInst.getVariableName(), hisVarInst.getValue()); - } - hisVarInstMap.put("approved", approved); - //获取bpm(模型)对象 - BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); - getFlow(bpmnModel, task.getTaskDefKey(), tmpBpmTaskAssignRuleDOList, bpmTaskRespVOList, userDoMap, deptMap, - hisVarInstMap); - return bpmTaskRespVOList; - } - - /** - * 格式化任务信息 - */ - private LinkedList nowTaskFormat(HistoricProcessInstance procInst, List taskList, - Map bpmTaskExtDoMap, Map userMap, Map deptMap) { - LinkedList bpmTaskRespVOList = new LinkedList<>(); - for (HistoricTaskInstance hisTaskInst : taskList) { - BpmTaskRespVO respVO = initRespVo(hisTaskInst, bpmTaskExtDoMap, procInst, userMap); - AdminUserDO user = userMap.get(Long.valueOf(hisTaskInst.getAssignee())); - if (BeanUtil.isNotEmpty(user)) { - respVO.setAssigneeUser(setUser(user)); - DeptDO dept = deptMap.get(user.getDeptId()); - if (BeanUtil.isNotEmpty(dept)) { - respVO.getAssigneeUser().setDeptName(dept.getName()); - } - } - bpmTaskRespVOList.addFirst(respVO); - } - return bpmTaskRespVOList; - } - - private BpmTaskRespVO initRespVo(Object taskInst, Map bpmTaskExtDoMap, - HistoricProcessInstance procInst, Map userMap) { - BpmTaskRespVO respVO = new BpmTaskRespVO(); - if (taskInst instanceof HistoricTaskInstance) { - respVO = setBpmnTaskRespVo((HistoricTaskInstance)taskInst); - BeanUtil.copyProperties(taskInst, respVO); - BpmTaskExtDO bpmTaskExtDO = bpmTaskExtDoMap.get(respVO.getId()); - if (ObjectUtil.isNotEmpty(bpmTaskExtDO)) { - BeanUtil.copyProperties(bpmTaskExtDO, respVO); - respVO.setId(bpmTaskExtDO.getTaskId()); - } - } - if (taskInst instanceof BpmTaskExtDO) { - respVO = setBpmnTaskRespVo((BpmTaskExtDO)taskInst); - BeanUtil.copyProperties(taskInst, respVO); - } - // copyTo(bpmTaskExtDO, respVO); - if (procInst != null) { - AdminUserDO startUser = userMap.get(Long.valueOf(procInst.getStartUserId())); - if (BeanUtil.isEmpty(startUser)) { - throw new RuntimeException("查找不到审批用户!!!"); - } - respVO.setProcessInstance(setProcInst(procInst, startUser)); - } - return respVO; - } - - private BpmTaskRespVO.User setUser(AdminUserDO bean) { - if (bean == null) { - return null; - } - - BpmTaskRespVO.User user = new BpmTaskRespVO.User(); - - user.setId(bean.getId()); - user.setNickname(bean.getNickname()); - user.setDeptId(bean.getDeptId()); - - return user; - - } - - private BpmTaskRespVO setBpmnTaskRespVo(BpmTaskExtDO bean) { - if (bean == null) { - return null; - } - - BpmTaskRespVO bpmTaskRespVO = new BpmTaskRespVO(); - - bpmTaskRespVO.setDefinitionKey(bean.getTaskDefKey()); - bpmTaskRespVO.setId(bean.getTaskId()); - bpmTaskRespVO.setName(bean.getName()); - bpmTaskRespVO.setCreateTime(bean.getCreateTime()); - - return bpmTaskRespVO; - } - - public BpmTaskRespVO setBpmnTaskRespVo(HistoricTaskInstance bean) { - if (bean == null) { - return null; - } - - BpmTaskRespVO bpmTaskRespVO = new BpmTaskRespVO(); - - bpmTaskRespVO.setDefinitionKey(bean.getTaskDefinitionKey()); - bpmTaskRespVO.setId(bean.getId()); - bpmTaskRespVO.setName(bean.getName()); - bpmTaskRespVO.setClaimTime(bean.getClaimTime()); - bpmTaskRespVO.setCreateTime(bean.getCreateTime()); - bpmTaskRespVO.setEndTime(bean.getEndTime()); - bpmTaskRespVO.setDurationInMillis(bean.getDurationInMillis()); - - return bpmTaskRespVO; - } - - public BpmTaskTodoPageItemRespVO.ProcessInstance setProcInst(HistoricProcessInstance processInstance, - AdminUserDO startUser) { - if (processInstance == null && startUser == null) { - return null; - } - - BpmTaskTodoPageItemRespVO.ProcessInstance processInstanceResult = - new BpmTaskTodoPageItemRespVO.ProcessInstance(); - - if (processInstance != null) { - processInstanceResult.setId(processInstance.getId()); - processInstanceResult.setName(processInstance.getName()); - if (processInstance.getStartUserId() != null) { - processInstanceResult.setStartUserId(Long.parseLong(processInstance.getStartUserId())); - } - processInstanceResult.setProcessDefinitionId(processInstance.getProcessDefinitionId()); - } - if (startUser != null) { - processInstanceResult.setStartUserNickname(startUser.getNickname()); - } - - return processInstanceResult; - } - - private void getFlow(BpmnModel bpmnModel, String taskDefKey, List tmpBpmTaskAssignRuleDOList, - LinkedList bpmTaskRespVOList, Map userDoMap, Map deptMap, - Map taskVarMap) { - //传节点定义key获取当前节点 - FlowNode flowNode = (FlowNode)bpmnModel.getFlowElement(taskDefKey); - //输出连线 - List outgoingFlows = flowNode.getOutgoingFlows(); - //遍历返回下一个节点信息 - for (SequenceFlow outgoingFlow : outgoingFlows) { - //类型自己判断(获取下个节点是网关还是节点) - FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement(); - getFlow(bpmnModel, targetFlowElement, tmpBpmTaskAssignRuleDOList, bpmTaskRespVOList, userDoMap, deptMap, - taskVarMap); - } - } - - private void getFlow(BpmnModel bpmnModel, FlowElement targetFlowElement, - List tmpBpmTaskAssignRuleDOList, LinkedList bpmTaskRespVOList, - Map userDoMap, Map deptMap, Map taskVarMap) { - // 下一个taskDefKey - String nextTaskDefKey = null; - //下个是节点 - if (targetFlowElement instanceof UserTask) { - // 判断是否是为并行任务 - List bpmTaskAssignRuleDOList = tmpBpmTaskAssignRuleDOList.stream().filter( - bpmTaskAssignRuleDO -> bpmTaskAssignRuleDO.getTaskDefinitionKey().equals(targetFlowElement.getId())) - .collect(Collectors.toList()); - if (CollUtil.isEmpty(bpmTaskAssignRuleDOList)) { - throw new RuntimeException("任务key不存在!!!"); - } - for (BpmTaskAssignRuleDO bpmTaskAssignRuleDO : bpmTaskAssignRuleDOList) { - nextTaskDefKey = bpmTaskAssignRuleDO.getTaskDefinitionKey(); - for (Long userId : bpmTaskAssignRuleDO.getOptions()) { - BpmTaskRespVO bpmTaskRespVO = - (BpmTaskRespVO)new BpmTaskRespVO().setName(targetFlowElement.getName()); - bpmTaskRespVOList.addLast(bpmTaskRespVO); - AdminUserDO adminUserDO = userDoMap.get(userId); - DeptDO deptDO = deptMap.get(adminUserDO.getDeptId()); - bpmTaskRespVO.setAssigneeUser(setUser(adminUserDO)); - bpmTaskRespVO.getAssigneeUser().setDeptName(deptDO.getName()); - // edit by 芋艿 TODO -// if (!bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType()) -// && !bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType())) { -// break; -// } - } - } - getFlow(bpmnModel, nextTaskDefKey, tmpBpmTaskAssignRuleDOList, bpmTaskRespVOList, userDoMap, deptMap, - taskVarMap); - // 下个节点是网关(调用下面的方法) - } else if (targetFlowElement instanceof ExclusiveGateway) { - String defaultFlow = ((ExclusiveGateway)targetFlowElement).getDefaultFlow(); - FlowElement nexFlowElement = getExclusiveGateway(targetFlowElement, taskVarMap, defaultFlow); - getFlow(bpmnModel, nexFlowElement, tmpBpmTaskAssignRuleDOList, bpmTaskRespVOList, userDoMap, deptMap, - taskVarMap); - } - } - - /** - * 获取排他网关分支名称、分支表达式、下一级任务节点 - * - * @param flowElement 任务节点 - * @param taskVarMap 审批数据 - */ - private FlowElement getExclusiveGateway(FlowElement flowElement, Map taskVarMap, - String defaultFlow) { - // 获取所有网关分支 - List targetFlows = ((ExclusiveGateway)flowElement).getOutgoingFlows(); - Boolean elExpressionFlag = Boolean.FALSE; - FlowElement sequenceFlowResult = null; - FlowElement defaultSequenceFlow = null; - // 循环每个网关分支 - for (SequenceFlow sequenceFlow : targetFlows) { - if (defaultFlow.equals(sequenceFlow.getId())) { - defaultSequenceFlow = sequenceFlow.getTargetFlowElement(); - continue; - } - elExpressionFlag = elExpression(sequenceFlow.getConditionExpression(), taskVarMap); - if (elExpressionFlag) { - // 获取下一个网关和节点数据 - FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement(); - // 网关的下个节点是用户节点 - if (targetFlowElement instanceof UserTask) { - sequenceFlowResult = targetFlowElement; - break; - } else if (targetFlowElement instanceof EndEvent) { - log.info("排他网关的下一节点是EndEvent: 结束节点"); - } else if (targetFlowElement instanceof ServiceTask) { - log.info("排他网关的下一节点是ServiceTask: 内部方法"); - } else if (targetFlowElement instanceof ExclusiveGateway) { - defaultFlow = ((ExclusiveGateway)targetFlowElement).getDefaultFlow(); - return getExclusiveGateway(targetFlowElement, taskVarMap, defaultFlow); - } else if (targetFlowElement instanceof SubProcess) { - log.info("排他网关的下一节点是SubProcess: 内部子流程"); - } - } - } - if (!elExpressionFlag) { - if (defaultSequenceFlow instanceof UserTask) { - sequenceFlowResult = defaultSequenceFlow; - } else if (defaultSequenceFlow instanceof ExclusiveGateway) { - defaultFlow = ((ExclusiveGateway)defaultSequenceFlow).getDefaultFlow(); - return getExclusiveGateway(defaultSequenceFlow, taskVarMap, defaultFlow); - } - } - return sequenceFlowResult; - } - - /** - * 网关分叉条件判断,网关分叉,必须要有默认出口 - * - * @param elExpression el表达式 - * @param variableMap 流程所有变量 - * - * @return 返回true或false - */ - private Boolean elExpression(String elExpression, Map variableMap) { - ExpressionFactory factory = new ExpressionFactoryImpl(); - SimpleContext context = new SimpleContext(); - for (String k : variableMap.keySet()) { - if (variableMap.get(k) != null) { - context.setVariable(k, - factory.createValueExpression(variableMap.get(k), variableMap.get(k).getClass())); - } - } - ValueExpression e = factory.createValueExpression(context, elExpression, Boolean.class); - //el表达式和variables得到的结果 - return (Boolean)e.getValue(context); - } -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/BpmActivityMapper.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/BpmActivityMapper.xml index 37ae2a225f..f17c04750e 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/BpmActivityMapper.xml +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/BpmActivityMapper.xml @@ -17,11 +17,6 @@ - -