首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >从发送矩阵到多人规则:一套工作流引擎的模式设计剖析

从发送矩阵到多人规则:一套工作流引擎的模式设计剖析

原创
作者头像
驰骋工作流程
发布于 2026-09-26 11:11:37
发布于 2026-09-26 11:11:37
1230
举报

本文基于一套主流开源工作流引擎的源码结构,梳理其流程模式抽象与发送调度机制,供架构与平台工程师参考。

1 引言

1.1 研究背景

随着企业数字化转型的深入,流程管理系统(BPM/Workflow)已从早期的 OA 审批工具,演进为连接组织、表单、数据与外部系统的业务编排中枢。一个成熟的流程引擎不仅需要支持"甲提交→乙审批→丙归档"这类简单串行场景,还必须应对以下复杂需求:

  • 并行处理:同一单据需多人或部门同时处理后再汇总;
  • 异构协同:不同岗位使用不同表单,完成后汇合到主流程;
  • 跨流程编排:主业务触发子流程,子流程结束后反填主流程并驱动其继续运行;
  • 丰富的运行时操作:发送、退回、移交、撤销、催办、加签、暂停、删除等;
  • 实例级治理:对运行中或已完成的流程进行跳转、回滚、逻辑删除与物理删除。

国际上有 BPMN 2.0、Workflow Patterns(van der Aalst 等)等成熟理论,但其元素繁多、学习曲线陡峭,不利于企业业务人员快速建模。该引擎(及其 Java 版本 该引擎)在国内政企、制造、金融等领域有大量落地实践,其提出的流程引擎四大模式——线形流程、同表单分合流、异表单分合流、父子流程——是一种面向工程落地的模式化抽象,具有重要的理论总结与论文化价值。

1.2 研究问题

本文围绕以下问题展开研究:

  1. RQ1:四大模式各自解决哪类流程结构问题?为何可以声称"涵盖流程应用环境的各个方面"?
  2. RQ2:四种模式在数据模型与运行时语义上如何区分与关联?
  3. RQ3:节点上的通用操作(发送、退回、移交等)能否由统一引擎支撑,而非各自独立实现?
  4. RQ4:节点向下运动的核心算法是什么?多人处理与退回规则如何与核心算法协同?
  5. RQ5:设计态(流程设计器)与运行态(待办处理)如何保持一致映射?

1.3 主要贡献

  1. 系统化定义流程引擎四大模式,给出每种模式的拓扑结构、适用场景、数据关联键及代码实现锚点;
  2. 提出"汽车控制系统"类比模型,统一阐释流程引擎、表单引擎、数据与通用操作之间的关系;
  3. 揭示 该引擎 以 WorkNode.NodeSend_Send_5_5() 为核心的 5×5 发送算法,说明其如何调度线形、分合流、子线程等全部运行模式;
  4. 系统梳理 TodolistModel 多人处理规则与 ReturnRole 退回规则,并说明其与发送、退回、移交、撤销算法的耦合方式;
  5. 结合 Vue3/src/WF 前端设计器与运行态页面,给出从设计到运行的端到端实现路径。

1.3.1 与既有理论的区别

维度

Workflow Patterns / BPMN

本文四大模式

受众

工作流研究人员、BPM 架构师

企业业务人员、实施顾问、二开工程师

粒度

43 种控制流模式 + 网关组合

4 种结构模式 + 统一操作集

数据视角

流程与数据分离(Data Object)

表单驱动,PTable/FrmNode 与 RunModel 绑定

实现锚点

标准 XML 元素

WF_Node.RunModel 字段 + NodeSend_Send_5_5()

四大模式并非对 BPMN 的替代,而是对表单驱动型流程引擎在工程实践中的认知压缩(Cognitive Compression):将 Petri 网中的顺序、并行分支、同步合并、子网调用四类结构,与"同表/异表"数据维度、跨流程编排维度正交组合,形成可直接映射到数据库字段与 UI 图元的最小模式集。

1.4 论文结构

第 2 章介绍相关工作;第 3 章给出总体架构与汽车类比模型;第 4 章至第 7 章分别论述四大模式;第 8 章论述四大模式覆盖性;第 9 章论述节点通用操作;第 10 章论述流程实例级操作;第 11 章论述节点向下运动核心算法;第 12 章论述多人处理规则;第 13 章论述退回规则;第 14 章给出案例验证;第 15 章总结与展望。


2 相关工作

2.1 工作流理论与 Workflow Patterns

Petri 网、有限状态机为工作流的形式化基础提供了严格语义。van der Aalst 等提出的 Workflow Patterns 将流程控制结构归纳为 43 种模式,其中与本文四大模式密切相关的包括:

Workflow Pattern

模式编号

本文四大模式对应

Sequence(顺序)

WCP-1

线形流程

Parallel Split(并行分支)

WCP-2, WCP-4

同/异表单分合流之分流节点

Synchronization(同步合并)

WCP-7, WCP-33

同/异表单分合流之合流节点

Sub-Process

WCP-41

父子流程

BPMN 2.0 以 Sequence Flow、Parallel Gateway、Inclusive Gateway、Call Activity 等元素表达类似语义。与 BPMN 相比,该引擎 的四大模式是面向业务人员的认知压缩:将网关、子流程、多实例活动等概念归纳为四种可组合的模式,降低建模门槛。

2.2 开源流程引擎对比

引擎

并行分支

子流程

特点

Activiti/Camunda

Parallel Gateway

Call Activity

BPMN 标准,与标准元素一一对应

Flowable

同上

同上

Activiti 分支,增强 REST 与 UI

该引擎

RunModel.FL/HL/FHL

SubFlowModel + PWorkID

表单驱动,RunModel 显式标注,国内实践丰富

该引擎 的差异化在于:将节点运行模式(RunModel)作为一等公民写入 WF_Node 表,并在发送引擎中以 5×5 矩阵统一调度,而非完全依赖 BPMN 解析器。

2.3 本文定位

本文并非提出全新的形式化工作流演算,而是对 该引擎 工程实践中沉淀的"四大模式 + 通用操作 + 统一发送引擎"进行系统化理论总结与实现剖析,为流程引擎教学、选型与二次开发提供参考。


3 系统总体架构与汽车类比模型

3.1 分层架构

该引擎 工作流子系统采用经典四层架构:

代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────┐
│  表现层   Vue3/src/WF                                         │
│           FlowDesignerV2(设计器)/ MyFlow(运行态)            │
├──────────────────────────────────────────────────────────────┤
│  接口层   HttpHandler                                         │
│           WF_MyFlow / WF_WorkOpt / WF_Admin_CCBPMDesigner    │
├──────────────────────────────────────────────────────────────┤
│  引擎层   BP.WF                                               │
│           WorkNode / WorkReturn / WorkUnSend / ShiftWork     │
│           WorkFlow / WorkReSend / Dev2Interface              │
├──────────────────────────────────────────────────────────────┤
│  模板层   BP.WF.Template                                      │
│           Node / Direction / Cond / SFlow(子流程配置)         │
├──────────────────────────────────────────────────────────────┤
│  数据层   WF_Flow / WF_Node / WF_Direction                   │
│           WF_GenerWorkFlow / WF_GenerWorkerList / WF_Track   │
└──────────────────────────────────────────────────────────────┘

3.2 汽车类比模型

为帮助业务人员与开发人员建立统一心智模型,本文提出如下类比:

汽车概念

流程引擎概念

代码/存储对应

说明

汽车控制系统

流程引擎

WorkNode, WorkReturn, WorkUnSend

控制车辆如何启动、前进、倒车、变道、停车

汽车车厢

表单引擎

CCForm, MapData, FrmNode

承载业务信息的容器,随流程节点切换而更换"车厢布局"

货物

业务数据

业务主表(PTable)、从表(MapDtl)

真正被运输和处理的对象

前进(踩油门)

发送

NodeSend(), ActionType.Forward

流程向下运动

倒车

退回

WorkReturn.DoIt(), ActionType.Return

流程向上回退

换司机

移交

ShiftWork.Node_Shift_ToEmp(), ActionType.Shift

更换当前节点处理人

取消本次行程

撤销

WorkUnSend.DoUnSend(), ActionType.UnSend

撤销最近一次发送

