修改登录

This commit is contained in:
jinqiming 2021-07-16 17:23:27 +08:00
parent c7efebd155
commit d359c2ae4e
13 changed files with 378 additions and 5 deletions

View File

@ -62,6 +62,13 @@ public class SysMessageCenterController extends BaseController
mmap.put("emailList",emailList); mmap.put("emailList",emailList);
} }
if(CollectionUtil.isNotEmpty(sysMessageTransitions)){
List<SysMessageTransition> 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"; return prefix + "/messageCenter";
} }

View File

@ -19,7 +19,8 @@
<a data-toggle="tab" href="#tab-2"> 站内邮件 <span class="label label-info pull-right" >[[${emailListCount}]]</span></a> <a data-toggle="tab" href="#tab-2"> 站内邮件 <span class="label label-info pull-right" >[[${emailListCount}]]</span></a>
</li> </li>
<li class=""><a data-toggle="tab" href="#tab-3"> 第二个选项卡</a> <li class="">
<a data-toggle="tab" href="#tab-3"> 系统流程待办 <span class="label label-info pull-right" >[[${todoTaskCount}]]</span></a>
</li> </li>
<li class=""><a data-toggle="tab" href="#tab-4"> 第二个选项卡</a> <li class=""><a data-toggle="tab" href="#tab-4"> 第二个选项卡</a>
</li> </li>
@ -71,7 +72,7 @@
<strong th:text="${#dates.format(email.createTime, 'yyyy-MM-dd HH:mm:ss')}"></strong> <strong th:text="${#dates.format(email.createTime, 'yyyy-MM-dd HH:mm:ss')}"></strong>
</p> </p>
<label > <label >
<a class="text-info" href="#"></i> @[[${email.producerUser.userName}]]</a> <a class="text-info" href="#"></i> @[[${email.producerUser.userName}]]</a>
</label> </label>
<label > 发来一条站内邮件,请及时查看。</label> <label > 发来一条站内邮件,请及时查看。</label>
<a href="javascript:void(0)" class="btn btn-sm btn-success" th:onclick="messageDetail([[${email.redirectUrl}]]);"> 查看详情 </a> <a href="javascript:void(0)" class="btn btn-sm btn-success" th:onclick="messageDetail([[${email.redirectUrl}]]);"> 查看详情 </a>
@ -86,10 +87,30 @@
</div> </div>
<div id="tab-3" class="tab-pane"> <div id="tab-3" class="tab-pane">
<div class="panel-body"> <div class="panel-body">
<strong>栅格系统</strong> <strong>系统流程待办</strong>
<div id="vertical-timeline" class="vertical-container light-timeline" th:each="todoTask,iterStat : ${todoTaskList}">
<div class="vertical-timeline-block">
<div class="vertical-timeline-icon blue-bg">
<i th:class="${todoTask.iconClass}"></i>
</div>
<p>Bootstrap 提供了一套响应式、移动设备优先的流式栅格系统随着屏幕或视口viewport尺寸的增加系统会自动分为最多12列。它包含了易于使用的预定义类还有强大的mixin 用于生成更具语义的布局。</p> <div class="vertical-timeline-content">
</div> <p>
<label th:switch="${todoTask.messageReadStatus}">
<span class="label label-danger" th:case="'0'">未读</span>
<span class="label label-success" th:case="'1'">已读</span>
</label>
<strong th:text="${#dates.format(todoTask.createTime, 'yyyy-MM-dd HH:mm:ss')}"></strong>
</p>
<p >[[${todoTask.messageContent}]]</p>
<a href="javascript:void(0)" class="btn btn-sm btn-success" th:onclick="messageDetail([[${todoTask.redirectUrl}]]);"> 查看详情 </a>
<p>
<small class="badge badge-warning"> <i class="fa fa-clock-o"></i>[[${email.spendTime}]]</small>
</p>
</div>
</div>
</div>
</div>
</div> </div>
<div id="tab-4" class="tab-pane"> <div id="tab-4" class="tab-pane">
<div class="panel-body"> <div class="panel-body">

View File

@ -37,4 +37,10 @@ public class MessageConstants {
*/ */
public static final String CUSTOMER_VISIT_LOG_CODE="1411568525448978432"; public static final String CUSTOMER_VISIT_LOG_CODE="1411568525448978432";
/**
* 站内信任务创建模板
*/
public static final String INNER_TASK_CREATED_CODE="1415927384573616128";
} }

View File

@ -9,6 +9,8 @@ package com.snow.common.enums;
public enum MessageEventType { public enum MessageEventType {
TASK_TODO("TASK_TODO", "任务待办"), TASK_TODO("TASK_TODO", "任务待办"),
INNER_TASK_TODO("INNER_TASK_TODO", "站内信任务待办"),
TASK_FINISH("TASK_FINISH", "任务完成"), TASK_FINISH("TASK_FINISH", "任务完成"),
SEND_EMAIL("SEND_EMAIL", "发送邮件"), SEND_EMAIL("SEND_EMAIL", "发送邮件"),

View File

@ -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<ContextRefreshedEvent> {
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);
}
}

