驰骋 BPM(CCFlow/JFlow)四大运行模式与 Flowable/Camunda 技术对比

驰骋 BPM(CCFlow/JFlow)四大运行模式与 Flowable/Camunda 技术对比

一、概述

1.1 驰骋 BPM 的产品定位

驰骋 BPM 由 CCFlow(.NET)JFlow(Java) 双平台构成,是一套流程引擎 + 表单引擎 + 低代码平台的一体化 BPM 产品。与 Flowable/Camunda 这类"纯流程引擎"不同,驰骋在引擎之上内置了组织架构、菜单权限、单据(CCBill)、门户、报表等完整企业应用能力。

代码中通过 Platform 枚举区分运行平台:

295:305:CCFlow/Components/BP.WF/EnumLib.cs 复制代码
    public enum Platform
    {
        /// <summary>
        /// CCFlow .net平台.
        /// </summary>
        CCFlow,
        /// <summary>
        /// JFlow java 平台.
        /// </summary>
        JFlow
    }

1.2 两个维度的"模式"概念(勿混淆)

维度 配置项 含义
部署/组织模式 CCBPMRunModel(0/1/2/3) 单机、集团、SaaS、平台应用
产品使用模式 门户/Middleware vs BPM 中间件模式 vs 全功能 BPM 模式

门户说明(Vue3/src/Portal/readme.txt):

  • 中间件模式:客户仅使用流程引擎 + 表单引擎,菜单精简(发起、待办、在途、草稿等)。
  • BPM 模式:完整菜单体系、权限管理、低代码设计器,可构建独立业务系统。

本文重点分析 四大运行模式(CCBPMRunModel) 的技术实现,并与 Flowable/Camunda 的多租户/组织架构能力对照。


二、四大运行模式定义与配置

2.1 枚举与配置入口

后端枚举定义(BP.Sys.CCBPMRunModel):

12:30:CCFlow/Components/BP.En30/Sys/EnumLab.cs 复制代码
    public enum CCBPMRunModel
    {
        /// <summary>
        /// 单机版
        /// </summary>
        Single,
        /// <summary>
        /// 集团模式
        /// </summary>
        GroupInc,
        /// <summary>
        /// 多租户模式
        /// </summary>
        SAAS,
        /// <summary>
        /// 平台应用模式
        /// </summary>
        PASS
    }

app.config 配置项:

xml 复制代码
<!-- 0=单组织,1=集团,2=SAAS,3=平台应用(PASS) -->
<add key="CCBPMRunModel" value="0"/>
模式 英文标识 典型场景
0 单机版 Single 单一企业、内网 OA、POC 演示
1 集团版 GroupInc 集团总部 + 多家子公司共用一套 BPM
2 多租户 SaaS SAAS 云 BPM 平台,租户数据强隔离
3 平台应用 PASS 云平台上的应用托管模式(CCBPMRunModelReal 识别,部分逻辑仍回落到 Single)

2.2 安装初始化差异

安装时按模式加载不同组织种子数据 SQL:

337:355:CCFlow/Components/BP.WF/Install.cs 复制代码
            sqlscript = BP.Difference.SystemConfig.CCFlowAppPath + "WF/Data/Install/SQLScript/Port_Inc_CH_RunModel_" + (int)SystemConfig.CCBPMRunModel + ".sql";
            DBAccess.RunSQLScript(sqlscript);

            if (SystemConfig.CCBPMRunModel == CCBPMRunModel.Single)
            {
                BP.Port.Emp empAdmin = new Emp("admin");
                BP.Web.WebUser.SignInOfGener(empAdmin);
            }

            if (SystemConfig.CCBPMRunModel == CCBPMRunModel.SAAS)
            {
                BP.WF.Dev2Interface.Port_Login("admin", "100", null);
            }

            if (SystemConfig.CCBPMRunModel == CCBPMRunModel.GroupInc)
            {
                BP.WF.Dev2Interface.Port_Login("admin", "100", null);
            }
  • Single :直接以 admin 登录,无多组织概念。
  • GroupInc / SAAS :以平台组织 100admin 登录,需选择/切换组织。

三、四大模式技术实现对比

3.1 单机版(Single)

核心特征 :无 OrgNo 数据隔离,人员编号全局唯一(如 zhangsan)。

后端实现要点

  • SystemConfig.CCBPMRunModel == Single 时,SQL 查询不加 OrgNo 条件。
  • WebUser.RootNo 对管理员返回 "0",表示无组织根节点概念。
  • 待办统计、流程查询等直接按 FK_Emp 过滤。
