驰骋BPM组织结构设计技术报告

驰骋低代码 BPM 组织结构设计 — 技术报告

文档版本:2026-06
章节编号:3.1
依据代码:CCFlow/Components/BP.En30/Port(组织实体)、CCFlow/Components/BP.WF/Port/OrganizationAPI.cs(同步接口)、CCFlow/Components/BP.WF/Template/FindWorker.cs(流程选人引擎)
说明:本文基于源码静态分析撰写,用于技术分享与方案论证,力求准确描述设计思想并客观分析优劣。


一、为什么组织结构设计如此重要

1.1 基本定义

组织结构是指:系统运行要依赖的人员、部门、角色,以及人员与部门、角色之间的对应关系。

在驰骋 BPM(CCBPM)中,这一概念直接落地为 Port_* 系列数据表,实体类统一归属 BP.Port 命名空间。流程引擎的节点接收人规则、表单权限、组织隔离、待办推送等能力,均以这套结构为数据底座。

1.2 组织结构是应用系统的基石

组织结构不仅是 BPM 的专属需求,更是整个应用系统的基础,也是权限管理的基本条件

依赖方典型场景
工作流引擎按"部门 + 角色"计算下一节点处理人
权限体系按部门、岗位控制菜单、数据范围
低代码平台组织树选人、按组织隔离应用与流程
第三方集成HR/OA 主数据向 BPM 同步或映射

若组织模型与业务语义不匹配,轻则集成成本陡增,重则流程"找不到人"、权限穿透或数据串租户——这类问题在生产环境中极难补救。

1.3 业界设计的困境

每个架构师对组织结构的理解、应用方向、部署环境各不相同,导致表结构设计千差万别

  • 有的系统只有「用户—部门」二元关系,角色挂在用户上,无法表达"同一人不同部门担任不同岗位";
  • 有的把角色做成全局属性,忽略"财务部经理"与"市场部经理"虽同为"经理"但权责不同的现实;
  • 有的为追求范式化拆出十几张表,集成时映射成本极高;
  • 有的为图省事把部门、岗位、人员揉进一张宽表,无法支撑树形部门与多组织隔离。

核心矛盾:模型太简单则无法覆盖政企复杂场景;模型太复杂则难以与存量 HR/OA 系统对接。究竟哪种设计能覆盖绝大多数场景? 这是本报告要回答的问题。

1.4 驰骋的命题

驰骋结合十余年 BPM 交付与组织结构集成经验,提出一套经过大量项目验证的五表核心模型。其目标不是学术上的"最范式化",而是:

用尽可能少的表,表达尽可能完整的组织语义,并让整个工作流引擎能用一条 SQL 完成"按部门+角色找人"。


二、驰骋五表核心模型

2.1 五表总览

#表名实体类职责
1Port_DeptDept部门树
2Port_EmpEmp人员主档
3Port_StationStation角色(岗位)
4Port_DeptEmpDeptEmp部门—人员(支持兼职)
5Port_DeptEmpStationDeptEmpStation部门—角色—人员(三要素绑定)

另有扩展表 Port_StationType(角色分类)、Port_Org / Port_OrgAdminer(多组织管理)等,服务于集团/SAAS 模式,不改变五表核心语义。

2.2 实体关系

ParentNo 树形

FK_Dept 主部门

FK_Dept

FK_Emp

FK_StationType

FK_Dept

FK_Emp

FK_Station

Port_Dept

Port_Emp

Port_DeptEmp

Port_StationType

Port_Station

Port_DeptEmpStation

2.3 各表设计要点(代码印证)

Port_Dept — 部门
                Map map = new Map("Port_Dept", "部门");
                map.ItIsEnableVer = true;

                map.AddTBStringPK(DeptAttr.No, null, "编号", true, false, 1, 50, 20);
                map.AddTBString(DeptAttr.Name, null, "名称", true, false, 0, 100, 30);
                map.AddTBString(DeptAttr.NameOfPath, null, "部门路径", true, false, 0, 100, 30);

                map.AddTBString(DeptAttr.ParentNo, null, "父节点编号", true, true, 0, 100, 30);
                map.AddTBString(DeptAttr.OrgNo, null, "OrgNo", true, true, 0, 50, 30);
                map.AddTBString(DeptAttr.Leader, null, "部门领导", true, true,0,50,100);
  • 树形结构:ParentNo 自关联,NameOfPath 冗余全路径以加速展示与检索。
  • Leader 存部门领导登录账号(非中文名),直接支撑"找部门负责人"类流程规则。
  • OrgNo 在集团/SAAS 模式下做组织隔离。
