diff --git a/pom.xml b/pom.xml index bb7b0fec..1ff7ed17 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ 8.7.2-20250101 - 1.7.0 + 1.7.2 2.3.0 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java index 5d24b350..e844398e 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java @@ -7,6 +7,21 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * 自定义条件注解,用于基于配置启用或禁用特定功能 + *

+ * 该注解只会在配置文件中 `warm-flow.enabled=true` 时,标注了此注解的类或方法才会被 Spring 容器加载 + *

+ * 示例配置: + *

+ * warm-flow:
+ *   enabled: true  # 设置为 true 时,启用工作流功能
+ * 
+ *

+ * 使用此注解时,可以动态控制工作流功能是否启用,而不需要修改代码逻辑 + * + * @author Lion Li + */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @ConditionalOnProperty(value = "warm-flow.enabled", havingValue = "true") diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java index b451caec..e36bccc9 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java @@ -14,7 +14,10 @@ import org.dromara.warm.flow.core.listener.GlobalListener; import org.dromara.warm.flow.core.listener.ListenerVariable; import org.dromara.warm.flow.orm.entity.FlowTask; import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.FlowCopyBo; import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.service.IFlwCommonService; import org.dromara.workflow.service.IFlwInstanceService; import org.dromara.workflow.service.IFlwTaskService; import org.springframework.stereotype.Component; @@ -37,6 +40,7 @@ public class WorkflowGlobalListener implements GlobalListener { private final IFlwTaskService taskService; private final IFlwInstanceService instanceService; private final FlowProcessEventHandler flowProcessEventHandler; + private final IFlwCommonService flwCommonService; /** * 创建监听器,任务创建时执行 @@ -70,6 +74,32 @@ public class WorkflowGlobalListener implements GlobalListener { */ @Override public void assignment(ListenerVariable listenerVariable) { + Map variable = listenerVariable.getVariable(); + List nextTasks = listenerVariable.getNextTasks(); + FlowParams flowParams = listenerVariable.getFlowParams(); + Definition definition = listenerVariable.getDefinition(); + Instance instance = listenerVariable.getInstance(); + String applyNodeCode = flwCommonService.applyNodeCode(definition.getId()); + for (Task flowTask : nextTasks) { + // 如果办理或者退回并行存在需要指定办理人,则直接覆盖办理人 + if (variable.containsKey(flowTask.getNodeCode()) && (TaskStatusEnum.PASS.getStatus().equals(flowParams.getHisStatus()) + || TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus()))) { + String userIds = variable.get(flowTask.getNodeCode()).toString(); + flowTask.setPermissionList(List.of(userIds.split(StringUtils.SEPARATOR))); + variable.remove(flowTask.getNodeCode()); + } else { + // 否则把所有的角色或者部门转成对应的用户 + List permissionList = flowTask.getPermissionList(); + if (CollUtil.isNotEmpty(permissionList)) { + List newUserList = flwCommonService.buildUser(permissionList); + flowTask.setPermissionList(newUserList); + } + } + // 如果是申请节点,则把启动人添加到办理人 + if (flowTask.getNodeCode().equals(applyNodeCode)) { + flowTask.setPermissionList(List.of(instance.getCreateBy())); + } + } } /** @@ -98,6 +128,27 @@ public class WorkflowGlobalListener implements GlobalListener { if (StringUtils.isNotBlank(status)) { flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, params, false); } + + // 只有办理或者退回的时候才执行消息通知和抄送 + if (TaskStatusEnum.PASS.getStatus().equals(flowParams.getHisStatus()) + || TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus())) { + Task task = listenerVariable.getTask(); + Map variable = listenerVariable.getVariable(); + List flowCopyList = (List) variable.get("flowCopyList"); + List messageType = (List) variable.get("messageType"); + String notice = (String) variable.get("notice"); + + // 添加抄送人 + taskService.setCopy(task, flowCopyList); + variable.remove("flowCopyList"); + + // 消息通知 + if (CollUtil.isNotEmpty(messageType)) { + flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice); + variable.remove("messageType"); + variable.remove("notice"); + } + } } /** diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java index c8090420..5314b6f6 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java @@ -1,12 +1,6 @@ package org.dromara.workflow.service; -import org.dromara.warm.flow.core.entity.Instance; -import org.dromara.warm.flow.core.entity.User; -import org.dromara.warm.flow.core.service.UserService; - import java.util.List; -import java.util.Map; -import java.util.Set; /** * 通用 工作流服务 @@ -15,28 +9,13 @@ import java.util.Set; */ public interface IFlwCommonService { - /** - * 获取工作流用户service - */ - UserService getFlowUserService(); - /** * 构建工作流用户 * - * @param userList 办理用户 - * @param taskId 任务ID + * @param permissionList 办理用户 * @return 用户 */ - Set buildUser(List userList, Long taskId); - - /** - * 构建工作流用户 - * - * @param userIdList 办理用户 - * @param taskId 任务ID - * @return 用户 - */ - Set buildFlowUser(List userIdList, Long taskId); + List buildUser(List permissionList); /** * 发送消息 @@ -55,12 +34,4 @@ public interface IFlwCommonService { */ String applyNodeCode(Long definitionId); - /** - * 合并变量 - * - * @param instance 流程实例 - * @param variable 变量 - */ - void mergeVariable(Instance instance, Map variable); - } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java index 6c7fc6bc..11d17ec4 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java @@ -4,6 +4,7 @@ import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.system.api.domain.vo.RemoteUserVo; import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.core.entity.Task; import org.dromara.warm.flow.orm.entity.FlowHisTask; import org.dromara.warm.flow.orm.entity.FlowNode; import org.dromara.warm.flow.orm.entity.FlowTask; @@ -38,6 +39,14 @@ public interface IFlwTaskService { */ boolean completeTask(CompleteTaskBo completeTaskBo); + /** + * 添加抄送人 + * + * @param task 任务信息 + * @param flowCopyList 抄送人 + */ + void setCopy(Task task, List flowCopyList); + /** * 查询当前用户的待办任务 * diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java index 7af0a8d5..5bf8acb2 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java @@ -45,7 +45,6 @@ import java.util.stream.Collectors; @Service public class FlwCommonServiceImpl implements IFlwCommonService { - private final UserService userService; private final NodeService nodeService; @DubboReference @@ -53,78 +52,22 @@ public class FlwCommonServiceImpl implements IFlwCommonService { @DubboReference private RemoteMailService remoteMailService; - /** - * 获取工作流用户service - */ - @Override - public UserService getFlowUserService() { - return userService; - } - /** * 构建工作流用户 * - * @param userList 办理用户 - * @param taskId 任务ID + * @param permissionList 办理用户 * @return 用户 */ @Override - public Set buildUser(List userList, Long taskId) { - if (CollUtil.isEmpty(userList)) { - return Set.of(); + public List buildUser(List permissionList) { + if (CollUtil.isEmpty(permissionList)) { + return List.of(); } - Set list = new HashSet<>(); - Set processedBySet = new HashSet<>(); IFlwTaskAssigneeService taskAssigneeService = SpringUtils.getBean(IFlwTaskAssigneeService.class); - Map> userListMap = StreamUtils.groupByKey(userList, User::getType); - for (Map.Entry> entry : userListMap.entrySet()) { - List entryValue = entry.getValue(); - String processedBys = StreamUtils.join(entryValue, User::getProcessedBy); - // 根据 processedBy 前缀判断处理人类型,分别获取用户列表 - List users = taskAssigneeService.fetchUsersByStorageIds(processedBys); - // 转换为 FlowUser 并添加到结果集合 - if (CollUtil.isNotEmpty(users)) { - users.forEach(dto -> { - String processedBy = String.valueOf(dto.getUserId()); - if (!processedBySet.contains(processedBy)) { - FlowUser flowUser = new FlowUser(); - flowUser.setType(entry.getKey()); - flowUser.setProcessedBy(processedBy); - flowUser.setAssociated(taskId); - list.add(flowUser); - processedBySet.add(processedBy); - } - }); - } - } - return list; - } - - /** - * 构建工作流用户 - * - * @param userIdList 办理用户 - * @param taskId 任务ID - * @return 用户 - */ - @Override - public Set buildFlowUser(List userIdList, Long taskId) { - if (CollUtil.isEmpty(userIdList)) { - return Set.of(); - } - Set list = new HashSet<>(); - Set processedBySet = new HashSet<>(); - for (String userId : userIdList) { - if (!processedBySet.contains(userId)) { - FlowUser flowUser = new FlowUser(); - flowUser.setType(TaskAssigneeType.APPROVER.getCode()); - flowUser.setProcessedBy(String.valueOf(userId)); - flowUser.setAssociated(taskId); - list.add(flowUser); - processedBySet.add(String.valueOf(userId)); - } - } - return list; + String processedBys = CollUtil.join(permissionList, StringUtils.SEPARATOR); + // 根据 processedBy 前缀判断处理人类型,分别获取用户列表 + List users = taskAssigneeService.fetchUsersByStorageIds(processedBys); + return StreamUtils.toList(users, userDTO -> String.valueOf(userDTO.getUserId())); } /** @@ -184,13 +127,4 @@ public class FlwCommonServiceImpl implements IFlwCommonService { return nextNode.getNodeCode(); } - @Override - public void mergeVariable(Instance instance, Map variable) { - if (MapUtil.isNotEmpty(variable)) { - String variableStr = instance.getVariable(); - Map deserialize = FlowEngine.jsonConvert.strToMap(variableStr); - deserialize.putAll(variable); - instance.setVariable(FlowEngine.jsonConvert.objToStr(deserialize)); - } - } } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java index e851e600..b0cc0075 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java @@ -360,7 +360,7 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService { public void setVariable(Long instanceId, Map variable) { Instance instance = insService.getById(instanceId); if (instance != null) { - flwCommonService.mergeVariable(instance, variable); + taskService.mergeVariable(instance, variable); insService.updateById(instance); } } 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 index e22cdfd1..bcc66836 100644 --- 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 @@ -25,6 +25,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.system.api.RemoteUserService; import org.dromara.system.api.domain.vo.RemoteUserVo; +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.NodeType; @@ -115,7 +116,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { if (ObjectUtil.isNotNull(flowInstance)) { BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus()); List taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId())); - flwCommonService.mergeVariable(flowInstance, variables); + taskService.mergeVariable(flowInstance, variables); insService.updateById(flowInstance); RemoteStartProcessReturn dto = new RemoteStartProcessReturn(); dto.setProcessInstanceId(taskList.get(0).getInstanceId()); @@ -158,6 +159,13 @@ public class FlwTaskServiceImpl implements IFlwTaskService { String notice = completeTaskBo.getNotice(); // 获取抄送人 List flowCopyList = completeTaskBo.getFlowCopyList(); + // 设置抄送人 + completeTaskBo.getVariables().put("flowCopyList", flowCopyList); + // 消息类型 + completeTaskBo.getVariables().put("messageType", messageType); + // 消息通知 + completeTaskBo.getVariables().put("notice", notice); + FlowTask flowTask = flowTaskMapper.selectById(taskId); if (ObjectUtil.isNull(flowTask)) { throw new ServiceException("流程任务不存在或任务已审批!"); @@ -183,12 +191,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { .hisStatus(TaskStatusEnum.PASS.getStatus()) .hisTaskExt(completeTaskBo.getFileId()); // 执行任务跳转,并根据返回的处理人设置下一步处理人 - Instance instance = taskService.skip(taskId, flowParams); - this.setHandler(instance, flowTask, flowCopyList); - // 消息通知 - flwCommonService.sendMessage(definition.getFlowName(), ins.getId(), messageType, notice); - //设置下一环节处理人 - setNextHandler(ins.getId(), completeTaskBo.getAssigneeMap()); + taskService.skip(taskId, flowParams); return true; } catch (Exception e) { log.error(e.getMessage(), e); @@ -196,33 +199,6 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } } - /** - * 设置下一环节处理人 - * - * @param instanceId 实例ID - * @param assigneeMap 办理人 - */ - private void setNextHandler(Long instanceId, Map assigneeMap) { - if (CollUtil.isEmpty(assigneeMap)) { - return; - } - Instance inst = insService.getById(instanceId); - List flowTaskList = selectByInstId(instanceId); - Map variableMap = inst.getVariableMap(); - for (FlowTask task : flowTaskList) { - if (variableMap != null && variableMap.containsKey(task.getNodeCode())) { - String userIds = variableMap.get(task.getNodeCode()).toString(); - // 批量删除现有任务的办理人记录 - flwCommonService.getFlowUserService().deleteByTaskIds(List.of(task.getId())); - // 批量新增任务办理人记录 - Set users = flwCommonService.buildFlowUser(List.of(userIds.split(StringUtils.SEPARATOR)), task.getId()); - flwCommonService.getFlowUserService().saveBatch(new ArrayList<>(users)); - variableMap.remove(task.getNodeCode()); - } - } - flwCommonService.mergeVariable(inst, variableMap); - } - /** * 设置弹窗处理人 * @@ -254,54 +230,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService { return map; } - /** - * 设置办理人 - * - * @param instance 实例 - * @param task (当前任务)未办理的任务 - * @param flowCopyList 抄送人 - */ - private void setHandler(Instance instance, FlowTask task, List flowCopyList) { - if (ObjectUtil.isNull(instance)) { - return; - } - // 添加抄送人 - this.setCopy(task, flowCopyList); - // 根据流程实例ID查询所有关联的任务 - List flowTasks = this.selectByInstId(instance.getId()); - if (CollUtil.isEmpty(flowTasks)) { - return; - } - List taskIdList = StreamUtils.toList(flowTasks, FlowTask::getId); - // 获取与当前任务关联的用户列表 - List associatedUsers = flwCommonService.getFlowUserService().getByAssociateds(taskIdList); - if (CollUtil.isEmpty(associatedUsers)) { - return; - } - List userList = new ArrayList<>(); - // 遍历任务列表,处理每个任务的办理人 - for (FlowTask flowTask : flowTasks) { - List users = StreamUtils.filter(associatedUsers, user -> Objects.equals(user.getAssociated(), flowTask.getId())); - if (CollUtil.isNotEmpty(users)) { - userList.addAll(flwCommonService.buildUser(users, flowTask.getId())); - } - } - // 批量删除现有任务的办理人记录 - flwCommonService.getFlowUserService().deleteByTaskIds(taskIdList); - // 确保要保存的 userList 不为空 - if (CollUtil.isEmpty(userList)) { - return; - } - flwCommonService.getFlowUserService().saveBatch(userList); - } - /** * 添加抄送人 * * @param task 任务信息 * @param flowCopyList 抄送人 */ - public void setCopy(FlowTask task, List flowCopyList) { + @Override + public void setCopy(Task task, List flowCopyList) { if (CollUtil.isEmpty(flowCopyList)) { return; } @@ -332,7 +268,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { return flowUser; }).collect(Collectors.toList()); // 批量保存抄送人员 - flwCommonService.getFlowUserService().saveBatch(userList); + FlowEngine.userService().saveBatch(userList); } /** @@ -459,21 +395,25 @@ public class FlwTaskServiceImpl implements IFlwTaskService { Instance inst = insService.getById(task.getInstanceId()); BusinessStatusEnum.checkBackStatus(inst.getFlowStatus()); Long definitionId = task.getDefinitionId(); - Definition definition = defService.getById(definitionId); String applyNodeCode = flwCommonService.applyNodeCode(definitionId); + + Map variable = new HashMap<>(); + // 设置抄送人 + variable.put("flowCopyList", bo.getMessageType()); + // 消息类型 + variable.put("messageType", messageType); + // 消息通知 + variable.put("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); - - Instance instance = insService.getById(inst.getId()); - this.setHandler(instance, task, null); - // 消息通知 - flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice); return true; } catch (Exception e) { log.error(e.getMessage(), e); @@ -748,7 +688,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { List flowTasks = this.selectByIdList(taskIdList); // 批量删除现有任务的办理人记录 if (CollUtil.isNotEmpty(flowTasks)) { - flwCommonService.getFlowUserService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); + FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); List userList = flowTasks.stream() .map(flowTask -> { FlowUser flowUser = new FlowUser(); @@ -759,7 +699,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { }) .collect(Collectors.toList()); if (CollUtil.isNotEmpty(userList)) { - flwCommonService.getFlowUserService().saveBatch(userList); + FlowEngine.userService().saveBatch(userList); } } } catch (Exception e) { @@ -778,13 +718,13 @@ public class FlwTaskServiceImpl implements IFlwTaskService { public Map> currentTaskAllUser(List taskIdList) { Map> map = new HashMap<>(); // 获取与当前任务关联的用户列表 - List associatedUsers = flwCommonService.getFlowUserService().getByAssociateds(taskIdList); + List associatedUsers = FlowEngine.userService().getByAssociateds(taskIdList); Map> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated); for (Map.Entry> entry : listMap.entrySet()) { List value = entry.getValue(); if (CollUtil.isNotEmpty(value)) { - List userDTOS = remoteUserService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy()))); - map.put(entry.getKey(), userDTOS); + List userDtoList = remoteUserService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy()))); + map.put(entry.getKey(), userDtoList); } } return map; @@ -798,7 +738,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { @Override public List currentTaskAllUser(Long taskId) { // 获取与当前任务关联的用户列表 - List userList = flwCommonService.getFlowUserService().getByAssociateds(Collections.singletonList(taskId)); + List userList = FlowEngine.userService().getByAssociateds(Collections.singletonList(taskId)); if (CollUtil.isEmpty(userList)) { return Collections.emptyList(); }