52:53:CCFlow/Components/BP.WF/Dev2Interface.cs 复制代码
                if (BP.Difference.SystemConfig.CCBPMRunModel == CCBPMRunModel.SAAS)
                    wfSql = " AND A.OrgNo='" + WebUser.OrgNo + "'";

(Single 模式下 wfSql 为空,不加 OrgNo 过滤。)

前端实现要点

  • SystemConfig.CCBPMRunModel 来自 Cookie/LocalStorage。
  • 人员选择、表单树、流程树等 SQL 数据源使用 Single 后缀 的全局查询(见 GloWF.ts*Single 系列 SFTable)。
  • 中间件门户不展示集团专属菜单(如"管理组织"、"切换部门")。

对比 Flowable/Camunda :等价于单租户部署 ,不启用 tenantId。组织架构需自行对接 IDM 或在应用层维护。


3.2 集团版(GroupInc)

核心特征 :一套 BPM 实例服务多个法人/子公司,通过 Port_Org + OrgNo 字段实现逻辑隔离,人员编号在组织内唯一。

数据模型Port_Inc_CH_RunModel_1.sql 种子数据):

  • Port_Org:组织主表(如 100 集团平台、ccs 驰骋公司、quanyi 泉亿公司)。
  • Port_DeptPort_StationPort_Emp 均带 OrgNo 字段。
  • 人员 No 在组织内唯一(如 yuwen),跨组织可重复。

后端隔离机制

  1. 查询过滤 :非 Single 模式在流程、人员、部门查询中追加 OrgNo 条件。
  2. 组织管理员Port_OrgAdminer 表维护二级管理员;WebUser.IsAdminOrgNo 判断。
  3. 集团岗责体系GroupStationModel 配置):
    • 0:每套组织独立角色体系(默认)。
    • 1:全集团共享一套岗责体系。
    • 2:每个部门独立角色体系。
924:934:CCFlow/Components/BP.En30/Difference/SystemConfig.cs 复制代码
        /// <summary>
        /// 集团模式下的角色体系
        /// @0=每套组织都有自己的角色体系@1=所有的组织共享一套岗则体系.@2=每个部门有自己的角色体系.
        /// </summary>
        public static int GroupStationModel
  1. 找人算法FindWorker.cs):按直属领导找人时,GroupInc 追加 And OrgNo = '@WebUser.OrgNo'
338:343:CCFlow/Components/BP.WF/Template/FindWorker.cs 复制代码
                        if (BP.Difference.SystemConfig.CCBPMRunModel == CCBPMRunModel.Single)
                            sql = "SELECT Leader,FK_Dept FROM Port_Emp WHERE No='" + empNo + "'";
                        if (BP.Difference.SystemConfig.CCBPMRunModel == CCBPMRunModel.GroupInc)
                            sql = "SELECT Leader,FK_Dept FROM Port_Emp WHERE No='" + empNo + "' And OrgNo = '" + WebUser.OrgNo + "'";
                        if (BP.Difference.SystemConfig.CCBPMRunModel == CCBPMRunModel.SAAS)
                            sql = "SELECT Leader,FK_Dept FROM Port_Emp WHERE No='" + WebUser.OrgNo + "_" + empNo + "'";

前端实现要点

  • 集团版用户菜单增加"管理组织(AdminOnly)"、"切换部门"(PopMenuUser.ts)。
  • 流程查询、单据搜索在 GroupInc 下追加组织过滤(SearchFlow.vueuseSearchBill.ts)。
  • 菜单、表单树按 OrgNo 隔离:OrgNo='@WebUser.OrgNo'

对比 Flowable/Camunda

能力 驰骋 GroupInc Flowable Camunda
多组织 Port_Org + OrgNo 字段贯穿全表 需自建或借助 Flowable Platform Camunda 8 有 Tenant 概念
组织切换 内置 Port_Login(user, orgNo) 无内置 Tenant 切换需自行实现
流程定义隔离 WF_Flow 可按组织复制/共享 tenantId 隔离部署 tenantId 隔离
岗责体系 内置 Port_Station,支持三种集团策略 候选组 candidateGroups candidateGroups / Identity Service

驰骋集团版的优势在于组织、岗责、流程、表单在同一产品内闭环;Flowable/Camunda 需额外集成 Identity/Org 模块。


3.3 多租户 SaaS 版(SAAS)

核心特征 :面向云 BPM 平台,租户间强隔离 ,人员主键采用 {OrgNo}_{UserID} 复合编号。

