Skip to content

Commit 9ad35bb

Browse files
authored
Merge pull request #221 from codingapi/dev
Dev
2 parents db9403c + 2b3c506 commit 9ad35bb

13 files changed

Lines changed: 113 additions & 19 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ REST 层通过请求参数 `mockKey` 分流到 Mock 实例(见 `FlowRecordCont
6464

6565
### 事件(IFlowEvent + EventPusher)
6666

67-
7 种事件:开始 / 待办 / 已办 / 完成 / 催办 / 撤销(`FlowRecordRevokeEvent`)/ 删除(`FlowRecordDeleteEvent`)。操作完成后用 `EventPusher.push(event)` 推送;事件通常携带 `FlowRecord` + `mock` 标记。外部可用 Spring `@EventListener` 订阅。
67+
8 种事件:开始 / 待办 / 已办 / 完成 / 催办 / 撤销(`FlowRecordRevokeEvent`)/ 删除(`FlowRecordDeleteEvent`/ 子流程重置(`FlowSubProcessResetEvent`。操作完成后用 `EventPusher.push(event)` 推送;记录类事件携带 `FlowRecord` + `mock` 标记,重置事件携带新旧聚合组快照。外部可用 Spring `@EventListener` 订阅。
6868

6969
### API 模块划分
7070

docs/Integration/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
| [快速开始](./quick-start.md) | 最小集成步骤:引入依赖 → 提供 Bean → 编写流程 → 发起流程 |
3333
| [流程用户体系](./user-integration.md) | `FlowOperatorGateway` / `IFlowOperator` / `GatewayContext` / 线程缓存 / 当前登录人 |
3434
| [流程默认脚本](./script-integration.md) | 12 种脚本类型、`GroovyScriptRequest` 完整 API、`$bind`、默认脚本替换、脚本生命周期 |
35-
| [流程事件机制](./event-integration.md) | 7 种事件、`EventPusher``IHandler` 订阅、异步分发管道、事务变体、推送时机 |
35+
| [流程事件机制](./event-integration.md) | 8 种事件、`EventPusher``IHandler` 订阅、异步分发管道、事务变体、推送时机 |
3636
| [仓储抽象与持久化](./repository-integration.md) | `IRepositoryHolder`、12 个仓储接口(含 11 个 JPA 实现 + 需自行实现的 `NodeViewJavaScriptRepository`)、脚本仓储、锁机制 |
3737
| [Spring Boot 自动配置](./auto-configuration.md) | `AutoConfiguration` 8 个 Bean、4 个 Register、必选/可选 Bean 清单 |
3838
| [REST API](./rest-api.md) | 4 个 Controller、`mockKey`/`operatorId` 分流机制、请求/响应结构 |

docs/Integration/event-integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,5 +225,5 @@ public class MyFlowRecordUrgeEventHandler implements IHandler<FlowRecordUrgeEven
225225

226226
## 6. Mock 模式标记
227227

228-
- 事件携带 `mock` 标记:有 session 的场景用 `session.isMock()`(等价于 `repositoryHolder instanceof MockRepositoryHolder`);无 session 的服务(`FlowDeleteService`/`FlowUrgeService`/`FlowRevokeService`)直接用 `repositoryHolder instanceof MockRepositoryHolder`
228+
- 事件携带 `mock` 标记:有 session 的场景用 `session.isMock()`(等价于 `repositoryHolder instanceof MockRepositoryHolder`);无 session 的服务(`FlowDeleteService`/`FlowUrgeService`/`FlowRevokeService`/`FlowSubProcessResetService`)直接用 `repositoryHolder instanceof MockRepositoryHolder`
229229
- 订阅方可通过 `event.isMock()` 区分测试/演示流量与生产流量(例如不发送真实消息)。

docs/Integration/rest-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ form(FlowForm 元数据) / fieldPermissions(字段权限)
180180
todos(当前节点待办 Body 列表) / actions / actionList
181181
mergeable / createOperator / currentOperator / flowState / recordState
182182
histories(审批历史) / nodes(NodeOption 可操作节点) / revoke / urge
183-
resetSubProcess(子流程重置能力标识:当前待办位于开启重置能力、已汇聚完成的子流程下游时为 true)
183+
resetSubProcess(子流程重置能力标识:当前待办位于开启重置能力、已汇聚完成的子流程的锁定合并节点上时为 true;更深层下游节点为 false
184184
```
185185

186186
### `FlowRecordContent`(列表响应,字段摘要)

docs/capabilities/flow-engine-framework/sub-process.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
name: flow-engine-framework/sub-process
33
module: flow-engine-framework
4-
description: 子流程聚合执行能力,支持批量创建、主流程等待、脚本结果判定与异常跳转
4+
description: 子流程聚合执行能力,支持批量创建、主流程等待、脚本结果判定、异常跳转与数据重置(退回重走)
55
status: 已实现
66
scope: 后端
77
source: 项目自有
@@ -115,7 +115,7 @@ def run(request){
115115

116116
### 可见性(详情标识字段)
117117

118-
重置不是节点动作,不出现在动作列表中。流程详情 `FlowContent` 新增 `resetSubProcess` 布尔标识:当前待办位于「开启重置能力、已汇聚完成」的子流程下游时为 `true`。前端解析到该标识即可自行提供重置交互(呈现方式由使用方决定,不限定于操作列);节点视图中新旧聚合组同时呈现,`ProcessNode.SubProcessBody.superseded``SubProcessInstanceBody.inherited/sourceProcessId` 供前端区分。
118+
重置不是节点动作,不出现在动作列表中。流程详情 `FlowContent` 新增 `resetSubProcess` 布尔标识:当前待办位于「开启重置能力、已汇聚完成」的子流程的**锁定合并节点**上时为 `true`(更深层下游节点为 `false`。前端解析到该标识即可自行提供重置交互(呈现方式由使用方决定,不限定于操作列);节点视图中新旧聚合组同时呈现,`ProcessNode.SubProcessBody.superseded``SubProcessInstanceBody.inherited/sourceProcessId` 供前端区分。
119119

120120
### 数据结构兼容性
121121

docs/capabilities/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
| [flow-engine-framework/operator-assignment](./flow-engine-framework/operator-assignment.md) | flow-engine-framework | 操作人分配能力,支持发起人/审批人设定的分配校验与落库 | 后端 | 项目自有 |
2020
| [flow-engine-framework/repository](./flow-engine-framework/repository.md) | flow-engine-framework | 仓储抽象层,定义流程引擎的持久化接口和仓储持有者上下文 | 后端 | 项目自有 |
2121
| [flow-engine-framework/script](./flow-engine-framework/script.md) | flow-engine-framework | Groovy 脚本运行时,包含脚本注册表、脚本类型封装和脚本执行上下文 | 后端 | 项目自有 |
22-
| [flow-engine-framework/sub-process](./flow-engine-framework/sub-process.md) | flow-engine-framework | 子流程聚合执行能力,支持批量创建、主流程等待、脚本结果判定与异常跳转 | 后端 | 项目自有 |
22+
| [flow-engine-framework/sub-process](./flow-engine-framework/sub-process.md) | flow-engine-framework | 子流程聚合执行能力,支持批量创建、主流程等待、脚本结果判定、异常跳转与数据重置(退回重走) | 后端 | 项目自有 |
2323
| [flow-engine-framework/workflow-strategy](./flow-engine-framework/workflow-strategy.md) | flow-engine-framework | 工作流级别策略体系,包含策略接口、工厂和具体策略实现 | 后端 | 项目自有 |
2424
| [flow-engine-framework/workflow](./flow-engine-framework/workflow.md) | flow-engine-framework | 工作流引擎核心模型,包含流程定义、构建器、版本管理和运行时快照 | 后端 | 项目自有 |
2525
| [flow-engine-starter/auto-configuration](./flow-engine-starter/auto-configuration.md) | flow-engine-starter | Spring Boot 自动配置入口,注册流程引擎的核心组件和仓储上下文 | 后端 | 项目自有 |

docs/capabilities/springboot/ioc.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ framework_version: "3.5.9"
1616
- **依赖注入**:容器管理 Bean 之间的依赖关系。本项目不使用 `@Autowired` / `@Inject` 注解,统一通过 Lombok `@AllArgsConstructor` 构造器注入(如 `WorkflowController``WorkflowService`、各 `RepositoryImpl`
1717
- **Bean 生命周期管理**:容器统一管理 Bean 的创建、初始化和销毁
1818
- **AOP 支持**:框架提供 `@Aspect` 横切关注点能力(本项目未使用)
19-
- **事件发布**:本项目不使用 Spring `ApplicationEventPublisher`,事件系统为自研 `IFlowEvent` + `EventPusher``flow-engine-framework/event/`7 种事件类,操作完成后通过 `EventPusher.push(event)` 推送)
19+
- **事件发布**:本项目不使用 Spring `ApplicationEventPublisher`,事件系统为自研 `IFlowEvent` + `EventPusher``flow-engine-framework/event/`8 种事件类,操作完成后通过 `EventPusher.push(event)` 推送)
2020
- **自动配置**:通过 `@Configuration` + `@Conditional` 实现条件化 Bean 注册
2121

2222
## 如何使用

docs/manual/integration-manual.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ <h2 id="be-extends">5. 后端:扩展点</h2>
284284

285285
<table>
286286
<tr><th>扩展点</th><th>说明</th></tr>
287-
<tr><td>事件订阅</td><td>实现 <code>IHandler&lt;E&gt;</code> 订阅 7 种事件:Start / Todo / Done / Finish / Urge / Revoke / Delete,自动被 Spring 扫描</td></tr>
287+
<tr><td>事件订阅</td><td>实现 <code>IHandler&lt;E&gt;</code> 订阅 8 种事件:Start / Todo / Done / Finish / Urge / Revoke / Delete / SubProcessReset,自动被 Spring 扫描</td></tr>
288288
<tr><td>节点策略</td><td>15 种策略(OperatorLoad / RecordMerge / Revoke / Router / FormFieldPermission 等)由 <code>NodeStrategyManager</code> 持有(工厂固定注册,不支持新增策略类型;业务方通过策略配置 + Groovy 脚本表达差异)</td></tr>
289289
<tr><td>自定义动作</td><td>8 种内置动作(PASS/REJECT/RETURN/TRANSFER/DELEGATE/ADD_AUDIT/SAVE/CUSTOM)由 <code>FlowActionFactory</code> 固定注册(不支持新增动作类型);业务方通过 CUSTOM 动作 + Groovy 脚本表达自定义行为</td></tr>
290290
<tr><td>自定义脚本注册</td><td><code>ScriptRegistryContext.getInstance().setRegistry(new CustomScriptRegistry())</code> 替换默认 Groovy 脚本</td></tr>

flow-engine-framework/src/main/java/com/codingapi/flow/mock/repository/FlowRecordRepositoryMockImpl.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ public List<FlowRecord> findTodoByOperator(long operatorId) {
3333
}
3434

3535
public List<FlowRecord> findDoneByOperator(long operatorId) {
36-
return cache.values().stream().filter(flowRecord -> flowRecord.getCurrentOperatorId() == operatorId && !flowRecord.isTodo()).toList();
36+
// 与 JPA 口径一致:已办列表过滤已作废与隐藏记录(撤销/重置产生的作废记录不进入已办)
37+
return cache.values().stream().filter(flowRecord -> flowRecord.getCurrentOperatorId() == operatorId && flowRecord.isDone()).toList();
3738
}
3839

3940
public List<FlowRecord> findNotifyByOperator(long operatorId) {
40-
return cache.values().stream().filter(flowRecord -> flowRecord.getCurrentOperatorId() == operatorId && flowRecord.isNotify()).toList();
41+
// 与 JPA 口径一致:抄送列表过滤已作废与隐藏记录
42+
return cache.values().stream().filter(flowRecord -> flowRecord.getCurrentOperatorId() == operatorId && flowRecord.isNotify() && !flowRecord.isRevoked() && !flowRecord.isHidden()).toList();
4143
}
4244

4345

flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowSubProcessResetService.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,12 @@ public void reset() {
141141
newInstances);
142142
subProcessRepository.save(newGroup);
143143

144-
for (FlowActionRequest submitRequest : submitRequests) {
145-
flowService.action(submitRequest);
146-
}
147-
148-
// 作废触发锚点之后的记录链(复用撤销语义):重置后主流程退回子流程节点等待,
144+
// 作废触发锚点之后的旧记录链(复用撤销语义):重置后主流程退回子流程节点等待,
149145
// 锚点之后的旧记录不再代表有效路径,且其 fromId + 节点与恢复后新建记录相同,
150-
// 不作废会被同节点记录查询误判为多人审批
146+
// 不作废会被同节点记录查询误判为多人审批。
147+
// 作废必须先于重建实例提交:纯自动子流程会在提交中同步跑完并触发结果判定
148+
// 恢复主流程(新记录 fromId == 锚点id),之后再作废会把刚恢复的新记录一并作废,
149+
// 导致主流程卡死
151150
List<FlowRecord> invalidatedRecords = new ArrayList<>();
152151
List<FlowRecord> afterRecords = repositoryHolder
153152
.findAfterRecords(currentRecord.getProcessId(), anchorRecord.getId());
@@ -164,6 +163,10 @@ public void reset() {
164163
// 避免重走再次触发下游节点(如抄送)时被被动式环检测误判为循环
165164
LoopTriggerTraceContext.getInstance().clearByProcess(currentRecord.getProcessId());
166165

166+
for (FlowActionRequest submitRequest : submitRequests) {
167+
flowService.action(submitRequest);
168+
}
169+
167170
boolean mock = repositoryHolder instanceof MockRepositoryHolder;
168171
IFlowOperator resetOperator = repositoryHolder.getOperatorById(request.getOperatorId());
169172
for (FlowRecord invalidatedRecord : invalidatedRecords) {

0 commit comments

Comments
 (0)