鸣笛催办

催办

Flow_DoPress(), ActionType.Press

提醒待办人尽快处理

左拐/右拐

方向条件

Direction, Cond, Func_GenerNextStepNodes()

根据条件选择下一节点

中途换人协助

前加签/后加签

Node_Askfor(), AskforHelpSta

临时增加协助处理人

停车等待

挂起(暂停)

WorkFlow.DoHungup(), WFState.Hungup

暂停流程运行

报废(标记)

逻辑删除

DoDeleteWorkFlowByFlag(), WFState.Delete

标记删除,数据保留

报废(拆解)

物理删除

DoDeleteWorkFlowByReal()

彻底清除全部关联数据

拖车到指定路口

调整

Flow_ReSend(), ActionType.Adjust

将运行中流程跳到指定节点/人员

行程记录回放

回滚

DoRebackFlowData()

已完成流程恢复到历史节点

该类比的核心价值在于:流程引擎不负责"装什么货"(业务逻辑在表单与数据中),而负责"怎么运"(节点如何推进、如何回退、如何并行)。表单引擎与流程引擎解耦,使得同一流程引擎可驱动不同业务表单,同一表单也可被不同流程复用。

进一步地,方向条件对应汽车导航中的"路口选择":在 Func_GenerNextStepNodes() 中,引擎遍历当前节点的所有出边(WF_Direction),逐条评估 Cond 条件——表达式比较、SQL 查询、岗位/部门匹配等——决定"左拐"还是"右拐"。这与 BPMN 的 Exclusive Gateway / Inclusive Gateway 语义等价,但在 该引擎 中无需额外网关节点,条件直接附着在连线上,降低了设计器图元的数量。

**阻塞模式(BlockModel)**可类比"前方施工禁行":在节点发送前,若 BlockModel ≠ None,引擎检查子线程是否全部完成(CurrNodeAll)、指定子流程是否到达某节点(SpecSubFlowNode)、或自定义 SQL/表达式是否返回阻塞信号,满足则禁止发送。这使父子流程、分合流场景下的"等待依赖"得以声明式配置。

3.3 核心数据模型

3.3.1 流程定义层

实体

表/类

关键字段

含义

流程

WF_Flow / Flow

No, Name

流程模板

节点

WF_Node / Node

NodeID, RunModel, TodolistModel

活动单元

方向

WF_Direction / Direction

Node, ToNode

节点连线

条件

WF_Cond / Cond

表达式/SQL

方向生效条件

子流程配置

WF_NodeSubFlow

SubFlowNo, SubFlowModel

父子流程绑定

3.3.2 流程实例层

实体

表/类

关键字段

含义

工作实例

WF_GenerWorkFlow

WorkID, FID, PWorkID, WFState

一次流程运行

工作人员列表

WF_GenerWorkerList

WorkID, FK_Node, FK_Emp, IsPass

待办/已办

轨迹

WF_Track

ActionType, NDFrom, NDTo

操作审计日志

3.3.3 三种关联键

关联键

适用模式

含义

WorkID

全部模式

工作实例主键,标识一次运行

FID

分合流

子线程的 FID 指向干流程 WorkID

PWorkID

父子流程

子流程的 PWorkID 指向父流程 WorkID

重要区分:FID 用于同一流程内的干/子线程关系;PWorkID 用于不同流程间的父/子调用关系。二者正交,可并存。

3.4 节点运行模式枚举 RunModel

该引擎 将节点的结构角色抽象为 RunModel 枚举(定义于 EnumLib.cs):

值

枚举名

中文标签

所属模式

0

Ordinary

线形

模式一

1

HL

合流

模式二/三

2

FL

分流

模式二/三

3

FHL

分合流

模式二/三

4

SubThreadSameWorkID

同表单子线程

模式二

5

SubThreadUnSameWorkID

异表单子线程

模式三

父子流程(模式四)不通过 RunModel 表达,而使用 NodeType.SubFlowNode 与 SubFlowModel 枚举。


4 模式一:线形流程

4.1 模式定义

线形流程是流程引擎中最基础的模式,指节点按有向图顺序(或条件分支)推进,RunModel = Ordinary(0),同一 WorkID 在节点间传递,FID = 0。

典型拓扑:

代码语言:javascript
复制
[开始节点] → [节点A] → [节点B] → [节点C] → [结束节点]
                  ↘ [节点D] → [节点E] ↗    (条件分支仍属线形)

4.2 适用场景

  • 请假、报销、用印等串行审批;
  • 条件路由:根据表单字段值选择不同审批路径(通过 Direction + Cond 实现,不改变 RunModel);
  • 作为其他三种模式的"骨架",复杂流程通常以线形节点为主体,嵌入分合流或子流程节点。

4.3 运行时语义

  1. 处理人完成当前节点表单后,调用 WorkNode.NodeSend();
  2. 发送引擎执行 NodeSend_11(Node toND)——普通节点到普通节点;
  3. WorkID 保持不变,业务主表 OID = WorkID;
  4. Func_GenerNextStepNodes() 根据方向条件计算下一节点集合;
  5. Func_GenerWorkerLists() 按 DeliveryWay(按部门、按角色、按表单字段等)计算接收人;
  6. 在 WF_GenerWorkerList 中插入下一节点待办记录;
  7. 写轨迹 ActionType.Forward。

4.4 方向条件(左拐/右拐)

线形流程中的分支不依赖专用网关节点,而通过方向条件实现:

  • 每条 Direction(WF_Direction)可配置一条或多条 Cond(条件);
  • 条件支持:表达式(表单字段比较)、SQL、岗位、部门等;
  • Func_GenerNextStepNodes() 遍历当前节点的所有出边,评估条件,返回满足条件的下一节点集合;
  • 若多条出边同时满足,可配置为"排他"或"并行"(后者需转入分合流模式)。

4.5 前端实现

环节

文件/组件

说明

设计器形状

Vue3/src/WF/Admin/FlowDesignerV2/shapes/index.ts

mode=0,矩形,标签"线性"

节点属性

Vue3/src/WF/Admin/AttrNode/NodeExt.ts

配置 TodolistModel、退回规则等

方向条件

NodeContextMenu → 方向条件配置

写入 WF_Cond

运行态

MyFlow.vue → MyFlow_Init → MyFlowGener.vue

后端返回 PageName 动态加载

4.6 小结

线形流程是四大模式的基石,复杂度最低,却是理解发送引擎、多人规则、退回规则的入门路径。其 Ordinary → Ordinary 路径在 5×5 矩阵中对应 (0,0) 单元格。


5 模式二:同表单分合流

5.1 模式定义

同表单分合流指在**同一物理表(PTable)**上,由分流节点(RunModel.FL=2)启动多个子线程(RunModel.SubThreadSameWorkID=4),各子线程并行处理后,经合流节点(RunModel.HL=1)或分合流节点(RunModel.FHL=3)同步汇总,再继续主干流程。

典型拓扑:

代码语言:javascript
复制
[普通] → [分流 FL] ─┬→ [同表单子线程-甲] ─┐
                    ├→ [同表单子线程-乙] ─┼→ [合流 HL] → [普通]
                    └→ [同表单子线程-丙] ─┘

5.2 适用场景

  • 采购申请明细按行分派给不同采购员并行处理;
  • 项目立项后多部门会签(共享同一申请单);
  • 同一合同需法务、财务、业务三方并行审核后汇总。

5.3 数据模型

角色

WorkID

FID

物理表

干流程

W0

0

PTable(主表)

子线程1

W1

W0

PTable(同一表,OID=W1)

子线程2

W2

W0

PTable(同一表,OID=W2)

合流后

W0

0

PTable(回到干流程 WorkID)

子线程与干流程共享同一 PTable,通过不同的 OID(= 各自 WorkID)区分数据行。子线程的 FID 字段指向干流程 WorkID,建立从属关系。

5.4 核心算法

5.4.1 分流启动子线程

方法:WorkNode.NodeSend_24_SameSheet(Node toNode) 文件:该引擎/Components/BP.WF/WF/WorkNode.cs