Port_Emp — 人员
                map.AddTBStringPK(EmpAttr.No, null, "编号", true, false, 1, 50, 30);
                //如果是集团模式或者是SAAS模式.
                if (BP.Difference.SystemConfig.CCBPMRunModel == CCBPMRunModel.SAAS)
                    map.AddTBString(EmpAttr.UserID, null, "用户ID", true, false, 0, 50, 30);

                map.AddTBString(EmpAttr.Name, null, "名称", true, false, 0, 200, 30);
                map.AddTBString(EmpAttr.PinYin, null, "拼音", false, false, 0, 200, 30);
                map.AddDDLEntities(EmpAttr.FK_Dept, null, "部门", new BP.Port.Depts(), false);
                map.AddTBString(EmpAttr.Tel, null, "手机号", false, false, 0, 20, 20);
                map.AddTBString(EmpAttr.Email, null, "邮箱", false, false, 0, 50, 50);
                map.AddTBString(EmpAttr.Leader, null, "直属部门领导", false, false, 0, 20, 130);
                map.SetHelperAlert(EmpAttr.Leader, "这里是领导的登录帐号,不是中文名字,用于流程的接受人规则中。");
                map.AddTBString(EmpAttr.LeaderName, null, "领导名", true, true, 0, 20, 130);
                map.AddTBString(EmpAttr.OrgNo, null, "组织编号", true, true, 0, 50, 50);
  • FK_Dept 表示主部门,满足"此人默认归属哪里"的高频查询。
  • SAAS 模式下 UserIDNo组织编号_UserID)分离,允许跨租户账号重复。
  • Leader 字段支撑"找直属领导"规则,与部门领导字段语义区分清晰。
Port_Station — 角色
                Map map = new Map("Port_Station", "角色");
               // map.setCodeStruct("3");
              //  map.setIsAutoGenerNo(true);

                map.AddTBStringPK(StationAttr.No, null, "编号", true, true, 1, 50, 200);
                map.AddTBString(StationAttr.Name, null, "名称", true, false, 0, 100, 200);
                map.AddDDLEntities(StationAttr.FK_StationType, null, "类型", new StationTypes(), true);
                map.AddTBString(StationAttr.OrgNo, null, "隶属组织", false, false, 0, 50, 250);
  • 角色是岗位抽象(如"部门经理"“出纳”),不直接绑定人员。
  • 通过 FK_StationType 分类,便于流程设计器按类型筛选。
  • 集团模式下可通过 GroupStationModel 配置为"组织级角色"或"部门级角色"。
Port_DeptEmp — 部门人员(兼职)
                Map map = new Map("Port_DeptEmp", "部门人员信息");
                map.IndexField = DeptEmpAttr.FK_Dept;

                map.AddMyPK();
                map.AddTBString(DeptEmpAttr.FK_Dept, null, "部门", false, false, 1, 50, 1);
                map.AddDDLEntities(DeptEmpAttr.FK_Emp, null, "操作员", new BP.Port.Emps(), false);
                map.AddTBString(DeptEmpAttr.OrgNo, null, "组织编码", false, false, 0, 50, 50);
  • 主键 MyPK = FK_Dept + "_" + FK_Emp,一人可挂多个部门。
  • 删除时级联清理该人员在该部门下的 Port_DeptEmpStation 记录,保证数据一致性。
Port_DeptEmpStation — 三要素绑定(设计灵魂)
                Map map = new Map("Port_DeptEmpStation", "部门角色人员对应");

                map.AddTBStringPK("MyPK", null, "主键MyPK", false, true, 1, 150, 10);
                map.AddTBString(DeptEmpStationAttr.FK_Dept, null, "部门", true, true, 1, 100, 1);
                map.AddTBString(DeptEmpStationAttr.FK_Station, null, "角色", true, true, 1, 50, 1);
                map.AddTBString(DeptEmpStationAttr.FK_Emp, null, "操作员", true, true, 1, 100, 1);
                map.AddTBString(DeptEmpAttr.OrgNo, null, "组织编码", true, true, 0, 50, 50);
  • 主键 MyPK = FK_Dept + "_" + FK_Emp + "_" + FK_Station
  • 语义:张三在财务部担任出纳,与张三在市场部担任经理是两条独立记录。
  • 这是整个 BPM 选人引擎的核心查询表。

三、设计思想:为什么是五表

3.1 主部门 + 兼职部门的双轨模型

驰骋没有强迫所有关系都走关联表,而是采用双轨策略:

场景使用表原因
默认部门、快速查人Port_Emp.FK_Dept单表查询,性能最优
一人多部门(兼职)Port_DeptEmp不破坏主部门字段的简洁性
部门内岗位绑定Port_DeptEmpStation角色必须带部门上下文

