news 2026/9/27 1:04:39

别再硬编码了!用两张表搞定OA多级审批(附加班申请完整SQL与事务处理)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再硬编码了!用两张表搞定OA多级审批(附加班申请完整SQL与事务处理)

通用审批引擎设计:用两张表实现企业级OA多级审批系统

当企业OA系统需要处理数十种不同类型的审批流程时,传统为每种表单单独开发审批逻辑的方式会带来巨大的维护成本。本文将介绍一种基于"审批主表+明细表"的通用审批引擎设计方案,通过松耦合的架构实现审批流程的复用,大幅降低开发复杂度。

1. 核心设计理念与表结构

1.1 为什么需要通用审批引擎

在传统OA系统中,每种审批表单(如请假、报销、采购等)通常都有自己独立的审批流程实现。这种方式会导致:

  • 代码重复:相似的审批逻辑在不同表单中重复实现
  • 维护困难:审批规则变更需要在多处修改
  • 扩展性差:新增审批类型需要从头开发

通用审批引擎通过将审批流程抽象为独立模块,实现与具体业务表单的解耦,提供统一的审批处理机制。

1.2 核心表结构设计

只需两张核心表即可支撑整个审批系统:

审批主表(AuditFlow)

字段名类型描述
FlowNoVARCHAR(50)审批编号(主键)
TitleNVARCHAR(50)审批标题
BusTypeVARCHAR(20)业务类型标识
AddUserNoVARCHAR(50)申请人
AddTimeDATETIME申请时间
ApproStatusINT审批状态

审批明细表(AuditFlowDetail)

字段名类型描述
IDINT自增主键
FlowNoVARCHAR(50)关联审批编号
AuditUserNoVARCHAR(50)审批人
AuditRemarkNVARCHAR(500)审批意见
AuditTimeDATETIME审批时间
AuditStatusINT审批状态

这种设计的关键在于:

  • 通过BusType字段区分不同业务类型
  • 通过FlowNo关联业务表与审批流程
  • 状态字段使用枚举值表示不同审批阶段

2. 审批流程的状态机设计

2.1 状态定义与流转

审批流程本质上是一个状态机,核心状态包括:

  • 待审:流程刚创建,等待第一级审批
  • 审批中:部分审批人已通过,流程继续
  • 通过:所有审批人同意
  • 驳回:任一审批人拒绝
  • 撤销:申请人主动撤回

状态流转规则:

stateDiagram-v2 [*] --> 待审 待审 --> 审批中: 第一级通过 审批中 --> 审批中: 中间级通过 审批中 --> 通过: 最后一级通过 待审 --> 驳回: 第一级拒绝 审批中 --> 驳回: 任一级拒绝 待审 --> 撤销: 申请人撤回 审批中 --> 撤销: 申请人撤回

2.2 多级审批的实现逻辑

明细表中的记录顺序决定了审批层级。处理逻辑如下:

  1. 创建审批流程时,按审批顺序插入明细记录
  2. 第一级审批人的状态设为"待我审批",后续设为"审核中"
  3. 当前审批人通过后:
    • 如果还有下一级,将下一级状态改为"待我审批"
    • 如果是最后一级,将主表状态改为"通过"
  4. 任一审批人拒绝时,立即终止流程,主表状态改为"驳回"

3. 与业务表的集成方案

3.1 松耦合设计模式

业务表只需包含FlowNo字段即可接入审批系统:

CREATE TABLE OverTimeAsk ( FlowNo VARCHAR(50) PRIMARY KEY, AddUserNo VARCHAR(20) NOT NULL, AddTime DATETIME NOT NULL, AskReason NVARCHAR(50) NOT NULL, -- 其他业务字段... FOREIGN KEY (FlowNo) REFERENCES AuditFlow(FlowNo) );

集成步骤:

  1. 业务表提交时生成唯一FlowNo
  2. 向AuditFlow插入主记录,BusType设为业务标识
  3. 向AuditFlowDetail插入审批人记录
  4. 业务表记录通过FlowNo关联审批流程

3.2 事务处理示例

以下是一个完整的加班申请提交事务处理SQL示例:

BEGIN TRANSACTION; DECLARE @FlowNo VARCHAR(50) = '2023050112300001'; DECLARE @BusType VARCHAR(20) = 'OverTimeAsk'; -- 插入业务表 INSERT INTO OverTimeAsk (FlowNo, AddUserNo, AddTime, AskReason, LeaveTimeFrom, LeaveTimeTo) VALUES (@FlowNo, 'U1001', GETDATE(), '项目紧急上线', '2023-05-01 19:00', '2023-05-01 22:00'); -- 插入审批主表 INSERT INTO AuditFlow (FlowNo, Title, BusType, AddUserNo, AddTime, ApproStatus) VALUES (@FlowNo, '张XX的加班申请', @BusType, 'U1001', GETDATE(), 1); -- 插入审批明细表(三级审批) INSERT INTO AuditFlowDetail (FlowNo, AuditUserNo, AuditStatus) VALUES (@FlowNo, 'U2001', 2), -- 主管(待我审批) (@FlowNo, 'U2002', 1), -- 部门经理(审核中) (@FlowNo, 'U2003', 1); -- 总监(审核中) COMMIT TRANSACTION;

