Skip to content

6 任务管理

6.1 任务流程管理

6.1.1 流程定义

流程图设计器基于bpmn.js

官网地址:https://bpmn.io/

bpmn相关参数、方法介绍(csdn):https://blog.csdn.net/a843334549/article/details/109200370

6.1.1.1 流程设计页面布局

工具栏:快捷选择节点

流转图:配置流程流转信息

属性栏:用户在点击流程图节点, 能获取到该节点的属性信息,并且配置相关信息

1

ps:下面主要基于重要流程节点和对应属性配置进行介绍

6.1.1.2 配置流程信息

点击流程图空白页面(如下图)即可对当前流程信息进行配置,包括流程名称、分类等信息。

2

6.1.1.3 配置申请人节点

3

ps:选中申请人节点后,那么任务配置里面审批类型选择指定用户,具体的任务执行人选择流程发起人

4

6.1.1.4 配置任务节点

ps:这里以用户任务节点为说明,其它类型配置参考此信息
6.1.1.4.1 常规配置
  • 节点ID,在整个流程中的唯一编号
  • 节点名称,当前节点的显示名称
  • 节点描述,节点备注信息

修改相应的信息后会同步至面板和xml中

5

6.1.1.4.2 任务配置
  • 审批类型,指定当前任务节点的接收人或组(角色,部门等)
6.1.1.4.2.1 审批类型

审批类型目前分为三种形式:

  1. 指定人员(assignee):用于直接将用户指派为任务的执行/接收者,只能指定一个用户,在其他人的任务列表中不可见,而只能在该办理人的个人任务列表中看到。
  2. 候选人员(candidateUsers):为任务分配多个候选人,每个用户都可在待办任务列表中查看到当前任务,当任一用户签收任务后,任务才会从其它用户待办列表中移除。
  3. 候选角色(candidateGroups):为任务分配多个候选角色,每个角色下的所属用户都可在待办任务列表中查看到当前任务,当任一用户签收任务后,任务才会从其它用户待办列表中移除。

6

6.1.1.4.2.2 任务接收
  • 基础配置

    指定任务接收用户/角色目前分为两种形式:

    1. 固定选择(fixed):这里指的是在流程设计时就选择好当前任务节点需要由谁来对任务进行处理。
    2. 动态选择(dynamic):通过选择内置表达式形式,指定当前任务节点的处理人需要由上一步任务处理人来选择由谁接收。举例说明:行政节点任务处理时,需要手动选择它的下一步节点,老板节点由谁(老板1、老板2、老板3,其中任选一个、多个)接收,再提交任务。

    7

    固定审批人

    8

    选择表达式

  • 扩展配置
任务接收“表达式”具有高度扩展性:
1. 设置任务审批人为上级审批
2. 设置任务审批人为某部门人员
3. 其它实现

现在以“设置任务审批人为上级审批”为例,讲解在项目中如何实现

9

图中行政节点任务接收人是动态的表达式,老板节点直接可以使用该参数进行传递,后端代码中对应的方法参数就可获取到行政节点审批人ID,再根据该获取对应的上级

10

6.1.1.4.3 监听配置
  • 执行监听器(executionListener)可以在流程执行中发生特定的事件时,执行外部Java代码或计算表达式。
  • 任务监听器(taskListener)用于在特定的任务相关事件发生时,执行自定义的Java逻辑或表达式。

11

6.1.1.4.3.1 执行监听器

执行监听器(executionListener)可以在流程执行中发生特定的事件时,执行外部Java代码或计算表达式。

可以被捕获的事件有:

  • 流程实例的启动和结束。
  • 流程执行转移。
  • 活动的启动和结束。
  • 网关的启动和结束。
  • 中间事件的启动和结束。
  • 启动事件的结束,和结束事件的启动。

下面的流程定义包含了三个执行监听器:

xml
<!--执行监听器xml示例-->
<process id="executionListenersProcess">

  <extensionElements>
    <flowable:executionListener
      class="org.flowable.examples.bpmn.executionlistener.ExampleExecutionListenerOne"
      event="start" />
  </extensionElements>

  <startEvent id="theStart" />
  <sequenceFlow sourceRef="theStart" targetRef="firstTask" />

  <userTask id="firstTask" />
  <sequenceFlow sourceRef="firstTask" targetRef="secondTask">
    <extensionElements>
      <flowable:executionListener
        class="org.flowable.examples.bpmn.executionListener.ExampleExecutionListenerTwo" />
    </extensionElements>
  </sequenceFlow>

  <userTask id="secondTask" >
    <extensionElements>
      <flowable:executionListener
        expression="${myPojo.myMethod(execution.event)}"
        event="end" />
    </extensionElements>
  </userTask>
  <sequenceFlow sourceRef="secondTask" targetRef="thirdTask" />

  <userTask id="thirdTask" />
  <sequenceFlow sourceRef="thirdTask" targetRef="theEnd" />

  <endEvent id="theEnd" />