算法步骤:

  1. 根据 DeliveryWay(如 ByDtlAsSubThreadEmps 从明细表行确定人员)计算子线程接收人列表;
  2. 为每个接收人生成独立 WorkID;
  3. 设置子线程 wk.FID = 干流程 WorkID;
  4. 复制分流节点表单数据到子线程(Copy(this.HisWork));
  5. 在 WF_GenerWorkerList 中为每个子线程插入待办;
  6. 写轨迹 ActionType.ForwardFL。
5.4.2 子线程到达合流

方法:WorkNode.NodeSend_53_SameSheet_To_HeLiu(Node toNode)

算法步骤:

  1. 子线程处理完毕发送时,目标为合流节点;
  2. 更新当前子线程 GenerWorkerList.IsPass = 1(已办);
  3. 在干流程 GenerWorkFlow.AtPara 中维护 ThreadCount(已到达合流点的子线程数);
  4. 计算通过率:passRate = numPassed / numAll × 100;
  5. 当 passRate ≥ Node.PassRate(合流通过率,默认 100%)时:
    • 将合流节点 GenerWorkerList.IsPass 置为 0(待办可见);
    • 干流程处理人可在合流节点继续操作;
  6. 执行合流汇总:GenerHieLiuHuiZhongDtlData_2013() 将子线程从表数据汇总到主干;
  7. 写轨迹 ActionType.ForwardHL。
5.4.3 合流通过率 PassRate

Node.PassRate 属性控制合流触发条件:

  • PassRate = 100:所有子线程完成后才触发合流(默认);
  • PassRate = 50:过半子线程完成即可触发合流;
  • 适用于"多数决"类业务场景。

5.5 运行时管理

功能

属性/方法

说明

增加子线程

ThreadIsCanAdd

分流节点是否允许运行时增加子线程

删除子线程

ThreadIsCanDel

是否允许删除子线程

移交子线程

ThreadIsCanShift

是否允许移交子线程处理人

合流点补加

ThreadIsCanAddOfHL

合流节点是否允许补加子线程

子线程查询

Dev2Interface.DB_GenerHLSubFlowDtl_TB()

查询同表单合流子线程列表

5.6 前端实现

环节

文件

说明

设计器

shapes/index.ts

分流(2)、合流(1)、分合流(3)、同表单(4) 各有独立多边形

运行态

MyFLDealThread.vue

分合流专用处理页

子线程管理

ThreadDtl.vue

工具栏"子线程"弹窗

轨迹

ActionType.ForwardFL(6) / ForwardHL(7)

显示"分流前进""合流前进"

5.7 撤销与退回

  • 撤销:WorkUnSend.UnSend_FHL() 针对分合流节点的专用撤销逻辑;
  • 退回:WorkReturn 中的分合流退回矩阵(如子线程退分流、合流退子线程等),详见第 13 章。

5.8 小结

同表单分合流解决了"同一单据、多人并行、数据共享"的核心需求,是政企会签类场景的主力模式。其关键在于 FID 关联与 PassRate 合流控制。


6 模式三:异表单分合流

6.1 模式定义

异表单分合流与同表单分合流共享分流(FL)、合流(HL)、分合流(FHL)节点类型,差异在于子线程节点使用 RunModel.SubThreadUnSameWorkID=5,每个子线程可绑定独立表单/物理表。

典型拓扑:

代码语言:javascript
复制
[普通] → [分流 FL] ─┬→ [异表单子线程-法务表单] ─┐
                    ├→ [异表单子线程-财务表单] ─┼→ [合流 HL] → [普通]
                    └→ [异表单子线程-技术表单] ─┘

6.2 适用场景

  • 项目立项后主流程表单不变,子线程分别走法务审查、财务评估、技术评审等独立表单;
  • 采购主单不变,子线程分别填写供应商资质表、价格对比表、质量验收表;
  • 任何需要"并行处理、异构表单、最终汇总"的场景。

6.3 与同表单的核心差异

维度

同表单 (RunModel=4)

异表单 (RunModel=5)

物理表

与干流程相同 PTable

独立表单/表(FrmNodes, RefOneFrmTree)

WorkID 规则

每接收人一个 WorkID

受 USSWorkIDRole 控制

数据复制

Copy(HisWork) 同表复制

GEEntityOID 独立插入

分流方法

NodeSend_24_SameSheet()

NodeSend_24_UnSameSheet()

合流方法

NodeSend_53_SameSheet_To_HeLiu()

NodeSend_53_UnSameSheet_To_HeLiu()

查询 API

DB_GenerHLSubFlowDtl_TB()

DB_GenerHLSubFlowDtl_YB()

退回特性

标准退回

可启用 IsKillEtcThread(退回时终止其他子线程)

6.4 USSWorkIDRole:异表单 WorkID 生成规则

NodeExt.cs 中定义:

值

含义

场景

0

仅生成一个 WorkID

多人共享同一子线程实例(协作模式)

1

按接收人生成 WorkID

每人独立子线程实例(默认)

6.5 核心算法

6.5.1 分流启动

方法:WorkNode.NodeSend_24_UnSameSheet(Nodes toNDs)

  1. 遍历目标子线程节点集合;
  2. 按 USSWorkIDRole 决定 WorkID 生成策略;
  3. 为每个子线程绑定独立表单,通过 FrmNodes 配置表单与节点的关联;
  4. 独立插入业务数据(GEEntityOID);
  5. 设置 wk.FID = 干流程 WorkID。
6.5.2 合流汇总

方法:WorkNode.NodeSend_53_UnSameSheet_To_HeLiu(Node nd)

  1. 合流逻辑与同表单类似(ThreadCount + PassRate);
  2. 额外执行字段级汇总:将各子线程表单字段值写入主干表单的合流汇总从表(MapDtl.IsHLDtl = true)。

6.6 设计约束

代码中明确规定(WorkNode.cs):

  • 分流节点不能同时启动同表单与异表单子线程;
  • 分流节点不能同时启动多个同表单子线程(仅允许一个同表单子线程节点)。

这些约束保证了 5×5 发送矩阵的确定性。

6.7 前端实现

环节

文件

说明

设计器

shapes/index.ts

mode=5/16,标签"异表单",梯形多边形

属性

NodeExt.ts

USSWorkIDRole 配置

退回

ReturnWork.vue

RunModel=4/5 时启用 IsKillEtcThread

运行态

MyFLDealThread.vue

与同表单共用

6.8 小结

异表单分合流将流程引擎的表达能力从"同构并行"扩展到"异构并行",是复杂协同场景的关键模式。其与同表单的统一合流控制(PassRate + ThreadCount)体现了 5×5 算法的复用性。


7 模式四:父子流程

7.1 模式定义

父子流程实现跨流程实例的编排:父流程在某个节点触发子流程,子流程独立运行,结束后可反填父流程字段并驱动父流程继续。与分合流的本质区别在于:

维度

分合流

父子流程

关联键

FID(同一 FlowNo 内)

PWorkID(不同 FlowNo 间)

节点标识

RunModel.FL/HL/SubThread*

NodeType.SubFlowNode

配置表

无额外配置

WF_NodeSubFlow

生命周期

子线程随干流程结束而结束

子流程可独立运行、独立结束

7.2 子流程类型

FrmSubFlow.cs 定义:

类型

枚举值

触发方式

典型场景

手动子流程

HandSubFlow = 0

用户在父流程表单点击启动

按需发起子审批

自动子流程

AutoSubFlow = 1

节点发送时 CallAutoSubFlow()

到达某节点自动创建

延续子流程

YanXuFlow = 2

子流程结束后延续父流程

阶段性子任务

7.3 子流程模式

模式

枚举

含义

下级子流程

SubLevel

子流程挂到当前父 WorkID

同级子流程

SameLevel

子流程挂到父流程的父级

7.4 典型拓扑

代码语言:javascript
复制
[父流程-节点A] → [父流程-节点B(含子流程配置)]
                        ↓ 自动/手动启动
                  [子流程-开始] → [子流程-审批] → [子流程-结束]
                        ↓ 子流程结束
                  反填父流程字段 → 驱动父流程到下一节点

7.5 核心算法

7.5.1 建立父子关系

方法:Dev2Interface.SetParentInfo(subFlowNo, subFlowWorkID, parentWorkID, ...)

