一.简介
建议在 Spring Boot 的 application.properties 中添加如下配置,开启 flowable 日志,一定要是debug 模式:
logging.level.org.flowable=debug
yml文件写法:
logging:
# config: classpath:logconfig/logback.xml
level:
root: info
com.alibaba.nacos.client.naming: WARN
com.alibaba.nacos.client.config.impl: WARN
# 增加flowable 底层打印sql
org.flowable: debug
设置完这个控制台会一直打印 -- 待解决
2023-11-24 13:28:05,076 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.common.engine.impl.interceptor.LogInterceptor - --- starting AcquireTimerJobsCmd --------------------------------------------------------
2023-11-24 13:28:05,076 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.common.spring.SpringTransactionInterceptor - Running command with propagation REQUIRED
2023-11-24 13:28:05,083 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.common.engine.impl.agenda.AbstractAgenda - Operation class org.flowable.engine.impl.interceptor.CommandInvoker$1 added to agenda
2023-11-24 13:28:05,083 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.engine.impl.interceptor.CommandInvoker - Executing operation class org.flowable.engine.impl.interceptor.CommandInvoker$1
2023-11-24 13:28:05,083 [flowable-bpmn-acquire-timer-jobs] DEBUG o.f.j.s.impl.persistence.entity.TimerJobEntityImpl.selectTimerJobsToExecute - ==> Preparing: SELECT RES.* from ACT_RU_TIMER_JOB RES where SCOPE_TYPE_ is null and DUEDATE_ <= ? and LOCK_OWNER_ is null order by RES.ID_ asc LIMIT ? OFFSET ?
2023-11-24 13:28:05,084 [flowable-bpmn-acquire-timer-jobs] DEBUG o.f.j.s.impl.persistence.entity.TimerJobEntityImpl.selectTimerJobsToExecute - ==> Parameters: 2023-11-24 13:28:05.083(Timestamp), 512(Integer), 0(Integer)
2023-11-24 13:28:05,093 [flowable-bpmn-acquire-timer-jobs] DEBUG o.f.j.s.impl.persistence.entity.TimerJobEntityImpl.selectTimerJobsToExecute - <== Total: 0
2023-11-24 13:28:05,093 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.common.engine.impl.db.DbSqlSession - Flushing dbSqlSession
2023-11-24 13:28:05,093 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.common.engine.impl.db.DbSqlSession - flush summary: 0 insert, 0 update, 0 delete.
2023-11-24 13:28:05,093 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.common.engine.impl.db.DbSqlSession - now executing flush...
2023-11-24 13:28:05,105 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.common.engine.impl.interceptor.LogInterceptor - --- AcquireTimerJobsCmd finished --------------------------------------------------------
2023-11-24 13:28:05,105 [flowable-bpmn-acquire-timer-jobs] DEBUG org.flowable.job.service.impl.asyncexecutor.AcquireTimerJobsRunnable - timer job acquisition thread for engine bpmn sleeping for 10000 millis
FindExpiredJobsCmd finished --------------------------------------------------------

flowable一直查询定时任务act_ru_timer_job问题 ,解决方式:
async-executor-activate: false # 设置这个就不打印
flowable:
# 1. false: 默认值,Flowable 启动时,对比数据库表中保存的版本,如果不匹配。将抛出异常
# 2. true: 启动时会对数据库中所有表进行更新操作,如果表存在,不做处理,反之,自动创建表
# 3. create_drop: 启动时自动创建表,关闭时自动删除表
# 4. drop_create: 启动时,删除旧表,再创建新表
database-schema-update: false # 设置为 false,可通过 https://github.com/flowable/flowable-sql 初始化
db-history-used: true # flowable6 默认 true 生成信息表,无需手动设置
check-process-definitions: false # 设置为 false,禁用 /resources/processes 自动部署 BPMN XML 流程
history-level: full # full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数
async-executor-activate: false # 设置这个就不打印

