Warm-Flow国产工作流引擎入门

Warm-Flow国产工作流引擎入门

Warm-Flow,国产的工作流引擎,以其简洁轻量、五脏俱全、灵活扩展性强的特点,成为了众多开发者的首选。它不仅可以通过jar包快速集成设计器,同时原生支持经典和仿钉钉双模式

  • 官网 https://www.warm-flow.com/
  • 入门开发环境:solon 3.8.4 + Warm-Flow 1.8.4(20260205最新版) + warm-flow-mybatis-flex 1.8.4

下面我演示用简单的方式接入Warm-Flow流程,我用过 Flowable (2020年)【有相关经验】说实话,难用很重。

文章出自:https://lingkang.top/archives/warm-flow-rm

OA 请假流程

需要做以下流程:

  • 导入 warm-flow 的表格
  • 设计审批权限表,用于配置用户有哪些审批权限,比你直接把固定审批人放到 warm-flow 更好
  • 设计请假表,记录请假的开始、结束时间等。我们不存储到 warm-flow 的变量中,减少耦合

依赖

整合到我的某个模块下

xml 复制代码
<dependency>
  <groupId>org.dromara.warm-flow-mybatis-flex</groupId>
  <artifactId>warm-flow-mybatis-flex-solon-plugin</artifactId>
  <exclusions>
    <exclusion>
      <groupId>org.noear</groupId>
      <artifactId>mybatis-solon-plugin</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<!-- 设计器 -->
<dependency>
  <groupId>org.dromara.warm</groupId>
  <artifactId>warm-flow-plugin-ui-solon-web</artifactId>
</dependency>

<dependency>
  <groupId>org.noear</groupId>
  <artifactId>solon-web</artifactId>
  <scope>provided</scope>
</dependency>
<!--入参校验-->
<dependency>
  <groupId>top.lingkang</groupId>
  <artifactId>final-validator-solon</artifactId>
</dependency>
<dependency>
  <groupId>org.noear</groupId>
  <artifactId>mybatis-flex-solon-plugin</artifactId>
  <scope>provided</scope>
</dependency>

审批权限表

为什么要设计审批权限表?因为你开始一个流程实例后,需要用户去审批,如果你的系统有OA可以直接拿到上级领导放在审批人字段;当你没有类似OA的组织架构时审批权限表可以配置你可以审批哪些流程任务。

我们在设计流程图时,将节点定义:待提交(submit)、项目经理审批(PM_A)、部门经理审批(DM_A);当你开始一个请假流程后,节点是待提交(submit),将流程提交到审批时,节点是:项目经理审批(PM_A);这时项目经理审批(PM_A)就是用户拥有的权限:PM_A,用户查询任务节点是 PM_A 的就是他能够审批的任务。

sql 复制代码
CREATE TABLE `flow_approval_permission` (
  `id` bigint NOT NULL COMMENT 'id',
  `user_id` bigint DEFAULT NULL COMMENT '用户id',
  `permission` json DEFAULT NULL COMMENT '审批权限,数组json',
  `status` tinyint(1) DEFAULT NULL COMMENT '状态:1启用,0禁用',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `create_user_id` bigint DEFAULT NULL COMMENT '创建用户id',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建用户',
  `update_user_id` bigint DEFAULT NULL COMMENT '更新用户id',
  `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新用户名',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户审批权限表';

OA 请假表

sql 复制代码
CREATE TABLE `flow_leave` (
  `id` bigint unsigned NOT NULL COMMENT '主键',
  `type` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '请假类型,字典:warm_flow:leaveType',
  `reason` varchar(500) COLLATE utf8mb4_general_ci NOT NULL COMMENT '请假原因',
  `picture` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '截图,json数组',
  `start_time` datetime NOT NULL COMMENT '开始时间',
  `end_time` datetime NOT NULL COMMENT '结束时间',
  `day` decimal(5,2) NOT NULL DEFAULT '0.00' COMMENT '请假天数',
  `instance_id` bigint NOT NULL COMMENT '流程实例的id',
  `node_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '节点编码',
  `node_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '流程节点名称',
  `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)',
  `flow_status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回  8已完成 9已退回 10失效)',
  `create_user_id` bigint unsigned DEFAULT NULL COMMENT '创建者',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_user_id` bigint unsigned DEFAULT NULL COMMENT '更新者',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='OA 请假申请表';

给用户配置权限

编辑

数据库数据如下

编写流程图

编写一个简单的审批流程图

注意节点的名称和编码