代码语言:javascript
复制
UPDATE WF_GenerWorkFlow 
SET PFlowNo=..., PWorkID=..., PNodeID=..., PEmp=... 
WHERE WorkID=子流程WorkID
7.5.2 手动启动

入口:WF_WorkOpt.SendSingleSubFlow()

  • SubLevel:Node_CreateBlankWork(subFlowNo, ..., parentWorkID, ...) + SetParentInfo()
  • SameLevel:挂到 gwf.PWorkID
7.5.3 自动启动

方法:WorkNode.CallAutoSubFlow()

  • 按 InvokeTime(节点发送前/后)、条件表达式、SQL 数据源批量创建子流程实例;
  • SubFlowHidTodolist 可隐藏父流程待办(IsPass=100)。
7.5.4 子流程全部结束后的父流程处理

方法:WorkNodePlus.SubFlowOver_* 系列 规则 AllSubFlowOverRole:

规则

行为

None

不驱动父流程

SendParentFlowToNextStep

自动发送父流程到下一步

OverParentFlow

结束父流程

字段反填:BackCopyRole 控制子流程字段向父流程的映射。

7.6 前端实现

环节

文件

说明

设计器

subFlowNodes[0]

六边形,NodeType.SubFlowNode=3

创建

useVueFlowNode.ts → CreateSubFlowNode

配置向导

GPN_NewSubFlow.ts

手工/自动/延续/导航

实体

SubFlowHand.ts, SubFlowAuto.ts, SubFlowYanXu.ts

运行态

SubFlow.vue

嵌入父流程表单

轨迹

Track.vue

聚合子流程实例卡片

动作

ActionType.CallChildenFlow(9), StartChildenFlow(10)

7.7 小结

父子流程解决了跨业务域流程编排问题,是四大模式中唯一涉及多个 FlowNo 的模式。PWorkID 关联键使其与分合流的 FID 完全正交。


8 四大模式的覆盖性论证

8.1 正交性与可组合性

四大模式并非互斥,一个完整企业流程通常是它们的组合:

代码语言:javascript
复制
[线形] → [分流] → [同表单子线程×3] → [合流] → [线形]
                                              ↓
                                    [自动启动父子流程]
                                              ↓
                                    [子流程:线形审批]
                                              ↓
                                    [反填父流程] → [线形] → [结束]

8.2 需求覆盖表

企业需求

对应模式

说明

串行审批、条件分支

线形流程

通过方向条件实现分支

同一单据多人并行、会签

同表单分合流

共享 PTable

并行子任务、异构表单

异表单分合流

独立表单绑定

跨业务域编排、主从单据

父子流程

PWorkID 关联

复杂监管(并行+子流程+汇总)

多模式组合

四大模式正交组合

8.3 "涵盖流程应用环境各个方面"的论证

从结构维度看,任意流程图均可分解为以下基本元素:

  1. 顺序执行 → 线形流程;
  2. 并行分支与同步合并(同构数据) → 同表单分合流;
  3. 并行分支与同步合并(异构数据) → 异表单分合流;
  4. 流程间调用 → 父子流程。

从操作维度看,第 9–13 章论述的通用操作(发送、退回、移交等)在所有模式下均可用统一引擎调度。因此,四大模式 + 通用操作构成了流程应用环境的最小完备集。

8.4 局限性

  1. 分流节点不能混启同表单与异表单子线程;
  2. 极端复杂编排(事件子流程、循环子流程)需结合脚本/服务任务扩展;
  3. 与 BPMN 完整语义并非一一对应,偏向表单驱动型场景。

9 节点通用操作

流程引擎在每个节点上提供一组通用操作,类比汽车驾驶行为(见 3.2 节)。本节结合 BP.WF 源码,逐一阐述各操作的触发条件、算法与轨迹记录。

9.1 操作总览

操作

汽车类比

核心类/方法

ActionType

WFState 变化

发送(前进)

踩油门

WorkNode.NodeSend()

Forward(1)

Runing

退回(后退)

倒车

WorkReturn.DoIt()

Return(2)

ReturnSta(5)

移交(换司机)

换司机

ShiftWork.Node_Shift_ToEmp()

Shift(3)

Shift(6)

撤销(取消任务)

取消行程

WorkUnSend.DoUnSend()

UnSend(5)

恢复上一状态

催办(鸣笛)

鸣笛

Dev2Interface.Flow_DoPress()

Press(18)

不变

前加签

临时乘客

Dev2Interface.Node_Askfor()

AskforHelp(24)

Askfor(8)

后加签

临时乘客

Node_Askfor() + AskforHelpSta

ForwardAskfor(25)

AskForReplay(10)

会签(前加签扩展)

多位乘客

Node_HuiQian_AddEmps()

HuiQian(30)

HuiQianing

删除

报废

WorkFlow.DoDeleteWorkFlowByFlag/Real()

DeleteFlowByFlag(19)

Delete(7)

挂起(暂停)

停车

WorkFlow.DoHungup()

Hungup(15)

Hungup(4)

9.2 发送(前进)

9.2.1 入口与调用链
代码语言:javascript
复制
前端 MyFlowGener.vue 
  → HttpHandler WF_WorkOpt 
  → Dev2Interface.Node_SendWork() 
  → WorkNode.NodeSend() 
  → NodeSend_Send_5_5()
9.2.2 三阶段处理

NodeSend() 方法体分为三大部分(WorkNode.cs 代码注释明确,约第 7613 行):

  1. 发送前检查(第 1 部分):
    • 流程是否已结束(IsOver)或逻辑删除(WFState.Delete);
    • 当前用户是否有处理权限(Flow_IsCanDoCurrentWork);
    • Guest 节点身份校验;
    • 会签状态检查(会签中是否允许发送);
    • 合流子线程是否全部完成;
    • 阻塞模式(BlockModel)检查;
    • 必填项校验;
    • 触发 EventListNode.SendWhen 事件。
  2. 5×5 核心算法(第 2 部分):详见第 11 章。
  3. 发送后处理(第 3 部分):
    • 更新 GenerWorkFlow 状态;
    • 写 WF_Track 轨迹;
    • 多人规则处理(队列/协作/抢办);
    • 会签完成判断;
    • 抄送(CC);
    • 子流程自动启动(CallAutoSubFlow);
    • DTS 数据同步;
    • 消息推送;
    • 触发 EventListNode.SendSuccess 事件。

9.3 退回(后退)

9.3.1 入口
代码语言:javascript
复制
前端 ReturnWork.vue 
  → WF_WorkOpt.DoReturnWork() 
  → Dev2Interface.Node_ReturnWork() 
  → WorkReturn.DoIt()
9.3.2 算法概要
  1. 若 returnToNodeID == 0,调用 DB_GenerWillReturnNodes(workid) 按 ReturnRole 计算可退节点列表;
  2. DoIt() 分支:
    • 跨流程退回 → ReturnToParentFlow();
    • 同节点队列模式 → DoOrderReturn();
    • 目标为协作/组长且 TeamReturnRole==1 → DoOrderReturn();
    • 否则按 当前 RunModel × 目标 RunModel 矩阵调用 ExeReturn1_1()、ExeReturn2_4() 等;
  3. 清理中间节点 GenerWorkerList、审核轨迹;
  4. IsBackTrack 控制是否保留中间节点业务数据;
  5. 更新 WFState = ReturnSta,写 ActionType.Return 或 ReturnAndBackWay(201)。

详见第 13 章退回规则。

9.4 移交(换司机)

9.4.1 入口
代码语言:javascript
复制
前端 Shift.vue 
  → WF_WorkOpt.Shift_Save() 
  → Dev2Interface.Node_Shift() 
  → ShiftWork.Node_Shift_ToEmp()
9.4.2 算法
  1. 校验:流程未完成、被移交人不在当前待办;
  2. 按 TodolistModel 分支:
    • 协作/队列/组长模式:删除移交人 GenerWorkerList,插入被移交人记录,重算 SDT(应完成时间);
    • 抢办模式:直接 UPDATE 或重建 GenerWorkerList;
  3. 设置 gwf.WFState = WFState.Shift;
  4. 更新 TodoEmps 字段;
  5. 写 ActionType.Shift,触发 EventListNode.ShitAfter 与消息推送。