与集团版的关键差异

项目 GroupInc SAAS
人员编号 组织内唯一,如 yuwen 全局唯一,如 ccs_yuwen
UserID 字段 可选 必须,存真实登录名
流程实例 部分表加 OrgNo WF_GenerWorkFlow 等强制 OrgNo
登录 选组织后登录 Port_Login("admin", "100", null) 平台管理员

后端实现Emp.cs):

106:130:CCFlow/Components/BP.En30/Port/Emp.cs 复制代码
                    if (value.StartsWith(BP.Web.WebUser.OrgNo + "_") == true)
                    {
                        this.SetValByKey(EmpAttr.UserID, value.Replace(BP.Web.WebUser.OrgNo + "_", ""));
                    }
                    else
                    {
                        this.SetValByKey(EmpAttr.No, BP.Web.WebUser.OrgNo + "_" + value);
                    }

SAAS 模式下实体 Map 自动注入隐藏条件 OrgNo = @WebUser.OrgNoStation.csTeam.cs 等)。

流程统计统一追加 OrgNo:

4680:4688:CCFlow/Components/BP.WF/Dev2Interface.cs 复制代码
        public static String Check_CCBPMRunModel()
        {
            String sql = "";
            if (BP.Difference.SystemConfig.CCBPMRunModel == CCBPMRunModel.SAAS)
            {
                sql += " AND A.OrgNo = '" + WebUser.OrgNo + "'";
            }
            return sql;
        }

前端实现要点

  • WebUser.CCBPMRunModel == 2 时,审核组件走云 Handler:BP.Cloud.HttpHandler.App
  • 用户头像路径含 OrgNo 前缀。
  • 数据源 SQL 使用 *SaaS 后缀版本,按 OrgNo 过滤。

对比 Flowable/Camunda

  • Flowable :企业版支持 Multi-tenancy(tenantId 贯穿引擎表);开源版需应用层隔离。
  • Camunda 8:原生多租户(Tenant),与 Zeebe 集群集成。
  • 驰骋 SAAS :租户隔离下沉到全产品线(组织、表单、流程、单据、菜单),不仅是引擎表隔离。

驰骋 SaaS 的不足:OrgNo 多以 SQL 字符串拼接实现隔离,需严格防范 SQL 注入;Flowable/Camunda 的 tenantId 在引擎层有框架级保障。


3.4 平台应用模式(PASS)

核心特征 :面向云平台应用商店/托管 场景,枚举值为 3CCBPMRunModelReal 返回 PASS,但 CCBPMRunModel 属性将 03 均映射为 Single 以兼容旧逻辑。

215:250:CCFlow/Components/BP.En30/Difference/SystemConfig.cs 复制代码
        public static CCBPMRunModel CCBPMRunModelReal
        {
            get
            {
                int val = BP.Difference.SystemConfig.GetValByKeyInt("CCBPMRunModel", 0);
                if (val == 0 ) return CCBPMRunModel.Single;
                if (val == 1) return CCBPMRunModel.GroupInc;
                if (val == 2) return CCBPMRunModel.SAAS;
                return CCBPMRunModel.PASS;
            }
        }
        public static CCBPMRunModel CCBPMRunModel
        {
            get
            {
                int val = BP.Difference.SystemConfig.GetValByKeyInt("CCBPMRunModel", 0);
                if (val == 0 || val==3) return CCBPMRunModel.Single;
                ...
            }
        }

PASS 模式在代码库中落地较少,前端 SystemConfig.ts 甚至未导出 PASS 枚举,属于演进中的模式,与 SaaS 云平台的应用分发场景配套。

对比 Flowable/Camunda :类似 Camunda SaaS 或 Flowable Cloud 的应用市场 + 租户双层模型,但驰骋 PASS 尚未形成与 Flowable Platform 同量级的独立产品线文档。


四、架构对照:驰骋 BPM vs Flowable/Camunda

4.1 总体架构图