条件如下

发起请假

请假时长需要自己算计

发起代码如下:

java 复制代码
    @Transaction
    @Override
    public Long addData(FlowLeaveSaveParam param) {
        boolean hasDefinition = flowDefinitionService.existsPublishByFlowCode(FlowConstants.FLOW_CODE_LEAVE);
        Assert.notNull(hasDefinition, "流程不存在:OA请假");

        BigDecimal day = param.getTime().divide(new BigDecimal("8.0"));
        Map<String, Object> var = new HashMap<>();
        var.put("time", param.getTime());
        var.put("day", day);
        var.put("reason", param.getReason());
        var.put("picture", param.getPicture());
        var.put("startTime", format.format(param.getStartTime()));
        var.put("endTime", format.format(param.getEndTime()));

        FlowLeaveEntity entity = BeanUtil.copyProperties(param, FlowLeaveEntity.class);
        FlowParams flowParams = new FlowParams()
                .flowCode(FlowConstants.FLOW_CODE_LEAVE)// 编码是流程图的编码 leave
                .handler(UserUtils.getUserIdElseSystemUserId())// 发起人
                .flowStatus(FlowStatus.TOBESUBMIT.getKey()) // 待提交
                .message("请假")
                .variable(var);
        // 开始一个请假流程
        Instance instance = FlowEngine.insService().start("level_" + IdUtils.genSnowflake_62(), flowParams);

        entity.setDay(day);
        entity.setInstanceId(instance.getId());
        entity.setNodeType(instance.getNodeType());
        entity.setNodeCode(instance.getNodeCode());
        entity.setNodeName(instance.getNodeName());
        entity.setFlowStatus(instance.getFlowStatus());
        save(entity);
        return entity.getId();
    }

发起完继续提示提交到审批流程

提交到项目经理审批代码:

java 复制代码
    @Override
    public void submit(Long id) {
        Long insId = getOneAs(
                QueryWrapper.create().select(FlowLeaveEntity::getInstanceId)
                        .eq(FlowLeaveEntity::getId, id),
                Long.class
        );
        FlowTask task = flowTaskService.getLastTaskByInstanceId(insId);
        boolean isSubmit = FlowNodeCode.SUBMIT.getCode().equals(task.getNodeCode());
        Assert.isTrue(isSubmit, "当前流程非待提交状态");
        Map<String, Object> var = flowInstanceService.getVariableMapById(insId);
        Instance instance = FlowEngine.taskService().pass(task.getId(), "提交审批", var);
        updateStatus(id, instance);// 需要将流程的节点、状态同步更新到 flow_leave 请假表
    }
    
    public void updateStatus(Long id, Instance instance) {
        updateChain().set(FlowLeaveEntity::getFlowStatus, instance.getFlowStatus())
                .set(FlowLeaveEntity::getNodeType, instance.getNodeType())
                .set(FlowLeaveEntity::getNodeCode, instance.getNodeCode())
                .set(FlowLeaveEntity::getNodeName, instance.getNodeName())
                .eq(FlowLeaveEntity::getId, id)
                .update();
    }

项目经理审批流程

请假流程管理页面可以看到由项目经理审批

有审批权限的用户登录查看OA请假审批即可看到能审批的流程

对应的审批列表查询代码如下:

