From 10b0a5bb5ae0ef6daef2360f90709d3fe704cecd Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 15:22:54 +0800 Subject: [PATCH 01/21] add dev --- .../com/codingapi/flow/action/BaseAction.java | 2 +- .../codingapi/flow/action/IFlowAction.java | 2 +- .../com/codingapi/flow/action/PassAction.java | 31 +---- .../codingapi/flow/action/RejectAction.java | 3 +- .../codingapi/flow/node/BaseAuditNode.java | 121 ++++++++++++++++++ .../com/codingapi/flow/node/BaseFlowNode.java | 20 +++ .../com/codingapi/flow/node/IFlowNode.java | 10 ++ .../flow/node/audit/ApprovalNode.java | 4 + .../com/codingapi/flow/record/FlowRecord.java | 7 +- .../flow/service/impl/FlowActionService.java | 76 +---------- .../flow/service/impl/FlowCreateService.java | 2 +- .../codingapi/flow/session/FlowSession.java | 63 ++++++--- .../flow/script/ErrorTriggerScriptTest.java | 2 +- 13 files changed, 213 insertions(+), 130 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index 24c6c90c..31ae6057 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -72,7 +72,7 @@ public Map toMap() { } @Override - public List trigger(FlowSession flowSession, FlowRecord currentRecord) { + public List trigger(FlowSession flowSession) { return null; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java index bb3bc6da..ddbaa7f1 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java @@ -36,7 +36,7 @@ public interface IFlowAction { /** * 执行动作 */ - List trigger(FlowSession flowSession, FlowRecord currentRecord); + List trigger(FlowSession flowSession); /** * 转换为map diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java index 05fb9d1b..85ede0ac 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java @@ -29,37 +29,10 @@ public static PassAction fromMap(Map data) { return BaseAction.fromMap(data, PassAction.class); } - @Override - public boolean isDone(FlowSession session, FlowRecord currentRecord, List currentRecords) { - // 多人审批 - if (currentRecords.size() > 1) { - StrategyManager strategyManager = session.getCurrentNode().strategies(); - MultiOperatorAuditStrategy.Type multiOperatorAuditStrategyType = strategyManager.getMultiOperatorAuditStrategyType(); - // 顺序审批 - if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.SEQUENCE) { - int currentOrder = currentRecord.getNodeOrder(); - int maxNodeOrder = currentRecords.size() - 1; - return currentOrder >= maxNodeOrder; - } - // 或签 - if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.ANY) { - return true; - } - // 并签 - if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.MERGE) { - float percent = strategyManager.getMultiOperatorAuditMergePercent(); - long total = currentRecords.size(); - // 尚未办理的数量为所有待办数-1,1是当前办理的这条记录 - long todoCount = currentRecords.stream().filter(FlowRecord::isTodo).count() - 1; - long doneCount = total - todoCount; - return doneCount >= total * percent; - } - } - return true; - } @Override - public List trigger(FlowSession flowSession, FlowRecord currentRecord) { + public List trigger(FlowSession flowSession) { + FlowRecord currentRecord = flowSession.getCurrentRecord(); List records = new ArrayList<>(); if (currentRecord.isReturnRecord()) { // 退回后的流程重新提交 diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java index 5fa00f66..b2154910 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java @@ -48,7 +48,8 @@ public static RejectAction fromMap(Map data) { } @Override - public List trigger(FlowSession flowSession, FlowRecord currentRecord) { + public List trigger(FlowSession flowSession) { + FlowRecord currentRecord = flowSession.getCurrentRecord(); RejectActionScript.RejectResult rejectResult = script.execute(flowSession); IAuditNode currentNode = null; // 返回指定节点 diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index 6bccb652..987c04d0 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -3,6 +3,10 @@ import com.codingapi.flow.action.*; import com.codingapi.flow.action.factory.FlowActionFactory; import com.codingapi.flow.error.ErrorThrow; +import com.codingapi.flow.event.FlowRecordDoneEvent; +import com.codingapi.flow.event.FlowRecordFinishEvent; +import com.codingapi.flow.event.FlowRecordTodoEvent; +import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.form.permission.PermissionType; @@ -11,13 +15,20 @@ import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.node.manager.OperatorManager; import com.codingapi.flow.node.manager.StrategyManager; +import com.codingapi.flow.operator.IFlowOperator; +import com.codingapi.flow.record.FlowRecord; +import com.codingapi.flow.repository.FlowRecordRepository; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; import com.codingapi.flow.session.FlowAdvice; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.strategy.INodeStrategy; +import com.codingapi.flow.strategy.MultiOperatorAuditStrategy; import com.codingapi.flow.strategy.NodeStrategyFactory; +import com.codingapi.flow.utils.RandomUtils; +import com.codingapi.flow.workflow.Workflow; +import com.codingapi.springboot.framework.event.EventPusher; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; @@ -222,6 +233,116 @@ public StrategyManager strategies() { return new StrategyManager(nodeStrategies); } + + @Override + public void execute(FlowSession session, FlowRecordRepository flowRecordRepository){ + List flowEvents = new ArrayList<>(); + FlowRecord flowRecord = session.getCurrentRecord(); + IFlowAction flowAction = session.getCurrentAction(); + List currentRecords = session.getCurrentNodeRecords(); + + // 判断当前节点是否已经完成 + boolean done = this.isDone(session); + if (done) { + List records = flowAction.trigger(session); + if (!records.isEmpty()) { + for (FlowRecord record : records) { + if (record.isShow()) { + flowEvents.add(new FlowRecordTodoEvent(record)); + } + } + } + flowRecord.update(session.getFormData().toMapData(), session.getAdvice().getAdvice(), session.getAdvice().getSignKey(), true); + // 判断是否结束 + if (records.size() == 1) { + FlowRecord record = records.get(0); + if (record.isNodeType(EndNode.NODE_TYPE)) { + boolean flowFinish = flowAction instanceof PassAction; + // 添加当前节点到记录中 + records.add(flowRecord); + // 添加历史记录到记录中 + List historyRecords = flowRecordRepository.findRecordsByProcessId(flowRecord.getProcessId()); + records.addAll(historyRecords); + // 设置状态为完成 + records.forEach(item -> { + item.finish(flowFinish); + }); + + // 流程是否正常结束 + if (flowFinish) { + flowEvents.add(new FlowRecordFinishEvent(record)); + } + } + // 添加流程结束事件 + flowEvents.add(new FlowRecordDoneEvent(record)); + } + flowRecordRepository.saveAll(records); + } else { + // 判断是否为串行多操作者 + if (this.strategies().isSequenceMultiOperator()) { + int nextRecordNodeOrder = flowRecord.getNodeOrder() + 1; + FlowRecord nextRecord = currentRecords.stream().filter(record -> record.getNodeOrder() == nextRecordNodeOrder).findFirst().orElse(null); + if (nextRecord != null) { + // 展示下一个审批人的待办 + nextRecord.show(); + flowEvents.add(new FlowRecordTodoEvent(nextRecord)); + flowRecordRepository.save(nextRecord); + } + } + flowRecord.update(session.getFormData().toMapData(), session.getAdvice().getAdvice(), session.getAdvice().getSignKey(), false); + flowRecordRepository.save(flowRecord); + } + + // 推送待办事件 + for (IFlowEvent event : flowEvents) { + EventPusher.push(event); + } + + } + + + public boolean isDone(FlowSession session) { + List currentRecords = session.getCurrentNodeRecords(); + FlowRecord currentRecord = session.getCurrentRecord(); + // 多人审批 + if (currentRecords.size() > 1) { + StrategyManager strategyManager = this.strategies(); + MultiOperatorAuditStrategy.Type multiOperatorAuditStrategyType = strategyManager.getMultiOperatorAuditStrategyType(); + // 顺序审批 + if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.SEQUENCE) { + int currentOrder = currentRecord.getNodeOrder(); + int maxNodeOrder = currentRecords.size() - 1; + return currentOrder >= maxNodeOrder; + } + // 或签 + if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.ANY) { + return true; + } + // 并签 + if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.MERGE) { + float percent = strategyManager.getMultiOperatorAuditMergePercent(); + long total = currentRecords.size(); + // 尚未办理的数量为所有待办数-1,1是当前办理的这条记录 + long todoCount = currentRecords.stream().filter(FlowRecord::isTodo).count() - 1; + long doneCount = total - todoCount; + return doneCount >= total * percent; + } + } + return true; + } + + @Override + public void verifySession(FlowSession session) { + FlowRecord flowRecord = session.getCurrentRecord(); + Workflow workflow = session.getWorkflow(); + // 数据验证 + FieldPermissionManager fieldPermissionManager = this.formFieldsPermissions(); + fieldPermissionManager.verifyFormData(workflow.getForm(),flowRecord.getFormData(),session.getFormData().toMapData()); + + // 节点请求验证 + this.verifyFlowAdvice(session.getAdvice()); + } + @Override public void verifyFlowAdvice(FlowAdvice flowAdvice) { StrategyManager strategyManager = this.strategies(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 889a5354..e500c3f5 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -1,6 +1,9 @@ package com.codingapi.flow.node; +import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.branch.RouterBranchNode; +import com.codingapi.flow.record.FlowRecord; +import com.codingapi.flow.repository.FlowRecordRepository; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.workflow.Workflow; import lombok.AllArgsConstructor; @@ -8,6 +11,7 @@ import lombok.Setter; import java.util.List; +import java.util.Map; @AllArgsConstructor public abstract class BaseFlowNode implements IFlowNode { @@ -35,4 +39,20 @@ public List nextNodes(FlowSession session) { return workflow.edgeNext(this); } } + + + @Override + public void verify(FormMeta form) { + + } + + @Override + public void execute(FlowSession session, FlowRecordRepository flowRecordRepository) { + + } + + @Override + public void verifySession(FlowSession session) { + + } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index 051b2980..839ac5c5 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -1,6 +1,7 @@ package com.codingapi.flow.node; import com.codingapi.flow.form.FormMeta; +import com.codingapi.flow.repository.FlowRecordRepository; import com.codingapi.flow.session.FlowSession; import java.util.List; @@ -44,4 +45,13 @@ public interface IFlowNode { */ List nextNodes(FlowSession session); + /** + * 执行节点 + */ + void execute(FlowSession session, FlowRecordRepository flowRecordRepository); + + /** + * 节点验证会话 + */ + void verifySession(FlowSession session); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/ApprovalNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/ApprovalNode.java index d179358c..64682b62 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/ApprovalNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/ApprovalNode.java @@ -7,9 +7,12 @@ import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.node.builder.AuditNodeBuilder; import com.codingapi.flow.node.BaseAuditNode; +import com.codingapi.flow.node.manager.StrategyManager; +import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; +import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.strategy.*; import com.codingapi.flow.utils.RandomUtils; @@ -58,6 +61,7 @@ private static List defaultActions() { } + public static ApprovalNode formMap(Map map) { return BaseAuditNode.formMap(map, ApprovalNode.class); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java index ec562abc..e50f861b 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java @@ -1,5 +1,6 @@ package com.codingapi.flow.record; +import com.codingapi.flow.node.IAuditNode; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.session.FlowSession; import lombok.Getter; @@ -160,7 +161,7 @@ public FlowRecord(FlowSession flowSession, String actionId, String processId, lo this.formData = flowSession.getFormData().toMapData(); this.fromId = fromId; this.nodeOrder = nodeOrder; - this.title = flowSession.getCurrentNode().generateTitle(flowSession); + this.title = ((IAuditNode)flowSession.getCurrentNode()).generateTitle(flowSession); this.processId = processId; this.createOperatorId = flowSession.getCreatedOperator().getUserId(); this.recordState = SATE_RECORD_TODO; @@ -171,8 +172,8 @@ public FlowRecord(FlowSession flowSession, String actionId, String processId, lo this.signKey = flowSession.getAdvice().getSignKey(); this.flowState = SATE_FLOW_RUNNING; this.createTime = System.currentTimeMillis(); - this.timeoutTime = flowSession.getCurrentNode().strategies().getTimeoutTime(); - this.mergeable = flowSession.getCurrentNode().strategies().isMergeable(); + this.timeoutTime = ((IAuditNode)flowSession.getCurrentNode()).strategies().getTimeoutTime(); + this.mergeable = ((IAuditNode)flowSession.getCurrentNode()).strategies().isMergeable(); this.isInterfere = flowSession.getWorkflow().isInterfere(); this.hidden = false; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java index 7a4f979a..6b6e69cb 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java @@ -1,15 +1,9 @@ package com.codingapi.flow.service.impl; import com.codingapi.flow.action.IFlowAction; -import com.codingapi.flow.action.PassAction; import com.codingapi.flow.backup.WorkflowBackup; -import com.codingapi.flow.event.FlowRecordDoneEvent; -import com.codingapi.flow.event.FlowRecordFinishEvent; -import com.codingapi.flow.event.FlowRecordTodoEvent; -import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.form.FormData; import com.codingapi.flow.gateway.FlowOperatorGateway; -import com.codingapi.flow.node.fixed.EndNode; import com.codingapi.flow.node.IAuditNode; import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.operator.IFlowOperator; @@ -20,10 +14,8 @@ import com.codingapi.flow.session.FlowAdvice; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.workflow.Workflow; -import com.codingapi.springboot.framework.event.EventPusher; import lombok.AllArgsConstructor; -import java.util.ArrayList; import java.util.List; @AllArgsConstructor @@ -72,75 +64,15 @@ public void action() { // 构建表单数据 FormData formData = new FormData(workflow.getForm()); formData.reset(request.getFormData()); - FlowAdvice flowAdvice = request.toFlowAdvice(workflow,flowAction); - // 数据验证 - FieldPermissionManager fieldPermissionManager = currentNode.formFieldsPermissions(); - fieldPermissionManager.verifyFormData(workflow.getForm(),flowRecord.getFormData(),request.getFormData()); - - // 节点验证 - currentNode.verifyFlowAdvice(flowAdvice); - List currentRecords = flowRecordRepository.findRecordsByFromId(flowRecord.getFromId()); - FlowSession session = new FlowSession(currentOperator, workflow.getForm(), workflow, currentNode, formData, workflowBackup.getId(),flowAdvice); + FlowSession session = new FlowSession(currentOperator, workflow, currentNode,flowAction, formData,flowRecord,currentRecords, workflowBackup.getId(),flowAdvice); - List flowEvents = new ArrayList<>(); + currentNode.verifySession(session); - // 判断当前节点是否已经完成 - boolean done = flowAction.isDone(session, flowRecord, currentRecords); - if (done) { - List records = flowAction.trigger(session, flowRecord); - if (!records.isEmpty()) { - for (FlowRecord record : records) { - if (record.isShow()) { - flowEvents.add(new FlowRecordTodoEvent(record)); - } - } - } - flowRecord.update(formData.toMapData(), request.getAdvice().getAdvice(), request.getAdvice().getSignKey(), true); - // 判断是否结束 - if (records.size() == 1) { - FlowRecord record = records.get(0); - if (record.isNodeType(EndNode.NODE_TYPE)) { - boolean flowFinish = flowAction instanceof PassAction; - // 添加当前节点到记录中 - records.add(flowRecord); - // 添加历史记录到记录中 - List historyRecords = flowRecordRepository.findRecordsByProcessId(flowRecord.getProcessId()); - records.addAll(historyRecords); - // 设置状态为完成 - records.forEach(item -> { - item.finish(flowFinish); - }); - // 流程是否正常结束 - if (flowFinish) { - flowEvents.add(new FlowRecordFinishEvent(record)); - } - } - // 添加流程结束事件 - flowEvents.add(new FlowRecordDoneEvent(record)); - } - flowRecordRepository.saveAll(records); - } else { - // 判断是否为串行多操作者 - if (currentNode.strategies().isSequenceMultiOperator()) { - int nextRecordNodeOrder = flowRecord.getNodeOrder() + 1; - FlowRecord nextRecord = currentRecords.stream().filter(record -> record.getNodeOrder() == nextRecordNodeOrder).findFirst().orElse(null); - if (nextRecord != null) { - // 展示下一个审批人的待办 - nextRecord.show(); - flowEvents.add(new FlowRecordTodoEvent(nextRecord)); - flowRecordRepository.save(nextRecord); - } - } - flowRecord.update(formData.toMapData(), request.getAdvice().getAdvice(), request.getAdvice().getSignKey(), false); - flowRecordRepository.save(flowRecord); - } + currentNode.execute(session,flowRecordRepository); - // 推送待办事件 - for (IFlowEvent event : flowEvents) { - EventPusher.push(event); - } } } + diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java index 91093ff8..54294ffb 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java @@ -57,7 +57,7 @@ public void create() { formData.reset(request.getFormData()); IAuditNode currentNode = workflow.getStartNode(); - FlowSession session = new FlowSession(currentOperator, workflow.getForm(), workflow, currentNode, formData, workflowBackup.getId()); + FlowSession session = FlowSession.startSession(currentOperator, workflow, currentNode, formData, workflowBackup.getId()); OperatorManager currentOperators = currentNode.operators(session); if (!currentOperators.match(currentOperator)) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java index 1b2c2ad0..b8c06540 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java @@ -1,10 +1,11 @@ package com.codingapi.flow.session; +import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.form.FormData; -import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.IAuditNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.operator.IFlowOperator; +import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.workflow.Workflow; import lombok.Getter; @@ -20,10 +21,6 @@ public class FlowSession { * 当前操作者 */ private final IFlowOperator currentOperator; - /** - * 当前流程表单 - */ - private final FormMeta formMeta; /** * 当前流程设计 */ @@ -31,7 +28,22 @@ public class FlowSession { /** * 当前流程节点 */ - private final IAuditNode currentNode; + private final IFlowNode currentNode; + + /** + * 当前流程动作 + */ + private final IFlowAction currentAction; + + /** + * 当前审批流程记录 + */ + private final FlowRecord currentRecord; + + /** + * 当前节点的流程记录 + */ + private final List currentNodeRecords; /** * 当前流程表单数据 @@ -48,20 +60,36 @@ public class FlowSession { private final FlowAdvice advice; - public FlowSession(IFlowOperator currentOperator, FormMeta formMeta, Workflow workflow, IAuditNode currentNode, FormData formData, long backupId) { - this(currentOperator, formMeta, workflow, currentNode, formData, backupId, FlowAdvice.nullFlowAdvice()); - } - - public FlowSession(IFlowOperator currentOperator, FormMeta formMeta, Workflow workflow, IAuditNode currentNode, FormData formData, long backupId, FlowAdvice advice) { + public FlowSession(IFlowOperator currentOperator, + Workflow workflow, + IFlowNode currentNode, + IFlowAction currentAction, + FormData formData, + FlowRecord currentRecord, + List currentNodeRecords, + long backupId, + FlowAdvice advice) { this.currentOperator = currentOperator; - this.formMeta = formMeta; this.workflow = workflow; + this.currentAction = currentAction; this.currentNode = currentNode; + this.currentRecord = currentRecord; + this.currentNodeRecords = currentNodeRecords; this.formData = formData; this.backupId = backupId; this.advice = advice; } + + public static FlowSession startSession(IFlowOperator currentOperator, + Workflow workflow, + IAuditNode currentNode, + FormData formData, + long backupId) { + return new FlowSession(currentOperator, workflow, currentNode, null,formData, null,null, backupId, new FlowAdvice()); + } + + /** * 获取流程的创建者 */ @@ -69,13 +97,6 @@ public IFlowOperator getCreatedOperator() { return workflow.getCreatedOperator(); } - /** - * 获取流程的开始节点 - */ - public IFlowNode getStartNode() { - return workflow.getStartNode(); - } - public String getWorkCode() { return workflow.getCode(); } @@ -101,10 +122,10 @@ public Object getFormData(String fieldName) { } public FlowSession updateSession(IAuditNode currentNode) { - return new FlowSession(currentOperator, formMeta, workflow, currentNode, formData, backupId, advice); + return new FlowSession(currentOperator, workflow, currentNode,currentAction, formData,currentRecord, currentNodeRecords, backupId, advice); } public FlowSession updateSession(IFlowOperator currentOperator) { - return new FlowSession(currentOperator, formMeta, workflow, currentNode, formData, backupId, advice); + return new FlowSession(currentOperator, workflow, currentNode,currentAction, formData,currentRecord, currentNodeRecords, backupId, advice); } } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java index ddf94290..d67f196e 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java @@ -66,7 +66,7 @@ void execute() { FormData data = new FormData(form); data.getDataBody().set("name", "张三").set("days", 10).set("reason", "事由"); - FlowSession flowSession = new FlowSession(user, form, workflow, startNode, data, 0); + FlowSession flowSession = FlowSession.startSession(user, workflow, startNode, data, 0); ErrorTriggerScript errorNodeTriggerScript = ErrorTriggerScript.defaultNodeScript(); ErrorThrow errorThrow = errorNodeTriggerScript.execute(flowSession); From 122cedf60d6f105a5af2b4b42b77259915d8558f Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 16:43:31 +0800 Subject: [PATCH 02/21] add dev --- .../com/codingapi/flow/node/BaseAuditNode.java | 3 +-- .../codingapi/flow/node/BaseBranchNode.java | 2 +- .../codingapi/flow/node/BaseConfigNode.java | 2 +- .../com/codingapi/flow/node/BaseFlowNode.java | 15 ++++++++++++--- .../com/codingapi/flow/node/IAuditNode.java | 9 +-------- .../com/codingapi/flow/node/IFlowNode.java | 18 +++++++++++++++++- .../codingapi/flow/service/FlowService.java | 2 ++ .../codingapi/flow/session/FlowSession.java | 2 +- .../com/codingapi/flow/workflow/Workflow.java | 13 +++++++------ 9 files changed, 43 insertions(+), 23 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index 987c04d0..3b366b5a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -220,7 +220,7 @@ public void addAction(IFlowAction action) { } @Override - public void verify(FormMeta form) { + public void verifyNode(FormMeta form) { this.verifyFields(); if (!(this instanceof EndNode)) { FieldPermissionManager fieldPermissionManager = this.formFieldsPermissions(); @@ -343,7 +343,6 @@ public void verifySession(FlowSession session) { this.verifyFlowAdvice(session.getAdvice()); } - @Override public void verifyFlowAdvice(FlowAdvice flowAdvice) { StrategyManager strategyManager = this.strategies(); IFlowAction flowAction = flowAdvice.getAction(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java index d6716f5e..d7664b5c 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java @@ -54,7 +54,7 @@ public int order() { } @Override - public void verify(FormMeta form) { + public void verifyNode(FormMeta form) { this.verifyFields(); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java index 39ff2756..15a657ff 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java @@ -15,7 +15,7 @@ public BaseConfigNode(String id, String name) { } @Override - public void verify(FormMeta form) { + public void verifyNode(FormMeta form) { this.verifyFields(); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index e500c3f5..af9e489e 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -11,7 +11,6 @@ import lombok.Setter; import java.util.List; -import java.util.Map; @AllArgsConstructor public abstract class BaseFlowNode implements IFlowNode { @@ -36,13 +35,13 @@ public List nextNodes(FlowSession session) { if(this instanceof RouterBranchNode routerBranchNode){ return routerBranchNode.matchRouters(session); }else { - return workflow.edgeNext(this); + return workflow.nextNodes(this); } } @Override - public void verify(FormMeta form) { + public void verifyNode(FormMeta form) { } @@ -55,4 +54,14 @@ public void execute(FlowSession session, FlowRecordRepository flowRecordReposito public void verifySession(FlowSession session) { } + + @Override + public boolean continueNode(FlowSession session) { + return true; + } + + @Override + public List generateNextRecords(FlowSession session) { + return List.of(); + } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java index 65060492..4cb8c7cc 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java @@ -6,7 +6,6 @@ import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.node.manager.OperatorManager; import com.codingapi.flow.node.manager.StrategyManager; -import com.codingapi.flow.session.FlowAdvice; import com.codingapi.flow.session.FlowSession; /** @@ -40,7 +39,7 @@ public interface IAuditNode extends IFlowNode { OperatorManager operators(FlowSession flowSession); /** - * 构建待办标题z + * 构建待办标题 */ String generateTitle(FlowSession flowSession); @@ -54,10 +53,4 @@ public interface IAuditNode extends IFlowNode { */ StrategyManager strategies(); - /** - * 校验提交参数 - * @param flowAdvice 请求参数 - */ - void verifyFlowAdvice(FlowAdvice flowAdvice); - } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index 839ac5c5..43c5f3ea 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -1,6 +1,7 @@ package com.codingapi.flow.node; import com.codingapi.flow.form.FormMeta; +import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.repository.FlowRecordRepository; import com.codingapi.flow.session.FlowSession; @@ -35,7 +36,7 @@ public interface IFlowNode { /** * 节点验证 */ - void verify(FormMeta form); + void verifyNode(FormMeta form); /** @@ -54,4 +55,19 @@ public interface IFlowNode { * 节点验证会话 */ void verifySession(FlowSession session); + + /** + * 节点是否继续 + * @param session 会话 + * @return 节点是否继续 + */ + boolean continueNode(FlowSession session); + + + /** + * 生成下一个节点记录 + * @param session 会话 + * @return 下一个节点记录 + */ + List generateNextRecords(FlowSession session); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java index b3765e88..55fd0a70 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java @@ -9,10 +9,12 @@ import com.codingapi.flow.service.impl.FlowCreateService; import com.codingapi.flow.service.impl.FlowActionService; import lombok.AllArgsConstructor; +import org.springframework.context.annotation.Configuration; /** * 流程服务 */ +@Configuration @AllArgsConstructor public class FlowService { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java index b8c06540..6eabe3e5 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java @@ -114,7 +114,7 @@ public String getCurrentNodeType() { } public List nextNodes() { - return workflow.nextNodes(this); + return workflow.generateNodes(this); } public Object getFormData(String fieldName) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java index 8fa00de2..91990132 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java @@ -9,6 +9,7 @@ import com.codingapi.flow.node.IConfigNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.node.audit.StartNode; +import com.codingapi.flow.node.branch.RouterBranchNode; import com.codingapi.flow.node.fixed.EndNode; import com.codingapi.flow.node.factory.NodeFactory; import com.codingapi.flow.operator.IFlowOperator; @@ -273,7 +274,7 @@ private void verifyNodes() { } for (IFlowNode node : nodes) { - node.verify(form); + node.verifyNode(form); } } @@ -285,7 +286,7 @@ private void verifyEdges() { } IFlowNode startNode = this.nodes.stream().filter(node -> node instanceof StartNode).findFirst().get(); - List nextNodes = edgeNext(startNode); + List nextNodes = nextNodes(startNode); for (IFlowNode nextNode : nextNodes) { this.verifyNextEdge(nextNode); } @@ -295,7 +296,7 @@ private void verifyNextEdge(IFlowNode node) { if (node instanceof EndNode) { return; } else { - List nextNodes = edgeNext(node); + List nextNodes = nextNodes(node); if (nextNodes.isEmpty()) { throw new IllegalArgumentException("workflow edges must have one end edge"); } @@ -306,13 +307,13 @@ private void verifyNextEdge(IFlowNode node) { } - public List edgeNext(IFlowNode node) { + public List nextNodes(IFlowNode node) { return edges.stream().filter(edge -> edge.getFrom().equals(node.getId())) .map(edge -> nodes.stream().filter(item -> item.getId().equals(edge.getTo())).findFirst().get()).toList(); } - public List nextNodes(FlowSession session) { - List nodeList = edgeNext(session.getCurrentNode()); + public List generateNodes(FlowSession session) { + List nodeList = nextNodes(session.getCurrentNode()); return this.loadNextAuditNodes(nodeList, session); } From c0ac36d8a355c86d226b414c1f41713e01ae369c Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 17:35:53 +0800 Subject: [PATCH 03/21] add dev --- .../com/codingapi/flow/action/BaseAction.java | 57 +++------------ .../codingapi/flow/action/IFlowAction.java | 6 +- .../com/codingapi/flow/action/PassAction.java | 19 +++-- .../codingapi/flow/action/RejectAction.java | 11 ++- .../flow/context/RepositoryContext.java | 53 ++++++++++++++ .../codingapi/flow/node/BaseAuditNode.java | 70 ++++++++++++++----- .../codingapi/flow/node/BaseBranchNode.java | 10 +-- .../codingapi/flow/node/BaseConfigNode.java | 13 ++-- .../com/codingapi/flow/node/BaseFlowNode.java | 28 +++----- .../com/codingapi/flow/node/IAuditNode.java | 56 --------------- .../com/codingapi/flow/node/IBranchNode.java | 22 ------ .../com/codingapi/flow/node/IConfigNode.java | 17 ----- .../com/codingapi/flow/node/IFlowNode.java | 29 ++++---- .../node/branch/BranchNodeBranchNode.java | 2 +- .../flow/pojo/request/FlowActionRequest.java | 2 +- .../com/codingapi/flow/record/FlowRecord.java | 9 ++- .../flow/service/impl/FlowActionService.java | 16 +++-- .../flow/service/impl/FlowCreateService.java | 5 +- .../codingapi/flow/session/FlowSession.java | 9 ++- .../com/codingapi/flow/workflow/Workflow.java | 44 +----------- 20 files changed, 186 insertions(+), 292 deletions(-) create mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java delete mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java delete mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/IBranchNode.java delete mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/IConfigNode.java diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index 31ae6057..97c4a367 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -1,17 +1,11 @@ package com.codingapi.flow.action; -import com.codingapi.flow.node.IAuditNode; -import com.codingapi.flow.node.manager.OperatorManager; -import com.codingapi.flow.node.manager.StrategyManager; -import com.codingapi.flow.operator.IFlowOperator; +import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; -import com.codingapi.flow.strategy.MultiOperatorAuditStrategy; -import com.codingapi.flow.utils.RandomUtils; import lombok.Getter; import lombok.SneakyThrows; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -72,7 +66,7 @@ public Map toMap() { } @Override - public List trigger(FlowSession flowSession) { + public List generateRecords(FlowSession flowSession) { return null; } @@ -96,47 +90,14 @@ protected static T fromMap(Map data, Clas } - /** - * 生成下一节点的记录 - * - * @param currentNode 当前节点 - * @param triggerSession 触发会话 - * @param currentRecord 当前记录 - * @return 下一节节点的记录 - */ - protected List generateNextRecords(IAuditNode currentNode, FlowSession triggerSession, FlowRecord currentRecord) { - List records = new ArrayList<>(); - OperatorManager operatorManager = currentNode.operators(triggerSession); - List operators = operatorManager.getOperators(); - for (int order = 0; order < operators.size(); order++) { - IFlowOperator operator = operators.get(order); - FlowRecord flowRecord = new FlowRecord(triggerSession.updateSession(operator), this.id, currentRecord.getProcessId(), currentRecord.getId(), order); - records.add(flowRecord); - } - if (operators.size() > 1) { - StrategyManager strategyManager = currentNode.strategies(); - MultiOperatorAuditStrategy.Type multiOperatorAuditStrategyType = strategyManager.getMultiOperatorAuditStrategyType(); - // 如果是顺序审批,则隐藏掉后续的人员的审批记录 - if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.SEQUENCE) { - for (int i = 1; i < records.size(); i++) { - FlowRecord record = records.get(i); - record.hidden(); - } - } - // 如果是随机审批,则隐藏掉后续的人员的审批记录 - if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.RANDOM_ONE) { - int index = RandomUtils.randomInt(operators.size()); - - List newRecords = new ArrayList<>(); - for (FlowRecord record : records) { - if (record.getNodeOrder() == index) { - record.resetNodeOrder(0); - newRecords.add(record); - } - } - return newRecords; + @Override + public void triggerNode(FlowSession flowSession) { + List nextNodes = flowSession.nextNodes(); + for (IFlowNode node : nextNodes) { + FlowSession triggerSession = flowSession.updateSession(node); + if (node.trigger(triggerSession)) { + this.triggerNode(triggerSession); } } - return records; } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java index ddbaa7f1..1fa7a026 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java @@ -1,7 +1,6 @@ package com.codingapi.flow.action; -import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; @@ -36,13 +35,16 @@ public interface IFlowAction { /** * 执行动作 */ - List trigger(FlowSession flowSession); + List generateRecords(FlowSession flowSession); /** * 转换为map */ Map toMap(); + + void triggerNode(FlowSession flowSession); + /** * 流程是否结束 * diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java index 85ede0ac..086f2ab9 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java @@ -1,11 +1,10 @@ package com.codingapi.flow.action; -import com.codingapi.flow.node.IAuditNode; +import com.codingapi.flow.node.BaseAuditNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.node.manager.StrategyManager; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; -import com.codingapi.flow.strategy.MultiOperatorAuditStrategy; import com.codingapi.flow.utils.RandomUtils; import java.util.ArrayList; @@ -14,7 +13,7 @@ /** - * 通过 + * 通过 */ public class PassAction extends BaseAction { @@ -31,29 +30,27 @@ public static PassAction fromMap(Map data) { @Override - public List trigger(FlowSession flowSession) { + public List generateRecords(FlowSession flowSession) { FlowRecord currentRecord = flowSession.getCurrentRecord(); List records = new ArrayList<>(); if (currentRecord.isReturnRecord()) { // 退回后的流程重新提交 - IAuditNode currentNode = flowSession.getWorkflow().getAuditNode(currentRecord.getReturnNodeId()); + BaseAuditNode currentNode = (BaseAuditNode)flowSession.getWorkflow().getFlowNode(currentRecord.getReturnNodeId()); StrategyManager strategyManager = currentNode.strategies(); // 是否退回到退回节点 if (strategyManager.isResume()) { FlowSession triggerSession = flowSession.updateSession(currentNode); - List nextRecords = this.generateNextRecords(currentNode, triggerSession.updateSession(currentNode), currentRecord); + List nextRecords = currentNode.generateNextRecords(triggerSession.updateSession(currentNode)); records.addAll(nextRecords); } } else { - List nextNodes = flowSession.nextNodes(); - for (IAuditNode node : nextNodes) { - //TODO 如果是条件节点,则自动完成当前记录,并构建下一个记录 - List nextRecords = this.generateNextRecords(node, flowSession.updateSession(node), currentRecord); + IFlowNode currentNode = flowSession.getCurrentNode(); + List nextRecords = currentNode.generateNextRecords(flowSession); + if (!nextRecords.isEmpty()) { records.addAll(nextRecords); } } return records; } - } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java index b2154910..46f6c371 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java @@ -1,6 +1,5 @@ package com.codingapi.flow.action; -import com.codingapi.flow.node.IAuditNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.script.action.RejectActionScript; @@ -48,14 +47,14 @@ public static RejectAction fromMap(Map data) { } @Override - public List trigger(FlowSession flowSession) { + public List generateRecords(FlowSession flowSession) { FlowRecord currentRecord = flowSession.getCurrentRecord(); RejectActionScript.RejectResult rejectResult = script.execute(flowSession); - IAuditNode currentNode = null; + IFlowNode currentNode = null; // 返回指定节点 if (rejectResult.isReturnNode()) { String nodeId = rejectResult.getNodeId(); - currentNode = flowSession.getWorkflow().getAuditNode(nodeId); + currentNode = flowSession.getWorkflow().getFlowNode(nodeId); } // 流程结束(非正常) if (rejectResult.isTerminate()) { @@ -68,13 +67,13 @@ public List trigger(FlowSession flowSession) { if (preRecord == null) { throw new IllegalArgumentException("preRecord is null"); } - currentNode = flowSession.getWorkflow().getAuditNode(preRecord.getNodeId()); + currentNode = flowSession.getWorkflow().getFlowNode(preRecord.getNodeId()); } if (currentNode == null) { throw new IllegalArgumentException("currentNode is null"); } FlowSession triggerSession = flowSession.updateSession(currentNode); - return this.generateNextRecords(currentNode, triggerSession, currentRecord); + return currentNode.generateNextRecords(triggerSession); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java new file mode 100644 index 00000000..fa3320f1 --- /dev/null +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java @@ -0,0 +1,53 @@ +package com.codingapi.flow.context; + +import com.codingapi.flow.gateway.FlowOperatorGateway; +import com.codingapi.flow.operator.IFlowOperator; +import com.codingapi.flow.record.FlowRecord; +import com.codingapi.flow.repository.FlowRecordRepository; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +public class RepositoryContext { + + @Getter + private final static RepositoryContext instance = new RepositoryContext(); + + private RepositoryContext() { + } + + @Setter + private FlowRecordRepository flowRecordRepository; + @Setter + private FlowOperatorGateway flowOperatorGateway; + + public FlowRecord getRecordById(long id) { + return flowRecordRepository.get(id); + } + + public List findOperatorByIds(List ids) { + return flowOperatorGateway.findByIds(ids); + } + + public List findOperatorByIds(long... ids) { + return flowOperatorGateway.findByIds(ids); + } + + public void saveRecord(FlowRecord flowRecord) { + flowRecordRepository.save(flowRecord); + } + + public void saveRecords(List flowRecords) { + flowRecordRepository.saveAll(flowRecords); + } + + public List findRecordsByFromId(long fromId) { + return flowRecordRepository.findRecordsByFromId(fromId); + } + + public List findRecordsByProcessId(String processId) { + return flowRecordRepository.findRecordsByProcessId(processId); + } + +} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index 3b366b5a..4fc360cc 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -2,6 +2,7 @@ import com.codingapi.flow.action.*; import com.codingapi.flow.action.factory.FlowActionFactory; +import com.codingapi.flow.context.RepositoryContext; import com.codingapi.flow.error.ErrorThrow; import com.codingapi.flow.event.FlowRecordDoneEvent; import com.codingapi.flow.event.FlowRecordFinishEvent; @@ -17,7 +18,6 @@ import com.codingapi.flow.node.manager.StrategyManager; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.record.FlowRecord; -import com.codingapi.flow.repository.FlowRecordRepository; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; @@ -39,7 +39,7 @@ import java.util.List; import java.util.Map; -public abstract class BaseAuditNode extends BaseFlowNode implements IAuditNode{ +public abstract class BaseAuditNode extends BaseFlowNode implements IFlowNode { public static final String DEFAULT_VIEW = "default"; @@ -185,33 +185,27 @@ public void setErrorTriggerScript(String errorTriggerScript) { } - @Override public FieldPermissionManager formFieldsPermissions() { return new FieldPermissionManager(formFieldPermissions); } - @Override public ActionManager actions() { return new ActionManager(actions); } - @Override public OperatorManager operators(FlowSession flowSession) { return new OperatorManager(operatorScript.execute(flowSession)); } - @Override public String generateTitle(FlowSession flowSession) { return nodeTitleScript.execute(flowSession); } - @Override public ErrorThrow errorTrigger(FlowSession flowSession) { return errorTriggerScript.execute(flowSession); } - @Override public void addAction(IFlowAction action) { if(this.actions == null){ this.actions = new ArrayList<>(); @@ -219,7 +213,6 @@ public void addAction(IFlowAction action) { this.actions.add(action); } - @Override public void verifyNode(FormMeta form) { this.verifyFields(); if (!(this instanceof EndNode)) { @@ -228,14 +221,13 @@ public void verifyNode(FormMeta form) { } } - @Override public StrategyManager strategies() { return new StrategyManager(nodeStrategies); } @Override - public void execute(FlowSession session, FlowRecordRepository flowRecordRepository){ + public boolean trigger(FlowSession session){ List flowEvents = new ArrayList<>(); FlowRecord flowRecord = session.getCurrentRecord(); IFlowAction flowAction = session.getCurrentAction(); @@ -244,7 +236,7 @@ public void execute(FlowSession session, FlowRecordRepository flowRecordReposito // 判断当前节点是否已经完成 boolean done = this.isDone(session); if (done) { - List records = flowAction.trigger(session); + List records = flowAction.generateRecords(session); if (!records.isEmpty()) { for (FlowRecord record : records) { if (record.isShow()) { @@ -261,7 +253,7 @@ public void execute(FlowSession session, FlowRecordRepository flowRecordReposito // 添加当前节点到记录中 records.add(flowRecord); // 添加历史记录到记录中 - List historyRecords = flowRecordRepository.findRecordsByProcessId(flowRecord.getProcessId()); + List historyRecords = RepositoryContext.getInstance().findRecordsByProcessId(flowRecord.getProcessId()); records.addAll(historyRecords); // 设置状态为完成 records.forEach(item -> { @@ -276,7 +268,7 @@ public void execute(FlowSession session, FlowRecordRepository flowRecordReposito // 添加流程结束事件 flowEvents.add(new FlowRecordDoneEvent(record)); } - flowRecordRepository.saveAll(records); + RepositoryContext.getInstance().saveRecords(records); } else { // 判断是否为串行多操作者 if (this.strategies().isSequenceMultiOperator()) { @@ -286,11 +278,11 @@ public void execute(FlowSession session, FlowRecordRepository flowRecordReposito // 展示下一个审批人的待办 nextRecord.show(); flowEvents.add(new FlowRecordTodoEvent(nextRecord)); - flowRecordRepository.save(nextRecord); + RepositoryContext.getInstance().saveRecord(nextRecord); } } flowRecord.update(session.getFormData().toMapData(), session.getAdvice().getAdvice(), session.getAdvice().getSignKey(), false); - flowRecordRepository.save(flowRecord); + RepositoryContext.getInstance().saveRecord(flowRecord); } // 推送待办事件 @@ -298,6 +290,7 @@ public void execute(FlowSession session, FlowRecordRepository flowRecordReposito EventPusher.push(event); } + return false; } @@ -331,6 +324,51 @@ public boolean isDone(FlowSession session) { return true; } + + /** + * 生成下一节点的记录 + * + * @param session 触发会话 + * @return 下一节节点的记录 + */ + @Override + public List generateNextRecords(FlowSession session) { + List records = new ArrayList<>(); + FlowRecord currentRecord = session.getCurrentRecord(); + OperatorManager operatorManager = this.operators(session); + List operators = operatorManager.getOperators(); + for (int order = 0; order < operators.size(); order++) { + IFlowOperator operator = operators.get(order); + FlowRecord flowRecord = new FlowRecord(session.updateSession(operator), this.id, currentRecord.getProcessId(), currentRecord.getId(), order); + records.add(flowRecord); + } + if (operators.size() > 1) { + StrategyManager strategyManager = this.strategies(); + MultiOperatorAuditStrategy.Type multiOperatorAuditStrategyType = strategyManager.getMultiOperatorAuditStrategyType(); + // 如果是顺序审批,则隐藏掉后续的人员的审批记录 + if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.SEQUENCE) { + for (int i = 1; i < records.size(); i++) { + FlowRecord record = records.get(i); + record.hidden(); + } + } + // 如果是随机审批,则隐藏掉后续的人员的审批记录 + if (multiOperatorAuditStrategyType == MultiOperatorAuditStrategy.Type.RANDOM_ONE) { + int index = RandomUtils.randomInt(operators.size()); + + List newRecords = new ArrayList<>(); + for (FlowRecord record : records) { + if (record.getNodeOrder() == index) { + record.resetNodeOrder(0); + newRecords.add(record); + } + } + return newRecords; + } + } + return records; + } + @Override public void verifySession(FlowSession session) { FlowRecord flowRecord = session.getCurrentRecord(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java index d7664b5c..fc616f1f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java @@ -1,7 +1,6 @@ package com.codingapi.flow.node; import com.codingapi.flow.form.FormMeta; -import com.codingapi.flow.session.FlowSession; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; @@ -10,7 +9,7 @@ import java.util.HashMap; import java.util.Map; -public abstract class BaseBranchNode extends BaseFlowNode implements IBranchNode { +public abstract class BaseBranchNode extends BaseFlowNode implements IFlowNode { public BaseBranchNode(String id, String name) { super(id, name); @@ -43,12 +42,7 @@ public static T formMap(Map map, Clas return node; } - @Override - public boolean match(FlowSession flowSession) { - return true; - } - @Override public int order() { return order; } @@ -58,7 +52,7 @@ public void verifyNode(FormMeta form) { this.verifyFields(); } - private void verifyFields () { + private void verifyFields() { if (!StringUtils.hasText(name)) { throw new IllegalArgumentException("name can not be null"); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java index 15a657ff..45211032 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java @@ -1,14 +1,15 @@ package com.codingapi.flow.node; import com.codingapi.flow.form.FormMeta; -import com.codingapi.flow.session.FlowSession; +import com.codingapi.flow.node.manager.ActionManager; import lombok.SneakyThrows; import org.springframework.util.StringUtils; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -public abstract class BaseConfigNode extends BaseFlowNode implements IConfigNode { +public abstract class BaseConfigNode extends BaseFlowNode implements IFlowNode { public BaseConfigNode(String id, String name) { super(id, name); @@ -28,10 +29,6 @@ private void verifyFields() { } } - @Override - public void execute(FlowSession flowSession) { - - } @Override public Map toMap() { @@ -51,4 +48,8 @@ public static T formMap(Map map, Clas return node; } + @Override + public ActionManager actions() { + return new ActionManager(new ArrayList<>()); + } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index af9e489e..168ac709 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -1,15 +1,14 @@ package com.codingapi.flow.node; import com.codingapi.flow.form.FormMeta; -import com.codingapi.flow.node.branch.RouterBranchNode; +import com.codingapi.flow.node.manager.ActionManager; import com.codingapi.flow.record.FlowRecord; -import com.codingapi.flow.repository.FlowRecordRepository; import com.codingapi.flow.session.FlowSession; -import com.codingapi.flow.workflow.Workflow; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; +import java.util.ArrayList; import java.util.List; @AllArgsConstructor @@ -29,25 +28,14 @@ public abstract class BaseFlowNode implements IFlowNode { protected String name; - @Override - public List nextNodes(FlowSession session) { - Workflow workflow = session.getWorkflow(); - if(this instanceof RouterBranchNode routerBranchNode){ - return routerBranchNode.matchRouters(session); - }else { - return workflow.nextNodes(this); - } - } - - @Override public void verifyNode(FormMeta form) { } @Override - public void execute(FlowSession session, FlowRecordRepository flowRecordRepository) { - + public boolean trigger(FlowSession session) { + return true; } @Override @@ -56,12 +44,12 @@ public void verifySession(FlowSession session) { } @Override - public boolean continueNode(FlowSession session) { - return true; + public List generateNextRecords(FlowSession session) { + return List.of(); } @Override - public List generateNextRecords(FlowSession session) { - return List.of(); + public ActionManager actions() { + return new ActionManager(new ArrayList<>()); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java deleted file mode 100644 index 4cb8c7cc..00000000 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IAuditNode.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.codingapi.flow.node; - -import com.codingapi.flow.action.IFlowAction; -import com.codingapi.flow.error.ErrorThrow; -import com.codingapi.flow.node.manager.ActionManager; -import com.codingapi.flow.node.manager.FieldPermissionManager; -import com.codingapi.flow.node.manager.OperatorManager; -import com.codingapi.flow.node.manager.StrategyManager; -import com.codingapi.flow.session.FlowSession; - -/** - * 审批节点 - */ -public interface IAuditNode extends IFlowNode { - - /** - * 节点视图 - */ - String getView(); - - /** - * 添加节点动作 - */ - void addAction(IFlowAction action); - - /** - * 节点动作 - */ - ActionManager actions(); - - /** - * 表单字段权限设置 - */ - FieldPermissionManager formFieldsPermissions(); - - /** - * 节点参与用户 - */ - OperatorManager operators(FlowSession flowSession); - - /** - * 构建待办标题 - */ - String generateTitle(FlowSession flowSession); - - /** - * 错误异常处理 - */ - ErrorThrow errorTrigger(FlowSession flowSession); - - /** - * 节点策略 - */ - StrategyManager strategies(); - -} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IBranchNode.java deleted file mode 100644 index 7ac7ffad..00000000 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IBranchNode.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.codingapi.flow.node; - -import com.codingapi.flow.session.FlowSession; - -/** - * 条件节点 - */ -public interface IBranchNode extends IFlowNode{ - - /** - * 匹配节点 - * @param flowSession 流程会话 - * @return 是否匹配 - */ - boolean match(FlowSession flowSession); - - /** - * 顺序 - */ - int order(); - -} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IConfigNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IConfigNode.java deleted file mode 100644 index c7e76641..00000000 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IConfigNode.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.codingapi.flow.node; - -import com.codingapi.flow.session.FlowSession; - -/** - * 配置节点 - * 包括:子流程节点、延迟节点、触发节点 - */ -public interface IConfigNode extends IFlowNode { - - /** - * 执行配置任务,子流程节点、触发节点 执行任务以后要继续执行下一环节 - * @param flowSession 当前会话 - */ - void execute(FlowSession flowSession); - -} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index 43c5f3ea..d2c30e52 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -1,8 +1,8 @@ package com.codingapi.flow.node; import com.codingapi.flow.form.FormMeta; +import com.codingapi.flow.node.manager.ActionManager; import com.codingapi.flow.record.FlowRecord; -import com.codingapi.flow.repository.FlowRecordRepository; import com.codingapi.flow.session.FlowSession; import java.util.List; @@ -38,36 +38,31 @@ public interface IFlowNode { */ void verifyNode(FormMeta form); - - /** - * 获取下一个节点列表 - * @param session 会话 - * @return 下一个节点列表 - */ - List nextNodes(FlowSession session); - /** * 执行节点 + * @param session 会话 + * @return true: 继续执行下一个节点 */ - void execute(FlowSession session, FlowRecordRepository flowRecordRepository); + boolean trigger(FlowSession session); /** * 节点验证会话 */ void verifySession(FlowSession session); + /** - * 节点是否继续 + * 构建当前节点下的流程记录 * @param session 会话 - * @return 节点是否继续 + * @return 流程记录 */ - boolean continueNode(FlowSession session); + List generateNextRecords(FlowSession session); /** - * 生成下一个节点记录 - * @param session 会话 - * @return 下一个节点记录 + * 获取节点操作 + * @return 节点操作 */ - List generateNextRecords(FlowSession session); + ActionManager actions(); + } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/BranchNodeBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/BranchNodeBranchNode.java index 908a77da..c1047bee 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/BranchNodeBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/BranchNodeBranchNode.java @@ -39,7 +39,7 @@ public BranchNodeBranchNode() { * 匹配条件 */ @Override - public boolean match(FlowSession request) { + public boolean trigger(FlowSession request) { return conditionScript.execute(request); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/pojo/request/FlowActionRequest.java b/flow-engine-framework/src/main/java/com/codingapi/flow/pojo/request/FlowActionRequest.java index eb803390..8c302f18 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/pojo/request/FlowActionRequest.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/pojo/request/FlowActionRequest.java @@ -39,7 +39,7 @@ public FlowAdvice toFlowAdvice(Workflow workflow, IFlowAction flowAction) { flowAdvice.setTransferOperators(GatewayContext.getInstance().findByIds(advice.getTransferOperatorIds())); } if (StringUtils.hasText(advice.getBackNodeId())) { - flowAdvice.setBackNode(workflow.getAuditNode(advice.getBackNodeId())); + flowAdvice.setBackNode(workflow.getFlowNode(advice.getBackNodeId())); } return flowAdvice; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java index e50f861b..20d64290 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java @@ -1,7 +1,6 @@ package com.codingapi.flow.record; -import com.codingapi.flow.node.IAuditNode; -import com.codingapi.flow.operator.IFlowOperator; +import com.codingapi.flow.node.BaseAuditNode; import com.codingapi.flow.session.FlowSession; import lombok.Getter; import lombok.Setter; @@ -161,7 +160,7 @@ public FlowRecord(FlowSession flowSession, String actionId, String processId, lo this.formData = flowSession.getFormData().toMapData(); this.fromId = fromId; this.nodeOrder = nodeOrder; - this.title = ((IAuditNode)flowSession.getCurrentNode()).generateTitle(flowSession); + this.title = ((BaseAuditNode)flowSession.getCurrentNode()).generateTitle(flowSession); this.processId = processId; this.createOperatorId = flowSession.getCreatedOperator().getUserId(); this.recordState = SATE_RECORD_TODO; @@ -172,8 +171,8 @@ public FlowRecord(FlowSession flowSession, String actionId, String processId, lo this.signKey = flowSession.getAdvice().getSignKey(); this.flowState = SATE_FLOW_RUNNING; this.createTime = System.currentTimeMillis(); - this.timeoutTime = ((IAuditNode)flowSession.getCurrentNode()).strategies().getTimeoutTime(); - this.mergeable = ((IAuditNode)flowSession.getCurrentNode()).strategies().isMergeable(); + this.timeoutTime = ((BaseAuditNode)flowSession.getCurrentNode()).strategies().getTimeoutTime(); + this.mergeable = ((BaseAuditNode)flowSession.getCurrentNode()).strategies().isMergeable(); this.isInterfere = flowSession.getWorkflow().isInterfere(); this.hidden = false; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java index 6b6e69cb..a8139845 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java @@ -2,10 +2,10 @@ import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.backup.WorkflowBackup; +import com.codingapi.flow.context.RepositoryContext; import com.codingapi.flow.form.FormData; import com.codingapi.flow.gateway.FlowOperatorGateway; -import com.codingapi.flow.node.IAuditNode; -import com.codingapi.flow.node.manager.FieldPermissionManager; +import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.pojo.request.FlowActionRequest; import com.codingapi.flow.record.FlowRecord; @@ -27,6 +27,9 @@ public class FlowActionService { private final WorkflowBackupRepository workflowBackupRepository; public void action() { + RepositoryContext.getInstance().setFlowRecordRepository(flowRecordRepository); + RepositoryContext.getInstance().setFlowOperatorGateway(flowOperatorGateway); + request.verify(); // 验证当前用户 IFlowOperator currentOperator = flowOperatorGateway.get(request.getAdvice().getOperatorId()); @@ -52,7 +55,7 @@ public void action() { } Workflow workflow = workflowBackup.toWorkflow(); - IAuditNode currentNode = workflow.getAuditNode(flowRecord.getNodeId()); + IFlowNode currentNode = workflow.getFlowNode(flowRecord.getNodeId()); if (currentNode == null) { throw new IllegalArgumentException("currentNode not exist"); } @@ -64,14 +67,13 @@ public void action() { // 构建表单数据 FormData formData = new FormData(workflow.getForm()); formData.reset(request.getFormData()); - FlowAdvice flowAdvice = request.toFlowAdvice(workflow,flowAction); + FlowAdvice flowAdvice = request.toFlowAdvice(workflow, flowAction); List currentRecords = flowRecordRepository.findRecordsByFromId(flowRecord.getFromId()); - FlowSession session = new FlowSession(currentOperator, workflow, currentNode,flowAction, formData,flowRecord,currentRecords, workflowBackup.getId(),flowAdvice); + FlowSession session = new FlowSession(currentOperator, workflow, currentNode, flowAction, formData, flowRecord, currentRecords, workflowBackup.getId(), flowAdvice); currentNode.verifySession(session); - - currentNode.execute(session,flowRecordRepository); + flowAction.triggerNode(session); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java index 54294ffb..5da996fb 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java @@ -7,8 +7,7 @@ import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.form.FormData; import com.codingapi.flow.gateway.FlowOperatorGateway; -import com.codingapi.flow.node.IAuditNode; -import com.codingapi.flow.node.IFlowNode; +import com.codingapi.flow.node.audit.StartNode; import com.codingapi.flow.node.manager.OperatorManager; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.pojo.request.FlowCreateRequest; @@ -56,7 +55,7 @@ public void create() { FormData formData = new FormData(workflow.getForm()); formData.reset(request.getFormData()); - IAuditNode currentNode = workflow.getStartNode(); + StartNode currentNode = (StartNode) workflow.getStartNode(); FlowSession session = FlowSession.startSession(currentOperator, workflow, currentNode, formData, workflowBackup.getId()); OperatorManager currentOperators = currentNode.operators(session); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java index 6eabe3e5..f787c6db 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java @@ -2,7 +2,6 @@ import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.form.FormData; -import com.codingapi.flow.node.IAuditNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.record.FlowRecord; @@ -83,7 +82,7 @@ public FlowSession(IFlowOperator currentOperator, public static FlowSession startSession(IFlowOperator currentOperator, Workflow workflow, - IAuditNode currentNode, + IFlowNode currentNode, FormData formData, long backupId) { return new FlowSession(currentOperator, workflow, currentNode, null,formData, null,null, backupId, new FlowAdvice()); @@ -113,15 +112,15 @@ public String getCurrentNodeType() { return currentNode.getType(); } - public List nextNodes() { - return workflow.generateNodes(this); + public List nextNodes() { + return workflow.nextNodes(this.getCurrentNode()); } public Object getFormData(String fieldName) { return formData.getDataBody().get(fieldName); } - public FlowSession updateSession(IAuditNode currentNode) { + public FlowSession updateSession(IFlowNode currentNode) { return new FlowSession(currentOperator, workflow, currentNode,currentAction, formData,currentRecord, currentNodeRecords, backupId, advice); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java index 91990132..3dbde66a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java @@ -4,17 +4,12 @@ import com.codingapi.flow.context.GatewayContext; import com.codingapi.flow.edge.FlowEdge; import com.codingapi.flow.form.FormMeta; -import com.codingapi.flow.node.IAuditNode; -import com.codingapi.flow.node.IBranchNode; -import com.codingapi.flow.node.IConfigNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.node.audit.StartNode; -import com.codingapi.flow.node.branch.RouterBranchNode; import com.codingapi.flow.node.fixed.EndNode; import com.codingapi.flow.node.factory.NodeFactory; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.script.node.OperatorMatchScript; -import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; import lombok.AllArgsConstructor; import lombok.Getter; @@ -306,57 +301,24 @@ private void verifyNextEdge(IFlowNode node) { } } - public List nextNodes(IFlowNode node) { return edges.stream().filter(edge -> edge.getFrom().equals(node.getId())) .map(edge -> nodes.stream().filter(item -> item.getId().equals(edge.getTo())).findFirst().get()).toList(); } - public List generateNodes(FlowSession session) { - List nodeList = nextNodes(session.getCurrentNode()); - return this.loadNextAuditNodes(nodeList, session); - } - - - private List loadNextAuditNodes(List nodeList, FlowSession session) { - List auditNodeList = new ArrayList<>(); - for (IFlowNode node : nodeList) { - // 审批节点 - if (node instanceof IAuditNode) { - auditNodeList.add((IAuditNode) node); - } - // 配置节点 - if (node instanceof IConfigNode) { - ((IConfigNode) node).execute(session); - } - if (node instanceof IBranchNode) { - if (((IBranchNode) node).match(session)) { - List nextNodes = node.nextNodes(session); - auditNodeList.addAll(this.loadNextAuditNodes(nextNodes, session)); - } - } - } - return auditNodeList; - } - - - public IAuditNode getAuditNode(String nodeId) { + public IFlowNode getFlowNode(String nodeId) { return nodes.stream() - .filter(node -> node instanceof IAuditNode) .filter(node -> node.getId().equals(nodeId)) - .map(node -> (IAuditNode) node) .findFirst().orElse(null); } - public IAuditNode getStartNode() { + public IFlowNode getStartNode() { return nodes.stream().filter(node -> node instanceof StartNode) - .map(node -> (IAuditNode) node) .findFirst().orElse(null); } - public IAuditNode getEndNode() { + public IFlowNode getEndNode() { return nodes.stream().filter(node -> node instanceof EndNode) - .map(node -> (IAuditNode) node) .findFirst().orElse(null); } } From 9bd719c70b0de0860068ad747c3dbd997b94ad62 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 18:01:12 +0800 Subject: [PATCH 04/21] add dev --- .../codingapi/flow/node/BaseAuditNode.java | 43 ++++++--------- .../codingapi/flow/node/BaseBranchNode.java | 6 +- .../codingapi/flow/node/BaseConfigNode.java | 55 ------------------- .../com/codingapi/flow/node/BaseFlowNode.java | 44 ++++++++++++++- .../flow/node/builder/BaseNodeBuilder.java | 34 ++++++++++++ .../flow/node/builder/ConfigNodeBuilder.java | 27 --------- .../flow/node/factory/NodeFactory.java | 21 ++++--- .../node/{audit => nodes}/ApprovalNode.java | 11 ++-- .../BranchNodeBranchNode.java | 5 +- .../node/{config => nodes}/DelayNode.java | 15 ++--- .../flow/node/{fixed => nodes}/EndNode.java | 8 +-- .../node/{audit => nodes}/HandleNode.java | 8 +-- .../InclusiveBranchNode.java | 5 +- .../node/{audit => nodes}/NotifyNode.java | 8 +-- .../{branch => nodes}/ParallelBranchNode.java | 5 +- .../{branch => nodes}/RouterBranchNode.java | 7 ++- .../flow/node/{audit => nodes}/StartNode.java | 8 +-- .../{config => nodes}/SubProcessNode.java | 15 ++--- .../node/{config => nodes}/TriggerNode.java | 15 ++--- .../flow/service/impl/FlowCreateService.java | 2 +- .../com/codingapi/flow/workflow/Workflow.java | 4 +- .../flow/script/ErrorTriggerScriptTest.java | 6 +- .../flow/service/FlowServiceTest.java | 8 +-- .../flow/workflow/WorkflowBuilderTest.java | 6 +- 24 files changed, 180 insertions(+), 186 deletions(-) delete mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java create mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java delete mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/ConfigNodeBuilder.java rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{audit => nodes}/ApprovalNode.java (73%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{branch => nodes}/BranchNodeBranchNode.java (94%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{config => nodes}/DelayNode.java (62%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{fixed => nodes}/EndNode.java (75%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{audit => nodes}/HandleNode.java (75%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{branch => nodes}/InclusiveBranchNode.java (90%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{audit => nodes}/NotifyNode.java (75%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{branch => nodes}/ParallelBranchNode.java (90%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{branch => nodes}/RouterBranchNode.java (86%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{audit => nodes}/StartNode.java (75%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{config => nodes}/SubProcessNode.java (62%) rename flow-engine-framework/src/main/java/com/codingapi/flow/node/{config => nodes}/TriggerNode.java (62%) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index 4fc360cc..a8caae60 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -11,11 +11,11 @@ import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.form.permission.PermissionType; -import com.codingapi.flow.node.fixed.EndNode; import com.codingapi.flow.node.manager.ActionManager; import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.node.manager.OperatorManager; import com.codingapi.flow.node.manager.StrategyManager; +import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.script.node.ErrorTriggerScript; @@ -71,12 +71,6 @@ public abstract class BaseAuditNode extends BaseFlowNode implements IFlowNode { @Setter private List formFieldPermissions; - /** - * 节点操作 - */ - @Setter - private List actions; - /** * 节点策略 */ @@ -84,23 +78,22 @@ public abstract class BaseAuditNode extends BaseFlowNode implements IFlowNode { private List nodeStrategies; - public BaseAuditNode(String id, String name, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldPermissions, List actions, List nodeStrategies) { - super(id, name); + public BaseAuditNode(String id, String name, List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldPermissions, List nodeStrategies) { + super(id, name, actions); this.view = view; this.operatorScript = operatorScript; this.nodeTitleScript = nodeTitleScript; this.errorTriggerScript = errorTriggerScript; this.formFieldPermissions = formFieldPermissions; - this.actions = actions; this.nodeStrategies = nodeStrategies; } @Override public Map toMap() { Map map = new HashMap<>(); - map.put("view", view); map.put("name", name); map.put("id", id); + map.put("view", view); map.put("operatorScript", operatorScript.getScript()); map.put("nodeTitleScript", nodeTitleScript.getScript()); map.put("errorTriggerScript", errorTriggerScript.getScript()); @@ -207,7 +200,7 @@ public ErrorThrow errorTrigger(FlowSession flowSession) { } public void addAction(IFlowAction action) { - if(this.actions == null){ + if (this.actions == null) { this.actions = new ArrayList<>(); } this.actions.add(action); @@ -215,10 +208,8 @@ public void addAction(IFlowAction action) { public void verifyNode(FormMeta form) { this.verifyFields(); - if (!(this instanceof EndNode)) { - FieldPermissionManager fieldPermissionManager = this.formFieldsPermissions(); - fieldPermissionManager.verifyPermissions(form); - } + FieldPermissionManager fieldPermissionManager = this.formFieldsPermissions(); + fieldPermissionManager.verifyPermissions(form); } public StrategyManager strategies() { @@ -227,7 +218,7 @@ public StrategyManager strategies() { @Override - public boolean trigger(FlowSession session){ + public boolean trigger(FlowSession session) { List flowEvents = new ArrayList<>(); FlowRecord flowRecord = session.getCurrentRecord(); IFlowAction flowAction = session.getCurrentAction(); @@ -375,7 +366,7 @@ public void verifySession(FlowSession session) { Workflow workflow = session.getWorkflow(); // 数据验证 FieldPermissionManager fieldPermissionManager = this.formFieldsPermissions(); - fieldPermissionManager.verifyFormData(workflow.getForm(),flowRecord.getFormData(),session.getFormData().toMapData()); + fieldPermissionManager.verifyFormData(workflow.getForm(), flowRecord.getFormData(), session.getFormData().toMapData()); // 节点请求验证 this.verifyFlowAdvice(session.getAdvice()); @@ -386,32 +377,32 @@ public void verifyFlowAdvice(FlowAdvice flowAdvice) { IFlowAction flowAction = flowAdvice.getAction(); // 保存操作,不做检查 - if(flowAction instanceof SaveAction){ + if (flowAction instanceof SaveAction) { return; } // 转办操作 - if(flowAction instanceof TransferAction){ - if(flowAdvice.getTransferOperators()==null || flowAdvice.getTransferOperators().isEmpty()){ + if (flowAction instanceof TransferAction) { + if (flowAdvice.getTransferOperators() == null || flowAdvice.getTransferOperators().isEmpty()) { throw new IllegalArgumentException("transferOperators can not be null"); } } // 退回操作 - if(flowAction instanceof ReturnAction){ - if(flowAdvice.getBackNode()==null ){ + if (flowAction instanceof ReturnAction) { + if (flowAdvice.getBackNode() == null) { throw new IllegalArgumentException("backNode can not be null"); } } // 是否必须填写审批意见 - if(strategyManager.isEnableAdvice()){ - if(!StringUtils.hasText(flowAdvice.getAdvice())){ + if (strategyManager.isEnableAdvice()) { + if (!StringUtils.hasText(flowAdvice.getAdvice())) { throw new IllegalArgumentException("advice can not be null"); } } // 通过操作 - if(flowAction instanceof PassAction) { + if (flowAction instanceof PassAction) { // 是否必须签名 if (strategyManager.isEnableSignable()) { if (!StringUtils.hasText(flowAdvice.getSignKey())) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java index fc616f1f..38c28b88 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java @@ -1,5 +1,6 @@ package com.codingapi.flow.node; +import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.form.FormMeta; import lombok.Getter; import lombok.Setter; @@ -7,12 +8,13 @@ import org.springframework.util.StringUtils; import java.util.HashMap; +import java.util.List; import java.util.Map; public abstract class BaseBranchNode extends BaseFlowNode implements IFlowNode { - public BaseBranchNode(String id, String name) { - super(id, name); + public BaseBranchNode(String id, String name, List actions) { + super(id, name,actions); } /** diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java deleted file mode 100644 index 45211032..00000000 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseConfigNode.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.codingapi.flow.node; - -import com.codingapi.flow.form.FormMeta; -import com.codingapi.flow.node.manager.ActionManager; -import lombok.SneakyThrows; -import org.springframework.util.StringUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public abstract class BaseConfigNode extends BaseFlowNode implements IFlowNode { - - public BaseConfigNode(String id, String name) { - super(id, name); - } - - @Override - public void verifyNode(FormMeta form) { - this.verifyFields(); - } - - private void verifyFields() { - if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("name can not be null"); - } - if (!StringUtils.hasText(id)) { - throw new IllegalArgumentException("id can not be null"); - } - } - - - @Override - public Map toMap() { - Map map = new HashMap<>(); - map.put("name", name); - map.put("id", id); - map.put("type", getType()); - return map; - } - - - @SneakyThrows - public static T formMap(Map map, Class clazz) { - T node = clazz.getDeclaredConstructor().newInstance(); - node.setId((String) map.get("id")); - node.setName((String) map.get("name")); - return node; - } - - @Override - public ActionManager actions() { - return new ActionManager(new ArrayList<>()); - } -} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 168ac709..f8fc0a8b 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -1,5 +1,7 @@ package com.codingapi.flow.node; +import com.codingapi.flow.action.IFlowAction; +import com.codingapi.flow.action.factory.FlowActionFactory; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.manager.ActionManager; import com.codingapi.flow.record.FlowRecord; @@ -7,9 +9,12 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; +import lombok.SneakyThrows; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @AllArgsConstructor public abstract class BaseFlowNode implements IFlowNode { @@ -27,6 +32,43 @@ public abstract class BaseFlowNode implements IFlowNode { @Setter protected String name; + /** + * 节点操作 + */ + @Setter + @Getter + protected List actions; + + + @Override + public Map toMap() { + Map map = new HashMap<>(); + map.put("name", name); + map.put("id", id); + map.put("type", getType()); + map.put("actions", actions.stream().map(IFlowAction::toMap).toList()); + return map; + } + + + @SneakyThrows + @SuppressWarnings("unchecked") + public static T loadFromMap(Map map, Class clazz) { + T node = clazz.getDeclaredConstructor().newInstance(); + node.setId((String) map.get("id")); + node.setName((String) map.get("name")); + List> actions = (List>) map.get("actions"); + if (actions != null) { + List actionList = new ArrayList<>(); + for (Map item : actions) { + IFlowAction action = FlowActionFactory.getInstance().createAction(item); + actionList.add(action); + } + node.setActions(actionList); + } + return node; + } + @Override public void verifyNode(FormMeta form) { @@ -50,6 +92,6 @@ public List generateNextRecords(FlowSession session) { @Override public ActionManager actions() { - return new ActionManager(new ArrayList<>()); + return new ActionManager(actions); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java new file mode 100644 index 00000000..772db36a --- /dev/null +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java @@ -0,0 +1,34 @@ +package com.codingapi.flow.node.builder; + +import com.codingapi.flow.action.IFlowAction; +import com.codingapi.flow.node.BaseFlowNode; + +import java.util.List; + +public abstract class BaseNodeBuilder, N extends BaseFlowNode> { + + private final N node; + + public BaseNodeBuilder(N node) { + this.node = node; + } + + public B id(String id) { + node.setId(id); + return (B)this; + } + + public B actions(List actions) { + node.setActions(actions); + return (B)this; + } + + public B name(String name) { + node.setName(name); + return (B)this; + } + + public N build() { + return node; + } +} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/ConfigNodeBuilder.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/ConfigNodeBuilder.java deleted file mode 100644 index 27ef1d48..00000000 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/ConfigNodeBuilder.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.codingapi.flow.node.builder; - -import com.codingapi.flow.node.BaseConfigNode; - -public abstract class ConfigNodeBuilder, N extends BaseConfigNode> { - - protected final N node; - - public ConfigNodeBuilder(N node) { - this.node = node; - } - - public B id(String id) { - node.setId(id); - return (B)this; - } - - public B name(String name) { - node.setName(name); - return (B)this; - } - - public N build() { - return node; - } - -} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/factory/NodeFactory.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/factory/NodeFactory.java index 88650ee1..451e3074 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/factory/NodeFactory.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/factory/NodeFactory.java @@ -1,15 +1,18 @@ package com.codingapi.flow.node.factory; import com.codingapi.flow.node.IFlowNode; -import com.codingapi.flow.node.audit.*; -import com.codingapi.flow.node.branch.BranchNodeBranchNode; -import com.codingapi.flow.node.branch.InclusiveBranchNode; -import com.codingapi.flow.node.branch.ParallelBranchNode; -import com.codingapi.flow.node.branch.RouterBranchNode; -import com.codingapi.flow.node.config.DelayNode; -import com.codingapi.flow.node.config.SubProcessNode; -import com.codingapi.flow.node.config.TriggerNode; -import com.codingapi.flow.node.fixed.EndNode; +import com.codingapi.flow.node.nodes.BranchNodeBranchNode; +import com.codingapi.flow.node.nodes.InclusiveBranchNode; +import com.codingapi.flow.node.nodes.ParallelBranchNode; +import com.codingapi.flow.node.nodes.RouterBranchNode; +import com.codingapi.flow.node.nodes.DelayNode; +import com.codingapi.flow.node.nodes.SubProcessNode; +import com.codingapi.flow.node.nodes.TriggerNode; +import com.codingapi.flow.node.nodes.EndNode; +import com.codingapi.flow.node.nodes.ApprovalNode; +import com.codingapi.flow.node.nodes.HandleNode; +import com.codingapi.flow.node.nodes.NotifyNode; +import com.codingapi.flow.node.nodes.StartNode; import lombok.Getter; import lombok.SneakyThrows; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/ApprovalNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ApprovalNode.java similarity index 73% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/ApprovalNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ApprovalNode.java index 64682b62..e70f1e8f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/ApprovalNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ApprovalNode.java @@ -1,4 +1,4 @@ -package com.codingapi.flow.node.audit; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.action.PassAction; @@ -7,12 +7,9 @@ import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.node.builder.AuditNodeBuilder; import com.codingapi.flow.node.BaseAuditNode; -import com.codingapi.flow.node.manager.StrategyManager; -import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; -import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.strategy.*; import com.codingapi.flow.utils.RandomUtils; @@ -33,12 +30,12 @@ public String getType() { return NODE_TYPE; } - public ApprovalNode(String id, String name, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List actions, List nodeStrategies) { - super(id, name, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, actions, nodeStrategies); + public ApprovalNode(String id, String name,List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { + super(id, name, actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); } public ApprovalNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME, DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultActions(), defaultStrategies()); + this(RandomUtils.generateStringId(), DEFAULT_NAME,defaultActions(), DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultStrategies()); } private static List defaultStrategies() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/BranchNodeBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java similarity index 94% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/BranchNodeBranchNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java index c1047bee..a9a9602f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/BranchNodeBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java @@ -1,4 +1,4 @@ -package com.codingapi.flow.node.branch; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.node.BaseBranchNode; import com.codingapi.flow.node.builder.BranchNodeBuilder; @@ -6,6 +6,7 @@ import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import java.util.ArrayList; import java.util.Map; /** @@ -27,7 +28,7 @@ public String getType() { } public BranchNodeBranchNode(String id, String name) { - super(id, name); + super(id, name,new ArrayList<>()); this.conditionScript = ConditionScript.defaultScript(); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/config/DelayNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java similarity index 62% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/config/DelayNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java index 5a6bf5eb..f81716b7 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/config/DelayNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java @@ -1,15 +1,16 @@ -package com.codingapi.flow.node.config; +package com.codingapi.flow.node.nodes; -import com.codingapi.flow.node.BaseConfigNode; -import com.codingapi.flow.node.builder.ConfigNodeBuilder; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; +import java.util.ArrayList; import java.util.Map; /** * 延迟节点 */ -public class DelayNode extends BaseConfigNode { +public class DelayNode extends BaseFlowNode { public static final String NODE_TYPE = "delay"; public static final String DEFAULT_NAME = "延迟节点"; @@ -21,7 +22,7 @@ public String getType() { public DelayNode(String id, String name) { - super(id, name); + super(id, name,new ArrayList<>()); } public DelayNode() { @@ -29,14 +30,14 @@ public DelayNode() { } public static DelayNode formMap(Map map) { - return BaseConfigNode.formMap(map, DelayNode.class); + return BaseFlowNode.loadFromMap(map, DelayNode.class); } public static Builder builder() { return new Builder(); } - public static class Builder extends ConfigNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new DelayNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/fixed/EndNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java similarity index 75% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/fixed/EndNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java index 16906663..2170e4d7 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/fixed/EndNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java @@ -1,4 +1,4 @@ -package com.codingapi.flow.node.fixed; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.action.DefaultAction; import com.codingapi.flow.action.IFlowAction; @@ -29,12 +29,12 @@ public String getType() { } - public EndNode(String id, String name, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List actions, List nodeStrategies) { - super(id, name, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, actions, nodeStrategies); + public EndNode(String id, String name, List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { + super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); } public EndNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME, DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultActions(), defaultStrategies()); + this(RandomUtils.generateStringId(), DEFAULT_NAME, defaultActions(), DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(),defaultStrategies()); } private static List defaultStrategies() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/HandleNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/HandleNode.java similarity index 75% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/HandleNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/HandleNode.java index 6ffa3549..e3b4ff78 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/HandleNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/HandleNode.java @@ -1,4 +1,4 @@ -package com.codingapi.flow.node.audit; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.action.PassAction; @@ -29,12 +29,12 @@ public String getType() { } - public HandleNode(String id, String name, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List actions, List nodeStrategies) { - super(id, name, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, actions, nodeStrategies); + public HandleNode(String id, String name,List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { + super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); } public HandleNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME, DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultActions(), defaultStrategies()); + this(RandomUtils.generateStringId(), DEFAULT_NAME, defaultActions(), DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(),new ArrayList<>(), defaultStrategies()); } private static List defaultStrategies() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/InclusiveBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/InclusiveBranchNode.java similarity index 90% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/InclusiveBranchNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/InclusiveBranchNode.java index 287e28b6..defd976e 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/InclusiveBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/InclusiveBranchNode.java @@ -1,9 +1,10 @@ -package com.codingapi.flow.node.branch; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.node.BaseBranchNode; import com.codingapi.flow.node.builder.BranchNodeBuilder; import com.codingapi.flow.utils.RandomUtils; +import java.util.ArrayList; import java.util.Map; /** @@ -21,7 +22,7 @@ public String getType() { public InclusiveBranchNode(String id, String name) { - super(id, name); + super(id, name,new ArrayList<>()); } public InclusiveBranchNode() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/NotifyNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/NotifyNode.java similarity index 75% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/NotifyNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/NotifyNode.java index f55d37d0..f504d919 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/NotifyNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/NotifyNode.java @@ -1,4 +1,4 @@ -package com.codingapi.flow.node.audit; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.action.DefaultAction; import com.codingapi.flow.action.IFlowAction; @@ -28,12 +28,12 @@ public String getType() { return NODE_TYPE; } - public NotifyNode(String id, String name, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List actions, List nodeStrategies) { - super(id, name, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, actions, nodeStrategies); + public NotifyNode(String id, String name,List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { + super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); } public NotifyNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME, DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultActions(), defaultStrategies()); + this(RandomUtils.generateStringId(), DEFAULT_NAME,defaultActions(), DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultStrategies()); } private static List defaultStrategies() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/ParallelBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java similarity index 90% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/ParallelBranchNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java index 6fcf86c0..a3426bc3 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/ParallelBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java @@ -1,9 +1,10 @@ -package com.codingapi.flow.node.branch; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.node.BaseBranchNode; import com.codingapi.flow.node.builder.BranchNodeBuilder; import com.codingapi.flow.utils.RandomUtils; +import java.util.ArrayList; import java.util.Map; /** @@ -20,7 +21,7 @@ public String getType() { } public ParallelBranchNode(String id, String name) { - super(id, name); + super(id, name,new ArrayList<>()); } public ParallelBranchNode() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/RouterBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java similarity index 86% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/RouterBranchNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java index 6bf7d99b..c0dd2b8e 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/branch/RouterBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java @@ -1,4 +1,4 @@ -package com.codingapi.flow.node.branch; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.node.BaseBranchNode; import com.codingapi.flow.node.IFlowNode; @@ -6,6 +6,7 @@ import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -24,7 +25,7 @@ public String getType() { public RouterBranchNode(String id, String name) { - super(id, name); + super(id, name, new ArrayList<>()); } public RouterBranchNode() { @@ -32,7 +33,7 @@ public RouterBranchNode() { } - public List matchRouters(FlowSession session){ + public List matchRouters(FlowSession session) { return null; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/StartNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java similarity index 75% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/StartNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java index 52435594..e2533d6b 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/audit/StartNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java @@ -1,4 +1,4 @@ -package com.codingapi.flow.node.audit; +package com.codingapi.flow.node.nodes; import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.action.PassAction; @@ -28,12 +28,12 @@ public String getType() { return NODE_TYPE; } - public StartNode(String id, String name, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List actions, List nodeStrategies) { - super(id, name, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, actions, nodeStrategies); + public StartNode(String id, String name,List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { + super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); } public StartNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME, DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultActions(), defaultStrategies()); + this(RandomUtils.generateStringId(), DEFAULT_NAME,defaultActions(), DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultStrategies()); } private static List defaultStrategies() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/config/SubProcessNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/SubProcessNode.java similarity index 62% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/config/SubProcessNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/SubProcessNode.java index e2b030a4..0eb9df55 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/config/SubProcessNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/SubProcessNode.java @@ -1,15 +1,16 @@ -package com.codingapi.flow.node.config; +package com.codingapi.flow.node.nodes; -import com.codingapi.flow.node.BaseConfigNode; -import com.codingapi.flow.node.builder.ConfigNodeBuilder; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; +import java.util.ArrayList; import java.util.Map; /** * 子流程 */ -public class SubProcessNode extends BaseConfigNode { +public class SubProcessNode extends BaseFlowNode { public static final String NODE_TYPE = "sub_process"; public static final String DEFAULT_NAME = "子流程"; @@ -20,7 +21,7 @@ public String getType() { } public SubProcessNode(String id, String name) { - super(id, name); + super(id, name,new ArrayList<>()); } public SubProcessNode() { @@ -28,14 +29,14 @@ public SubProcessNode() { } public static SubProcessNode formMap(Map map) { - return BaseConfigNode.formMap(map, SubProcessNode.class); + return BaseFlowNode.loadFromMap(map, SubProcessNode.class); } public static Builder builder() { return new Builder(); } - public static class Builder extends ConfigNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new SubProcessNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/config/TriggerNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/TriggerNode.java similarity index 62% rename from flow-engine-framework/src/main/java/com/codingapi/flow/node/config/TriggerNode.java rename to flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/TriggerNode.java index edc8e8d3..dcf93abb 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/config/TriggerNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/TriggerNode.java @@ -1,15 +1,16 @@ -package com.codingapi.flow.node.config; +package com.codingapi.flow.node.nodes; -import com.codingapi.flow.node.BaseConfigNode; -import com.codingapi.flow.node.builder.ConfigNodeBuilder; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; +import java.util.ArrayList; import java.util.Map; /** * 触发节点 */ -public class TriggerNode extends BaseConfigNode { +public class TriggerNode extends BaseFlowNode { public static final String NODE_TYPE = "trigger"; public static final String DEFAULT_NAME = "触发节点"; @@ -20,7 +21,7 @@ public String getType() { } public TriggerNode(String id, String name) { - super(id, name); + super(id, name,new ArrayList<>()); } public TriggerNode() { @@ -28,14 +29,14 @@ public TriggerNode() { } public static TriggerNode formMap(Map map) { - return BaseConfigNode.formMap(map, TriggerNode.class); + return BaseFlowNode.loadFromMap(map, TriggerNode.class); } public static Builder builder() { return new Builder(); } - public static class Builder extends ConfigNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new TriggerNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java index 5da996fb..bb39a744 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java @@ -7,7 +7,7 @@ import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.form.FormData; import com.codingapi.flow.gateway.FlowOperatorGateway; -import com.codingapi.flow.node.audit.StartNode; +import com.codingapi.flow.node.nodes.StartNode; import com.codingapi.flow.node.manager.OperatorManager; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.pojo.request.FlowCreateRequest; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java index 3dbde66a..c04d716a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java @@ -5,8 +5,8 @@ import com.codingapi.flow.edge.FlowEdge; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.IFlowNode; -import com.codingapi.flow.node.audit.StartNode; -import com.codingapi.flow.node.fixed.EndNode; +import com.codingapi.flow.node.nodes.StartNode; +import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.node.factory.NodeFactory; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.script.node.OperatorMatchScript; diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java index d67f196e..8b291f70 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java @@ -6,9 +6,9 @@ import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.FormMetaBuilder; import com.codingapi.flow.form.permission.PermissionType; -import com.codingapi.flow.node.audit.ApprovalNode; -import com.codingapi.flow.node.audit.StartNode; -import com.codingapi.flow.node.fixed.EndNode; +import com.codingapi.flow.node.nodes.ApprovalNode; +import com.codingapi.flow.node.nodes.StartNode; +import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.user.User; diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index 5e0e8204..ebf3dc65 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -7,10 +7,10 @@ import com.codingapi.flow.form.FormMetaBuilder; import com.codingapi.flow.form.permission.PermissionType; import com.codingapi.flow.gateway.impl.UserGateway; -import com.codingapi.flow.node.audit.ApprovalNode; -import com.codingapi.flow.node.audit.StartNode; -import com.codingapi.flow.node.branch.BranchNodeBranchNode; -import com.codingapi.flow.node.fixed.EndNode; +import com.codingapi.flow.node.nodes.ApprovalNode; +import com.codingapi.flow.node.nodes.StartNode; +import com.codingapi.flow.node.nodes.BranchNodeBranchNode; +import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.pojo.body.FlowAdviceBody; import com.codingapi.flow.pojo.request.FlowCreateRequest; import com.codingapi.flow.pojo.request.FlowActionRequest; diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java index 9e29b0f8..7724b842 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java @@ -5,9 +5,9 @@ import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.FormMetaBuilder; import com.codingapi.flow.form.permission.PermissionType; -import com.codingapi.flow.node.audit.ApprovalNode; -import com.codingapi.flow.node.audit.StartNode; -import com.codingapi.flow.node.fixed.EndNode; +import com.codingapi.flow.node.nodes.ApprovalNode; +import com.codingapi.flow.node.nodes.StartNode; +import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.gateway.impl.UserGateway; import com.codingapi.flow.user.User; import org.junit.jupiter.api.Test; From aec8edac70c479528f663e64c5f24d9ce26ba142 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 19:37:05 +0800 Subject: [PATCH 05/21] add dev --- .../com/codingapi/flow/action/BaseAction.java | 29 +++++++- .../com/codingapi/flow/action/PassAction.java | 50 ++++++++++++- .../codingapi/flow/action/RejectAction.java | 47 ++++++++---- .../codingapi/flow/node/BaseAuditNode.java | 72 ++----------------- .../com/codingapi/flow/node/BaseFlowNode.java | 9 ++- .../com/codingapi/flow/node/IFlowNode.java | 17 +++-- .../flow/node/nodes/BranchNodeBranchNode.java | 5 +- .../codingapi/flow/node/nodes/EndNode.java | 56 +++++++++------ .../script/action/RejectActionScript.java | 29 ++++---- .../codingapi/flow/session/FlowSession.java | 4 ++ .../flow/service/FlowServiceTest.java | 12 ++-- 11 files changed, 190 insertions(+), 140 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index 97c4a367..fea86ade 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -1,11 +1,16 @@ package com.codingapi.flow.action; +import com.codingapi.flow.context.RepositoryContext; +import com.codingapi.flow.event.FlowRecordFinishEvent; import com.codingapi.flow.node.IFlowNode; +import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; +import com.codingapi.springboot.framework.event.EventPusher; import lombok.Getter; import lombok.SneakyThrows; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -95,9 +100,31 @@ public void triggerNode(FlowSession flowSession) { List nextNodes = flowSession.nextNodes(); for (IFlowNode node : nextNodes) { FlowSession triggerSession = flowSession.updateSession(node); - if (node.trigger(triggerSession)) { + if (node.isContinueTrigger(triggerSession)) { this.triggerNode(triggerSession); } } } + + + public void flowFinish(FlowRecord latestRecord,IFlowNode latestNode){ + List recordList = new ArrayList<>(); + // 添加当前节点到记录中 + if (latestNode instanceof EndNode) { + recordList.add(latestRecord); + // 添加历史记录到记录中 + List historyRecords = RepositoryContext.getInstance().findRecordsByProcessId(latestRecord.getProcessId()); + recordList.addAll(historyRecords); + // 设置状态为完成 + recordList.forEach(item -> { + item.finish(true); + }); + + RepositoryContext.getInstance().saveRecords(recordList); + + // 流程是否正常结束 + EventPusher.push(new FlowRecordFinishEvent(latestRecord)); + } + } + } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java index 086f2ab9..a2432f01 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java @@ -1,11 +1,18 @@ package com.codingapi.flow.action; +import com.codingapi.flow.context.RepositoryContext; +import com.codingapi.flow.event.FlowRecordDoneEvent; +import com.codingapi.flow.event.FlowRecordFinishEvent; +import com.codingapi.flow.event.FlowRecordTodoEvent; +import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.node.BaseAuditNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.node.manager.StrategyManager; +import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import com.codingapi.springboot.framework.event.EventPusher; import java.util.ArrayList; import java.util.List; @@ -35,17 +42,17 @@ public List generateRecords(FlowSession flowSession) { List records = new ArrayList<>(); if (currentRecord.isReturnRecord()) { // 退回后的流程重新提交 - BaseAuditNode currentNode = (BaseAuditNode)flowSession.getWorkflow().getFlowNode(currentRecord.getReturnNodeId()); + BaseAuditNode currentNode = (BaseAuditNode) flowSession.getWorkflow().getFlowNode(currentRecord.getReturnNodeId()); StrategyManager strategyManager = currentNode.strategies(); // 是否退回到退回节点 if (strategyManager.isResume()) { FlowSession triggerSession = flowSession.updateSession(currentNode); - List nextRecords = currentNode.generateNextRecords(triggerSession.updateSession(currentNode)); + List nextRecords = currentNode.generateCurrentRecords(triggerSession.updateSession(currentNode)); records.addAll(nextRecords); } } else { IFlowNode currentNode = flowSession.getCurrentNode(); - List nextRecords = currentNode.generateNextRecords(flowSession); + List nextRecords = currentNode.generateCurrentRecords(flowSession); if (!nextRecords.isEmpty()) { records.addAll(nextRecords); } @@ -53,4 +60,41 @@ public List generateRecords(FlowSession flowSession) { return records; } + + @Override + public void triggerNode(FlowSession flowSession) { + List flowEvents = new ArrayList<>(); + List recordList = new ArrayList<>(); + FlowRecord flowRecord = flowSession.getCurrentRecord(); + IFlowNode currentNode = flowSession.getCurrentNode(); + boolean done = currentNode.isDone(flowSession); + flowRecord.update(flowSession.getFormData().toMapData(), flowSession.getAdvice().getAdvice(), flowSession.getAdvice().getSignKey(), done); + // 添加流程结束事件 + flowEvents.add(new FlowRecordDoneEvent(flowRecord)); + recordList.add(flowRecord); + + if (done) { + super.triggerNode(flowSession); + List nextNodes = flowSession.nextNodes(); + for (IFlowNode node : nextNodes) { + FlowSession triggerSession = flowSession.updateSession(node); + IFlowNode latestNode = triggerSession.getCurrentNode(); + List records = this.generateRecords(triggerSession); + if (records.isEmpty()) { + super.flowFinish(flowRecord, latestNode); + }else { + for (FlowRecord record : records) { + if (record.isShow()) { + flowEvents.add(new FlowRecordTodoEvent(record)); + } + } + recordList.addAll(records); + } + } + } + + RepositoryContext.getInstance().saveRecords(recordList); + + flowEvents.forEach(EventPusher::push); + } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java index 46f6c371..aae027c2 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java @@ -1,13 +1,17 @@ package com.codingapi.flow.action; +import com.codingapi.flow.context.RepositoryContext; +import com.codingapi.flow.event.FlowRecordTodoEvent; +import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.script.action.RejectActionScript; -import com.codingapi.flow.script.runtime.FlowScriptContext; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import com.codingapi.springboot.framework.event.EventPusher; import lombok.Getter; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -25,7 +29,7 @@ public RejectAction() { this.title = "拒绝"; this.type = ActionType.REJECT; this.display = new ActionDisplay(this.title); - this.script = RejectActionScript.defaultScript(); + this.script = RejectActionScript.startScript(); } public void setScript(String script) { @@ -48,7 +52,6 @@ public static RejectAction fromMap(Map data) { @Override public List generateRecords(FlowSession flowSession) { - FlowRecord currentRecord = flowSession.getCurrentRecord(); RejectActionScript.RejectResult rejectResult = script.execute(flowSession); IFlowNode currentNode = null; // 返回指定节点 @@ -60,20 +63,36 @@ public List generateRecords(FlowSession flowSession) { if (rejectResult.isTerminate()) { currentNode = flowSession.getWorkflow().getEndNode(); } - // 退回上级节点 - if (rejectResult.isReturnPrev()) { - long fromId = currentRecord.getFromId(); - FlowRecord preRecord = FlowScriptContext.getInstance().getRecordById(fromId); - if (preRecord == null) { - throw new IllegalArgumentException("preRecord is null"); - } - currentNode = flowSession.getWorkflow().getFlowNode(preRecord.getNodeId()); - } if (currentNode == null) { throw new IllegalArgumentException("currentNode is null"); } + flowSession = flowSession.updateSession(currentNode); + return currentNode.generateCurrentRecords(flowSession); + } + + @Override + public void triggerNode(FlowSession flowSession) { + List flowEvents = new ArrayList<>(); + List recordList = new ArrayList<>(); + + FlowRecord flowRecord = flowSession.getCurrentRecord(); + flowRecord.update(flowSession.getFormData().toMapData(), flowSession.getAdvice().getAdvice(), flowSession.getAdvice().getSignKey(), true); + recordList.add(flowRecord); + + List records = this.generateRecords(flowSession); + IFlowNode latestNode = flowSession.getCurrentNode(); + if(records.isEmpty()){ + super.flowFinish(flowRecord, latestNode); + } + recordList.addAll(records); + for (FlowRecord record : records){ + if (record.isShow()) { + flowEvents.add(new FlowRecordTodoEvent(record)); + } + } + + RepositoryContext.getInstance().saveRecords(recordList); + flowEvents.forEach(EventPusher::push); - FlowSession triggerSession = flowSession.updateSession(currentNode); - return currentNode.generateNextRecords(triggerSession); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index a8caae60..f4ae1775 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -218,73 +218,11 @@ public StrategyManager strategies() { @Override - public boolean trigger(FlowSession session) { - List flowEvents = new ArrayList<>(); - FlowRecord flowRecord = session.getCurrentRecord(); - IFlowAction flowAction = session.getCurrentAction(); - List currentRecords = session.getCurrentNodeRecords(); - - // 判断当前节点是否已经完成 - boolean done = this.isDone(session); - if (done) { - List records = flowAction.generateRecords(session); - if (!records.isEmpty()) { - for (FlowRecord record : records) { - if (record.isShow()) { - flowEvents.add(new FlowRecordTodoEvent(record)); - } - } - } - flowRecord.update(session.getFormData().toMapData(), session.getAdvice().getAdvice(), session.getAdvice().getSignKey(), true); - // 判断是否结束 - if (records.size() == 1) { - FlowRecord record = records.get(0); - if (record.isNodeType(EndNode.NODE_TYPE)) { - boolean flowFinish = flowAction instanceof PassAction; - // 添加当前节点到记录中 - records.add(flowRecord); - // 添加历史记录到记录中 - List historyRecords = RepositoryContext.getInstance().findRecordsByProcessId(flowRecord.getProcessId()); - records.addAll(historyRecords); - // 设置状态为完成 - records.forEach(item -> { - item.finish(flowFinish); - }); - - // 流程是否正常结束 - if (flowFinish) { - flowEvents.add(new FlowRecordFinishEvent(record)); - } - } - // 添加流程结束事件 - flowEvents.add(new FlowRecordDoneEvent(record)); - } - RepositoryContext.getInstance().saveRecords(records); - } else { - // 判断是否为串行多操作者 - if (this.strategies().isSequenceMultiOperator()) { - int nextRecordNodeOrder = flowRecord.getNodeOrder() + 1; - FlowRecord nextRecord = currentRecords.stream().filter(record -> record.getNodeOrder() == nextRecordNodeOrder).findFirst().orElse(null); - if (nextRecord != null) { - // 展示下一个审批人的待办 - nextRecord.show(); - flowEvents.add(new FlowRecordTodoEvent(nextRecord)); - RepositoryContext.getInstance().saveRecord(nextRecord); - } - } - flowRecord.update(session.getFormData().toMapData(), session.getAdvice().getAdvice(), session.getAdvice().getSignKey(), false); - RepositoryContext.getInstance().saveRecord(flowRecord); - } - - // 推送待办事件 - for (IFlowEvent event : flowEvents) { - EventPusher.push(event); - } - + public boolean isContinueTrigger(FlowSession session) { return false; } - + @Override public boolean isDone(FlowSession session) { List currentRecords = session.getCurrentNodeRecords(); FlowRecord currentRecord = session.getCurrentRecord(); @@ -317,13 +255,13 @@ public boolean isDone(FlowSession session) { /** - * 生成下一节点的记录 + * 生成当前节点的记录 * * @param session 触发会话 - * @return 下一节节点的记录 + * @return 生成当前节点的记录 */ @Override - public List generateNextRecords(FlowSession session) { + public List generateCurrentRecords(FlowSession session) { List records = new ArrayList<>(); FlowRecord currentRecord = session.getCurrentRecord(); OperatorManager operatorManager = this.operators(session); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index f8fc0a8b..5bb992df 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -76,7 +76,7 @@ public void verifyNode(FormMeta form) { } @Override - public boolean trigger(FlowSession session) { + public boolean isContinueTrigger(FlowSession session) { return true; } @@ -86,7 +86,12 @@ public void verifySession(FlowSession session) { } @Override - public List generateNextRecords(FlowSession session) { + public boolean isDone(FlowSession session) { + return true; + } + + @Override + public List generateCurrentRecords(FlowSession session) { return List.of(); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index d2c30e52..77bc495d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -39,25 +39,23 @@ public interface IFlowNode { void verifyNode(FormMeta form); /** - * 执行节点 + * 是否执行节点 * @param session 会话 * @return true: 继续执行下一个节点 */ - boolean trigger(FlowSession session); + boolean isContinueTrigger(FlowSession session); /** * 节点验证会话 */ void verifySession(FlowSession session); - /** - * 构建当前节点下的流程记录 + * 构建当前节点下的流程记录,不需要创建记录的返回 空集合 * @param session 会话 * @return 流程记录 */ - List generateNextRecords(FlowSession session); - + List generateCurrentRecords(FlowSession session); /** * 获取节点操作 @@ -65,4 +63,11 @@ public interface IFlowNode { */ ActionManager actions(); + /** + * 节点是否完成 + * @param session 会话 + * @return true: 节点完成 + */ + boolean isDone(FlowSession session); + } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java index a9a9602f..1fe9caf6 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java @@ -40,7 +40,7 @@ public BranchNodeBranchNode() { * 匹配条件 */ @Override - public boolean trigger(FlowSession request) { + public boolean isContinueTrigger(FlowSession request) { return conditionScript.execute(request); } @@ -70,8 +70,5 @@ public Builder conditionScript(String script) { node.conditionScript = new ConditionScript(script); return this; } - - - } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java index 2170e4d7..6840639a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java @@ -3,11 +3,14 @@ import com.codingapi.flow.action.DefaultAction; import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.form.permission.FormFieldPermission; +import com.codingapi.flow.node.BaseFlowNode; import com.codingapi.flow.node.builder.AuditNodeBuilder; import com.codingapi.flow.node.BaseAuditNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; +import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.strategy.*; import com.codingapi.flow.utils.RandomUtils; @@ -18,7 +21,7 @@ /** * 结束节点 */ -public class EndNode extends BaseAuditNode { +public class EndNode extends BaseFlowNode { public static final String NODE_TYPE = "end"; public static final String DEFAULT_NAME = "结束节点"; @@ -29,41 +32,50 @@ public String getType() { } - public EndNode(String id, String name, List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { - super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); - } +// public EndNode(String id, String name, List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { +// super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); +// } - public EndNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME, defaultActions(), DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(),defaultStrategies()); + + @Override + public boolean isContinueTrigger(FlowSession session) { + return false; } - private static List defaultStrategies() { - List strategies = new ArrayList<>(); - strategies.add(TimeoutStrategy.defaultStrategy()); - strategies.add(MultiOperatorAuditStrategy.defaultStrategy()); - strategies.add(SameOperatorAuditStrategy.defaultStrategy()); - strategies.add(RecordMergeStrategy.defaultStrategy()); - strategies.add(ResubmitStrategy.defaultStrategy()); - strategies.add(AdviceStrategy.defaultStrategy()); - return strategies; + public EndNode(String id, String name, List actions) { + super(id, name, actions); } - private static List defaultActions() { - List actions = new ArrayList<>(); - actions.add(new DefaultAction()); - return actions; + public EndNode() { + this(RandomUtils.generateStringId(), DEFAULT_NAME,new ArrayList<>()); } +// +// private static List defaultStrategies() { +// List strategies = new ArrayList<>(); +// strategies.add(TimeoutStrategy.defaultStrategy()); +// strategies.add(MultiOperatorAuditStrategy.defaultStrategy()); +// strategies.add(SameOperatorAuditStrategy.defaultStrategy()); +// strategies.add(RecordMergeStrategy.defaultStrategy()); +// strategies.add(ResubmitStrategy.defaultStrategy()); +// strategies.add(AdviceStrategy.defaultStrategy()); +// return strategies; +// } +// +// private static List defaultActions() { +// List actions = new ArrayList<>(); +// actions.add(new DefaultAction()); +// return actions; +// } public static EndNode formMap(Map map) { - return BaseAuditNode.formMap(map, EndNode.class); + return BaseFlowNode.loadFromMap(map, EndNode.class); } public static Builder builder() { return new Builder(); } - public static class Builder extends AuditNodeBuilder { - + public static class Builder extends BaseNodeBuilder { public Builder() { super(new EndNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/script/action/RejectActionScript.java b/flow-engine-framework/src/main/java/com/codingapi/flow/script/action/RejectActionScript.java index 44acd962..599f0429 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/script/action/RejectActionScript.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/script/action/RejectActionScript.java @@ -7,12 +7,13 @@ /** * 拒绝脚本 - * 拒绝,拒绝时需要根据拒绝的配置流程来设置,退回上级节点、退回指定节点、终止流程 + * 拒绝,拒绝时需要根据拒绝的配置流程来设置,退回指定节点、终止流程 */ @AllArgsConstructor public class RejectActionScript { - public static final String SCRIPT_DEFAULT = "def run(session){return new com.codingapi.flow.script.action.RejectActionScript.RejectResult('RETURN_PREV')}"; + public static final String SCRIPT_START = "def run(session){return new com.codingapi.flow.script.action.RejectActionScript.RejectResult(session.getStartNode().getId())}"; + public static final String SCRIPT_TERMINATE = "def run(session){return new com.codingapi.flow.script.action.RejectActionScript.RejectResult(\"TERMINATE\")}"; @Getter private final String script; @@ -22,16 +23,21 @@ public RejectResult execute(FlowSession session) { } /** - * 退回至上一流程 + * 退回至发起节点 */ - public static RejectActionScript defaultScript() { - return new RejectActionScript(SCRIPT_DEFAULT); + public static RejectActionScript startScript() { + return new RejectActionScript(SCRIPT_START); + } + + /** + * 终止流程 + */ + public static RejectActionScript terminateScript() { + return new RejectActionScript(SCRIPT_TERMINATE); } public enum RejectType { - // 退回上级节点 - RETURN_PREV, // 退回指定节点 RETURN_NODE, // 终止流程 @@ -43,11 +49,6 @@ public static class RejectResult { private final RejectType type; private String nodeId; - - public boolean isReturnPrev() { - return type == RejectType.RETURN_PREV; - } - public boolean isReturnNode() { return type == RejectType.RETURN_NODE; } @@ -57,9 +58,7 @@ public boolean isTerminate() { } public RejectResult(String result) { - if (result.equals("RETURN_PREV")) { - this.type = RejectType.RETURN_PREV; - } else if (result.equals("TERMINATE")) { + if (result.equals("TERMINATE")) { this.type = RejectType.TERMINATE; } else { this.type = RejectType.RETURN_NODE; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java index f787c6db..d0a70c6d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java @@ -108,6 +108,10 @@ public String getCurrentNodeId() { return currentNode.getId(); } + public IFlowNode getStartNode() { + return workflow.getStartNode(); + } + public String getCurrentNodeType() { return currentNode.getType(); } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index ebf3dc65..1228e354 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -186,8 +186,8 @@ void pass() { flowService.action(lorneRequest); List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); - assertEquals(3, records.size()); - assertEquals(3, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(2, records.size()); + assertEquals(2, records.stream().filter(FlowRecord::isFinish).toList().size()); } @@ -310,8 +310,8 @@ void condition() { flowService.action(lorneRequest); List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); - assertEquals(3, records.size()); - assertEquals(3, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(2, records.size()); + assertEquals(2, records.stream().filter(FlowRecord::isFinish).toList().size()); } @@ -426,8 +426,8 @@ public FlowRecord getRecordById(long id) { flowService.action(lorneRequest); List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); - assertEquals(5, records.size()); - assertEquals(5, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(4, records.size()); + assertEquals(4, records.stream().filter(FlowRecord::isFinish).toList().size()); } } \ No newline at end of file From 59a71f8fbdd5a28d7776e0616a89c49fa5d1e865 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 19:53:09 +0800 Subject: [PATCH 06/21] add dev --- .../com/codingapi/flow/action/PassAction.java | 2 +- .../codingapi/flow/node/nodes/EndNode.java | 30 ------------------- .../flow/node/nodes/RouterBranchNode.java | 6 ---- 3 files changed, 1 insertion(+), 37 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java index a2432f01..9279c460 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java @@ -78,9 +78,9 @@ public void triggerNode(FlowSession flowSession) { List nextNodes = flowSession.nextNodes(); for (IFlowNode node : nextNodes) { FlowSession triggerSession = flowSession.updateSession(node); - IFlowNode latestNode = triggerSession.getCurrentNode(); List records = this.generateRecords(triggerSession); if (records.isEmpty()) { + IFlowNode latestNode = triggerSession.getCurrentNode(); super.flowFinish(flowRecord, latestNode); }else { for (FlowRecord record : records) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java index 6840639a..0d1dac88 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java @@ -1,17 +1,9 @@ package com.codingapi.flow.node.nodes; -import com.codingapi.flow.action.DefaultAction; import com.codingapi.flow.action.IFlowAction; -import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.node.BaseFlowNode; -import com.codingapi.flow.node.builder.AuditNodeBuilder; -import com.codingapi.flow.node.BaseAuditNode; import com.codingapi.flow.node.builder.BaseNodeBuilder; -import com.codingapi.flow.script.node.ErrorTriggerScript; -import com.codingapi.flow.script.node.NodeTitleScript; -import com.codingapi.flow.script.node.OperatorLoadScript; import com.codingapi.flow.session.FlowSession; -import com.codingapi.flow.strategy.*; import com.codingapi.flow.utils.RandomUtils; import java.util.ArrayList; @@ -32,11 +24,6 @@ public String getType() { } -// public EndNode(String id, String name, List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { -// super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); -// } - - @Override public boolean isContinueTrigger(FlowSession session) { return false; @@ -49,23 +36,6 @@ public EndNode(String id, String name, List actions) { public EndNode() { this(RandomUtils.generateStringId(), DEFAULT_NAME,new ArrayList<>()); } -// -// private static List defaultStrategies() { -// List strategies = new ArrayList<>(); -// strategies.add(TimeoutStrategy.defaultStrategy()); -// strategies.add(MultiOperatorAuditStrategy.defaultStrategy()); -// strategies.add(SameOperatorAuditStrategy.defaultStrategy()); -// strategies.add(RecordMergeStrategy.defaultStrategy()); -// strategies.add(ResubmitStrategy.defaultStrategy()); -// strategies.add(AdviceStrategy.defaultStrategy()); -// return strategies; -// } -// -// private static List defaultActions() { -// List actions = new ArrayList<>(); -// actions.add(new DefaultAction()); -// return actions; -// } public static EndNode formMap(Map map) { return BaseFlowNode.loadFromMap(map, EndNode.class); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java index c0dd2b8e..e5eecedf 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java @@ -32,12 +32,6 @@ public RouterBranchNode() { this(RandomUtils.generateStringId(), DEFAULT_NAME); } - - public List matchRouters(FlowSession session) { - return null; - } - - public static RouterBranchNode formMap(Map map) { return BaseBranchNode.formMap(map, RouterBranchNode.class); } From eb7be799fe8912a2bbef43e795f7cf99f2d5b264 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 20:02:37 +0800 Subject: [PATCH 07/21] add dev --- .../com/codingapi/flow/node/BaseAuditNode.java | 15 ++++++++------- .../com/codingapi/flow/node/BaseFlowNode.java | 5 +++++ .../java/com/codingapi/flow/node/IFlowNode.java | 6 ++++++ .../com/codingapi/flow/record/FlowRecord.java | 6 ++---- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index f4ae1775..2c881a45 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -2,12 +2,7 @@ import com.codingapi.flow.action.*; import com.codingapi.flow.action.factory.FlowActionFactory; -import com.codingapi.flow.context.RepositoryContext; import com.codingapi.flow.error.ErrorThrow; -import com.codingapi.flow.event.FlowRecordDoneEvent; -import com.codingapi.flow.event.FlowRecordFinishEvent; -import com.codingapi.flow.event.FlowRecordTodoEvent; -import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.form.permission.PermissionType; @@ -15,7 +10,6 @@ import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.node.manager.OperatorManager; import com.codingapi.flow.node.manager.StrategyManager; -import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.script.node.ErrorTriggerScript; @@ -28,7 +22,6 @@ import com.codingapi.flow.strategy.NodeStrategyFactory; import com.codingapi.flow.utils.RandomUtils; import com.codingapi.flow.workflow.Workflow; -import com.codingapi.springboot.framework.event.EventPusher; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; @@ -222,6 +215,14 @@ public boolean isContinueTrigger(FlowSession session) { return false; } + @Override + public void fillNewRecord(FlowSession session, FlowRecord flowRecord) { + StrategyManager strategyManager = this.strategies(); + flowRecord.setTitle(this.generateTitle(session)); + flowRecord.setTimeoutTime(strategyManager.getTimeoutTime()); + flowRecord.setMergeable(strategyManager.isMergeable()); + } + @Override public boolean isDone(FlowSession session) { List currentRecords = session.getCurrentNodeRecords(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 5bb992df..3b9638a3 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -90,6 +90,11 @@ public boolean isDone(FlowSession session) { return true; } + @Override + public void fillNewRecord(FlowSession session, FlowRecord flowRecord) { + + } + @Override public List generateCurrentRecords(FlowSession session) { return List.of(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index 77bc495d..57760c5a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -70,4 +70,10 @@ public interface IFlowNode { */ boolean isDone(FlowSession session); + /** + * 填充流程记录 + * @param session 会话 + * @param flowRecord 流程记录 + */ + void fillNewRecord(FlowSession session,FlowRecord flowRecord); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java index 20d64290..d421aba6 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java @@ -1,6 +1,5 @@ package com.codingapi.flow.record; -import com.codingapi.flow.node.BaseAuditNode; import com.codingapi.flow.session.FlowSession; import lombok.Getter; import lombok.Setter; @@ -9,6 +8,7 @@ import java.util.Map; @Getter +@Setter public class FlowRecord { // 待办、已办 @@ -160,7 +160,6 @@ public FlowRecord(FlowSession flowSession, String actionId, String processId, lo this.formData = flowSession.getFormData().toMapData(); this.fromId = fromId; this.nodeOrder = nodeOrder; - this.title = ((BaseAuditNode)flowSession.getCurrentNode()).generateTitle(flowSession); this.processId = processId; this.createOperatorId = flowSession.getCreatedOperator().getUserId(); this.recordState = SATE_RECORD_TODO; @@ -171,10 +170,9 @@ public FlowRecord(FlowSession flowSession, String actionId, String processId, lo this.signKey = flowSession.getAdvice().getSignKey(); this.flowState = SATE_FLOW_RUNNING; this.createTime = System.currentTimeMillis(); - this.timeoutTime = ((BaseAuditNode)flowSession.getCurrentNode()).strategies().getTimeoutTime(); - this.mergeable = ((BaseAuditNode)flowSession.getCurrentNode()).strategies().isMergeable(); this.isInterfere = flowSession.getWorkflow().isInterfere(); this.hidden = false; + flowSession.getCurrentNode().fillNewRecord(flowSession,this); } public void verify() { From 1a7f986b1e2f1729f211be9a85a51449455fe0d3 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 20:14:43 +0800 Subject: [PATCH 08/21] add dev --- .../codingapi/flow/node/BaseAuditNode.java | 2 +- .../codingapi/flow/node/BaseBranchNode.java | 66 ------------------- .../com/codingapi/flow/node/BaseFlowNode.java | 31 ++++++++- .../com/codingapi/flow/node/IFlowNode.java | 6 ++ .../flow/node/builder/BaseNodeBuilder.java | 15 +++-- .../flow/node/builder/BranchNodeBuilder.java | 31 --------- .../flow/node/nodes/BranchNodeBranchNode.java | 20 +++--- .../codingapi/flow/node/nodes/DelayNode.java | 2 +- .../codingapi/flow/node/nodes/EndNode.java | 6 +- .../flow/node/nodes/InclusiveBranchNode.java | 13 ++-- .../flow/node/nodes/ParallelBranchNode.java | 12 ++-- .../flow/node/nodes/RouterBranchNode.java | 15 ++--- 12 files changed, 79 insertions(+), 140 deletions(-) delete mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java delete mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BranchNodeBuilder.java diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index 2c881a45..c24d1e98 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -71,7 +71,7 @@ public abstract class BaseAuditNode extends BaseFlowNode implements IFlowNode { private List nodeStrategies; - public BaseAuditNode(String id, String name, List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldPermissions, List nodeStrategies) { + public BaseAuditNode(String id, String name,List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldPermissions, List nodeStrategies) { super(id, name, actions); this.view = view; this.operatorScript = operatorScript; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java deleted file mode 100644 index 38c28b88..00000000 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseBranchNode.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.codingapi.flow.node; - -import com.codingapi.flow.action.IFlowAction; -import com.codingapi.flow.form.FormMeta; -import lombok.Getter; -import lombok.Setter; -import lombok.SneakyThrows; -import org.springframework.util.StringUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public abstract class BaseBranchNode extends BaseFlowNode implements IFlowNode { - - public BaseBranchNode(String id, String name, List actions) { - super(id, name,actions); - } - - /** - * 条件顺序,越小则优先级越高 - */ - @Getter - @Setter - private int order; - - @Override - public Map toMap() { - Map map = new HashMap<>(); - map.put("name", name); - map.put("id", id); - map.put("type", getType()); - map.put("order", String.valueOf(order)); - return map; - } - - - @SneakyThrows - public static T formMap(Map map, Class clazz) { - T node = clazz.getDeclaredConstructor().newInstance(); - node.setId((String) map.get("id")); - node.setName((String) map.get("name")); - node.setOrder(Integer.parseInt((String) map.get("order"))); - return node; - } - - - public int order() { - return order; - } - - @Override - public void verifyNode(FormMeta form) { - this.verifyFields(); - } - - private void verifyFields() { - if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("name can not be null"); - } - if (!StringUtils.hasText(id)) { - throw new IllegalArgumentException("id can not be null"); - } - } - -} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 3b9638a3..2ca12355 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -6,7 +6,6 @@ import com.codingapi.flow.node.manager.ActionManager; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; @@ -16,7 +15,6 @@ import java.util.List; import java.util.Map; -@AllArgsConstructor public abstract class BaseFlowNode implements IFlowNode { /** @@ -32,6 +30,13 @@ public abstract class BaseFlowNode implements IFlowNode { @Setter protected String name; + /** + * 条件顺序,越小则优先级越高 + */ + @Getter + @Setter + protected int order; + /** * 节点操作 */ @@ -39,13 +44,32 @@ public abstract class BaseFlowNode implements IFlowNode { @Getter protected List actions; + public BaseFlowNode(String name, String id) { + this(name, id, 0, new ArrayList<>()); + } + + public BaseFlowNode(String id, String name, int order) { + this(id, name, order, new ArrayList<>()); + } + + public BaseFlowNode(String id, String name,List actions) { + this(id, name, 0, actions); + } + + public BaseFlowNode(String id, String name, int order, List actions) { + this.id = id; + this.name = name; + this.order = order; + this.actions = actions; + } @Override public Map toMap() { Map map = new HashMap<>(); - map.put("name", name); map.put("id", id); + map.put("name", name); map.put("type", getType()); + map.put("order", String.valueOf(order)); map.put("actions", actions.stream().map(IFlowAction::toMap).toList()); return map; } @@ -57,6 +81,7 @@ public static T loadFromMap(Map map, Cl T node = clazz.getDeclaredConstructor().newInstance(); node.setId((String) map.get("id")); node.setName((String) map.get("name")); + node.setOrder(Integer.parseInt((String) map.get("order"))); List> actions = (List>) map.get("actions"); if (actions != null) { List actionList = new ArrayList<>(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index 57760c5a..02d45cf8 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -28,6 +28,12 @@ public interface IFlowNode { */ String getType(); + /** + * 节点顺序,同一层级下的节点顺序,越小则优先级越高 + * @return 节点顺序 + */ + int getOrder(); + /** * 转化为map */ diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java index 772db36a..866b1f29 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BaseNodeBuilder.java @@ -7,7 +7,7 @@ public abstract class BaseNodeBuilder, N extends BaseFlowNode> { - private final N node; + protected final N node; public BaseNodeBuilder(N node) { this.node = node; @@ -15,19 +15,26 @@ public BaseNodeBuilder(N node) { public B id(String id) { node.setId(id); - return (B)this; + return (B) this; } public B actions(List actions) { node.setActions(actions); - return (B)this; + return (B) this; } public B name(String name) { node.setName(name); - return (B)this; + return (B) this; } + + public B order(int order) { + node.setOrder(order); + return (B) this; + } + + public N build() { return node; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BranchNodeBuilder.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BranchNodeBuilder.java deleted file mode 100644 index 00550dc2..00000000 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/BranchNodeBuilder.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.codingapi.flow.node.builder; - -import com.codingapi.flow.node.BaseBranchNode; - -public abstract class BranchNodeBuilder, N extends BaseBranchNode> { - - protected final N node; - - public BranchNodeBuilder(N node) { - this.node = node; - } - - public B id(String id) { - node.setId(id); - return (B)this; - } - - public B name(String name) { - node.setName(name); - return (B)this; - } - - public B order(int order) { - node.setOrder(order); - return (B)this; - } - public N build() { - return node; - } - -} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java index 1fe9caf6..6c72a53d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java @@ -1,18 +1,18 @@ package com.codingapi.flow.node.nodes; -import com.codingapi.flow.node.BaseBranchNode; -import com.codingapi.flow.node.builder.BranchNodeBuilder; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.script.node.ConditionScript; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import lombok.Setter; -import java.util.ArrayList; import java.util.Map; /** * 分支节点 */ -public class BranchNodeBranchNode extends BaseBranchNode { +public class BranchNodeBranchNode extends BaseFlowNode { public static final String NODE_TYPE = "condition_branch"; public static final String DEFAULT_NAME = "分支节点"; @@ -20,6 +20,7 @@ public class BranchNodeBranchNode extends BaseBranchNode { /** * 条件脚本 */ + @Setter private ConditionScript conditionScript; @Override @@ -27,13 +28,13 @@ public String getType() { return NODE_TYPE; } - public BranchNodeBranchNode(String id, String name) { - super(id, name,new ArrayList<>()); + public BranchNodeBranchNode(String id, String name, int order) { + super(id, name, order); this.conditionScript = ConditionScript.defaultScript(); } public BranchNodeBranchNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME); + this(RandomUtils.generateStringId(), DEFAULT_NAME, 0); } /** @@ -52,7 +53,7 @@ public Map toMap() { } public static BranchNodeBranchNode formMap(Map map) { - BranchNodeBranchNode branchNode = BaseBranchNode.formMap(map, BranchNodeBranchNode.class); + BranchNodeBranchNode branchNode = BaseFlowNode.loadFromMap(map, BranchNodeBranchNode.class); branchNode.conditionScript = new ConditionScript((String) map.get("script")); return branchNode; } @@ -61,7 +62,8 @@ public static Builder builder() { return new Builder(); } - public static class Builder extends BranchNodeBuilder { + public static class Builder extends BaseNodeBuilder { + public Builder() { super(new BranchNodeBranchNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java index f81716b7..def24b1d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java @@ -22,7 +22,7 @@ public String getType() { public DelayNode(String id, String name) { - super(id, name,new ArrayList<>()); + super(id, name); } public DelayNode() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java index 0d1dac88..9cb754a0 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java @@ -29,12 +29,12 @@ public boolean isContinueTrigger(FlowSession session) { return false; } - public EndNode(String id, String name, List actions) { - super(id, name, actions); + public EndNode(String id, String name) { + super(id, name); } public EndNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME,new ArrayList<>()); + this(RandomUtils.generateStringId(), DEFAULT_NAME); } public static EndNode formMap(Map map) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/InclusiveBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/InclusiveBranchNode.java index defd976e..8368ae3e 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/InclusiveBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/InclusiveBranchNode.java @@ -1,16 +1,15 @@ package com.codingapi.flow.node.nodes; -import com.codingapi.flow.node.BaseBranchNode; -import com.codingapi.flow.node.builder.BranchNodeBuilder; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; -import java.util.ArrayList; import java.util.Map; /** * 包容分支节点 */ -public class InclusiveBranchNode extends BaseBranchNode { +public class InclusiveBranchNode extends BaseFlowNode { public static final String NODE_TYPE = "inclusive_branch"; public static final String DEFAULT_NAME = "包容分支节点"; @@ -22,7 +21,7 @@ public String getType() { public InclusiveBranchNode(String id, String name) { - super(id, name,new ArrayList<>()); + super(id, name); } public InclusiveBranchNode() { @@ -30,14 +29,14 @@ public InclusiveBranchNode() { } public static InclusiveBranchNode formMap(Map map) { - return BaseBranchNode.formMap(map, InclusiveBranchNode.class); + return BaseFlowNode.loadFromMap(map, InclusiveBranchNode.class); } public static Builder builder() { return new Builder(); } - public static class Builder extends BranchNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new InclusiveBranchNode()); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java index a3426bc3..59ea8881 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java @@ -1,7 +1,7 @@ package com.codingapi.flow.node.nodes; -import com.codingapi.flow.node.BaseBranchNode; -import com.codingapi.flow.node.builder.BranchNodeBuilder; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; import java.util.ArrayList; @@ -10,7 +10,7 @@ /** * 并行节点 */ -public class ParallelBranchNode extends BaseBranchNode { +public class ParallelBranchNode extends BaseFlowNode { public static final String NODE_TYPE = "parallel_branch"; public static final String DEFAULT_NAME = "并行节点"; @@ -21,7 +21,7 @@ public String getType() { } public ParallelBranchNode(String id, String name) { - super(id, name,new ArrayList<>()); + super(id, name); } public ParallelBranchNode() { @@ -30,14 +30,14 @@ public ParallelBranchNode() { public static ParallelBranchNode formMap(Map map) { - return BaseBranchNode.formMap(map, ParallelBranchNode.class); + return BaseFlowNode.loadFromMap(map, ParallelBranchNode.class); } public static Builder builder() { return new Builder(); } - public static class Builder extends BranchNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new ParallelBranchNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java index e5eecedf..14bc5886 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java @@ -1,19 +1,16 @@ package com.codingapi.flow.node.nodes; -import com.codingapi.flow.node.BaseBranchNode; -import com.codingapi.flow.node.IFlowNode; -import com.codingapi.flow.node.builder.BranchNodeBuilder; -import com.codingapi.flow.session.FlowSession; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; import java.util.ArrayList; -import java.util.List; import java.util.Map; /** * 路由分支节点 */ -public class RouterBranchNode extends BaseBranchNode { +public class RouterBranchNode extends BaseFlowNode { public static final String NODE_TYPE = "router_branch"; public static final String DEFAULT_NAME = "路由节点"; @@ -25,7 +22,7 @@ public String getType() { public RouterBranchNode(String id, String name) { - super(id, name, new ArrayList<>()); + super(id, name); } public RouterBranchNode() { @@ -33,14 +30,14 @@ public RouterBranchNode() { } public static RouterBranchNode formMap(Map map) { - return BaseBranchNode.formMap(map, RouterBranchNode.class); + return BaseFlowNode.loadFromMap(map, RouterBranchNode.class); } public static Builder builder() { return new Builder(); } - public static class Builder extends BranchNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new RouterBranchNode()); } From 05a6fbca52673d57f815bc91ebd88c4bef91a0df Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 20:21:16 +0800 Subject: [PATCH 09/21] add dev --- .../codingapi/flow/node/BaseAuditNode.java | 27 ++++--------------- .../com/codingapi/flow/node/BaseFlowNode.java | 26 ++++++++++++++++++ .../codingapi/flow/node/nodes/StartNode.java | 9 +------ 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index c24d1e98..5f6efcda 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -308,32 +308,15 @@ public void verifySession(FlowSession session) { fieldPermissionManager.verifyFormData(workflow.getForm(), flowRecord.getFormData(), session.getFormData().toMapData()); // 节点请求验证 - this.verifyFlowAdvice(session.getAdvice()); + this.verifyDefaultFlowAdviceAction(session.getAdvice()); } - public void verifyFlowAdvice(FlowAdvice flowAdvice) { - StrategyManager strategyManager = this.strategies(); - IFlowAction flowAction = flowAdvice.getAction(); - - // 保存操作,不做检查 - if (flowAction instanceof SaveAction) { - return; - } + public void verifyDefaultFlowAdviceAction(FlowAdvice flowAdvice) { - // 转办操作 - if (flowAction instanceof TransferAction) { - if (flowAdvice.getTransferOperators() == null || flowAdvice.getTransferOperators().isEmpty()) { - throw new IllegalArgumentException("transferOperators can not be null"); - } - } - - // 退回操作 - if (flowAction instanceof ReturnAction) { - if (flowAdvice.getBackNode() == null) { - throw new IllegalArgumentException("backNode can not be null"); - } - } + IFlowAction flowAction = flowAdvice.getAction(); + super.verifyDefaultFlowAdviceAction(flowAdvice); + StrategyManager strategyManager = this.strategies(); // 是否必须填写审批意见 if (strategyManager.isEnableAdvice()) { if (!StringUtils.hasText(flowAdvice.getAdvice())) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 2ca12355..7423ff90 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -1,10 +1,14 @@ package com.codingapi.flow.node; import com.codingapi.flow.action.IFlowAction; +import com.codingapi.flow.action.ReturnAction; +import com.codingapi.flow.action.SaveAction; +import com.codingapi.flow.action.TransferAction; import com.codingapi.flow.action.factory.FlowActionFactory; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.manager.ActionManager; import com.codingapi.flow.record.FlowRecord; +import com.codingapi.flow.session.FlowAdvice; import com.codingapi.flow.session.FlowSession; import lombok.Getter; import lombok.Setter; @@ -129,4 +133,26 @@ public List generateCurrentRecords(FlowSession session) { public ActionManager actions() { return new ActionManager(actions); } + + + + public void verifyDefaultFlowAdviceAction(FlowAdvice flowAdvice) { + IFlowAction flowAction = flowAdvice.getAction(); + // 保存操作,不做检查 + if (flowAction instanceof SaveAction) { + return; + } + // 转办操作 + if (flowAction instanceof TransferAction) { + if (flowAdvice.getTransferOperators() == null || flowAdvice.getTransferOperators().isEmpty()) { + throw new IllegalArgumentException("transferOperators can not be null"); + } + } + // 退回操作 + if (flowAction instanceof ReturnAction) { + if (flowAdvice.getBackNode() == null) { + throw new IllegalArgumentException("backNode can not be null"); + } + } + } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java index e2533d6b..337c42fa 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java @@ -37,14 +37,7 @@ public StartNode() { } private static List defaultStrategies() { - List strategies = new ArrayList<>(); - strategies.add(TimeoutStrategy.defaultStrategy()); - strategies.add(MultiOperatorAuditStrategy.defaultStrategy()); - strategies.add(SameOperatorAuditStrategy.defaultStrategy()); - strategies.add(RecordMergeStrategy.defaultStrategy()); - strategies.add(ResubmitStrategy.defaultStrategy()); - strategies.add(AdviceStrategy.defaultStrategy()); - return strategies; + return new ArrayList<>(); } private static List defaultActions() { From 7932f881a4040a7b1b0a0ccca4b5549ec2c185db Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 21:32:31 +0800 Subject: [PATCH 10/21] add dev --- .../com/codingapi/flow/form/FormMeta.java | 5 +- .../codingapi/flow/node/BaseAuditNode.java | 110 +++++------------ .../com/codingapi/flow/node/BaseFlowNode.java | 53 ++++---- .../flow/node/builder/AuditNodeBuilder.java | 54 ++------- .../builder/FormFieldPermissionsBuilder.java | 34 ++++++ .../builder/IFormFieldPermissionsNode.java | 13 ++ .../flow/node/builder/NodeMapBuilder.java | 81 +++++++++++++ .../flow/node/nodes/ApprovalNode.java | 3 +- .../codingapi/flow/node/nodes/HandleNode.java | 3 +- .../codingapi/flow/node/nodes/NotifyNode.java | 3 +- .../codingapi/flow/node/nodes/StartNode.java | 112 +++++++++++++++-- .../flow/service/impl/FlowCreateService.java | 22 ++-- .../codingapi/flow/session/FlowSession.java | 15 +-- .../flow/script/ErrorTriggerScriptTest.java | 27 +++-- .../flow/service/FlowServiceTest.java | 113 ++++++++++-------- .../flow/workflow/WorkflowBuilderTest.java | 25 ++-- 16 files changed, 412 insertions(+), 261 deletions(-) create mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/FormFieldPermissionsBuilder.java create mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/IFormFieldPermissionsNode.java create mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/NodeMapBuilder.java diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/form/FormMeta.java b/flow-engine-framework/src/main/java/com/codingapi/flow/form/FormMeta.java index 797109d3..63790c07 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/form/FormMeta.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/form/FormMeta.java @@ -36,7 +36,10 @@ public class FormMeta { public boolean isSubForm(String formCode){ - return subForms.stream().anyMatch(form -> form.getCode().equals(formCode)); + if(subForms!=null) { + return subForms.stream().anyMatch(form -> form.getCode().equals(formCode)); + } + return false; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index 5f6efcda..d51f0fe9 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -1,11 +1,11 @@ package com.codingapi.flow.node; -import com.codingapi.flow.action.*; -import com.codingapi.flow.action.factory.FlowActionFactory; +import com.codingapi.flow.action.IFlowAction; +import com.codingapi.flow.action.PassAction; import com.codingapi.flow.error.ErrorThrow; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.permission.FormFieldPermission; -import com.codingapi.flow.form.permission.PermissionType; +import com.codingapi.flow.node.builder.IFormFieldPermissionsNode; import com.codingapi.flow.node.manager.ActionManager; import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.node.manager.OperatorManager; @@ -19,12 +19,10 @@ import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.strategy.INodeStrategy; import com.codingapi.flow.strategy.MultiOperatorAuditStrategy; -import com.codingapi.flow.strategy.NodeStrategyFactory; import com.codingapi.flow.utils.RandomUtils; import com.codingapi.flow.workflow.Workflow; import lombok.Getter; import lombok.Setter; -import lombok.SneakyThrows; import org.springframework.util.StringUtils; import java.util.ArrayList; @@ -32,7 +30,7 @@ import java.util.List; import java.util.Map; -public abstract class BaseAuditNode extends BaseFlowNode implements IFlowNode { +public abstract class BaseAuditNode extends BaseFlowNode implements IFlowNode, IFormFieldPermissionsNode { public static final String DEFAULT_VIEW = "default"; @@ -71,7 +69,7 @@ public abstract class BaseAuditNode extends BaseFlowNode implements IFlowNode { private List nodeStrategies; - public BaseAuditNode(String id, String name,List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldPermissions, List nodeStrategies) { + public BaseAuditNode(String id, String name, List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldPermissions, List nodeStrategies) { super(id, name, actions); this.view = view; this.operatorScript = operatorScript; @@ -97,51 +95,7 @@ public Map toMap() { return map; } - @SneakyThrows - @SuppressWarnings("unchecked") - public static T formMap(Map map, Class clazz) { - T node = clazz.getDeclaredConstructor().newInstance(); - node.setId((String) map.get("id")); - node.setName((String) map.get("name")); - node.setView((String) map.get("view")); - node.setOperatorScript((String) map.get("operatorScript")); - node.setNodeTitleScript((String) map.get("nodeTitleScript")); - node.setErrorTriggerScript((String) map.get("errorTriggerScript")); - List> permissions = (List>) map.get("formFieldsPermissions"); - if (permissions != null) { - List permissionList = new ArrayList<>(); - for (Map item : permissions) { - FormFieldPermission permission = new FormFieldPermission(); - permission.setFormCode((String) item.get("formCode")); - permission.setFieldName((String) item.get("fieldName")); - permission.setType(PermissionType.valueOf((String) item.get("type"))); - permissionList.add(permission); - } - node.setFormFieldPermissions(permissionList); - } - List> actions = (List>) map.get("actions"); - if (actions != null) { - List actionList = new ArrayList<>(); - for (Map item : actions) { - IFlowAction action = FlowActionFactory.getInstance().createAction(item); - actionList.add(action); - } - node.setActions(actionList); - } - - List> nodeStrategies = (List>) map.get("nodeStrategies"); - if (nodeStrategies != null) { - List strategyList = new ArrayList<>(); - for (Map item : nodeStrategies) { - INodeStrategy strategy = NodeStrategyFactory.getInstance().createStrategy(item); - strategyList.add(strategy); - } - node.setNodeStrategies(strategyList); - } - - return node; - } /** * 设置审批人配置脚本 @@ -171,7 +125,7 @@ public void setErrorTriggerScript(String errorTriggerScript) { } - public FieldPermissionManager formFieldsPermissions() { + public FieldPermissionManager formFieldsPermissionsManager() { return new FieldPermissionManager(formFieldPermissions); } @@ -200,8 +154,25 @@ public void addAction(IFlowAction action) { } public void verifyNode(FormMeta form) { - this.verifyFields(); - FieldPermissionManager fieldPermissionManager = this.formFieldsPermissions(); + if (!StringUtils.hasText(view)) { + throw new IllegalArgumentException("view can not be null"); + } + if (!StringUtils.hasText(name)) { + throw new IllegalArgumentException("name can not be null"); + } + if (!StringUtils.hasText(id)) { + throw new IllegalArgumentException("id can not be null"); + } + if (actions == null || actions.isEmpty()) { + throw new IllegalArgumentException("actions can not be null"); + } + if (operatorScript == null) { + throw new IllegalArgumentException("operator can not be null"); + } + if (nodeTitleScript == null) { + throw new IllegalArgumentException("nodeTitle can not be null"); + } + FieldPermissionManager fieldPermissionManager = this.formFieldsPermissionsManager(); fieldPermissionManager.verifyPermissions(form); } @@ -301,20 +272,15 @@ public List generateCurrentRecords(FlowSession session) { @Override public void verifySession(FlowSession session) { + super.verifySession(session); FlowRecord flowRecord = session.getCurrentRecord(); Workflow workflow = session.getWorkflow(); // 数据验证 - FieldPermissionManager fieldPermissionManager = this.formFieldsPermissions(); + FieldPermissionManager fieldPermissionManager = this.formFieldsPermissionsManager(); fieldPermissionManager.verifyFormData(workflow.getForm(), flowRecord.getFormData(), session.getFormData().toMapData()); - // 节点请求验证 - this.verifyDefaultFlowAdviceAction(session.getAdvice()); - } - - public void verifyDefaultFlowAdviceAction(FlowAdvice flowAdvice) { - + FlowAdvice flowAdvice = session.getAdvice(); IFlowAction flowAction = flowAdvice.getAction(); - super.verifyDefaultFlowAdviceAction(flowAdvice); StrategyManager strategyManager = this.strategies(); // 是否必须填写审批意见 @@ -334,24 +300,4 @@ public void verifyDefaultFlowAdviceAction(FlowAdvice flowAdvice) { } } - private void verifyFields() { - if (!StringUtils.hasText(view)) { - throw new IllegalArgumentException("view can not be null"); - } - if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("name can not be null"); - } - if (!StringUtils.hasText(id)) { - throw new IllegalArgumentException("id can not be null"); - } - if (actions == null || actions.isEmpty()) { - throw new IllegalArgumentException("actions can not be null"); - } - if (operatorScript == null) { - throw new IllegalArgumentException("operator can not be null"); - } - if (nodeTitleScript == null) { - throw new IllegalArgumentException("nodeTitle can not be null"); - } - } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 7423ff90..38bad07f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -6,10 +6,13 @@ import com.codingapi.flow.action.TransferAction; import com.codingapi.flow.action.factory.FlowActionFactory; import com.codingapi.flow.form.FormMeta; +import com.codingapi.flow.node.builder.NodeMapBuilder; import com.codingapi.flow.node.manager.ActionManager; +import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowAdvice; import com.codingapi.flow.session.FlowSession; +import com.codingapi.flow.workflow.Workflow; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; @@ -80,21 +83,12 @@ public Map toMap() { @SneakyThrows - @SuppressWarnings("unchecked") public static T loadFromMap(Map map, Class clazz) { T node = clazz.getDeclaredConstructor().newInstance(); node.setId((String) map.get("id")); node.setName((String) map.get("name")); node.setOrder(Integer.parseInt((String) map.get("order"))); - List> actions = (List>) map.get("actions"); - if (actions != null) { - List actionList = new ArrayList<>(); - for (Map item : actions) { - IFlowAction action = FlowActionFactory.getInstance().createAction(item); - actionList.add(action); - } - node.setActions(actionList); - } + node.setActions(NodeMapBuilder.loadActions(map)); return node; } @@ -111,7 +105,25 @@ public boolean isContinueTrigger(FlowSession session) { @Override public void verifySession(FlowSession session) { + FlowAdvice flowAdvice = session.getAdvice(); + IFlowAction flowAction = flowAdvice.getAction(); + // 保存操作,不做检查 + if (flowAction instanceof SaveAction) { + return; + } + // 转办操作 + if (flowAction instanceof TransferAction) { + if (flowAdvice.getTransferOperators() == null || flowAdvice.getTransferOperators().isEmpty()) { + throw new IllegalArgumentException("transferOperators can not be null"); + } + } + // 退回操作 + if (flowAction instanceof ReturnAction) { + if (flowAdvice.getBackNode() == null) { + throw new IllegalArgumentException("backNode can not be null"); + } + } } @Override @@ -134,25 +146,4 @@ public ActionManager actions() { return new ActionManager(actions); } - - - public void verifyDefaultFlowAdviceAction(FlowAdvice flowAdvice) { - IFlowAction flowAction = flowAdvice.getAction(); - // 保存操作,不做检查 - if (flowAction instanceof SaveAction) { - return; - } - // 转办操作 - if (flowAction instanceof TransferAction) { - if (flowAdvice.getTransferOperators() == null || flowAdvice.getTransferOperators().isEmpty()) { - throw new IllegalArgumentException("transferOperators can not be null"); - } - } - // 退回操作 - if (flowAction instanceof ReturnAction) { - if (flowAdvice.getBackNode() == null) { - throw new IllegalArgumentException("backNode can not be null"); - } - } - } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/AuditNodeBuilder.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/AuditNodeBuilder.java index 50ee1347..91f4c3dc 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/AuditNodeBuilder.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/AuditNodeBuilder.java @@ -2,11 +2,9 @@ import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.form.permission.FormFieldPermission; -import com.codingapi.flow.form.permission.PermissionType; import com.codingapi.flow.node.BaseAuditNode; import com.codingapi.flow.strategy.INodeStrategy; -import java.util.ArrayList; import java.util.List; public abstract class AuditNodeBuilder, N extends BaseAuditNode> { @@ -19,87 +17,57 @@ public AuditNodeBuilder(N node) { public B id(String id) { node.setId(id); - return (B)this; + return (B) this; } public B actions(List actions) { node.setActions(actions); - return (B)this; + return (B) this; } public B addAction(IFlowAction action) { node.addAction(action); - return (B)this; + return (B) this; } public B name(String name) { node.setName(name); - return (B)this; + return (B) this; } public B view(String view) { node.setView(view); - return (B)this; + return (B) this; } public B nodeStrategies(List nodeStrategies) { node.setNodeStrategies(nodeStrategies); - return (B)this; + return (B) this; } public B operatorScript(String operatorScript) { node.setOperatorScript(operatorScript); - return (B)this; + return (B) this; } public B nodeTitleScript(String nodeTitleScript) { node.setNodeTitleScript(nodeTitleScript); - return (B)this; + return (B) this; } public B errorTriggerScript(String errorTriggerScript) { node.setErrorTriggerScript(errorTriggerScript); - return (B)this; + return (B) this; } public B formFieldsPermissions(List permissions) { node.setFormFieldPermissions(permissions); - return (B)this; - } - - public FormFieldPermissionsBuilder formFieldPermissionsBuilder() { - return new FormFieldPermissionsBuilder<>(this, node); + return (B) this; } public N build() { return node; } - - public static class FormFieldPermissionsBuilder,N extends BaseAuditNode> { - - private final N node; - private final AuditNodeBuilder baseBuilder; - private final List permissions; - - public FormFieldPermissionsBuilder(AuditNodeBuilder baseBuilder, N node) { - this.baseBuilder = baseBuilder; - this.node = node; - this.permissions = new ArrayList<>(); - } - - public FormFieldPermissionsBuilder addPermission(String form, String name, PermissionType type) { - FormFieldPermission permission = new FormFieldPermission(); - permission.setFormCode(form); - permission.setFieldName(name); - permission.setType(type); - permissions.add(permission); - return this; - } - - public AuditNodeBuilder build() { - node.setFormFieldPermissions(this.permissions); - return baseBuilder; - } - } } + diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/FormFieldPermissionsBuilder.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/FormFieldPermissionsBuilder.java new file mode 100644 index 00000000..e7ea957f --- /dev/null +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/FormFieldPermissionsBuilder.java @@ -0,0 +1,34 @@ +package com.codingapi.flow.node.builder; + +import com.codingapi.flow.form.permission.FormFieldPermission; +import com.codingapi.flow.form.permission.PermissionType; + +import java.util.ArrayList; +import java.util.List; + +public class FormFieldPermissionsBuilder { + + private final List permissions; + + private FormFieldPermissionsBuilder() { + this.permissions = new ArrayList<>(); + } + + public static FormFieldPermissionsBuilder builder() { + return new FormFieldPermissionsBuilder(); + } + + public FormFieldPermissionsBuilder addPermission(String form, String name, PermissionType type) { + FormFieldPermission permission = new FormFieldPermission(); + permission.setFormCode(form); + permission.setFieldName(name); + permission.setType(type); + permissions.add(permission); + return this; + } + + public List build() { + return permissions; + } + +} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/IFormFieldPermissionsNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/IFormFieldPermissionsNode.java new file mode 100644 index 00000000..9c27ebb6 --- /dev/null +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/IFormFieldPermissionsNode.java @@ -0,0 +1,13 @@ +package com.codingapi.flow.node.builder; + +import com.codingapi.flow.form.permission.FormFieldPermission; +import com.codingapi.flow.node.manager.FieldPermissionManager; + +import java.util.List; + +public interface IFormFieldPermissionsNode { + + void setFormFieldPermissions(List formFieldPermissions); + + FieldPermissionManager formFieldsPermissionsManager(); +} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/NodeMapBuilder.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/NodeMapBuilder.java new file mode 100644 index 00000000..3bc2b7f2 --- /dev/null +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/builder/NodeMapBuilder.java @@ -0,0 +1,81 @@ +package com.codingapi.flow.node.builder; + +import com.codingapi.flow.action.IFlowAction; +import com.codingapi.flow.action.factory.FlowActionFactory; +import com.codingapi.flow.form.permission.FormFieldPermission; +import com.codingapi.flow.form.permission.PermissionType; +import com.codingapi.flow.node.BaseAuditNode; +import com.codingapi.flow.strategy.INodeStrategy; +import com.codingapi.flow.strategy.NodeStrategyFactory; +import lombok.SneakyThrows; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class NodeMapBuilder { + + @SuppressWarnings("unchecked") + public static List loadFormFieldPermissions(Map data) { + List> permissions = (List>) data.get("formFieldPermissions"); + if (permissions != null) { + List permissionList = new ArrayList<>(); + for (Map item : permissions) { + FormFieldPermission permission = new FormFieldPermission(); + permission.setFormCode((String) item.get("formCode")); + permission.setFieldName((String) item.get("fieldName")); + permission.setType(PermissionType.valueOf((String) item.get("type"))); + permissionList.add(permission); + } + return permissionList; + } + return null; + } + + @SuppressWarnings("unchecked") + public static List loadActions(Map data) { + List> actions = (List>) data.get("actions"); + if (actions != null) { + List actionList = new ArrayList<>(); + for (Map item : actions) { + IFlowAction action = FlowActionFactory.getInstance().createAction(item); + actionList.add(action); + } + return actionList; + } + return null; + } + + @SuppressWarnings("unchecked") + public static List loadNodeStrategies(Map data) { + List> nodeStrategies = (List>) data.get("nodeStrategies"); + if (nodeStrategies != null) { + List strategyList = new ArrayList<>(); + for (Map item : nodeStrategies) { + INodeStrategy strategy = NodeStrategyFactory.getInstance().createStrategy(item); + strategyList.add(strategy); + } + return strategyList; + } + return null; + } + + + @SneakyThrows + public static T formMap(Map map, Class clazz) { + T node = clazz.getDeclaredConstructor().newInstance(); + node.setId((String) map.get("id")); + node.setName((String) map.get("name")); + node.setView((String) map.get("view")); + node.setOperatorScript((String) map.get("operatorScript")); + node.setNodeTitleScript((String) map.get("nodeTitleScript")); + node.setErrorTriggerScript((String) map.get("errorTriggerScript")); + List permissionList = NodeMapBuilder.loadFormFieldPermissions(map); + node.setFormFieldPermissions(permissionList); + List actionList = NodeMapBuilder.loadActions(map); + node.setActions(actionList); + List strategyList = NodeMapBuilder.loadNodeStrategies(map); + node.setNodeStrategies(strategyList); + return node; + } +} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ApprovalNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ApprovalNode.java index e70f1e8f..5fee2511 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ApprovalNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ApprovalNode.java @@ -7,6 +7,7 @@ import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.node.builder.AuditNodeBuilder; import com.codingapi.flow.node.BaseAuditNode; +import com.codingapi.flow.node.builder.NodeMapBuilder; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; @@ -60,7 +61,7 @@ private static List defaultActions() { public static ApprovalNode formMap(Map map) { - return BaseAuditNode.formMap(map, ApprovalNode.class); + return NodeMapBuilder.formMap(map, ApprovalNode.class); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/HandleNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/HandleNode.java index e3b4ff78..3371bbf1 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/HandleNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/HandleNode.java @@ -5,6 +5,7 @@ import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.node.builder.AuditNodeBuilder; import com.codingapi.flow.node.BaseAuditNode; +import com.codingapi.flow.node.builder.NodeMapBuilder; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; @@ -55,7 +56,7 @@ private static List defaultActions() { } public static HandleNode formMap(Map map) { - return BaseAuditNode.formMap(map, HandleNode.class); + return NodeMapBuilder.formMap(map, HandleNode.class); } public static Builder builder() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/NotifyNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/NotifyNode.java index f504d919..5831f62a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/NotifyNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/NotifyNode.java @@ -5,6 +5,7 @@ import com.codingapi.flow.form.permission.FormFieldPermission; import com.codingapi.flow.node.builder.AuditNodeBuilder; import com.codingapi.flow.node.BaseAuditNode; +import com.codingapi.flow.node.builder.NodeMapBuilder; import com.codingapi.flow.script.node.ErrorTriggerScript; import com.codingapi.flow.script.node.NodeTitleScript; import com.codingapi.flow.script.node.OperatorLoadScript; @@ -54,7 +55,7 @@ private static List defaultActions() { } public static NotifyNode formMap(Map map) { - return BaseAuditNode.formMap(map, NotifyNode.class); + return NodeMapBuilder.formMap(map, NotifyNode.class); } public static Builder builder() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java index 337c42fa..5ec45ef0 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java @@ -2,14 +2,20 @@ import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.action.PassAction; +import com.codingapi.flow.context.GatewayContext; import com.codingapi.flow.form.permission.FormFieldPermission; -import com.codingapi.flow.node.builder.AuditNodeBuilder; -import com.codingapi.flow.node.BaseAuditNode; -import com.codingapi.flow.script.node.ErrorTriggerScript; +import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.builder.BaseNodeBuilder; +import com.codingapi.flow.node.builder.IFormFieldPermissionsNode; +import com.codingapi.flow.node.builder.NodeMapBuilder; +import com.codingapi.flow.node.manager.FieldPermissionManager; +import com.codingapi.flow.operator.IFlowOperator; +import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.script.node.NodeTitleScript; -import com.codingapi.flow.script.node.OperatorLoadScript; -import com.codingapi.flow.strategy.*; +import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import lombok.Getter; +import lombok.Setter; import java.util.ArrayList; import java.util.List; @@ -18,26 +24,79 @@ /** * 开始节点 */ -public class StartNode extends BaseAuditNode { +public class StartNode extends BaseFlowNode implements IFormFieldPermissionsNode { public static final String NODE_TYPE = "start"; public static final String DEFAULT_NAME = "开始节点"; + public static final String DEFAULT_VIEW = "default"; + + /** + * 渲染视图 + */ + @Getter + @Setter + private String view; + + /** + * 节点待办标题脚本 + */ + private NodeTitleScript nodeTitleScript; + + /** + * 表单字段权限 + */ + @Setter + private List formFieldPermissions; + + @Override public String getType() { return NODE_TYPE; } - public StartNode(String id, String name,List actions, String view, OperatorLoadScript operatorScript, NodeTitleScript nodeTitleScript, ErrorTriggerScript errorTriggerScript, List formFieldsPermissions, List nodeStrategies) { - super(id, name,actions, view, operatorScript, nodeTitleScript, errorTriggerScript, formFieldsPermissions, nodeStrategies); + public String generateTitle(FlowSession flowSession) { + return nodeTitleScript.execute(flowSession); + } + + + public void setNodeTitleScript(String script) { + this.nodeTitleScript = new NodeTitleScript(script); + } + + public StartNode(String id, String name, List actions, String view, NodeTitleScript nodeTitleScript, List formFieldPermissions) { + super(id, name, actions); + this.view = view; + this.nodeTitleScript = nodeTitleScript; + this.formFieldPermissions = formFieldPermissions; } public StartNode() { - this(RandomUtils.generateStringId(), DEFAULT_NAME,defaultActions(), DEFAULT_VIEW, OperatorLoadScript.creator(), NodeTitleScript.defaultScript(), ErrorTriggerScript.defaultNodeScript(), new ArrayList<>(), defaultStrategies()); + this(RandomUtils.generateStringId(), DEFAULT_NAME, defaultActions(), DEFAULT_VIEW, NodeTitleScript.defaultScript(), new ArrayList<>()); } - private static List defaultStrategies() { - return new ArrayList<>(); + + @Override + public List generateCurrentRecords(FlowSession session) { + List records = new ArrayList<>(); + FlowRecord currentRecord = session.getCurrentRecord(); + IFlowOperator operator = session.getCurrentOperator(); + IFlowAction action = session.getCurrentAction(); + if (currentRecord == null) { + FlowRecord flowRecord = new FlowRecord(session.updateSession(operator), action.id(), RandomUtils.generateStringId(), 0, 0); + records.add(flowRecord); + } else { + // 获取流程创建者 + IFlowOperator creatorOperator = GatewayContext.getInstance().getFlowOperator(currentRecord.getCreateOperatorId()); + FlowRecord flowRecord = new FlowRecord(session.updateSession(creatorOperator), action.id(), currentRecord.getProcessId(), currentRecord.getId(), 0); + records.add(flowRecord); + } + return records; + } + + @Override + public FieldPermissionManager formFieldsPermissionsManager() { + return new FieldPermissionManager(formFieldPermissions); } private static List defaultActions() { @@ -47,17 +106,44 @@ private static List defaultActions() { } public static StartNode formMap(Map map) { - return BaseAuditNode.formMap(map, StartNode.class); + StartNode startNode = BaseFlowNode.loadFromMap(map, StartNode.class); + startNode.setNodeTitleScript((String) map.get("nodeTitleScript")); + startNode.setFormFieldPermissions(NodeMapBuilder.loadFormFieldPermissions(map)); + return startNode; + } + + @Override + public Map toMap() { + Map map = super.toMap(); + map.put("name", name); + map.put("id", id); + map.put("view", view); + map.put("nodeTitleScript", nodeTitleScript.getScript()); + map.put("formFieldPermissions", formFieldPermissions); + map.put("type", getType()); + map.put("actions", actions.stream().map(IFlowAction::toMap).toList()); + return map; } + @Override + public void fillNewRecord(FlowSession session, FlowRecord flowRecord) { + flowRecord.setTitle(this.generateTitle(session)); + } + + public static Builder builder() { return new Builder(); } - public static class Builder extends AuditNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new StartNode()); } + + public Builder formFieldsPermissions(List permissions) { + node.setFormFieldPermissions(permissions); + return this; + } } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java index bb39a744..b66ec0f1 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java @@ -8,7 +8,6 @@ import com.codingapi.flow.form.FormData; import com.codingapi.flow.gateway.FlowOperatorGateway; import com.codingapi.flow.node.nodes.StartNode; -import com.codingapi.flow.node.manager.OperatorManager; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.pojo.request.FlowCreateRequest; import com.codingapi.flow.record.FlowRecord; @@ -16,7 +15,6 @@ import com.codingapi.flow.repository.WorkflowBackupRepository; import com.codingapi.flow.repository.WorkflowRepository; import com.codingapi.flow.session.FlowSession; -import com.codingapi.flow.utils.RandomUtils; import com.codingapi.flow.workflow.Workflow; import com.codingapi.springboot.framework.event.EventPusher; import lombok.AllArgsConstructor; @@ -56,22 +54,20 @@ public void create() { formData.reset(request.getFormData()); StartNode currentNode = (StartNode) workflow.getStartNode(); - FlowSession session = FlowSession.startSession(currentOperator, workflow, currentNode, formData, workflowBackup.getId()); + IFlowAction action = currentNode.actions().getActionById(request.getAdvice().getActionId()); + FlowSession session = FlowSession.startSession(currentOperator, workflow, currentNode, action, formData, workflowBackup.getId()); - OperatorManager currentOperators = currentNode.operators(session); - if (!currentOperators.match(currentOperator)) { - throw new IllegalArgumentException("node operator not match"); - } + currentNode.verifySession(session); - IFlowAction action = currentNode.actions().getActionById(request.getAdvice().getActionId()); + List flowRecords = currentNode.generateCurrentRecords(session); - FlowRecord flowRecord = new FlowRecord(session, action.id(), RandomUtils.generateStringId(), 0, 0); - flowRecord.verify(); - flowRecordRepository.save(flowRecord); + flowRecordRepository.saveAll(flowRecords); List events = new ArrayList<>(); - events.add(new FlowRecordStartEvent(flowRecord)); - events.add(new FlowRecordTodoEvent(flowRecord)); + for (FlowRecord flowRecord : flowRecords) { + events.add(new FlowRecordStartEvent(flowRecord)); + events.add(new FlowRecordTodoEvent(flowRecord)); + } // 推送事件 for (IFlowEvent event : events) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java index d0a70c6d..9217f24a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java @@ -81,11 +81,12 @@ public FlowSession(IFlowOperator currentOperator, public static FlowSession startSession(IFlowOperator currentOperator, - Workflow workflow, - IFlowNode currentNode, - FormData formData, - long backupId) { - return new FlowSession(currentOperator, workflow, currentNode, null,formData, null,null, backupId, new FlowAdvice()); + Workflow workflow, + IFlowNode currentNode, + IFlowAction currentAction, + FormData formData, + long backupId) { + return new FlowSession(currentOperator, workflow, currentNode, currentAction, formData, null, null, backupId, new FlowAdvice()); } @@ -125,10 +126,10 @@ public Object getFormData(String fieldName) { } public FlowSession updateSession(IFlowNode currentNode) { - return new FlowSession(currentOperator, workflow, currentNode,currentAction, formData,currentRecord, currentNodeRecords, backupId, advice); + return new FlowSession(currentOperator, workflow, currentNode, currentAction, formData, currentRecord, currentNodeRecords, backupId, advice); } public FlowSession updateSession(IFlowOperator currentOperator) { - return new FlowSession(currentOperator, workflow, currentNode,currentAction, formData,currentRecord, currentNodeRecords, backupId, advice); + return new FlowSession(currentOperator, workflow, currentNode, currentAction, formData, currentRecord, currentNodeRecords, backupId, advice); } } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java index 8b291f70..47252c71 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/script/ErrorTriggerScriptTest.java @@ -6,6 +6,7 @@ import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.FormMetaBuilder; import com.codingapi.flow.form.permission.PermissionType; +import com.codingapi.flow.node.builder.FormFieldPermissionsBuilder; import com.codingapi.flow.node.nodes.ApprovalNode; import com.codingapi.flow.node.nodes.StartNode; import com.codingapi.flow.node.nodes.EndNode; @@ -33,21 +34,25 @@ void execute() { .build(); StartNode startNode = StartNode.builder() - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.READ) + .addPermission("leave", "days", PermissionType.READ) + .addPermission("leave", "reason", PermissionType.READ) + .build() + ) .build(); ApprovalNode approvalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [request.getCreatedOperator()]}") - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.READ) - .addPermission("leave", "days", PermissionType.READ) - .addPermission("leave", "reason", PermissionType.READ) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.READ) + .addPermission("leave", "days", PermissionType.READ) + .addPermission("leave", "reason", PermissionType.READ) + .build() + ) .build(); EndNode endNode = EndNode.builder().build(); @@ -66,7 +71,7 @@ void execute() { FormData data = new FormData(form); data.getDataBody().set("name", "张三").set("days", 10).set("reason", "事由"); - FlowSession flowSession = FlowSession.startSession(user, workflow, startNode, data, 0); + FlowSession flowSession = FlowSession.startSession(user, workflow, startNode,startNode.getActions().get(0), data, 0); ErrorTriggerScript errorNodeTriggerScript = ErrorTriggerScript.defaultNodeScript(); ErrorThrow errorThrow = errorNodeTriggerScript.execute(flowSession); diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index 1228e354..3319bfd5 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -7,13 +7,14 @@ import com.codingapi.flow.form.FormMetaBuilder; import com.codingapi.flow.form.permission.PermissionType; import com.codingapi.flow.gateway.impl.UserGateway; +import com.codingapi.flow.node.builder.FormFieldPermissionsBuilder; import com.codingapi.flow.node.nodes.ApprovalNode; -import com.codingapi.flow.node.nodes.StartNode; import com.codingapi.flow.node.nodes.BranchNodeBranchNode; import com.codingapi.flow.node.nodes.EndNode; +import com.codingapi.flow.node.nodes.StartNode; import com.codingapi.flow.pojo.body.FlowAdviceBody; -import com.codingapi.flow.pojo.request.FlowCreateRequest; import com.codingapi.flow.pojo.request.FlowActionRequest; +import com.codingapi.flow.pojo.request.FlowCreateRequest; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.repository.*; import com.codingapi.flow.script.runtime.FlowScriptContext; @@ -56,21 +57,25 @@ void create() { StartNode startNode = StartNode .builder() - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); ApprovalNode approvalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [$bind.getOperatorById(2)]}") - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.READ) - .addPermission("leave", "days", PermissionType.READ) - .addPermission("leave", "reason", PermissionType.READ) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.READ) + .addPermission("leave", "days", PermissionType.READ) + .addPermission("leave", "reason", PermissionType.READ) + .build() + ) .build(); EndNode endNode = EndNode.builder().build(); @@ -124,21 +129,25 @@ void pass() { StartNode startNode = StartNode .builder() - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); ApprovalNode approvalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [$bind.getOperatorById(2)]}") - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.READ) - .addPermission("leave", "days", PermissionType.READ) - .addPermission("leave", "reason", PermissionType.READ) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.READ) + .addPermission("leave", "days", PermissionType.READ) + .addPermission("leave", "reason", PermissionType.READ) + .build() + ) .build(); EndNode endNode = EndNode.builder().build(); @@ -217,11 +226,13 @@ void condition() { StartNode startNode = StartNode .builder() - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); BranchNodeBranchNode departConditionNode = BranchNodeBranchNode.builder() @@ -239,21 +250,25 @@ void condition() { ApprovalNode departApprovalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [$bind.getOperatorById(2)]}") - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.READ) - .addPermission("leave", "days", PermissionType.READ) - .addPermission("leave", "reason", PermissionType.READ) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); ApprovalNode bossApprovalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.READ) - .addPermission("leave", "days", PermissionType.READ) - .addPermission("leave", "reason", PermissionType.READ) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); EndNode endNode = EndNode.builder().build(); @@ -345,21 +360,25 @@ public FlowRecord getRecordById(long id) { StartNode startNode = StartNode .builder() - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); ApprovalNode approvalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [$bind.getOperatorById(2)]}") - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.READ) - .addPermission("leave", "days", PermissionType.READ) - .addPermission("leave", "reason", PermissionType.READ) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); EndNode endNode = EndNode.builder().build(); diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java index 7724b842..9cebad69 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/workflow/WorkflowBuilderTest.java @@ -5,6 +5,7 @@ import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.form.FormMetaBuilder; import com.codingapi.flow.form.permission.PermissionType; +import com.codingapi.flow.node.builder.FormFieldPermissionsBuilder; import com.codingapi.flow.node.nodes.ApprovalNode; import com.codingapi.flow.node.nodes.StartNode; import com.codingapi.flow.node.nodes.EndNode; @@ -36,21 +37,25 @@ void buildBasicWorkflow() { StartNode startNode = StartNode .builder() - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); ApprovalNode approvalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [request.getCreatedOperator()]}") - .formFieldPermissionsBuilder() - .addPermission("leave", "name", PermissionType.READ) - .addPermission("leave", "days", PermissionType.READ) - .addPermission("leave", "reason", PermissionType.READ) - .build() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) .build(); EndNode endNode = EndNode.builder().build(); From ea6ac2d15d0f02652175be8b1d240ffbd7924b84 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 21:53:26 +0800 Subject: [PATCH 11/21] add matchBranch --- .../com/codingapi/flow/node/BaseFlowNode.java | 5 +++++ .../com/codingapi/flow/node/IFlowNode.java | 10 ++++++++++ .../flow/node/nodes/BranchNodeBranchNode.java | 20 +++++++++++++++++++ .../codingapi/flow/session/FlowSession.java | 7 ++++++- .../com/codingapi/flow/workflow/Workflow.java | 4 ++-- 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 38bad07f..f1754da6 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -136,6 +136,11 @@ public void fillNewRecord(FlowSession session, FlowRecord flowRecord) { } + @Override + public List matchBranch(List nodeList, FlowSession flowSession) { + return nodeList; + } + @Override public List generateCurrentRecords(FlowSession session) { return List.of(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index 02d45cf8..7095ef4f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -82,4 +82,14 @@ public interface IFlowNode { * @param flowRecord 流程记录 */ void fillNewRecord(FlowSession session,FlowRecord flowRecord); + + + /** + * 匹配条件分支 + * @param nodeList 当前节点下的所有条件 + * @param flowSession 当前会话 + * @return 匹配的节点 + */ + List matchBranch(List nodeList, FlowSession flowSession); + } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java index 6c72a53d..146426b8 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java @@ -1,12 +1,16 @@ package com.codingapi.flow.node.nodes; import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.script.node.ConditionScript; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; import lombok.Setter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; import java.util.Map; /** @@ -45,6 +49,22 @@ public boolean isContinueTrigger(FlowSession request) { return conditionScript.execute(request); } + @Override + public List matchBranch(List nodeList, FlowSession flowSession) { + List nodes = new ArrayList<>(); + for (IFlowNode node: nodeList){ + if (node.isContinueTrigger(flowSession)){ + nodes.add(node); + } + } + // 获取最小order的节点 + nodes.sort(Comparator.comparingInt(IFlowNode::getOrder)); + if(!nodes.isEmpty()){ + return nodes.subList(0,1); + } + return nodes; + } + @Override public Map toMap() { Map map = super.toMap(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java index 9217f24a..e143302b 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java @@ -118,7 +118,12 @@ public String getCurrentNodeType() { } public List nextNodes() { - return workflow.nextNodes(this.getCurrentNode()); + List nodeList = workflow.nextNodes(this.getCurrentNode()); + if(!nodeList.isEmpty() && nodeList.size()>1){ + IFlowNode currentNode = nodeList.get(0); + return currentNode.matchBranch(nodeList,this); + } + return nodeList; } public Object getFormData(String fieldName) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java index c04d716a..0ee9ad94 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java @@ -5,9 +5,9 @@ import com.codingapi.flow.edge.FlowEdge; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.IFlowNode; -import com.codingapi.flow.node.nodes.StartNode; -import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.node.factory.NodeFactory; +import com.codingapi.flow.node.nodes.EndNode; +import com.codingapi.flow.node.nodes.StartNode; import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.script.node.OperatorMatchScript; import com.codingapi.flow.utils.RandomUtils; From a4c2c525992b1011b70dbf8c2d9433f2fb7875e7 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Tue, 20 Jan 2026 23:02:34 +0800 Subject: [PATCH 12/21] add matchBranch --- .../src/main/java/com/codingapi/flow/action/BaseAction.java | 2 +- .../src/main/java/com/codingapi/flow/node/BaseAuditNode.java | 2 +- .../src/main/java/com/codingapi/flow/node/BaseFlowNode.java | 2 +- .../src/main/java/com/codingapi/flow/node/IFlowNode.java | 2 +- .../com/codingapi/flow/node/nodes/BranchNodeBranchNode.java | 4 ++-- .../src/main/java/com/codingapi/flow/node/nodes/EndNode.java | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index fea86ade..f0170664 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -100,7 +100,7 @@ public void triggerNode(FlowSession flowSession) { List nextNodes = flowSession.nextNodes(); for (IFlowNode node : nextNodes) { FlowSession triggerSession = flowSession.updateSession(node); - if (node.isContinueTrigger(triggerSession)) { + if (node.continueTrigger(triggerSession)) { this.triggerNode(triggerSession); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index d51f0fe9..e98e1dce 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -182,7 +182,7 @@ public StrategyManager strategies() { @Override - public boolean isContinueTrigger(FlowSession session) { + public boolean continueTrigger(FlowSession session) { return false; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index f1754da6..09c49f28 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -99,7 +99,7 @@ public void verifyNode(FormMeta form) { } @Override - public boolean isContinueTrigger(FlowSession session) { + public boolean continueTrigger(FlowSession session) { return true; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index 7095ef4f..aaf662c3 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -49,7 +49,7 @@ public interface IFlowNode { * @param session 会话 * @return true: 继续执行下一个节点 */ - boolean isContinueTrigger(FlowSession session); + boolean continueTrigger(FlowSession session); /** * 节点验证会话 diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java index 146426b8..dc106a91 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java @@ -45,7 +45,7 @@ public BranchNodeBranchNode() { * 匹配条件 */ @Override - public boolean isContinueTrigger(FlowSession request) { + public boolean continueTrigger(FlowSession request) { return conditionScript.execute(request); } @@ -53,7 +53,7 @@ public boolean isContinueTrigger(FlowSession request) { public List matchBranch(List nodeList, FlowSession flowSession) { List nodes = new ArrayList<>(); for (IFlowNode node: nodeList){ - if (node.isContinueTrigger(flowSession)){ + if (node.continueTrigger(flowSession)){ nodes.add(node); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java index 9cb754a0..11aa4914 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java @@ -25,7 +25,7 @@ public String getType() { @Override - public boolean isContinueTrigger(FlowSession session) { + public boolean continueTrigger(FlowSession session) { return false; } From d03c99bb1122a9eca43ed34856c1280d2743a967 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 10:05:49 +0800 Subject: [PATCH 13/21] format code --- .../src/main/java/com/codingapi/flow/action/PassAction.java | 2 -- .../src/main/java/com/codingapi/flow/node/BaseFlowNode.java | 3 --- .../src/main/java/com/codingapi/flow/node/nodes/DelayNode.java | 1 - .../src/main/java/com/codingapi/flow/node/nodes/EndNode.java | 3 --- .../java/com/codingapi/flow/node/nodes/ParallelBranchNode.java | 1 - .../java/com/codingapi/flow/node/nodes/RouterBranchNode.java | 1 - 6 files changed, 11 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java index 9279c460..33d2d3b6 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java @@ -2,13 +2,11 @@ import com.codingapi.flow.context.RepositoryContext; import com.codingapi.flow.event.FlowRecordDoneEvent; -import com.codingapi.flow.event.FlowRecordFinishEvent; import com.codingapi.flow.event.FlowRecordTodoEvent; import com.codingapi.flow.event.IFlowEvent; import com.codingapi.flow.node.BaseAuditNode; import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.node.manager.StrategyManager; -import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 09c49f28..32e417ed 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -4,15 +4,12 @@ import com.codingapi.flow.action.ReturnAction; import com.codingapi.flow.action.SaveAction; import com.codingapi.flow.action.TransferAction; -import com.codingapi.flow.action.factory.FlowActionFactory; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.builder.NodeMapBuilder; import com.codingapi.flow.node.manager.ActionManager; -import com.codingapi.flow.node.manager.FieldPermissionManager; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowAdvice; import com.codingapi.flow.session.FlowSession; -import com.codingapi.flow.workflow.Workflow; import lombok.Getter; import lombok.Setter; import lombok.SneakyThrows; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java index def24b1d..4a5e78fc 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/DelayNode.java @@ -4,7 +4,6 @@ import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; -import java.util.ArrayList; import java.util.Map; /** diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java index 11aa4914..c7440453 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java @@ -1,13 +1,10 @@ package com.codingapi.flow.node.nodes; -import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.node.BaseFlowNode; import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; -import java.util.ArrayList; -import java.util.List; import java.util.Map; /** diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java index 59ea8881..c796d562 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java @@ -4,7 +4,6 @@ import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; -import java.util.ArrayList; import java.util.Map; /** diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java index 14bc5886..1ccd23e0 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/RouterBranchNode.java @@ -4,7 +4,6 @@ import com.codingapi.flow.node.builder.BaseNodeBuilder; import com.codingapi.flow.utils.RandomUtils; -import java.util.ArrayList; import java.util.Map; /** From f188bf5aef8616b0f35feab36435a948f74ed3f9 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 11:55:52 +0800 Subject: [PATCH 14/21] add parallel --- .../flow/context/RepositoryContext.java | 4 +- .../flow/node/nodes/ParallelBranchNode.java | 128 ++++++++++++- .../com/codingapi/flow/record/FlowRecord.java | 34 ++++ .../flow/repository/FlowRecordRepository.java | 2 +- .../flow/service/impl/FlowActionService.java | 3 +- .../repository/FlowRecordRepositoryImpl.java | 8 +- .../flow/service/FlowServiceTest.java | 179 +++++++++++++++++- 7 files changed, 346 insertions(+), 12 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java index fa3320f1..a0494fd4 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java @@ -42,8 +42,8 @@ public void saveRecords(List flowRecords) { flowRecordRepository.saveAll(flowRecords); } - public List findRecordsByFromId(long fromId) { - return flowRecordRepository.findRecordsByFromId(fromId); + public List findRecordsByFromIdAndNodeId(long fromId,String nodeId) { + return flowRecordRepository.findRecordsByFromIdAndNodeId(fromId,nodeId); } public List findRecordsByProcessId(String processId) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java index c796d562..a688d591 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java @@ -1,10 +1,16 @@ package com.codingapi.flow.node.nodes; import com.codingapi.flow.node.BaseFlowNode; +import com.codingapi.flow.node.IFlowNode; import com.codingapi.flow.node.builder.BaseNodeBuilder; +import com.codingapi.flow.record.FlowRecord; +import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import com.codingapi.flow.workflow.Workflow; +import lombok.AllArgsConstructor; +import lombok.Getter; -import java.util.Map; +import java.util.*; /** * 并行节点 @@ -27,6 +33,124 @@ public ParallelBranchNode() { this(RandomUtils.generateStringId(), DEFAULT_NAME); } + /** + * 匹配条件分支 + * + * @param nodeList 当前节点下的所有条件 + * @param flowSession 当前会话 + * @return 匹配的节点 + */ + public List matchBranch(List nodeList, FlowSession flowSession) { + Workflow workflow = flowSession.getWorkflow(); + ParallelNodeRelationHelper helper = new ParallelNodeRelationHelper(nodeList, workflow); + // 分析并行分支的结束汇聚节点 + IFlowNode overNode = helper.fetchParallelEndNode(); + if(overNode==null){ + throw new IllegalArgumentException("parallel end node is null"); + } + + // 在流程记录中记录,合并的条件信息。 + FlowRecord flowRecord = flowSession.getCurrentRecord(); + flowRecord.parallelBranchNode(overNode.getId(), nodeList.size()); + + return nodeList; + } + + + private static class ParallelNodeRelationHelper { + private final Workflow workflow; + private final List parallelNodes; + + public ParallelNodeRelationHelper(List parallelNodes, Workflow workflow) { + this.parallelNodes = parallelNodes; + this.workflow = workflow; + } + + public IFlowNode fetchParallelEndNode() { + if (parallelNodes.isEmpty()) { + return null; + } + if (parallelNodes.size() > 1) { + LineManager lineManager = new LineManager(); + for (IFlowNode node : parallelNodes) { + List nodeLines = this.getNodeLines(node); + lineManager.addLine(nodeLines); + } + return lineManager.fetchEndNode(workflow); + } + return parallelNodes.get(0); + } + + private List getNodeLines(IFlowNode node) { + List lines = new ArrayList<>(); + lines.add(node.getId()); + IFlowNode currentNode = node; + NodeManger nodeManger = null; + do { + nodeManger = this.nextNodes(currentNode); + currentNode = nodeManger.getCurrentNode(); + lines.add(currentNode.getId()); + } while (nodeManger.next()); + return lines; + } + + private NodeManger nextNodes(IFlowNode node) { + return new NodeManger(workflow.nextNodes(node)); + } + + private static class LineManager { + + private final List> lines = new ArrayList<>(); + + public void addLine(List line) { + lines.add(line); + } + + + public IFlowNode fetchEndNode(Workflow workflow) { + // 对线进行倒叙 + List firstLine = lines.get(0); + Collections.reverse(firstLine); + + IFlowNode flowNode = null; + for (int i = 1; i < lines.size(); i++) { + List line = lines.get(i); + if (flowNode == null) { + for (String nodeId : firstLine) { + if (line.contains(nodeId)) { + flowNode = workflow.getFlowNode(nodeId); + } + } + } + } + return flowNode; + } + + } + + + @AllArgsConstructor + private static class NodeManger { + @Getter + private final List nodes; + + public IFlowNode getCurrentNode() { + return nodes.get(0); + } + + public boolean next() { + if (nodes.isEmpty()) { + return false; + } + IFlowNode currentNode = nodes.get(0); + if (currentNode instanceof EndNode) { + return false; + } + return true; + } + } + } + public static ParallelBranchNode formMap(Map map) { return BaseFlowNode.loadFromMap(map, ParallelBranchNode.class); @@ -36,7 +160,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder extends BaseNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new ParallelBranchNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java index d421aba6..1a69f8ee 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java @@ -152,6 +152,17 @@ public class FlowRecord { */ private long interferedOperatorId; + /** + * 并行分支节点id + */ + private String parallelBranchNodeId; + + /** + * 并行分支数量 + */ + private int parallelBranchCount; + + public FlowRecord(FlowSession flowSession, String actionId, String processId, long fromId, int nodeOrder) { this.workCode = flowSession.getWorkCode(); this.workBackupId = flowSession.getBackupId(); @@ -172,7 +183,30 @@ public FlowRecord(FlowSession flowSession, String actionId, String processId, lo this.createTime = System.currentTimeMillis(); this.isInterfere = flowSession.getWorkflow().isInterfere(); this.hidden = false; + flowSession.getCurrentNode().fillNewRecord(flowSession,this); + this.extendsRecord(flowSession.getCurrentRecord()); + + this.verify(); + } + + + public void extendsRecord(FlowRecord record) { + if(record!=null) { + this.parallelBranchNodeId = record.parallelBranchNodeId; + this.parallelBranchCount = record.parallelBranchCount; + } + } + + + /** + * 并行分支节点 + * @param parallelBranchNodeId 并行分支节点id + * @param parallelBranchCount 并行分支数量 + */ + public void parallelBranchNode(String parallelBranchNodeId, int parallelBranchCount) { + this.parallelBranchNodeId = parallelBranchNodeId; + this.parallelBranchCount = parallelBranchCount; } public void verify() { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java index ffb47332..34a165a0 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java @@ -14,7 +14,7 @@ public interface FlowRecordRepository { void delete(FlowRecord flowRecord); - List findRecordsByFromId(long fromId); + List findRecordsByFromIdAndNodeId(long fromId,String nodeId); List findRecordsByProcessId(String processId); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java index a8139845..1e0fc377 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java @@ -68,7 +68,8 @@ public void action() { FormData formData = new FormData(workflow.getForm()); formData.reset(request.getFormData()); FlowAdvice flowAdvice = request.toFlowAdvice(workflow, flowAction); - List currentRecords = flowRecordRepository.findRecordsByFromId(flowRecord.getFromId()); + + List currentRecords = flowRecordRepository.findRecordsByFromIdAndNodeId(flowRecord.getFromId(), flowRecord.getNodeId()); FlowSession session = new FlowSession(currentOperator, workflow, currentNode, flowAction, formData, flowRecord, currentRecords, workflowBackup.getId(), flowAdvice); currentNode.verifySession(session); diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java index 1308e09f..8ab82a22 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java @@ -45,8 +45,12 @@ public void delete(FlowRecord flowRecord) { } @Override - public List findRecordsByFromId(long fromId) { - return cache.values().stream().filter(flowRecord -> flowRecord.getFromId() == fromId).toList(); + public List findRecordsByFromIdAndNodeId(long fromId,String nodeId) { + return cache.values().stream().filter(flowRecord -> + flowRecord.getFromId() == fromId + && flowRecord.getNodeId().equals(nodeId) + ) + .toList(); } @Override diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index 3319bfd5..b34aadb5 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -8,10 +8,7 @@ import com.codingapi.flow.form.permission.PermissionType; import com.codingapi.flow.gateway.impl.UserGateway; import com.codingapi.flow.node.builder.FormFieldPermissionsBuilder; -import com.codingapi.flow.node.nodes.ApprovalNode; -import com.codingapi.flow.node.nodes.BranchNodeBranchNode; -import com.codingapi.flow.node.nodes.EndNode; -import com.codingapi.flow.node.nodes.StartNode; +import com.codingapi.flow.node.nodes.*; import com.codingapi.flow.pojo.body.FlowAdviceBody; import com.codingapi.flow.pojo.request.FlowActionRequest; import com.codingapi.flow.pojo.request.FlowCreateRequest; @@ -449,4 +446,178 @@ public FlowRecord getRecordById(long id) { assertEquals(4, records.stream().filter(FlowRecord::isFinish).toList().size()); } + + + + + /** + * 并行分支测试 + */ + @Test + void parallel() { + + User user = new User(1, "user"); + User depart = new User(2, "depart"); + User boss = new User(3, "boss"); + userGateway.save(user); + userGateway.save(depart); + userGateway.save(boss); + + GatewayContext.getInstance().setFlowOperatorGateway(userGateway); + + FormMeta form = FormMetaBuilder.builder() + .name("请假流程") + .code("leave") + .addField("请假人", "name", "string") + .addField("请假天数", "days", "int") + .addField("请假事由", "reason", "string") + .build(); + + StartNode startNode = StartNode + .builder() + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) + .build(); + + ParallelBranchNode parallelBranchNode1 = ParallelBranchNode.builder() + .name("并行分支1") + .order(1) + .build(); + + ParallelBranchNode parallelBranchNode2 = ParallelBranchNode.builder() + .name("并行分支2") + .order(2) + .build(); + + ApprovalNode departApprovalNode = ApprovalNode.builder() + .name("经理审批") + .operatorScript("def run(request){return [$bind.getOperatorById(2)]}") + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) + .build(); + + ApprovalNode bossApprovalNode1 = ApprovalNode.builder() + .name("经理审批") + .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) + .build(); + + ApprovalNode bossApprovalNode2 = ApprovalNode.builder() + .name("经理审批") + .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) + .build(); + + ApprovalNode endOver1 = ApprovalNode.builder() + .name("end-over1") + .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) + .build(); + + ApprovalNode endOver2 = ApprovalNode.builder() + .name("end-over2") + .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) + .build(); + + EndNode endNode = EndNode.builder().build(); + Workflow workflow = WorkflowBuilder.builder() + .title("请假流程") + .code("leave") + .createdOperator(user) + .form(form) + .addNode(startNode) + .addNode(parallelBranchNode1) + .addNode(parallelBranchNode2) + .addNode(departApprovalNode) + .addNode(bossApprovalNode1) + .addNode(bossApprovalNode2) + .addNode(endOver1) + .addNode(endOver2) + .addNode(endNode) + .addEdge(new FlowEdge(startNode.getId(), parallelBranchNode1.getId())) + .addEdge(new FlowEdge(startNode.getId(), parallelBranchNode2.getId())) + .addEdge(new FlowEdge(parallelBranchNode1.getId(), departApprovalNode.getId())) + .addEdge(new FlowEdge(parallelBranchNode2.getId(), bossApprovalNode1.getId())) + .addEdge(new FlowEdge(departApprovalNode.getId(), endOver1.getId())) + .addEdge(new FlowEdge(bossApprovalNode1.getId(), bossApprovalNode2.getId())) + .addEdge(new FlowEdge(bossApprovalNode2.getId(), endOver1.getId())) + .addEdge(new FlowEdge(endOver1.getId(), endOver2.getId())) + .addEdge(new FlowEdge(endOver2.getId(), endNode.getId())) + .build(); + + workflowRepository.save(workflow); + + Map data = Map.of("name", "lorne", "days", 3, "reason", "leave"); + + FlowCreateRequest request = new FlowCreateRequest(); + request.setWorkId(workflow.getId()); + request.setFormData(data); + List actions = startNode.actions().getActions(); + request.setAdvice(new FlowAdviceBody(actions.get(0).id(), "同意", user.getUserId())); + + flowService.create(request); + + List recordList = flowRecordRepository.findTodoByOperator(user.getUserId()); + assertEquals(1, recordList.size()); + + FlowActionRequest submitRequest = new FlowActionRequest(); + submitRequest.setFormData(data); + submitRequest.setRecordId(recordList.get(0).getId()); + submitRequest.setAdvice(new FlowAdviceBody(actions.get(0).id(), "同意", user.getUserId())); + flowService.action(submitRequest); + + List lorneRecordList = flowRecordRepository.findTodoByOperator(depart.getUserId()); + assertEquals(1, lorneRecordList.size()); + + + List lorneActions = departApprovalNode.actions().getActions(); + + FlowActionRequest lorneRequest = new FlowActionRequest(); + lorneRequest.setFormData(data); + lorneRequest.setRecordId(lorneRecordList.get(0).getId()); + lorneRequest.setAdvice(new FlowAdviceBody(lorneActions.get(0).id(), "同意", depart.getUserId())); + flowService.action(lorneRequest); + + List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); + assertEquals(4, records.size()); + assertEquals(2, records.stream().filter(FlowRecord::isTodo).toList().size()); + assertEquals(0, records.stream().filter(FlowRecord::isFinish).toList().size()); + + } + } \ No newline at end of file From a7d2e568f413ba9d51574b24c3530bbdd60ec8f1 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 12:02:08 +0800 Subject: [PATCH 15/21] add todo --- .../main/java/com/codingapi/flow/action/BaseAction.java | 1 + .../main/java/com/codingapi/flow/node/BaseFlowNode.java | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index f0170664..615eaa10 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -107,6 +107,7 @@ public void triggerNode(FlowSession flowSession) { } + // TODO 需要判断是从什么情况下触发的完成,如果是非PASS结束的视为非正常结束 public void flowFinish(FlowRecord latestRecord,IFlowNode latestNode){ List recordList = new ArrayList<>(); // 添加当前节点到记录中 diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 32e417ed..60d0b93b 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -97,6 +97,13 @@ public void verifyNode(FormMeta form) { @Override public boolean continueTrigger(FlowSession session) { + FlowRecord currentRecord = session.getCurrentRecord(); + String id = this.getId(); + // 如果是合并的汇聚节点的话,需要等全部分支结束才能继续执行 + if(currentRecord.getParallelBranchNodeId().equals(id)){ + //TODO 判断并行分支是的都汇聚到了该节点,如果都汇聚到了则继续执行。 + } + return true; } From 4a2341238bfe3345b0215e5630e87d4fd026e0f2 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 15:03:21 +0800 Subject: [PATCH 16/21] add todo --- .../com/codingapi/flow/action/BaseAction.java | 21 ---- .../com/codingapi/flow/action/PassAction.java | 5 +- .../codingapi/flow/action/RejectAction.java | 15 ++- .../flow/context/RepositoryContext.java | 7 +- .../codingapi/flow/node/BaseAuditNode.java | 7 +- .../com/codingapi/flow/node/BaseFlowNode.java | 26 +++-- .../codingapi/flow/node/nodes/EndNode.java | 39 ++++++- .../flow/node/nodes/ParallelBranchNode.java | 2 +- .../codingapi/flow/node/nodes/StartNode.java | 4 +- .../com/codingapi/flow/record/FlowRecord.java | 21 ++-- .../flow/repository/FlowRecordRepository.java | 2 + .../repository/FlowRecordRepositoryImpl.java | 8 ++ .../flow/service/FlowServiceTest.java | 101 +++++++----------- 13 files changed, 139 insertions(+), 119 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index 615eaa10..d460750d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -107,25 +107,4 @@ public void triggerNode(FlowSession flowSession) { } - // TODO 需要判断是从什么情况下触发的完成,如果是非PASS结束的视为非正常结束 - public void flowFinish(FlowRecord latestRecord,IFlowNode latestNode){ - List recordList = new ArrayList<>(); - // 添加当前节点到记录中 - if (latestNode instanceof EndNode) { - recordList.add(latestRecord); - // 添加历史记录到记录中 - List historyRecords = RepositoryContext.getInstance().findRecordsByProcessId(latestRecord.getProcessId()); - recordList.addAll(historyRecords); - // 设置状态为完成 - recordList.forEach(item -> { - item.finish(true); - }); - - RepositoryContext.getInstance().saveRecords(recordList); - - // 流程是否正常结束 - EventPusher.push(new FlowRecordFinishEvent(latestRecord)); - } - } - } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java index 33d2d3b6..52e2d9df 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java @@ -77,10 +77,7 @@ public void triggerNode(FlowSession flowSession) { for (IFlowNode node : nextNodes) { FlowSession triggerSession = flowSession.updateSession(node); List records = this.generateRecords(triggerSession); - if (records.isEmpty()) { - IFlowNode latestNode = triggerSession.getCurrentNode(); - super.flowFinish(flowRecord, latestNode); - }else { + if (!records.isEmpty()) { for (FlowRecord record : records) { if (record.isShow()) { flowEvents.add(new FlowRecordTodoEvent(record)); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java index aae027c2..d1dad3f8 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java @@ -80,17 +80,14 @@ public void triggerNode(FlowSession flowSession) { recordList.add(flowRecord); List records = this.generateRecords(flowSession); - IFlowNode latestNode = flowSession.getCurrentNode(); - if(records.isEmpty()){ - super.flowFinish(flowRecord, latestNode); - } - recordList.addAll(records); - for (FlowRecord record : records){ - if (record.isShow()) { - flowEvents.add(new FlowRecordTodoEvent(record)); + if(!records.isEmpty()) { + recordList.addAll(records); + for (FlowRecord record : records) { + if (record.isShow()) { + flowEvents.add(new FlowRecordTodoEvent(record)); + } } } - RepositoryContext.getInstance().saveRecords(recordList); flowEvents.forEach(EventPusher::push); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java index a0494fd4..bee0f0e4 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java @@ -42,12 +42,15 @@ public void saveRecords(List flowRecords) { flowRecordRepository.saveAll(flowRecords); } - public List findRecordsByFromIdAndNodeId(long fromId,String nodeId) { - return flowRecordRepository.findRecordsByFromIdAndNodeId(fromId,nodeId); + public List findRecordsByFromIdAndNodeId(long fromId, String nodeId) { + return flowRecordRepository.findRecordsByFromIdAndNodeId(fromId, nodeId); } public List findRecordsByProcessId(String processId) { return flowRecordRepository.findRecordsByProcessId(processId); } + public List findRecordsNodeIdAndParallelId(String nodeId, String parallelId) { + return flowRecordRepository.findRecordsNodeIdAndParallelId(nodeId, parallelId); + } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index e98e1dce..4543ab47 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -234,13 +234,18 @@ public boolean isDone(FlowSession session) { */ @Override public List generateCurrentRecords(FlowSession session) { + + if(this.isWaitParallelRecord(session)){ + return List.of(); + } + List records = new ArrayList<>(); FlowRecord currentRecord = session.getCurrentRecord(); OperatorManager operatorManager = this.operators(session); List operators = operatorManager.getOperators(); for (int order = 0; order < operators.size(); order++) { IFlowOperator operator = operators.get(order); - FlowRecord flowRecord = new FlowRecord(session.updateSession(operator), this.id, currentRecord.getProcessId(), currentRecord.getId(), order); + FlowRecord flowRecord = new FlowRecord(session.updateSession(operator), this.id, order); records.add(flowRecord); } if (operators.size() > 1) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 60d0b93b..25a3864a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -4,6 +4,7 @@ import com.codingapi.flow.action.ReturnAction; import com.codingapi.flow.action.SaveAction; import com.codingapi.flow.action.TransferAction; +import com.codingapi.flow.context.RepositoryContext; import com.codingapi.flow.form.FormMeta; import com.codingapi.flow.node.builder.NodeMapBuilder; import com.codingapi.flow.node.manager.ActionManager; @@ -56,7 +57,7 @@ public BaseFlowNode(String id, String name, int order) { this(id, name, order, new ArrayList<>()); } - public BaseFlowNode(String id, String name,List actions) { + public BaseFlowNode(String id, String name, List actions) { this(id, name, 0, actions); } @@ -95,15 +96,26 @@ public void verifyNode(FormMeta form) { } - @Override - public boolean continueTrigger(FlowSession session) { + /** + * 是否等待并行节点的汇聚 + */ + public boolean isWaitParallelRecord(FlowSession session) { FlowRecord currentRecord = session.getCurrentRecord(); - String id = this.getId(); - // 如果是合并的汇聚节点的话,需要等全部分支结束才能继续执行 - if(currentRecord.getParallelBranchNodeId().equals(id)){ - //TODO 判断并行分支是的都汇聚到了该节点,如果都汇聚到了则继续执行。 + if (currentRecord != null && this.getId().equals(currentRecord.getParallelBranchNodeId())) { + //TODO + System.out.println(currentRecord.isTodo()); + // 此时还没有创建当前节点的记录数据,当时已经到了该汇聚节点,需要判断汇聚次数。 + int parallelBranchCount = currentRecord.getParallelBranchCount(); + List parallelRecords = RepositoryContext.getInstance().findRecordsNodeIdAndParallelId(this.getId(), currentRecord.getParallelId()); + List finishRecords = parallelRecords.stream().filter(FlowRecord::isFinish).toList(); + return parallelBranchCount != finishRecords.size(); } + return false; + } + + @Override + public boolean continueTrigger(FlowSession session) { return true; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java index c7440453..9807fcf3 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/EndNode.java @@ -1,10 +1,17 @@ package com.codingapi.flow.node.nodes; +import com.codingapi.flow.action.IFlowAction; +import com.codingapi.flow.action.PassAction; +import com.codingapi.flow.context.RepositoryContext; +import com.codingapi.flow.event.FlowRecordFinishEvent; import com.codingapi.flow.node.BaseFlowNode; import com.codingapi.flow.node.builder.BaseNodeBuilder; +import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; +import com.codingapi.springboot.framework.event.EventPusher; +import java.util.List; import java.util.Map; /** @@ -21,6 +28,36 @@ public String getType() { } + @Override + public List generateCurrentRecords(FlowSession session) { + if(this.isWaitParallelRecord(session)){ + return List.of(); + } + // 构建结束记录 + FlowRecord finishRecord = new FlowRecord(session, session.getCurrentAction().id(), 0); + finishRecord.finish(true); + return List.of(finishRecord); + } + + @Override + public void fillNewRecord(FlowSession session, FlowRecord flowRecord) { + flowRecord.setTitle("over"); + flowRecord.setCurrentOperatorId(-1); + + IFlowAction currentAction = session.getCurrentAction(); + // 标记当前流程结束 + FlowRecord latestRecord = session.getCurrentRecord(); + // 添加历史记录到记录中 + List historyRecords = RepositoryContext.getInstance().findRecordsByProcessId(latestRecord.getProcessId()); + // 设置状态为完成 + historyRecords.forEach(item -> { + item.finish(currentAction instanceof PassAction); + }); + RepositoryContext.getInstance().saveRecords(historyRecords); + // 流程是否正常结束 + EventPusher.push(new FlowRecordFinishEvent(latestRecord)); + } + @Override public boolean continueTrigger(FlowSession session) { return false; @@ -42,7 +79,7 @@ public static Builder builder() { return new Builder(); } - public static class Builder extends BaseNodeBuilder { + public static class Builder extends BaseNodeBuilder { public Builder() { super(new EndNode()); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java index a688d591..8e2c4f5d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java @@ -51,7 +51,7 @@ public List matchBranch(List nodeList, FlowSession flowSes // 在流程记录中记录,合并的条件信息。 FlowRecord flowRecord = flowSession.getCurrentRecord(); - flowRecord.parallelBranchNode(overNode.getId(), nodeList.size()); + flowRecord.parallelBranchNode(overNode.getId(), nodeList.size(),RandomUtils.generateStringId()); return nodeList; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java index 5ec45ef0..20d46695 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/StartNode.java @@ -83,12 +83,12 @@ public List generateCurrentRecords(FlowSession session) { IFlowOperator operator = session.getCurrentOperator(); IFlowAction action = session.getCurrentAction(); if (currentRecord == null) { - FlowRecord flowRecord = new FlowRecord(session.updateSession(operator), action.id(), RandomUtils.generateStringId(), 0, 0); + FlowRecord flowRecord = new FlowRecord(session.updateSession(operator), action.id(), 0); records.add(flowRecord); } else { // 获取流程创建者 IFlowOperator creatorOperator = GatewayContext.getInstance().getFlowOperator(currentRecord.getCreateOperatorId()); - FlowRecord flowRecord = new FlowRecord(session.updateSession(creatorOperator), action.id(), currentRecord.getProcessId(), currentRecord.getId(), 0); + FlowRecord flowRecord = new FlowRecord(session.updateSession(creatorOperator), action.id(), 0); records.add(flowRecord); } return records; diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java index 1a69f8ee..b8ff9ac1 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java @@ -1,6 +1,7 @@ package com.codingapi.flow.record; import com.codingapi.flow.session.FlowSession; +import com.codingapi.flow.utils.RandomUtils; import lombok.Getter; import lombok.Setter; import org.springframework.util.StringUtils; @@ -152,6 +153,11 @@ public class FlowRecord { */ private long interferedOperatorId; + /** + * 并行id + */ + private String parallelId; + /** * 并行分支节点id */ @@ -163,15 +169,15 @@ public class FlowRecord { private int parallelBranchCount; - public FlowRecord(FlowSession flowSession, String actionId, String processId, long fromId, int nodeOrder) { + public FlowRecord(FlowSession flowSession, String actionId, int nodeOrder) { this.workCode = flowSession.getWorkCode(); this.workBackupId = flowSession.getBackupId(); this.nodeId = flowSession.getCurrentNodeId(); this.nodeType = flowSession.getCurrentNodeType(); this.formData = flowSession.getFormData().toMapData(); - this.fromId = fromId; + this.fromId = 0; this.nodeOrder = nodeOrder; - this.processId = processId; + this.processId = RandomUtils.generateStringId(); this.createOperatorId = flowSession.getCreatedOperator().getUserId(); this.recordState = SATE_RECORD_TODO; this.actionId = actionId; @@ -195,6 +201,9 @@ public void extendsRecord(FlowRecord record) { if(record!=null) { this.parallelBranchNodeId = record.parallelBranchNodeId; this.parallelBranchCount = record.parallelBranchCount; + this.parallelId = record.parallelId; + this.fromId = record.id; + this.processId = record.processId; } } @@ -204,9 +213,10 @@ public void extendsRecord(FlowRecord record) { * @param parallelBranchNodeId 并行分支节点id * @param parallelBranchCount 并行分支数量 */ - public void parallelBranchNode(String parallelBranchNodeId, int parallelBranchCount) { + public void parallelBranchNode(String parallelBranchNodeId, int parallelBranchCount,String parallelId) { this.parallelBranchNodeId = parallelBranchNodeId; this.parallelBranchCount = parallelBranchCount; + this.parallelId = parallelId; } public void verify() { @@ -234,9 +244,6 @@ public void verify() { if (createOperatorId <= 0) { throw new IllegalArgumentException("createOperator is null"); } - if (currentOperatorId <= 0) { - throw new IllegalArgumentException("currentOperatorId is null"); - } if (actionId == null) { throw new IllegalArgumentException("actionId is null"); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java index 34a165a0..39548e6f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java @@ -17,4 +17,6 @@ public interface FlowRecordRepository { List findRecordsByFromIdAndNodeId(long fromId,String nodeId); List findRecordsByProcessId(String processId); + + List findRecordsNodeIdAndParallelId(String nodeId, String parallelId); } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java index 8ab82a22..3bded8bf 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java @@ -57,4 +57,12 @@ public List findRecordsByFromIdAndNodeId(long fromId,String nodeId) public List findRecordsByProcessId(String processId) { return cache.values().stream().filter(flowRecord -> flowRecord.getProcessId().equals(processId)).toList(); } + + @Override + public List findRecordsNodeIdAndParallelId( String nodeId, String parallelId) { + return cache.values().stream().filter(flowRecord -> + flowRecord.getNodeId().equals(nodeId) + && flowRecord.getParallelId().equals(parallelId)) + .toList(); + } } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index b34aadb5..58e9e28e 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -192,8 +192,8 @@ void pass() { flowService.action(lorneRequest); List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); - assertEquals(2, records.size()); - assertEquals(2, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(3, records.size()); + assertEquals(3, records.stream().filter(FlowRecord::isFinish).toList().size()); } @@ -322,8 +322,8 @@ void condition() { flowService.action(lorneRequest); List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); - assertEquals(2, records.size()); - assertEquals(2, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(3, records.size()); + assertEquals(3, records.stream().filter(FlowRecord::isFinish).toList().size()); } @@ -442,8 +442,8 @@ public FlowRecord getRecordById(long id) { flowService.action(lorneRequest); List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); - assertEquals(4, records.size()); - assertEquals(4, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(5, records.size()); + assertEquals(5, records.stream().filter(FlowRecord::isFinish).toList().size()); } @@ -506,19 +506,7 @@ void parallel() { ) .build(); - ApprovalNode bossApprovalNode1 = ApprovalNode.builder() - .name("经理审批") - .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") - .formFieldsPermissions( - FormFieldPermissionsBuilder.builder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() - ) - .build(); - - ApprovalNode bossApprovalNode2 = ApprovalNode.builder() + ApprovalNode bossApprovalNode = ApprovalNode.builder() .name("经理审批") .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") .formFieldsPermissions( @@ -530,30 +518,6 @@ void parallel() { ) .build(); - ApprovalNode endOver1 = ApprovalNode.builder() - .name("end-over1") - .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") - .formFieldsPermissions( - FormFieldPermissionsBuilder.builder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() - ) - .build(); - - ApprovalNode endOver2 = ApprovalNode.builder() - .name("end-over2") - .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") - .formFieldsPermissions( - FormFieldPermissionsBuilder.builder() - .addPermission("leave", "name", PermissionType.WRITE) - .addPermission("leave", "days", PermissionType.WRITE) - .addPermission("leave", "reason", PermissionType.WRITE) - .build() - ) - .build(); - EndNode endNode = EndNode.builder().build(); Workflow workflow = WorkflowBuilder.builder() .title("请假流程") @@ -564,20 +528,14 @@ void parallel() { .addNode(parallelBranchNode1) .addNode(parallelBranchNode2) .addNode(departApprovalNode) - .addNode(bossApprovalNode1) - .addNode(bossApprovalNode2) - .addNode(endOver1) - .addNode(endOver2) + .addNode(bossApprovalNode) .addNode(endNode) .addEdge(new FlowEdge(startNode.getId(), parallelBranchNode1.getId())) .addEdge(new FlowEdge(startNode.getId(), parallelBranchNode2.getId())) .addEdge(new FlowEdge(parallelBranchNode1.getId(), departApprovalNode.getId())) - .addEdge(new FlowEdge(parallelBranchNode2.getId(), bossApprovalNode1.getId())) - .addEdge(new FlowEdge(departApprovalNode.getId(), endOver1.getId())) - .addEdge(new FlowEdge(bossApprovalNode1.getId(), bossApprovalNode2.getId())) - .addEdge(new FlowEdge(bossApprovalNode2.getId(), endOver1.getId())) - .addEdge(new FlowEdge(endOver1.getId(), endOver2.getId())) - .addEdge(new FlowEdge(endOver2.getId(), endNode.getId())) + .addEdge(new FlowEdge(parallelBranchNode2.getId(), bossApprovalNode.getId())) + .addEdge(new FlowEdge(departApprovalNode.getId(), endNode.getId())) + .addEdge(new FlowEdge(bossApprovalNode.getId(), endNode.getId())) .build(); workflowRepository.save(workflow); @@ -601,21 +559,36 @@ void parallel() { submitRequest.setAdvice(new FlowAdviceBody(actions.get(0).id(), "同意", user.getUserId())); flowService.action(submitRequest); - List lorneRecordList = flowRecordRepository.findTodoByOperator(depart.getUserId()); - assertEquals(1, lorneRecordList.size()); + List departRecordList = flowRecordRepository.findTodoByOperator(depart.getUserId()); + assertEquals(1, departRecordList.size()); + List boosRecordList = flowRecordRepository.findTodoByOperator(boss.getUserId()); + assertEquals(1, boosRecordList.size()); - List lorneActions = departApprovalNode.actions().getActions(); - FlowActionRequest lorneRequest = new FlowActionRequest(); - lorneRequest.setFormData(data); - lorneRequest.setRecordId(lorneRecordList.get(0).getId()); - lorneRequest.setAdvice(new FlowAdviceBody(lorneActions.get(0).id(), "同意", depart.getUserId())); - flowService.action(lorneRequest); + List departActions = departApprovalNode.actions().getActions(); - List records = flowRecordRepository.findRecordsByProcessId(lorneRecordList.get(0).getProcessId()); - assertEquals(4, records.size()); - assertEquals(2, records.stream().filter(FlowRecord::isTodo).toList().size()); + FlowActionRequest departRequest = new FlowActionRequest(); + departRequest.setFormData(data); + departRequest.setRecordId(departRecordList.get(0).getId()); + departRequest.setAdvice(new FlowAdviceBody(departActions.get(0).id(), "同意", depart.getUserId())); + flowService.action(departRequest); + + boosRecordList = flowRecordRepository.findTodoByOperator(boss.getUserId()); + assertEquals(1, boosRecordList.size()); + + List bossActions = bossApprovalNode.actions().getActions(); + + FlowActionRequest dossRequest = new FlowActionRequest(); + dossRequest.setFormData(data); + dossRequest.setRecordId(boosRecordList.get(0).getId()); + dossRequest.setAdvice(new FlowAdviceBody(bossActions.get(0).id(), "同意", boss.getUserId())); + flowService.action(dossRequest); + + + List records = flowRecordRepository.findRecordsByProcessId(departRecordList.get(0).getProcessId()); + assertEquals(3, records.size()); + assertEquals(0, records.stream().filter(FlowRecord::isTodo).toList().size()); assertEquals(0, records.stream().filter(FlowRecord::isFinish).toList().size()); } From a7f2bf6afbb0cc269b05552e472bc3e69877bcd7 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 15:23:46 +0800 Subject: [PATCH 17/21] add parallel branch --- .../flow/context/RepositoryContext.java | 11 +++++-- .../com/codingapi/flow/node/BaseFlowNode.java | 15 +++++----- .../com/codingapi/flow/record/FlowRecord.java | 29 +++++++++++++------ .../flow/repository/FlowRecordRepository.java | 1 - .../repository/ParallelBranchRepository.java | 8 +++++ .../codingapi/flow/service/FlowService.java | 6 ++-- .../flow/service/impl/FlowActionService.java | 5 +++- .../flow/service/impl/FlowCreateService.java | 8 +++++ .../repository/FlowRecordRepositoryImpl.java | 7 ----- .../ParallelBranchRepositoryImpl.java | 20 +++++++++++++ .../flow/service/FlowServiceTest.java | 7 +++-- 11 files changed, 85 insertions(+), 32 deletions(-) create mode 100644 flow-engine-framework/src/main/java/com/codingapi/flow/repository/ParallelBranchRepository.java create mode 100644 flow-engine-framework/src/test/java/com/codingapi/flow/repository/ParallelBranchRepositoryImpl.java diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java index bee0f0e4..5a1db55e 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/context/RepositoryContext.java @@ -4,6 +4,7 @@ import com.codingapi.flow.operator.IFlowOperator; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.repository.FlowRecordRepository; +import com.codingapi.flow.repository.ParallelBranchRepository; import lombok.Getter; import lombok.Setter; @@ -21,6 +22,8 @@ private RepositoryContext() { private FlowRecordRepository flowRecordRepository; @Setter private FlowOperatorGateway flowOperatorGateway; + @Setter + private ParallelBranchRepository parallelBranchRepository; public FlowRecord getRecordById(long id) { return flowRecordRepository.get(id); @@ -50,7 +53,11 @@ public List findRecordsByProcessId(String processId) { return flowRecordRepository.findRecordsByProcessId(processId); } - public List findRecordsNodeIdAndParallelId(String nodeId, String parallelId) { - return flowRecordRepository.findRecordsNodeIdAndParallelId(nodeId, parallelId); + public int getParallelBranchTriggerCount(String parallelId) { + return parallelBranchRepository.getTriggerCount(parallelId); + } + + public void addParallelTriggerCount(String parallelId) { + parallelBranchRepository.addTriggerCount(parallelId); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 25a3864a..469d16f3 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -102,13 +102,14 @@ public void verifyNode(FormMeta form) { public boolean isWaitParallelRecord(FlowSession session) { FlowRecord currentRecord = session.getCurrentRecord(); if (currentRecord != null && this.getId().equals(currentRecord.getParallelBranchNodeId())) { - //TODO - System.out.println(currentRecord.isTodo()); - // 此时还没有创建当前节点的记录数据,当时已经到了该汇聚节点,需要判断汇聚次数。 - int parallelBranchCount = currentRecord.getParallelBranchCount(); - List parallelRecords = RepositoryContext.getInstance().findRecordsNodeIdAndParallelId(this.getId(), currentRecord.getParallelId()); - List finishRecords = parallelRecords.stream().filter(FlowRecord::isFinish).toList(); - return parallelBranchCount != finishRecords.size(); + RepositoryContext.getInstance().addParallelTriggerCount(currentRecord.getParallelId()); + int parallelBranchTotal = currentRecord.getParallelBranchTotal(); + int parallelBranchCount = RepositoryContext.getInstance().getParallelBranchTriggerCount(currentRecord.getParallelId()); + if(parallelBranchCount == parallelBranchTotal){ + // 清空并行节点,防止数据继续继承到后续节点 + currentRecord.clearParallel(); + } + return parallelBranchCount != parallelBranchTotal; } return false; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java index b8ff9ac1..8b30008a 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/record/FlowRecord.java @@ -1,5 +1,6 @@ package com.codingapi.flow.record; +import com.codingapi.flow.context.RepositoryContext; import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; import lombok.Getter; @@ -166,10 +167,10 @@ public class FlowRecord { /** * 并行分支数量 */ - private int parallelBranchCount; + private int parallelBranchTotal; - public FlowRecord(FlowSession flowSession, String actionId, int nodeOrder) { + public FlowRecord(FlowSession flowSession, String actionId, int nodeOrder) { this.workCode = flowSession.getWorkCode(); this.workBackupId = flowSession.getBackupId(); this.nodeId = flowSession.getCurrentNodeId(); @@ -182,7 +183,7 @@ public FlowRecord(FlowSession flowSession, String actionId, int nodeOrder) { this.recordState = SATE_RECORD_TODO; this.actionId = actionId; this.currentOperatorId = flowSession.getCurrentOperator().getUserId(); - this.interferedOperatorId = flowSession.getCurrentOperator().entrustOperator()!=null?flowSession.getCurrentOperator().entrustOperator().getUserId():0; + this.interferedOperatorId = flowSession.getCurrentOperator().entrustOperator() != null ? flowSession.getCurrentOperator().entrustOperator().getUserId() : 0; this.advice = flowSession.getAdvice().getAdvice(); this.signKey = flowSession.getAdvice().getSignKey(); this.flowState = SATE_FLOW_RUNNING; @@ -190,7 +191,7 @@ public FlowRecord(FlowSession flowSession, String actionId, int nodeOrder) { this.isInterfere = flowSession.getWorkflow().isInterfere(); this.hidden = false; - flowSession.getCurrentNode().fillNewRecord(flowSession,this); + flowSession.getCurrentNode().fillNewRecord(flowSession, this); this.extendsRecord(flowSession.getCurrentRecord()); this.verify(); @@ -198,24 +199,34 @@ public FlowRecord(FlowSession flowSession, String actionId, int nodeOrder) { public void extendsRecord(FlowRecord record) { - if(record!=null) { + if (record != null) { this.parallelBranchNodeId = record.parallelBranchNodeId; - this.parallelBranchCount = record.parallelBranchCount; + this.parallelBranchTotal = record.parallelBranchTotal; this.parallelId = record.parallelId; this.fromId = record.id; this.processId = record.processId; } } + /** + * 当满足条件以后需要清空并行的记录数据 + */ + public void clearParallel() { + this.parallelBranchNodeId = null; + this.parallelBranchTotal = 0; + this.parallelId = null; + } + /** * 并行分支节点 + * * @param parallelBranchNodeId 并行分支节点id - * @param parallelBranchCount 并行分支数量 + * @param parallelBranchCount 并行分支数量 */ - public void parallelBranchNode(String parallelBranchNodeId, int parallelBranchCount,String parallelId) { + public void parallelBranchNode(String parallelBranchNodeId, int parallelBranchCount, String parallelId) { this.parallelBranchNodeId = parallelBranchNodeId; - this.parallelBranchCount = parallelBranchCount; + this.parallelBranchTotal = parallelBranchCount; this.parallelId = parallelId; } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java index 39548e6f..172b5e0f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/FlowRecordRepository.java @@ -18,5 +18,4 @@ public interface FlowRecordRepository { List findRecordsByProcessId(String processId); - List findRecordsNodeIdAndParallelId(String nodeId, String parallelId); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/repository/ParallelBranchRepository.java b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/ParallelBranchRepository.java new file mode 100644 index 00000000..b49225d8 --- /dev/null +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/repository/ParallelBranchRepository.java @@ -0,0 +1,8 @@ +package com.codingapi.flow.repository; + +public interface ParallelBranchRepository { + + int getTriggerCount(String parallelId); + + void addTriggerCount(String parallelId); +} diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java index 55fd0a70..55ae6850 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/FlowService.java @@ -4,6 +4,7 @@ import com.codingapi.flow.pojo.request.FlowActionRequest; import com.codingapi.flow.gateway.FlowOperatorGateway; import com.codingapi.flow.repository.FlowRecordRepository; +import com.codingapi.flow.repository.ParallelBranchRepository; import com.codingapi.flow.repository.WorkflowBackupRepository; import com.codingapi.flow.repository.WorkflowRepository; import com.codingapi.flow.service.impl.FlowCreateService; @@ -22,15 +23,16 @@ public class FlowService { private final FlowOperatorGateway flowOperatorGateway; private final FlowRecordRepository flowRecordRepository; private final WorkflowBackupRepository workflowBackupRepository; + private final ParallelBranchRepository parallelBranchRepository; public void create(FlowCreateRequest request) { - FlowCreateService flowCreateService = new FlowCreateService(request, flowOperatorGateway, flowRecordRepository, workflowRepository, workflowBackupRepository); + FlowCreateService flowCreateService = new FlowCreateService(request, flowOperatorGateway, flowRecordRepository, workflowRepository, workflowBackupRepository,parallelBranchRepository); flowCreateService.create(); } public void action(FlowActionRequest request) { - FlowActionService flowActionService = new FlowActionService(request, flowOperatorGateway, flowRecordRepository, workflowBackupRepository); + FlowActionService flowActionService = new FlowActionService(request, flowOperatorGateway, flowRecordRepository, workflowBackupRepository,parallelBranchRepository); flowActionService.action(); } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java index 1e0fc377..2600e36f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java @@ -10,6 +10,7 @@ import com.codingapi.flow.pojo.request.FlowActionRequest; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.repository.FlowRecordRepository; +import com.codingapi.flow.repository.ParallelBranchRepository; import com.codingapi.flow.repository.WorkflowBackupRepository; import com.codingapi.flow.session.FlowAdvice; import com.codingapi.flow.session.FlowSession; @@ -25,10 +26,12 @@ public class FlowActionService { private final FlowOperatorGateway flowOperatorGateway; private final FlowRecordRepository flowRecordRepository; private final WorkflowBackupRepository workflowBackupRepository; + private final ParallelBranchRepository parallelBranchRepository; public void action() { RepositoryContext.getInstance().setFlowRecordRepository(flowRecordRepository); RepositoryContext.getInstance().setFlowOperatorGateway(flowOperatorGateway); + RepositoryContext.getInstance().setParallelBranchRepository(parallelBranchRepository); request.verify(); // 验证当前用户 @@ -69,7 +72,7 @@ public void action() { formData.reset(request.getFormData()); FlowAdvice flowAdvice = request.toFlowAdvice(workflow, flowAction); - List currentRecords = flowRecordRepository.findRecordsByFromIdAndNodeId(flowRecord.getFromId(), flowRecord.getNodeId()); + List currentRecords = RepositoryContext.getInstance().findRecordsByFromIdAndNodeId(flowRecord.getFromId(), flowRecord.getNodeId()); FlowSession session = new FlowSession(currentOperator, workflow, currentNode, flowAction, formData, flowRecord, currentRecords, workflowBackup.getId(), flowAdvice); currentNode.verifySession(session); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java index b66ec0f1..67e08b0d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java @@ -2,6 +2,7 @@ import com.codingapi.flow.action.IFlowAction; import com.codingapi.flow.backup.WorkflowBackup; +import com.codingapi.flow.context.RepositoryContext; import com.codingapi.flow.event.FlowRecordStartEvent; import com.codingapi.flow.event.FlowRecordTodoEvent; import com.codingapi.flow.event.IFlowEvent; @@ -12,6 +13,7 @@ import com.codingapi.flow.pojo.request.FlowCreateRequest; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.repository.FlowRecordRepository; +import com.codingapi.flow.repository.ParallelBranchRepository; import com.codingapi.flow.repository.WorkflowBackupRepository; import com.codingapi.flow.repository.WorkflowRepository; import com.codingapi.flow.session.FlowSession; @@ -30,8 +32,14 @@ public class FlowCreateService { private final FlowRecordRepository flowRecordRepository; private final WorkflowRepository workflowRepository; private final WorkflowBackupRepository workflowBackupRepository; + private final ParallelBranchRepository parallelBranchRepository; public void create() { + + RepositoryContext.getInstance().setFlowRecordRepository(flowRecordRepository); + RepositoryContext.getInstance().setFlowOperatorGateway(flowOperatorGateway); + RepositoryContext.getInstance().setParallelBranchRepository(parallelBranchRepository); + request.verify(); Workflow workflow = workflowRepository.get(request.getWorkId()); if (workflow == null) { diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java index 3bded8bf..1613f2d7 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/FlowRecordRepositoryImpl.java @@ -58,11 +58,4 @@ public List findRecordsByProcessId(String processId) { return cache.values().stream().filter(flowRecord -> flowRecord.getProcessId().equals(processId)).toList(); } - @Override - public List findRecordsNodeIdAndParallelId( String nodeId, String parallelId) { - return cache.values().stream().filter(flowRecord -> - flowRecord.getNodeId().equals(nodeId) - && flowRecord.getParallelId().equals(parallelId)) - .toList(); - } } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/repository/ParallelBranchRepositoryImpl.java b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/ParallelBranchRepositoryImpl.java new file mode 100644 index 00000000..7ae7a041 --- /dev/null +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/repository/ParallelBranchRepositoryImpl.java @@ -0,0 +1,20 @@ +package com.codingapi.flow.repository; + +import java.util.HashMap; +import java.util.Map; + +public class ParallelBranchRepositoryImpl implements ParallelBranchRepository{ + + private final Map cache = new HashMap<>(); + + @Override + public int getTriggerCount(String parallelId) { + Integer value = cache.get(parallelId); + return value == null ? 0 : value; + } + + @Override + public void addTriggerCount(String parallelId) { + this.cache.put(parallelId, this.getTriggerCount(parallelId) + 1); + } +} diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index 58e9e28e..cf74b14a 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -32,7 +32,8 @@ class FlowServiceTest { private final UserGateway userGateway = new UserGateway(); private final WorkflowBackupRepository workflowBackupRepository = new WorkflowBackupRepositoryImpl(); private final WorkflowRepository workflowRepository = new WorkflowRepositoryImpl(); - private final FlowService flowService = new FlowService(workflowRepository, userGateway, flowRecordRepository, workflowBackupRepository); + private final ParallelBranchRepository parallelBranchRepository = new ParallelBranchRepositoryImpl(); + private final FlowService flowService = new FlowService(workflowRepository, userGateway, flowRecordRepository, workflowBackupRepository,parallelBranchRepository); @Test void create() { @@ -587,9 +588,9 @@ void parallel() { List records = flowRecordRepository.findRecordsByProcessId(departRecordList.get(0).getProcessId()); - assertEquals(3, records.size()); + assertEquals(4, records.size()); assertEquals(0, records.stream().filter(FlowRecord::isTodo).toList().size()); - assertEquals(0, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(4, records.stream().filter(FlowRecord::isFinish).toList().size()); } From 74aa009a3e4079535791cec856ec933f9a379c4b Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 15:27:15 +0800 Subject: [PATCH 18/21] add parallel branch --- .../flow/service/FlowServiceTest.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index cf74b14a..62328bec 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -508,7 +508,19 @@ void parallel() { .build(); ApprovalNode bossApprovalNode = ApprovalNode.builder() - .name("经理审批") + .name("老板审批") + .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") + .formFieldsPermissions( + FormFieldPermissionsBuilder.builder() + .addPermission("leave", "name", PermissionType.WRITE) + .addPermission("leave", "days", PermissionType.WRITE) + .addPermission("leave", "reason", PermissionType.WRITE) + .build() + ) + .build(); + + ApprovalNode bigBossApprovalNode = ApprovalNode.builder() + .name("大老板审批") .operatorScript("def run(request){return [$bind.getOperatorById(3)]}") .formFieldsPermissions( FormFieldPermissionsBuilder.builder() @@ -530,13 +542,15 @@ void parallel() { .addNode(parallelBranchNode2) .addNode(departApprovalNode) .addNode(bossApprovalNode) + .addNode(bigBossApprovalNode) .addNode(endNode) .addEdge(new FlowEdge(startNode.getId(), parallelBranchNode1.getId())) .addEdge(new FlowEdge(startNode.getId(), parallelBranchNode2.getId())) .addEdge(new FlowEdge(parallelBranchNode1.getId(), departApprovalNode.getId())) .addEdge(new FlowEdge(parallelBranchNode2.getId(), bossApprovalNode.getId())) + .addEdge(new FlowEdge(bossApprovalNode.getId(), bigBossApprovalNode.getId())) .addEdge(new FlowEdge(departApprovalNode.getId(), endNode.getId())) - .addEdge(new FlowEdge(bossApprovalNode.getId(), endNode.getId())) + .addEdge(new FlowEdge(bigBossApprovalNode.getId(), endNode.getId())) .build(); workflowRepository.save(workflow); @@ -587,10 +601,21 @@ void parallel() { flowService.action(dossRequest); + boosRecordList = flowRecordRepository.findTodoByOperator(boss.getUserId()); + assertEquals(1, boosRecordList.size()); + + List bigBossActions = bigBossApprovalNode.actions().getActions(); + + FlowActionRequest bigBossRequest = new FlowActionRequest(); + bigBossRequest.setFormData(data); + bigBossRequest.setRecordId(boosRecordList.get(0).getId()); + bigBossRequest.setAdvice(new FlowAdviceBody(bigBossActions.get(0).id(), "同意", boss.getUserId())); + flowService.action(bigBossRequest); + List records = flowRecordRepository.findRecordsByProcessId(departRecordList.get(0).getProcessId()); - assertEquals(4, records.size()); + assertEquals(5, records.size()); assertEquals(0, records.stream().filter(FlowRecord::isTodo).toList().size()); - assertEquals(4, records.stream().filter(FlowRecord::isFinish).toList().size()); + assertEquals(5, records.stream().filter(FlowRecord::isFinish).toList().size()); } From 6b3754fb5a2fb3cac68f761172318f3a7c0398ce Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 16:11:28 +0800 Subject: [PATCH 19/21] add readme --- .../com/codingapi/flow/action/BaseAction.java | 29 ++++++++++--------- .../codingapi/flow/action/IFlowAction.java | 12 ++------ .../com/codingapi/flow/action/PassAction.java | 9 ++---- .../codingapi/flow/action/RejectAction.java | 2 +- .../com/codingapi/flow/action/SaveAction.java | 8 ----- .../com/codingapi/flow/node/IFlowNode.java | 7 +++++ .../flow/service/impl/FlowActionService.java | 2 +- 7 files changed, 29 insertions(+), 40 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index d460750d..ab9f8bda 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -1,19 +1,15 @@ package com.codingapi.flow.action; -import com.codingapi.flow.context.RepositoryContext; -import com.codingapi.flow.event.FlowRecordFinishEvent; import com.codingapi.flow.node.IFlowNode; -import com.codingapi.flow.node.nodes.EndNode; import com.codingapi.flow.record.FlowRecord; import com.codingapi.flow.session.FlowSession; -import com.codingapi.springboot.framework.event.EventPusher; import lombok.Getter; import lombok.SneakyThrows; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; @Getter public abstract class BaseAction implements IFlowAction { @@ -72,13 +68,9 @@ public Map toMap() { @Override public List generateRecords(FlowSession flowSession) { - return null; + return List.of(); } - @Override - public boolean isDone(FlowSession session, FlowRecord currentRecord, List currentRecords) { - return true; - } @SneakyThrows @SuppressWarnings("unchecked") @@ -96,15 +88,24 @@ protected static T fromMap(Map data, Clas @Override - public void triggerNode(FlowSession flowSession) { + public void run(FlowSession flowSession) {} + + /** + * 触发节点 + * @param flowSession 当前会话 + * @param consumer 节点处理 + */ + public void triggerNode(FlowSession flowSession, Consumer consumer) { List nextNodes = flowSession.nextNodes(); for (IFlowNode node : nextNodes) { FlowSession triggerSession = flowSession.updateSession(node); if (node.continueTrigger(triggerSession)) { - this.triggerNode(triggerSession); + this.triggerNode(triggerSession,consumer); + }else { + if (consumer != null) { + consumer.accept(triggerSession); + } } } } - - } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java index 1fa7a026..73deec82 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java @@ -43,15 +43,7 @@ public interface IFlowAction { Map toMap(); - void triggerNode(FlowSession flowSession); + void run(FlowSession flowSession); + - /** - * 流程是否结束 - * - * @param session session - * @param currentRecord 当前审批记录 - * @param currentRecords 当前节点所有人提交的记录 - * @return 是否结束 - */ - boolean isDone(FlowSession session, FlowRecord currentRecord, List currentRecords); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java index 52e2d9df..38e64d59 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/PassAction.java @@ -60,7 +60,7 @@ public List generateRecords(FlowSession flowSession) { @Override - public void triggerNode(FlowSession flowSession) { + public void run(FlowSession flowSession) { List flowEvents = new ArrayList<>(); List recordList = new ArrayList<>(); FlowRecord flowRecord = flowSession.getCurrentRecord(); @@ -72,10 +72,7 @@ public void triggerNode(FlowSession flowSession) { recordList.add(flowRecord); if (done) { - super.triggerNode(flowSession); - List nextNodes = flowSession.nextNodes(); - for (IFlowNode node : nextNodes) { - FlowSession triggerSession = flowSession.updateSession(node); + this.triggerNode(flowSession,(triggerSession)->{ List records = this.generateRecords(triggerSession); if (!records.isEmpty()) { for (FlowRecord record : records) { @@ -85,7 +82,7 @@ public void triggerNode(FlowSession flowSession) { } recordList.addAll(records); } - } + }); } RepositoryContext.getInstance().saveRecords(recordList); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java index d1dad3f8..79b6b359 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/RejectAction.java @@ -71,7 +71,7 @@ public List generateRecords(FlowSession flowSession) { } @Override - public void triggerNode(FlowSession flowSession) { + public void run(FlowSession flowSession) { List flowEvents = new ArrayList<>(); List recordList = new ArrayList<>(); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/SaveAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/SaveAction.java index 427741d7..207dcffb 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/SaveAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/SaveAction.java @@ -1,10 +1,7 @@ package com.codingapi.flow.action; -import com.codingapi.flow.record.FlowRecord; -import com.codingapi.flow.session.FlowSession; import com.codingapi.flow.utils.RandomUtils; -import java.util.List; import java.util.Map; /** @@ -24,9 +21,4 @@ public static SaveAction fromMap(Map data) { } - @Override - public boolean isDone(FlowSession session, FlowRecord currentRecord, List currentRecords) { - // 保存按钮,不创建后续流程 - return false; - } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index aaf662c3..c3461e26 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -10,6 +10,13 @@ /** * 流程节点 + * + * 流程执行的生命周期 + * {@link IFlowNode#verifyNode(FormMeta)}} 用于流程配置完成以后的验证时触发 + * {@link IFlowNode#verifySession(FlowSession)} 流程执行continueTrigger之前需要先对判断请求会话的参数是否满足节点参数要求 + * {@link IFlowNode#continueTrigger(FlowSession)} 当前流程节点执行完成以后,触发下一环节时执行的函数,当返回true时则将继续执行后续流程,当返回false时则不继续执行后续流程,将执行当前节点的创建流程记录函数 {@link IFlowNode#generateCurrentRecords(FlowSession)} + * {@link IFlowNode#generateCurrentRecords(FlowSession)} 创建当前节点下的流程记录数据。 + * */ public interface IFlowNode { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java index 2600e36f..f15a2d3f 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java @@ -77,7 +77,7 @@ public void action() { currentNode.verifySession(session); - flowAction.triggerNode(session); + flowAction.run(session); } } From 44fbf3e99cd9eb3078905d88f9f530cbc70eb1d7 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 16:34:14 +0800 Subject: [PATCH 20/21] add readme --- .../com/codingapi/flow/action/BaseAction.java | 4 +- .../codingapi/flow/action/IFlowAction.java | 5 ++ .../codingapi/flow/node/BaseAuditNode.java | 2 +- .../com/codingapi/flow/node/BaseFlowNode.java | 4 +- .../com/codingapi/flow/node/IFlowNode.java | 25 ++++----- .../flow/node/nodes/BranchNodeBranchNode.java | 2 +- .../flow/node/nodes/ParallelBranchNode.java | 2 +- .../flow/service/impl/FlowActionService.java | 2 +- .../flow/service/impl/FlowCreateService.java | 2 +- .../codingapi/flow/session/FlowSession.java | 52 +++++++++++++++---- .../flow/service/FlowServiceTest.java | 22 ++++---- 11 files changed, 80 insertions(+), 42 deletions(-) diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java index ab9f8bda..d297fd61 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/BaseAction.java @@ -91,12 +91,12 @@ protected static T fromMap(Map data, Clas public void run(FlowSession flowSession) {} /** - * 触发节点 + * 触发并执行后续节点 * @param flowSession 当前会话 * @param consumer 节点处理 */ public void triggerNode(FlowSession flowSession, Consumer consumer) { - List nextNodes = flowSession.nextNodes(); + List nextNodes = flowSession.matchNextNodes(); for (IFlowNode node : nextNodes) { FlowSession triggerSession = flowSession.updateSession(node); if (node.continueTrigger(triggerSession)) { diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java index 73deec82..fe82c326 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/action/IFlowAction.java @@ -43,6 +43,11 @@ public interface IFlowAction { Map toMap(); + /** + * 执行动作 + * 业务流程的处理入口时通过run函数触发开启的流程 + * @param flowSession 会话 + */ void run(FlowSession flowSession); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java index 4543ab47..24b0819d 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java @@ -129,7 +129,7 @@ public FieldPermissionManager formFieldsPermissionsManager() { return new FieldPermissionManager(formFieldPermissions); } - public ActionManager actions() { + public ActionManager actionManager() { return new ActionManager(actions); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java index 469d16f3..a7a48b18 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseFlowNode.java @@ -154,7 +154,7 @@ public void fillNewRecord(FlowSession session, FlowRecord flowRecord) { } @Override - public List matchBranch(List nodeList, FlowSession flowSession) { + public List filterBranches(List nodeList, FlowSession flowSession) { return nodeList; } @@ -164,7 +164,7 @@ public List generateCurrentRecords(FlowSession session) { } @Override - public ActionManager actions() { + public ActionManager actionManager() { return new ActionManager(actions); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java index c3461e26..77a2c181 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/IFlowNode.java @@ -10,13 +10,7 @@ /** * 流程节点 - * * 流程执行的生命周期 - * {@link IFlowNode#verifyNode(FormMeta)}} 用于流程配置完成以后的验证时触发 - * {@link IFlowNode#verifySession(FlowSession)} 流程执行continueTrigger之前需要先对判断请求会话的参数是否满足节点参数要求 - * {@link IFlowNode#continueTrigger(FlowSession)} 当前流程节点执行完成以后,触发下一环节时执行的函数,当返回true时则将继续执行后续流程,当返回false时则不继续执行后续流程,将执行当前节点的创建流程记录函数 {@link IFlowNode#generateCurrentRecords(FlowSession)} - * {@link IFlowNode#generateCurrentRecords(FlowSession)} 创建当前节点下的流程记录数据。 - * */ public interface IFlowNode { @@ -48,11 +42,14 @@ public interface IFlowNode { /** * 节点验证 + * 用于流程配置完成以后的验证时触发 */ void verifyNode(FormMeta form); /** * 是否执行节点 + * 当前流程节点执行完成以后,触发下一环节时执行的函数,当返回true时则将继续执行后续流程,当返回false时则不继续执行后续流程,将执行当前节点的创建流程记录函数 {@link IFlowNode#generateCurrentRecords(FlowSession)} + * 同时 continueTrigger 函数也是条件分支的触发判定依据。{@link FlowSession#matchNextNodes()} 将会调用 {@link IFlowNode#filterBranches(List, FlowSession)} 匹配过滤条件 * @param session 会话 * @return true: 继续执行下一个节点 */ @@ -60,6 +57,7 @@ public interface IFlowNode { /** * 节点验证会话 + * 流程执行continueTrigger之前需要先对判断请求会话的参数是否满足节点参数要求 */ void verifySession(FlowSession session); @@ -71,20 +69,23 @@ public interface IFlowNode { List generateCurrentRecords(FlowSession session); /** - * 获取节点操作 - * @return 节点操作 + * 获取节点操作对象管理器 + * @return 节点操作对象管理器 */ - ActionManager actions(); + ActionManager actionManager(); /** * 节点是否完成 + * 当前节点是否完成,由于IFlowAction无法判断节点是否完成,是否完成需要根据节点配置的多人审批规则来判定,因此在提交通过节点时 + * {@link com.codingapi.flow.action.PassAction#run(FlowSession)} 函数中会判断当前节点是否完成 + * 如果完成则将执行当前节点的生成流程记录函数 {@link IFlowNode#continueTrigger(FlowSession)} * @param session 会话 * @return true: 节点完成 */ boolean isDone(FlowSession session); /** - * 填充流程记录 + * 填充流程记录,在保存流程记录时将会触发当前节点的填充流程记录函数。由于不同节点存储的流程数据会存在差异。 * @param session 会话 * @param flowRecord 流程记录 */ @@ -92,11 +93,11 @@ public interface IFlowNode { /** - * 匹配条件分支 + * 过滤条件分支 * @param nodeList 当前节点下的所有条件 * @param flowSession 当前会话 * @return 匹配的节点 */ - List matchBranch(List nodeList, FlowSession flowSession); + List filterBranches(List nodeList, FlowSession flowSession); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java index dc106a91..a72bc6ce 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/BranchNodeBranchNode.java @@ -50,7 +50,7 @@ public boolean continueTrigger(FlowSession request) { } @Override - public List matchBranch(List nodeList, FlowSession flowSession) { + public List filterBranches(List nodeList, FlowSession flowSession) { List nodes = new ArrayList<>(); for (IFlowNode node: nodeList){ if (node.continueTrigger(flowSession)){ diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java index 8e2c4f5d..069d5a96 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/node/nodes/ParallelBranchNode.java @@ -40,7 +40,7 @@ public ParallelBranchNode() { * @param flowSession 当前会话 * @return 匹配的节点 */ - public List matchBranch(List nodeList, FlowSession flowSession) { + public List filterBranches(List nodeList, FlowSession flowSession) { Workflow workflow = flowSession.getWorkflow(); ParallelNodeRelationHelper helper = new ParallelNodeRelationHelper(nodeList, workflow); // 分析并行分支的结束汇聚节点 diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java index f15a2d3f..0ddc0ea9 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowActionService.java @@ -62,7 +62,7 @@ public void action() { if (currentNode == null) { throw new IllegalArgumentException("currentNode not exist"); } - IFlowAction flowAction = currentNode.actions().getActionById(request.getAdvice().getActionId()); + IFlowAction flowAction = currentNode.actionManager().getActionById(request.getAdvice().getActionId()); if (flowAction == null) { throw new IllegalArgumentException("action not exist"); } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java index 67e08b0d..2d26bdcb 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowCreateService.java @@ -62,7 +62,7 @@ public void create() { formData.reset(request.getFormData()); StartNode currentNode = (StartNode) workflow.getStartNode(); - IFlowAction action = currentNode.actions().getActionById(request.getAdvice().getActionId()); + IFlowAction action = currentNode.actionManager().getActionById(request.getAdvice().getActionId()); FlowSession session = FlowSession.startSession(currentOperator, workflow, currentNode, action, formData, workflowBackup.getId()); currentNode.verifySession(session); diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java index e143302b..722cf5a0 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/session/FlowSession.java @@ -80,6 +80,16 @@ public FlowSession(IFlowOperator currentOperator, } + /** + * 构建开始会话 + * @param currentOperator 当前操作者 + * @param workflow 流程设计 + * @param currentNode 当前节点 + * @param currentAction 当前动作 + * @param formData 表单数据 + * @param backupId 流程备份id + * @return 新的会话 + */ public static FlowSession startSession(IFlowOperator currentOperator, Workflow workflow, IFlowNode currentNode, @@ -90,6 +100,14 @@ public static FlowSession startSession(IFlowOperator currentOperator, } + /** + * 获取流程开始节点 + */ + public IFlowNode getStartNode() { + return workflow.getStartNode(); + } + + /** * 获取流程的创建者 */ @@ -97,43 +115,57 @@ public IFlowOperator getCreatedOperator() { return workflow.getCreatedOperator(); } + /** + * 获取流程设计编号 + */ public String getWorkCode() { return workflow.getCode(); } - public String getWorkTitle() { - return workflow.getTitle(); - } - public String getCurrentNodeId() { return currentNode.getId(); } - public IFlowNode getStartNode() { - return workflow.getStartNode(); - } - public String getCurrentNodeType() { return currentNode.getType(); } - public List nextNodes() { + /** + * 获取下一节点列表 + * @return 下一节点列表 + */ + public List matchNextNodes() { List nodeList = workflow.nextNodes(this.getCurrentNode()); if(!nodeList.isEmpty() && nodeList.size()>1){ IFlowNode currentNode = nodeList.get(0); - return currentNode.matchBranch(nodeList,this); + return currentNode.filterBranches(nodeList,this); } return nodeList; } + /** + * 获取表单数据 + * @param fieldName 字段名称 + * @return 表单数据 + */ public Object getFormData(String fieldName) { return formData.getDataBody().get(fieldName); } + /** + * 更新会话 + * @param currentNode 当前节点 + * @return 新的会话 + */ public FlowSession updateSession(IFlowNode currentNode) { return new FlowSession(currentOperator, workflow, currentNode, currentAction, formData, currentRecord, currentNodeRecords, backupId, advice); } + /** + * 更新会话 + * @param currentOperator 当前操作者 + * @return 新的会话 + */ public FlowSession updateSession(IFlowOperator currentOperator) { return new FlowSession(currentOperator, workflow, currentNode, currentAction, formData, currentRecord, currentNodeRecords, backupId, advice); } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java index 62328bec..866febc7 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java @@ -94,7 +94,7 @@ void create() { FlowCreateRequest request = new FlowCreateRequest(); request.setWorkId(workflow.getId()); request.setFormData(Map.of("name", "lorne", "days", 1, "reason", "leave")); - List actions = startNode.actions().getActions(); + List actions = startNode.actionManager().getActions(); request.setAdvice(new FlowAdviceBody(actions.get(0).id(), "同意", test.getUserId())); flowService.create(request); @@ -166,7 +166,7 @@ void pass() { FlowCreateRequest request = new FlowCreateRequest(); request.setWorkId(workflow.getId()); request.setFormData(Map.of("name", "lorne", "days", 1, "reason", "leave")); - List actions = startNode.actions().getActions(); + List actions = startNode.actionManager().getActions(); request.setAdvice(new FlowAdviceBody(actions.get(0).id(), "同意", test.getUserId())); flowService.create(request); @@ -184,7 +184,7 @@ void pass() { assertEquals(1, lorneRecordList.size()); - List lorneActions = approvalNode.actions().getActions(); + List lorneActions = approvalNode.actionManager().getActions(); FlowActionRequest lorneRequest = new FlowActionRequest(); lorneRequest.setFormData(Map.of("name", "lorne", "days", 1, "reason", "leave")); @@ -296,7 +296,7 @@ void condition() { FlowCreateRequest request = new FlowCreateRequest(); request.setWorkId(workflow.getId()); request.setFormData(data); - List actions = startNode.actions().getActions(); + List actions = startNode.actionManager().getActions(); request.setAdvice(new FlowAdviceBody(actions.get(0).id(), "同意", user.getUserId())); flowService.create(request); @@ -314,7 +314,7 @@ void condition() { assertEquals(1, lorneRecordList.size()); - List lorneActions = departApprovalNode.actions().getActions(); + List lorneActions = departApprovalNode.actionManager().getActions(); FlowActionRequest lorneRequest = new FlowActionRequest(); lorneRequest.setFormData(data); @@ -397,7 +397,7 @@ public FlowRecord getRecordById(long id) { FlowCreateRequest request = new FlowCreateRequest(); request.setWorkId(workflow.getId()); request.setFormData(Map.of("name", "lorne", "days", 1, "reason", "leave")); - List startActions = startNode.actions().getActions(); + List startActions = startNode.actionManager().getActions(); request.setAdvice(new FlowAdviceBody(startActions.get(0).id(), "同意", test.getUserId())); flowService.create(request); @@ -415,7 +415,7 @@ public FlowRecord getRecordById(long id) { assertEquals(1, lorneRecordList.size()); - List lorneActions = approvalNode.actions().getActions(); + List lorneActions = approvalNode.actionManager().getActions(); FlowActionRequest lorneRequest = new FlowActionRequest(); lorneRequest.setFormData(Map.of("name", "lorne", "days", 1, "reason", "leave")); @@ -560,7 +560,7 @@ void parallel() { FlowCreateRequest request = new FlowCreateRequest(); request.setWorkId(workflow.getId()); request.setFormData(data); - List actions = startNode.actions().getActions(); + List actions = startNode.actionManager().getActions(); request.setAdvice(new FlowAdviceBody(actions.get(0).id(), "同意", user.getUserId())); flowService.create(request); @@ -581,7 +581,7 @@ void parallel() { assertEquals(1, boosRecordList.size()); - List departActions = departApprovalNode.actions().getActions(); + List departActions = departApprovalNode.actionManager().getActions(); FlowActionRequest departRequest = new FlowActionRequest(); departRequest.setFormData(data); @@ -592,7 +592,7 @@ void parallel() { boosRecordList = flowRecordRepository.findTodoByOperator(boss.getUserId()); assertEquals(1, boosRecordList.size()); - List bossActions = bossApprovalNode.actions().getActions(); + List bossActions = bossApprovalNode.actionManager().getActions(); FlowActionRequest dossRequest = new FlowActionRequest(); dossRequest.setFormData(data); @@ -604,7 +604,7 @@ void parallel() { boosRecordList = flowRecordRepository.findTodoByOperator(boss.getUserId()); assertEquals(1, boosRecordList.size()); - List bigBossActions = bigBossApprovalNode.actions().getActions(); + List bigBossActions = bigBossApprovalNode.actionManager().getActions(); FlowActionRequest bigBossRequest = new FlowActionRequest(); bigBossRequest.setFormData(data); From 58d022f12e45ef7681bd4629237da739f3e48420 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Wed, 21 Jan 2026 16:48:23 +0800 Subject: [PATCH 21/21] add Design.md --- flow-engine-framework/src/test/Design.md | 595 +++++++++++++++++++++++ 1 file changed, 595 insertions(+) create mode 100644 flow-engine-framework/src/test/Design.md diff --git a/flow-engine-framework/src/test/Design.md b/flow-engine-framework/src/test/Design.md new file mode 100644 index 00000000..96dc7b7d --- /dev/null +++ b/flow-engine-framework/src/test/Design.md @@ -0,0 +1,595 @@ +# 关键设计介绍 + +## 一、核心类设计 + +### 1. 流程定义层 (Workflow Layer) + +#### Workflow +- **位置**: `com.codingapi.flow.workflow.Workflow` +- **职责**: 流程定义的顶层容器,包含流程的完整定义信息 +- **核心属性**: + - `id`: 流程唯一标识 + - `code`: 流程编号 + - `title`: 流程名称 + - `form`: 流程表单定义 (`FormMeta`) + - `nodes`: 节点列表 (`List`) + - `edges`: 节点连接关系 (`List`) + - `operatorCreateScript`: 创建者匹配脚本 + - `isInterfere`: 是否开启干预 + - `isRevoke`: 是否开启撤销 +- **核心方法**: + - `verify()`: 验证流程定义的合法性 + - `nextNodes(IFlowNode)`: 获取指定节点的后续节点 + - `getStartNode()`: 获取开始节点 + - `getEndNode()`: 获取结束节点 + - `toJson()`: 序列化为JSON + - `formJson()`: 从JSON反序列化 + +#### WorkflowBuilder +- **位置**: `com.codingapi.flow.workflow.WorkflowBuilder` +- **职责**: 使用Builder模式构建Workflow对象 +- **设计模式**: Builder模式 +- **用法**: `WorkflowBuilder.builder().title("请假流程").node(startNode).build()` + +--- + +### 2. 节点层 (Node Layer) + +#### IFlowNode +- **位置**: `com.codingapi.flow.node.IFlowNode` +- **职责**: 所有流程节点的顶层接口,定义节点生命周期方法 +- **核心方法**(按执行顺序): + 1. `verifySession(FlowSession)`: 验证会话参数 + 2. `continueTrigger(FlowSession)`: 判断是否继续执行后续节点 + 3. `generateCurrentRecords(FlowSession)`: 生成当前节点的流程记录 + 4. `isDone(FlowSession)`: 判断节点是否完成 + 5. `fillNewRecord(FlowSession, FlowRecord)`: 填充新记录数据 + 6. `filterBranches()`: 过滤条件分支 + 7. `actionManager()`: 获取动作管理器 + +#### BaseFlowNode +- **位置**: `com.codingapi.flow.node.BaseFlowNode` +- **职责**: 所有节点的抽象基类,实现IFlowNode的默认行为 +- **核心属性**: `id`, `name`, `order`, `actions` +- **核心方法**: + - `isWaitParallelRecord()`: 判断是否等待并行节点汇聚 + +#### BaseAuditNode +- **位置**: `com.codingapi.flow.node.BaseAuditNode` +- **职责**: 审批类节点的抽象基类(ApprovalNode、HandleNode) +- **核心属性**: + - `operatorScript`: 审批人加载脚本 + - `nodeTitleScript`: 节点标题脚本 + - `errorTriggerScript`: 异常触发脚本 + - `formFieldPermissions`: 表单字段权限 + - `nodeStrategies`: 节点策略列表 +- **核心方法**: + - `operators()`: 获取操作者管理器 + - `strategies()`: 获取策略管理器 + - `generateTitle()`: 生成节点标题 + +#### 节点类型一览 (11种) + +| 节点类型 | 类名 | NODE_TYPE | 说明 | +|---------|------|-----------|------| +| 开始节点 | StartNode | `start` | 流程起点 | +| 结束节点 | EndNode | `end` | 流程终点 | +| 审批节点 | ApprovalNode | `approval` | 需要审批的任务节点 | +| 办理节点 | HandleNode | `handle` | 需要办理的任务节点 | +| 条件分支 | BranchNodeBranchNode | `condition_branch` | 按条件路由 | +| 并行分支 | ParallelBranchNode | `parallel_branch` | 并行执行多个分支 | +| 路由分支 | RouterBranchNode | `router_branch` | 普通路由节点 | +| 包容分支 | InclusiveBranchNode | `inclusive_branch` | 包容性分支 | +| 通知节点 | NotifyNode | `notify` | 发送通知 | +| 延迟节点 | DelayNode | `delay` | 延迟执行 | +| 触发节点 | TriggerNode | `trigger` | 事件触发 | +| 子流程节点 | SubProcessNode | `sub_process` | 嵌套子流程 | + +--- + +### 3. 动作层 (Action Layer) + +#### IFlowAction +- **位置**: `com.codingapi.flow.action.IFlowAction` +- **职责**: 节点上可执行的动作接口 +- **核心方法**: + - `type()`: 动作类型 + - `run(FlowSession)`: 执行动作的主入口 + - `generateRecords()`: 生成流程记录 + +#### BaseAction +- **位置**: `com.codingapi.flow.action.BaseAction` +- **职责**: 动作的抽象基类 +- **核心方法**: + - `triggerNode()`: 递归触发后续节点 + +#### 动作类型 + +| 动作类 | ActionType | 说明 | +|-------|------------|------| +| PassAction | `PASS` | 通过 | +| RejectAction | `REJECT` | 驳回 | +| SaveAction | `SAVE` | 保存 | +| ReturnAction | `RETURN` | 退回 | +| TransferAction | `TRANSFER` | 转办 | +| AddAuditAction | `ADD_AUDIT` | 加签 | +| DelegateAction | `DELEGATE` | 委托 | +| CustomAction | `CUSTOM` | 自定义 | + +--- + +### 4. 流程记录层 (Record Layer) + +#### FlowRecord +- **位置**: `com.codingapi.flow.record.FlowRecord` +- **职责**: 流程执行过程中的每一条记录 +- **状态定义**: + - `SATE_RECORD_TODO = 0`: 待办 + - `SATE_RECORD_DONE = 1`: 已办 + - `SATE_FLOW_RUNNING = 0`: 运行中 + - `SATE_FLOW_DONE = 1`: 已完成 + - `SATE_FLOW_FINISH = 2`: 终止 + - `SATE_FLOW_ERROR = 3`: 异常 + - `SATE_FLOW_DELETE = 4`: 删除 +- **核心属性**: + - `processId`: 流程实例ID(每次启动生成) + - `nodeId`: 当前节点ID + - `currentOperatorId`: 当前审批人ID + - `formData`: 表单数据 + - `parallelId`: 并行分支ID + - `parallelBranchNodeId`: 并行分支节点ID + - `parallelBranchTotal`: 并行分支总数 + +--- + +### 5. 会话层 (Session Layer) + +#### FlowSession +- **位置**: `com.codingapi.flow.session.FlowSession` +- **职责**: 流程执行的上下文会话对象 +- **核心属性**: + - `currentOperator`: 当前操作者 + - `workflow`: 流程定义 + - `currentNode`: 当前节点 + - `currentAction`: 当前动作 + - `currentRecord`: 当前记录 + - `formData`: 表单数据 + - `advice`: 审批意见 +- **核心方法**: + - `matchNextNodes()`: 匹配后续节点 + - `updateSession()`: 更新会话 + +#### FlowAdvice +- **位置**: `com.codingapi.flow.session.FlowAdvice` +- **职责**: 封装审批操作的相关参数 +- **核心属性**: `advice`(审批意见), `signKey`(签名), `action`(动作), `backNode`(退回节点), `transferOperators`(转办人员) + +--- + +### 6. 管理器层 (Manager Layer) + +#### ActionManager +- **位置**: `com.codingapi.flow.node.manager.ActionManager` +- **职责**: 管理节点的动作列表 +- **核心方法**: `getActionById(String)` + +#### OperatorManager +- **位置**: `com.codingapi.flow.node.manager.OperatorManager` +- **职责**: 管理节点的操作者列表 +- **核心方法**: `match(IFlowOperator)` + +#### FieldPermissionManager +- **位置**: `com.codingapi.flow.node.manager.FieldPermissionManager` +- **职责**: 管理表单字段权限 + +#### StrategyManager +- **位置**: `com.codingapi.flow.node.manager.StrategyManager` +- **职责**: 管理节点策略(多人审批、超时、退回等) + +--- + +### 7. 策略层 (Strategy Layer) + +#### INodeStrategy +- **位置**: `com.codingapi.flow.strategy.INodeStrategy` +- **职责**: 节点策略的顶层接口 + +#### 策略类型 + +| 策略类 | 说明 | +|-------|------| +| MultiOperatorAuditStrategy | 多人审批策略(顺序/或签/并签/随机) | +| TimeoutStrategy | 超时策略 | +| SameOperatorAuditStrategy | 同一操作者审批策略 | +| RecordMergeStrategy | 记录合并策略 | +| ResubmitStrategy | 重新提交策略 | +| AdviceStrategy | 审批意见策略 | + +--- + +### 8. 脚本层 (Script Layer) + +#### ScriptRuntimeContext +- **位置**: `com.codingapi.flow.script.runtime.ScriptRuntimeContext` +- **职责**: Groovy脚本运行时环境 +- **核心方法**: `execute(String method, String script, ...)` + +#### 脚本类型 + +| 脚本类 | 说明 | +|-------|------| +| OperatorMatchScript | 操作者匹配脚本 | +| OperatorLoadScript | 操作者加载脚本 | +| NodeTitleScript | 节点标题脚本 | +| ConditionScript | 条件判断脚本 | +| ErrorTriggerScript | 异常触发脚本 | + +--- + +## 二、流程生命周期 + +### 1. 流程创建阶段 (FlowCreateService) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ FlowCreateService │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 1. 验证请求参数 │ + │ request.verify() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 2. 获取流程定义 │ + │ workflowRepository.get() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 3. 验证流程定义 │ + │ workflow.verify() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 4. 创建/获取备份 │ + │ WorkflowBackup │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 5. 验证创建者权限 │ + │ matchCreatedOperator() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 6. 构建表单数据 │ + │ new FormData() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 7. 创建开始会话 │ + │ FlowSession.startSession() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 8. 验证会话参数 │ + │ verifySession() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 9. 生成流程记录 │ + │ generateCurrentRecords() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 10. 保存记录 │ + │ flowRecordRepository.saveAll() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 11. 推送事件 │ + │ FlowRecordStartEvent │ + │ FlowRecordTodoEvent │ + └─────────────────┘ +``` + +--- + +### 2. 流程执行阶段 (FlowActionService) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ FlowActionService │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 1. 验证请求参数 │ + │ request.verify() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 2. 验证操作者 │ + │ flowOperatorGateway.get() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 3. 获取流程记录 │ + │ flowRecordRepository.get() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 4. 验证记录状态 │ + │ isTodo() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 5. 加载流程定义 │ + │ workflowBackup.toWorkflow() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 6. 获取当前节点 │ + │ workflow.getFlowNode() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 7. 获取动作对象 │ + │ actionManager.getActionById() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 8. 构建表单数据 │ + │ new FormData() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 9. 创建执行会话 │ + │ new FlowSession() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 10. 验证会话参数 │ + │ verifySession() │ + └─────────────────┘ + │ + ▼ + ┌─────────────────┐ + │ 11. 执行动作 │ + │ flowAction.run(session) │ + └─────────────────┘ +``` + +--- + +### 3. 节点生命周期 (Node Lifecycle) + +``` + ┌─────────────────────────────────────────┐ + │ 节点生命周期 │ + └─────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 1. verifySession(session) │ + │ 验证会话参数是否满足节点要求 │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 2. continueTrigger(session) │ + │ 判断是否继续执行后续节点 │ + │ true: 继续执行下一节点 │ + │ false: 执行步骤3 │ + └───────────────────────────────────────────┘ + │ │ + true │ │ false + ▼ ▼ + ┌─────────────────────┐ ┌─────────────────────────┐ + │ 递归执行下一节点 │ │ 3. generateCurrentRecords() │ + │ │ │ 生成当前节点的流程记录 │ + └─────────────────────┘ └─────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 4. fillNewRecord(session, record) │ + │ 填充新记录的数据 │ + └───────────────────────────────────────────┘ +``` + +--- + +### 4. 节点执行流程 (以PassAction为例) + +``` + ┌─────────────────────────────────────────┐ + │ PassAction.run() │ + └─────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 1. 判断节点是否完成 │ + │ currentNode.isDone(session) │ + └───────────────────────────────────────────┘ + │ │ + done │ │ not done + ▼ ▼ + ┌─────────────────────┐ ┌─────────────────────┐ + │ 更新当前记录为已办 │ │ 更新当前记录, │ + │ record.update(...) │ │ 保持待办状态 │ + └─────────────────────┘ └─────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 2. 生成后续记录 │ + │ generateRecords(session) │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 3. 触发后续节点 │ + │ triggerNode(session, callback) │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 4. 获取下一节点列表 │ + │ session.matchNextNodes() │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 5. 遍历下一节点 │ + │ for (IFlowNode node : nextNodes) │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 6. 更新会话到下一节点 │ + │ session.updateSession(node) │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 7. continueTrigger() │ + │ 判断是否继续执行 │ + └───────────────────────────────────────────┘ + │ │ + true │ │ false + ▼ ▼ + ┌─────────────────────┐ ┌─────────────────────┐ + │ 递归执行下一节点 │ │ 生成当前节点记录 │ + │ triggerNode() │ │ callback() │ + └─────────────────────┘ └─────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 8. 保存所有记录 │ + │ RepositoryContext.saveRecords() │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 9. 推送事件 │ + │ FlowRecordDoneEvent │ + │ FlowRecordTodoEvent │ + └───────────────────────────────────────────┘ +``` + +--- + +### 5. 并行分支执行流程 + +``` + ┌─────────────────────────────────────────┐ + │ 遇到ParallelBranchNode │ + └─────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 1. filterBranches() │ + │ 分析并行分支的结束汇聚节点 │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 2. 记录并行信息 │ + │ flowRecord.parallelBranchNode() │ + │ - parallelBranchNodeId: 汇聚节点ID │ + │ - parallelBranchTotal: 分支总数 │ + │ - parallelId: 并行实例ID │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 3. 同时执行所有并行分支 │ + │ 为每个分支生成流程记录 │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 4. 分支执行中... │ + │ 每个分支独立执行 │ + └───────────────────────────────────────────┘ + │ + ▼ + ┌───────────────────────────────────────────┐ + │ 5. 到达汇聚节点 │ + │ isWaitParallelRecord() │ + └───────────────────────────────────────────┘ + │ │ + 等待 │ │ 全部到达 + ▼ ▼ + ┌─────────────────────┐ ┌─────────────────────┐ + │ 增加触发计数 │ │ 清空并行信息 │ + │ 等待其他分支完成 │ │ 继续执行后续流程 │ + └─────────────────────┘ └─────────────────────┘ +``` + +--- + +## 三、核心设计模式 + +### 1. 建造者模式 (Builder Pattern) +- `WorkflowBuilder`: 构建流程定义 +- `BaseNodeBuilder`: 构建节点对象 +- `AuditNodeBuilder`: 构建审批节点 + +### 2. 工厂模式 (Factory Pattern) +- `NodeFactory`: 创建不同类型的节点 +- `FlowActionFactory`: 创建不同类型的动作 + +### 3. 策略模式 (Strategy Pattern) +- `INodeStrategy`: 节点策略接口 +- `MultiOperatorAuditStrategy`: 多人审批策略 +- `TimeoutStrategy`: 超时策略 + +### 4. 模板方法模式 (Template Method Pattern) +- `BaseFlowNode`: 定义节点生命周期模板 +- `BaseAction`: 定义动作执行模板 + +### 5. 单例模式 (Singleton Pattern) +- `NodeFactory.getInstance()`: 节点工厂单例 +- `ScriptRuntimeContext.getInstance()`: 脚本运行时单例 +- `RepositoryContext.getInstance()`: 仓储上下文单例 + +### 6. 责任链模式 (Chain of Responsibility Pattern) +- `triggerNode()`: 递归触发后续节点 + +--- + +## 四、扩展点 + +### 1. 自定义节点 +继承 `BaseFlowNode` 或 `BaseAuditNode`,实现 `IFlowNode` 接口 + +### 2. 自定义动作 +继承 `BaseAction`,实现 `IFlowAction` 接口 + +### 3. 自定义策略 +实现 `INodeStrategy` 接口 + +### 4. 自定义脚本 +使用 `ScriptRuntimeContext` 执行 Groovy 脚本 + +### 5. 事件扩展 +监听 `FlowRecordStartEvent`, `FlowRecordTodoEvent`, `FlowRecordDoneEvent`, `FlowRecordFinishEvent`