diff --git a/snow-admin/src/main/java/com/snow/web/controller/system/SysMessageCenterController.java b/snow-admin/src/main/java/com/snow/web/controller/system/SysMessageCenterController.java
index a08e817..a7ad041 100644
--- a/snow-admin/src/main/java/com/snow/web/controller/system/SysMessageCenterController.java
+++ b/snow-admin/src/main/java/com/snow/web/controller/system/SysMessageCenterController.java
@@ -62,6 +62,13 @@ public class SysMessageCenterController extends BaseController
mmap.put("emailList",emailList);
}
+ if(CollectionUtil.isNotEmpty(sysMessageTransitions)){
+ List todoTaskList = sysMessageTransitions.stream().filter(t -> t.getMessageType().equals(MessageEventType.INNER_TASK_TODO.getCode())).collect(Collectors.toList());
+ long count = todoTaskList.stream().filter(t -> t.getMessageReadStatus() == 0).count();
+ mmap.put("todoTaskCount",count);
+ mmap.put("todoTaskList",todoTaskList);
+ }
+
return prefix + "/messageCenter";
}
diff --git a/snow-admin/src/main/resources/templates/system/messageCenter/messageCenter.html b/snow-admin/src/main/resources/templates/system/messageCenter/messageCenter.html
index ab3e327..80faf98 100644
--- a/snow-admin/src/main/resources/templates/system/messageCenter/messageCenter.html
+++ b/snow-admin/src/main/resources/templates/system/messageCenter/messageCenter.html
@@ -19,7 +19,8 @@
站内邮件 [[${emailListCount}]]
- 第二个选项卡
+
+ 系统流程待办 [[${todoTaskCount}]]
第二个选项卡
@@ -71,7 +72,7 @@
diff --git a/snow-common/src/main/java/com/snow/common/constant/MessageConstants.java b/snow-common/src/main/java/com/snow/common/constant/MessageConstants.java
index 012917b..93fa6a0 100644
--- a/snow-common/src/main/java/com/snow/common/constant/MessageConstants.java
+++ b/snow-common/src/main/java/com/snow/common/constant/MessageConstants.java
@@ -37,4 +37,10 @@ public class MessageConstants {
*/
public static final String CUSTOMER_VISIT_LOG_CODE="1411568525448978432";
+ /**
+ * 站内信任务创建模板
+ */
+ public static final String INNER_TASK_CREATED_CODE="1415927384573616128";
+
+
}
diff --git a/snow-common/src/main/java/com/snow/common/enums/MessageEventType.java b/snow-common/src/main/java/com/snow/common/enums/MessageEventType.java
index 5ebbab2..b954ddc 100644
--- a/snow-common/src/main/java/com/snow/common/enums/MessageEventType.java
+++ b/snow-common/src/main/java/com/snow/common/enums/MessageEventType.java
@@ -9,6 +9,8 @@ package com.snow.common.enums;
public enum MessageEventType {
TASK_TODO("TASK_TODO", "任务待办"),
+ INNER_TASK_TODO("INNER_TASK_TODO", "站内信任务待办"),
+
TASK_FINISH("TASK_FINISH", "任务完成"),
SEND_EMAIL("SEND_EMAIL", "发送邮件"),
diff --git a/snow-flowable/src/main/java/com/snow/flowable/listener/common/GlobalListenerConfig.java b/snow-flowable/src/main/java/com/snow/flowable/listener/common/GlobalListenerConfig.java
new file mode 100644
index 0000000..742bdc9
--- /dev/null
+++ b/snow-flowable/src/main/java/com/snow/flowable/listener/common/GlobalListenerConfig.java
@@ -0,0 +1,33 @@
+package com.snow.flowable.listener.common;
+
+import lombok.RequiredArgsConstructor;
+import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
+import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher;
+import org.flowable.spring.SpringProcessEngineConfiguration;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.lang.NonNull;
+
+/**
+ * Flowable全局监听器配置
+ *
+ */
+@Configuration
+@RequiredArgsConstructor
+public class GlobalListenerConfig implements ApplicationListener {
+
+ private final SpringProcessEngineConfiguration configuration;
+
+ private final TaskCreateListener taskCreateListener;
+
+ @Override
+ public void onApplicationEvent(@NonNull ContextRefreshedEvent event) {
+ FlowableEventDispatcher dispatcher = configuration.getEventDispatcher();
+ // 流程结束事件
+ // dispatcher.addEventListener(processEndListener, FlowableEngineEventType.PROCESS_COMPLETED);
+ //任务创建
+ dispatcher.addEventListener(taskCreateListener, FlowableEngineEventType.TASK_CREATED);
+ }
+
+}
diff --git a/snow-flowable/src/main/java/com/snow/flowable/listener/common/ProcessEndListener.java b/snow-flowable/src/main/java/com/snow/flowable/listener/common/ProcessEndListener.java
new file mode 100644
index 0000000..4fc08b8
--- /dev/null
+++ b/snow-flowable/src/main/java/com/snow/flowable/listener/common/ProcessEndListener.java
@@ -0,0 +1,85 @@
+package com.snow.flowable.listener.common;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.snow.flowable.common.enums.FlowDefEnum;
+import com.snow.flowable.service.FlowableService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.common.engine.api.delegate.event.FlowableEngineEvent;
+import org.flowable.common.engine.api.delegate.event.FlowableEvent;
+import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
+import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.flowable.engine.impl.util.CommandContextUtil;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Optional;
+
+/**
+ * @author qimingjin
+ * @Title:
+ * @Description:
+ * @date 2021/7/16 13:29
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class ProcessEndListener implements FlowableEventListener {
+
+ @Resource
+ private FlowableService flowableService;
+
+ @Override
+ public void onEvent(FlowableEvent flowableEvent) {
+ if (flowableEvent instanceof FlowableEngineEvent) {
+ FlowableEngineEvent flowableEngineEvent = (FlowableEngineEvent) flowableEvent;
+ ProcessDefinitionEntity processDefinition = flowableService.getProcessDefinition(flowableEngineEvent);
+ if(ObjectUtil.isNull(processDefinition)){
+ return;
+ }
+ String key = Optional.ofNullable(processDefinition.getKey()).orElse("");
+ for (FlowDefEnum flowDefEnum : flowableService.getAllFlowDefEnumsSet()) {
+ //在流程中存在的才监听
+ if (flowDefEnum.getCode().equals(key)) {
+ //发送站内信
+ }
+ }
+
+
+ }
+
+ }
+
+ @Override
+ public boolean isFailOnException() {
+ return false;
+ }
+
+ @Override
+ public boolean isFireOnTransactionLifecycleEvent() {
+ return false;
+ }
+
+ @Override
+ public String getOnTransaction() {
+ return null;
+ }
+
+ /**
+ * 获取流程定义信息
+ *
+ * @param event
+ * @return
+ */
+ protected ProcessDefinitionEntity getProcessDefinition(FlowableEngineEvent event) {
+ String processDefinitionId = event.getProcessDefinitionId();
+ if (processDefinitionId != null) {
+ CommandContext commandContext = CommandContextUtil.getCommandContext();
+ if (commandContext != null) {
+ return CommandContextUtil.getProcessDefinitionEntityManager(commandContext).findById(processDefinitionId);
+ }
+ }
+ return null;
+ }
+}
diff --git a/snow-flowable/src/main/java/com/snow/flowable/listener/common/TaskCreateListener.java b/snow-flowable/src/main/java/com/snow/flowable/listener/common/TaskCreateListener.java
new file mode 100644
index 0000000..969229a
--- /dev/null
+++ b/snow-flowable/src/main/java/com/snow/flowable/listener/common/TaskCreateListener.java
@@ -0,0 +1,122 @@
+package com.snow.flowable.listener.common;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.snow.common.constant.MessageConstants;
+import com.snow.common.enums.MessageEventType;
+import com.snow.flowable.common.enums.FlowDefEnum;
+import com.snow.flowable.service.FlowableService;
+import com.snow.flowable.service.impl.FlowableUserServiceImpl;
+import com.snow.framework.web.domain.common.MessageEventDTO;
+import com.snow.system.domain.SysUser;
+import com.snow.system.service.impl.SysUserServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
+import org.flowable.common.engine.api.delegate.event.FlowableEvent;
+import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.flowable.task.service.impl.persistence.entity.TaskEntity;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author qimingjin
+ * @Title: 待办创建
+ * @Description:
+ * @date 2021/7/16 13:29
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class TaskCreateListener implements FlowableEventListener {
+
+ @Resource
+ private FlowableService flowableService;
+
+ @Resource
+ private FlowableUserServiceImpl flowableUserService;
+
+ @Resource
+ private SysUserServiceImpl sysUserServiceImpl;
+
+
+ @Resource
+ private ApplicationContext applicationContext;
+
+ @Override
+ public void onEvent(FlowableEvent flowableEvent) {
+ if (flowableEvent instanceof FlowableEngineEntityEvent) {
+ FlowableEngineEntityEvent flowableEngineEvent = (FlowableEngineEntityEvent) flowableEvent;
+ ProcessDefinitionEntity processDefinition = flowableService.getProcessDefinition(flowableEngineEvent);
+ if(ObjectUtil.isNull(processDefinition)){
+ return;
+ }
+ String key = Optional.ofNullable(processDefinition.getKey()).orElse("");
+ for (FlowDefEnum flowDefEnum : flowableService.getAllFlowDefEnumsSet()) {
+ //在流程中存在的才监听
+ if (flowDefEnum.getCode().equals(key)) {
+ TaskEntity entity = (TaskEntity) flowableEngineEvent.getEntity();
+ //发送站内信
+ List candidateUsers = flowableUserService.getCandidateUsers(entity.getAssignee(), entity.getId());
+ if(CollectionUtils.isNotEmpty(candidateUsers)){
+ HistoricProcessInstance processInstance = flowableService.getHistoricProcessInstanceById(entity.getProcessInstanceId());
+ candidateUsers.forEach(t->
+ sendInnerMessage(t,processInstance)
+ );
+ }
+ }
+ }
+ }
+
+ }
+
+
+
+ private void sendInnerMessage(SysUser toUsers, HistoricProcessInstance processInstance){
+ SysUser startSysUser = sysUserServiceImpl.selectUserById(Long.parseLong(processInstance.getStartUserId()));
+ MessageEventDTO messageEventDTO=new MessageEventDTO(MessageEventType.INNER_TASK_TODO.getCode());
+ messageEventDTO.setProducerId(String.valueOf(0));
+ messageEventDTO.setConsumerIds(Sets.newHashSet(String.valueOf(toUsers.getUserId())));
+ messageEventDTO.setMessageEventType(MessageEventType.INNER_TASK_TODO);
+ messageEventDTO.setMessageOutsideId(processInstance.getId());
+ messageEventDTO.setMessageShow(2);
+ Map map= Maps.newHashMap();
+ map.put("toUser", toUsers.getUserName());
+ //map.put("starttime", DateUtil.formatDateTime(hisProcessInstance.getStartTime()));
+ map.put("startUser", startSysUser.getUserName());
+ map.put("processInstance", processInstance.getProcessDefinitionName());
+ map.put("url", "http://localhost/flow/getMyHistoricProcessInstance");
+ // map.put("datetime", DateUtil.formatDateTime(new Date()));
+ messageEventDTO.setParamMap(map);
+ messageEventDTO.setTemplateCode(MessageConstants.INNER_TASK_CREATED_CODE);
+ applicationContext.publishEvent(messageEventDTO);
+ }
+
+
+
+
+ @Override
+ public boolean isFailOnException() {
+ return false;
+ }
+
+ @Override
+ public boolean isFireOnTransactionLifecycleEvent() {
+ return false;
+ }
+
+ @Override
+ public String getOnTransaction() {
+ return null;
+ }
+
+}
diff --git a/snow-flowable/src/main/java/com/snow/flowable/service/FlowableService.java b/snow-flowable/src/main/java/com/snow/flowable/service/FlowableService.java
index c71160f..701face 100644
--- a/snow-flowable/src/main/java/com/snow/flowable/service/FlowableService.java
+++ b/snow-flowable/src/main/java/com/snow/flowable/service/FlowableService.java
@@ -1,10 +1,13 @@
package com.snow.flowable.service;
import com.snow.common.core.page.PageModel;
+import com.snow.flowable.common.enums.FlowDefEnum;
import com.snow.flowable.domain.*;
import com.snow.system.domain.ActDeModel;
import com.snow.system.domain.SysUser;
+import org.flowable.common.engine.api.delegate.event.FlowableEngineEvent;
import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.repository.Model;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
@@ -178,4 +181,18 @@ public interface FlowableService {
* @param suspendState
*/
void suspendOrActiveProcessInstance(String instanceId, Integer suspendState);
+ /**
+ * 获取流程定义实体信息
+ *
+ * @param event
+ * @return ProcessDefinitionEntity
+ */
+ ProcessDefinitionEntity getProcessDefinition(FlowableEngineEvent event);
+
+
+ /**
+ * 获取所有流程定义枚举set
+ * @return
+ */
+ Set getAllFlowDefEnumsSet();
}
diff --git a/snow-flowable/src/main/java/com/snow/flowable/service/FlowableUserService.java b/snow-flowable/src/main/java/com/snow/flowable/service/FlowableUserService.java
index e5ef3d8..e67d582 100644
--- a/snow-flowable/src/main/java/com/snow/flowable/service/FlowableUserService.java
+++ b/snow-flowable/src/main/java/com/snow/flowable/service/FlowableUserService.java
@@ -52,4 +52,13 @@ public interface FlowableUserService {
* @return
*/
Set getFlowGroupByUserId(Long userId);
+
+
+ /**
+ * 获取当前节点的待办人
+ * @param assignee 任务分配人
+ * @param taskId 任务ID
+ * @return 待处理人员集合
+ */
+ List getCandidateUsers(String assignee,String taskId);
}
diff --git a/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableServiceImpl.java b/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableServiceImpl.java
index 15c81ed..6151e1e 100644
--- a/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableServiceImpl.java
+++ b/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableServiceImpl.java
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import com.snow.common.core.page.PageModel;
import com.snow.common.core.text.Convert;
import com.snow.common.enums.WorkRecordStatus;
@@ -28,7 +29,9 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
+import org.flowable.common.engine.api.delegate.event.FlowableEngineEvent;
import org.flowable.common.engine.impl.identity.Authentication;
+import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
@@ -36,6 +39,7 @@ import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.repository.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
@@ -1164,4 +1168,28 @@ public class FlowableServiceImpl implements FlowableService {
return sysUserService.selectUserById(Long.parseLong(id)).getUserName();
}
+
+ /**
+ * 获取流程定义实体信息
+ *
+ * @param event
+ * @return ProcessDefinitionEntity
+ */
+ public ProcessDefinitionEntity getProcessDefinition(FlowableEngineEvent event) {
+ String processDefinitionId = event.getProcessDefinitionId();
+ if (processDefinitionId != null) {
+ CommandContext commandContext = CommandContextUtil.getCommandContext();
+ if (commandContext != null) {
+ return CommandContextUtil.getProcessDefinitionEntityManager(commandContext).findById(processDefinitionId);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Set getAllFlowDefEnumsSet() {
+ FlowDefEnum[] values = FlowDefEnum.values();
+ return Sets.newHashSet(values);
+ }
+
}
diff --git a/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableUserServiceImpl.java b/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableUserServiceImpl.java
index a3305bf..99e1736 100644
--- a/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableUserServiceImpl.java
+++ b/snow-flowable/src/main/java/com/snow/flowable/service/impl/FlowableUserServiceImpl.java
@@ -1,5 +1,6 @@
package com.snow.flowable.service.impl;
+import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.snow.common.constant.UserConstants;
@@ -12,6 +13,8 @@ import com.snow.system.service.IFlowGroupDOService;
import com.snow.system.service.ISysRoleService;
import com.snow.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
+import org.flowable.identitylink.api.IdentityLink;
+import org.flowable.engine.TaskService;
import org.flowable.ui.common.model.RemoteGroup;
import org.flowable.ui.common.model.RemoteUser;
import org.springframework.beans.factory.annotation.Autowired;
@@ -40,6 +43,9 @@ public class FlowableUserServiceImpl implements FlowableUserService {
@Autowired
private IFlowGroupDOService flowGroupDOService;
+ @Autowired
+ private TaskService taskService;
+
@Override
public Map loginFlowable() {
Map map = new HashMap<>();
@@ -199,4 +205,36 @@ public class FlowableUserServiceImpl implements FlowableUserService {
return parentFlowGroup;
}
+
+ /**
+ * 获取当前节点的待办人
+ * @param assignee 任务分配人
+ * @param taskId 任务ID
+ * @return 待处理人员集合
+ */
+ public List getCandidateUsers(String assignee,String taskId) {
+ Set result = Sets.newHashSet();
+ if (ObjectUtil.isNotNull(assignee)) {
+ // 已经被指派了,则可审批人就是指派的人
+ SysUser sysUser = iSysUserService.selectUserById(Long.parseLong(assignee));
+ if (sysUser != null) {
+ result.add(sysUser);
+ }
+ } else {
+ // 获取待办对应的groupId和userId
+ List identityLinks = taskService.getIdentityLinksForTask(taskId);
+ for (IdentityLink identityLink : identityLinks) {
+ if (ObjectUtil.isNotNull(identityLink.getGroupId())) {
+ List sysUsers = getUserByFlowGroupId(Long.parseLong(identityLink.getGroupId()));
+ result.addAll(sysUsers);
+ } else if (ObjectUtil.isNotNull(identityLink.getUserId())) {
+ SysUser handleUser = iSysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
+ if (handleUser != null) {
+ result.add(handleUser);
+ }
+ }
+ }
+ }
+ return new ArrayList<>(result);
+ }
}
diff --git a/snow-framework/src/main/java/com/snow/framework/web/message/MessageEventHandler.java b/snow-framework/src/main/java/com/snow/framework/web/message/MessageEventHandler.java
index dcf92b1..8efe3d6 100644
--- a/snow-framework/src/main/java/com/snow/framework/web/message/MessageEventHandler.java
+++ b/snow-framework/src/main/java/com/snow/framework/web/message/MessageEventHandler.java
@@ -38,6 +38,7 @@ public class MessageEventHandler implements ApplicationListener
break;
case "SEND_VISIT_LOG":
case "REGISTER_ACCOUNT_SUCCESS":
+ case "INNER_TASK_TODO":
messageEventContext.setMessageEventTypeStrategy(new InnerMessageStrategy());
break;
diff --git a/sql/v1.8.sql b/sql/v1.8.sql
index 6c148d3..9cf65d8 100644
--- a/sql/v1.8.sql
+++ b/sql/v1.8.sql
@@ -13,3 +13,7 @@ INSERT INTO `snow`.`sys_dict_type`( `dict_name`, `dict_type`, `status`, `create_
INSERT INTO `snow`.`sys_dict_data`( `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1, '系统用户', '00', 'sys_user_type', 'info', '', 'Y', '0', 'admin', NOW(), 'ry', NOW(), '系统用户');
INSERT INTO `snow`.`sys_dict_data`( `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2, '官网用户', '01', 'sys_user_type', 'primary', '', 'N', '0', 'admin', NOW(), 'ry', NOW(), '官网用户');
+
+#2021-07-16
+
+INSERT INTO `snow`.`sys_message_template`( `template_code`, `template_name`, `template_body`, `template_desc`, `template_type`, `pc_url`, `app_url`, `icon_class`, `template_status`, `is_delete`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ( '1415927384573616128', '任务待办', '尊敬的${toUser}:\r\n 您好,由${startUser}发起的${processInstance}。需要您去协助处理。\r\n 前往处理${url}。', '任务待办', 4, '', '', 'fa fa-bullhorn', 0, 0, '1', NOW(), NULL, NULL);
\ No newline at end of file