mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 15:21:53 +08:00
仿钉钉流程设计- 审批节点超时处理
This commit is contained in:
parent
afad8ac619
commit
d34fef67da
@ -0,0 +1,24 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.enums.definition;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时器边界事件类型枚举
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum BpmTimerBoundaryEventType {
|
||||||
|
|
||||||
|
USER_TASK_TIMEOUT(1,"用户任务超时");
|
||||||
|
|
||||||
|
private final Integer type;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static BpmTimerBoundaryEventType typeOf(Integer type) {
|
||||||
|
return ArrayUtil.firstMatch(eventType -> eventType.getType().equals(type), values());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.enums.definition;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户任务超时处理执行动作枚举
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum BpmUserTaskTimeoutActionEnum {
|
||||||
|
|
||||||
|
AUTO_REMINDER(1,"自动提醒"),
|
||||||
|
AUTO_APPROVE(2, "自动同意"),
|
||||||
|
AUTO_REJECT(3, "自动拒绝");
|
||||||
|
|
||||||
|
private final Integer action;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public static BpmUserTaskTimeoutActionEnum actionOf(Integer action) {
|
||||||
|
return ArrayUtil.firstMatch(item -> item.getAction().equals(action), values());
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,16 @@ public interface BpmnModelConstants {
|
|||||||
*/
|
*/
|
||||||
String USER_TASK_CANDIDATE_PARAM = "candidateParam";
|
String USER_TASK_CANDIDATE_PARAM = "candidateParam";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPMN ExtensionElement 的扩展属性,用于标记用户任务超时执行动作
|
||||||
|
*/
|
||||||
|
String USER_TASK_TIMEOUT_HANDLER_ACTION = "timeoutAction";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BPMN ExtensionElement 的扩展属性,用于标记定时边界事件类型
|
||||||
|
*/
|
||||||
|
String TIMER_BOUNDARY_EVENT_TYPE = "timerBoundaryEventType";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限
|
* BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.listener;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRejectReqVO;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmTimerBoundaryEventType;
|
||||||
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.message.task.TodoTaskReminderMessage;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.producer.task.TodoTaskReminderProducer;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
|
||||||
|
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.flowable.bpmn.model.BoundaryEvent;
|
||||||
|
import org.flowable.bpmn.model.BpmnModel;
|
||||||
|
import org.flowable.bpmn.model.ExtensionElement;
|
||||||
|
import org.flowable.bpmn.model.FlowElement;
|
||||||
|
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
|
||||||
|
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
|
||||||
|
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
|
||||||
|
import org.flowable.job.api.Job;
|
||||||
|
import org.flowable.task.api.Task;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听定时器触发事件
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListener {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Lazy // 延迟加载,避免循环依赖
|
||||||
|
private BpmModelService bpmModelService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Lazy // 延迟加载,避免循环依赖
|
||||||
|
private BpmTaskService bpmTaskService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TodoTaskReminderProducer todoTaskReminderProducer;
|
||||||
|
|
||||||
|
public static final Set<FlowableEngineEventType> TIME_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
|
||||||
|
.add(FlowableEngineEventType.TIMER_FIRED)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public BpmTimerFiredEventListener() {
|
||||||
|
super(TIME_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void timerFired(FlowableEngineEntityEvent event) {
|
||||||
|
String processDefinitionId = event.getProcessDefinitionId();
|
||||||
|
BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(processDefinitionId);
|
||||||
|
Job entity = (Job) event.getEntity();
|
||||||
|
FlowElement element = BpmnModelUtils.getFlowElementById(bpmnModel, entity.getElementId());
|
||||||
|
// 如果是定时器边界事件
|
||||||
|
if (element instanceof BoundaryEvent) {
|
||||||
|
BoundaryEvent boundaryEvent = (BoundaryEvent) element;
|
||||||
|
ExtensionElement extensionElement = CollUtil.getFirst(boundaryEvent.getExtensionElements().get(BpmnModelConstants.TIMER_BOUNDARY_EVENT_TYPE));
|
||||||
|
Integer timerBoundaryEventType = NumberUtils.parseInt(Optional.ofNullable(extensionElement).map(ExtensionElement::getElementText).orElse(null));
|
||||||
|
BpmTimerBoundaryEventType bpmTimerBoundaryEventType = BpmTimerBoundaryEventType.typeOf(timerBoundaryEventType);
|
||||||
|
// 类型为用户任务超时未处理的情况
|
||||||
|
if (bpmTimerBoundaryEventType == BpmTimerBoundaryEventType.USER_TASK_TIMEOUT) {
|
||||||
|
ExtensionElement timeoutActionElement = CollUtil.getFirst(boundaryEvent.getExtensionElements().get(BpmnModelConstants.USER_TASK_TIMEOUT_HANDLER_ACTION));
|
||||||
|
Integer timeoutAction = NumberUtils.parseInt(Optional.ofNullable(timeoutActionElement).map(ExtensionElement::getElementText).orElse(null));
|
||||||
|
processUserTaskTimeout(event.getProcessInstanceId(), boundaryEvent.getAttachedToRefId(), timeoutAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processUserTaskTimeout(String processInstanceId, String taskDefKey, Integer timeoutAction) {
|
||||||
|
BpmUserTaskTimeoutActionEnum userTaskTimeoutAction = BpmUserTaskTimeoutActionEnum.actionOf(timeoutAction);
|
||||||
|
if (userTaskTimeoutAction != null) {
|
||||||
|
// 查询超时未处理的任务
|
||||||
|
List<Task> taskList = bpmTaskService.getAssignedTaskListByConditions(processInstanceId, taskDefKey);
|
||||||
|
taskList.forEach(task -> {
|
||||||
|
// 自动提醒
|
||||||
|
if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REMINDER) {
|
||||||
|
TodoTaskReminderMessage message = new TodoTaskReminderMessage().setTenantId(Long.parseLong(task.getTenantId()))
|
||||||
|
.setUserId(Long.parseLong(task.getAssignee())).setTaskName(task.getName());
|
||||||
|
todoTaskReminderProducer.sendReminderMessage(message);
|
||||||
|
}
|
||||||
|
// 自动同意
|
||||||
|
if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_APPROVE) {
|
||||||
|
// TODO @芋艿 这个上下文如何清除呢? 任务通过后, BpmProcessInstanceEventListener 会有回调
|
||||||
|
TenantContextHolder.setTenantId(Long.parseLong(task.getTenantId()));
|
||||||
|
TenantContextHolder.setIgnore(false);
|
||||||
|
BpmTaskApproveReqVO req = new BpmTaskApproveReqVO().setId(task.getId())
|
||||||
|
.setReason("超时系统自动同意");
|
||||||
|
bpmTaskService.approveTask(Long.parseLong(task.getAssignee()), req);
|
||||||
|
|
||||||
|
}
|
||||||
|
// 自动拒绝
|
||||||
|
if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REJECT) {
|
||||||
|
// TODO @芋艿 这个上下文如何清除呢? 任务拒绝后, BpmProcessInstanceEventListener 会有回调
|
||||||
|
TenantContextHolder.setTenantId(Long.parseLong(task.getTenantId()));
|
||||||
|
TenantContextHolder.setIgnore(false);
|
||||||
|
BpmTaskRejectReqVO req = new BpmTaskRejectReqVO().setId(task.getId()).setReason("超时系统自动拒绝");
|
||||||
|
bpmTaskService.rejectTask(Long.parseLong(task.getAssignee()), req);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.consumer.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.message.task.TodoTaskReminderMessage;
|
||||||
|
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办任务提醒 - 站内信的消费者
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class SysNotifyTodoTaskReminderConsumer {
|
||||||
|
|
||||||
|
private static final String TASK_REMIND_TEMPLATE_CODE = "user_task_remind";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private NotifyMessageSendApi notifyMessageSendApi;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
@Async
|
||||||
|
public void onMessage(TodoTaskReminderMessage message) {
|
||||||
|
log.info("站内信消费者接收到消息 [消息内容({})] ", message);
|
||||||
|
TenantUtils.execute(message.getTenantId(), ()-> {
|
||||||
|
Map<String,Object> templateParams = MapUtil.newHashMap();
|
||||||
|
templateParams.put("name", message.getTaskName());
|
||||||
|
NotifySendSingleToUserReqDTO req = new NotifySendSingleToUserReqDTO().setUserId(message.getUserId())
|
||||||
|
.setTemplateCode(TASK_REMIND_TEMPLATE_CODE).setTemplateParams(templateParams);
|
||||||
|
notifyMessageSendApi.sendSingleMessageToAdmin(req);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.message.task;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办任务提醒消息
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TodoTaskReminderMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户 Id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "租户 Id 不能未空")
|
||||||
|
private Long tenantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户Id
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户 Id 不能未空")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务名称
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "任务名称不能未空")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
// TODO 暂时只有站内信通知. 后面可以增加
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.producer.task;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.mq.message.task.TodoTaskReminderMessage;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 待办任务提醒 Producer
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Validated
|
||||||
|
public class TodoTaskReminderProducer {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public void sendReminderMessage(@Valid TodoTaskReminderMessage message) {
|
||||||
|
applicationContext.publishEvent(message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package cn.iocoder.yudao.module.bpm.framework.flowable.core.simple;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仿钉钉流程设计器审批节点配置 Model
|
||||||
|
*
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SimpleModelUserTaskConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 候选人策略
|
||||||
|
*/
|
||||||
|
private Integer candidateStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 候选人参数
|
||||||
|
*/
|
||||||
|
private String candidateParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段权限
|
||||||
|
*/
|
||||||
|
private List<Map<String,String>> fieldsPermission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批方式
|
||||||
|
*/
|
||||||
|
private Integer approveMethod;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超时处理
|
||||||
|
*/
|
||||||
|
private TimeoutHandler timeoutHandler;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class TimeoutHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否开启超时处理
|
||||||
|
*/
|
||||||
|
private Boolean enable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超时执行的动作
|
||||||
|
*/
|
||||||
|
private Integer action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超时时间设置
|
||||||
|
*/
|
||||||
|
private String timeDuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果执行动作是自动提醒, 最大提醒次数
|
||||||
|
*/
|
||||||
|
private Integer maxRemindCount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,27 +5,27 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.TypeReference;
|
import cn.hutool.core.lang.TypeReference;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.*;
|
||||||
import cn.hutool.core.util.BooleanUtil;
|
|
||||||
import cn.hutool.core.util.NumberUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.simple.BpmSimpleModelNodeVO;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmApproveMethodEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModeConditionType;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModeConditionType;
|
||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants;
|
|
||||||
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelConditionGroups;
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelConditionGroups;
|
||||||
|
import cn.iocoder.yudao.module.bpm.framework.flowable.core.simple.SimpleModelUserTaskConfig;
|
||||||
import org.flowable.bpmn.BpmnAutoLayout;
|
import org.flowable.bpmn.BpmnAutoLayout;
|
||||||
import org.flowable.bpmn.model.Process;
|
import org.flowable.bpmn.model.Process;
|
||||||
import org.flowable.bpmn.model.*;
|
import org.flowable.bpmn.model.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT;
|
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.END_EVENT;
|
||||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.FORM_FIELD_PERMISSION_ELEMENT;
|
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmTimerBoundaryEventType.USER_TASK_TIMEOUT;
|
||||||
|
import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER;
|
||||||
|
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
|
||||||
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*;
|
import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*;
|
||||||
import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;
|
import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_NAMESPACE;
|
||||||
import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX;
|
import static org.flowable.bpmn.constants.BpmnXMLConstants.FLOWABLE_EXTENSIONS_PREFIX;
|
||||||
@ -205,8 +205,15 @@ public class SimpleModelUtils {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case USER_TASK: {
|
case USER_TASK: {
|
||||||
UserTask userTask = buildBpmnUserTask(simpleModelNode);
|
// 获取用户任务的配置
|
||||||
|
SimpleModelUserTaskConfig userTaskConfig = BeanUtil.toBean(simpleModelNode.getAttributes(), SimpleModelUserTaskConfig.class);
|
||||||
|
UserTask userTask = buildBpmnUserTask(simpleModelNode, userTaskConfig);
|
||||||
mainProcess.addFlowElement(userTask);
|
mainProcess.addFlowElement(userTask);
|
||||||
|
if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) {
|
||||||
|
// 添加用户任务的 Timer Boundary Event, 用于任务的超时处理
|
||||||
|
BoundaryEvent boundaryEvent = buildUserTaskTimerBoundaryEvent(userTask, userTaskConfig.getTimeoutHandler());
|
||||||
|
mainProcess.addFlowElement(boundaryEvent);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COPY_TASK: {
|
case COPY_TASK: {
|
||||||
@ -263,6 +270,28 @@ public class SimpleModelUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BoundaryEvent buildUserTaskTimerBoundaryEvent(UserTask userTask, SimpleModelUserTaskConfig.TimeoutHandler timeoutHandler) {
|
||||||
|
// 定时器边界事件
|
||||||
|
BoundaryEvent boundaryEvent = new BoundaryEvent();
|
||||||
|
boundaryEvent.setId(IdUtil.fastUUID());
|
||||||
|
// 设置关联的任务为不会被中断
|
||||||
|
boundaryEvent.setCancelActivity(false);
|
||||||
|
boundaryEvent.setAttachedToRef(userTask);
|
||||||
|
TimerEventDefinition eventDefinition = new TimerEventDefinition();
|
||||||
|
eventDefinition.setTimeDuration(timeoutHandler.getTimeDuration());
|
||||||
|
if (Objects.equals(AUTO_REMINDER.getAction(), timeoutHandler.getAction()) &&
|
||||||
|
timeoutHandler.getMaxRemindCount() != null && timeoutHandler.getMaxRemindCount() > 1) {
|
||||||
|
// 最大提醒次数
|
||||||
|
eventDefinition.setTimeCycle(String.format("R%d/%s", timeoutHandler.getMaxRemindCount(), timeoutHandler.getTimeDuration()));
|
||||||
|
}
|
||||||
|
boundaryEvent.addEventDefinition(eventDefinition);
|
||||||
|
// 添加定时器边界事件类型
|
||||||
|
addExtensionElement(boundaryEvent, TIMER_BOUNDARY_EVENT_TYPE, USER_TASK_TIMEOUT.getType().toString());
|
||||||
|
// 添加超时执行动作元素
|
||||||
|
addExtensionElement(boundaryEvent, USER_TASK_TIMEOUT_HANDLER_ACTION, StrUtil.toStringOrNull(timeoutHandler.getAction()));
|
||||||
|
return boundaryEvent;
|
||||||
|
}
|
||||||
|
|
||||||
private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) {
|
private static ParallelGateway buildBpmnParallelGateway(BpmSimpleModelNodeVO node) {
|
||||||
ParallelGateway parallelGateway = new ParallelGateway();
|
ParallelGateway parallelGateway = new ParallelGateway();
|
||||||
parallelGateway.setId(node.getId());
|
parallelGateway.setId(node.getId());
|
||||||
@ -278,9 +307,14 @@ public class SimpleModelUtils {
|
|||||||
// TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现;
|
// TODO @jason:建议使用 ServiceTask,通过 executionListeners 实现;
|
||||||
// @芋艿 ServiceTask 就可以了吧。 不需要 executionListeners
|
// @芋艿 ServiceTask 就可以了吧。 不需要 executionListeners
|
||||||
// 添加抄送候选人元素
|
// 添加抄送候选人元素
|
||||||
addCandidateElements(node, serviceTask);
|
addCandidateElements(MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY),
|
||||||
|
MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM),
|
||||||
|
serviceTask);
|
||||||
// 添加表单字段权限属性元素
|
// 添加表单字段权限属性元素
|
||||||
addFormFieldsPermission(node, serviceTask);
|
List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(),
|
||||||
|
FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() {
|
||||||
|
});
|
||||||
|
addFormFieldsPermission(fieldsPermissions, serviceTask);
|
||||||
return serviceTask;
|
return serviceTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,12 +322,10 @@ public class SimpleModelUtils {
|
|||||||
/**
|
/**
|
||||||
* 给节点添加候选人元素
|
* 给节点添加候选人元素
|
||||||
*/
|
*/
|
||||||
private static void addCandidateElements(BpmSimpleModelNodeVO node, FlowElement flowElement) {
|
private static void addCandidateElements(Integer candidateStrategy, String candidateParam, FlowElement flowElement) {
|
||||||
Integer candidateStrategy = MapUtil.getInt(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY);
|
|
||||||
addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,
|
addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY,
|
||||||
candidateStrategy == null ? null : String.valueOf(candidateStrategy));
|
candidateStrategy == null ? null : candidateStrategy.toString());
|
||||||
addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM,
|
addExtensionElement(flowElement, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM, candidateParam);
|
||||||
MapUtil.getStr(node.getAttributes(), BpmnModelConstants.USER_TASK_CANDIDATE_PARAM));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ExclusiveGateway buildBpmnExclusiveGateway(BpmSimpleModelNodeVO node) {
|
private static ExclusiveGateway buildBpmnExclusiveGateway(BpmSimpleModelNodeVO node) {
|
||||||
@ -328,21 +360,25 @@ public class SimpleModelUtils {
|
|||||||
return endEvent;
|
return endEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node) {
|
private static UserTask buildBpmnUserTask(BpmSimpleModelNodeVO node, SimpleModelUserTaskConfig userTaskConfig) {
|
||||||
UserTask userTask = new UserTask();
|
UserTask userTask = new UserTask();
|
||||||
userTask.setId(node.getId());
|
userTask.setId(node.getId());
|
||||||
userTask.setName(node.getName());
|
userTask.setName(node.getName());
|
||||||
|
// 设置审批任务的截止时间
|
||||||
|
if (userTaskConfig.getTimeoutHandler() != null && userTaskConfig.getTimeoutHandler().getEnable()) {
|
||||||
|
userTask.setDueDate(userTaskConfig.getTimeoutHandler().getTimeDuration());
|
||||||
|
}
|
||||||
|
|
||||||
// 添加候选人元素
|
// 添加候选人元素
|
||||||
addCandidateElements(node, userTask);
|
addCandidateElements(userTaskConfig.getCandidateStrategy(), userTaskConfig.getCandidateParam(), userTask);
|
||||||
// 添加表单字段权限属性元素
|
// 添加表单字段权限属性元素
|
||||||
addFormFieldsPermission(node, userTask);
|
addFormFieldsPermission(userTaskConfig.getFieldsPermission(), userTask);
|
||||||
// 处理多实例
|
// 处理多实例
|
||||||
processMultiInstanceLoopCharacteristics(node, userTask);
|
processMultiInstanceLoopCharacteristics(userTaskConfig.getApproveMethod(), userTask);
|
||||||
return userTask;
|
return userTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processMultiInstanceLoopCharacteristics(BpmSimpleModelNodeVO node, UserTask userTask) {
|
private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, UserTask userTask) {
|
||||||
Integer approveMethod = MapUtil.getInt(node.getAttributes(), SimpleModelConstants.APPROVE_METHOD_ATTRIBUTE);
|
|
||||||
BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod);
|
BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod);
|
||||||
if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.SINGLE_PERSON_APPROVE) {
|
if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.SINGLE_PERSON_APPROVE) {
|
||||||
return;
|
return;
|
||||||
@ -369,10 +405,7 @@ public class SimpleModelUtils {
|
|||||||
/**
|
/**
|
||||||
* 给节点添加表单字段权限元素
|
* 给节点添加表单字段权限元素
|
||||||
*/
|
*/
|
||||||
private static void addFormFieldsPermission(BpmSimpleModelNodeVO node, FlowElement flowElement) {
|
private static void addFormFieldsPermission(List<Map<String, String>> fieldsPermissions, FlowElement flowElement) {
|
||||||
List<Map<String, String>> fieldsPermissions = MapUtil.get(node.getAttributes(),
|
|
||||||
FORM_FIELD_PERMISSION_ELEMENT, new TypeReference<>() {
|
|
||||||
});
|
|
||||||
if (CollUtil.isNotEmpty(fieldsPermissions)) {
|
if (CollUtil.isNotEmpty(fieldsPermissions)) {
|
||||||
fieldsPermissions.forEach(item -> addExtensionElement(flowElement, FORM_FIELD_PERMISSION_ELEMENT, item));
|
fieldsPermissions.forEach(item -> addExtensionElement(flowElement, FORM_FIELD_PERMISSION_ELEMENT, item));
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,13 @@ public interface BpmTaskService {
|
|||||||
*/
|
*/
|
||||||
Task getTask(String id);
|
Task getTask(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询已经分配的用户任务列表
|
||||||
|
* @param processInstanceId 流程实例编号
|
||||||
|
* @param taskDefineKey 任务定义 Key
|
||||||
|
*/
|
||||||
|
List<Task> getAssignedTaskListByConditions(String processInstanceId, String taskDefineKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前任务的可回退的 UserTask 集合
|
* 获取当前任务的可回退的 UserTask 集合
|
||||||
*
|
*
|
||||||
|
@ -433,6 +433,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
|
|||||||
return taskService.createTaskQuery().taskId(id).includeTaskLocalVariables().singleResult();
|
return taskService.createTaskQuery().taskId(id).includeTaskLocalVariables().singleResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Task> getAssignedTaskListByConditions(String processInstanceId, String defineKey) {
|
||||||
|
TaskQuery taskQuery = taskService.createTaskQuery().processInstanceId(processInstanceId)
|
||||||
|
.taskDefinitionKey(defineKey).active().taskAssigned().includeTaskLocalVariables();
|
||||||
|
return taskQuery.list();
|
||||||
|
}
|
||||||
|
|
||||||
private HistoricTaskInstance getHistoricTask(String id) {
|
private HistoricTaskInstance getHistoricTask(String id) {
|
||||||
return historyService.createHistoricTaskInstanceQuery().taskId(id).includeTaskLocalVariables().singleResult();
|
return historyService.createHistoricTaskInstanceQuery().taskId(id).includeTaskLocalVariables().singleResult();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user