From f1208474f771a1c233d7425c8ed13fbaa0d521ac Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期三, 12 三月 2025 09:35:13 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/5.X' into 5.X --- ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java | 687 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 687 insertions(+), 0 deletions(-) diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java new file mode 100644 index 0000000..21a54d7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -0,0 +1,687 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.*; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.service.*; +import org.dromara.warm.flow.orm.entity.*; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskAssigneeType; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.handler.WorkflowPermissionHandler; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.mapper.FlwTaskMapper; +import org.dromara.workflow.service.IFlwTaskService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 浠诲姟 鏈嶅姟灞傚疄鐜� + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwTaskServiceImpl implements IFlwTaskService { + + private final TaskService taskService; + private final InsService insService; + private final DefService defService; + private final HisTaskService hisTaskService; + private final NodeService nodeService; + private final FlowInstanceMapper flowInstanceMapper; + private final FlowTaskMapper flowTaskMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final IdentifierGenerator identifierGenerator; + private final FlowProcessEventHandler flowProcessEventHandler; + private final UserService userService; + private final FlwTaskMapper flwTaskMapper; + private final FlwCategoryMapper flwCategoryMapper; + + /** + * 鍚姩浠诲姟 + * + * @param startProcessBo 鍚姩娴佺▼鍙傛暟 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) { + String businessId = startProcessBo.getBusinessId(); + if (StringUtils.isBlank(businessId)) { + throw new ServiceException("鍚姩宸ヤ綔娴佹椂蹇呴』鍖呭惈涓氬姟ID"); + } + // 鍚姩娴佺▼瀹炰緥锛堟彁浜ょ敵璇凤級 + Map<String, Object> variables = startProcessBo.getVariables(); + // 娴佺▼鍙戣捣浜� + variables.put(INITIATOR, LoginHelper.getUserIdStr()); + // 涓氬姟id + variables.put(BUSINESS_ID, businessId); + FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class) + .eq(FlowInstance::getBusinessId, businessId)); + if (ObjectUtil.isNotNull(flowInstance)) { + BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus()); + List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId())); + StartProcessReturnDTO dto = new StartProcessReturnDTO(); + dto.setProcessInstanceId(taskList.get(0).getInstanceId()); + dto.setTaskId(taskList.get(0).getId()); + return dto; + } + FlowParams flowParams = new FlowParams(); + flowParams.flowCode(startProcessBo.getFlowCode()); + flowParams.variable(startProcessBo.getVariables()); + flowParams.flowStatus(BusinessStatusEnum.DRAFT.getStatus()); + Instance instance; + try { + instance = insService.start(businessId, flowParams); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + // 鐢宠浜烘墽琛屾祦绋� + List<Task> taskList = taskService.list(new FlowTask().setInstanceId(instance.getId())); + if (taskList.size() > 1) { + throw new ServiceException("璇锋鏌ユ祦绋嬬涓�涓幆鑺傛槸鍚︿负鐢宠浜猴紒"); + } + StartProcessReturnDTO dto = new StartProcessReturnDTO(); + dto.setProcessInstanceId(instance.getId()); + dto.setTaskId(taskList.get(0).getId()); + return dto; + } + + /** + * 鍔炵悊浠诲姟 + * + * @param completeTaskBo 鍔炵悊浠诲姟鍙傛暟 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean completeTask(CompleteTaskBo completeTaskBo) { + try { + // 鑾峰彇浠诲姟ID骞舵煡璇㈠搴旂殑娴佺▼浠诲姟鍜屽疄渚嬩俊鎭� + Long taskId = completeTaskBo.getTaskId(); + List<String> messageType = completeTaskBo.getMessageType(); + String notice = completeTaskBo.getNotice(); + // 鑾峰彇鎶勯�佷汉 + List<FlowCopyBo> flowCopyList = completeTaskBo.getFlowCopyList(); + FlowTask flowTask = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(flowTask)) { + throw new ServiceException("娴佺▼浠诲姟涓嶅瓨鍦ㄦ垨浠诲姟宸插鎵癸紒"); + } + Instance ins = insService.getById(flowTask.getInstanceId()); + // 鑾峰彇娴佺▼瀹氫箟淇℃伅 + Definition definition = defService.getById(flowTask.getDefinitionId()); + // 妫�鏌ユ祦绋嬬姸鎬佹槸鍚︿负鑽夌銆佸凡鎾ら攢鎴栧凡閫�鍥炵姸鎬侊紝鑻ユ槸鍒欐墽琛屾祦绋嬫彁浜ょ洃鍚� + if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { + flowProcessEventHandler.processHandler(definition.getFlowCode(), ins.getBusinessId(), ins.getFlowStatus(), null, true); + } + // 鏋勫缓娴佺▼鍙傛暟锛屽寘鎷彉閲忋�佽烦杞被鍨嬨�佹秷鎭�佸鐞嗕汉銆佹潈闄愮瓑淇℃伅 + FlowParams flowParams = new FlowParams(); + flowParams.variable(completeTaskBo.getVariables()); + flowParams.skipType(SkipType.PASS.getKey()); + flowParams.message(completeTaskBo.getMessage()); + flowParams.flowStatus(BusinessStatusEnum.WAITING.getStatus()).hisStatus(TaskStatusEnum.PASS.getStatus()); + + flowParams.hisTaskExt(completeTaskBo.getFileId()); + // 鎵ц浠诲姟璺宠浆锛屽苟鏍规嵁杩斿洖鐨勫鐞嗕汉璁剧疆涓嬩竴姝ュ鐞嗕汉 + Instance instance = taskService.skip(taskId, flowParams); + this.setHandler(instance, flowTask, flowCopyList); + // 娑堟伅閫氱煡 + WorkflowUtils.sendMessage(definition.getFlowName(), ins.getId(), messageType, notice); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 璁剧疆鍔炵悊浜� + * + * @param instance 瀹炰緥 + * @param task (褰撳墠浠诲姟)鏈姙鐞嗙殑浠诲姟 + * @param flowCopyList 鎶勯�佷汉 + */ + private void setHandler(Instance instance, FlowTask task, List<FlowCopyBo> flowCopyList) { + if (ObjectUtil.isNull(instance)) { + return; + } + // 娣诲姞鎶勯�佷汉 + this.setCopy(task, flowCopyList); + // 鏍规嵁娴佺▼瀹炰緥ID鏌ヨ鎵�鏈夊叧鑱旂殑浠诲姟 + List<FlowTask> flowTasks = this.selectByInstId(instance.getId()); + if (CollUtil.isEmpty(flowTasks)) { + return; + } + List<Long> taskIdList = StreamUtils.toList(flowTasks, FlowTask::getId); + // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃 + List<User> associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList); + if (CollUtil.isEmpty(associatedUsers)) { + return; + } + List<User> userList = new ArrayList<>(); + // 閬嶅巻浠诲姟鍒楄〃锛屽鐞嗘瘡涓换鍔$殑鍔炵悊浜� + for (FlowTask flowTask : flowTasks) { + List<User> users = StreamUtils.filter(associatedUsers, user -> Objects.equals(user.getAssociated(), flowTask.getId())); + if (CollUtil.isNotEmpty(users)) { + userList.addAll(WorkflowUtils.buildUser(users, flowTask.getId())); + } + } + // 鎵归噺鍒犻櫎鐜版湁浠诲姟鐨勫姙鐞嗕汉璁板綍 + WorkflowUtils.getFlowUserService().deleteByTaskIds(taskIdList); + // 纭繚瑕佷繚瀛樼殑 userList 涓嶄负绌� + if (CollUtil.isEmpty(userList)) { + return; + } + WorkflowUtils.getFlowUserService().saveBatch(userList); + } + + /** + * 娣诲姞鎶勯�佷汉 + * + * @param task 浠诲姟淇℃伅 + * @param flowCopyList 鎶勯�佷汉 + */ + public void setCopy(FlowTask task, List<FlowCopyBo> flowCopyList) { + if (CollUtil.isEmpty(flowCopyList)) { + return; + } + // 娣诲姞鎶勯�佷汉璁板綍 + FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0); + FlowNode flowNode = new FlowNode(); + flowNode.setNodeCode(flowHisTask.getTargetNodeCode()); + flowNode.setNodeName(flowHisTask.getTargetNodeName()); + //鐢熸垚鏂扮殑浠诲姟id + long taskId = identifierGenerator.nextId(null).longValue(); + task.setId(taskId); + task.setNodeName("銆愭妱閫併��" + task.getNodeName()); + Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000); + FlowParams flowParams = FlowParams.build(); + flowParams.skipType(SkipType.NONE.getKey()); + flowParams.hisStatus(TaskStatusEnum.COPY.getStatus()); + flowParams.message("銆愭妱閫佺粰銆�" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName)); + HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams); + hisTask.setCreateTime(updateTime); + hisTask.setUpdateTime(updateTime); + hisTaskService.save(hisTask); + List<User> userList = flowCopyList.stream() + .map(flowCopy -> { + FlowUser flowUser = new FlowUser(); + flowUser.setType(TaskAssigneeType.COPY.getCode()); + flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId())); + flowUser.setAssociated(taskId); + return flowUser; + }).collect(Collectors.toList()); + // 鎵归噺淇濆瓨鎶勯�佷汉鍛� + WorkflowUtils.getFlowUserService().saveBatch(userList); + } + + /** + * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫緟鍔炰换鍔� + * + * @param flowTaskBo 鍙傛暟 + * @param pageQuery 鍒嗛〉 + */ + @Override + public TableDataInfo<FlowTaskVo> pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + queryWrapper.in("t.processed_by", SpringUtils.getBean(WorkflowPermissionHandler.class).permissions()); + queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus()); + Page<FlowTaskVo> page = this.getFlowTaskVoPage(pageQuery, queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 鏌ヨ褰撳墠鐢ㄦ埛鐨勫凡鍔炰换鍔� + * + * @param flowTaskBo 鍙傛暟 + * @param pageQuery 鍒嗛〉 + */ + @Override + public TableDataInfo<FlowHisTaskVo> pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + queryWrapper.in("t.approver", LoginHelper.getUserIdStr()); + queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time"); + Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 鏌ヨ寰呭姙浠诲姟 + * + * @param flowTaskBo 鍙傛暟 + * @param pageQuery 鍒嗛〉 + */ + @Override + public TableDataInfo<FlowTaskVo> pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + Page<FlowTaskVo> page = getFlowTaskVoPage(pageQuery, queryWrapper); + return TableDataInfo.build(page); + } + + private Page<FlowTaskVo> getFlowTaskVoPage(PageQuery pageQuery, QueryWrapper<FlowTaskBo> queryWrapper) { + Page<FlowTaskVo> page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper); + List<FlowTaskVo> records = page.getRecords(); + if (CollUtil.isNotEmpty(records)) { + List<Long> taskIds = StreamUtils.toList(records, FlowTaskVo::getId); + Map<Long, List<UserDTO>> listMap = currentTaskAllUser(taskIds); + records.forEach(t -> { + List<UserDTO> userList = listMap.getOrDefault(t.getId(), Collections.emptyList()); + if (CollUtil.isNotEmpty(userList)) { + t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId()))); + t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName)); + } + }); + } + return page; + } + + /** + * 鏌ヨ宸插姙浠诲姟 + * + * @param flowTaskBo 鍙傛暟 + * @param pageQuery 鍒嗛〉 + */ + @Override + public TableDataInfo<FlowHisTaskVo> pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo); + Page<FlowHisTaskVo> page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 鏌ヨ褰撳墠鐢ㄦ埛鐨勬妱閫� + * + * @param flowTaskBo 鍙傛暟 + * @param pageQuery 鍒嗛〉 + */ + @Override + public TableDataInfo<FlowTaskVo> pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper<FlowTaskBo> queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr()); + Page<FlowTaskVo> page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + private QueryWrapper<FlowTaskBo> buildQueryWrapper(FlowTaskBo flowTaskBo) { + QueryWrapper<FlowTaskBo> wrapper = Wrappers.query(); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getNodeName()), "t.node_name", flowTaskBo.getNodeName()); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowName()), "t.flow_name", flowTaskBo.getFlowName()); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode()); + wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds()); + if (StringUtils.isNotBlank(flowTaskBo.getCategory())) { + List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory())); + wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr)); + } + wrapper.orderByDesc("t.create_time"); + return wrapper; + } + + /** + * 椹冲洖浠诲姟 + * + * @param bo 鍙傛暟 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean backProcess(BackProcessBo bo) { + try { + Long taskId = bo.getTaskId(); + String notice = bo.getNotice(); + List<String> messageType = bo.getMessageType(); + String message = bo.getMessage(); + FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("浠诲姟涓嶅瓨鍦紒"); + } + Instance inst = insService.getById(task.getInstanceId()); + BusinessStatusEnum.checkBackStatus(inst.getFlowStatus()); + Long definitionId = task.getDefinitionId(); + Definition definition = defService.getById(definitionId); + String applyNodeCode = WorkflowUtils.applyNodeCode(definitionId); + FlowParams flowParams = FlowParams.build(); + flowParams.nodeCode(bo.getNodeCode()); + flowParams.message(message); + flowParams.skipType(SkipType.REJECT.getKey()); + flowParams.flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.BACK.getStatus()); + flowParams.hisTaskExt(bo.getFileId()); + taskService.skip(task.getId(), flowParams); + + Instance instance = insService.getById(inst.getId()); + this.setHandler(instance, task, null); + // 娑堟伅閫氱煡 + WorkflowUtils.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣 + * + * @param definitionId 娴佺▼瀹氫箟id + * @param nowNodeCode 褰撳墠鑺傜偣 + */ + @Override + public List<Node> getBackTaskNode(Long definitionId, String nowNodeCode) { + List<Node> nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId); + if (!CollUtil.isNotEmpty(nodeCodes)) { + return nodeCodes; + } + //鍒ゆ柇鏄惁閰嶇疆浜嗗浐瀹氶┏鍥炶妭鐐� + Node node = nodeCodes.get(0); + if (StringUtils.isNotBlank(node.getAnyNodeSkip())) { + return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId); + } + //鑾峰彇鍙┏鍥炵殑鍓嶇疆鑺傜偣 + List<Node> nodes = nodeService.previousNodeList(definitionId, nowNodeCode); + if (CollUtil.isNotEmpty(nodes)) { + return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType())); + } + return nodes; + } + + /** + * 缁堟浠诲姟 + * + * @param bo 鍙傛暟 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean terminationTask(FlowTerminationBo bo) { + try { + Long taskId = bo.getTaskId(); + Task task = taskService.getById(taskId); + if (task == null) { + throw new ServiceException("浠诲姟涓嶅瓨鍦紒"); + } + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNotNull(instance)) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + FlowParams flowParams = new FlowParams(); + flowParams.message(bo.getComment()); + flowParams.flowStatus(BusinessStatusEnum.TERMINATION.getStatus()) + .hisStatus(TaskStatusEnum.TERMINATION.getStatus()); + taskService.termination(taskId, flowParams); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 鎸夌収浠诲姟id鏌ヨ浠诲姟 + * + * @param taskIdList 浠诲姟id + */ + @Override + public List<FlowTask> selectByIdList(List<Long> taskIdList) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .in(FlowTask::getId, taskIdList)); + } + + /** + * 鎸夌収浠诲姟id鏌ヨ浠诲姟 + * + * @param taskId 浠诲姟id + */ + @Override + public FlowTaskVo selectById(Long taskId) { + Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + return null; + } + FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class); + Instance instance = insService.getById(task.getInstanceId()); + Definition definition = defService.getById(task.getDefinitionId()); + flowTaskVo.setFlowStatus(instance.getFlowStatus()); + flowTaskVo.setVersion(definition.getVersion()); + flowTaskVo.setFlowCode(definition.getFlowCode()); + flowTaskVo.setFlowName(definition.getFlowName()); + flowTaskVo.setBusinessId(instance.getBusinessId()); + List<Node> nodeList = nodeService.getByNodeCodes(Collections.singletonList(flowTaskVo.getNodeCode()), instance.getDefinitionId()); + if (CollUtil.isNotEmpty(nodeList)) { + Node node = nodeList.get(0); + flowTaskVo.setNodeRatio(node.getNodeRatio()); + } + return flowTaskVo; + } + + /** + * 鎸夌収浠诲姟id鏌ヨ浠诲姟 + * + * @param taskIdList 浠诲姟id + * @return 缁撴灉 + */ + @Override + public List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList) { + return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class) + .in(FlowHisTask::getId, taskIdList)); + } + + /** + * 鎸夌収浠诲姟id鏌ヨ浠诲姟 + * + * @param taskId 浠诲姟id + * @return 缁撴灉 + */ + @Override + public FlowHisTask selectHisTaskById(Long taskId) { + return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class) + .eq(FlowHisTask::getId, taskId)); + } + + /** + * 鎸夌収瀹炰緥id鏌ヨ浠诲姟 + * + * @param instanceIdList 娴佺▼瀹炰緥id + */ + @Override + public List<FlowTask> selectByInstIdList(List<Long> instanceIdList) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .in(FlowTask::getInstanceId, instanceIdList)); + } + + /** + * 鎸夌収瀹炰緥id鏌ヨ浠诲姟 + * + * @param instanceId 娴佺▼瀹炰緥id + */ + @Override + public List<FlowTask> selectByInstId(Long instanceId) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .eq(FlowTask::getInstanceId, instanceId)); + } + + /** + * 浠诲姟鎿嶄綔 + * + * @param bo 鍙傛暟 + * @param taskOperation 鎿嶄綔绫诲瀷锛屽娲� delegateTask銆佽浆鍔� transferTask銆佸姞绛� addSignature銆佸噺绛� reductionSignature + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean taskOperation(TaskOperationBo bo, String taskOperation) { + FlowParams flowParams = new FlowParams(); + flowParams.message(bo.getMessage()); + if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { + flowParams.ignore(true); + } + + // 鏍规嵁鎿嶄綔绫诲瀷鏋勫缓 FlowParams + switch (taskOperation) { + case DELEGATE_TASK, TRANSFER_TASK -> { + ValidatorUtils.validate(bo, AddGroup.class); + flowParams.addHandlers(Collections.singletonList(bo.getUserId())); + } + case ADD_SIGNATURE -> { + ValidatorUtils.validate(bo, EditGroup.class); + flowParams.addHandlers(bo.getUserIds()); + } + case REDUCTION_SIGNATURE -> { + ValidatorUtils.validate(bo, EditGroup.class); + flowParams.reductionHandlers(bo.getUserIds()); + } + default -> { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + } + + Long taskId = bo.getTaskId(); + FlowTaskVo flowTaskVo = selectById(taskId); + if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) { + if (flowTaskVo.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) { + throw new ServiceException(flowTaskVo.getNodeName() + "涓嶆槸浼氱鑺傜偣锛�"); + } + } + // 璁剧疆浠诲姟鐘舵�佸苟鎵ц瀵瑰簲鐨勪换鍔℃搷浣� + switch (taskOperation) { + //濮旀淳浠诲姟 + case DELEGATE_TASK -> { + flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus()); + return taskService.depute(taskId, flowParams); + } + //杞姙浠诲姟 + case TRANSFER_TASK -> { + flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus()); + return taskService.transfer(taskId, flowParams); + } + //鍔犵锛屽鍔犲姙鐞嗕汉 + case ADD_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus()); + return taskService.addSignature(taskId, flowParams); + } + //鍑忕锛屽噺灏戝姙鐞嗕汉 + case REDUCTION_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); + return taskService.reductionSignature(taskId, flowParams); + } + default -> { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + } + } + + /** + * 淇敼浠诲姟鍔炵悊浜猴紙姝ゆ柟娉曞皢浼氭壒閲忎慨鏀规墍鏈変换鍔$殑鍔炵悊浜猴級 + * + * @param taskIdList 浠诲姟id + * @param userId 鐢ㄦ埛id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateAssignee(List<Long> taskIdList, String userId) { + if (CollUtil.isEmpty(taskIdList)) { + return false; + } + try { + List<FlowTask> flowTasks = this.selectByIdList(taskIdList); + // 鎵归噺鍒犻櫎鐜版湁浠诲姟鐨勫姙鐞嗕汉璁板綍 + if (CollUtil.isNotEmpty(flowTasks)) { + WorkflowUtils.getFlowUserService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); + List<User> userList = flowTasks.stream() + .map(flowTask -> { + FlowUser flowUser = new FlowUser(); + flowUser.setType(TaskAssigneeType.APPROVER.getCode()); + flowUser.setProcessedBy(userId); + flowUser.setAssociated(flowTask.getId()); + return flowUser; + }) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(userList)) { + WorkflowUtils.getFlowUserService().saveBatch(userList); + } + } + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + return true; + } + + /** + * 鑾峰彇浠诲姟鎵�鏈夊姙鐞嗕汉 + * + * @param taskIdList 浠诲姟id + */ + @Override + public Map<Long, List<UserDTO>> currentTaskAllUser(List<Long> taskIdList) { + Map<Long, List<UserDTO>> map = new HashMap<>(); + // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃 + List<User> associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList); + Map<Long, List<User>> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated); + for (Map.Entry<Long, List<User>> entry : listMap.entrySet()) { + List<User> value = entry.getValue(); + if (CollUtil.isNotEmpty(value)) { + List<UserDTO> userDTOS = userService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy()))); + map.put(entry.getKey(), userDTOS); + } + } + return map; + } + + /** + * 鑾峰彇褰撳墠浠诲姟鐨勬墍鏈夊姙鐞嗕汉 + * + * @param taskId 浠诲姟id + */ + @Override + public List<UserDTO> currentTaskAllUser(Long taskId) { + // 鑾峰彇涓庡綋鍓嶄换鍔″叧鑱旂殑鐢ㄦ埛鍒楄〃 + List<User> userList = WorkflowUtils.getFlowUserService().getByAssociateds(Collections.singletonList(taskId)); + if (CollUtil.isEmpty(userList)) { + return Collections.emptyList(); + } + return userService.selectListByIds(StreamUtils.toList(userList, e -> Long.valueOf(e.getProcessedBy()))); + } +} -- Gitblit v1.9.3