java 复制代码
    public PageData<FlowLeaveVO> approvalList(FlowLeaveParam param) {
        UserVO userVO = UserUtils.getUser();
        QueryWrapper query = QueryWrapper.create()
                .select(FlowLeaveEntity::getId, FlowLeaveEntity::getType, FlowLeaveEntity::getReason,
                        FlowLeaveEntity::getPicture, FlowLeaveEntity::getStartTime, FlowLeaveEntity::getEndTime,
                        FlowLeaveEntity::getDay, FlowLeaveEntity::getInstanceId, FlowLeaveEntity::getNodeCode,
                        FlowLeaveEntity::getNodeName, FlowLeaveEntity::getNodeType, FlowLeaveEntity::getFlowStatus,
                        FlowLeaveEntity::getCreateUserId, FlowLeaveEntity::getCreateTime, FlowLeaveEntity::getUpdateUserId,
                        FlowLeaveEntity::getUpdateTime, FlowLeaveEntity::getDelFlag)
                .in(FlowLeaveEntity::getFlowStatus, Arrays.asList(
                        FlowStatus.APPROVAL.getKey()
                ))
                .in(FlowLeaveEntity::getNodeCode,
                        flowApprovalPermissionService.getApprovalPermissionList(userVO.getUserId()),
                        !UserUtils.isAdminByUserType(userVO.getUserType())
                )
                .eq(FlowLeaveEntity::getType, param.getType(), ObjUtil.isNotEmpty(param.getType()))
                .between(
                        FlowLeaveEntity::getStartTime, param.getStartTimeStart(), param.getStartTimeEnd(),
                        ObjUtil.isNotEmpty(param.getStartTimeStart()) && ObjUtil.isNotEmpty(param.getStartTimeEnd())
                )
                .between(
                        FlowLeaveEntity::getEndTime, param.getEndTimeStart(), param.getEndTimeEnd(),
                        ObjUtil.isNotEmpty(param.getEndTimeStart()) && ObjUtil.isNotEmpty(param.getEndTimeEnd())
                )
                .eq(FlowLeaveEntity::getNodeCode, param.getNodeCode(), ObjUtil.isNotEmpty(param.getNodeCode()))
                .eq(FlowLeaveEntity::getFlowStatus, param.getFlowStatus(), ObjUtil.isNotEmpty(param.getFlowStatus()))
                .orderBy(FlowLeaveEntity::getId, false);

        Page<FlowLeaveVO> result = pageAs(param.toQueryPage(), query, FlowLeaveVO.class);
        PageData<FlowLeaveVO> pageData = PageData.of(result);
        return DictUtils.convert(pageData);
    }

其中用节点code来作为权限查询审批数据

复制代码
// 返回:["PM_A", "DM_A"]
flowApprovalPermissionService.getApprovalPermissionList(userVO.getUserId())

然后就是 项目经理审批同意

后端代码如下:

java 复制代码
    @Transaction
    @Override
    public void approval(FlowApprovalLeaveParam param) {
        FlowLeaveEntity entity = getById(param.getId());
        Assert.notNull(entity, "审批的任务不存在");
        Assert.isTrue(DelFlagEnum.NOT.getCode().equals(entity.getDelFlag()), "审批的任务不存在");
        boolean hasPermission = flowApprovalPermissionService.hasPermission(entity.getNodeCode());
        Assert.isTrue(hasPermission, "您没有权限审批流程");

        Map<String, Object> variable = flowInstanceService.getVariableMapById(entity.getInstanceId());
        Long taskId = flowTaskService.getLastIdByInstanceId(entity.getInstanceId());
        Instance instance = null;
        if (FlowApprovalEnum.PASS.getType().equals(param.getType())) {
            // 同意
            instance = FlowEngine.taskService().pass(taskId, param.getMessage(), variable);
        } else if (FlowApprovalEnum.REJECT.getType().equals(param.getType())) {
            // 拒绝
            instance = FlowEngine.taskService().reject(taskId, param.getMessage(), variable);
        } else {
            throw new BusinessException("审批类型错误:" + param.getType());
        }
        updateStatus(param.getId(), instance);// 需要将流程的节点、状态同步更新到 flow_leave 请假表
    }

查看流程详情

本次用到的warm-flow前端接口

  • 查看任务详情

    /warm-flow-ui/index.html?id=${instanceId}&type=FlowChart&onlyDesignShow=false

  • 编辑流程图

    /warm-flow-ui/index.html?id=" + 流程图的id + "&onlyDesignShow=false

  • 添加流程图

    /warm-flow-ui/index.html

相关推荐
数智工坊2 小时前
【数据结构-栈、队列、数组】3.3栈在括号匹配-表达式求值上
java·开发语言·数据结构
知我心·2 小时前
Java 正则表达式知识点总结
java
indexsunny2 小时前
互联网大厂Java面试实战:微服务与Spring生态技术解析
java·spring boot·redis·kafka·mybatis·hibernate·microservices
小疙瘩2 小时前
去掉 IDEA 中 mybatis配置文件的局部背景颜色(图解)
java·ide·intellij-idea
xqqxqxxq2 小时前
洛谷算法1-3 暴力枚举(NOIP经典真题解析)java(持续更新)
java·开发语言·算法
逝水如流年轻往返染尘2 小时前
正则表达式字符串
java·正则表达式
LYS_06182 小时前
寒假学习(14)(HAL库5)
java·linux·学习
qq_336313932 小时前
javaweb-maven单元测试
java·开发语言·maven
消失的旧时光-19432 小时前
第十三课实战版:权限系统实战:RBAC + Spring Security 从 0 到可用(含核心代码)
java·架构·rbac