From 5f53681b9541d2398331e45cd926aa623715db62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 27 Mar 2026 15:20:39 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E5=B7=A5=E4=BD=9C=E6=B5=81=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=8E=A8=E9=80=81=E5=A2=9E=E5=8A=A0=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/core/service/UserService.java | 8 +++ .../service/impl/SysUserServiceImpl.java | 18 +++++++ .../common/constant/FlowConstant.java | 20 +++++++ .../listener/WorkflowGlobalListener.java | 54 +++++++++++++++++-- .../workflow/service/IFlwCommonService.java | 22 ++++++++ .../service/impl/FlwCommonServiceImpl.java | 26 +++++++-- .../service/impl/FlwTaskServiceImpl.java | 14 ++++- 7 files changed, 152 insertions(+), 10 deletions(-) diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java index 8b63f6c6a..3e1d16d59 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java @@ -53,6 +53,14 @@ public interface UserService { */ String selectEmailById(Long userId); + /** + * 通过用户ID查询用户 + * + * @param userId 用户id + * @return 用户列表 + */ + UserDTO selectById(Long userId); + /** * 通过用户ID查询用户列表 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java index 27e0eef5d..72da9b9f4 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -641,6 +641,24 @@ public class SysUserServiceImpl implements ISysUserService, UserService { return ObjectUtils.notNullGetter(sysUser, SysUser::getEmail); } + /** + * 通过用户ID查询用户 + * + * @param userId 用户id + * @return 用户列表 + */ + @Override + public UserDTO selectById(Long userId) { + SysUserVo vo = baseMapper.selectVoOne(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getDeptId, SysUser::getUserName, + SysUser::getNickName, SysUser::getUserType, SysUser::getEmail, + SysUser::getPhoneNumber, SysUser::getGender, SysUser::getStatus, + SysUser::getCreateTime) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .eq(SysUser::getUserId, userId)); + return BeanUtil.copyProperties(vo, UserDTO.class); + } + /** * 通过用户ID查询用户列表 * diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java index 850caf062..512a1348f 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -58,6 +58,26 @@ public interface FlowConstant { */ String MESSAGE_NOTICE = "messageNotice"; + /** + * 我的发起页面路径。 + */ + String PATH_MY_DOCUMENT = "/task/myDocument"; + + /** + * 我的待办页面路径。 + */ + String PATH_TASK_WAITING = "/task/taskWaiting"; + + /** + * 我的已办页面路径。 + */ + String PATH_TASK_FINISH = "/task/taskFinish"; + + /** + * 我的抄送页面路径。 + */ + String PATH_TASK_COPY = "/task/taskCopyList"; + /** * 任务状态字典类型编码。 */ 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 642744fb6..633e9724e 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 @@ -8,6 +8,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.UserDTO; import org.dromara.common.core.enums.BusinessStatusEnum; import org.dromara.common.core.service.UserService; import org.dromara.common.core.utils.StreamUtils; @@ -21,6 +22,7 @@ import org.dromara.warm.flow.core.listener.GlobalListener; import org.dromara.warm.flow.core.listener.ListenerVariable; import org.dromara.workflow.common.ConditionalOnEnable; import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.common.enums.MessageTypeEnum; import org.dromara.workflow.common.enums.TaskStatusEnum; import org.dromara.workflow.domain.bo.FlowCopyBo; import org.dromara.workflow.domain.vo.NodeExtVo; @@ -31,10 +33,7 @@ import org.dromara.workflow.service.IFlwNodeExtService; import org.dromara.workflow.service.IFlwTaskService; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * 工作流全局监听器,处理任务流转中的扩展变量、消息和事件发布。 @@ -198,12 +197,14 @@ public class WorkflowGlobalListener implements GlobalListener { String status = determineFlowStatus(instance); if (StringUtils.isNotBlank(status)) { flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, status, params, false); + notifyInitiatorIfNeeded(definition, instance, status, variable); } if (!BusinessStatusEnum.initialState(instance.getFlowStatus())) { if (task != null && CollUtil.isNotEmpty(nextTasks) && nextTasks.size() == 1 && flwCommonService.applyNodeCode(definition.getId()).equals(nextTasks.get(0).getNodeCode())) { // 如果为画线指定驳回 线条指定为驳回 驳回得节点为申请人节点 则修改流程状态为退回 flowProcessEventHandler.processHandler(definition.getFlowCode(), instance, BusinessStatusEnum.BACK.getStatus(), params, false); + notifyInitiatorIfNeeded(definition, instance, BusinessStatusEnum.BACK.getStatus(), variable); // 修改流程实例状态 instance.setFlowStatus(BusinessStatusEnum.BACK.getStatus()); FlowEngine.insService().updateById(instance); @@ -237,7 +238,10 @@ public class WorkflowGlobalListener implements GlobalListener { List messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() { }); String notice = MapUtil.getStr(variable, FlowConstant.MESSAGE_NOTICE); - flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice); + // 退回到申请人时只保留“已退回”结果消息,避免再追加一条“新的待办”形成重复提醒。 + if (shouldSendTaskMessage(flowParams, definition, nextTasks)) { + flwCommonService.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice); + } } FlowEngine.insService().removeVariables(instance.getId(), FlowConstant.FLOW_COPY_LIST, @@ -247,6 +251,46 @@ public class WorkflowGlobalListener implements GlobalListener { ); } + private boolean shouldSendTaskMessage(FlowParams flowParams, Definition definition, List nextTasks) { + if (flowParams == null || !TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus())) { + return true; + } + if (CollUtil.isEmpty(nextTasks) || nextTasks.size() != 1) { + return true; + } + // 只有“退回到申请人”场景需要拦截待办提醒,其余退回/流转仍然保留待办消息。 + String applyNodeCode = flwCommonService.applyNodeCode(definition.getId()); + return !StringUtils.equals(applyNodeCode, nextTasks.get(0).getNodeCode()); + } + + private void notifyInitiatorIfNeeded(Definition definition, Instance instance, String status, Map variable) { + if (!StringUtils.equalsAny(status, BusinessStatusEnum.FINISH.getStatus(), BusinessStatusEnum.BACK.getStatus())) { + return; + } + if (StringUtils.isBlank(instance.getCreateBy())) { + return; + } + BusinessStatusEnum statusEnum = BusinessStatusEnum.getByStatus(status); + if (statusEnum == null) { + return; + } + Long createBy = Convert.toLong(instance.getCreateBy(), null); + if (createBy == null) { + return; + } + UserDTO initiator = userService.selectById(createBy); + if (initiator == null || initiator.getUserId() == null) { + return; + } + // 已完成、已退回这类结果消息只发给发起人,不再混入处理人待办消息。 + List messageType = Collections.singletonList(MessageTypeEnum.SYSTEM_MESSAGE.getCode()); + if (MapUtil.isNotEmpty(variable) && variable.containsKey(FlowConstant.MESSAGE_TYPE)) { + messageType = MapUtil.get(variable, FlowConstant.MESSAGE_TYPE, new TypeReference<>() { + }); + } + flwCommonService.sendResultMessage(definition.getFlowName(), statusEnum, messageType, Collections.singletonList(initiator)); + } + /** * 根据流程实例确定最终状态 * 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 f809f47b3..ea773ce3e 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,5 +1,6 @@ package org.dromara.workflow.service; +import org.dromara.common.core.enums.BusinessStatusEnum; import org.dromara.common.core.domain.dto.UserDTO; import java.util.List; @@ -31,6 +32,27 @@ public interface IFlwCommonService { */ void sendMessage(List messageType, String message, String subject, List userList); + /** + * 发送带跳转路径的消息。 + * + * @param messageType 消息类型 + * @param message 消息内容 + * @param subject 邮件标题 + * @param userList 接收用户 + * @param path 前端跳转路径 + */ + void sendMessage(List messageType, String message, String subject, List userList, String path); + + /** + * 发送工作流结果消息给指定用户。 + * + * @param flowName 流程名称 + * @param status 流程状态 + * @param messageType 消息类型 + * @param userList 接收用户 + */ + void sendResultMessage(String flowName, BusinessStatusEnum status, List messageType, List userList); + /** * 申请人节点编码 * 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 cfccc7661..d377575c2 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 @@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.domain.dto.PushPayloadDTO; import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.enums.BusinessStatusEnum; import org.dromara.common.core.enums.PushSourceEnum; import org.dromara.common.core.enums.PushTypeEnum; import org.dromara.common.core.exception.ServiceException; @@ -28,6 +29,8 @@ import java.util.HashMap; import java.util.List; import java.util.Set; +import static org.dromara.workflow.common.constant.FlowConstant.PATH_MY_DOCUMENT; +import static org.dromara.workflow.common.constant.FlowConstant.PATH_TASK_WAITING; /** * 工作流工具 @@ -68,7 +71,8 @@ public class FlwCommonServiceImpl implements IFlwCommonService { if (CollUtil.isEmpty(userList)) { return; } - sendMessage(messageType, message, DEFAULT_SUBJECT, userList); + // 发给当前处理人的工作流消息统一进入“我的待办”。 + sendMessage(messageType, message, DEFAULT_SUBJECT, userList, PATH_TASK_WAITING); } /** @@ -81,11 +85,27 @@ public class FlwCommonServiceImpl implements IFlwCommonService { */ @Override public void sendMessage(List messageType, String message, String subject, List userList) { + sendMessage(messageType, message, subject, userList, null); + } + + @Override + public void sendResultMessage(String flowName, BusinessStatusEnum status, List messageType, List userList) { + if (status == null || CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) { + return; + } + // 审批结果类消息面向发起人查看,统一跳转到“我发起的”。 + String message = "您发起的【" + flowName + "】单据审批已" + status.getDesc() + "。"; + sendMessage(messageType, message, DEFAULT_SUBJECT, userList, PATH_MY_DOCUMENT); + } + + @Override + public void sendMessage(List messageType, String message, String subject, List userList, String path) { if (CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) { return; } List userIds = new ArrayList<>(StreamUtils.toSet(userList, UserDTO::getUserId)); Set emails = StreamUtils.toSet(userList, UserDTO::getEmail); + emails.removeIf(StringUtils::isBlank); for (String code : messageType) { MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code); @@ -95,11 +115,11 @@ public class FlwCommonServiceImpl implements IFlwCommonService { try { switch (messageTypeEnum) { case SYSTEM_MESSAGE -> { + // 站内消息直接携带前端路由,消息盒子点击后可按路径分流。 messageService.publishMessage(userIds, PushPayloadDTO.of( PushTypeEnum.MESSAGE, PushSourceEnum.WORKFLOW, - message, - null + message, null, path )); } case EMAIL_MESSAGE -> MailUtils.sendText(emails, subject, message); 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 eb1e3db82..5c6e15d7e 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 @@ -363,6 +363,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService { .setAssociated(taskId)); // 批量保存抄送人员 FlowEngine.userService().saveBatch(userList); + // 抄送消息进入“我的抄送”,不和待办列表混用。 + flwCommonService.sendMessage( + List.of(org.dromara.workflow.common.enums.MessageTypeEnum.SYSTEM_MESSAGE.getCode()), + "您收到一条新的流程抄送,请及时查看。", + "单据抄送提醒", + userService.selectListByIds(StreamUtils.toList(flowCopyList, FlowCopyBo::getUserId)), + PATH_TASK_COPY + ); } /** @@ -824,11 +832,13 @@ public class FlwTaskServiceImpl implements IFlwTaskService { userIdList.addAll(StreamUtils.toList(bo.getUserIds(), Convert::toLong)); } if (CollUtil.isNotEmpty(userIdList)) { + // 转办、委托、加减签等运行时操作,消息接收人统一从“我的待办”进入处理。 flwCommonService.sendMessage( bo.getMessageType(), StringUtils.isNotBlank(bo.getMessage()) ? bo.getMessage() : "单据「" + op.getDesc() + "」通知", "单据「" + op.getDesc() + "」提醒", - userService.selectListByIds(userIdList) + userService.selectListByIds(userIdList), + PATH_TASK_WAITING ); } } @@ -907,7 +917,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService { } List messageType = bo.getMessageType(); String message = bo.getMessage(); - flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList); + flwCommonService.sendMessage(messageType, message, "单据审批提醒", userList, PATH_TASK_WAITING); return true; } }