approval-workflow-example.md 11 KB

审批流框架使用示例

概述

本框架实现了一个简单而灵活的审批流系统,支持以下几种审批流程:

  1. 个人级别: 无需审批,发送待办通知,点击确认知悉后归档
  2. 科级: 科长选择整改班组 → 班组长填写整改详情 → 科长审批 → 质检科审批 → 归档
  3. 班组级: 科长提交 → 班组长填写整改详情 → 科长审批 → 归档
  4. 查获上报: 根据提交人角色选择不同流程
    • 安检员提交: 班组长审批 → 归档
    • 班组长提交: 科长审批 → 归档

API 使用示例

1. 启动个人级别审批流程

@PostMapping("/check/personal")
public AjaxResult submitPersonalCheck(@RequestBody PersonalCheckDTO checkData) {
    Map<String, Object> params = new HashMap<>();
    params.put("businessType", "SECURITY_CHECK");
    params.put("businessId", checkData.getId());
    params.put("title", "个人级别安检问题");
    
    // 目标通知用户ID列表
    List<Long> targetUserIds = Arrays.asList(checkData.getTargetUserIds());
    params.put("targetUserIds", targetUserIds);
    
    // 表单数据
    Map<String, Object> formData = new HashMap<>();
    formData.put("checkLevel", "PERSONAL");
    formData.put("description", checkData.getDescription());
    params.put("formData", formData);
    
    // 业务数据
    Map<String, Object> businessData = new HashMap<>();
    businessData.put("checkType", checkData.getCheckType());
    businessData.put("location", checkData.getLocation());
    params.put("businessData", businessData);
    
    return approvalController.startPersonalLevelProcess(params);
}

2. 启动科级审批流程

@PostMapping("/check/section")
public AjaxResult submitSectionCheck(@RequestBody SectionCheckDTO checkData) {
    Map<String, Object> params = new HashMap<>();
    params.put("businessType", "SECURITY_CHECK");
    params.put("businessId", checkData.getId());
    params.put("title", "科级安检问题处理");
    
    // 表单数据
    Map<String, Object> formData = new HashMap<>();
    formData.put("checkLevel", "SECTION");
    formData.put("description", checkData.getDescription());
    formData.put("severity", checkData.getSeverity());
    params.put("formData", formData);
    
    // 业务数据  
    Map<String, Object> businessData = new HashMap<>();
    businessData.put("checkType", checkData.getCheckType());
    businessData.put("targetDeptId", checkData.getTargetDeptId());
    params.put("businessData", businessData);
    
    return approvalController.startSectionLevelProcess(params);
}

3. 启动查获上报审批流程

@PostMapping("/seizure/report")
public AjaxResult submitSeizureReport(@RequestBody SeizureReportDTO reportData) {
    Map<String, Object> params = new HashMap<>();
    params.put("businessType", "SEIZURE_REPORT");
    params.put("businessId", reportData.getId());
    params.put("title", "查获物品上报");
    
    // 根据当前用户角色确定提交人角色
    String submitterRole = getCurrentUserRole(); // "GROUP_LEADER" 或其他
    params.put("submitterRole", submitterRole);
    
    // 表单数据
    Map<String, Object> formData = new HashMap<>();
    formData.put("itemType", reportData.getItemType());
    formData.put("quantity", reportData.getQuantity());
    formData.put("location", reportData.getLocation());
    params.put("formData", formData);
    
    // 业务数据
    Map<String, Object> businessData = new HashMap<>();
    businessData.put("seizureTime", reportData.getSeizureTime());
    businessData.put("passengerInfo", reportData.getPassengerInfo());
    params.put("businessData", businessData);
    
    return approvalController.startSeizureReportProcess(params);
}

4. 审批任务(同意)

@PutMapping("/approval/approve/{taskId}")
public AjaxResult approveTask(@PathVariable Long taskId, @RequestBody ApprovalDTO approvalData) {
    Map<String, Object> params = new HashMap<>();
    params.put("comment", approvalData.getComment());
    
    // 如果是科长节点,需要选择整改班组
    if ("SECTION_LEADER".equals(approvalData.getNodeType())) {
        Map<String, Object> formData = new HashMap<>();
        formData.put("targetGroupId", approvalData.getTargetGroupId());
        formData.put("rectificationRequirement", approvalData.getRectificationRequirement());
        params.put("formData", formData);
    }
    
    // 如果是班组长整改节点,需要填写整改详情
    if ("GROUP_LEADER_RECTIFY".equals(approvalData.getNodeType())) {
        Map<String, Object> formData = new HashMap<>();
        formData.put("rectificationDetail", approvalData.getRectificationDetail());
        formData.put("rectificationTime", approvalData.getRectificationTime());
        formData.put("rectificationResult", approvalData.getRectificationResult());
        params.put("formData", formData);
    }
    
    return approvalController.approveTask(taskId, params);
}

5. 驳回任务

@PutMapping("/approval/reject/{taskId}")
public AjaxResult rejectTask(@PathVariable Long taskId, @RequestBody RejectDTO rejectData) {
    Map<String, Object> params = new HashMap<>();
    params.put("comment", rejectData.getRejectReason());
    
    return approvalController.rejectTask(taskId, params);
}

6. 获取待办任务列表

@GetMapping("/approval/tasks/pending")
public TableDataInfo getPendingTasks() {
    return approvalController.getPendingTasks();
}

7. 获取已办任务列表

@GetMapping("/approval/tasks/completed")
public TableDataInfo getCompletedTasks() {
    return approvalController.getCompletedTasks();
}

