工作流:审批规则设计

审批规则设计

以下是针对审批人规则表处理人计算规则的设计方案,支持灵活的多维度审批人分配策略:


一、审批规则表设计(approval_rule)

1. 表结构设计
CREATE TABLE approval_rule (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    process_key VARCHAR(100) NOT NULL COMMENT '流程定义Key',
    node_id VARCHAR(50) NOT NULL COMMENT '流程节点ID(如ActivityId)',
    assign_type VARCHAR(20) NOT NULL COMMENT '分配类型',
    assign_expression VARCHAR(500) NOT NULL COMMENT '分配规则表达式',
    fallback_assignee VARCHAR(100) COMMENT '备选处理人(当表达式结果为空时使用)',
    tenant_id VARCHAR(20) NOT NULL COMMENT '租户隔离',
    version INT DEFAULT 1 COMMENT '规则版本',
    is_active BOOLEAN DEFAULT 1 COMMENT '是否启用',
    INDEX idx_process_node (process_key, node_id)
);
2. 字段说明

字段

说明

assign_type

分配策略类型,枚举值:FIXED_USER, ROLE, DEPT_LEADER, UPWARD, EXPRESSION

assign_expression

根据类型存储不同内容(用户ID、角色代码、部门路径等)

fallback_assignee

当规则计算失败时的备用处理人(可指定具体用户或管理员角色)


二、处理人计算规则示例

场景1:直接指定用户
INSERT INTO approval_rule 
  (process_key, node_id, assign_type, assign_expression, tenant_id)
VALUES
('purchase_high_value', 'approval_step1', 'FIXED_USER', 'user_001', 'T001');

运行时逻辑:直接使用用户ID user_001 作为审批人


场景2:按角色分配
INSERT INTO approval_rule 
  (process_key, node_id, assign_type, assign_expression, tenant_id)
VALUES
('sales_contract', 'finance_approve', 'ROLE', 'FINANCE_DIRECTOR', 'T001');

运行时逻辑:查询拥有 FINANCE_DIRECTOR 角色的所有用户


场景3:按部门负责人分配
INSERT INTO approval_rule 
  (process_key, node_id, assign_type, assign_expression, tenant_id)
VALUES
('production_plan', 'dept_approve', 'DEPT_LEADER', 'order.deptCode', 'T001');

运行时逻辑:根据业务单据中的 deptCode 字段,查找该部门的负责人


场景4:逐级上报
INSERT INTO approval_rule 
  (process_key, node_id, assign_type, assign_expression, tenant_id)
VALUES
('purchase_medium', 'upward_approve', 'UPWARD', '3', 'T001');

运行时逻辑:从申请人开始向上找3级领导(需集成组织架构服务)


场景5:动态表达式
INSERT INTO approval_rule 
  (process_key, node_id, assign_type, assign_expression, tenant_id)
VALUES
('sales_vip', 'special_approve', 'EXPRESSION', 
 'userService.findByRoleAndDept("VIP_APPROVER", order.salesDept)', 'T001');

运行时逻辑:执行SpEL表达式,调用userService查询符合条件的用户


三、处理人计算服务实现

1. 核心计算逻辑(Java示例)
public class AssigneeCalculator {
    // 策略模式处理不同分配类型
    public List<String> calculate(ApprovalRule rule, Order order) {
        switch (rule.getAssignType()) {
            case "FIXED_USER":
                return Collections.singletonList(rule.getAssignExpression());
                
            case "ROLE":
                return userService.findUsersByRole(rule.getAssignExpression());
                
            case "DEPT_LEADER":
                String deptCode = order.getDeptCode();
                return deptService.getDeptLeaders(deptCode);
                
            case "UPWARD":
                int level = Integer.parseInt(rule.getAssignExpression());
                return orgStructureService.findUpwardUsers(order.getApplicant(), level);
                
            case "EXPRESSION":
                return evalExpression(rule.getAssignExpression(), order);
                
            default:
                return handleFallback(rule);
        }
    }
    
