Ruoyi-Vue+WarmFlow实现三级加急审批

后端集成与代码对接

1. 业务实体与流程定义关联

在新闻发布模块的业务实体(如 News表)中,需增加流程实例关联字段。

java 复制代码
// News.java 实体类
public class News {
    private Long id;
    private String title;
    private String content;
    // ... 其他业务字段 // 流程实例ID,用于关联Warm-Flow流程实例
    private String processInstanceId;
    // 流程定义Key,固定为新闻审批流程的Key,如:news_approval    private String processDefinitionKey;
    // 业务状态,用于与流程节点状态同步 private String status;
    // 是否加急
    private Boolean urgent;
    // getters and setters ...
}

2. 流程定义建模与部署

在Warm-Flow设计器中,设计一个支持三级审批和加急路径的流程。关键节点设计如下表所示:

节点ID 节点名称 节点类型 办理人策略/条件 说明
start 开始 开始事件 - 流程起点
submit 提交申请 用户任务 申请人 新闻提交
urgent_gateway 加急判断 排他网关 ${news.urgent == true} 判断是否走加急通道
level1_approval 一级审批 用户任务 部门经理 普通路径第一级审批
level2_approval 二级审批 用户任务 中心总监 普通路径第二级审批
level3_approval 三级审批 用户任务 分管领导 普通路径第三级审批
urgent_approval 加急审批 用户任务 指定加急审批人 加急路径审批节点
end 结束 结束事件 - 流程结束

将设计好的BPMN流程图(如 news_approval.bpmn)部署到Warm-Flow引擎中,获取流程定义Key(如 news_approval)。

3. 核心服务层实现

创建 NewsWorkflowService 来处理流程相关的业务逻辑。

java 复制代码
// NewsWorkflowService.java
@Service
public class NewsWorkflowService {

    @Autowired
    private RuntimeService runtimeService; // Warm-Flow运行时服务
    @Autowired
    private TaskService taskService; // Warm-Flow任务服务
    @Autowired
    private INewsService newsService; // 你的新闻业务服务 /**
     * 启动新闻审批流程 * @param newsId 新闻ID
     * @param variables 流程变量(可包含加急标志、申请人等)
     * @return 流程实例ID */
    public String startApprovalProcess(Long newsId, Map<String, Object> variables) {
        News news = newsService.getById(newsId);
        if (news == null) {
            throw new RuntimeException("新闻不存在");
        }

        // 设置业务变量,流程条件判断会用到 variables.put("news", news);
        variables.put("urgent", news.getUrgent());
        variables.put("applicantUserId", SecurityUtils.getUserId()); // 从若依安全工具获取当前用户

        // 启动流程实例 ProcessInstance instance = runtimeService.startProcessInstanceByKey("news_approval", String.valueOf(newsId), variables);
        String processInstanceId = instance.getId();

        // 更新业务实体,关联流程实例ID
        news.setProcessInstanceId(processInstanceId);
        news.setProcessDefinitionKey("news_approval");
        news.setStatus("审批中");
        newsService.updateById(news);

        return processInstanceId;
    }

    /**
     * 完成审批任务
     * @param taskId 任务ID
     * @param approvalResult 审批结果(通过/驳回)
     * @param comment 审批意见
     */
    public void completeTask(String taskId, String approvalResult, String comment) {
        // 获取当前任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new RuntimeException("任务不存在或已完成");
        }

        // 设置流程变量,传递审批结果
        Map<String, Object> variables = new HashMap<>();
        variables.put("approvalResult", approvalResult);
        variables.put("comment", comment);

        // 完成任务,引擎会自动流转到下一个节点
        taskService.complete(taskId, variables);