#mermaid-svg-vaGClo6KyGNibhR3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vaGClo6KyGNibhR3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vaGClo6KyGNibhR3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vaGClo6KyGNibhR3 .error-icon{fill:#552222;}#mermaid-svg-vaGClo6KyGNibhR3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vaGClo6KyGNibhR3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vaGClo6KyGNibhR3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vaGClo6KyGNibhR3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vaGClo6KyGNibhR3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vaGClo6KyGNibhR3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vaGClo6KyGNibhR3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vaGClo6KyGNibhR3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vaGClo6KyGNibhR3 .marker.cross{stroke:#333333;}#mermaid-svg-vaGClo6KyGNibhR3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vaGClo6KyGNibhR3 p{margin:0;}#mermaid-svg-vaGClo6KyGNibhR3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vaGClo6KyGNibhR3 .cluster-label text{fill:#333;}#mermaid-svg-vaGClo6KyGNibhR3 .cluster-label span{color:#333;}#mermaid-svg-vaGClo6KyGNibhR3 .cluster-label span p{background-color:transparent;}#mermaid-svg-vaGClo6KyGNibhR3 .label text,#mermaid-svg-vaGClo6KyGNibhR3 span{fill:#333;color:#333;}#mermaid-svg-vaGClo6KyGNibhR3 .node rect,#mermaid-svg-vaGClo6KyGNibhR3 .node circle,#mermaid-svg-vaGClo6KyGNibhR3 .node ellipse,#mermaid-svg-vaGClo6KyGNibhR3 .node polygon,#mermaid-svg-vaGClo6KyGNibhR3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vaGClo6KyGNibhR3 .rough-node .label text,#mermaid-svg-vaGClo6KyGNibhR3 .node .label text,#mermaid-svg-vaGClo6KyGNibhR3 .image-shape .label,#mermaid-svg-vaGClo6KyGNibhR3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-vaGClo6KyGNibhR3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vaGClo6KyGNibhR3 .rough-node .label,#mermaid-svg-vaGClo6KyGNibhR3 .node .label,#mermaid-svg-vaGClo6KyGNibhR3 .image-shape .label,#mermaid-svg-vaGClo6KyGNibhR3 .icon-shape .label{text-align:center;}#mermaid-svg-vaGClo6KyGNibhR3 .node.clickable{cursor:pointer;}#mermaid-svg-vaGClo6KyGNibhR3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vaGClo6KyGNibhR3 .arrowheadPath{fill:#333333;}#mermaid-svg-vaGClo6KyGNibhR3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vaGClo6KyGNibhR3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vaGClo6KyGNibhR3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vaGClo6KyGNibhR3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vaGClo6KyGNibhR3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vaGClo6KyGNibhR3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vaGClo6KyGNibhR3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vaGClo6KyGNibhR3 .cluster text{fill:#333;}#mermaid-svg-vaGClo6KyGNibhR3 .cluster span{color:#333;}#mermaid-svg-vaGClo6KyGNibhR3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vaGClo6KyGNibhR3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vaGClo6KyGNibhR3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-vaGClo6KyGNibhR3 .icon-shape,#mermaid-svg-vaGClo6KyGNibhR3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vaGClo6KyGNibhR3 .icon-shape p,#mermaid-svg-vaGClo6KyGNibhR3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vaGClo6KyGNibhR3 .icon-shape .label rect,#mermaid-svg-vaGClo6KyGNibhR3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vaGClo6KyGNibhR3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vaGClo6KyGNibhR3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vaGClo6KyGNibhR3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 数据库
后端 CCFlow (.NET) / JFlow (Java)
前端 Vue3
Portal 门户