撤销移交:ShiftWork.DoUnShift() → ActionType.UnShift(4)。

9.5 撤销(取消任务)

9.5.1 入口
代码语言:javascript
复制
前端在途列表 
  → WF.Runing_UnSend() 
  → Dev2Interface.Flow_DoUnSend() 
  → WorkUnSend.DoUnSend()
9.5.2 算法
  1. 校验 CancelRole:若为 None 则禁止撤销;
  2. 开始节点禁止撤销;
  3. 对方已读/已办时禁止(受 CancelDisWhenRead 控制);
  4. 会签状态:默认禁止(IsEnableUnSendWhenHuiQian 可放开);
  5. 查 GenerWorkerList 中 IsPass=1 的记录确定 cancelToNodeID;
  6. 按节点类型(普通/分流/合流/子流程/游离态)分别调用 DoUnSendIt()、DoUnSendFeiLiu()、DoUnSendHeiLiu_Main() 等;
  7. 恢复上一节点待办,删除后续节点数据;
  8. 写 ActionType.UnSend;
  9. 若 Track 存在 Return/ReturnAndBackWay,撤销后恢复 WFState.ReturnSta。
9.5.3 撤销规则 CancelRole

值

含义

OnlyNextStep

仅允许撤销到下一步

None

禁止撤销

NextStepAndStartNode

可撤销到下一步和开始节点

SpecNodes

可撤销到指定节点

9.6 催办(鸣笛)

9.6.1 入口
代码语言:javascript
复制
前端 Press.vue 
  → WF_WorkOpt.Press() 
  → Dev2Interface.Flow_DoPress()
9.6.2 算法
  1. 校验流程未完成且非开始节点;
  2. 查当前节点 GenerWorkerList(IsPass=0)获取待办人;
  3. 按日写入 PressWork 催办记录表(防重复:WorkID_UserNo_ToEmp_Date);
  4. Port_SendMsg(..., SMSMsgType.DoPress) 发送消息(站内信/短信/微信等);
  5. 写 ActionType.Press;
  6. 可选递归催办子流程待办人。

会签主持人催办:HuiQian_Press() 专门催办会签中的待办人。

9.7 前加签与后加签

该引擎 将"加签"与"会签"分为两套机制:

9.7.1 加签(Askfor)——单人请求协助

概念

说明

前加签

处理人先请他人协助,协助完成后由自己继续发送

后加签

处理人先发送,加签人协助后流程才到下一步

入口:WF_WorkOpt.Askfor() → Dev2Interface.Node_Askfor()

算法:

  1. 设 WFState.Askfor;
  2. 在 GenerWorkerList 为被加签人插入待办,PassInt 存储加签模式;
  3. 被加签人处理完毕后 DealAskForState() 根据 AskforHelpSta:
    • AfterDealSend(5):加签后直接发送 → 继续 NodeSend 到下一步(后加签语义);
    • AfterDealSendByWorker(6):加签后由发起人发送 → WFState.AskForReplay,待办回到发起人(前加签语义);
  4. Node_AskforReply():加签人回复后触发发送或返回。
9.7.2 会签(HuiQian)——多人同节点会签

方法

功能

Node_HuiQian_Init()

初始化会签界面数据

Node_HuiQian_AddEmps()

增加会签人(IsPass=-1)

Node_HuiQian_AddLeader()

激活组长(IsPass=-1→0)

Node_HuiQianDone()

发起会签,通知会签人

Node_HuiQian_Delete()

删除会签人

会签完成判断在 NodeSend 发送后处理中,依据 HuiQianRole、HuiQianLeaderRole、TeamLeaderConfirmRole 决定是否全员完成。

9.8 删除

9.8.1 逻辑删除

方法:WorkFlow.DoDeleteWorkFlowByFlag()

  • 设 WFState = Delete;
  • 删除 GenerWorkerList(待办不可见);
  • 保留 WF_Track 轨迹和业务主表数据;
  • 可恢复:DoUnDeleteWorkFlowByFlag()。
9.8.2 物理删除

方法:WorkFlow.DoDeleteWorkFlowByReal()

  • 删除 WF_Track、GERpt、MapDtl、各节点表单数据;
  • 删除 WF_GenerWorkFlow、WF_GenerWorkerList、WF_CCList;
  • 不可恢复。
9.8.3 写日志删除

方法:WorkFlow.DoDeleteWorkFlowByWriteLog()

  • 先插入 WorkFlowDeleteLog;
  • 再调用 DoDeleteWorkFlowByReal()。
9.8.4 删除权限 DelWorkFlowRole

值

含义

None

禁止删除

DeleteByFlag

仅逻辑删除

DeleteAndWriteToLog

写日志后物理删除

DeleteReal

直接物理删除

ByUser

由用户选择删除方式

9.9 挂起(暂停)

该引擎 中"暂停"对应 挂起(Hungup)。

方法:WorkFlow.DoHungup()

  1. 设 WFState = Hungup;
  2. 在 AtPara 记录挂起人、方式(HungupWay:永久/指定日期)、审批人;
  3. 通知除开始节点外的当前待办人;
  4. 审批人 HungupWorkAgree() 解除挂起,或 HungupWorkReject() 拒绝;
  5. 写 ActionType.Hungup(15) / UnHungup(16)。

入口:WF_WorkOpt.Hungup_Save() → Dev2Interface.Node_HungupWork()。


10 流程实例级操作

节点通用操作作用于当前节点,而流程实例级操作作用于整个流程实例,通常由管理员执行。

10.1 调整(ReSend)

定义:将运行中的流程实例跳转到指定节点、指定人员,使其在该节点产生待办。

入口:Dev2Interface.Flow_ReSend(workid, toNodeID, toEmps, note, model)

算法:

  1. 校验:流程未完成、非子线程节点、非"退回并原路返回"状态;
  2. type=1(向前跳过):Flow_ReSendBySkip()——当前待办转已办、强制结束子流程、重建目标节点待办;
  3. 否则:WorkReSend.DoIt() 按 RunModel 矩阵调整(类似退回的逆操作);
  4. 写 ActionType.Adjust(31)。

应用场景:流程发错节点、需要管理员干预跳转、跳过某些审批环节。

10.2 回滚(Rollback)

定义:将已完成的流程实例恢复到指定历史节点,使其重新进入运行状态。

入口:WF_WorkOpt.Rollback_Done() → FlowExt.DoRebackFlowData()

算法:

  1. 从 WF_Track 轨迹重建 GenerWorkFlow 和 GenerWorkerList;
  2. 恢复到指定节点,WFState = ReturnSta;
  3. 清理完成后的冗余数据;
  4. 逻辑删除恢复(DoUnDeleteWorkFlowByFlag)也调用此接口。

与退回的区别:

维度

退回

回滚

执行人

当前节点处理人

管理员

流程状态

运行中

已完成

权限

节点 ReturnRole

流程 RollbackPower

回滚权限 RollbackPower(Flow.cs):

值

含义

0

管理员

1

流程参与人

2

指定节点处理人

3

指定角色

4

指定人员

10.3 逻辑删除与物理删除

已在 9.8 节论述。实例级删除通过 WF_WorkOpt.DeleteFlowInstance_DoDelete() 入口,按 DelWorkFlowRole 分支调用不同删除方法。

10.4 小结

操作

适用状态

核心方法

可逆性

调整

运行中

Flow_ReSend()

可再次调整

回滚

已完成

DoRebackFlowData()

可再次回滚

逻辑删除

任意

DoDeleteWorkFlowByFlag()

可恢复

物理删除

任意

DoDeleteWorkFlowByReal()

不可恢复


11 节点向下运动的核心算法:5×5 发送矩阵

11.1 算法背景

该引擎 的发送引擎经历了多次演进。2012 年升级的 NodeSend_Send_5_5() 方法将发送逻辑统一为 5×5 矩阵:当前节点 RunModel(行)× 目标节点 RunModel(列),每个单元格对应一个专用发送方法。这一设计避免了为每种模式编写独立引擎,保证了撤销、退回、轨迹的一致性。

11.2 矩阵结构