    // 使用Spring EL解析动态表达式
    private List<String> evalExpression(String expr, Order order) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext();
        context.setVariable("order", order);
        context.setVariable("userService", userService);
        return parser.parseExpression(expr).getValue(context, List.class);
    }
}
2. 计算过程时序图
sequenceDiagram
    participant Engine as 流程引擎
    participant Service as 审批服务
    participant RuleDB as 规则表
    participant Org as 组织服务
    
    Engine->>Service: 获取节点审批人(processKey, nodeId, order)
    Service->>RuleDB: 查询审批规则
    RuleDB-->>Service: 返回rule数据
    alt 需要动态计算
        Service->>Org: 获取部门负责人/角色用户
        Org-->>Service: 返回用户列表
    else 表达式计算
        Service->>Service: 执行SpEL表达式
    end
    Service-->>Engine: 返回审批人列表

四、高级设计:可扩展规则引擎

1. 策略接口定义
public interface AssignmentStrategy {
    List<String> execute(String expression, Order order);
}

// 注册所有策略
@Component
public class StrategyRegistry {
    @Autowired
    private Map<String, AssignmentStrategy> strategies;
    
    public AssignmentStrategy getStrategy(String type) {
        return strategies.get(type + "Strategy");
    }
}

// 示例:角色策略实现
@Component
public class RoleStrategy implements AssignmentStrategy {
    @Override
    public List<String> execute(String roleCode, Order order) {
        return userService.findByRole(roleCode);
    }
}
2. 规则表达式语法示例
// 复杂场景:多条件组合
{
  "type": "COMPOSITE",
  "rules": [
    {
      "type": "ROLE",
      "value": "FINANCE_APPROVER"
    },
    {
      "type": "DEPT_LEADER",
      "field": "order.applyDept"
    }
  ],
  "logic": "AND" // 或 OR
}

五、安全与性能优化

1. 表达式白名单
// 限制可访问的类和方法
SpelParserConfiguration config = new SpelParserConfiguration(
    null, 
    new SafeExpressionCompiler()
);

public class SafeExpressionCompiler extends SpelCompilerMode {
    @Override
    public boolean isAllowed(String expression) {
        return expression.matches("^[a-zA-Z0-9._()]+$"); // 过滤危险字符
    }
}
2. 缓存设计
@Cacheable(value = "approvalRules", 
           key = "#processKey + ':' + #nodeId + ':' + #tenantId")
public ApprovalRule getActiveRule(String processKey, String nodeId, String tenantId) {
    return ruleDao.findActiveRule(processKey, nodeId, tenantId);
}

@Cacheable(value = "roleUsers", key = "#roleCode + ':' + #tenantId")
public List<String> getUsersByRole(String roleCode, String tenantId) {
    return userDao.findByRole(roleCode, tenantId);
}

六、最佳实践建议

  1. 审批链设计
    对于需要多人审批的场景,可采用:
INSERT INTO approval_rule 
  (process_key, node_id, assign_type, assign_expression)
VALUES
('contract_approve', 'multi_step', 'SEQUENTIAL', 
 '["ROLE:LEGAL_REVIEWER", "DEPT_LEADER:order.applyDept"]');

表示需要依次经过法务审核和部门负责人审批

  1. 会签/或签支持
    添加 approval_mode 字段:
ALTER TABLE approval_rule ADD approval_mode VARCHAR(10) DEFAULT 'SINGLE' 
  COMMENT '审批模式:SINGLE/AND/OR';
  • AND:所有审批人同意
  • OR:任意一人同意即可
  1. 动态代理审批人
    当审批人不在岗时,可配置自动转发规则:
CREATE TABLE approval_delegation (
    user_id VARCHAR(20) NOT NULL,
    delegate_user_id VARCHAR(20) NOT NULL,
    start_time DATETIME,
    end_time DATETIME
);

通过这种设计,系统可以实现:

  • 灵活配置:支持从简单指定到复杂动态计算的各类场景
  • 安全可控:表达式执行沙箱化+白名单机制
  • 高性能:关键数据缓存+预编译策略
  • 易扩展:策略模式支持新增分配类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值