Middleware / BPM
WF 流程模块
CCFast 低代码
Toolkit SDK
HttpHandler.ts
APIController / InnerForVueController
HttpHandler WF_*
Dev2Interface SDK
WorkNode 流程引擎
Port 组织架构
Sys_MapData 表单引擎
CCBill 单据引擎
WF_Flow / WF_Node 流程定义
WF_GenerWorkFlow 流程实例
WF_GenerWorkerList 待办任务
Port_* 组织人员
#mermaid-svg-PyAwlIcTdwmtix8a{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PyAwlIcTdwmtix8a .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PyAwlIcTdwmtix8a .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PyAwlIcTdwmtix8a .error-icon{fill:#552222;}#mermaid-svg-PyAwlIcTdwmtix8a .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PyAwlIcTdwmtix8a .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PyAwlIcTdwmtix8a .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PyAwlIcTdwmtix8a .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PyAwlIcTdwmtix8a .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PyAwlIcTdwmtix8a .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PyAwlIcTdwmtix8a .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PyAwlIcTdwmtix8a .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PyAwlIcTdwmtix8a .marker.cross{stroke:#333333;}#mermaid-svg-PyAwlIcTdwmtix8a svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PyAwlIcTdwmtix8a p{margin:0;}#mermaid-svg-PyAwlIcTdwmtix8a .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PyAwlIcTdwmtix8a .cluster-label text{fill:#333;}#mermaid-svg-PyAwlIcTdwmtix8a .cluster-label span{color:#333;}#mermaid-svg-PyAwlIcTdwmtix8a .cluster-label span p{background-color:transparent;}#mermaid-svg-PyAwlIcTdwmtix8a .label text,#mermaid-svg-PyAwlIcTdwmtix8a span{fill:#333;color:#333;}#mermaid-svg-PyAwlIcTdwmtix8a .node rect,#mermaid-svg-PyAwlIcTdwmtix8a .node circle,#mermaid-svg-PyAwlIcTdwmtix8a .node ellipse,#mermaid-svg-PyAwlIcTdwmtix8a .node polygon,#mermaid-svg-PyAwlIcTdwmtix8a .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PyAwlIcTdwmtix8a .rough-node .label text,#mermaid-svg-PyAwlIcTdwmtix8a .node .label text,#mermaid-svg-PyAwlIcTdwmtix8a .image-shape .label,#mermaid-svg-PyAwlIcTdwmtix8a .icon-shape .label{text-anchor:middle;}#mermaid-svg-PyAwlIcTdwmtix8a .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PyAwlIcTdwmtix8a .rough-node .label,#mermaid-svg-PyAwlIcTdwmtix8a .node .label,#mermaid-svg-PyAwlIcTdwmtix8a .image-shape .label,#mermaid-svg-PyAwlIcTdwmtix8a .icon-shape .label{text-align:center;}#mermaid-svg-PyAwlIcTdwmtix8a .node.clickable{cursor:pointer;}#mermaid-svg-PyAwlIcTdwmtix8a .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PyAwlIcTdwmtix8a .arrowheadPath{fill:#333333;}#mermaid-svg-PyAwlIcTdwmtix8a .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PyAwlIcTdwmtix8a .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PyAwlIcTdwmtix8a .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PyAwlIcTdwmtix8a .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PyAwlIcTdwmtix8a .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PyAwlIcTdwmtix8a .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PyAwlIcTdwmtix8a .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PyAwlIcTdwmtix8a .cluster text{fill:#333;}#mermaid-svg-PyAwlIcTdwmtix8a .cluster span{color:#333;}#mermaid-svg-PyAwlIcTdwmtix8a div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PyAwlIcTdwmtix8a .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PyAwlIcTdwmtix8a rect.text{fill:none;stroke-width:0;}#mermaid-svg-PyAwlIcTdwmtix8a .icon-shape,#mermaid-svg-PyAwlIcTdwmtix8a .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PyAwlIcTdwmtix8a .icon-shape p,#mermaid-svg-PyAwlIcTdwmtix8a .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PyAwlIcTdwmtix8a .icon-shape .label rect,#mermaid-svg-PyAwlIcTdwmtix8a .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PyAwlIcTdwmtix8a .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PyAwlIcTdwmtix8a .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PyAwlIcTdwmtix8a :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 引擎表
Flowable / Camunda
REST API
RuntimeService
TaskService
HistoryService
RepositoryService
BPMN 2.0 引擎
IdentityService / 外部 IDM
ACT_RE_PROCDEF
ACT_RU_EXECUTION
ACT_RU_TASK
ACT_HI_* 历史表

4.2 核心概念映射表

驰骋 BPM 数据表/类 Flowable/Camunda 说明
流程定义 WF_Flow + WF_Node + WF_Direction ACT_RE_PROCDEF(BPMN XML) 驰骋用关系表存节点;Flowable 用 BPMN 标准
流程实例 GenerWorkFlow / WF_GenerWorkFlow ACT_RU_EXECUTION / ACT_HI_PROCINST 驰骋一张宽表承载实例状态
待办任务 GenerWorkerList / WF_GenerWorkerList ACT_RU_TASK 驰骋 IsPass 标识任务状态
流程发送 WorkNode.NodeSend() TaskService.complete() 驰骋"发送"=审批驱动流转
人员分配 FindWorker + DeliveryWay 枚举 Candidate Users/Groups 驰骋内置 20+ 找人策略
二次开发 API Dev2Interface 静态方法 RuntimeService 命名规范:Flow_*/Node_*/Port_*
Web 接口 HttpHandlerWF_MyFlow 等) REST Controller 前后端通过 Handler 类名 + 方法名路由
事件扩展 ExecEvent.DoNode() ExecutionListener/TaskListener 支持 Java/C# 反射 + JS 脚本
表单 Sys_MapData 内置表单引擎 无(需集成 Form.io 等) 驰骋核心差异化能力
租户 OrgNo + CCBPMRunModel tenantId 隔离层级与范围不同