该引擎 源码注释将发送逻辑称为"5×5 算法"(WorkNode.NodeSend(),2012-11-11 厦门升级),意指当前节点 5 类运行角色 × 目标节点 5 类运行角色的笛卡尔调度。其中子线程的"同表单/异表单"是同一行内的分支,而非独立行。RunModel 枚举共 6 个值(0–5),在 NodeSend_Send_5_5() 的 switch 中合并为 5 个 case 分支。

代码语言:javascript
复制
                    目标节点 RunModel
                 Ord(0)  HL(1)  FL(2)  FHL(3)  Same(4)  UnSame(5)
当前  Ordinary(0)  [11]   [11]   [11]   [11]    禁止     禁止
节点  HL(1)        [31]   [31]   [31]   [31]    禁止     禁止
RunM  FL(2)        [11]   [11]   [11]   [11]    [24_S]   [24_U]
odel  FHL(3)       [11]   [11]   禁止   [11]    [24_S]   [24_U]
      Same(4)      禁止   [53_S] 禁止   [53_S]   [11]     禁止
      UnSame(5)    禁止   [53_U] 禁止   [53_U]   禁止     [11]

注:[11] = NodeSend_11();[24_S] = NodeSend_24_SameSheet();[24_U] = NodeSend_24_UnSameSheet();[31] = NodeSend_31();[53_S/U] = 合流方法。空白/禁止格在代码中 throw Exception 提示流程设计错误。

核心源码结构(WorkNode.NodeSend_Send_5_5(),该引擎/Components/BP.WF/WF/WorkNode.cs):

代码语言:javascript
复制
switch (this.HisNode.HisRunModel)
{
    case RunModel.Ordinary:       // 行1:普通节点
        switch (toND.HisRunModel) {
            case RunModel.Ordinary: this.NodeSend_11(toND); break;
            case RunModel.SubThreadSameWorkID:
            case RunModel.SubThreadUnSameWorkID:
                throw new Exception("普通节点不能连接子线程节点");
        }
        break;
    case RunModel.FL:             // 行2:分流节点
        switch (toND2.HisRunModel) {
            case RunModel.SubThreadSameWorkID:
                NodeSend_24_SameSheet(toND2); break;
            case RunModel.SubThreadUnSameWorkID:
                NodeSend_24_UnSameSheet(toNDs); break;
        }
        break;
    case RunModel.HL:             // 行3:合流节点
        this.NodeSend_31(toND3); break;
    case RunModel.SubThreadSameWorkID:  // 行4/5:子线程
    case RunModel.SubThreadUnSameWorkID:
        if (toND5.HisRunModel == RunModel.HL)
            NodeSend_53_SameSheet_To_HeLiu(toND5);  // 或 UnSameSheet 版本
        break;
}

设计约束(源码强制校验,保证矩阵确定性):

  • 分流节点不能同时启动同表单与异表单子线程(workflow_error_4);
  • 分流节点不能同时启动多个同表单子线程(workflow_error_5);
  • 普通节点不能直接连接子线程节点(须经分流节点);
  • 合流节点不能连接子线程节点。

11.3 关键单元格详解

单元格

方法

场景

(0,0)

NodeSend_11()

线形 → 线形(最常用)

(0,4)

NodeSend_24_SameSheet()

线形 → 同表单子线程(经分流)

(2,4)

NodeSend_24_SameSheet()

分流 → 同表单子线程

(2,5)

NodeSend_24_UnSameSheet()

分流 → 异表单子线程

(4,1)

NodeSend_53_SameSheet_To_HeLiu()

同表单子线程 → 合流

(5,1)

NodeSend_53_UnSameSheet_To_HeLiu()

异表单子线程 → 合流

(1,0)

NodeSend_31()

合流 → 线形(合流后继续)

(3,*)

分合流行

分合流节点可再次分流

11.4 算法执行流程

代码语言:javascript
复制
NodeSend(jumpToNode, jumpToEmp)
│
├─ 第1部分:发送前检查
│   ├─ 权限校验
│   ├─ 状态校验(已结束/已删除/会签中)
│   ├─ 阻塞模式检查
│   └─ SendWhen 事件
│
├─ 第2部分:5×5 核心算法
│   ├─ Func_GenerNextStepNodes()  // 计算下一节点
│   ├─ 遍历下一节点集合
│   │   └─ switch(当前RunModel)
│   │       └─ switch(目标RunModel)
│   │           └─ 调用对应 NodeSend_XY() 方法
│   └─ 子流程自动启动 CallAutoSubFlow()
│
└─ 第3部分:发送后处理
    ├─ 更新 GenerWorkFlow
    ├─ 写 Track
    ├─ 多人规则(队列/协作/抢办)
    ├─ 会签完成判断
    ├─ 抄送 CC
    ├─ DTS 同步
    ├─ 消息推送
    └─ SendSuccess 事件

11.5 下一节点计算

方法:Func_GenerNextStepNodes()

  1. 查询当前节点的所有出边(WF_Direction);
  2. 对每条出边评估条件(Cond):
    • 表达式条件:解析表单字段值,执行比较;
    • SQL 条件:执行 SQL 查询,返回行数 > 0 则满足;
    • 岗位/部门条件:判断当前处理人是否匹配;
  3. 返回满足条件的下一节点集合;
  4. 若仅一个下一节点,直接发送;若多个,根据配置决定排他或并行。

11.6 接收人计算

方法:Func_GenerWorkerLists(Node toNode)

  1. 读取目标节点的 DeliveryWay(接收人规则);
  2. 按规则计算人员集合(ByStation、ByDept、BySQL、BySelected、ByDtlAsSubThreadEmps 等 20+ 种);
  3. 过滤无效人员;
  4. 返回 (EmpNo, EmpName) 列表。

11.7 算法优势

  1. 统一性:全部模式走同一入口,撤销/退回/轨迹逻辑一致;
  2. 可扩展性:新增 RunModel 只需扩展矩阵行列;
  3. 可测试性:每个单元格可独立单元测试;
  4. 可维护性:避免 if-else 堆叠,逻辑清晰。

12 多人处理规则

12.1 TodolistModel 枚举

当同一节点有多个接收人时,TodolistModel 决定他们如何协作:

值

枚举名

中文

行为

汽车类比

0

QiangBan

抢办

谁先处理谁生效,其他人待办自动消除

多人抢开一辆车

1

Teamup

协作

所有人都要处理,最后一人发送到下一步

多人轮流驾驶

2

Order

队列

按顺序处理,最后一人发送到下一步

排队驾驶

3

Sharing

共享

需申请后才能处理

需拿钥匙才能开

4

TeamupGroupLeader

协作组长

组员协作 + 组长确认

车队队长最后验收

定义位置:EnumLib.cs 第 640 行;节点属性 Node.TodolistModel(WF/Node.cs 第 2633 行)。

12.2 抢办模式(QiangBan)

行为:

  1. 为所有接收人各插入一条 GenerWorkerList(IsPass=0);
  2. 任一人发送时,将其余人 IsPass 置为 1(自动已办);
  3. 流程向下运动。

适用场景:值班审批、客服处理——谁有空谁处理。

12.3 协作模式(Teamup)

行为:

  1. 为所有接收人各插入一条 GenerWorkerList(IsPass=0);
  2. 每人发送时仅将自己的 IsPass 置为 1;
  3. 当最后一人发送时,流程才向下运动;
  4. 发送后处理中判断 IsAllPassed()。

适用场景:多部门会签、联合审批——所有人都必须发表意见。

12.4 队列模式(Order)

行为:

  1. 为所有接收人按顺序插入 GenerWorkerList,仅第一人 IsPass=0,其余 IsPass=-1(未到);
  2. 当前人发送后,下一人 IsPass 从 -1 变为 0;
  3. DealOradeNode() 方法管理队列推进;
  4. 最后一人发送时流程向下运动。

适用场景:逐级审批——必须按职级顺序处理。

12.5 共享模式(Sharing)

行为:

  1. 所有接收人可见待办,但需先"申请"才能获得处理权;
  2. 申请后其他人待办消除;
  3. 处理完毕发送。

适用场景:任务池、工单抢单。

12.6 协作组长模式(TeamupGroupLeader)

行为:

  1. 组员按协作模式处理;
  2. 组长通过 TeamLeaderConfirmRole 计算;
  3. 组长最后确认后流程向下运动。

12.7 会签机制(HuiQian)

