diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/message/BpmMessageConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/message/BpmMessageConvert.java new file mode 100644 index 000000000..869f7b741 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/message/BpmMessageConvert.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.convert.message; + +import cn.iocoder.yudao.adminserver.modules.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; +import org.activiti.api.task.model.Task; +import org.activiti.engine.runtime.ProcessInstance; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +@Mapper +public interface BpmMessageConvert { + + BpmMessageConvert INSTANCE = Mappers.getMapper(BpmMessageConvert.class); + + default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, SysUserDO startUser, Task task) { + BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO(); + copyTo(processInstance, reqDTO); + copyTo(startUser, reqDTO); + copyTo(task, reqDTO); + return reqDTO; + } + @Mapping(source = "name", target = "processInstanceName") + void copyTo(ProcessInstance from, @MappingTarget BpmMessageSendWhenTaskCreatedReqDTO to); + @Mappings({ + @Mapping(source = "id", target = "startUserId"), + @Mapping(source = "nickname", target = "startUserNickname") + }) + void copyTo(SysUserDO from, @MappingTarget BpmMessageSendWhenTaskCreatedReqDTO to); + @Mappings({ + @Mapping(source = "id", target = "taskId"), + @Mapping(source = "name", target = "taskName"), + @Mapping(source = "assignee", target = "assigneeUserId") + }) + void copyTo(Task task, @MappingTarget BpmMessageSendWhenTaskCreatedReqDTO to); + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/message/BpmMessageEnum.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/message/BpmMessageEnum.java new file mode 100644 index 000000000..5632ff47e --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/message/BpmMessageEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.enums.message; + +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Bpm 消息的枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum BpmMessageEnum { + + TASK_ASSIGNED("bpm_task_assigned"); // 任务被分配时,发送给审批人 + + /** + * 短信模板的标识 + * + * 关联 {@link SysSmsTemplateDO#getCode()} + */ + private final String smsCode; + + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTaskEventListener.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTaskEventListener.java index 241782a87..b03f6b802 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTaskEventListener.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/framework/activiti/core/listener/BpmTaskEventListener.java @@ -53,6 +53,12 @@ public class BpmTaskEventListener> return; } + // 审核人修改时,进行拓展表,并额外发送通知 + if (event.getEventType() == TaskRuntimeEvent.TaskEvents.TASK_ASSIGNED) { + taskService.updateTaskExtAssign(event.getEntity()); + return; + } + // 其它事件,进行更新拓展表 taskService.updateTaskExt(event.getEntity()); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/BpmMessageService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/BpmMessageService.java new file mode 100644 index 000000000..43ce86fdb --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/BpmMessageService.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.message; + +import cn.iocoder.yudao.adminserver.modules.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; + +import javax.validation.Valid; + +/** + * BPM 消息 Service 接口 + * + * TODO 芋艿:未来支持消息的可配置;不同的流程,在什么场景下,需要发送什么消息,消息的内容是什么; + * + * @author 芋道源码 + */ +public interface BpmMessageService { + + void sendMessageWhenTaskAssigned(@Valid BpmMessageSendWhenTaskCreatedReqDTO reqDTO); + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java new file mode 100644 index 000000000..a3905e9d2 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.message.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * BPM 发送任务创建的 Request DTO + */ +@Data +public class BpmMessageSendWhenTaskCreatedReqDTO { + + /** + * 流程实例的编号 + */ + @NotEmpty(message = "流程实例的编号不能为空") + private String processInstanceId; + /** + * 流程实例的名字 + */ + @NotEmpty(message = "流程实例的名字不能为空") + private String processInstanceName; + @NotEmpty(message = "发起人的用户编号") + private String startUserId; + @NotEmpty(message = "发起人的昵称") + private String startUserNickname; + + /** + * 流程任务的编号 + */ + @NotEmpty(message = "流程任务的编号不能为空") + private String taskId; + /** + * 流程任务的名字 + */ + @NotEmpty(message = "流程任务的名字不能为空") + private String taskName; + + /** + * 审批人的用户编号 + */ + @NotNull(message = "审批人的用户编号不能为空") + private Long assigneeUserId; + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/impl/BpmMessageServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/impl/BpmMessageServiceImpl.java new file mode 100644 index 000000000..20f987c4c --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/impl/BpmMessageServiceImpl.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.message.impl; + +import cn.iocoder.yudao.adminserver.modules.bpm.enums.message.BpmMessageEnum; +import cn.iocoder.yudao.adminserver.modules.bpm.service.message.BpmMessageService; +import cn.iocoder.yudao.adminserver.modules.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO; +import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; + +/** + * BPM 消息 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class BpmMessageServiceImpl implements BpmMessageService { + + @Resource + private SysSmsCoreService smsCoreService; + + @Value("${yudao.url.admin-ui}") + private String adminUiUrl; + + @Override + public void sendMessageWhenTaskAssigned(BpmMessageSendWhenTaskCreatedReqDTO reqDTO) { + Map templateParams = new HashMap<>(); + templateParams.put("processInstanceName", reqDTO.getProcessInstanceName()); + templateParams.put("taskName", reqDTO.getTaskName()); + templateParams.put("startUserNickname", reqDTO.getStartUserNickname()); + templateParams.put("taskDetailUrl", getTaskDetailUrl(reqDTO.getTaskId())); + smsCoreService.sendSingleSmsToAdmin(null, reqDTO.getAssigneeUserId(), + BpmMessageEnum.TASK_ASSIGNED.getSmsCode(), templateParams); + } + + private String getTaskDetailUrl(String taskId) { + return adminUiUrl + "bpm/process-instance/detail?id=" + taskId; + } + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java index 47ee36bc8..cad468a2e 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java @@ -126,6 +126,13 @@ public interface BpmTaskService { */ void updateTaskExt(org.activiti.api.task.model.Task task); + /** + * 更新 Task 拓展记录,并发送通知 + * + * @param task 任务实体 + */ + void updateTaskExtAssign(org.activiti.api.task.model.Task task); + /** * 更新 Task 拓展记录为取消 * @@ -148,4 +155,5 @@ public interface BpmTaskService { */ List getTaskExtListByProcessInstanceId(String processInstanceId); + } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java index 2135a8ce2..d9b434673 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java @@ -1,12 +1,15 @@ package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task.*; +import cn.iocoder.yudao.adminserver.modules.bpm.convert.message.BpmMessageConvert; import cn.iocoder.yudao.adminserver.modules.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.adminserver.modules.bpm.dal.dataobject.task.BpmTaskExtDO; import cn.iocoder.yudao.adminserver.modules.bpm.dal.mysql.task.BpmTaskExtMapper; import cn.iocoder.yudao.adminserver.modules.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.adminserver.modules.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService; import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO; @@ -29,10 +32,13 @@ import org.activiti.engine.task.TaskQuery; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import javax.annotation.Resource; import javax.validation.Valid; import java.util.*; +import java.util.concurrent.TimeUnit; import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -61,6 +67,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Resource @Lazy // 解决循环依赖 private BpmProcessInstanceService processInstanceService; + @Resource + private BpmMessageService messageService; @Resource private BpmTaskExtMapper taskExtMapper; @@ -277,6 +285,21 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskExtMapper.updateByTaskId(taskExtDO); } + @Override + public void updateTaskExtAssign(org.activiti.api.task.model.Task task) { + // 更新 + updateTaskExt(task); + // 发送通知。由于 Activiti 操作是在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); + SysUserDO startUser = userService.getUser(Long.valueOf(processInstance.getStartUserId())); + messageService.sendMessageWhenTaskAssigned(BpmMessageConvert.INSTANCE.convert(processInstance, startUser, task)); + } + }); + } + @Override public void updateTaskExtCancel(org.activiti.api.task.model.Task task) { BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert(task) diff --git a/yudao-admin-server/src/main/resources/application.yaml b/yudao-admin-server/src/main/resources/application.yaml index 9f3e76f6d..7652dd5be 100644 --- a/yudao-admin-server/src/main/resources/application.yaml +++ b/yudao-admin-server/src/main/resources/application.yaml @@ -72,5 +72,7 @@ yudao: - cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants tenant: # 多租户相关配置项 tables: # 配置需要开启多租户的表;如果实体已经继承 TenantBaseDO 类,则无需重复配置 + url: + admin-ui: http://dashboard.yudao.iocoder.cn # Admin 管理后台 UI 的地址 debug: false