4.3 流程执行核心路径

驰骋流程发送(WorkNode.NodeSend)三阶段:

  1. 发送前检查:权限、表单校验、条件判断。
  2. 5×5 算法:按节点运行模式(普通/分流/合流/子线程)处理路由。
  3. 发送后业务:抄送、子流程、事件、数据汇总。
7606:7614:CCFlow/Components/BP.WF/WF/WorkNode.cs 复制代码
        /// 工作流发送业务处理.
        /// ----------------------------------- 说明 -----------------------------
        /// 1,方法体分为三大部分: 发送前检查\5*5算法\发送后的业务处理.
        /// 2, 详细请参考代码体上的说明.
        /// 3, 发送后可以直接获取它的

Flowable/Camunda 则基于 BPMN Token 推进模型,由引擎解析 BPMN 图自动流转,扩展点主要为 Listener、Delegate、External Task。

4.4 BPMN 支持

驰骋原生建模 使用自研流程设计器(节点表驱动),同时提供 BPMN 2.0 导入能力:

549:595:CCFlow/Components/BP.WF/HttpHandler/WF_Admin_AttrFlow.cs 复制代码
        /// 导入bpmn2.0
        public string Imp_DoneBPMN()
        ...
            Flow flow = BP.WF.Template.TemplateGlo.NewFlowByBPMN(FK_FlowSort, filePath);

BPMN 导入后转换为 WF_Node 关系数据,不是 以 BPMN XML 作为运行时定义。Flowable/Camunda 则以 BPMN XML 为唯一真相源(SSOT)


五、前端代码结构梳理

5.1 技术栈

  • 框架:Vue 3 + Vite + TypeScript + Ant Design Vue
  • 包管理:pnpm monorepo(turbo)
  • 通信HttpHandler 类封装后端 Handler 调用

5.2 目录结构与职责

目录 职责 与运行模式关系
Vue3/src/Portal/ 登录、门户;Middleware(中间件)与 Standard 两套入口 中间件模式精简菜单
Vue3/src/WF/ 流程发起、待办、设计器、报表 核心流程 UI
Vue3/src/CCFast/ 低代码:GPM 菜单权限、CCBill 单据、门户窗口 BPM 模式主战场
Vue3/src/Toolkit/ 可嵌入第三方系统的流程 SDK(WorkOpt、WorkCheck) 中间件集成场景
Vue3/src/bp/ 前端 ORM 层(Entity、EnMap),镜像后端 BP.En30 按模式切换 SQL 数据源
Vue3/src/App/ 行业/客户定制应用(LIMS、Star 等) 客户项目层

5.3 前后端通信机制

typescript 复制代码
// Vue3/src/utils/gener/HttpHandler.ts
const handler = new HttpHandler('BP.WF.HttpHandler.WF_MyFlow');
handler.AddPara('WorkID', workID);
const data = await handler.DoMethod('MyFlow_Init');

请求路由至后端 WF_CommAPIController,通过反射调用 BP.WF.HttpHandler.* 类方法。这与 Flowable 的 /runtime/process-instances RESTful 风格截然不同,更接近 RPC over HTTP

5.4 运行模式在前端的分支模式

前端通过 SystemConfig.CCBPMRunModel / WebUser.CCBPMRunModel 在以下场景分支:

  1. 数据源 SQLGloWF.ts*Single vs 带 OrgNo 的查询。
  2. 权限菜单StationMenu.ts 非 Single 时隐藏 OrgNo 条件。
  3. 审核组件:SAAS 模式切换云 Handler 与头像路径。
  4. 集团菜单PopMenuUser.ts 注入组织管理入口。

六、后端代码结构梳理

6.1 项目模块

项目 路径 职责
CCFlow CCFlow/CCFlow/ ASP.NET Core 宿主、API Controller、配置
BP.WF CCFlow/Components/BP.WF/ 流程引擎核心(WorkNode、Dev2Interface、HttpHandler)
BP.En30 CCFlow/Components/BP.En30/ 实体框架、组织架构(Port)、SystemConfig
BP.App / BP.Trade CCFlow/Components/ 行业扩展

6.2 流程引擎分层

复制代码
HttpHandler (WF_MyFlow, WF_WorkOpt, WF_Comm...)
    ↓
Dev2Interface (对外 SDK:Flow_*, Node_*, Port_*, DB_*)
    ↓
WorkNode.NodeSend() / WorkUnSend / FindWorker
    ↓
