用户任务

概览

用户任务(User task) 是分配给用户或用户组的一种任务类型,在业务流程中需要手动完成。 用户任务是业务流中不可或缺的内容,参与者可以通过执行特定操作、 做出决策或提供输入的方式和流程进行交互。

单一执行人和分组

在 BPMN 中,只有执行人才能执行其中的任务。 当我们说“任务分配给了某个用户组”, 其实是表示这里的一组 潜在的执行人,而不是说执行人是一个 UserGroup 对象。 分组的某个人通过 领取 任务而成为真正的执行人。

图形表示法

用户任务在图中显示为一个典型的任务(圆角矩形),左上角有一个小的用户图标。

user task
XML 表示

用户任务在 XML 中的定义如下。 其中 id 属性必需,name 属性可选。

<userTask id="user-task-01" name="User task" />

属性

除了通用属性之外,用户任务还有下列特殊属性:

  • Due Date 提醒执行人任务的过期时间。

  • Assignee,可为任务分配单个执行者或可能的执行人(候选人);

  • Form,定义任务的用户界面;

  • Task Listeners,添加任务生命周期事件触发的监听器。

到期时间

用户任务中的 due date 参数指定任务必须完成的截止日期。 该参数对于管理业务流程中的时间敏感型活动至关重要。

设置截止日期不会启动任何自动操作。需要手动配置后续的操作。

设置到期时间

Due date 支持两种类型的设置:

  • 固定日期:填写将来的一个到期时间。 (如果填写的是过去的时间,则该时间会被忽略,任务显示已过期)。

  • 时长:从任务创建开始计算的一个时长。

事实上,到期时间的字段是一个文本框,流程引擎在运行时对其内容进行解析。 支持以下格式:

  • ISO8601 格式的文本字符串,表示固定日期或持续时间。

  • 以下类型的流程变量:

    • java.lang.String — 必须包含 ISO8601 格式的值。

    • java.util.Date — 必须包含日期值。

  • 在运行时可以解析为上述类型之一的表达式,例如 $/{someDateVariable/}

  • 变量值为 null 并不会导致错误。而是表示任务没有指定截止日期。

  • 流程部署期间不会验证该参数。 但不正确的值将在运行时导致错误。

ISO 8601 示例

  • 固定时期时间:

    • 2024-02-01T08:40:37

    • 2050-01-01

  • 时长:

    • PT20M - 20 分钟

    • PT5H - 5 小时

    • PT3D - 3 天

编程时处理到期时间

到期时间参数可以通过 Task 类的方法处理:

Task task = taskService.createTaskQuery()
                .taskId("taskId").singleResult(); (1)
task.getDueDate(); (2)
task.setDueDate(null); (3)
taskService.saveTask(task); (4)
1  — 通过 ID 获取任务
2  — 获取到期时间
3  — 设置新的到期时间为 null
4  — 保存任务对象。

因此,可以根据业务逻辑动态修改任务的到期时间。 例如,任务的执行人可以申请将任务延时处理。

使用工作日历

项目中如果安装了 工作日历 扩展组件, 在 Web BPM 建模器General 部分会显示如下内容:

busines calendar

这里可以从下拉列表中选择一个已配置的工作日历。 此时,只能将截止日期设置为持续时长,并且将根据工作日历计算经过的时间。

例如,用户在下午 4:00 收到了任务。 在工作日历中,标准的工作时间设置为上午 10:00 至下午 6:00, 而截止日期参数设置为 3 小时 (PT3H)。

在考虑了工作日历后,截止日期不会设置为晚上的 7:00,而会设置为第二个工作日的早上 7:00。 使用了工作日历后,仅计算工作时间。

使用工作日历时,时长只能按小时和分钟设置,不能按天设置。

XML 表示

带截止时间的用户任务:

<userTask id="Activity_0gsy9yk" name="User task"
    flowable:dueDate="PT3H" (1)
    flowable:businessCalendarName="test-calendar"> (2)
. . .
</userTask>
1  — 时长类型的截止时间
2  — 工作日历属性

详情请参阅 工作日历 扩展组件。

分配用户

任务要有执行人才能最终完成。 一个任务只能有 一个 执行人,此用户称为 assignee

assignee 属性可以为空,即,没有用户可以在任务列表中看到此任务。 当设置了潜在执行人或 candidates 的列表时,此类任务通常被视为 分组任务。 此外,还可以使用管理页面或以编程方式在运行时设置执行人。

执行人来源

在 Jmix BPM 中,执行人来源(assignee source)是指一种在流程中选择用户作为任务执行人的机制。 有三种选项:

Expression

- 表达式。必须返回字符串,包含 username。

Process variable

- 流程变量。指向一个 User 实体的流程变量。

User provider

- 一个特定的 Java 类,带有返回 username 的方法。

assignee sources

表达式