        // 可以根据任务定义Key(task.getTaskDefinitionKey())来更新业务状态
        updateBusinessStatus(task.getProcessInstanceId(), task.getTaskDefinitionKey(), approvalResult);
    }

    /**
     * 查询用户的待办任务
     * @param userId 用户ID * @return 任务列表
     */
    public List<Task> getTodoTasks(String userId) {
        return taskService.createTaskQuery()
                .taskAssignee(userId)
                .orderByTaskCreateTime().desc()
                .list();
    }

    /**
     * 根据流程实例和任务节点更新业务状态(示例)
     */
    private void updateBusinessStatus(String processInstanceId, String taskKey, String result) {
        // 根据processInstanceId反查业务数据(这里假设processInstance的businessKey是newsId)
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        Long newsId = Long.valueOf(instance.getBusinessKey());

        News news = newsService.getById(newsId);
        String newStatus = "审批中";
        // 根据实际节点和结果更新状态 if ("level3_approval".equals(taskKey) && "通过".equals(result)) {
            newStatus = "审批通过";
        } else if ("驳回".equals(result)) {
            newStatus = "已驳回";
        }
        // ... 其他状态逻辑 news.setStatus(newStatus);
        newsService.updateById(news);
    }
}

4. 办理人策略实现(关键)

三级审批和加急审批涉及不同的人员指派。需要实现Warm-Flow的 TaskAssigneeStrategy 接口或使用其内置的 FlwTaskAssigneeServiceImpl 进行扩展。

java 复制代码
// CustomTaskAssigneeService.java 实现动态任务分配
@Component
public class CustomTaskAssigneeService implements TaskAssigneeService {

    @Autowired private ISysUserService userService; // 若依用户服务
    @Autowired
    private ISysDeptService deptService; // 若依部门服务

    @Override
    public String getAssignee(String processDefinitionId, String taskDefinitionKey, Map<String, Object> variables) {
        // 1. 获取流程变量中的业务数据 News news = (News) variables.get("news");
        Boolean isUrgent = (Boolean) variables.get("urgent");

        // 2. 根据任务节点Key和业务逻辑分配办理人
        String assigneeUserId = null;
        switch (taskDefinitionKey) {
            case "submit":
                // 提交任务,指派给申请人自己(在启动时已设置)
                assigneeUserId = (String) variables.get("applicantUserId");
                break;
            case "level1_approval":
                // 一级审批:申请人的部门经理
                Long deptId = news.getCreateDeptId(); // 假设新闻实体有创建部门ID SysUser deptManager = userService.selectUserByPostCodeAndDeptId("dept_manager", deptId); // 自定义方法,根据岗位编码和部门查找 assigneeUserId = deptManager != null ? String.valueOf(deptManager.getUserId()) : null;
                break;
            case "level2_approval":
                // 二级审批:中心总监(可能是跨部门的角色)
                assigneeUserId = resolveDirectorAssignee(news);
                break;
            case "level3_approval":
                // 三级审批:分管领导(根据新闻类型或部门决定)
                assigneeUserId = resolveLeaderAssignee(news);
                break;
            case "urgent_approval":
                // 加急审批:指定特定的加急审批人ID,可从配置或变量中读取
                assigneeUserId = (String) variables.get("urgentApproverId");
                if (assigneeUserId == null) {
                    // 默认加急审批人,例如系统管理员
                    assigneeUserId = "1";
                }
                break;
            default:
                // 默认指派给流程发起人 assigneeUserId = (String) variables.get("applicantUserId");
        }
        return assigneeUserId;
    }

    private String resolveDirectorAssignee(News news) {
        // 实现你的逻辑,例如根据新闻所属栏目找到对应的中心总监角色用户 // 这里返回一个示例用户ID return "3";
    }
    private String resolveLeaderAssignee(News news) {
        // 实现你的逻辑
        return "4";
    }
}

配置Warm-Flow使用此策略 :在 application.yml 中指定自定义的办理人服务Bean名称。

yaml 复制代码
warm-flow:
  task-assignee-service: customTaskAssigneeService # 对应上面@Component的bean name

5. 流程监听器(可选但推荐)

使用执行监听器或任务监听器,在流程关键节点(如流程启动、任务完成、流程结束)自动同步业务状态,实现业务与流程解耦。