</process>

实现org.flowable.engine.delegate.ExecutionListener接口

java
//class类示例
public class FlowExecutionListener implements ExecutionListener {
    /**
	* 流程设计器添加的参数
	*/
    private Expression param;

    @Override
    public void notify(DelegateExecution execution) {
        // log.info("执行监听器:{}", execution);
        // Do something 
    }
}

项目中提供两种任务监听器配置方式:

  1. 内置监听器:需提前在流程监听模块中定义好执行监听器,流程设计时直接选择启用。
  2. 自定义监听器:流程设计时手动新增监听器。

12

自定义监听器

13

内置监听器

6.1.1.4.3.2 任务监听器

任务监听器(taskListener)只能在流程定义中作为用户任务的子元素。请注意,任务监听器是一个Flowable自定义结构,因此也需要作为BPMN 2.0 extensionElements的子元素并且放在flowable命名空间下。

xml
<!--任务监听器xml示例-->
<userTask id="myTask" name="My Task" >
  <extensionElements>
    <flowable:taskListener event="create" class="org.flowable.MyTaskCreateListener" />
  </extensionElements>
</userTask>

任务监听器包含下列属性:

  • event(事件)(必填):触发任务监听器的任务事件类型。可用的事件有:

    • create(创建):当任务已经创建,并且所有任务参数都已经设置时触发。
    • assignment(指派):当任务已经指派给某人时触发。请注意:当流程执行到达用户任务时,在触发create事件之前,会首先触发assignment事件。这顺序看起来不太自然,但是有实际原因的:当收到create事件时,我们通常希望能看到任务的所有参数,包括办理人。
    • complete(完成):当任务已经完成,从运行时数据中删除前触发。
    • delete(删除):在任务即将被删除前触发。请注意任务由completeTask正常完成时也会触发。
  • class:需要调用的委托类。这个类必须实现org.flowable.engine.delegate.TaskListener接口。

java
//class类示例
public class FlowTaskListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        // log.info("任务监听器:{}", delegateTask);
        // TODO  获取事件类型 delegateTask.getEventName(),可以通过监听器给任务执行人发送相应的通知消息
    }
}
  • expression:(不能与class属性一起使用):指定在事件发生时要执行的表达式。可以为被调用的对象传递DelegateTask对象与事件名(使用task.eventName)作为参数。
xml
<!--expression示例-->
<flowable:taskListener event="create" 
  					expression="${myObject.callMethod(task, task.eventName)}" />
  • delegateExpression:指定一个能够解析为TaskListener接口实现类的对象的表达式。
xml
<!--delegateExpression示例-->
<flowable:taskListener event="create"
  					delegateExpression="${myTaskListenerBean}" />

项目中提供两种任务监听器配置方式:

  1. 内置监听器:需提前在流程监听模块中定义好任务监听器,流程设计时直接选择启用。
  2. 自定义监听器:流程设计时手动新增监听器。

14

内置任务监听器

15

自定义任务监听器

6.1.1.4.4 其他配置
6.1.1.4.4.1 表单配置

任务节点配置表单后,表示在流程任务运转过程中该节点需要单独填写的表单信息

16

节点表单配置

6.1.1.4.4.2 多实例配置

实例(multi-instance )(会签)是在业务流程中,为特定步骤定义重复的方式。在编程概念中,多实例类似for each结构:可以为给定集合中的每一条目,顺序或并行的执行特定步骤。网关与事件不能设置为多实例。

三条短线表示。三条竖线代表实例会并行执行,而三条横线代表顺序执行

  • 回路特性(isSequential),代表了活动的实例为顺序还是并行执行
  • 循环基数(loopCardinality),List循环次数,一般不使用,建议不填写。
  • 集合(collection),传入List参数, 一般为用户ID集合
  • 元素变量(elementVariable),List中单个参数的名称
  • 完成条件(completionCondition),任务出口条件
  • 异步状态:暂未使用

多实例配置时,由于需要动态选择会签的人员,所以在多实例任务配置时,默认设置成表达式形式

17

多实例节点任务接收人固定配置表达式选项

多实例配置中的元素变量参数对应表达式里面配置的参数,复制过来即可

18

