仿钉钉流程设计- 审批节点超时处理

This commit is contained in:
jason 2024-05-23 22:34:56 +08:00
parent afad8ac619
commit d34fef67da
11 changed files with 417 additions and 24 deletions

View File

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

View File

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

View File

@ -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 流程表单字段权限元素, 用于标记字段权限
*/ */

View File

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

View File

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

View File

@ -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 暂时只有站内信通知. 后面可以增加
}

View File

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

View File

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

View File

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

View File

@ -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 集合
* *

View File

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