View File

@ -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;
}
}

View File

@ -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<SysUser> 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<String,Object> 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;
}
}

View File

@ -1,10 +1,13 @@
package com.snow.flowable.service; package com.snow.flowable.service;
import com.snow.common.core.page.PageModel; import com.snow.common.core.page.PageModel;
import com.snow.flowable.common.enums.FlowDefEnum;
import com.snow.flowable.domain.*; import com.snow.flowable.domain.*;
import com.snow.system.domain.ActDeModel; import com.snow.system.domain.ActDeModel;
import com.snow.system.domain.SysUser; 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.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.repository.Model; import org.flowable.engine.repository.Model;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task; import org.flowable.task.api.Task;
@ -178,4 +181,18 @@ public interface FlowableService {
* @param suspendState * @param suspendState
*/ */
void suspendOrActiveProcessInstance(String instanceId, Integer suspendState); void suspendOrActiveProcessInstance(String instanceId, Integer suspendState);
/**
* 获取流程定义实体信息
*
* @param event
* @return ProcessDefinitionEntity
*/
ProcessDefinitionEntity getProcessDefinition(FlowableEngineEvent event);
/**
* 获取所有流程定义枚举set
* @return
*/
Set<FlowDefEnum> getAllFlowDefEnumsSet();
} }

View File

@ -52,4 +52,13 @@ public interface FlowableUserService {
* @return * @return
*/ */
Set<Long> getFlowGroupByUserId(Long userId); Set<Long> getFlowGroupByUserId(Long userId);
/**
* 获取当前节点的待办人
* @param assignee 任务分配人
* @param taskId 任务ID
* @return 待处理人员集合
*/
List<SysUser> getCandidateUsers(String assignee,String taskId);
} }

View File

@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.snow.common.core.page.PageModel; import com.snow.common.core.page.PageModel;
import com.snow.common.core.text.Convert; import com.snow.common.core.text.Convert;
import com.snow.common.enums.WorkRecordStatus; import com.snow.common.enums.WorkRecordStatus;
@ -28,7 +29,9 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process; 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.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.common.engine.impl.util.IoUtil; import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*; import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance; 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.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.RepositoryServiceImpl; import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.repository.*; import org.flowable.engine.repository.*;
import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
@ -1164,4 +1168,28 @@ public class FlowableServiceImpl implements FlowableService {
return sysUserService.selectUserById(Long.parseLong(id)).getUserName(); 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<FlowDefEnum> getAllFlowDefEnumsSet() {
FlowDefEnum[] values = FlowDefEnum.values();
return Sets.newHashSet(values);
}
} }

View File

@ -1,5 +1,6 @@
package com.snow.flowable.service.impl; package com.snow.flowable.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.snow.common.constant.UserConstants; 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.ISysRoleService;
import com.snow.system.service.ISysUserService; import com.snow.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j; 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.RemoteGroup;
import org.flowable.ui.common.model.RemoteUser; import org.flowable.ui.common.model.RemoteUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -40,6 +43,9 @@ public class FlowableUserServiceImpl implements FlowableUserService {
@Autowired @Autowired
private IFlowGroupDOService flowGroupDOService; private IFlowGroupDOService flowGroupDOService;
@Autowired
private TaskService taskService;
@Override @Override
public Map<String, Object> loginFlowable() { public Map<String, Object> loginFlowable() {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
@ -199,4 +205,36 @@ public class FlowableUserServiceImpl implements FlowableUserService {
return parentFlowGroup; return parentFlowGroup;
} }
/**
* 获取当前节点的待办人
* @param assignee 任务分配人
* @param taskId 任务ID
* @return 待处理人员集合
*/
public List<SysUser> getCandidateUsers(String assignee,String taskId) {
Set<SysUser> result = Sets.newHashSet();
if (ObjectUtil.isNotNull(assignee)) {
// 已经被指派了则可审批人就是指派的人
SysUser sysUser = iSysUserService.selectUserById(Long.parseLong(assignee));
if (sysUser != null) {
result.add(sysUser);
}
} else {
// 获取待办对应的groupId和userId
List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(taskId);
for (IdentityLink identityLink : identityLinks) {
if (ObjectUtil.isNotNull(identityLink.getGroupId())) {
List<SysUser> 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);
}
} }

View File

@ -38,6 +38,7 @@ public class MessageEventHandler implements ApplicationListener<MessageEventDTO>
break; break;
case "SEND_VISIT_LOG": case "SEND_VISIT_LOG":
case "REGISTER_ACCOUNT_SUCCESS": case "REGISTER_ACCOUNT_SUCCESS":
case "INNER_TASK_TODO":
messageEventContext.setMessageEventTypeStrategy(new InnerMessageStrategy()); messageEventContext.setMessageEventTypeStrategy(new InnerMessageStrategy());
break; break;

View File

@ -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 (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(), '官网用户'); 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);