flowable:
async-executor-activate: false
dmn:
enabled: false
idm:
enabled: false
ldap:
enabled: false
form:
enabled: false
database-schema-update: true
history-level: full
management:
endpoint:
flowable:
enabled: false
参考链接:https://www.cnblogs.com/zhaodefu/p/17717921.html
这个配置表示开启 flowable 的日志,开启日志的好处是可以看到底层的 SQL语句。
二.查询部署信息
例如查询流程的部署信息,代码如下:
@Test
void test01() throws IOException {
List<Deployment> list = repositoryService.createDeploymentQuery().list();
for (Deployment deployment : list) {
logger.info("id:{};key:{}", deployment.getId(), deployment.getKey());
}
}
创建一个查询器,然后返回所有的流程部署信息并打印出来,此时看下 IDEA 控制台打印出来的 SQL 信息:

可以看到,底层执行的 SQL 其实就是去查询 ACT_RE_DEPLOYMENT 表。

从上图中可以看到,利用流程部署的名字、分类、ID 等各种信息去查询,可以精确匹配也可以模糊匹配。
例如:查询 key 为 javaboy的工作流key 的流程部署文件,但是这个流程我之前部署过多次(版本升级),现在我想查询最近一次的流程部署信息,代码如下:
@Test
void test01() throws IOException {
Deployment deployment = repositoryService.createDeploymentQuery().deploymentKey("javaboy的工作流key").latest().singleResult();
logger.info("id:{};key:{}", deployment.getId(), deployment.getKey());
}
看下控制台打印出来的 SQL:
--- [ main] i.p.e.D.selectDeploymentsByQueryCriteria : ==> Preparing: SELECT RES.* from ACT_RE_DEPLOYMENT RES WHERE RES.KEY_ = ? and RES.DEPLOY_TIME_ = (select max(DEPLOY_TIME_) from ACT_RE_DEPLOYMENT where KEY_ = RES.KEY_ and DERIVED_FROM_ is null and ( (TENANT_ID_ IS NOT NULL and TENANT_ID_ = RES.TENANT_ID_) or (TENANT_ID_ IS NULL and RES.TENANT_ID_ IS NULL) ) ) order by RES.ID_ asc
--- [ main] i.p.e.D.selectDeploymentsByQueryCriteria : ==> Parameters: javaboy的工作流key(String)
--- [ main] i.p.e.D.selectDeploymentsByQueryCriteria : <== Total: 1
这个 SQL 写的有点复杂,但是仔细看就一个意思,给定查询的 key 是 javaboy的工作流key,查询时间是一个最大的时间,这就很好懂了。
三.查询流程定义信息
查询所有的流程定义信息,代码如下:
@Test
void test02() {
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
for (ProcessDefinition pd : list) {
logger.info("id:{};key:{};version:{};",pd.getId(),pd.getKey(),pd.getVersion());
}
}
看下控制台打印的 SQL:

可以看到,就是去流程定义表 ACT_RE_PROCDEF 去查看所有。
基于此,其他的查询 API 就都好理解了,例如:根据流程定义的 KEY 去查询所有的流程定义,这个 KEY 其实就是流程定义 XML 文件中的 id:
@Test
void test02() {
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("javaboy_submit_an_expense_account").list();
for (ProcessDefinition pd : list) {
logger.info("id:{};key:{};version:{};",pd.getId(),pd.getKey(),pd.getVersion());
}
}
看下控制台打印的 SQL:

其他的查询 API 也是类似的。
四.原生查询
我们也可以自己写 SQL 查询。
跟前面一样,例如我想查询 key 为 javaboy的工作流key 的流程部署文件,但是这个流程我之前部署过多次(版本升级),现在我想查询最近一次的流程部署信息,查询代码如下:
@Test
void test03() {
Deployment deployment = repositoryService.createNativeDeploymentQuery().sql("SELECT RES.* from ACT_RE_DEPLOYMENT RES WHERE RES.KEY_ = #{key} and RES.DEPLOY_TIME_ = (select max(DEPLOY_TIME_) from ACT_RE_DEPLOYMENT where KEY_ = RES.KEY_) order by RES.ID_ asc").parameter("key", "javaboy的工作流key").singleResult();
logger.info("id:{};key:{}", deployment.getId(), deployment.getKey());
}
``
自己写 SQL 即可,参数的占位符用 #,因为这里底层的 SQL 操作实际上是 MyBatis。
相同的道理,我想根据流程定义的 KEY 去查询流程定义信息,使用原生查询方式,代码如下:
@Test
void test04() {
List list = repositoryService.createNativeProcessDefinitionQuery()
.sql(“SELECT RES.* from ACT_RE_PROCDEF RES WHERE RES.KEY_ = #{key} order by RES.ID_ asc”)
.parameter(“key”, “javaboy_submit_an_expense_account”).list();
for (ProcessDefinition pd : list) {
logger.info(“id:{};key:{};version:{};”, pd.getId(), pd.getKey(), pd.getVersion());
}
}
以上转载:https://blog.youkuaiyun.com/weixin_40991408/article/details/130375294
第二篇参考文章
一.简介
有一个常见的场景是,查询执行过的流程信息。对于正在执行的流程,会在 ACT_RU_EXECUTION 表中保存一条对应的记录,不过流程执行结束之后,ACT_RU_EXECUTION 表中的记录会被删除掉,此时要是想查询已经执行过的流程信息,去哪里查询呢?这就要了解下 HistoryService 的使用方法。
流程图如下:

二.查询历史流程
查询历史流程的代码如下:
@SpringBootTest
public class HiTest {
@Autowired
HistoryService historyService;
private static final Logger logger = LoggerFactory.getLogger(HiTest.class);
@Test
void test01() {
List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().list();
for (HistoricProcessInstance hi : list) {
logger.info("==={},{},{},{},{},{}",hi.getId(),hi.getName(),hi.getStartActivityId(),hi.getStartTime(),hi.getEndActivityId(),hi.getEndTime());
}
}
}
由于项目使用的框架是 Spring Boot ,所以基本上不需要额外的配置,直接注入 HistoryService 实例即可。
test01() 方法中的代码就是查询出来目前所有的流程实例,包括正在执行的和已经执行完毕的都可以查询到。查询之后,控制台打印结果如下:
==> Preparing: SELECT RES.* , DEF.KEY_ as PROC_DEF_KEY_, DEF.NAME_ as PROC_DEF_NAME_, DEF.VERSION_ as PROC_DEF_VERSION_, DEF.DEPLOYMENT_ID_ as DEPLOYMENT_ID_ from ACT_HI_PROCINST RES left outer join ACT_RE_PROCDEF DEF on RES.PROC_DEF_ID_ = DEF.ID_ order by RES.ID_ asc
==> Parameters:
<== Total: 1
Flushing dbSqlSession
flush summary: 0 insert, 0 update, 0 delete.
now executing flush...
--- HistoricProcessInstanceQueryImpl finished --------------------------------------------------------
===a3786614-38eb-11ed-afc8-acde48001122,null,startEvent1,Tue Sep 20 21:53:42 CST 2022,null,null
首先可以看到,这里查询的 SQL,查询的表是 ACT_HI_PROCINST,截图如下:

这张表中记录了流程实例 ID,流程定义 ID,流程开始的时间,流程结束的时间,流程执行耗时,流程开始的节点,流程发起人,流程结束的节点等等。
同时大家也可以看到,在打印出来的查询结果中,getEndActivityId 和 getEndTime 这两个字段的值都为 null,这就说明这个流程目前还在执行中,还没执行完毕,当一个流程执行完毕的时候,这两个字段就不会为 null 了,我们可以根据这个特点去判断一个流程是否执行完毕。
现将流程这个流程中的任务都执行完毕,执行完毕之后,ACT_RU_EXECUTION 表中关于流程的记录就会被删除掉,也就是执行如下代码现在是查询不到上面这个流程了:
@Autowired
RuntimeService runtimeService;
@Test
void test02() {
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId("a3786614-38eb-11ed-afc8-acde48001122").singleResult();
logger.info("pi:{}",pi);
}
这个方法执行返回的 pi 对象现在为 null。
现在我们想查询刚刚执行的流程,得去查询历史流程,也就是去 ACT_HI_PROCINST 表中去查询,执行我们最上面那个方法:
@Test
void test01() {
List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().list();
for (HistoricProcessInstance hi : list) {
logger.info("==={},{},{},{},{},{}",hi.getId(),hi.getName(),hi.getStartActivityId(),hi.getStartTime(),hi.getEndActivityId(),hi.getEndTime());
}
}
现在去查询,返回的结果中就可以看到 EndActivityId 以及 EndTime 这两个字段了,因为流程已经执行结束了。
在流程执行的过程中,ACT_HI_PROCINST 表中的流程记录和 ACT_RU_EXECUTION 表中的流程记录是一一对应的。
三.查询历史活动
一个流程中的每一个节点都是一个活动,当一个流程执行结束的时候,如果我们还想查看每一个活动执行的细节,就得通过查询历史活动来实现了。
在查询之前,先来了解下跟历史活动相关的两张表。
1.ACT_HI_ACTINST
这张表中保存**一个流程中的所有活动细节。包括流程的启动节点、结束节点、各种 Task 甚至节点之间的连线,**可以看下这张表中的信息:
这刚好是一个流程的完整记录,从上往下,分别是:
①启动流程。
②连线
③提交请假申请这个 UserTask
④连线
⑤主管审批这个 UserTask
⑥连线
⑦经理审批这个 UserTask
⑧连线
⑨结束
2.ACT_HI_TASKINST
这个表只记录下来了 Task 的信息,截图如下:

这张表记录下来了每一个 Task 的具体信息,包括这个 Task 是由谁处理的,Task 的名字,开始时间、结束时间、耗时等信息。
针对这两张表,也有不同的查询方式。
首先来看查询历史活动:
@Test
void test03() {
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().orderByHistoricActivityInstanceStartTime().asc().list();
for (HistoricActivityInstance hai : list) {
logger.info("流程ID:{},活动名称:{},活动ID:{},活动处理人:{}",hai.getProcessInstanceId(),hai.getActivityName(),hai.getActivityId(),hai.getAssignee());
}
}
查询结果如下图:

由于只执行了一个流程,所以这里就只显示了一个流程的所有活动,大家看打印出来的流程 ID 都是一样的。
再来看查询历史 Task:
@Test
void test04() {
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().orderByHistoricTaskInstanceStartTime().asc().list();
for (HistoricTaskInstance hti : list) {
logger.info("流程ID:{},Task 开始时间:{},Task 结束时间:{},Task 处理人:{}",hti.getProcessInstanceId(),hti.getCreateTime(),hti.getEndTime(),hti.getAssignee());
}
}

以上转载:https://blog.youkuaiyun.com/weixin_40991408/article/details/130415623
第三篇文章
事情是这个样子的,在学习flowable的时候,粗略的看了一遍用户手册,是的还蛮清晰的,但是总觉得少了点什么,仔细想了想,方法调用是很简单,但总觉得不了解内部机制,而了解内部运行机制最简单的方法就是数据库表,的确无论是官网还是博客资料均对flowable数据库表进行了详细的说明,细化到了每个表的字段,但是呢?还是不够,我想要了解的是运行机制,比如我部署的时候,内部到底执行了什么,执行的sql语句是什么,操作了哪些表哪些字段等等,带着这种疑问,尝试了起来。
我的运行环境是springboot+flowable,这里我把代码都一起贴上来。
核心
logging.level.org.flowable.engine.impl.persistence.entity.*=debug
logging.level.org.flowable.task.service.impl.persistence.entity.*=debug
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>flowable</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>flowable</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.flowable/flowable-spring-boot-starter -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件 application.properties
注意最后两句就是可以让flowable相关的执行可以带引出sql语句的配置
spring.datasource.url=jdbc:mysql://??????/flowable-spring-boot?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
logging.level.org.flowable.engine.impl.persistence.entity.*=debug
logging.level.org.flowable.task.service.impl.persistence.entity.*=debug
如果是.yaml文件,是这样的:
logging:
level:
org.flowable.engine.impl.persistence.entity.*: debug
org.flowable.task.service.impl.persistence.entity.*: debug
FlowableApplication
package com.example.flowable;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class FlowableApplication {
public static void main(String[] args) {
SpringApplication.run(FlowableApplication.class, args);
}
// 启动时自动执行
@Bean
public CommandLineRunner init(final RepositoryService repositoryService,
final RuntimeService runtimeService,
final TaskService taskService) {
return new CommandLineRunner() {
@Override
public void run(String... strings) throws Exception {
System.out.println("Number of process definitions : "
+ repositoryService.createProcessDefinitionQuery().count());
System.out.println("Number of tasks : " + taskService.createTaskQuery().count());
runtimeService.startProcessInstanceByKey("oneTaskProcess"); //启动自动部署,这里是开启实例
System.out.println("Number of tasks after process start: "
+ taskService.createTaskQuery().count());
}
};
}
}
MyRestController
package com.example.flowable.controller;
import com.example.flowable.service.MyService;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
public class MyRestController {
@Autowired
private MyService myService;
@RequestMapping(value="/process", method= RequestMethod.POST)
public void startProcessInstance() {
myService.startProcess();
}
@RequestMapping(value="/tasks", method= RequestMethod.GET, produces= MediaType.APPLICATION_JSON_VALUE)
public List<TaskRepresentation> getTasks(@RequestParam String assignee) {
List<Task> tasks = myService.getTasks(assignee);
List<TaskRepresentation> dtos = new ArrayList<TaskRepresentation>();
for (Task task : tasks) {
dtos.add(new TaskRepresentation(task.getId(), task.getName()));
}
return dtos;
}
@GetMapping(value="/getDeploment")
public void getDeploment() {
myService.getDeploment();
System.out.println();
}
static class TaskRepresentation {
private String id;
private String name;
public TaskRepresentation(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
MyService
package com.example.flowable.service;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class MyService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private TaskService taskService;
@Transactional
public void startProcess() {
runtimeService.startProcessInstanceByKey("oneTaskProcess");
}
@Transactional
public List<Task> getTasks(String assignee) {
return taskService.createTaskQuery().taskAssignee(assignee).list();
}
@Transactional
public void getDeploment() {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId("f8046347-ab16-11ec-a6c0-3c9c0f202230").singleResult();
System.out.println(processDefinition.getId());
}
}
然后启动后就会打印一堆日志

当我调用某个关于flowable的某个方法时,也会有sql语句输出,这样就知道内部机制了



那么之后,你想知道什么,就可以用这种方式去调试看内部sql机制了。
以上转载至https://blog.youkuaiyun.com/weixin_44663675/article/details/123705018
第四篇sql 如何使用
背景
流程任务流转过程中,各环节的处理,会填写处理意见。
Camunda自带了相关的功能,但功能过于简陋,问题较多,今天来说说这一块。
自带功能的问题
如使用Camunda官方自身的办理意见相关功能,会遇到两个问题:
1.因为指定环节跳转,使用了cancelActivityInstance,所以存在部分历史任务状态为deleted,需要过滤掉该部分数据
2.任务转办,需要查询并显示状态为未结束的任务环节相关审批意见(任务转办只重新设置审批人,不会重新生成1条新的任务)
使用官方自带的api,如下,始终无法拼接生成有效的sql语句
HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery();
query.processInstanceId(id).taskDeleteReason(WorkFlowConstant.TASK_DELETE_REASON_COMPLETE)
.or().taskDeleteReason(null).endOr().orderByHistoricActivityInstanceStartTime().asc();
生成的sql语句如下:
==> Preparing: select distinct RES.* from ACT_HI_TASKINST RES WHERE ( 1 = 1 and RES.PROC_INST_ID_ = ? and RES.DELETE_REASON_ = ? ) and ( 1 = 1 ) order by RES.START_TIME_ asc LIMIT ? OFFSET ?
==> Parameters: a1624965-e050-11ea-a4ec-8c1645df7f9d(String), completed(String), 2147483647(Integer), 0(Integer)
即api无法支持查询null值,推测碰到null值会自动忽略
转而采用native查询来实现
NativeHistoricTaskInstanceQuery query =historyService.createNativeHistoricTaskInstanceQuery()
.sql("select * from act_hi_taskinst where PROC_INST_ID_=#{processInstanceId} " +
"and (delete_reason_=#{deleteReason} or delete_reason_ is null) order by start_time_ ")
.parameter("processInstanceId",id)
.parameter("deleteReason",WorkFlowConstant.TASK_DELETE_REASON_COMPLETE);
以上代码能获取到期望的审批历史,但是……仍然存在问题:
1.任务转办后,查出任务历史直接是被转办人,例如张三转办给李四,在李四处理前,显示该环节为李四,但审批意见是张三写的,看上去很诡异
2.任务转办处理后,显示任务是李四处理的,张三和李四的审批意见做了拼接,依旧很诡异,看上去张三仍然在流程处理过程中但什么也没做,实际原本流程处理人就是他,并由他进行了任务转办。
任务委派也出现复用任务的情况,导致流程处理过程不清晰,不显示某些实际参与流程处理的人,以及合并显示审批意见的情况出现。
基于以上几点,还是自己实现审批意见表比较合适。
自行设计与实现
实体配置

实体属性

常用处理意见
通过平台数据字典功能,配置常用的处理意见,用于快速填充

数据写入
在任务处理等环节,弹出对话框,由用户录入办理意见或通过常用处理意见下拉列表快速填充

任务处理时,调用办理意见的服务接口,写入数据,以任务提交为例:
/**
* 新增处理意见
* @param processInstanceId 流程实例标识
* @param nodeId 环节标识
* @param nodeName 环节名称
* @param comment 处理意见
* @param commitType 提交类型
*/
void addComment(String processInstanceId,String nodeId,String nodeName, String comment, CommitTypeEnum commitType);
@Override
public void addComment(String processInstanceId,String nodeId,String nodeName, String comment, CommitTypeEnum commitType) {
WorkflowComment entity=init();
entity.setProcessInstanceId(processInstanceId);
entity.setNodeId(nodeId);
entity.setNodeName(nodeName);
entity.setComment(comment);
entity.setCommitType(commitType.name());
add(entity);
}
流转历史
在流程流转期间以及流程结束的查看页面,通过办理意见表,可以直观地看到该流程实例的流转和处理情况,如下图所示:

前端封装了一个通用组件
<template>
<el-card>
<template #header>
<span>历史</span>
</template>
<el-timeline>
<el-timeline-item v-for="(step, index) in steps" :key="index" type="success" size="large">
<div style="font-weight: bold">{{ step.nodeName }}</div>
<div>{{ step.assigneeName }}</div>
<div>{{ step.commitTypeName }}</div>
<div :title="step.comment">{{ abbreviate(step.comment, 20) }}</div>
<div>{{ $dateFormatter.formatUTCTime(step.commitTime) }}</div>
</el-timeline-item>
</el-timeline>
</el-card>
</template>
<script>
import { abbreviate } from '@/utils'
export default {
data() {
return {
// 历史信息
steps: [],
queryParams: {
processInstanceId: '',
sortInfo: {
sort_field: 'commitTime',
sort_sortType: 'ascending'
}
}
}
},
methods: {
abbreviate,
view(processInstanceId) {
this.queryParams.processInstanceId = processInstanceId
this.$api.workflow.workflowComment.list(this.queryParams).then((res) => {
this.steps = res.data
})
}
}
}
</script>
<style scoped></style>
调用的后端方法就是标准的获取办理意见的列表,按提交时间升序排列即可。
此外,流程中可能存在上传附件的需求,跟办理意见类似,Camunda也有这方面功能支持,同样支持的不好,我们平台的表单自身就能处理附件,不使用Camunda的附件相关功能。
开发平台资料
平台名称:一二三开发平台
简介: 企业级通用开发平台
设计资料:csdn专栏
开源地址:Gitee
开源协议:MIT
开源不易,欢迎收藏、点赞、评论。
转载至 https://blog.youkuaiyun.com/seawaving/article/details/133981217
如何转载别人的csdn
https://blog.youkuaiyun.com/weixin_45190065/article/details/129622677
https://blog.youkuaiyun.com/qq_44999561/article/details/129602541?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-129602541-blog-109611915.235v38pc_relevant_default_base3&spm=1001.2101.3001.4242.1&utm_relevant_index=3
https://blog.youkuaiyun.com/weixin_52322842/article/details/129652955
工具网址
http://www.atoolbox.net/Tool.php?Id=715
2692

被折叠的 条评论
为什么被折叠?



