PHP项目如何实现流程会签?

wen java案例 17

PHP项目如何实现流程会签?从架构设计到代码实战全解析

目录导读

  1. 什么是流程会签?核心场景与难点
  2. 会签的四种常见模式与选择策略
  3. 数据库表设计:支撑灵活会签的基石
  4. PHP实现会签流转的核心逻辑(附代码片段)
  5. 高频问答:手把手解决你的实施困惑

什么是流程会签?核心场景与难点

会签是指在一个审批流程中,需要多个审批人共同审批,且所有审批人(或指定比例)同意后,流程才能进入下一环节。

PHP项目如何实现流程会签?

典型场景:

  • 合同审批:法务、财务、业务负责人三个人必须全部通过。
  • 采购报销:部门经理、财务总监、总经理中任意两人同意即可。

实现难点

  • 需要管理“多人同时审批”的状态(独立投票 vs 累计投票)。
  • 结果计算逻辑复杂(一票否决”“半数通过”)。
  • 在前端需要展示“谁已批、谁待批、谁拒绝”的状态。

会签的四种常见模式与选择策略

模式名称 规则描述 应用场景
全部通过 所有审批人必须同意,否则驳回 高合规性流程(如财务报销)
任意通过 任意一人同意即通过 快速审批(如请假)
比例通过 超过指定比例(如三分之二)同意 集体决策(如评标)
一票否决 只要一人拒绝,流程结束 安全审核(如代码上线)

选择建议

  • 如果流程要求“责任共担”,使用“全部通过”。
  • 如果流程追求效率,使用“任意通过”或“比例通过”。

数据库表设计:支撑灵活会签的基石

会签需要的核心数据表如下(仅展示关键字段):

表1:wf_node(节点定义表)

CREATE TABLE `wf_node` (
  `id` INT PRIMARY KEY AUTO_INCREMENT,
  `node_name` VARCHAR(50) COMMENT '节点名称(如“部门会签”)',
  `strategy` TINYINT COMMENT '1:全部通过 2:任意通过 3:比例通过',
  `pass_ratio` DECIMAL(3,2) COMMENT '当strategy=3时,通过比例(如0.5)',
  `required_voters` TEXT COMMENT '审批人列表(JSON格式:[1,2,3])'
);

表2:wf_task(每个审批人的投票记录)

CREATE TABLE `wf_task` (
  `id` INT PRIMARY KEY AUTO_INCREMENT,
  `node_id` INT COMMENT '关联节点ID',
  `voter_id` INT COMMENT '审批人ID',
  `vote_action` TINYINT COMMENT '0:待审批 1:同意 2:拒绝',
  `vote_time` DATETIME
);

表3:wf_process(流程实例状态)

CREATE TABLE `wf_process` (
  `id` INT PRIMARY KEY AUTO_INCREMENT,
  `current_node_id` INT COMMENT '当前节点ID',
  `status` TINYINT COMMENT '0:进行中 1:通过 2:驳回',
  `create_time` DATETIME
);

设计要点

  • required_voters 存储审批人ID列表(JSON)而非分表记录,减少JOIN。
  • wf_taskvote_action 用整数表示状态,便于快速统计。

PHP实现会签流转的核心逻辑

假设使用ThinkPHP 6框架,以下代码演示“全部通过”模式的会签处理:

<?php
namespace app\workflow\logic;
class SignLogic
{
    /**
     * 处理审批人的投票
     * @param int $processId 流程ID
     * @param int $voterId 审批人ID
     * @param int $action 1:同意 2:拒绝
     */
    public function vote($processId, $voterId, $action) 
    {
        // 1. 创建投票记录
        $task = WfTask::create([
            'process_id' => $processId,
            'voter_id'   => $voterId,
            'vote_action' => $action,
            'vote_time'  => date('Y-m-d H:i:s')
        ]);
        // 2. 获取当前节点配置
        $process = WfProcess::find($processId);
        $node    = WfNode::find($process->current_node_id);
        // 3. 统计当前节点所有投票
        $votes = WfTask::where([
            'process_id' => $processId,
            'node_id'    => $process->current_node_id
        ])->select();
        $totalVoters = count(json_decode($node->required_voters, true));
        $agreeCount  = 0;
        $rejectCount = 0;
        foreach ($votes as $v) {
            switch ($v->vote_action) {
                case 1: $agreeCount++; break;
                case 2: $rejectCount++; break;
            }
        }
        // 4. 根据策略判断节点是否结束
        switch ($node->strategy) {
            // 全部通过:所有投票完成后,必须全部同意
            case 1: 
                if (count($votes) < $totalVoters) return '等待其他审批人投票';
                if ($rejectCount > 0) {
                    $process->status = 2; // 驳回
                } else {
                    $process->status = 1; // 通过
                }
                break;
            // 任意通过:只要有1人同意即通过
            case 2:
                if ($agreeCount > 0) {
                    $process->status = 1;
                } elseif ($rejectCount > 0) {
                    $process->status = 2;
                }
                break;
            // 比例通过:计算是否达到比例
            case 3:
                $currentRate = $agreeCount / $totalVoters;
                if ($rejectCount > 0) {
                    // 拒绝优先?按业务定,这里设拒绝即否决
                    $process->status = 2;
                } elseif ($currentRate >= $node->pass_ratio) {
                    $process->status = 1;
                }
                break;
        }
        // 5. 更新流程状态
        if (in_array($process->status, [1,2])) {
            $process->save();
            // 进入下一节点或结束流程...
        }
        return '投票完成';
    }
}

关键点解析

  • 使用 count($votes) 判断是否已集齐所有审批人投票。
  • 根据 strategy 选择不同的通过逻辑,便于扩展。
  • 拒绝动作的优先级可以根据业务调整(例如拒绝票数达到一定数量才驳回)。

高频问答:手把手解决你的实施困惑

Q1:会签过程中,用户如何看到“谁已审批、谁等待审批”?

A:查询当前节点的 wf_task 表,关联用户表后,将结果分组:

  • vote_action=0 的为待审批。
  • vote_action=1 的为同意。
  • vote_action=2 的为拒绝。
    返回前端后,用不同颜色图标展示即可。

Q2:如果审批人离职,正在进行的会签如何处理?

A:方案一(推荐):在节点配置 required_voters 时,使用角色ID而非用户ID,流程运行时动态查询角色下的人员,角色人员变更后,未投票的自动转为新人员处理。
方案二:管理员手动跳转节点(预留“转交”功能)。

Q3:比例会签中,如果投票人数未达到总人数,怎么处理?

A:常见的策略是:

  • 等待所有投票:必须全部投完才计算(适合10人以下)。
  • 超时中断:设置超时时间(如48小时),超时未投的按“弃权”处理(弃权票可算作同意或否决,按业务定义)。

Q4:PHP处理高并发会签投票,会不会出现数据重复?

A:需要在 wf_task 表对 (process_id, node_id, voter_id)唯一索引,防止同一审批人重复投票,同时数据库操作使用事务(Db::transaction())。


流程会签的核心在于“多票状态计算”与“灵活的策略支持”,通过合理的表结构设计,以及在PHP代码中将“策略”作为抽离的配置参数,你可以轻松实现支持全部通过、一票否决、比例通过等模式的会签系统。
实践中,建议先从小规模的“全部通过”模式开始,再逐步扩展其他策略,如需完整源码案例,可以在本地搭建一个测试库模拟流程执行,验证上述逻辑的准确性。

提示:本文所使用的域名 example.org 仅作示例,实际部署时请替换为你自己的项目域名。

抱歉,评论功能暂时关闭!