这避免了"所有关系都塞进关联表"导致的性能问题,也避免了"只在用户表上挂一个部门字段"无法表达兼职的局限。

3.2 角色必须带部门上下文

这是驰骋方案与许多简易 OA 的根本分歧

简易方案常把角色直接挂在人员上(User.Role = 经理),但现实中:

  • 张三在 A 部门是部门经理(可审批本部门费用);
  • 张三在 B 部门是普通员工(只能提交申请)。

若角色不绑定部门,流程引擎无法区分"找 A 部门的经理"与"找 B 部门的经理"。

驰骋用 Port_DeptEmpStation部门 × 角色 × 人员 三维绑定,使语义与政企编制管理一致。

3.3 流程引擎的直接受益

FindWorker.cs 中大量接收人规则最终归结为对 Port_DeptEmpStation 的查询。例如"按角色智能计算"的核心 SQL:

                string sql1 = "SELECT FK_Emp FROM Port_DeptEmpStation WHERE FK_Station='" + stas + "' AND FK_Dept='" + depts + "' ";// + sqlEnd;
                return DBAccess.RunSQLReturnTable(sql1);

BP.Port.Glo 中的公共选人方法同样依赖此表:

            string sql = "SELECT B.No,B.Name FROM Port_DeptEmpStation A,Port_Emp B  WHERE A.FK_Station IN (" + GenerWhereInSQL(stationNos) + ") AND A.FK_Dept IN (" + BP.Port.Glo.GenerWhereInSQL(deptNos) + ") AND A.FK_Emp=B.No";

人员是否拥有某角色,也通过此表判断:

        public bool HaveStation(string stationNo)
        {
            string sql = "SELECT COUNT(FK_Emp) AS Num FROM Port_DeptEmpStation WHERE FK_Emp='" + this.No + "' AND FK_Station='" + stationNo + "'";
            if (DBAccess.RunSQLReturnValInt(sql) == 0)
                return false;
            return true;
        }

设计结论:五表不是"数据库教科书式"的拆表,而是让引擎能用简单 SQL 表达复杂组织语义的最小闭包。


四、与常见设计方案对比

4.1 三种典型路线

方案C:重度 RBAC

User

UserRole

Role

RolePermission

Permission

UserDept

Dept

方案B:驰骋五表

Emp

Dept

DeptEmp

DeptEmpStation

Station

方案A:极简二元

User

Dept

维度方案A:用户—部门方案B:驰骋五表方案C:重度 RBAC
表数量2~35(核心)8~15+
兼职部门不支持或 hack原生支持需额外建模
部门上下文角色不支持原生支持需 RoleScope 扩展
BPM 选人 SQL 复杂度高(需业务层拼装)低(单表/双表 JOIN)高(多表 JOIN + 范围判断)
与 HR 主数据映射简单但不完整中等,语义对齐复杂,概念不对等
权限细粒度中(角色+部门)强(资源级 ACL)
集成维护成本

4.2 为什么不选"角色直接挂用户"

许多系统采用 UserStation(用户—角色)二元关联。其缺陷在 BPM 场景下会被放大:

  1. 无法表达"同一人不同部门不同岗位"——政企兼职极常见;
  2. 流程按部门找人时语义模糊——"财务部经理"究竟指哪个部门;
  3. 集成时需大量业务规则补偿——在应用层判断"当前流程实例部门"再过滤角色。

驰骋在数据模型层一次性解决,使引擎逻辑保持简洁、可测试、可审计。

4.3 为什么不选"十几张表的完整 IAM"

完整身份与访问管理(IAM)模型适合统一身份平台,但对 BPM 集成而言往往过度设计

  • HR 系统通常提供的是部门、人员、岗位,而非 Permission、Resource、Policy;
  • 映射链路过长,任一环节不一致即导致"流程找不到人";
  • 运维人员难以理解"为什么这个人有角色但流程选不到"。

驰骋五表在表达能力集成友好度之间取了工程上的平衡点。


五、优劣分析

5.1 优势

优势说明
语义贴近政企编制部门树 + 岗位 + 兼职,与真实组织管理一致,业务人员易理解
BPM 原生适配FindWorker 引擎直接查询 Port_DeptEmpStation,无需应用层翻译
集成面收敛视图/接口集成都只需对齐五表,文档与 API 边界清晰
多组织可扩展通过 OrgNo 字段贯通五表,单组织到 SAAS 无需改模型
双轨性能主部门走 Port_Emp.FK_Dept 快速查询,复杂关系走关联表
级联一致性DeptEmp 删除自动清理 DeptEmpStation,减少脏数据
经大量项目验证OrganizationAPI 提供完整增删改同步能力,降低对接风险