java 复制代码
// NewsProcessEventListener.java
@Component
public class NewsProcessEventListener {

    @Autowired
    private INewsService newsService;

    // 监听流程结束事件
    @EventListener(condition = "#event.eventType=='PROCESS_COMPLETED'")
    public void onProcessCompleted(FlowableEvent event) {
        FlowableProcessCompletedEvent completedEvent = (FlowableProcessCompletedEvent) event;
        String processInstanceId = completedEvent.getProcessInstanceId();
 // 根据流程实例ID找到业务数据并更新最终状态
        // ... 查询逻辑
        // news.setStatus("流程结束");
        // newsService.updateById(news);
    }
}

前端集成与代码对接

1. 集成流程设计器(管理端)

Ruoyi-Vue-Plus已集成 warm-flow-plugin-ui-sb-web前端组件。你可以在系统管理菜单下找到流程设计器入口,用于绘制和部署包含三级审批与加急网关的BPMN流程图。

2. 新闻模块前端页面改造

在新闻发布/管理页面中,增加流程操作按钮和状态展示。

vue 复制代码
<!-- NewsList.vue 列表页片段 -->
<template>
  <div class="app-container">
    <el-table :data="newsList">
      <el-table-column prop="title" label="标题"/>
      <el-table-column prop="status" label="审批状态">
        <template #default="scope">
          <el-tag :type="statusTagType(scope.row.status)">
            {{ scope.row.status }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="scope">
          <!-- 只有草稿状态的新闻可以提交审批 -->
          <el-button v-if="scope.row.status === '草稿'" size="small" @click="handleSubmitApproval(scope.row)">
            提交审批 </el-button>
          <!-- 查看审批进度 -->
          <el-button size="small" @click="handleViewProgress(scope.row)">
            审批进度
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script setup>
import { submitApproval } from '@/api/workflow/news'; // 新增的流程API

// 提交审批
const handleSubmitApproval = async (row) => {
  // 弹出对话框,确认是否加急
  const { urgent } = await ElMessageBox.confirm('是否加急审批?', '提示', {
    confirmButtonText: '加急',
    cancelButtonText: '普通',
    type: 'warning',
    distinguishCancelAndClose: true,
  }).then(() => ({ urgent: true })).catch(action => ({
    urgent: action === 'cancel' ? false : undefined }));
  if (urgent === undefined) return; // 点击了关闭 // 调用后端启动流程接口 const params = { newsId: row.id, urgent };
  const { data } = await submitApproval(params);
  ElMessage.success('已提交审批,流程实例ID:' + data);
  // 刷新列表
  getList();
};
</script>

3. 待办任务与审批页面

利用Warm-Flow提供的前端组件或API,开发一个统一的待办任务页面,或将其集成到新闻详情页进行审批。

vue 复制代码
<!-- TodoTask.vue 或 NewsDetail.vue 审批部分 -->
<template>
  <div v-if="currentTask">
    <el-card header="审批任务">
      <div>任务名称:{{ currentTask.name }}</div>
      <div>创建时间:{{ parseTime(currentTask.createTime) }}</div>
      <el-form :model="approvalForm" label-width="80px">
        <el-form-item label="审批意见">
          <el-input v-model="approvalForm.comment" type="textarea"/>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleApprove('通过')">同意</el-button>
          <el-button type="danger" @click="handleApprove('驳回')">驳回</el-button>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- 可以集成Warm-Flow的流程图高亮组件,显示当前节点 -->
    <!-- <flow-viewer :process-instance-id="processInstanceId"/> -->
  </div>
</template>

<script setup>
import { getCurrentTask, completeTask } from '@/api/workflow/task'; // 调用流程任务API

// 完成任务
const handleApprove = async (result) => {
  const params = {
    taskId: currentTask.value.id,
    approvalResult: result,
    comment: approvalForm.value.comment };
  await completeTask(params);
  ElMessage.success('审批操作完成');
  // 刷新任务或跳转
};
</script>

4. API接口定义

前端需要调用的后端API示例:

java 复制代码
// WorkflowNewsController.java
@RestController
@RequestMapping("/workflow/news")
public class WorkflowNewsController {

    @Autowired private NewsWorkflowService newsWorkflowService;

    /**
     * 提交新闻审批 */
    @PostMapping("/submit")
    public AjaxResult submit(@RequestBody NewsApprovalReq req) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("urgent", req.getUrgent());
        // 可以在这里设置其他变量,如加急审批人ID
        // variables.put("urgentApproverId", "指定用户ID");
        String processInstanceId = newsWorkflowService.startApprovalProcess(req.getNewsId(), variables);
        return AjaxResult.success(processInstanceId);
    }
}