会签是协作模式的扩展,通过 HuiQianRole 控制:

HuiQianRole

含义

Teamup(1)

协作会签

TeamupGroupLeader(4)

组长会签

组长会签规则 HuiQianLeaderRole:

值

含义

OnlyOne

仅一个组长

LastOneMain

最后一个组长为主持人

EveryOneMain

每人都可以是主持人

12.8 多人规则在操作中的体现

操作

抢办

协作

队列

发送

一人发送即可

最后一人发送

按序发送

退回

标准退回

TeamReturnRole 控制

DoOrderReturn()

移交

UPDATE 单人

替换 GenerWorkerList

替换当前队列项

撤销

标准撤销

协作节点特殊处理

恢复队列状态


13 退回规则

13.1 ReturnRole 枚举

每个节点可配置 ReturnRole,决定处理人可以退回到哪些历史节点:

值

枚举名

中文

行为

0

CanNotReturn

不能退回

该节点禁止退回操作

1

ReturnPreviousNode

仅上一节点

只能退回到直接前驱节点

2

ReturnAnyNodes

任意历史节点

可退回到任何已处理过的节点(默认)

3

ReturnSpecifiedNodes

指定节点

仅可退回到配置的节点列表

4

ReturnStartNode

退到开始节点

只能退回到流程开始节点

5

ByReturnLine

按退回线

由流程图上标注的退回方向决定

定义位置:EnumLib.cs 第 1250 行;计算可退节点:Dev2Interface.DB_GenerWillReturnNodes(workid)。

13.2 可退节点计算

方法:DB_GenerWillReturnNodes(workid)

  1. 读取当前节点的 ReturnRole;
  2. 按规则查询 WF_GenerWorkerList 历史记录;
  3. 分流/合流节点特殊处理:直接查 GenerWorkerList 而非按 ReturnRole;
  4. 返回可退节点列表供前端展示。

13.3 退回执行矩阵

WorkReturn.DoIt() 按 当前 RunModel × 目标 RunModel 矩阵调用执行方法:

方法

场景

ExeReturn1_1()

线形 → 线形

ExeReturn2_4()

分流 → 同表单子线程

ExeReturn3_2()

合流 → 分流

ExeReturn3_4()

合流 → 同表单子线程

ExeReturn5_2()

同表单子线程 → 分流

DoItOfKillEtcThread()

子线程退分流且杀死其他子线程

ReturnToParentFlow()

跨流程退回到父流程

DoOrderReturn()

队列/协作模式专用退回

13.4 退回并原路返回

ActionType:ReturnAndBackWay(201)

行为:

  1. 退回到目标节点后,处理人重新处理;
  2. 处理完毕后,流程自动按原路径返回到退回前的节点;
  3. 在 GenerWorkFlow.AtPara 中记录返回路径;
  4. 适用于"退回到发起人修改后直接回到当前审批人"的场景。

13.5 分合流退回特殊规则

场景

规则

子线程退分流

可选 IsKillEtcThread:是否终止其他子线程

合流退子线程

需清理 ThreadCount

分流节点

不按 ReturnRole 算,直接查 GenerWorkerList

协作节点

TeamReturnRole==1 时走 DoOrderReturn()

13.6 退回与撤销的协同

  • 若流程经退回后发送,再撤销:撤销会恢复到 WFState.ReturnSta;
  • 若 Track 存在 ReturnAndBackWay,撤销后保留原路返回标记;
  • 退回后的业务数据处理受 IsBackTrack 控制。

13.7 前端实现

环节

文件

说明

退回页面

ReturnWork.vue

展示可退节点列表

初始化

WF_WorkOpt.Return_Init()

调用 DB_GenerWillReturnNodes

执行

WF_WorkOpt.DoReturnWork()

调用 Node_ReturnWork

异表单

ReturnWork.vue

RunModel=4/5 时显示 IsKillEtcThread 选项


14 案例研究与实验验证

14.1 案例一:采购申请(同表单分合流)

业务描述:采购员提交采购申请,系统按明细表行自动分派给各采购专员并行询价,全部完成后汇总到采购主管处合流审批。

配置要点:

节点

RunModel

关键属性

开始

Ordinary

—

采购员提交

Ordinary

—

分流

FL(2)

DeliveryWay=ByDtlAsSubThreadEmps

专员询价×N

SubThreadSameWorkID(4)

共享主表

主管合流

HL(1)

PassRate=100

结束

Ordinary

—

验证步骤:

  1. 提交含 3 行明细的采购申请;
  2. 验证生成 3 个子线程,各专员待办正确;
  3. 专员 1、2 完成,合流未触发;
  4. 专员 3 完成,合流触发,主管待办出现;
  5. 查 WF_Track 轨迹含 ForwardFL 和 ForwardHL。

14.2 案例二:项目立项(异表单分合流)

业务描述:项目经理提交立项申请(主表单),系统自动分流到法务、财务、技术三方,各方填写独立评审表单,完成后合流汇总到总经理审批。

配置要点:

节点

RunModel

关键属性

开始

Ordinary

—

项目经理提交

Ordinary

主表单 Frm_Project

分流

FL(2)

出边 3 条,分别连向 3 个子线程

法务评审

SubThreadUnSameWorkID(5)

绑定 Frm_LegalReview

财务评审

SubThreadUnSameWorkID(5)

绑定 Frm_FinanceReview

技术评审

SubThreadUnSameWorkID(5)

绑定 Frm_TechReview

总经理合流

HL(1)

PassRate=100,合流从表 IsHLDtl=true

结束

Ordinary

—

数据流:

  1. 干流程 WorkID=W0,FID=0,主表 Frm_Project 的 OID=W0;
  2. 分流后生成 3 个子线程:W1(FID=W0)、W2(FID=W0)、W3(FID=W0),各自绑定不同物理表;
  3. 法务填写 Frm_LegalReview,财务填写 Frm_FinanceReview,互不干扰;
  4. 三方完成后 ThreadCount 递增至 3,触发合流;
  5. NodeSend_53_UnSameSheet_To_HeLiu() 将各子表单关键字段汇总到主表合流从表;
  6. 总经理在主表单看到三方评审摘要后审批。

验证步骤:

  1. 提交立项申请,验证 3 个子线程待办分别出现在法务/财务/技术人员待办列表;
  2. 验证各子线程打开的是不同表单(非同一 PTable);
  3. 仅完成 2 个子线程时,总经理无待办;
  4. 第 3 个子线程完成后,总经理待办出现;
  5. 查 WF_Track 含 3 条 SubThreadForward 与 1 条 ForwardHL;
  6. 测试退回:子线程退分流时勾选 IsKillEtcThread,验证其余子线程被终止。

14.3 案例三:合同审批调用法务子流程(父子流程)

业务描述:合同审批流程到达"法务审核"节点时自动启动法务子流程;子流程独立走完法务审批链后,反填合同审批单字段并自动驱动父流程到下一节点。

配置要点:

配置项

值

说明

父流程节点

NodeType.SubFlowNode

六边形子流程节点

子流程类型

AutoSubFlow(1)

节点发送时自动触发

子流程模式

SubLevel

PWorkID 指向父 WorkID

启动时机

InvokeTime = 发送后

CallAutoSubFlow()

全部结束规则

SendParentFlowToNextStep

子流程全结束后自动发送父流程

字段反填

BackCopyRole

子流程"法务意见"→父流程"法务审核意见"

待办隐藏

SubFlowHidTodolist=true

父节点 IsPass=80,待办不可见

生命周期:

  1. 业务员在父流程"合同审批"节点点击发送;
  2. NodeSend_Send_5_5() 正常发送后,触发 CallAutoSubFlow();
  3. 创建子流程实例 W_sub,PWorkID=W_parent,PFlowNo=合同审批,PNodeID=法务审核节点;
  4. 父流程当前处理人待办设为不可见(IsPass=80);
  5. 法务人员在子流程中完成多级审批;
  6. SubFlowOver_SendParentFlowToNextStep() 检测全部子流程结束;
  7. 执行字段反填,恢复父流程待办,自动 NodeSend 到下一节点;
  8. 轨迹记录 ActionType.StartChildenFlow(10) 与 CallChildenFlow(9)。

