From e3b86b3d7a58b34bcb6e12e48beb21784a7cdf24 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Fri, 21 Jan 2022 22:53:43 +0800
Subject: [PATCH] =?UTF-8?q?bpm=20=E5=A2=9E=E5=8A=A0=E4=BB=BB=E5=8A=A1?=
 =?UTF-8?q?=E5=88=86=E9=85=8D=E5=88=B0=E6=8C=87=E5=AE=9A=E4=BA=BA=E6=97=B6?=
 =?UTF-8?q?=EF=BC=8C=E5=8F=91=E9=80=81=E7=9F=AD=E4=BF=A1=E9=80=9A=E7=9F=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../convert/message/BpmMessageConvert.java    | 39 +++++++++++++++
 .../bpm/enums/message/BpmMessageEnum.java     | 26 ++++++++++
 .../core/listener/BpmTaskEventListener.java   |  6 +++
 .../service/message/BpmMessageService.java    | 18 +++++++
 .../BpmMessageSendWhenTaskCreatedReqDTO.java  | 46 ++++++++++++++++++
 .../message/impl/BpmMessageServiceImpl.java   | 47 +++++++++++++++++++
 .../bpm/service/task/BpmTaskService.java      |  8 ++++
 .../service/task/impl/BpmTaskServiceImpl.java | 23 +++++++++
 .../src/main/resources/application.yaml       |  2 +
 9 files changed, 215 insertions(+)
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/message/BpmMessageConvert.java
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/message/BpmMessageEnum.java
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/BpmMessageService.java
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/dto/BpmMessageSendWhenTaskCreatedReqDTO.java
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/message/impl/BpmMessageServiceImpl.java

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<T extends RuntimeEvent<?, ?>>
             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<String, Object> 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<BpmTaskExtDO> 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