GenerWorkFlow / GenerWorkerList (持久化)
    ↓
WF_GenerWorkFlow / WF_GenerWorkerList (数据库)

6.3 组织架构与四大模式切点

四大模式的差异不集中在一个类,而是散落在:

  • BP.En30.Port.*:Emp/Dept/Station/Team 的 Map 隐藏条件。
  • BP.WF.Template.FindWorker:找人 SQL 按模式切换。
  • BP.WF.Dev2Interface:待办/在途统计 SQL 追加 OrgNo。
  • BP.WF.Data.DA.SQLPort / SQLFrm:报表 SQL 模板分支。
  • BP.WF.Install:安装脚本与初始登录。

6.4 对外 API

  • RESTCCFlow/DataUser/API/Controllers/APIController.csWF/APIController/{Action}
  • Vue 专用InnerForVueController.cs
  • SDKDev2Interface 静态类(代码集成首选)

Flowable/Camunda 提供标准 REST + Java Client;驰骋额外提供 HttpHandler 协议Dev2Interface 两套集成面。


七、优势与不足分析

7.1 驰骋 BPM 优势

维度 说明
产品完整性 流程 + 表单 + 组织 + 权限 + 单据 + 门户 + 报表,一套交付
四大模式开箱即用 单机→集团→SaaS 升级路径清晰,无需自研多租户
中国式流程特性 分流/合流/会签/加签/子线程/退回策略等原生支持
找人规则丰富 DeliveryWay 20+ 策略(直属领导、部门负责人、WebAPI 等)
低代码能力 表单设计器、单据(CCBill)、EnMap 实体、GPM 菜单权限
双语言栈 CCFlow(.NET) / JFlow(Java) 同源架构,适配不同技术栈甲方
中间件 + BPM 双模式 可嵌入 ERP,也可独立建站
BPMN 导入 支持从 Flowable 等工具导入 BPMN(单向)

7.2 驰骋 BPM 不足

维度 说明
非 BPMN 原生运行时 流程定义存关系表,与 BPMN 生态互操作性弱
标准开放度 无 DMN/CMMN 标准实现;API 非 RESTful 标准
引擎与业务耦合 OrgNo 隔离散落各处,升级引擎需全量回归
PASS 模式不成熟 枚举存在但前后端支持不完整
云原生架构 单体 + DB 为主,无内置 K8s Operator / 水平扩展方案
社区与生态 相比 Flowable/Camunda 国际社区,插件、咨询、人才池较小
SaaS 安全 部分 OrgNo 过滤为字符串拼接,需审计

7.3 Flowable/Camunda 优势

维度 说明
BPMN 2.0 标准 模型可交换、工具链成熟(Camunda Modeler 等)
引擎纯粹 专注流程执行,易嵌入微服务
扩展机制标准 Listener、Delegate、Connector、External Task
云原生 Camunda 8 + Zeebe 支持分布式、高吞吐
社区活跃 文档、案例、Spring Boot Starter 丰富
多租户 Flowable Platform / Camunda Tenant 引擎级支持

7.4 Flowable/Camunda 不足(相对驰骋)

维度 说明
无内置表单引擎 需集成自研或第三方表单
无内置组织权限 Identity 简陋,企业级需 Keycloak 等
中国式 OA 特性 会签、加签、退回等需大量自定义
交付周期长 从引擎到可用 OA 需拼装多个系统
许可成本 企业版多租户、高级特性需商业许可

八、如何选择工作流引擎------决策指南

8.1 决策树

复制代码
是否需要完整 BPM/OA 产品(表单+组织+权限)?
├── 是 → 驰骋 BPM 优先考虑
│   ├── 仅嵌入现有系统 → 中间件模式 + Dev2Interface/Toolkit SDK
│   └── 独立业务系统 → BPM 模式 + 四大运行模式选型
└── 否 → 仅需流程引擎
    ├── 强依赖 BPMN 标准 / 微服务编排 → Flowable 或 Camunda
    ├── 超高吞吐、云原生 → Camunda 8 (Zeebe)
    └── Spring 生态、国内案例多 → Flowable

8.2 四大运行模式选型

场景 推荐模式 理由
单一企业 OA Single 配置简单,无 OrgNo 开销
集团多法人 GroupInc 内置组织切换、岗责策略
云 BPM 平台 SAAS 人员编号隔离、全链路 OrgNo
应用商店托管 PASS(待成熟) 关注后续版本支持

8.3 场景对照表