注意:实际应用中应考虑添加异常处理和事务回滚逻辑。

4. 高级功能与优化建议

4.1 动态审批人配置

可以通过额外表实现审批人的动态配置:

审批配置表(AuditConfig)

字段名类型描述
IDINT自增主键
BusTypeVARCHAR(20)业务类型
DeptNoVARCHAR(20)部门编号
RoleNoVARCHAR(20)角色编号
AuditLevelINT审批层级

获取审批人逻辑:

-- 根据业务类型和申请人部门获取审批流程 SELECT ac.AuditLevel, ur.UserNo FROM AuditConfig ac JOIN UserRole ur ON ac.RoleNo = ur.RoleNo AND ac.DeptNo = ur.DeptNo WHERE ac.BusType = 'OverTimeAsk' ORDER BY ac.AuditLevel;

4.2 性能优化策略

  1. 索引优化:

    CREATE INDEX IX_AuditFlow_Status ON AuditFlow(ApproStatus); CREATE INDEX IX_AuditFlowDetail_FlowNo ON AuditFlowDetail(FlowNo); CREATE INDEX IX_AuditFlowDetail_UserStatus ON AuditFlowDetail(AuditUserNo, AuditStatus);
  2. 查询优化:

    • 分页查询待审批列表
    • 使用JOIN替代子查询
    • 考虑使用视图简化常用查询
  3. 缓存策略:

    • 缓存常用审批配置
    • 缓存审批人信息
    • 考虑使用Redis缓存进行状态跟踪

4.3 扩展性设计

  1. 审批委托:

    • 添加委托关系表
    • 查询审批人时检查是否有委托
  2. 审批条件分支:

    • 根据业务数据动态调整审批流程
    • 实现条件审批规则引擎
  3. 审批超时处理:

    • 添加超时时间字段
    • 定时任务检查超时审批
    • 自动升级或提醒

5. 实战中的经验分享

在实际项目中实现这套方案时,有几个关键点值得注意:

  1. 审批编号生成:建议使用"年月日时分+序号"的格式,如2023050112300001,既保证唯一性又带有时间信息。

  2. 状态同步:业务表的状态应与审批主表保持同步,可以通过触发器或应用逻辑实现。

  3. 历史记录:考虑添加审批历史表,记录完整的审批轨迹,便于审计和查询。

  4. 消息通知:审批状态变更时应实时通知相关人,可以集成消息队列实现异步通知。

  5. 测试覆盖:特别注意测试边界条件,如:

    • 单级审批流程
    • 多级全部通过
    • 中间级驳回
    • 第一级驳回
    • 申请人撤销等场景

这套方案已经在多个项目中得到验证,最高支持过12级审批流程,日均处理超过5000条审批记录,表现出良好的稳定性和扩展性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 7:11:08

Java安装与环境配置避坑指南:Phi-4-mini-reasoning智能排错

Java安装与环境配置避坑指南:Phi-4-mini-reasoning智能排错 1. 为什么Java安装总是出问题? 刚接触Java开发的朋友,十个有九个会在环境配置这一步栽跟头。明明跟着教程一步步操作,却总遇到"不是内部或外部命令"、"…

作者头像 李华
网站建设 2026/9/19 1:50:02

比迪丽LoRA模型与ComfyUI工作流集成:实现复杂角色绘制

比迪丽LoRA模型与ComfyUI工作流集成:实现复杂角色绘制 如果你已经用Stable Diffusion WebUI玩过LoRA模型,可能会觉得,虽然效果不错,但流程总有点“黑盒”的感觉。想同时用两个LoRA模型?想精确控制角色的姿势和构图&am…

作者头像 李华
网站建设 2026/9/18 19:59:14

从理论到波形:基于D触发器的模10同步计数器设计与实现

1. 从零开始理解模10同步计数器 第一次接触数字电路设计时,看到"模10同步计数器"这个名词确实有点懵。简单来说,这就是一个能循环计数0到9的电子计数器,就像我们常见的电子钟的秒位显示。但要用D触发器实现它,就需要理…

作者头像 李华
网站建设 2026/9/21 17:05:06

Swin2SR在Java项目中的集成指南:SpringBoot图像增强服务开发

Swin2SR在Java项目中的集成指南:SpringBoot图像增强服务开发 1. 引言 作为一名Java开发者,你可能经常遇到这样的场景:用户上传的图片分辨率太低,直接显示会影响用户体验;或者需要处理大量历史图片,但原始…

作者头像 李华