8. 获取我发起的审批实例

@GetMapping("/approval/instances/submitted")
public TableDataInfo getSubmittedInstances(@RequestParam(required = false) String status) {
    return approvalController.getSubmittedInstances(status);
}

前端集成示例

1. 待办任务列表页面

// 获取待办任务
function loadPendingTasks() {
    $.get('/system/approval/tasks/pending', function(res) {
        if (res.code === 200) {
            renderTaskList(res.rows);
        }
    });
}

// 审批任务
function approveTask(taskId, comment, formData) {
    const params = {
        comment: comment,
        formData: formData
    };
    
    $.ajax({
        url: `/system/approval/approve/${taskId}`,
        type: 'PUT',
        contentType: 'application/json',
        data: JSON.stringify(params),
        success: function(res) {
            if (res.code === 200) {
                $.modal.msgSuccess("审批成功");
                loadPendingTasks();
            } else {
                $.modal.msgError(res.msg);
            }
        }
    });
}

// 驳回任务
function rejectTask(taskId, reason) {
    const params = {
        comment: reason
    };
    
    $.ajax({
        url: `/system/approval/reject/${taskId}`,
        type: 'PUT', 
        contentType: 'application/json',
        data: JSON.stringify(params),
        success: function(res) {
            if (res.code === 200) {
                $.modal.msgSuccess("驳回成功");
                loadPendingTasks();
            } else {
                $.modal.msgError(res.msg);
            }
        }
    });
}

2. 个人级别检查提交

function submitPersonalCheck(checkData) {
    const params = {
        businessType: 'SECURITY_CHECK',
        businessId: checkData.id,
        title: '个人级别安检问题',
        targetUserIds: checkData.targetUserIds,
        formData: {
            checkLevel: 'PERSONAL',
            description: checkData.description
        },
        businessData: {
            checkType: checkData.checkType,
            location: checkData.location
        }
    };
    
    $.post('/system/approval/start/personal', params, function(res) {
        if (res.code === 200) {
            $.modal.msgSuccess("提交成功,已发送通知");
        } else {
            $.modal.msgError(res.msg);
        }
    });
}

数据库初始化

在使用审批流框架前,需要执行以下SQL脚本初始化数据库:

-- 执行审批流数据库脚本
source sql/approval_workflow.sql

权限配置

需要在系统中配置以下权限:

-- 审批流相关权限
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
('审批管理', 1, 8, 'approval', NULL, 1, 0, 'M', '0', '0', NULL, 'documentation', 'admin', sysdate(), '', NULL, '审批流程管理目录'),
('待办任务', 2000, 1, 'pending', 'approval/pending/index', 1, 0, 'C', '0', '0', 'system:approval:query', '#', 'admin', sysdate(), '', NULL, '待办任务菜单'),
('已办任务', 2000, 2, 'completed', 'approval/completed/index', 1, 0, 'C', '0', '0', 'system:approval:query', '#', 'admin', sysdate(), '', NULL, '已办任务菜单'),
('我的申请', 2000, 3, 'submitted', 'approval/submitted/index', 1, 0, 'C', '0', '0', 'system:approval:query', '#', 'admin', sysdate(), '', NULL, '我的申请菜单');

-- 审批流权限
INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) VALUES
('审批', '', 1, '', '', 1, 0, 'F', '0', '0', 'system:approval:approve', '#', 'admin', sysdate(), '', NULL, ''),
('驳回', '', 2, '', '', 1, 0, 'F', '0', '0', 'system:approval:reject', '#', 'admin', sysdate(), '', NULL, ''),
('取消', '', 3, '', '', 1, 0, 'F', '0', '0', 'system:approval:cancel', '#', 'admin', sysdate(), '', NULL, ''),
('启动流程', '', 4, '', '', 1, 0, 'F', '0', '0', 'system:approval:start', '#', 'admin', sysdate(), '', NULL, '');

角色配置

确保系统中存在以下角色:

-- 班组长角色
INSERT INTO sys_role (role_name, role_key, role_sort, data_scope, status, del_flag, create_by, create_time, remark) 
VALUES ('班组长', 'group_leader', 3, '4', '0', '0', 'admin', sysdate(), '班组长角色');

-- 科长角色  
INSERT INTO sys_role (role_name, role_key, role_sort, data_scope, status, del_flag, create_by, create_time, remark)
VALUES ('科长', 'section_leader', 2, '3', '0', '0', 'admin', sysdate(), '科长角色');

-- 质检员角色
INSERT INTO sys_role (role_name, role_key, role_sort, data_scope, status, del_flag, create_by, create_time, remark)
VALUES ('质检员', 'quality_inspector', 4, '4', '0', '0', 'admin', sysdate(), '质检员角色');

注意事项

  1. 审批人配置: 确保各部门的班组长、科长角色配置正确
  2. 业务数据: 根据实际业务需求调整 businessData 的数据结构
  3. 超时处理: 系统会自动标记超时任务,建议定期清理
  4. 权限控制: 确保只有相关人员才能审批对应的任务
  5. 数据备份: 审批历史数据建议定期备份

扩展开发

如需扩展新的审批流程类型:

  1. 在数据库中添加新的流程定义和节点定义
  2. ApprovalConstants 中添加相应常量
  3. IApprovalEngineService 中添加新的方法
  4. ApprovalController 中添加对应的接口
  5. 根据需要扩展 IApprovalUserService 的审批人获取逻辑