|
@@ -14,7 +14,6 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
|
|
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
|
|
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
|
|
|
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
|
|
-import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
|
|
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
|
|
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
|
|
|
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
|
|
@@ -63,7 +62,6 @@ import org.springframework.context.annotation.Lazy;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.validation.annotation.Validated;
|
|
|
-import org.springframework.web.client.RestTemplate;
|
|
|
|
|
|
import java.util.*;
|
|
|
|
|
@@ -263,30 +261,31 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
processVariables.putAll(reqVO.getProcessVariables());
|
|
|
}
|
|
|
|
|
|
- // 3 获取当前任务节点的信息
|
|
|
- // 3.1 获取下一个将要执行的节点集合
|
|
|
+ // 3. 获取下一个将要执行的节点集合
|
|
|
FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
|
|
|
List<FlowNode> nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables);
|
|
|
- return convertList(nextFlowNodes, node -> {
|
|
|
- List<Long> candidateUserIds = getTaskCandidateUserList(bpmnModel, node.getId(),
|
|
|
- loginUserId, historicProcessInstance.getProcessDefinitionId(), processVariables);
|
|
|
- // 3.2 获取节点的审批人信息
|
|
|
- Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(candidateUserIds);
|
|
|
- // 3.3 获取节点的审批人部门信息
|
|
|
- Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
|
|
|
- // 3.4 存在一个节点多人审批的情况,组装审批人信息
|
|
|
- List<UserSimpleBaseVO> candidateUsers = new ArrayList<>();
|
|
|
- userMap.forEach((key, value) -> candidateUsers.add(BpmProcessInstanceConvert.INSTANCE.buildUser(key, userMap, deptMap)));
|
|
|
- return new ActivityNode().setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
|
|
|
- .setId(node.getId())
|
|
|
- .setName(node.getName())
|
|
|
- .setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
|
|
|
- .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node))
|
|
|
- // TODO @小北:先把 candidateUserIds 设置完,然后最后拼接 candidateUsers 信息。这样,如果有多个节点,就不用重复查询啦;类似 buildApprovalDetail 思路;
|
|
|
- // TODO 先拼接处 List ActivityNode
|
|
|
- // TODO 接着,再起一段,处理 adminUserApi.getUserMap(candidateUserIds)、deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId))
|
|
|
- .setCandidateUsers(candidateUsers);
|
|
|
- });
|
|
|
+ List<ActivityNode> nextActivityNodes = convertList(nextFlowNodes, node -> new ActivityNode().setId(node.getId())
|
|
|
+ .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
|
|
|
+ .setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
|
|
|
+ .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(node))
|
|
|
+ .setCandidateUserIds(getTaskCandidateUserList(bpmnModel, node.getId(),
|
|
|
+ loginUserId, historicProcessInstance.getProcessDefinitionId(), processVariables)));
|
|
|
+ if (CollUtil.isNotEmpty(nextActivityNodes)) {
|
|
|
+ return nextActivityNodes;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 拼接基础信息
|
|
|
+ Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
|
|
|
+ convertSetByFlatMap(nextActivityNodes, ActivityNode::getCandidateUserIds, Collection::stream));
|
|
|
+ Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
|
|
|
+ nextActivityNodes.forEach(node -> node.setCandidateUsers(convertList(node.getCandidateUserIds(), userId -> {
|
|
|
+ AdminUserRespDTO user = userMap.get(userId);
|
|
|
+ if (user != null) {
|
|
|
+ return BpmProcessInstanceConvert.INSTANCE.buildUser(userId, userMap, deptMap);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ })));
|
|
|
+ return nextActivityNodes;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -388,8 +387,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
List<HistoricActivityInstance> activities, List<HistoricTaskInstance> tasks) {
|
|
|
// 遍历 tasks 列表,只处理已结束的 UserTask
|
|
|
// 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点
|
|
|
- // TODO @芋艿:子流程只有activity,这里获取不到已结束的子流程;
|
|
|
- // TODO @lesan:【子流程】基于 activities 查询出 usertask、callactivity,然后拼接?如果是子流程,就是可以点击过去?
|
|
|
List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null);
|
|
|
List<ActivityNode> approvalNodes = convertList(endTasks, task -> {
|
|
|
FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
|
|
@@ -411,7 +408,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
|
|
|
// 遍历 activities,只处理已结束的 StartEvent、EndEvent
|
|
|
List<HistoricActivityInstance> endActivities = filterList(activities, activity -> activity.getEndTime() != null
|
|
|
- && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_EVENT_END)));
|
|
|
+ && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_EVENT_START, ELEMENT_CALL_ACTIVITY, ELEMENT_EVENT_END)));
|
|
|
endActivities.forEach(activity -> {
|
|
|
// StartEvent:只处理 BPMN 的场景。因为,SIMPLE 情况下,已经有 START_USER_NODE 节点
|
|
|
if (ELEMENT_EVENT_START.equals(activity.getActivityType())
|
|
@@ -445,7 +442,20 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
}
|
|
|
approvalNodes.add(endNode);
|
|
|
}
|
|
|
+ // CallActivity
|
|
|
+ if (ELEMENT_CALL_ACTIVITY.equals(activity.getActivityType())) {
|
|
|
+ ActivityNode callActivity = new ActivityNode().setId(activity.getId())
|
|
|
+ .setName(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getName())
|
|
|
+ .setNodeType(BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType()).setStatus(processInstanceStatus)
|
|
|
+ .setStartTime(DateUtils.of(activity.getStartTime()))
|
|
|
+ .setEndTime(DateUtils.of(activity.getEndTime()))
|
|
|
+ .setProcessInstanceId(activity.getProcessInstanceId());
|
|
|
+ approvalNodes.add(callActivity);
|
|
|
+ }
|
|
|
});
|
|
|
+
|
|
|
+ // 按照时间排序
|
|
|
+ approvalNodes.sort(Comparator.comparing(ActivityNode::getStartTime));
|
|
|
return approvalNodes;
|
|
|
}
|
|
|
|
|
@@ -465,7 +475,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
HistoricActivityInstance::getActivityId);
|
|
|
|
|
|
// 按照 activityId 分组,构建 ApprovalNodeInfo 节点
|
|
|
- // TODO @lesan:【子流程】在子流程进行审批的时候,HistoricActivityInstance 里面可以拿到 runActivities.get(0).getCalledProcessInstanceId()。要不要支持跳转???
|
|
|
Map<String, HistoricTaskInstance> taskMap = convertMap(tasks, HistoricTaskInstance::getId);
|
|
|
return convertList(runningTaskMap.entrySet(), entry -> {
|
|
|
String activityId = entry.getKey();
|
|
@@ -511,6 +520,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner
|
|
|
activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size()));
|
|
|
}
|
|
|
+ if (BpmSimpleModelNodeTypeEnum.CHILD_PROCESS.getType().equals(activityNode.getNodeType())) {
|
|
|
+ activityNode.setProcessInstanceId(firstActivity.getProcessInstanceId());
|
|
|
+ }
|
|
|
return activityNode;
|
|
|
});
|
|
|
}
|
|
@@ -824,6 +836,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
&& Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) {
|
|
|
throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW);
|
|
|
}
|
|
|
+ // 1.4 子流程不允许取消
|
|
|
+ if (StrUtil.isNotBlank(instance.getSuperExecutionId())) {
|
|
|
+ throw exception(PROCESS_INSTANCE_CANCEL_CHILD_FAIL_NOT_ALLOW);
|
|
|
+ }
|
|
|
|
|
|
// 2. 取消流程
|
|
|
updateProcessInstanceCancel(cancelReqVO.getId(),
|
|
@@ -850,7 +866,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
BpmProcessInstanceStatusEnum.CANCEL.getStatus());
|
|
|
runtimeService.setVariable(id, BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, reason);
|
|
|
|
|
|
- // 2. 结束流程
|
|
|
+ // 2. 取消所有子流程
|
|
|
+ List<ProcessInstance> childProcessInstances = runtimeService.createProcessInstanceQuery()
|
|
|
+ .superProcessInstanceId(id).list();
|
|
|
+ childProcessInstances.forEach(processInstance -> updateProcessInstanceCancel(
|
|
|
+ processInstance.getProcessInstanceId(), BpmReasonEnum.CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS.getReason()));
|
|
|
+
|
|
|
+ // 3. 结束流程
|
|
|
taskService.moveTaskToEnd(id, reason);
|
|
|
}
|
|
|
|
|
@@ -915,10 +937,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessAfterTriggerSetting();
|
|
|
|
|
|
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
|
|
|
- setting.getUrl(),
|
|
|
- setting.getHeader(),
|
|
|
- setting.getBody(),
|
|
|
- true, setting.getResponse());
|
|
|
+ setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
|
|
|
}
|
|
|
}
|
|
|
});
|
|
@@ -937,10 +956,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
|
|
}
|
|
|
BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting();
|
|
|
BpmHttpRequestUtils.executeBpmHttpRequest(instance,
|
|
|
- setting.getUrl(),
|
|
|
- setting.getHeader(),
|
|
|
- setting.getBody(),
|
|
|
- true, setting.getResponse());
|
|
|
+ setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse());
|
|
|
});
|
|
|
}
|
|
|
|