IMS系统工作流引擎设计与实现

工作流引擎是 IMS 系统的核心组件,负责处理各种审批流程的业务逻辑。本文将详细介绍工作流引擎的架构设计、流程定义、节点类型与审批逻辑实现。

工作流引擎整体架构

工作流引擎采用分层架构设计:

  • 流程设计器 - 可视化设计审批流程
  • 流程引擎 - 核心执行逻辑
  • 任务调度 - 待办任务分配与超时处理
  • 规则引擎 - 动态决定审批人与条件分支
  • 历史记录 - 流程执行轨迹追踪

流程定义数据结构

流程定义采用 JSON 格式存储:

process-definition.js
// 流程定义结构
const ProcessDefinition = {
  id: 'leave_request',
  name: '请假申请流程',
  version: 1,

  // 流程变量定义
  variables: [
    { key: 'days', type: 'number', label: '请假天数' },
    { key: 'reason', type: 'string', label: '请假原因' }
  ],

  // 节点定义
  nodes: [
    {
      id: 'start',
      type: 'start',
      name: '开始',
      next: 'apply'
    },
    {
      id: 'apply',
      type: 'userTask',
      name: '提交申请',
      assigneeType: 'initiator',  // 申请人自己
      formKey: 'leave_form',
      next: 'decide'
    },
    {
      id: 'decide',
      type: 'exclusiveGateway',
      name: '判断审批路径',
      conditions: [
        { expr: '${days <= 3}', target: 'manager_approve' },
        { expr: '${days > 3}', target: 'dept_approve' }
      ]
    },
    {
      id: 'manager_approve',
      type: 'userTask',
      name: '部门经理审批',
      assigneeType: 'variable',
      assigneeExpr: '${manager}',
      // 会签设置
      counterSign: {
        enabled: false,
        strategy: 'any'  // 任意一人通过即可
      },
      next: 'end'
    },
    {
      id: 'dept_approve',
      type: 'userTask',
      name: '部门经理审批',
      assigneeExpr: '${manager}',
      next: 'hr_approve'
    },
    {
      id: 'hr_approve',
      type: 'userTask',
      name: 'HR审批',
      assigneeType: 'role',
      assigneeExpr: 'HR',
      next: 'end'
    },
    {
      id: 'end',
      type: 'end',
      name: '结束'
    }
  ]
};

流程引擎核心实现

流程引擎负责解析流程定义并执行:

workflow-engine.js
class WorkflowEngine {
  constructor(repository) {
    this.repository = repository;
    this.variableResolver = new VariableResolver();
  }

  // 启动流程实例
  async startProcess(definitionId, initiator, variables) {
    const definition = await this.repository.getDefinition(definitionId);

    // 创建流程实例
    const instance = {
      id: generateId(),
      definitionId: definition.id,
      definitionKey: definition.key,
      version: definition.version,
      initiator: initiator,
      status: 'running',
      variables: { ...variables, initiator },
      startTime: new Date(),
      currentNodeId: 'start'
    };

    await this.repository.saveInstance(instance);

    // 自动流转到下一个节点
    await this.moveToNextNode(instance, 'start');

    return instance;
  }

  // 节点流转逻辑
  async moveToNextNode(instance, currentNodeId) {
    const definition = await this.repository.getDefinition(instance.definitionKey);
    const currentNode = definition.nodes.find(n => n.id === currentNodeId);

    if (!currentNode.next) return;

    const nextNodeId = await this.resolveNextNode(definition, currentNode, instance);
    const nextNode = definition.nodes.find(n => n.id === nextNodeId);

    // 处理不同节点类型
    switch (nextNode.type) {
      case 'userTask':
        await this.createTask(instance, nextNode);
        break;
      case 'end':
        instance.status = 'completed';
        instance.endTime = new Date();
        break;
    }

    instance.currentNodeId = nextNodeId;
    await this.repository.saveInstance(instance);
  }

  // 处理用户任务完成
  async completeTask(taskId, userId, variables = {}) {
    const task = await this.repository.getTask(taskId);

    // 验证任务是否可办理
    if (!this.canCompleteTask(task, userId)) {
      throw new Error('无权限办理此任务');
    }

    // 更新流程变量
    const instance = await this.repository.getInstance(task.instanceId);
    Object.assign(instance.variables, variables);

    // 记录任务历史
    await this.repository.saveHistory({
      taskId, userId, action: 'complete',
      variables, completedAt: new Date()
    });

    // 完成任务
    task.status = 'completed';
    task.completedAt = new Date();
    await this.repository.saveTask(task);

    // 流转到下一节点
    await this.moveToNextNode(instance, task.nodeId);
  }
}

审批人分配策略

支持多种审批人分配方式:

assignee-resolver.js
class AssigneeResolver {
  async resolve(assigneeType, assigneeExpr, instance) {
    switch (assigneeType) {
      case 'initiator':
        // 申请人自己
        return instance.initiator;

      case 'user':
        // 指定用户
        return assigneeExpr;

      case 'role':
        // 角色对应的用户
        return await this.findUsersByRole(assigneeExpr);

      case 'deptLeader':
        // 申请人部门领导
        const user = await this.getUser(instance.initiator);
        return user.department.leaderId;

      case 'variable':
        // 从变量获取
        return instance.variables[assigneeExpr];

      case 'script':
        // 脚本计算
        return eval(assigneeExpr);

      default:
        throw new Error(`Unknown assignee type: ${assigneeType}`);
    }
  }
}

会签与转交实现

支持多人审批场景:

counter-sign.js
// 会签处理逻辑
class CounterSignHandler {
  async handleTaskComplete(task, userId, instance) {
    const node = await this.getNodeDefinition(instance, task.nodeId);

    // 检查是否会签
    if (!node.counterSign || !node.counterSign.enabled) {
      return true;
    }

    // 记录会签意见
    await this.saveCounterSignVote(task.instanceId, task.nodeId, userId, task.comment);

    // 判断是否满足会签条件
    const votes = await this.getVotes(task.instanceId, task.nodeId);
    const strategy = node.counterSign.strategy;

    switch (strategy) {
      case 'all':  // 所有人同意
        return votes.every(v => v.approved);
      case 'any':  // 任意一人同意
        return votes.some(v => v.approved);
      case 'majority':  // 多数同意
        return votes.filter(v => v.approved).length > votes.length / 2;
    }
  }

  // 转交任务
  async transferTask(taskId, fromUserId, toUserId) {
    const task = await this.getTask(taskId);
    if (task.assigneeId !== fromUserId) {
      throw new Error('无权限转交此任务');
    }
    task.assigneeId = toUserId;
    await this.saveTask(task);
  }
}

流程监控与催办

流程运行状态的监控与超时提醒:

  • 超时检测 - 定时扫描待办任务,对超时任务发送提醒
  • 流程追踪 - 记录每个节点的开始/结束时间
  • 催办功能 - 支持手动触发催办通知
  • 流程挂起 - 特殊情况下暂停流程执行

总结

工作流引擎是企业级 IMS 系统的核心。良好的架构设计需要考虑流程定义的灵活性、审批人分配的多样性、会签转交等复杂场景,以及流程执行的可靠性和可追溯性。