场景 推荐 关键原因
政府/国企 OA 全系统 驰骋 BPM 表单+流程+组织一体,国产化 .NET/Java
电商订单履约编排 Camunda 8 高并发、事件驱动、微服务
银行核心流程(强审计) Flowable + 自研表单 BPMN 标准、成熟案例
ERP 内嵌审批流 驰骋中间件模式Flowable 前者中国式特性强;后者 BPMN 标准
多租户 SaaS OA 驰骋 SAASFlowable Platform 前者开箱即用;后者引擎级租户
流程即代码、GitOps Camunda BPMN XML 版本化管理
快速 POC / 低预算 驰骋 Single 安装即用,Demo 数据齐全

8.4 综合结论

  1. 选驰骋 BPM :需要"流程 + 表单 + 组织 + 低代码"一体化交付;面向中国政府/企业 OA、集团化、SaaS 运维;团队熟悉 .NET 或 Java 驰骋栈;重视中国式审批特性。

  2. 选 Flowable :Spring 技术栈;需要 BPMN 标准 与现有 BPMN 资产互通;流程编排是核心、表单组织已有系统;可接受较长集成周期。

  3. 选 Camunda :微服务/云原生架构;高吞吐流程编排;需要 DMN 决策表;国际化团队与标准化治理。

  4. 混合策略 :以 Flowable/Camunda 作编排引擎 ,驰骋表单/组织作业务层------技术上可行(驰骋支持 BPMN 导入),但需评估双向同步成本,一般不建议双引擎并行。


九、附录:关键代码索引

主题 文件路径
运行模式枚举 CCFlow/Components/BP.En30/Sys/EnumLab.cs
运行模式配置 CCFlow/Components/BP.En30/Difference/SystemConfig.cs
安装初始化 CCFlow/Components/BP.WF/Install.cs
集团种子数据 CCFlow/CCFlow/WF/Data/Install/SQLScript/Port_Inc_CH_RunModel_1.sql
SaaS 种子数据 CCFlow/CCFlow/WF/Data/Install/SQLScript/Port_Inc_CH_RunModel_2.sql
流程实例 CCFlow/Components/BP.WF/WF/GenerWorkFlow.cs
待办任务 CCFlow/Components/BP.WF/WF/GenerWorkerList.cs
流程发送引擎 CCFlow/Components/BP.WF/WF/WorkNode.cs
对外 SDK CCFlow/Components/BP.WF/Dev2Interface.cs
找人算法 CCFlow/Components/BP.WF/Template/FindWorker.cs
事件机制 CCFlow/Components/BP.WF/WF/ExecEvent.cs
REST API CCFlow/CCFlow/DataUser/API/Controllers/APIController.cs
前端模式枚举 Vue3/src/bp/difference/SystemConfig.ts
前端通信 Vue3/src/utils/gener/HttpHandler.ts
门户模式说明 Vue3/src/Portal/readme.txt
中间件菜单 Vue3/src/Portal/Middleware/Sysmenu.vue

十、参考文献


本文基于 CCFlowWorkSpace 仓库源码静态分析生成,PASS 模式及 JFlow 侧实现以 CCFlow 为准,生产部署请以官方文档与版本发布说明为准。

相关推荐
OA之道2 天前
OA 实施教程 | 第7集:详解数据字典与流水号配置,规范表单录入与单据编号
工作流·oa·oa办公系统·oa实施
imkaifan4 天前
工作流(Worker/Graph)配置对象如何解读、子图
javascript·工作流·(worker/graph)·配置对象如何解读·子图
Irissgwe6 天前
十、LangGraph能力详解:工作流的常见模式
python·langchain·ai编程·工作流·langgraph
nap-joker6 天前
使用n8n+飞书搭建自动推送新闻机器人
javascript·json·飞书·工作流·n8n·36氪新闻向客户端推送
jiayong236 天前
AI工作流实现原理深度解析
人工智能·comfyui·工作流·coze
jiayong2310 天前
AI工作流系统全景概述
人工智能·工作流·coze
SuniaWang11 天前
《AgentX 专栏》08-工作流引擎:AgentWorkflow怎么把工具记忆流程串成一条流水线
java·ai·架构·langchain·工作流引擎·langgraph·agent架构
深念Y12 天前
多 Agent 对证循环协作架构:Hermes + Claude Code + Codex 三角色工作流实战
ai·工作流·codex·vibecoding·claudecode·skills·hermes
空空潍12 天前
使用Coze工作流API实现结构化输出
json·工作流·coze