xml
<!--配置成功后xml示例-->
<multiInstanceLoopCharacteristics isSequential="true" flowable:exclusive="false" flowable:collection="userList" flowable:elementVariable="approval">
  <loopCardinality xsi:type="tFormalExpression">1</loopCardinality>
  <completionCondition xsi:type="tFormalExpression">${nrOfCompletedInstances &gt;= 2}</completionCondition>
</multiInstanceLoopCharacteristics>

按照BPMN2.0规范的要求,用于为每个实例创建执行的父执行,会提供下列变量:

参数描述
collection(集合变量)传入List参数, 一般为用户ID集合
elementVariable(元素变量)List中单个参数的名称
loopCardinality(基数)List循环次数
isSequential(串并行)Parallel: 并行多实例,Sequential: 串行多实例
completionCondition(完成条件)任务出口条件
nrOfInstances(实例总数)实例总数
nrOfActiveInstances(未完成数)当前活动的(即未完成的),实例数量。对于顺序多实例,这个值总为1
nrOfCompletedInstances(已完成数)已完成的实例数量
loopCounter给定实例在for-each循环中的index
6.1.1.4.4.3 流转条件配置
  • 普通流转路径,流程执行过程中,一个元素被访问后,会沿着其所有出口顺序流继续执行。
  • 默认流转路径,只有当没有其他顺序流可以选择时,才会选择默认顺序流作为活动的出口顺序流。流程会忽略默认顺序流上的条件。
  • 条件流转路径,是计算其每个出口顺序流上的条件。当条件计算为true时,选择该出口顺序流。如果该方法选择了多条顺序流,则会生成多个执行,流程会以并行方式继续。

流程条件表示从当前任务到下一任务节点直接流转需要满足条件后才能正常运转

19

6.1.1.4.4.4 扩展属性

自定义流程任务节点属性名称和属性值

20

  • 写入自定义扩展属性后xml示例
xml
<!--扩展属性xml-->
<userTask id="Activity_0wlo0x2" name="任务1">
  <extensionElements>
    <flowable:properties>
      <flowable:property name="name" value="zhangsan" />
    </flowable:properties>
  </extensionElements>
</userTask>
  • 后端读取自定义属性值
java
//FlowableUtils.java
/**
 * 获取当前任务节点扩展属性信息
 *
 * @param repositoryService
 * @param task 当前任务
 * @return 自定义属性列表
*/
public static List<Object> getPropertyElement(RepositoryService repositoryService, org.flowable.task.api.Task task) {
    FlowElement flowElement = getCurrentElement(repositoryService, task);
    ExtensionElement extensionElement = FlowableUtils.getExtensionElementFromFlowElementByName(flowElement, "properties");
    if (extensionElement == null) {
        return Collections.emptyList();
    }
    return FlowableUtils.getPropertyExtensionElementByName(extensionElement, "property");
}

6.1.2 表单配置

在线表单设计一个低代码表单,详细使用文档可以参考Vformhttps://www.vform666.com/vform3/

21

ps:下面基于日常使用提供一些常用使用方法和配置以供参考

6.1.2.1 表单内部字段事件交互

已选择时间后,自动计算时间差为例:

22

编写表单全局函数

javascript
//计算时间间隔
function calculateDateInterval (dateRegion) {
  var day1 = dateRegion[0];
  var day2 = dateRegion[1]
  let startTime = new Date(day1); // 开始时间
  let endTime = new Date(day2); // 结束时间
  var dateInterval = endTime.getTime() - startTime.getTime()  //获取时间差毫秒
  // //计算出相差天数
  var days = Math.floor(dateInterval / (24 * 60 * 60 * 1000));
  return days;
}

编写时间组件的onChange()方法

23

事件处理方法

javascript
//实现js
var dateTime = this.getWidgetRef('day');
dateTime.setValue(window.calculateDateInterval(value));
dateTime.setDisabled(true);

6.1.2.2 表单内部按钮获取表单数据对象

通过点击表单内部按钮获取到整个表单对象值,如下:

24

获取对象值

javascript
//按钮click事件添加
var formData = this.formModel;

6.1.2.3 文件、图片上传

实现文件、图片上传需要注意两个点:

  1. 配置后端的上传地址
  2. 后台上传接口需要token信息时,这时候就需要去Cookie中查找到当前用户的token,并且设置到上传文件的请求中

25

添加对应方法

javascript
//添加js方法
var currentWidget = this;
var token = getCookie("Admin-Token");
currentWidget.setUploadHeader('Authorization', 'Bearer ' + token);