验证步骤:

  1. 父流程发送到法务节点,验证子流程自动创建且 PWorkID 正确;
  2. 验证父流程发起人在此期间待办不可见(在途可查进度);
  3. 子流程完成后,验证父流程字段被反填;
  4. 验证父流程自动流转到下一节点(如"总经理审批");
  5. 测试催办:Flow_DoPress(workID, msg, isPressSubFlow=true) 可递归催办子流程待办人。

14.4 案例四:请假审批(线形流程 + 多人规则组合)

业务描述:员工提交请假申请,部门经理与 HR 按队列模式逐级审批,最后由分管领导协作会签后归档。全程为线形流程,无分合流。

配置要点:

节点

RunModel

TodolistModel

说明

开始

Ordinary

—

员工填写

部门经理

Ordinary

Order(2)

若多人则按职级队列

HR 审批

Ordinary

QiangBan(0)

多人抢办,谁先处理谁生效

分管领导

Ordinary

Teamup(1)

协作会签,全员完成后发送

结束

Ordinary

—

归档

验证要点:

  1. 队列节点验证 IsPass=-1(未到)与顺序激活;
  2. 抢办节点验证一人发送后他人待办自动消除;
  3. 协作节点验证最后一人发送才触发 NodeSend_11();
  4. 退回测试:ReturnRole=ReturnPreviousNode,部门经理退回后员工修改再提交。

14.5 通用操作验证矩阵

操作

线形

同表单分合流

异表单分合流

父子流程

发送

✓

✓

✓

✓

退回

✓

✓

✓

✓

移交

✓

✓

✓

✓

撤销

✓

✓

✓

✓

催办

✓

✓

✓

✓

加签

✓

✓

✓

—

挂起

✓

✓

✓

✓

调整

✓

✓

✓

—

回滚

✓

✓

✓

✓


15 结论与展望

15.1 主要结论

  1. 四大模式构成最小完备集:线形流程、同表单分合流、异表单分合流、父子流程分别从顺序执行、同构并行、异构并行、跨流程编排四个维度覆盖了流程应用环境的主要结构需求,且可正交组合。
  2. 统一发送引擎保证一致性:该引擎 以 RunModel 枚举和 5×5 发送矩阵统一调度全部模式,使得发送、退回、撤销、轨迹、待办查询共用一套基础设施。
  3. 三元关联键语义清晰:WorkID 标识实例,FID 承载分合流关系,PWorkID 承载父子流程关系,三者正交。
  4. 汽车类比模型降低认知门槛:将流程引擎、表单引擎、业务数据分别类比为控制系统、车厢、货物,将通用操作类比为驾驶行为。
  5. 通用操作与多人/退回规则协同:发送、退回、移交等操作均考虑 TodolistModel 与 ReturnRole,保证复杂场景下行为一致。
  6. 前后端一致映射:Vue3 设计器通过 RunModel 形状模板实现设计态可视化,运行态由后端 PageName 动态路由。

15.2 未来工作

  1. 模式自动识别与流程检查增强;
  2. BPMN 2.0 导入导出映射;
  3. 基于 AI 的流程模式推荐;
  4. 5×5 发送矩阵的形式化验证;
  5. 微服务架构下的分布式扩展。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 1 引言
    • 1.1 研究背景
    • 1.2 研究问题
    • 1.3 主要贡献
    • 1.3.1 与既有理论的区别
    • 1.4 论文结构
  • 2 相关工作
    • 2.1 工作流理论与 Workflow Patterns
    • 2.2 开源流程引擎对比
    • 2.3 本文定位
  • 3 系统总体架构与汽车类比模型
    • 3.1 分层架构
    • 3.2 汽车类比模型
    • 3.3 核心数据模型
      • 3.3.1 流程定义层
      • 3.3.2 流程实例层
      • 3.3.3 三种关联键
    • 3.4 节点运行模式枚举 RunModel
  • 4 模式一:线形流程
    • 4.1 模式定义
    • 4.2 适用场景
    • 4.3 运行时语义
    • 4.4 方向条件(左拐/右拐)
    • 4.5 前端实现
    • 4.6 小结
  • 5 模式二:同表单分合流
    • 5.1 模式定义
    • 5.2 适用场景
    • 5.3 数据模型
    • 5.4 核心算法
      • 5.4.1 分流启动子线程
      • 5.4.2 子线程到达合流
      • 5.4.3 合流通过率 PassRate
    • 5.5 运行时管理
    • 5.6 前端实现
    • 5.7 撤销与退回
    • 5.8 小结
  • 6 模式三:异表单分合流
    • 6.1 模式定义
    • 6.2 适用场景
    • 6.3 与同表单的核心差异
    • 6.4 USSWorkIDRole:异表单 WorkID 生成规则
    • 6.5 核心算法
      • 6.5.1 分流启动
      • 6.5.2 合流汇总
    • 6.6 设计约束
    • 6.7 前端实现
    • 6.8 小结
  • 7 模式四:父子流程
    • 7.1 模式定义
    • 7.2 子流程类型
    • 7.3 子流程模式
    • 7.4 典型拓扑
    • 7.5 核心算法
      • 7.5.1 建立父子关系
      • 7.5.2 手动启动
      • 7.5.3 自动启动
      • 7.5.4 子流程全部结束后的父流程处理
    • 7.6 前端实现
    • 7.7 小结
  • 8 四大模式的覆盖性论证
    • 8.1 正交性与可组合性
    • 8.2 需求覆盖表
    • 8.3 "涵盖流程应用环境各个方面"的论证
    • 8.4 局限性
  • 9 节点通用操作
    • 9.1 操作总览
    • 9.2 发送(前进)
      • 9.2.1 入口与调用链
      • 9.2.2 三阶段处理
    • 9.3 退回(后退)
      • 9.3.1 入口
      • 9.3.2 算法概要
    • 9.4 移交(换司机)
      • 9.4.1 入口
      • 9.4.2 算法
    • 9.5 撤销(取消任务)
      • 9.5.1 入口
      • 9.5.2 算法
      • 9.5.3 撤销规则 CancelRole
    • 9.6 催办(鸣笛)
      • 9.6.1 入口
      • 9.6.2 算法
    • 9.7 前加签与后加签
      • 9.7.1 加签(Askfor)——单人请求协助
      • 9.7.2 会签(HuiQian)——多人同节点会签
    • 9.8 删除
      • 9.8.1 逻辑删除
      • 9.8.2 物理删除
      • 9.8.3 写日志删除
      • 9.8.4 删除权限 DelWorkFlowRole
    • 9.9 挂起(暂停)
  • 10 流程实例级操作
    • 10.1 调整(ReSend)
    • 10.2 回滚(Rollback)
    • 10.3 逻辑删除与物理删除
    • 10.4 小结
  • 11 节点向下运动的核心算法:5×5 发送矩阵
    • 11.1 算法背景
    • 11.2 矩阵结构
    • 11.3 关键单元格详解
    • 11.4 算法执行流程
    • 11.5 下一节点计算
    • 11.6 接收人计算
    • 11.7 算法优势
  • 12 多人处理规则
    • 12.1 TodolistModel 枚举
    • 12.2 抢办模式(QiangBan)
    • 12.3 协作模式(Teamup)
    • 12.4 队列模式(Order)
    • 12.5 共享模式(Sharing)
    • 12.6 协作组长模式(TeamupGroupLeader)
    • 12.7 会签机制(HuiQian)
    • 12.8 多人规则在操作中的体现
  • 13 退回规则
    • 13.1 ReturnRole 枚举
    • 13.2 可退节点计算
    • 13.3 退回执行矩阵
    • 13.4 退回并原路返回
    • 13.5 分合流退回特殊规则
    • 13.6 退回与撤销的协同
    • 13.7 前端实现
  • 14 案例研究与实验验证
    • 14.1 案例一:采购申请(同表单分合流)
    • 14.2 案例二:项目立项(异表单分合流)
    • 14.3 案例三:合同审批调用法务子流程(父子流程)
    • 14.4 案例四:请假审批(线形流程 + 多人规则组合)
    • 14.5 通用操作验证矩阵
  • 15 结论与展望
    • 15.1 主要结论
    • 15.2 未来工作
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档