表达式是默认的执行人来源。 需要编写一个表达式来获取执行人的 username。 例如,User 实体存在名为 manager 的流程变量中,则表达式可以是 ${manager.username}

assign by expression
XML 表示
<userTask id="user-task-01" name="User task"
    flowable:assignee="${manager.username}"
    jmix:assigneeSource="expression"
    jmix:assigneeValue="${manager.username}" />

如果需要将一个任务直接分配给特定的用户,这里可以直接写该用户的 username:

assigne by expression direct

另外,也可以调用 Spring bean 的方法返回 username:

${smpl_MyBean.evaluateManager(methodParam1, 'methodParam2')}

流程变量

如果选择 Process variable 执行人源,则属性面板中将显示一个 ComboBox。其中可以选择 Entity 类型的字段和流程变量,这些实体类还要求实现了 UserDetails 接口。

预置的 initiator 变量

预置的 initiator 流程变量可以在建模时用来分配任务。包含启动流程的用户实体:

assignee initiator
XML 表示

下面是使用流程变量分配任务的示例:

<userTask id="user-task-01" name="User task"
    camunda:assignee="${initiator.username}"
    jmix:assigneeSource="processVariable"
    jmix:assigneeValue="initiator" />

如果流程是通过 API 或消息/信号启动的,则 initiator 变量未定义。 贸然使用会导致运行时错误。

可以通过下面的应用程序属性禁用 initiator 变量:

jmix.bpm.process-initiator-variable-enabled=false

还可以修改发起人属性的名称:

jmix.bpm.process-initiator-variable-name=manager

User Provider

如果需要通过复杂的逻辑确定任务的执行人,则建议使用 User provider. 此时,系统会加载已有的 user provider Java 类以供选择:

selecting user provider

User Provider 中需要包含一个或多个 String 返回类型的方法。 方法获取在建模器中指定的参数值,并返回可以作为任务执行人的用户名。

XML 表示

使用 User provider 的用户任务:

<userTask id="user-task" name="User task" jmix:assigneeSource="userProvider" jmix:assigneeValue="smpl_MyUserProvider">
  <extensionElements>
    <jmix:springBean beanName="smpl_MyUserProvider" methodName="getUser" />
  </extensionElements>
</userTask>

User provider 类是一个普通的 Spring bean,带有 @UserProvider 注解。 下面是一个 user provider 的示例,其中的方法会根据用户 email 的流程变量从数据库加载用户。

@UserProvider(value = "smpl_MyUserProvider", description = "Returns a user with the specified email")
public class MyUserProvider {

    @Autowired
    private DataManager dataManager;

    public String getUserByEmail(String parameter) {
        return dataManager.load(User.class)
                .query("select u from smpl_User u where u.email = :email")
                .parameter("email", parameter)
                .one()
                .getUsername();
    }
}

UserProvider 类中可以实现任意的业务逻辑。 例如,可以从角色或部门中选择一个不太忙的用户;选择下一个轮到的用户;或者从候选人里选择一个随机用户等。

编程式分配任务

如需编程式设置任务的执行人,可以使用 TaskServicesetAssignee 方法。示例:

Task task = taskService.createTaskQuery()
                       .taskId("taskId")
                       .singleResult(); (1)

taskService.setAssignee(task.getId(), "jane"); (2)
1 通过 Query API 获取任务
2 通过 username 指定执行人

获取特定用户以分配的任务,可以用 TaskService 的下列方法:

List<Task> tasks = taskService.createTaskQuery()
    .taskAssignee("jane") (1)
    .list();
1 username

候选用户和组

候选(Candidates) 表示可以领取/完成任务的用户和用户组(groups)。 当一个任务有多个候选人时,该任务会在所有候选人的任务列表展示。 第一个领取任务的候选人变成任务的执行人,并可以完成任务。 之后,其他候选人的任务列表中该任务不可见。

这里 “groups” 表示一组 User group 的编码。

领取组内任务

一种常见的情况是,我们不需要某个特定的用户去执行任务。 例如,对于一个经理来说,具体那个会计对他下达的命令做出决定并不重要。

在这种情况下,Jmix BPM 可以将任务分配给 候选人组 — 其中的任何成员都可以成为任务的执行人。 但该成员必须先领取任务。 领取任务是用户对任务所有权的一个操作。

有多个候选人的的任务会显示在每个候选人组任务(Group tasks)菜单的 我的任务(My tasks) 视图中。

my tasks claim

在任何候选人领取任务后,该任务将移至此用户的 已分配任务(Assigned tasks) 列表中,并从其他候选人的 组任务 表中移除。

claiming form

领取任务是,用户必须打开任务并执行以下操作之一:

  • 领取并继续(Claim and resume) - 用户成为任务执行人,任务表单将以正常模式重新打开,该用户可以继续填写表单。

  • 领取并关闭(Claim and close) - 用户成为任务执行人后关闭表单;该用户可以稍后在任务列表的 已分配任务 部分中找到该任务:

my tasks claimed task

编程式领取任务

通过 API 也可以为用户领取任务:

taskService.claim("taskId", "userId");

在建模器中设置候选人

点击下图所示的按钮可以编辑候选人组:

web modeler candidate groups

在打开的 候选人组编辑器 中,可以选择组的来源:

candidate groups sources
  • User groups - 从列表中选择用户组

  • User groups provider — 选择一个能返回用户组列表的特定 Java 类。

  • Expression — 从表达式返回用户组列表,例如,使用之前定义的流程变量。

用户组设置

If you have chosen a User groups option as a source, you can select any from existing user groups:

selecting candidate grouos

用户组 Provider

如果需要通过复杂的逻辑设置候选人组,最好选择 User groups provider 选项。

selecting user group provider

这种方式可以选择已创建的带有 @UserGroupListProvider 注解的一个 Java bean。 Bean 必须实现一个或多个返回 List<String> 表示用户组编码的方法。

@UserGroupListProvider 注解有两个属性:

  • value — 在建模器中显示的名称。

  • description — 方法说明,可选。

示例:

@UserGroupListProvider(value="allGroups",
                       description = "Returns a list of all groups")
public class MyGroupListProvider {

    @Autowired
    private UserGroupService userGroupService;

    public List<String> getAllUserGroups() {
        List<UserGroup> allUserGroups = userGroupService.getAllUserGroups();
        if (!allUserGroups.isEmpty()) {
            return allUserGroups.stream().map(UserGroup::getCode).toList();
        } else {
            return Collections.emptyList();
        }
    }
}

参阅 用户组 章节了解更多内容。

表达式设置

设置 BPMN 参数最通用的方法是表达式。 候选组也可以使用该方法:

candidate groups expression

候选用户选项

Web BPM 建模器 中设置候选用户与设置候选组类似。 以下是可以选择的来源:

candidate users options
  • Users — 从列表中选择用户

  • Users provider --选择一个能返回用户名列表的特定 Java 类。

  • Expression — 从表达式返回用户名列表。

用户列表 Provider

用户组 Provider 类似,可以通过编程方式获取候选用户列表, 对应的 Spring bean 需要带 @UserListProvider 注解:

candidate user list provider

示例:

@UserListProvider(value = "smpl_UserListProviderDemo",
                  description = "Get all users")
public class UserListProviderDemo {

    @Autowired
    private DataManager dataManager;
    @Autowired
    private SystemAuthenticator authenticator;

    public List<String> getAllUsers() {
        authenticator.begin();
        try {
            List<User> users = dataManager.load(User.class).all().list();
            return users.stream().map(User::getUsername).toList();
        } finally {
            authenticator.end();
        }
    }
}

表达式设置

可以使用流程模型中最通用的参数设置方法 — 表达式:

candidate users expression

例如,使用下面的表达式可以获取流程发起人的用户名:

${initiator.username}

同一个用户任务可以同时定义候选用户和候选用户组。

用户任务流程表单

用户任务可以配置一个 流程表单,协助执行人输入任务所需的数据。收集的数据可以在之后的流程中传递。

多实例

用户任务可以是多实例的。 详情请参阅 多实例活动 部分。

设置任务监听器

Jmix BPM 中的用户任务支持通过任务监听器对特定的事件执行自定义逻辑。 在用户任务触发特定的事件时, 任务监听器中的 Java 类或表达式将执行。

task listeners field

用户任务支持的事件监听器包括:

  • create:当用户任务创建时触发

  • assignment:当用户任务分配给一个用户或用户组时触发

  • complete:当完成用户任务时触发。

  • delete:当删除用户任务时触发。

如需为用户任务配置监听器,可以在 BPMN XML 中使用 flowable:taskListener 扩展元素, 或者用 addTaskListener Java API。

任务监听器为用户任务提供了一种强大的扩展机制, 可以在流程中集成自定义逻辑。 例如发送通知、更新外部系统, 或根据用户任务生命周期中的事件做额外的验证等等。

XML 表示
<userTask id="approve-invoice" name="Approve invoice" jmix:assigneeSource="expression">
  <extensionElements>
    . . .
    <flowable:taskListener class="com.company.demo.listener.ApproverAssignment" (1)
                           event="assignment" /> (2)
  </extensionElements>
 . . .
</userTask>
1 任务监听器类
2 任务事件

详情请参阅 任务监听器

文档

为了给用户提供额外的信息,在 BPMN 中可以使用 documentation 参数,或在 API 中使用 description。 描述的长度不能超过 4000 个字符。

documentation 字段的原来用法是分析师在建模时为流程写的说明。 但是在 用户任务 中,可以作为任务的说明,告诉用户该如何完成任务。

该字段在属性面板的底部。

可以在每次修改流程后都更新一下 documentation 字段。 这是为用户提供及时准确信息的最简单方法。