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.lang.Dict; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.lock.annotation.Lock4j; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 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.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.json.utils.JsonUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.utils.IdGeneratorUtil; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.warm.flow.core.FlowEngine; import org.dromara.warm.flow.core.dto.FlowParams; import org.dromara.warm.flow.core.entity.*; import org.dromara.warm.flow.core.enums.CooperateType; import org.dromara.warm.flow.core.enums.NodeType; import org.dromara.warm.flow.core.enums.SkipType; import org.dromara.warm.flow.core.enums.UserType; import org.dromara.warm.flow.core.service.*; import org.dromara.warm.flow.core.utils.ExpressionUtil; import org.dromara.warm.flow.core.utils.MapUtil; 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.FlowNodeMapper; import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; import org.dromara.workflow.common.ConditionalOnEnable; import org.dromara.workflow.common.constant.FlowConstant; import org.dromara.workflow.common.enums.TaskAssigneeType; import org.dromara.workflow.common.enums.TaskStatusEnum; import org.dromara.workflow.domain.FlowInstanceBizExt; import org.dromara.workflow.domain.bo.*; import org.dromara.workflow.domain.vo.FlowCopyVo; import org.dromara.workflow.domain.vo.FlowHisTaskVo; import org.dromara.workflow.domain.vo.FlowTaskVo; import org.dromara.workflow.domain.vo.NodeExtVo; import org.dromara.workflow.mapper.FlwCategoryMapper; import org.dromara.workflow.mapper.FlwInstanceBizExtMapper; import org.dromara.workflow.mapper.FlwTaskMapper; import org.dromara.workflow.service.IFlwCommonService; import org.dromara.workflow.service.IFlwNodeExtService; import org.dromara.workflow.service.IFlwTaskAssigneeService; import org.dromara.workflow.service.IFlwTaskService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; 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 UserService userService; private final FlwTaskMapper flwTaskMapper; private final FlwCategoryMapper flwCategoryMapper; private final FlowNodeMapper flowNodeMapper; private final IFlwTaskAssigneeService flwTaskAssigneeService; private final IFlwCommonService flwCommonService; private final IFlwNodeExtService flwNodeExtService; private final FlwInstanceBizExtMapper flwInstanceBizExtMapper; /** * 启动任务 * * @param startProcessBo 启动流程参数 */ @Override @Transactional(rollbackFor = Exception.class) @Lock4j(keys = {"#startProcessBo.flowCode + #startProcessBo.businessId"}) public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) { String businessId = startProcessBo.getBusinessId(); if (StringUtils.isBlank(businessId)) { throw new ServiceException("启动工作流时必须包含业务ID"); } // 启动流程实例(提交申请) Map variables = startProcessBo.getVariables(); // 流程发起人 variables.put(INITIATOR, LoginHelper.getUserIdStr()); // 发起人部门id variables.put(INITIATOR_DEPT_ID, LoginHelper.getDeptId()); // 业务id variables.put(BUSINESS_ID, businessId); FlowInstanceBizExt bizExt = startProcessBo.getBizExt(); // 获取已有流程实例 FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class) .eq(FlowInstance::getBusinessId, businessId)); if (ObjectUtil.isNotNull(flowInstance)) { // 已存在流程 BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus()); List taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId())); taskService.mergeVariable(flowInstance, variables); insService.updateById(flowInstance); StartProcessReturnDTO dto = new StartProcessReturnDTO(); dto.setProcessInstanceId(taskList.get(0).getInstanceId()); dto.setTaskId(taskList.get(0).getId()); // 保存流程实例业务信息 this.buildFlowInstanceBizExt(flowInstance, bizExt); return dto; } // 将流程定义内的扩展参数设置到变量中 Definition definition = FlowEngine.defService().getPublishByFlowCode(startProcessBo.getFlowCode()); if (ObjectUtil.isNull(definition)) { throw new ServiceException("流程【" + startProcessBo.getFlowCode() + "】未发布,请先在流程设计器中发布流程定义"); } Dict dict = JsonUtils.parseMap(definition.getExt()); boolean autoPass = !ObjectUtil.isNull(dict) && dict.getBool(FlowConstant.AUTO_PASS); variables.put(FlowConstant.AUTO_PASS, autoPass); variables.put(FlowConstant.BUSINESS_CODE, this.generateBusinessCode(bizExt)); FlowParams flowParams = FlowParams.build() .handler(startProcessBo.getHandler()) .flowCode(startProcessBo.getFlowCode()) .variable(startProcessBo.getVariables()) .flowStatus(BusinessStatusEnum.DRAFT.getStatus()); Instance instance = insService.start(businessId, flowParams); // 保存流程实例业务信息 this.buildFlowInstanceBizExt(instance, bizExt); // 申请人执行流程 List 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; } /** * 生成业务编号,如果已有则直接返回已有值 */ private String generateBusinessCode(FlowInstanceBizExt bizExt) { if (StringUtils.isBlank(bizExt.getBusinessCode())) { // TODO: 按照自己业务规则生成编号 String businessCode = Convert.toStr(System.currentTimeMillis()); bizExt.setBusinessCode(businessCode); return businessCode; } return bizExt.getBusinessCode(); } /** * 构建流程实例业务信息 * * @param instance 流程实例 * @param bizExt 流程业务扩展信息 */ private void buildFlowInstanceBizExt(Instance instance, FlowInstanceBizExt bizExt) { bizExt.setInstanceId(instance.getId()); bizExt.setBusinessId(instance.getBusinessId()); flwInstanceBizExtMapper.saveOrUpdateByInstanceId(bizExt); } /** * 办理任务 * * @param completeTaskBo 办理任务参数 */ @Override @Transactional(rollbackFor = Exception.class) @Lock4j(keys = {"#completeTaskBo.taskId"}) public boolean completeTask(CompleteTaskBo completeTaskBo) { // 获取任务ID并查询对应的流程任务和实例信息 Long taskId = completeTaskBo.getTaskId(); List messageType = completeTaskBo.getMessageType(); String notice = completeTaskBo.getNotice(); // 获取抄送人 List flowCopyList = completeTaskBo.getFlowCopyList(); // 设置抄送人 Map variables = completeTaskBo.getVariables(); variables.put(FlowConstant.FLOW_COPY_LIST, flowCopyList); // 消息类型 variables.put(FlowConstant.MESSAGE_TYPE, messageType); // 消息通知 variables.put(FlowConstant.MESSAGE_NOTICE, notice); FlowTask flowTask = flowTaskMapper.selectById(taskId); if (ObjectUtil.isNull(flowTask)) { throw new ServiceException("流程任务不存在或任务已审批!"); } Instance ins = insService.getById(flowTask.getInstanceId()); // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { variables.put(FlowConstant.SUBMIT, true); } // 设置弹窗处理人 Map assigneeMap = setPopAssigneeMap(completeTaskBo.getAssigneeMap(), ins.getVariableMap()); if (CollUtil.isNotEmpty(assigneeMap)) { variables.putAll(assigneeMap); } // 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息 FlowParams flowParams = FlowParams.build() .handler(completeTaskBo.getHandler()) .variable(variables) .ignore(Convert.toBool(variables.getOrDefault(VAR_IGNORE, false))) .ignoreDepute(Convert.toBool(variables.getOrDefault(VAR_IGNORE_DEPUTE, false))) .ignoreCooperate(Convert.toBool(variables.getOrDefault(VAR_IGNORE_COOPERATE, false))) .skipType(SkipType.PASS.getKey()) .message(completeTaskBo.getMessage()) .flowStatus(BusinessStatusEnum.WAITING.getStatus()) .hisStatus(TaskStatusEnum.PASS.getStatus()) .hisTaskExt(completeTaskBo.getFileId()); Boolean autoPass = Convert.toBool(variables.getOrDefault(AUTO_PASS, false)); skipTask(taskId, flowParams, flowTask.getInstanceId(), autoPass); return true; } /** * 流程办理 * * @param taskId 任务ID * @param flowParams 参数 * @param instanceId 实例ID * @param autoPass 自动审批 */ private void skipTask(Long taskId, FlowParams flowParams, Long instanceId, Boolean autoPass) { // 执行任务跳转,并根据返回的处理人设置下一步处理人 taskService.skip(taskId, flowParams); List flowTaskList = selectByInstId(instanceId); if (CollUtil.isEmpty(flowTaskList)) { return; } List userList = FlowEngine.userService() .getByAssociateds(StreamUtils.toList(flowTaskList, FlowTask::getId)); if (CollUtil.isEmpty(userList)) { return; } for (FlowTask task : flowTaskList) { if (!task.getId().equals(taskId) && autoPass) { List users = StreamUtils.filter(userList, e -> ObjectUtil.equals(task.getId(), e.getAssociated()) && ObjectUtil.equal(e.getProcessedBy(), LoginHelper.getUserIdStr())); if (CollUtil.isEmpty(users)) { continue; } flowParams. message("流程引擎自动审批!"). variable(Map.of( FlowConstant.SUBMIT, false, FlowConstant.FLOW_COPY_LIST, Collections.emptyList(), FlowConstant.MESSAGE_NOTICE, StringUtils.EMPTY)); skipTask(task.getId(), flowParams, instanceId, true); } } } /** * 设置弹窗处理人 * * @param assigneeMap 处理人 * @param variablesMap 变量 */ private Map setPopAssigneeMap(Map assigneeMap, Map variablesMap) { Map map = new HashMap<>(); if (CollUtil.isEmpty(assigneeMap)) { return map; } for (Map.Entry entry : assigneeMap.entrySet()) { if (variablesMap.containsKey(entry.getKey())) { String userIds = variablesMap.get(entry.getKey()).toString(); if (StringUtils.isNotBlank(userIds)) { Set hashSet = new HashSet<>(); //弹窗传入的选人 List popUserIds = Arrays.asList(entry.getValue().toString().split(StringUtils.SEPARATOR)); //已有的选人 List variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR)); hashSet.addAll(popUserIds); hashSet.addAll(variableUserIds); map.put(TaskStatusEnum.PASS.getStatus() + StrUtil.COLON + entry.getKey(), StringUtils.joinComma(hashSet)); map.put(TaskStatusEnum.BACK.getStatus() + StrUtil.COLON + entry.getKey(), StringUtils.joinComma(hashSet)); } } else { map.put(TaskStatusEnum.PASS.getStatus() + StrUtil.COLON + entry.getKey(), entry.getValue()); map.put(TaskStatusEnum.BACK.getStatus() + StrUtil.COLON + entry.getKey(), entry.getValue()); } } return map; } /** * 添加抄送人 * * @param task 任务信息 * @param flowCopyList 抄送人 */ @Override public void setCopy(Task task, List 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 = IdGeneratorUtil.nextLongId(); task.setId(taskId); task.setNodeName("【抄送】" + task.getNodeName()); Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000); FlowParams flowParams = FlowParams.build() .skipType(SkipType.NONE.getKey()) .hisStatus(TaskStatusEnum.COPY.getStatus()) .message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName)); HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams); hisTask.setCreateTime(updateTime); hisTask.setUpdateTime(updateTime); hisTaskService.save(hisTask); List userList = StreamUtils.toList(flowCopyList, x -> new FlowUser() .setType(TaskAssigneeType.COPY.getCode()) .setProcessedBy(Convert.toStr(x.getUserId())) .setAssociated(taskId)); // 批量保存抄送人员 FlowEngine.userService().saveBatch(userList); } /** * 查询当前用户的待办任务 * * @param flowTaskBo 参数 * @param pageQuery 分页 */ @Override public TableDataInfo pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr()); queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus()); Page page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper); this.wrapAssigneeInfo(page.getRecords()); return TableDataInfo.build(page); } /** * 查询当前用户的已办任务 * * @param flowTaskBo 参数 * @param pageQuery 分页 */ @Override public TableDataInfo pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); queryWrapper.in("t.approver", LoginHelper.getUserIdStr()); Page page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); return TableDataInfo.build(page); } /** * 查询待办任务 * * @param flowTaskBo 参数 * @param pageQuery 分页 */ @Override public TableDataInfo pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); Page page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper); this.wrapAssigneeInfo(page.getRecords()); return TableDataInfo.build(page); } /** * 为流程任务列表封装处理人 ID(assigneeIds) * * @param taskList 流程任务列表 */ private void wrapAssigneeInfo(List taskList) { if (CollUtil.isEmpty(taskList)) { return; } List associatedUsers = FlowEngine.userService().getByAssociateds(StreamUtils.toList(taskList, FlowTaskVo::getId)); Map> taskUserMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated); // 组装用户数据回任务列表 for (FlowTaskVo task : taskList) { List users = taskUserMap.get(task.getId()); task.setAssigneeIds(StreamUtils.join(users, User::getProcessedBy)); } } /** * 查询已办任务 * * @param flowTaskBo 参数 * @param pageQuery 分页 */ @Override public TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); Page page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); return TableDataInfo.build(page); } /** * 查询当前用户的抄送 * * @param flowTaskBo 参数 * @param pageQuery 分页 */ @Override public TableDataInfo pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr()); Page page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper); return TableDataInfo.build(page); } private QueryWrapper buildQueryWrapper(FlowTaskBo flowTaskBo) { Map params = flowTaskBo.getParams(); QueryWrapper 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.like(StringUtils.isNotBlank(flowTaskBo.getFlowStatus()), "t.flow_status", flowTaskBo.getFlowStatus()); wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds()); if (StringUtils.isNotBlank(flowTaskBo.getCategory())) { List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory())); wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr)); } wrapper.between(params.get("beginTime") != null && params.get("endTime") != null, "t.create_time", params.get("beginTime"), params.get("endTime")); wrapper.orderByDesc("t.create_time").orderByDesc("t.update_time"); return wrapper; } /** * 驳回任务 * * @param bo 参数 */ @Override @Transactional(rollbackFor = Exception.class) public boolean backProcess(BackProcessBo bo) { Long taskId = bo.getTaskId(); String notice = bo.getNotice(); List 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(); String applyNodeCode = flwCommonService.applyNodeCode(definitionId); Map variable = new HashMap<>(); // 消息类型 variable.put(FlowConstant.MESSAGE_TYPE, messageType); // 消息通知 variable.put(FlowConstant.MESSAGE_NOTICE, notice); FlowParams flowParams = FlowParams.build() .nodeCode(bo.getNodeCode()) .variable(variable) .message(message) .skipType(SkipType.REJECT.getKey()) .flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()) .hisStatus(TaskStatusEnum.BACK.getStatus()) .hisTaskExt(bo.getFileId()); taskService.skip(task.getId(), flowParams); return true; } /** * 获取可驳回的前置节点 * * @param taskId 任务id * @param nowNodeCode 当前节点 */ @Override public List getBackTaskNode(Long taskId, String nowNodeCode) { FlowTask task = flowTaskMapper.selectById(taskId); List nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), task.getDefinitionId()); if (!CollUtil.isNotEmpty(nodeCodes)) { return nodeCodes; } List userList = FlowEngine.userService() .getByAssociateds(Collections.singletonList(task.getId()), UserType.DEPUTE.getKey()); if (CollUtil.isNotEmpty(userList)) { return nodeCodes; } //判断是否配置了固定驳回节点 Node node = nodeCodes.get(0); if (StringUtils.isNotBlank(node.getAnyNodeSkip())) { return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), task.getDefinitionId()); } //获取可驳回的前置节点 List nodes = nodeService.previousNodeList(task.getDefinitionId(), nowNodeCode); List hisTaskList = hisTaskService.getByInsId(task.getInstanceId()); Map nodeMap = StreamUtils.toIdentityMap(nodes, Node::getNodeCode); Set added = new HashSet<>(); List backNodeList = new ArrayList<>(); for (HisTask hisTask : hisTaskList) { Node nodeValue = nodeMap.get(hisTask.getNodeCode()); if (nodeValue != null && NodeType.BETWEEN.getKey().equals(nodeValue.getNodeType()) && added.add(nodeValue.getNodeCode())) { backNodeList.add(nodeValue); } } if (CollUtil.isNotEmpty(backNodeList)) { Collections.reverse(backNodeList); return backNodeList; } return nodes; } /** * 终止任务 * * @param bo 参数 */ @Override @Transactional(rollbackFor = Exception.class) public boolean terminationTask(FlowTerminationBo bo) { 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 = FlowParams.build() .message(bo.getComment()) .flowStatus(BusinessStatusEnum.TERMINATION.getStatus()) .hisStatus(TaskStatusEnum.TERMINATION.getStatus()); taskService.termination(taskId, flowParams); return true; } /** * 按照任务id查询任务 * * @param taskIdList 任务id */ @Override public List selectByIdList(List 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()); FlowNode flowNode = this.getByNodeCode(flowTaskVo.getNodeCode(), instance.getDefinitionId()); if (ObjectUtil.isNull(flowNode)) { throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在"); } NodeExtVo nodeExtVo = flwNodeExtService.parseNodeExt(flowNode.getExt(), instance.getVariableMap()); //设置按钮权限 if (CollUtil.isNotEmpty(nodeExtVo.getButtonPermissions())) { flowTaskVo.setButtonList(nodeExtVo.getButtonPermissions()); } else { flowTaskVo.setButtonList(new ArrayList<>()); } if (CollUtil.isNotEmpty(nodeExtVo.getCopySettings())) { List list = StreamUtils.toList(nodeExtVo.getCopySettings(), x -> new FlowCopyVo(Convert.toLong(x))); flowTaskVo.setCopyList(list); } else { flowTaskVo.setCopyList(new ArrayList<>()); } if (CollUtil.isNotEmpty(nodeExtVo.getVariables())) { flowTaskVo.setVarList(nodeExtVo.getVariables()); } else { flowTaskVo.setVarList(new HashMap<>()); } flowTaskVo.setNodeRatio(flowNode.getNodeRatio()); flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId()))); return flowTaskVo; } /** * 获取下一节点信息 * * @param bo 参数 */ @Override public List getNextNodeList(FlowNextNodeBo bo) { Long taskId = bo.getTaskId(); Map variables = bo.getVariables(); Task task = taskService.getById(taskId); Instance instance = insService.getById(task.getInstanceId()); Definition definition = defService.getById(task.getDefinitionId()); Map mergeVariable = MapUtil.mergeAll(instance.getVariableMap(), variables); // 获取下一节点列表 List nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null, SkipType.PASS.getKey(), mergeVariable); List nextFlowNodes = BeanUtil.copyToList(nextNodeList, FlowNode.class); // 只获取中间节点 nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType())); if (CollUtil.isNotEmpty(nextNodeList)) { //构建以下节点数据 List buildNextTaskList = StreamUtils.toList(nextNodeList, node -> taskService.addTask(node, instance, definition, FlowParams.build())); //办理人变量替换 ExpressionUtil.evalVariable(buildNextTaskList, FlowParams.build().variable(mergeVariable)); for (FlowNode flowNode : nextFlowNodes) { StreamUtils.findFirst(buildNextTaskList, t -> t.getNodeCode().equals(flowNode.getNodeCode())) .ifPresent(first -> { List users; if (CollUtil.isNotEmpty(first.getPermissionList()) && CollUtil.isNotEmpty(users = flwTaskAssigneeService.fetchUsersByStorageIds(StringUtils.joinComma(first.getPermissionList())))) { flowNode.setPermissionFlag(StreamUtils.join(users, e -> Convert.toStr(e.getUserId()))); } }); } } return nextFlowNodes; } /** * 按照任务id查询任务 * * @param taskId 任务id * @return 结果 */ @Override public FlowHisTask selectHisTaskById(Long taskId) { return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getId, taskId)); } /** * 按照实例id查询任务 * * @param instanceId 流程实例id */ @Override public List selectByInstId(Long instanceId) { return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).eq(FlowTask::getInstanceId, instanceId)); } /** * 按照实例id查询任务 * * @param instanceIds 流程实例id */ @Override public List selectByInstIds(List instanceIds) { return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class).in(FlowTask::getInstanceId, instanceIds)); } /** * 判断流程是否已结束(即该流程实例下是否还有未完成的任务) * * @param instanceId 流程实例ID * @return true 表示任务已全部结束;false 表示仍有任务存在 */ @Override public boolean isTaskEnd(Long instanceId) { boolean exists = flowTaskMapper.exists(new LambdaQueryWrapper().eq(FlowTask::getInstanceId, instanceId)); return !exists; } /** * 任务操作 * * @param bo 参数 * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature */ @Override @Transactional(rollbackFor = Exception.class) public boolean taskOperation(TaskOperationBo bo, String taskOperation) { FlowParams flowParams = FlowParams.build().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(); Task task = taskService.getById(taskId); FlowNode flowNode = getByNodeCode(task.getNodeCode(), task.getDefinitionId()); if (ADD_SIGNATURE.equals(taskOperation) || REDUCTION_SIGNATURE.equals(taskOperation)) { if (CooperateType.isOrSign(flowNode.getNodeRatio())) { throw new ServiceException(task.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 taskIdList, String userId) { if (CollUtil.isEmpty(taskIdList)) { return false; } List flowTasks = this.selectByIdList(taskIdList); // 批量删除现有任务的办理人记录 if (CollUtil.isNotEmpty(flowTasks)) { FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); List userList = StreamUtils.toList(flowTasks, flowTask -> new FlowUser() .setType(TaskAssigneeType.APPROVER.getCode()) .setProcessedBy(userId) .setAssociated(flowTask.getId())); if (CollUtil.isNotEmpty(userList)) { FlowEngine.userService().saveBatch(userList); } } return true; } /** * 获取当前任务的所有办理人 * * @param taskIds 任务id */ @Override public List currentTaskAllUser(List taskIds) { // 获取与当前任务关联的用户列表 List userList = FlowEngine.userService().getByAssociateds(taskIds); if (CollUtil.isEmpty(userList)) { return Collections.emptyList(); } return userService.selectListByIds(StreamUtils.toList(userList, e -> Convert.toLong(e.getProcessedBy()))); } /** * 按照节点编码查询节点 * * @param nodeCode 节点编码 * @param definitionId 流程定义id */ @Override public FlowNode getByNodeCode(String nodeCode, Long definitionId) { return flowNodeMapper.selectOne(new LambdaQueryWrapper() .eq(FlowNode::getNodeCode, nodeCode) .eq(FlowNode::getDefinitionId, definitionId)); } /** * 催办任务 * * @param bo 参数 */ @Override public boolean urgeTask(FlowUrgeTaskBo bo) { if (CollUtil.isEmpty(bo.getTaskIdList())) { return false; } List userList = this.currentTaskAllUser(bo.getTaskIdList()); if (CollUtil.isEmpty(userList)) { return false; } List messageType = bo.getMessageType(); String message = bo.getMessage(); flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList); return true; } }