// 获取token
function getCookie(cookieName) {
  var strCookie = document.cookie;
  var arrCookie = strCookie.split("; ");
  for(var i = 0; i < arrCookie.length; i++){
    var arr = arrCookie[i].split("=");
    if(cookieName == arr[0]){
      return arr[1];
    }
  }
  return "";
}

6.1.2.4 点击按钮后赋值给文本框

点击按钮后把从后台接口获取的数据赋值给表单中某一组件

26

按钮点击赋值

javascript
//按钮click事件
var test = this.getWidgetRef('test')
axios.get('https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/getCity').then(function(res) {
  test.setValue(res.data.data[1].label)
}).catch(function(error) {
  console.error(error)
})

6.1.2.5 上传图片、文件回显

上传图片、文件成功后,表单页面进行回显

27

赋值响应数据

6.1.2.6 后台接口传参

调用后台接口需要传入参数

28

填写接口参数

javascript
//js方法示例
var citySelectR = this.getWidgetRef('citySelect')
const config = {
  headers: {
    Authorization: 'Bearer ' + window.getCookie("Admin-Token")
  }
}
const params = {
  id: '123',
  name: '张三'
}
// get
// const url = 'https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/getCity';
// axios.get(url,{ params:{id: '123',name: '张三'} },config).then(function(res) {
//   citySelectR.setValue(res.data.data)
// }).catch(function(error) {
//   console.error(error)
// })

// post
const url = 'https://www.fastmock.site/mock/2de212e0dc4b8e0885fea44ab9f2e1d0/vform/getCity';
axios.post(url,{id: '123',name: '张三'},config).then(function(res) {
  citySelectR.setValue(res.data.data)
}).catch(function(error) {
  console.error(error)
})

6.1.3 流程表达式

流程表达式主要用于 流程设计-用户任务审批配置,便于实现动态分配任务,表达式可配置为值表达式(UEL-value)和方法表达式(UEL-method)两种类型。

29

表达式配置列表

6.1.3.1 指定类型

用户前端验证是否需要弹窗出审批人选择页面

  • 系统指定

表示该表达式的值由后端代码处理或者其他方式已经赋值,不再需要用户手动选择

  • 动态选择

表示该表达式的值需要用户手动选择赋值,即在审批当前任务时,又审批人指定下一步任务的接收人

6.1.3.2 表达式

  • 值表达式解析结果为一个值。默认情况下,所有流程变量都可以在表达式中使用。此外,如果Flowable集成了Spring环境,则所有spring-beans都可以在表达式中使用,例如:
java
//表达式
//使用流程变量
${userName}
//使用spring-bean的属性
${userBean.userName}
  • 方法表达式可以调用不带或带有参数的方法。调用不带参数的方法时,需确保在方法名称后添加空括号(用于将表达式与值表达式区分开);调用带有参数的方法时,传递的参数可以是文字值或自行解析的表达式,例如:
java
//表达式
//调用不带参数的方法
${taskAssigneeBean.getMangerOfProcessInitiator()}
//调用带有参数的方法
${taskAssigneeBean.getMangerOfDeptId("EP", execution)}
不论是值表达式,还是方法表达式,均支持解析和比较原始类型(primitive)、Java Bean、列表(list)、数组(array)和映射(map)。这些表达式可以使用所有流程变量,同时Activiti还允许使用一些默认对象。
1.  execution:当前正在运行的执行实例的DelegateExecution对象。
2.  task:当前正在操作的任务实例的DelegateTask对象,仅在任务监听器求值表达式中有效。
3.  authenticatedUserId:当前已认证的用户的唯一标识,如果没有用户通过身份验证,则该变量不可用。

6.1.4 流程监听

详见6.1.1.4.3 监听配置,不再重复

6.2 已发任务

在已发任务列表中,选择发起任务按钮后,会提供流程任务,选择某个任务即可发起流程任务

30

在流程发起页面,填写完当前任务所需的表单信息后(图1),点击提交按钮,如果在流程设计时,申请人的下一节点配置的是表达式(表示需要动态选择任务接收人),此时需要手动选择下一节点的审批人(图2)。

31

图1,填写表单发起申请

32

图2 手动选择下一步任务接收人

6.3 代办任务

显示当前登录用户作为任务的指定处理人、候选处理人、候选角色时的待办任务信息。

33

点击任务办理后,可以查看流程表单信息,流转记录,流程图。

34

表单信息

35

流转记录

36

流程图

6.4 已办任务

显示当前用户登录已审批过的所有流程任务。可以点击 “流转记录” 按钮查看任务的业务数据、流转记录和审批信息。

37

MIT License.