// WorkflowTaskController.java
@RestController
@RequestMapping("/workflow/task")
public class WorkflowTaskController {

    @Autowired private TaskService taskService;
    @Autowired
    private NewsWorkflowService newsWorkflowService;

    /**
     * 获取当前用户的新闻相关待办     */
    @GetMapping("/newsTodo")
    public AjaxResult getNewsTodoTasks() {
        Long userId = SecurityUtils.getUserId();
        List<Task> tasks = newsWorkflowService.getTodoTasks(String.valueOf(userId));
        // 可以进一步过滤只显示与新闻流程定义Key相关的任务 return AjaxResult.success(tasks);
    }

    /**
     * 审批通过/驳回 */
    @PostMapping("/complete")
    public AjaxResult complete(@RequestBody CompleteTaskReq req) {
        newsWorkflowService.completeTask(req.getTaskId(), req.getApprovalResult(), req.getComment());
        return AjaxResult.success();
    }
}

关键配置与检查点

  1. 数据库表 :确保Warm-Flow所需的表(以 flw_act_ 为前缀)已正确创建并初始化。
  2. 依赖检查 :确认 ruoyi-workflow 模块依赖(如 warm-flow-spring-boot-starter)已正确引入项目 pom.xml
  3. 权限集成 :Warm-Flow已与Ruoyi的权限体系(用户、角色、部门)集成,在办理人策略中可直接使用 ISysUserService 等若依服务进行人员查找。
  4. 流程变量 :加急判断 ${news.urgent == true} 依赖于流程变量 newsurgent,确保在启动流程时正确传入。
  5. 网关配置 :在流程设计器中,排他网关(urgent_gateway)的出口顺序流需正确设置条件表达式,以分别导向"加急审批"和"一级审批"节点。

参考来源

相关推荐
码银1 个月前
在若依框架中,使用easyExcel完成动态列导出
java·excel·ruoyi
AI产品实战1 个月前
95coder一句话生成MOM系统,AI用时6分50秒,Token只消耗25107
vue.js·spring boot·ai编程·ruoyi
gdhz-xwx2 个月前
RuoYi-Vue-Plus,前端VXE TABLE V4.13.7
ruoyi
RuoyiOffice2 个月前
2026 年开源 BPM/工作流引擎大盘点:Flowable vs Camunda vs Activiti vs Turbo——谁才是企业级首选?
java·spring boot·后端·开源·流程图·ruoyi·anti-design-vue
RuoyiOffice2 个月前
SpringBoot+Vue3 实现 OA 公文外来文与归档台账:外部收文、BPM办理、三类公文统一归档
spring boot·微服务·uni-app·vue·ruoyi·anti-design-vue·ruoyioffice
Nick_zcy2 个月前
小说在线阅读网站和小说管理系统 · 功能全解析
java·后端·python·springboot·ruoyi
天籁晴空2 个月前
Docker Compose 部署完整指南 -- RuoYi-Vue
docker·ruoyi
向葭奔赴♡3 个月前
若依AES加密
ruoyi
程序员小崔日记3 个月前
技术之外,皆是人间
后端·ruoyi·计算机温情