5.2 局限与应对

局限影响驰骋的应对
五表同步成本外部 HR 需维护 DeptEmp + DeptEmpStation提供 Port_Emp_Save 一次调用写入三表;推荐视图模式合并库
角色非全局"全公司总监"类岗位需特殊处理可用虚拟部门、或按组织根部门绑定角色
冗余字段NameOfPath、DeptEmp 中 Vue3 辅助列换取查询性能与前端展示便利
复合主键MyPK 拼接规则在 SAAS 下有变体统一由实体 beforeUpdateInsertAction 生成,集成时调用 API 即可
非完整 IAM不支持资源级 ACL、动态策略权限场景由应用系统承担;BPM 聚焦流程选人
标签/用户组非核心Port_Team 系列为辅助不影响五表主模型,按需启用

5.3 客观评价

驰骋五表模型不是万能的组织架构,而是为 BPM 工作流场景优化的最小完备集

  • 若您的核心需求是"复杂审批流按部门岗位找人、支持兼职、支持多组织",五表方案高度匹配
  • 若您的核心需求是"细粒度资源权限、零信任策略、跨系统联邦身份",应在五表之上叠加专业 IAM,而非替换五表;
  • 若您的组织极简单(无兼职、无多岗位),五表略显"重",但集成接口与视图模式使额外成本可控,且为未来业务扩展留有余地。

六、多组织运行模式

五表模型通过 CCBPMRunModel 配置项支持三种运行模式,无需修改表结构:

模式组织特征
0单组织OrgNo 隔离,一个 admin 管理全部
1集团组织多独立组织,OrgNo 隔离;用户账号全局唯一;可共享流程
2SAAS多租户;账号可跨租户重复;Emp.UserID + Emp.No 双字段

扩展表 Port_OrgPort_OrgAdminer 在集团/SAAS 模式下管理组织生命周期与管理员权限,与五表通过 OrgNo 松耦合。


七、集成实践:两种模式

驰骋提供两种组织结构集成路径,均围绕五表展开:

7.1 视图模式(推荐)

删除 CCBPM 侧五张物理表,创建同结构视图,将业务库组织数据映射过来。优势:

  • 单一数据源,无同步延迟;
  • 业务系统改组织,BPM 即时生效;
  • 维护成本最低。

7.2 接口模式(数据同步)

通过 OrganizationAPI 在组织变更时主动同步。核心接口:

接口作用
Port_Org_Save同步组织及主管理员
Port_Dept_Save / Port_Dept_Delete同步部门
Port_Emp_Save / Port_Emp_Delete同步人员及部门角色关系
Port_Station_Save / Port_Station_Delete同步角色

Port_Emp_Save 的实现体现了五表联动逻辑——一次调用完成 Port_EmpPort_DeptEmpPort_DeptEmpStation 的写入:

                //插入部门.
                BP.Port.DeptEmp de = new BP.Port.DeptEmp();
                de.MyPK = de.DeptNo + "_" + userNo;
                //更新角色.
                if (stats == null)
                    stats = "";
                string[] strs = stats.Split(',');
                // ...
                    DeptEmpStation des = new DeptEmpStation();
                    des.DeptNo = deptNo;
                    des.EmpNo = userNo;
                    des.StationNo = str;
                    des.OrgNo = orgNo;
                    des.MyPK = de.DeptNo + "_" + des.EmpNo + "_" + des.StationNo;
                    des.DirectInsert();

集成建议

  • 数据库可合并 → 优先视图模式;
  • 数据库必须分离 → 接口模式,一人多部门时每个部门各调用一次 Port_Emp_Save

八、总结

8.1 设计命题回顾

#命题驰骋的回答
1组织结构是什么人员、部门、角色及其对应关系
2为何重要应用系统基础,权限与流程的前提
3为何设计千差万别场景、环境、理解差异导致模型分化
4哪种设计覆盖大多数场景五表核心模型,经大量政企项目验证
5五表是什么Dept、Emp、Station、DeptEmp、DeptEmpStation
6优劣如何流程语义完备、集成面收敛;非完整 IAM,同步需规范
7如何落地视图模式或 OrganizationAPI,按部署条件选择

8.2 一句话概括

驰骋 BPM 用五张表把"谁在哪个部门担任什么角色"这一政企最核心的组织语义数据结构化了,使整个工作流引擎能用简洁 SQL 完成复杂选人——这是多年集成经验沉淀下的工程选择,而非纸上谈兵。

8.3 延伸阅读


本文档由驰骋 BPM 技术团队基于源码分析编写,转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驰骋低代码、工作流、表单引擎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值