Merge branch 'feature/countersign_ext' into dev
This commit is contained in:
commit
a1e65b73f6
@ -47,7 +47,7 @@ public interface BpmnConstants {
|
||||
String BIZ_NODE_ALTER = "[_BIZ_NODE_ALTER_]";
|
||||
String INITIATOR_SPECIFY = "[_INITIATOR_SPECIFY_]";
|
||||
String SIGNATURE_COLLECTION = "[_SIGNATURE_COLLECTION_]";
|
||||
String FORWARD_COUNTERSIGN_COUNT = "[_FORWARD_COUNTERSIGN_COUNT_]";
|
||||
String COUNTERSIGN_COUNT = "[_COUNTERSIGN_COUNT_]";
|
||||
String PROCESS_PREFIX = "Flowable";
|
||||
@Deprecated
|
||||
String OLD_TASK_ASSIGNEE_SKIP_FLAT = "taskSkip";
|
||||
@ -269,4 +269,8 @@ public interface BpmnConstants {
|
||||
* 前加签节点 ID 片段
|
||||
*/
|
||||
String FORWARD_ACTIVITY_FRAGMENT = "[forward_sign]";
|
||||
/**
|
||||
* 后加签节点 ID 片段
|
||||
*/
|
||||
String BACK_ACTIVITY_FRAGMENT = "[back_sign]";
|
||||
}
|
||||
|
||||
@ -43,9 +43,10 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.code.OtherRespCode.ASSIGNEE_NODE_ID_NOT_EXISTS;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.BACK_ACTIVITY_FRAGMENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_COUNT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_ACTIVITY_FRAGMENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FORWARD_COUNTERSIGN_COUNT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
|
||||
import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTERSIGN;
|
||||
@ -150,11 +151,11 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
switch (countersignType) {
|
||||
case FORWARD_COUNTERSIGN:
|
||||
// 加签的一种方式:前加签,具体定义由后续产品需求来定
|
||||
forwardCountSign(commandContext, task, valuTargetAssigneeList);
|
||||
forwardAndBackCountSign(commandContext, task, valuTargetAssigneeList);
|
||||
break;
|
||||
case BACK_COUNTERSIGN:
|
||||
// 加签的另一种方式
|
||||
backCountSign(commandContext, historicTaskInstance, task, valuTargetAssigneeList);
|
||||
forwardAndBackCountSign(commandContext, task, valuTargetAssigneeList);
|
||||
break;
|
||||
default:
|
||||
// 共享签,不区分顺序
|
||||
@ -166,13 +167,15 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
}
|
||||
|
||||
/**
|
||||
* 前加签
|
||||
* 前、后加签
|
||||
* <p>
|
||||
* 使用内存动态变更模型连接实现前加签功能
|
||||
*
|
||||
* @param commandContext
|
||||
* @param task
|
||||
* @param valuTargetAssigneeList
|
||||
*/
|
||||
private void forwardCountSign(CommandContext commandContext, TaskEntity task, List<BpmnTaskDelegateAssigner> valuTargetAssigneeList) {
|
||||
private void forwardAndBackCountSign(CommandContext commandContext, TaskEntity task, List<BpmnTaskDelegateAssigner> valuTargetAssigneeList) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
|
||||
@ -182,51 +185,90 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
|
||||
UserTask originalUserTask = (UserTask) process.getFlowElement(task.getTaskDefinitionKey());
|
||||
|
||||
// 获取当前实例前加签次数
|
||||
Long forwardCounterSignCount = runtimeService.getVariable(processInstance.getId(), FORWARD_COUNTERSIGN_COUNT, Long.class);
|
||||
if (Objects.isNull(forwardCounterSignCount)) {
|
||||
forwardCounterSignCount = 0L;
|
||||
Long counterSignCount = runtimeService.getVariable(processInstance.getId(), COUNTERSIGN_COUNT, Long.class);
|
||||
if (Objects.isNull(counterSignCount)) {
|
||||
counterSignCount = 0L;
|
||||
} else {
|
||||
forwardCounterSignCount = forwardCounterSignCount + 1;
|
||||
counterSignCount = counterSignCount + 1;
|
||||
}
|
||||
runtimeService.setVariable(processInstance.getId(), COUNTERSIGN_COUNT, counterSignCount);
|
||||
|
||||
BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR;
|
||||
// 创建前加签节点
|
||||
|
||||
// 生成加签节点ID
|
||||
String newActivityId = originalUserTask.getId();
|
||||
if (newActivityId.contains(FORWARD_ACTIVITY_FRAGMENT)) {
|
||||
newActivityId = newActivityId.substring(0, newActivityId.indexOf(FORWARD_ACTIVITY_FRAGMENT));
|
||||
switch (countersignType) {
|
||||
case FORWARD_COUNTERSIGN:
|
||||
newActivityId = processActivityId(newActivityId, FORWARD_ACTIVITY_FRAGMENT, counterSignCount);
|
||||
break;
|
||||
case BACK_COUNTERSIGN:
|
||||
newActivityId = processActivityId(newActivityId, BACK_ACTIVITY_FRAGMENT, counterSignCount);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, newActivityId + FORWARD_ACTIVITY_FRAGMENT + forwardCounterSignCount, nodeMode, valuTargetAssigneeList);
|
||||
|
||||
// 创建被加签节点
|
||||
UserTask newUserTask = CustomBpmnModelHelper.createUserTask(processEngineConfiguration, originalUserTask, newActivityId, nodeMode, valuTargetAssigneeList);
|
||||
// 加入模型
|
||||
process.addFlowElement(newUserTask);
|
||||
|
||||
// 重新连接顺序流 (Sequence Flow)
|
||||
CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask);
|
||||
CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask, countersignType);
|
||||
|
||||
saveCounterSignRecord(valuTargetAssigneeList, processInstance, originalUserTask, newUserTask, nodeMode);
|
||||
|
||||
if (Objects.equals(FORWARD_COUNTERSIGN, countersignType)) {
|
||||
log.info("前加签任务处理完成,原任务ID:{},新任务ID:{}", task.getId(), newUserTask.getId());
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId())
|
||||
.changeState();
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 前后加签动作记录,用于 JVM 重启后的动态恢复
|
||||
*
|
||||
* @param valuTargetAssigneeList
|
||||
* @param processInstance
|
||||
* @param originalUserTask
|
||||
* @param newUserTask
|
||||
* @param nodeMode
|
||||
*/
|
||||
private void saveCounterSignRecord(List<BpmnTaskDelegateAssigner> valuTargetAssigneeList, ProcessInstance processInstance, UserTask originalUserTask, UserTask newUserTask, BpmnFlowNodeMode nodeMode) {
|
||||
ExtAxDynamicSignRecord entity = new ExtAxDynamicSignRecord();
|
||||
entity.setProcessInstanceId(processInstance.getProcessInstanceId());
|
||||
entity.setProcessDefinitionId(processInstance.getProcessDefinitionId());
|
||||
entity.setOriginalActivityId(originalUserTask.getId());
|
||||
entity.setTargetActivityId(newUserTask.getId());
|
||||
entity.setCounterSignType(FORWARD_COUNTERSIGN.getType());
|
||||
entity.setCounterSignType(countersignType.getType());
|
||||
entity.setTargetNodeMode(nodeMode.getType());
|
||||
entity.setAssignerList(valuTargetAssigneeList);
|
||||
extAxDynamicSignRecordService.saveOrUpdate(entity);
|
||||
|
||||
runtimeService.setVariable(processInstance.getId(), FORWARD_COUNTERSIGN_COUNT, forwardCounterSignCount);
|
||||
runtimeService.createChangeActivityStateBuilder()
|
||||
.processInstanceId(task.getProcessInstanceId())
|
||||
.moveActivityIdTo(task.getTaskDefinitionKey(), newUserTask.getId())
|
||||
.changeState();
|
||||
}
|
||||
|
||||
// 提取公共处理方法
|
||||
private String processActivityId(String originalId, String fragment, long count) {
|
||||
if (originalId.contains(fragment)) {
|
||||
int fragmentIndex = originalId.indexOf(fragment);
|
||||
return originalId.substring(0, fragmentIndex) + fragment + count;
|
||||
}
|
||||
return originalId; // 不包含目标片段时,返回原字符串
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 后加签
|
||||
* <p>
|
||||
* 基于当前节点的后加签,内部实现主要依靠加减签的能力实现
|
||||
*
|
||||
* @param commandContext
|
||||
* @param historicTaskInstance
|
||||
* @param task
|
||||
* @param valuTargetAssigneeList
|
||||
*/
|
||||
@Deprecated
|
||||
private void backCountSign(CommandContext commandContext,
|
||||
HistoricTaskInstance historicTaskInstance,
|
||||
TaskEntity task,
|
||||
|
||||
@ -3,6 +3,7 @@ package cn.axzo.workflow.core.engine.cmd.helper;
|
||||
import cn.axzo.workflow.common.enums.ApprovalMethodEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.exception.WorkflowEngineException;
|
||||
@ -69,7 +70,7 @@ public class CustomBpmnModelHelper {
|
||||
newUserTask.setId(originalUserTask.getId());
|
||||
}
|
||||
newUserTask.setName(originalUserTask.getName());
|
||||
newUserTask.setDocumentation("由" + originalUserTask.getId() + "节点前加签生成");
|
||||
newUserTask.setDocumentation("由" + originalUserTask.getId() + "节点加签生成");
|
||||
|
||||
MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics();
|
||||
loopCharacteristics.setInputDataItem(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId());
|
||||
@ -129,7 +130,7 @@ public class CustomBpmnModelHelper {
|
||||
nodeTypeElement.setElementText(BpmnFlowNodeType.NODE_TASK.getType());
|
||||
newUserTask.addExtensionElement(nodeTypeElement);
|
||||
|
||||
// TODO 追加设置审批人为空的配置,因为查找审批人模式是固定人员,会执行退场、离职校验,导致最终审批人可能为空
|
||||
// 追加设置审批人为空的配置,因为查找审批人模式是固定人员,会执行退场、离职校验,导致最终审批人可能为空
|
||||
// 审批人为空时
|
||||
ExtensionElement approverEmptyHandleTypeElement = new ExtensionElement();
|
||||
approverEmptyHandleTypeElement.setName(CONFIG_APPROVER_EMPTY_HANDLE_TYPE);
|
||||
@ -147,7 +148,6 @@ public class CustomBpmnModelHelper {
|
||||
|
||||
ActivityBehaviorFactory activityBehaviorFactory = processEngineConfiguration.getActivityBehaviorFactory();
|
||||
UserTaskActivityBehavior userTaskActivityBehavior = activityBehaviorFactory.createUserTaskActivityBehavior(newUserTask);
|
||||
// TODO 这里设置的 userTaskActivityBehavior 似乎是不对的。需要
|
||||
ParallelMultiInstanceBehavior behavior = activityBehaviorFactory.createParallelMultiInstanceBehavior(newUserTask, userTaskActivityBehavior);
|
||||
|
||||
behavior.setCollectionVariable(INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO + newUserTask.getId());
|
||||
@ -157,31 +157,64 @@ public class CustomBpmnModelHelper {
|
||||
return newUserTask;
|
||||
}
|
||||
|
||||
public static void rewireSequenceFlows(Process process, UserTask originalUserTask, UserTask newUserTask) {
|
||||
public static void rewireSequenceFlows(Process process, UserTask originalUserTask, UserTask targetUserTask, BpmnCountersignTypeEnum countersignType) {
|
||||
switch (countersignType) {
|
||||
case FORWARD_COUNTERSIGN:
|
||||
// 1. 找到所有指向原始节点的输入流
|
||||
List<SequenceFlow> incomingFlows = originalUserTask.getIncomingFlows();
|
||||
if (incomingFlows.isEmpty()) {
|
||||
throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输入流,无法进行前加签");
|
||||
}
|
||||
|
||||
// 2. 将这些输入流的目标从 originalUserTask 修改为 newUserTask
|
||||
// 2. 将这些输入流的目标从 originalUserTask 修改为 targetUserTask
|
||||
for (SequenceFlow incomingFlow : incomingFlows) {
|
||||
incomingFlow.setTargetRef(newUserTask.getId());
|
||||
incomingFlow.setTargetRef(targetUserTask.getId());
|
||||
// 如果需要,也可以更新FlowElement中的引用,但通常改TargetRef即可
|
||||
}
|
||||
newUserTask.setIncomingFlows(incomingFlows);
|
||||
targetUserTask.setIncomingFlows(incomingFlows);
|
||||
|
||||
// 3. 创建一个新的顺序流,从 newUserTask 指向 originalUserTask
|
||||
// 3. 创建一个新的顺序流,从 targetUserTask 指向 originalUserTask
|
||||
SequenceFlow newSequenceFlow = new SequenceFlow();
|
||||
newSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_PreSign"));
|
||||
newSequenceFlow.setSourceRef(newUserTask.getId());
|
||||
newSequenceFlow.setSourceFlowElement(newUserTask);
|
||||
newSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_ForwardSign"));
|
||||
newSequenceFlow.setSourceRef(targetUserTask.getId());
|
||||
newSequenceFlow.setSourceFlowElement(targetUserTask);
|
||||
newSequenceFlow.setTargetRef(originalUserTask.getId());
|
||||
newSequenceFlow.setTargetFlowElement(originalUserTask);
|
||||
|
||||
newUserTask.setOutgoingFlows(Collections.singletonList(newSequenceFlow));
|
||||
targetUserTask.setOutgoingFlows(Collections.singletonList(newSequenceFlow));
|
||||
process.addFlowElement(newSequenceFlow);
|
||||
|
||||
originalUserTask.setIncomingFlows(Collections.singletonList(newSequenceFlow));
|
||||
break;
|
||||
case BACK_COUNTERSIGN:
|
||||
// 1. 找到所有指向原始节点的输出流
|
||||
List<SequenceFlow> outgoingFlows = originalUserTask.getOutgoingFlows();
|
||||
if (outgoingFlows.isEmpty()) {
|
||||
throw new WorkflowEngineException(CREATE_BPMN_PRE_SIGN_ERROR, "节点 " + originalUserTask.getId() + " 没有输出流,无法进行后加签");
|
||||
}
|
||||
|
||||
// 2. 将这些输出流的源从 originalUserTask 修改为 targetUserTask
|
||||
for (SequenceFlow outgoingFlow : outgoingFlows) {
|
||||
outgoingFlow.setSourceRef(targetUserTask.getId());
|
||||
// 如果需要,也可以更新FlowElement中的引用,但通常改SourceRef即可
|
||||
}
|
||||
targetUserTask.setOutgoingFlows(outgoingFlows);
|
||||
|
||||
// 3. 创建一个新的顺序流,从 originalUserTask 指向 targetUserTask
|
||||
SequenceFlow backSequenceFlow = new SequenceFlow();
|
||||
backSequenceFlow.setId(id(SEQUENCE_FLOW_ID + "_BackSign"));
|
||||
backSequenceFlow.setSourceRef(originalUserTask.getId());
|
||||
backSequenceFlow.setSourceFlowElement(originalUserTask);
|
||||
backSequenceFlow.setTargetRef(targetUserTask.getId());
|
||||
backSequenceFlow.setTargetFlowElement(targetUserTask);
|
||||
|
||||
originalUserTask.setOutgoingFlows(Collections.singletonList(backSequenceFlow));
|
||||
process.addFlowElement(backSequenceFlow);
|
||||
|
||||
targetUserTask.setIncomingFlows(Collections.singletonList(backSequenceFlow));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.server.initializer;
|
||||
|
||||
import cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.core.engine.cmd.helper.CustomBpmnModelHelper;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxDynamicSignRecord;
|
||||
@ -7,7 +8,6 @@ import cn.axzo.workflow.core.service.ExtAxDynamicSignRecordService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.impl.persistence.deploy.DeploymentManager;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
@ -26,8 +26,6 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.AND_SIGN_EXPRESSION;
|
||||
import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.BACK_COUNTERSIGN;
|
||||
import static cn.axzo.workflow.common.enums.BpmnCountersignTypeEnum.FORWARD_COUNTERSIGN;
|
||||
|
||||
/**
|
||||
* 在框架提供 Web 服务前,恢复动态前后加签的流程实例的内存中的模型
|
||||
@ -51,7 +49,7 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// TODO 恢复动态会签中的流程实例
|
||||
// 恢复动态会签中的流程实例
|
||||
log.info("executing before web server start");
|
||||
// 查询有过加签的审批实例
|
||||
List<ExtAxDynamicSignRecord> list = extAxDynamicSignRecordService.list();
|
||||
@ -85,7 +83,6 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle {
|
||||
)
|
||||
));
|
||||
|
||||
RepositoryService repositoryService = springProcessEngineConfiguration.getRepositoryService();
|
||||
DeploymentManager deploymentManager = springProcessEngineConfiguration.getDeploymentManager();
|
||||
grouped.forEach((k, v) -> {
|
||||
if (runningProcessIds.contains(k)) {
|
||||
@ -94,19 +91,15 @@ public class RecoverDynamicCounterSignProcess implements SmartLifecycle {
|
||||
ProcessDefinition processDefinitionEntity = deploymentManager.findDeployedProcessDefinitionById(v.get(0).getProcessDefinitionId());
|
||||
Process process = deploymentManager.resolveProcessDefinition(processDefinitionEntity).getProcess();
|
||||
v.forEach(sign -> {
|
||||
if (Objects.equals(sign.getCounterSignType(), FORWARD_COUNTERSIGN.getType())) {
|
||||
UserTask originalUserTask = (UserTask) process.getFlowElement(sign.getOriginalActivityId());
|
||||
BpmnFlowNodeMode nodeMode = Objects.equals(originalUserTask.getLoopCharacteristics().getCompletionCondition(), AND_SIGN_EXPRESSION) ? BpmnFlowNodeMode.AND : BpmnFlowNodeMode.OR;
|
||||
if (StringUtils.hasText(sign.getTargetNodeMode())) {
|
||||
nodeMode = BpmnFlowNodeMode.valueOfType(sign.getTargetNodeMode());
|
||||
}
|
||||
// 创建前加签节点
|
||||
// 创建加签节点
|
||||
UserTask newUserTask = CustomBpmnModelHelper.createUserTask(springProcessEngineConfiguration, originalUserTask, sign.getTargetActivityId(), nodeMode, sign.getAssignerList());
|
||||
process.addFlowElement(newUserTask);
|
||||
CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask);
|
||||
} else if (Objects.equals(sign.getCounterSignType(), BACK_COUNTERSIGN.getType())) {
|
||||
|
||||
}
|
||||
CustomBpmnModelHelper.rewireSequenceFlows(process, originalUserTask, newUserTask, Objects.requireNonNull(BpmnCountersignTypeEnum.valueOfType(sign.getCounterSignType())));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user