Browse Source

Merge branch 'master' of http://124.222.6.97:3000/sunquan/apelet_tenant into feature/form-permission-control

feature/form-permission-control
chenchuchuan 2 weeks ago
parent
commit
65f2f7938d
  1. 5
      application-tenant/tenant-admin/pom.xml
  2. 44
      common/common-flow/pom.xml
  3. 11
      common/common-flow/src/main/java/apelet/common/flow/Plugin/AbstractAssigneePlugin.java
  4. 10
      common/common-flow/src/main/java/apelet/common/flow/Plugin/DemoFlowNodePlugin.java
  5. 49
      common/common-flow/src/main/java/apelet/common/flow/Plugin/FlowNodeExpressionUtil.java
  6. 58
      common/common-flow/src/main/java/apelet/common/flow/advice/FlowExceptionHandler.java
  7. 26
      common/common-flow/src/main/java/apelet/common/flow/base/service/BaseFlowOnlineService.java
  8. 273
      common/common-flow/src/main/java/apelet/common/flow/base/service/BaseFlowService.java
  9. 34
      common/common-flow/src/main/java/apelet/common/flow/cmd/ExpressionCmd.java
  10. 162
      common/common-flow/src/main/java/apelet/common/flow/cmd/RestartProcessInstanceCmd.java
  11. 48
      common/common-flow/src/main/java/apelet/common/flow/config/CustomEngineConfigurator.java
  12. 13
      common/common-flow/src/main/java/apelet/common/flow/config/FlowAutoConfig.java
  13. 20
      common/common-flow/src/main/java/apelet/common/flow/config/FlowProperties.java
  14. 97
      common/common-flow/src/main/java/apelet/common/flow/constant/FlowApprovalType.java
  15. 25
      common/common-flow/src/main/java/apelet/common/flow/constant/FlowBackType.java
  16. 33
      common/common-flow/src/main/java/apelet/common/flow/constant/FlowBuiltinApprovalStatus.java
  17. 266
      common/common-flow/src/main/java/apelet/common/flow/constant/FlowConstant.java
  18. 49
      common/common-flow/src/main/java/apelet/common/flow/constant/FlowTaskStatus.java
  19. 25
      common/common-flow/src/main/java/apelet/common/flow/constant/FlowTaskType.java
  20. 229
      common/common-flow/src/main/java/apelet/common/flow/controller/FlowCategoryController.java
  21. 469
      common/common-flow/src/main/java/apelet/common/flow/controller/FlowEntryController.java
  22. 156
      common/common-flow/src/main/java/apelet/common/flow/controller/FlowEntryVariableController.java
  23. 113
      common/common-flow/src/main/java/apelet/common/flow/controller/FlowMessageController.java
  24. 56
      common/common-flow/src/main/java/apelet/common/flow/controller/FlowNodeTasksController.java
  25. 1225
      common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java
  26. 26
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowCategoryMapper.java
  27. 26
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryMapper.java
  28. 13
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryPublishMapper.java
  29. 22
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryPublishVariableMapper.java
  30. 27
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryVariableMapper.java
  31. 21
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowMessageCandidateIdentityMapper.java
  32. 21
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowMessageIdentityOperationMapper.java
  33. 86
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowMessageMapper.java
  34. 13
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowMultiInstanceTransMapper.java
  35. 9
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowNodeTasksMapper.java
  36. 13
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowTaskCommentMapper.java
  37. 22
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowTaskExtMapper.java
  38. 14
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowTaskTimeoutJobMapper.java
  39. 13
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowTransProducerMapper.java
  40. 14
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowVariableLogMapper.java
  41. 14
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowWorkOrderExtMapper.java
  42. 49
      common/common-flow/src/main/java/apelet/common/flow/dao/FlowWorkOrderMapper.java
  43. 56
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowCategoryMapper.xml
  44. 95
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryMapper.xml
  45. 18
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryPublishMapper.xml
  46. 30
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryPublishVariableMapper.xml
  47. 41
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryVariableMapper.xml
  48. 16
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMessageCandidateIdentityMapper.xml
  49. 17
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMessageIdentityOperationMapper.xml
  50. 119
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMessageMapper.xml
  51. 17
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMultiInstanceTransMapper.xml
  52. 23
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskCommentMapper.xml
  53. 36
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskExtMapper.xml
  54. 19
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskTimeoutJobMapper.xml
  55. 23
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTransProducerMapper.xml
  56. 13
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowVariableLogMapper.xml
  57. 15
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowWorkOrderExtMapper.xml
  58. 82
      common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowWorkOrderMapper.xml
  59. 47
      common/common-flow/src/main/java/apelet/common/flow/dto/FlowCategoryDto.java
  60. 114
      common/common-flow/src/main/java/apelet/common/flow/dto/FlowEntryDto.java
  61. 82
      common/common-flow/src/main/java/apelet/common/flow/dto/FlowEntryVariableDto.java
  62. 51
      common/common-flow/src/main/java/apelet/common/flow/dto/FlowMessageDto.java
  63. 38
      common/common-flow/src/main/java/apelet/common/flow/dto/FlowTaskCommentDto.java
  64. 39
      common/common-flow/src/main/java/apelet/common/flow/dto/FlowWorkOrderDto.java
  65. 35
      common/common-flow/src/main/java/apelet/common/flow/exception/FlowEmptyUserException.java
  66. 35
      common/common-flow/src/main/java/apelet/common/flow/exception/FlowOperationException.java
  67. 161
      common/common-flow/src/main/java/apelet/common/flow/listener/AutoSkipListener.java
  68. 156
      common/common-flow/src/main/java/apelet/common/flow/listener/AutoSkipTaskListener.java
  69. 27
      common/common-flow/src/main/java/apelet/common/flow/listener/DeptPostLeaderListener.java
  70. 74
      common/common-flow/src/main/java/apelet/common/flow/listener/FlowEmptyUserHandleListener.java
  71. 70
      common/common-flow/src/main/java/apelet/common/flow/listener/FlowFinishedListener.java
  72. 80
      common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskNotifyListener.java
  73. 26
      common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskRejectBackListener.java
  74. 55
      common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskReviveListener.java
  75. 48
      common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskTimeoutListener.java
  76. 32
      common/common-flow/src/main/java/apelet/common/flow/listener/FlowUserTaskListener.java
  77. 27
      common/common-flow/src/main/java/apelet/common/flow/listener/UpDeptPostLeaderListener.java
  78. 44
      common/common-flow/src/main/java/apelet/common/flow/listener/UpdateLatestApprovalStatusListener.java
  79. 88
      common/common-flow/src/main/java/apelet/common/flow/model/FlowCategory.java
  80. 192
      common/common-flow/src/main/java/apelet/common/flow/model/FlowEntry.java
  81. 98
      common/common-flow/src/main/java/apelet/common/flow/model/FlowEntryPublish.java
  82. 71
      common/common-flow/src/main/java/apelet/common/flow/model/FlowEntryPublishVariable.java
  83. 88
      common/common-flow/src/main/java/apelet/common/flow/model/FlowEntryVariable.java
  84. 178
      common/common-flow/src/main/java/apelet/common/flow/model/FlowMessage.java
  85. 41
      common/common-flow/src/main/java/apelet/common/flow/model/FlowMessageCandidateIdentity.java
  86. 50
      common/common-flow/src/main/java/apelet/common/flow/model/FlowMessageIdentityOperation.java
  87. 99
      common/common-flow/src/main/java/apelet/common/flow/model/FlowMultiInstanceTrans.java
  88. 55
      common/common-flow/src/main/java/apelet/common/flow/model/FlowNodeTasks.java
  89. 161
      common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskComment.java
  90. 88
      common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskExt.java
  91. 97
      common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskTimeoutJob.java
  92. 33
      common/common-flow/src/main/java/apelet/common/flow/model/FlowTransConsumer.java
  93. 121
      common/common-flow/src/main/java/apelet/common/flow/model/FlowTransProducer.java
  94. 61
      common/common-flow/src/main/java/apelet/common/flow/model/FlowVariableLog.java
  95. 172
      common/common-flow/src/main/java/apelet/common/flow/model/FlowWorkOrder.java
  96. 72
      common/common-flow/src/main/java/apelet/common/flow/model/FlowWorkOrderExt.java
  97. 44
      common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowBindFormType.java
  98. 44
      common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowEntryStatus.java
  99. 21
      common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowMessageOperationType.java
  100. 26
      common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowMessageType.java
  101. Some files were not shown because too many files have changed in this diff Show More

5
application-tenant/tenant-admin/pom.xml

@ -57,6 +57,11 @@ @@ -57,6 +57,11 @@
</dependency>
<dependency>
<groupId>apelet</groupId>
<artifactId>common-flow</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>apelet</groupId>
<artifactId>common-flow-online</artifactId>
<version>1.0.0</version>
</dependency>

44
common/common-flow/pom.xml

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>apelet</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-flow</artifactId>
<version>1.0.0</version>
<name>common-flow</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>apelet</groupId>
<artifactId>common-datafilter</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>apelet</groupId>
<artifactId>common-sequence</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>apelet</groupId>
<artifactId>common-log</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>apelet</groupId>
<artifactId>common-swagger</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-basic</artifactId>
<version>${flowable.version}</version>
</dependency>
</dependencies>
</project>

11
common/common-flow/src/main/java/apelet/common/flow/Plugin/AbstractAssigneePlugin.java

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
package apelet.common.flow.Plugin;
import java.util.ArrayList;
import java.util.List;
public class AbstractAssigneePlugin {
public List<String> userStr = new ArrayList<>();
public void getFlowNodeUser(String parame){}
}

10
common/common-flow/src/main/java/apelet/common/flow/Plugin/DemoFlowNodePlugin.java

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
package apelet.common.flow.Plugin;
public class DemoFlowNodePlugin extends AbstractAssigneePlugin{
@Override
public void getFlowNodeUser(String parame) {
System.out.println("-----------DemoFlowNodePlugin:"+parame);
this.userStr.add("650");
}
}

49
common/common-flow/src/main/java/apelet/common/flow/Plugin/FlowNodeExpressionUtil.java

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
package apelet.common.flow.Plugin;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
*
* 流程实例中表达式解析工具
*/
@Component
@Slf4j
public class FlowNodeExpressionUtil {
public String getAssigneeByPlugin( String parame){
List<String> list = new ArrayList<>();
String returnStr=",";
try {
//parame = URLDecoder.decode(parame,"UTF-8");
JSONArray josnarr = JSONArray.parseArray(parame);
for(int i=0;i<josnarr.size();i++){
JSONObject jsono = josnarr.getJSONObject(i);
Class<?> aClass = Class.forName(jsono.getString("pluginType"));
Method method = aClass.getMethod("getFlowNodeUser", String.class);
Object object = aClass.newInstance();
method.invoke(object, jsono.toString());
list.addAll((List<String>) aClass.getSuperclass().getDeclaredField("userStr").get(object));
}
if(list.size()>0){
for(int i=0;i<list.size();i++){
returnStr=returnStr+list.get(i);
}
}
returnStr = returnStr.substring(1);
} catch (Exception e) {
e.printStackTrace();
}
return returnStr;
}
}

58
common/common-flow/src/main/java/apelet/common/flow/advice/FlowExceptionHandler.java

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
package apelet.common.flow.advice;
import apelet.common.core.constant.ErrorCodeEnum;
import apelet.common.core.object.ResponseResult;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.core.util.ContextUtil;
import apelet.common.flow.exception.FlowEmptyUserException;
import apelet.common.flow.model.FlowTaskComment;
import apelet.common.flow.service.FlowTaskCommentService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.FlowableException;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 流程业务层的异常处理类
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
@Order(1)
@RestControllerAdvice("apelet")
public class FlowExceptionHandler {
private final transient FlowTaskCommentService flowTaskCommentService =
ApplicationContextHolder.getBean(FlowTaskCommentService.class);
@ExceptionHandler(value = FlowableException.class)
public ResponseResult<Void> exceptionHandle(FlowableException ex, HttpServletRequest request) {
FlowEmptyUserException flowEmptyUserException = this.findCause(ex, FlowEmptyUserException.class);
if (flowEmptyUserException != null) {
FlowTaskComment comment = JSON.parseObject(flowEmptyUserException.getMessage(), FlowTaskComment.class);
flowTaskCommentService.saveNew(comment);
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, "下一个任务节点的审批人为空,提交被自动驳回!");
}
log.error("Unhandled FlowException from URL [" + request.getRequestURI() + "]", ex);
ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return ResponseResult.error(ErrorCodeEnum.UNHANDLED_EXCEPTION, ex.getMessage());
}
@SuppressWarnings("unchecked")
private <T extends Exception> T findCause(Throwable ex, Class<T> clazz) {
if (ex.getCause() == null) {
return null;
}
if (ex.getCause().getClass().equals(clazz)) {
return (T) ex.getCause();
} else {
return this.findCause(ex.getCause(), clazz);
}
}
}

26
common/common-flow/src/main/java/apelet/common/flow/base/service/BaseFlowOnlineService.java

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
package apelet.common.flow.base.service;
import apelet.common.flow.model.FlowWorkOrder;
/**
* 工作流在线表单的服务接口
*
* @author guifc
* @date 2023-08-04
*/
public interface BaseFlowOnlineService {
/**
* 更新在线表单主表数据的流程状态字段值
*
* @param workOrder 工单对象
*/
void updateFlowStatus(FlowWorkOrder workOrder);
/**
* 根据工单对象级联删除业务数据
*
* @param workOrder 工单对象
*/
void deleteBusinessData(FlowWorkOrder workOrder);
}

273
common/common-flow/src/main/java/apelet/common/flow/base/service/BaseFlowService.java

@ -0,0 +1,273 @@ @@ -0,0 +1,273 @@
package apelet.common.flow.base.service;
import apelet.common.core.base.service.BaseService;
import apelet.common.core.exception.MyRuntimeException;
import apelet.common.core.object.CallResult;
import apelet.common.core.object.MyRelationParam;
import apelet.common.core.util.MyDateUtil;
import apelet.common.core.util.MyModelUtil;
import apelet.common.flow.constant.FlowApprovalType;
import apelet.common.flow.constant.FlowConstant;
import apelet.common.flow.constant.FlowTaskStatus;
import apelet.common.flow.exception.FlowOperationException;
import apelet.common.flow.model.FlowTaskComment;
import apelet.common.flow.model.FlowWorkOrder;
import apelet.common.flow.model.FlowWorkOrderExt;
import apelet.common.flow.service.FlowApiService;
import apelet.common.flow.service.FlowWorkOrderService;
import apelet.common.flow.vo.FlowWorkOrderVo;
import apelet.common.redis.cache.SessionCacheHelper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
/**
* 路由表单工作流服务抽象类
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public abstract class BaseFlowService<M, K extends Serializable> extends BaseService<M, K> {
@Autowired
private FlowApiService flowApiService;
@Autowired
private FlowWorkOrderService flowWorkOrderService;
@Autowired
private SessionCacheHelper cacheHelper;
@Transactional(rollbackFor = Exception.class)
public void startWithBusinessKey(String processDefinitionId, K dataId) {
ProcessInstance instance = flowApiService.start(processDefinitionId, dataId);
flowWorkOrderService.saveNew(instance, dataId, null, super.tableName);
}
@Transactional(rollbackFor = Exception.class)
public void startAndTakeFirst(
String processDefinitionId, K dataId, FlowTaskComment comment, JSONObject variables) {
ProcessInstance instance = flowApiService.start(processDefinitionId, dataId);
flowWorkOrderService.saveNew(instance, dataId, null, super.tableName);
flowApiService.takeFirstTask(instance.getProcessInstanceId(), comment, variables);
// 这里需要在创建工单后再次更新一下工单状态,在flowApiService.completeTask中的更新,
// 因为当时没有创建工单对象,更新会不起任何作用,所以这里要补偿一下。
Integer approvalStatus = MapUtil.getInt(variables, FlowConstant.LATEST_APPROVAL_STATUS_KEY);
flowWorkOrderService.updateLatestApprovalStatusByProcessInstanceId(instance.getId(), approvalStatus);
}
@Transactional(rollbackFor = Exception.class)
public FlowWorkOrder saveNewDraftAndStartProcess(String processDefinitionId, String masterData, String slaveData) {
ProcessInstance instance = flowApiService.start(processDefinitionId, null);
Map<String, Object> variableMap = flowApiService.initAndGetProcessInstanceVariables(processDefinitionId);
flowApiService.setProcessInstanceVariables(instance.getProcessInstanceId(), variableMap);
return flowWorkOrderService.saveNewWithDraft(instance, null, super.tableName, masterData, slaveData);
}
@Transactional(rollbackFor = Exception.class)
public void takeFirstTask(
String processInstanceId, String taskId, K dataId, FlowTaskComment comment, JSONObject variables) {
Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
flowApiService.setBusinessKeyForProcessInstance(processInstanceId, dataId);
ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId);
FlowWorkOrder flowWorkOrder =
flowWorkOrderService.getFlowWorkOrderByProcessInstanceId(instance.getProcessInstanceId());
if (flowWorkOrder == null) {
flowWorkOrderService.saveNew(instance, dataId, null, super.tableName);
} else {
flowWorkOrder.setBusinessKey(dataId.toString());
flowWorkOrder.setUpdateTime(new Date());
flowWorkOrder.setFlowStatus(FlowTaskStatus.SUBMITTED);
flowWorkOrderService.updateById(flowWorkOrder);
}
flowApiService.completeTask(task, comment, variables, null);
}
@Transactional(rollbackFor = Exception.class)
public void takeTask(Task task, K dataId, FlowTaskComment comment, JSONObject variables) {
int flowStatus = FlowTaskStatus.APPROVING;
if (comment.getApprovalType().equals(FlowApprovalType.REFUSE)) {
flowStatus = FlowTaskStatus.REFUSED;
} else if (comment.getApprovalType().equals(FlowApprovalType.STOP)) {
flowStatus = FlowTaskStatus.FINISHED;
}
if (comment.getApprovalType().equals(FlowApprovalType.STOP)) {
Integer s = MapUtil.getInt(variables, FlowConstant.LATEST_APPROVAL_STATUS_KEY);
flowWorkOrderService.updateLatestApprovalStatusByProcessInstanceId(task.getProcessInstanceId(), s);
CallResult stopResult = flowApiService.stopProcessInstance(
task.getProcessInstanceId(), comment.getTaskComment(), flowStatus);
if (!stopResult.isSuccess()) {
throw new FlowOperationException(stopResult.getErrorMessage());
}
} else {
flowWorkOrderService.updateFlowStatusByProcessInstanceId(task.getProcessInstanceId(), flowStatus);
flowApiService.completeTask(task, comment, variables, null);
}
}
public void buildDraftData(List<FlowWorkOrderVo> draftWorkOrderList) {
if (CollUtil.isEmpty(draftWorkOrderList)) {
return;
}
Set<Long> workOrderIdSet = draftWorkOrderList.stream()
.map(FlowWorkOrderVo::getWorkOrderId).collect(Collectors.toSet());
Map<Long, FlowWorkOrderExt> workOrderExtMap =
flowWorkOrderService.getFlowWorkOrderExtByWorkOrderIds(workOrderIdSet)
.stream().collect(Collectors.toMap(FlowWorkOrderExt::getWorkOrderId, c -> c));
for (FlowWorkOrderVo workOrder : draftWorkOrderList) {
FlowWorkOrderExt workOrderExt = workOrderExtMap.get(workOrder.getWorkOrderId());
if (workOrderExt == null) {
continue;
}
JSONObject draftData = JSON.parseObject(workOrderExt.getDraftData());
JSONObject masterData = draftData.getJSONObject(FlowConstant.MASTER_DATA_KEY);
JSONObject slaveData = draftData.getJSONObject(FlowConstant.SLAVE_DATA_KEY);
M model;
if (masterData != null) {
model = masterData.toJavaObject(modelClass);
super.buildRelationForData(model, MyRelationParam.dictOnly());
} else {
model = ReflectUtil.newInstance(modelClass);
}
this.bindLocalOneToOneSlaveData(model, slaveData);
super.buildLocalOneToOneDictOnly(model);
workOrder.setMasterData(BeanUtil.beanToMap(model));
}
}
/**
* 在流程实例审批结束后需要进行审批表到发布表数据同步的服务实现子类需要实现该方法
*
* @param workOrder 工单对象
*/
public void syncBusinessData(FlowWorkOrder workOrder) {
// 请自行在子类中实现当前service的数据同步逻辑。
}
/**
* 在流程实例审批结束后需要进行业务表的状态更新业务Service需要实现该方法
*
* @param workOrder 工单对象
*/
public void updateFlowStatus(FlowWorkOrder workOrder) {
if (flowStatusField == null && flowLatestApprovalStatusField == null) {
return;
}
Serializable id = this.convertToKeyValue(workOrder.getBusinessKey());
M data = this.getById(id);
if (data == null) {
String msg = StrFormatter.format(
"WorkOrderId [{}] don't find business data by key [{}] while calling [updateFlowStatus].",
workOrder.getWorkOrderId(), workOrder.getBusinessKey());
log.warn(msg);
return;
}
if (flowStatusField != null) {
ReflectUtil.setFieldValue(data, flowStatusField, workOrder.getFlowStatus());
}
if (flowLatestApprovalStatusField != null) {
ReflectUtil.setFieldValue(data, flowLatestApprovalStatusField, workOrder.getLatestApprovalStatus());
}
mapper().updateById(data);
}
/**
* 根据工单对象删除流程业务数据
*
* @param workOrder 工单对象
*/
@SuppressWarnings("unchecked")
public void removeByWorkOrder(FlowWorkOrder workOrder) {
Serializable id = this.convertToKeyValue(workOrder.getBusinessKey());
M data = this.getById(id);
if (data == null) {
String msg = StrFormatter.format(
"WorkOrderId [{}] don't find business data by key [{}] while calling [removeByWorkOrder].",
workOrder.getWorkOrderId(), workOrder.getBusinessKey());
log.warn(msg);
return;
}
// 级联删除业务数据,调用的是橙单默认生成的remove方法,参数类型为主键类型,如Long、String等。
// 进一步补充说明,橙单默认生成的remove方法,会根据在生成器中的配置,生成关联从表数据的级联删除代码。
this.remove((K) id);
}
/**
* 获取业务详情数据
*
* @param processInstanceId 流程实例Id
* @param businessKey 业务主键Id如果与实际主键值类型不同需要在子类中自行完成类型转换
* @return 业务主表数据以及关联从表数据
*/
@SuppressWarnings("unchecked")
public String getBusinessData(String processInstanceId, String businessKey) {
Serializable id = this.convertToKeyValue(businessKey);
M data = this.getByIdWithRelation((K) id, MyRelationParam.full());
return JSON.toJSONStringWithDateFormat(data, MyDateUtil.COMMON_SHORT_DATETIME_FORMAT);
}
/**
* 规格化工单扩展表中保存的草稿数据如果仅仅包含主表数据可以使用当前的缺省实现
*
* @param processInstanceId 流程实例Id
* @param masterData 草稿中的主表数据
* @param slaveData 草稿中的全部关联从表数据
* @return 格式化后用于前端显示的业务草稿数据
*/
public String getNormalizedDraftData(String processInstanceId, JSONObject masterData, JSONObject slaveData) {
// 看到这个异常千万别慌,这是及时的提示您,如果草稿中包含了关联从表数据,就一定要在业务的ServiceImpl中实现该方法。
// 在子类中实现主表和关联从表数据的数据组装。通用的方法中,只能解析主表数据,关联从表各式各样,所以需要在子类中实现。
if (slaveData != null) {
throw new UnsupportedOperationException(
"Please implement getNormalizedDraftData by self, because draft data includes related slaveData");
}
if (masterData == null) {
return JSON.toJSONString(ReflectUtil.newInstance(modelClass));
}
M model = BeanUtil.toBean(masterData, modelClass);
// 这里会缺省缓存主表中上传字段的下载地址,以便在显示草稿数据时,这些上传字段对应的download方法,不会被数据权限过滤。
Set<String> cachedDownableFilename =
new HashSet<>(MyModelUtil.extractDownloadFileName(model, modelClass));
cacheHelper.putSessionDownloadableFileNameSet(cachedDownableFilename);
return JSON.toJSONStringWithDateFormat(model, MyDateUtil.COMMON_SHORT_DATETIME_FORMAT);
}
private Serializable convertToKeyValue(String businessKey) {
if (idFieldClass.equals(String.class)) {
return businessKey;
} else if (idFieldClass.equals(Long.class)) {
return Long.valueOf(businessKey);
} else if (idFieldClass.equals(Integer.class)) {
return Integer.valueOf(businessKey);
} else {
throw new MyRuntimeException("Unsupported Primary Key Field Type.");
}
}
private void bindLocalOneToOneSlaveData(M model, JSONObject slaveData) {
if (slaveData == null) {
return;
}
for (BaseService.RelationStruct relationStruct : super.localRelationOneToOneStructList) {
Field relationField = relationStruct.getRelationField();
JSONObject slaveObject = slaveData.getJSONObject(relationField.getName());
if (slaveObject != null) {
ReflectUtil.setFieldValue(model, relationField,
slaveObject.toJavaObject(relationStruct.getRelationOneToOne().slaveModelClass()));
}
}
}
}

34
common/common-flow/src/main/java/apelet/common/flow/cmd/ExpressionCmd.java

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
package apelet.common.flow.cmd;
import lombok.AllArgsConstructor;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.common.engine.api.variable.VariableContainer;
import org.flowable.common.engine.impl.el.VariableContainerWrapper;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import java.util.Map;
/**
* EL表达式解析和执行的命令
*
* @author guifc
* @date 2024-08-27
*/
@AllArgsConstructor
public class ExpressionCmd implements Command<Object> {
private String executionId;
private String exp;
@Override
public Object execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl cfg = CommandContextUtil.getProcessEngineConfiguration(commandContext);
Expression expression = cfg.getExpressionManager().createExpression(exp);
Map<String, Object> variables = cfg.getRuntimeService().getVariables(executionId);
VariableContainer variableContainer = new VariableContainerWrapper(variables);
return cfg.getManagementService().executeCommand(cc -> expression.getValue(variableContainer));
}
}

162
common/common-flow/src/main/java/apelet/common/flow/cmd/RestartProcessInstanceCmd.java

@ -0,0 +1,162 @@ @@ -0,0 +1,162 @@
package apelet.common.flow.cmd;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ChangeActivityStateBuilder;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import java.util.*;
/**
* 流程复活命令对象
*
* @author guifc
* @date 2023-08-04
*/
@AllArgsConstructor
public class RestartProcessInstanceCmd implements Command<ProcessInstance> {
/**
* 待复活的流程实例编号
*/
protected String processInstanceId;
/**
* 要复活到的节点列表
*/
protected List<String> activityIds;
/**
* 流程任务标识和变量数据的Map
*/
protected Map<String, String> variableMap;
@Override
public ProcessInstance execute(CommandContext commandContext) {
ProcessEngineConfiguration engineConfig = CommandContextUtil.getProcessEngineConfiguration(commandContext);
HistoryService historyService = engineConfig.getHistoryService();
//校验和查询历史流程实例
HistoricProcessInstance historicProcessInstance = this.checkAndGetHistoricProcessInstance(historyService);
//校验待复活节点
this.checkActivityIds(historicProcessInstance.getProcessDefinitionId());
//校验流程定义
ProcessDefinition processDefinition =
ProcessDefinitionUtil.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
if (processDefinition == null) {
throw new FlowableException("流程定义不存在");
}
//获取流程启动节点
Process process = ProcessDefinitionUtil.getProcess(processDefinition.getId());
StartEvent initialFlowElement = (StartEvent) process.getInitialFlowElement();
//重建运行时流程实例的主执行实例
ExecutionEntity processInstance =
this.recreateProcessInstance(processDefinition, initialFlowElement, historicProcessInstance);
//创建子执行实例
ExecutionEntity childExecution =
CommandContextUtil.getExecutionEntityManager().createChildExecution(processInstance);
childExecution.setCurrentFlowElement(initialFlowElement);
//重建运行时流程变量
//设置历史流程实例结束节点和结束时间为空
((HistoricProcessInstanceEntityImpl) historicProcessInstance).setEndActivityId(null);
((HistoricProcessInstanceEntityImpl) historicProcessInstance).setEndTime(null);
Map<String, Object> gloablVariables = this.collectVariables(historyService, historicProcessInstance);
//执行动态跳转
ChangeActivityStateBuilder builder = engineConfig.getRuntimeService()
.createChangeActivityStateBuilder()
.processInstanceId(processInstance.getProcessInstanceId())
.moveSingleExecutionToActivityIds(childExecution.getId(), activityIds)
.processVariables(gloablVariables);
for (String activityId : activityIds) {
String variableData = variableMap.get(activityId);
if (StrUtil.isNotBlank(variableData)) {
builder.localVariables(activityId, JSON.parseObject(variableData));
}
}
builder.changeState();
return engineConfig.getRuntimeService()
.createProcessInstanceQuery().processInstanceId(processInstance.getId()).singleResult();
}
private HistoricProcessInstance checkAndGetHistoricProcessInstance(HistoryService historyService) {
if (StrUtil.isBlank(processInstanceId)) {
throw new FlowableIllegalArgumentException("processInstanceId不能为空");
}
HistoricProcessInstance historicProcessInstance = historyService
.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
if (historicProcessInstance == null) {
throw new FlowableException("id为" + processInstanceId + "的流程实例不存在");
} else if (historicProcessInstance != null && historicProcessInstance.getEndTime() == null) {
throw new FlowableException("id为" + processInstanceId + "的流程实例没有结束");
}
return historicProcessInstance;
}
private void checkActivityIds(String processDefinitionId) {
if (CollUtil.isEmpty(activityIds)) {
throw new FlowableIllegalArgumentException("activityIds不能为空");
}
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
List<String> notExistedFlowElements = new ArrayList<>();
for (String activityId : activityIds) {
if (!bpmnModel.getMainProcess().containsFlowElementId(activityId)) {
notExistedFlowElements.add(activityId);
}
}
if (!CollUtil.isEmpty(notExistedFlowElements)) {
throw new FlowableIllegalArgumentException("Id为" + String.join("、", notExistedFlowElements) + "节点不存在");
}
}
private ExecutionEntity recreateProcessInstance(
ProcessDefinition processDefinition,
StartEvent initialFlowElement,
HistoricProcessInstance historicProcessInstance) {
//创建流程实例
ExecutionEntity executionEntity = CommandContextUtil.getExecutionEntityManager()
.createProcessInstanceExecution(processDefinition,
historicProcessInstance.getId(),
historicProcessInstance.getBusinessKey(),
historicProcessInstance.getBusinessStatus(),
historicProcessInstance.getName(),
historicProcessInstance.getCallbackId(),
historicProcessInstance.getCallbackType(),
historicProcessInstance.getReferenceId(),
historicProcessInstance.getReferenceType(),
null,
historicProcessInstance.getTenantId(),
initialFlowElement.getInitiator(),
historicProcessInstance.getStartActivityId());
//重设流程开始事件
executionEntity.setStartTime(historicProcessInstance.getStartTime());
return executionEntity;
}
private Map<String, Object> collectVariables(
HistoryService historyService, HistoricProcessInstance historicProcessInstance) {
Map<String, Object> variables = new HashMap<>(10);
List<HistoricVariableInstance> historicVariables = historyService
.createHistoricVariableInstanceQuery()
.processInstanceId(historicProcessInstance.getId())
.executionId(historicProcessInstance.getId()).list();
for (HistoricVariableInstance historicVariable : historicVariables) {
variables.put(historicVariable.getVariableName(), historicVariable.getValue());
}
return variables;
}
}

48
common/common-flow/src/main/java/apelet/common/flow/config/CustomEngineConfigurator.java

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
package apelet.common.flow.config;
import apelet.common.core.config.DynamicDataSource;
import apelet.common.core.constant.ApplicationConstant;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.AbstractEngineConfiguration;
import org.flowable.common.engine.impl.EngineConfigurator;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import javax.sql.DataSource;
import java.util.Map;
/**
* 服务启动过程中动态切换flowable引擎内置表所在的数据源
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class CustomEngineConfigurator implements EngineConfigurator {
@Override
public void beforeInit(AbstractEngineConfiguration engineConfiguration) {
DataSource dataSource = engineConfiguration.getDataSource();
if (dataSource instanceof TransactionAwareDataSourceProxy) {
TransactionAwareDataSourceProxy proxy = (TransactionAwareDataSourceProxy) dataSource;
DataSource targetDataSource = proxy.getTargetDataSource();
if (targetDataSource instanceof DynamicDataSource) {
DynamicDataSource dynamicDataSource = (DynamicDataSource) targetDataSource;
Map<Object, DataSource> dynamicDataSourceMap = dynamicDataSource.getResolvedDataSources();
DataSource flowDataSource = dynamicDataSourceMap.get(ApplicationConstant.COMMON_FLOW_AND_ONLINE_DATASOURCE_TYPE);
if (flowDataSource != null) {
engineConfiguration.setDataSource(flowDataSource);
}
}
}
}
@Override
public void configure(AbstractEngineConfiguration engineConfiguration) {
// 默认实现。
}
@Override
public int getPriority() {
return 0;
}
}

13
common/common-flow/src/main/java/apelet/common/flow/config/FlowAutoConfig.java

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
package apelet.common.flow.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
/**
* common-flow模块的自动配置引导类
*
* @author guifc
* @date 2023-08-04
*/
@EnableConfigurationProperties({FlowProperties.class})
public class FlowAutoConfig {
}

20
common/common-flow/src/main/java/apelet/common/flow/config/FlowProperties.java

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
package apelet.common.flow.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 工作流的配置对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@ConfigurationProperties(prefix = "common-flow")
public class FlowProperties {
/**
* 工作落工单操作接口的URL前缀
*/
private String urlPrefix;
}

97
common/common-flow/src/main/java/apelet/common/flow/constant/FlowApprovalType.java

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
package apelet.common.flow.constant;
/**
* 工作流任务触发BUTTON
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowApprovalType {
/**
* 保存
*/
public static final String SAVE = "save";
/**
* 同意
*/
public static final String AGREE = "agree";
/**
* 拒绝
*/
public static final String REFUSE = "refuse";
/**
* 驳回
*/
public static final String REJECT = "reject";
/**
* 撤销
*/
public static final String REVOKE = "revoke";
/**
* 指派
*/
public static final String TRANSFER = "transfer";
/**
* 多实例会签
*/
public static final String MULTI_SIGN = "multi_sign";
/**
* 会签同意
*/
public static final String MULTI_AGREE = "multi_agree";
/**
* 会签拒绝
*/
public static final String MULTI_REFUSE = "multi_refuse";
/**
* 会签弃权
*/
public static final String MULTI_ABSTAIN = "multi_abstain";
/**
* 多实例加签
*/
public static final String MULTI_CONSIGN = "multi_consign";
/**
* 多实例减签
*/
public static final String MULTI_MINUS_SIGN = "multi_minus_sign";
/**
* 中止
*/
public static final String STOP = "stop";
/**
* 干预
*/
public static final String INTERVENE = "intervene";
/**
* 自由跳转
*/
public static final String FREE_JUMP = "free_jump";
/**
* 流程复活
*/
public static final String REUSED = "reused";
/**
* 流程复活
*/
public static final String REVIVE = "revive";
/**
* 超时自动审批
*/
public static final String TIMEOUT_AUTO_COMPLETE = "timeout_auto_complete";
/**
* 空审批人自动审批
*/
public static final String EMPTY_USER_AUTO_COMPLETE = "empty_user_auto_complete";
/**
* 空审批人自动退回
*/
public static final String EMPTY_USER_AUTO_REJECT = "empty_user_auto_reject";
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowApprovalType() {
}
}

25
common/common-flow/src/main/java/apelet/common/flow/constant/FlowBackType.java

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
package apelet.common.flow.constant;
/**
* 待办任务回退类型
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowBackType {
/**
* 驳回
*/
public static final int REJECT = 0;
/**
* 撤回
*/
public static final int REVOKE = 1;
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowBackType() {
}
}

33
common/common-flow/src/main/java/apelet/common/flow/constant/FlowBuiltinApprovalStatus.java

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
package apelet.common.flow.constant;
/**
* 内置的流程审批状态
*
* @author guifc
* @date 2023-08-04
*/
public class FlowBuiltinApprovalStatus {
/**
* 同意
*/
public static final int AGREED = 1;
/**
* 拒绝
*/
public static final int REFUSED = 2;
/**
* 会签同意
*/
public static final int MULTI_AGREED = 3;
/**
* 会签拒绝
*/
public static final int MULTI_REFUSED = 4;
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowBuiltinApprovalStatus() {
}
}

266
common/common-flow/src/main/java/apelet/common/flow/constant/FlowConstant.java

@ -0,0 +1,266 @@ @@ -0,0 +1,266 @@
package apelet.common.flow.constant;
/**
* 工作流中的常量数据
*
* @author guifc
* @date 2023-08-04
*/
public class FlowConstant {
/**
* 标识流程实例启动用户的变量名
*/
public static final String START_USER_NAME_VAR = "${startUserName}";
/**
* 流程实例发起人变量名
*/
public static final String PROC_INSTANCE_INITIATOR_VAR = "initiator";
/**
* 流程实例中发起人用户的变量名
*/
public static final String PROC_INSTANCE_START_USER_NAME_VAR = "startUserName";
/**
* 流程任务的指定人变量
*/
public static final String TASK_APPOINTED_ASSIGNEE_VAR = "appointedAssignee";
/**
* 操作类型变量
*/
public static final String OPERATION_TYPE_VAR = "operationType";
/**
* 提交用户
*/
public static final String SUBMIT_USER_VAR = "submitUser";
/**
* 多任务拒绝数量变量
*/
public static final String MULTI_REFUSE_COUNT_VAR = "multiRefuseCount";
/**
* 多任务同意数量变量
*/
public static final String MULTI_AGREE_COUNT_VAR = "multiAgreeCount";
/**
* 多任务弃权数量变量
*/
public static final String MULTI_ABSTAIN_COUNT_VAR = "multiAbstainCount";
/**
* 会签发起任务
*/
public static final String MULTI_SIGN_START_TASK_VAR = "multiSignStartTask";
/**
* 会签任务总数量
*/
public static final String MULTI_SIGN_NUM_OF_INSTANCES_VAR = "multiNumOfInstances";
/**
* 会签任务执行的批次Id
*/
public static final String MULTI_SIGN_TASK_EXECUTION_ID_VAR = "taskExecutionId";
/**
* 多实例实例数量变量
*/
public static final String NUMBER_OF_INSTANCES_VAR = "nrOfInstances";
/**
* 多实例已完成实例数量变量
*/
public static final String NUMBER_OF_COMPLETED_INSTANCES_VAR = "nrOfCompletedInstances";
/**
* 多任务指派人列表变量
*/
public static final String MULTI_ASSIGNEE_LIST_VAR = "assigneeList";
/**
* 上级部门领导审批变量
*/
public static final String GROUP_TYPE_UP_DEPT_POST_LEADER_VAR = "upDeptPostLeader";
/**
* 本部门领导审批变量
*/
public static final String GROUP_TYPE_DEPT_POST_LEADER_VAR = "deptPostLeader";
/**
* 所有部门岗位审批变量
*/
public static final String GROUP_TYPE_ALL_DEPT_POST_VAR = "allDeptPost";
/**
* 本部门岗位审批变量
*/
public static final String GROUP_TYPE_SELF_DEPT_POST_VAR = "selfDeptPost";
/**
* 同级部门岗位审批变量
*/
public static final String GROUP_TYPE_SIBLING_DEPT_POST_VAR = "siblingDeptPost";
/**
* 上级部门岗位审批变量
*/
public static final String GROUP_TYPE_UP_DEPT_POST_VAR = "upDeptPost";
/**
* 任意部门关联的岗位审批变量
*/
public static final String GROUP_TYPE_DEPT_POST_VAR = "deptPost";
/**
* 指定角色分组变量
*/
public static final String GROUP_TYPE_ROLE_VAR = "role";
/**
* 指定部门分组变量
*/
public static final String GROUP_TYPE_DEPT_VAR = "dept";
/**
* 指定用户分组变量
*/
public static final String GROUP_TYPE_USER_VAR = "user";
/**
* 指定审批人
*/
public static final String GROUP_TYPE_ASSIGNEE = "ASSIGNEE";
/**
* 岗位
*/
public static final String GROUP_TYPE_POST = "POST";
/**
* 上级部门领导审批
*/
public static final String GROUP_TYPE_UP_DEPT_POST_LEADER = "UP_DEPT_POST_LEADER";
/**
* 本部门岗位领导审批
*/
public static final String GROUP_TYPE_DEPT_POST_LEADER = "DEPT_POST_LEADER";
/**
* 本部门岗位前缀
*/
public static final String SELF_DEPT_POST_PREFIX = "SELF_DEPT_";
/**
* 上级部门岗位前缀
*/
public static final String UP_DEPT_POST_PREFIX = "UP_DEPT_";
/**
* 同级部门岗位前缀
*/
public static final String SIBLING_DEPT_POST_PREFIX = "SIBLING_DEPT_";
/**
* 当前流程实例所有任务的抄送数据前缀
*/
public static final String COPY_DATA_MAP_PREFIX = "copyDataMap_";
/**
* 作为临时变量存入任务变量JSONObject对象时的key
*/
public static final String COPY_DATA_KEY = "copyDataKey";
/**
* 流程中业务快照数据中主表数据的Key
*/
public static final String MASTER_DATA_KEY = "masterData";
/**
* 流程中业务快照数据中关联从表数据的Key
*/
public static final String SLAVE_DATA_KEY = "slaveData";
/**
* 流程任务的最近更新状态的Key
*/
public static final String LATEST_APPROVAL_STATUS_KEY = "latestApprovalStatus";
/**
* 流程用户任务待办之前的通知类型的Key
*/
public static final String USER_TASK_NOTIFY_TYPES_KEY = "flowNotifyTypeList";
/**
* 流程用户任务自动跳过类型的Key
*/
public static final String USER_TASK_AUTO_SKIP_KEY = "autoSkipType";
/**
* 流程用户任务驳回类型的Key
*/
public static final String USER_TASK_REJECT_TYPE_KEY = "rejectType";
/**
* 驳回时携带的变量数据
*/
public static final String REJECT_TO_SOURCE_DATA_VAR = "rejectData";
/**
* 驳回时携带的变量数据
*/
public static final String REJECT_BACK_TO_SOURCE_DATA_VAR = "rejectBackData";
/**
* 指定审批人
*/
public static final String DELEGATE_ASSIGNEE_VAR = "defaultAssignee";
/**
* 业务主表对象的键目前仅仅用户在线表单工作流
*/
public static final String MASTER_TABLE_KEY = "masterTable";
/**
* 不删除任务超时作业
*/
public static final String NOT_DELETE_TIMEOUT_TASK_JOB_KEY = "notDeleteTimeoutTaskJob";
/**
* 用户任务超时小时数
*/
public static final String TASK_TIMEOUT_HOURS = "timeoutHours";
/**
* 用户任务超时处理方式
*/
public static final String TASK_TIMEOUT_HANDLE_WAY = "timeoutHandleWay";
/**
* 用户任务超时指定审批人
*/
public static final String TASK_TIMEOUT_DEFAULT_ASSIGNEE = "defaultAssignee";
/**
* 空处理人处理方式
*/
public static final String EMPTY_USER_HANDLE_WAY = "emptyUserHandleWay";
/**
* 空处理人时指定的审批人
*/
public static final String EMPTY_USER_TO_ASSIGNEE = "emptyUserToAssignee";
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowConstant() {
}
}

49
common/common-flow/src/main/java/apelet/common/flow/constant/FlowTaskStatus.java

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
package apelet.common.flow.constant;
/**
* 工作流任务类型
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowTaskStatus {
/**
* 已提交
*/
public static final int SUBMITTED = 0;
/**
* 审批中
*/
public static final int APPROVING = 1;
/**
* 被拒绝
*/
public static final int REFUSED = 2;
/**
* 已结束
*/
public static final int FINISHED = 3;
/**
* 提前停止
*/
public static final Integer STOPPED = 4;
/**
* 已取消
*/
public static final Integer CANCELLED = 5;
/**
* 保存草稿
*/
public static final Integer DRAFT = 6;
/**
* 流程复活
*/
public static final Integer REVIVE = 7;
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowTaskStatus() {
}
}

25
common/common-flow/src/main/java/apelet/common/flow/constant/FlowTaskType.java

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
package apelet.common.flow.constant;
/**
* 工作流任务类型
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowTaskType {
/**
* 其他类型任务
*/
public static final int OTHER_TYPE = 0;
/**
* 用户任务
*/
public static final int USER_TYPE = 1;
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowTaskType() {
}
}

229
common/common-flow/src/main/java/apelet/common/flow/controller/FlowCategoryController.java

@ -0,0 +1,229 @@ @@ -0,0 +1,229 @@
package apelet.common.flow.controller;
import apelet.common.core.annotation.MyRequestBody;
import apelet.common.core.constant.ErrorCodeEnum;
import apelet.common.core.object.*;
import apelet.common.core.util.MyCommonUtil;
import apelet.common.core.util.MyModelUtil;
import apelet.common.core.util.MyPageUtil;
import apelet.common.core.validator.UpdateGroup;
import apelet.common.flow.dto.FlowCategoryDto;
import apelet.common.flow.model.FlowCategory;
import apelet.common.flow.model.FlowEntry;
import apelet.common.flow.model.constant.FlowEntryStatus;
import apelet.common.flow.service.FlowCategoryService;
import apelet.common.flow.service.FlowEntryService;
import apelet.common.flow.vo.FlowCategoryVo;
import apelet.common.log.annotation.OperationLog;
import apelet.common.log.model.constant.SysOperationLogType;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.page.PageMethod;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import javax.validation.groups.Default;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* 工作流流程分类接口
*
* @author guifc
* @date 2023-08-04
*/
@Tag(name = "工作流流程分类接口")
@Slf4j
@RestController
@RequestMapping("${common-flow.urlPrefix}/flowCategory")
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
public class FlowCategoryController {
@Autowired
private FlowCategoryService flowCategoryService;
@Autowired
private FlowEntryService flowEntryService;
/**
* 新增FlowCategory数据
*
* @param flowCategoryDto 新增对象
* @return 应答结果对象包含新增对象主键Id
*/
@ApiOperationSupport(ignoreParameters = {"flowCategoryDto.categoryId"})
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody FlowCategoryDto flowCategoryDto) {
String errorMessage = MyCommonUtil.getModelValidationError(flowCategoryDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
FlowCategory flowCategory = MyModelUtil.copyTo(flowCategoryDto, FlowCategory.class);
if (flowCategoryService.existByCode(flowCategory.getCode())) {
return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, "数据验证失败,当前流程分类已经存在!");
}
flowCategory = flowCategoryService.saveNew(flowCategory);
return ResponseResult.success(flowCategory.getCategoryId());
}
/**
* 更新FlowCategory数据
*
* @param flowCategoryDto 更新对象
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody FlowCategoryDto flowCategoryDto) {
String errorMessage = MyCommonUtil.getModelValidationError(flowCategoryDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
FlowCategory flowCategory = MyModelUtil.copyTo(flowCategoryDto, FlowCategory.class);
ResponseResult<FlowCategory> verifyResult = this.doVerifyAndGet(flowCategory.getCategoryId());
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowCategory originalFlowCategory = verifyResult.getData();
if (!StrUtil.equals(flowCategory.getCode(), originalFlowCategory.getCode())) {
FlowEntry filter = new FlowEntry();
filter.setCategoryId(flowCategory.getCategoryId());
filter.setStatus(FlowEntryStatus.PUBLISHED);
List<FlowEntry> flowEntryList = flowEntryService.getListByFilter(filter);
if (CollUtil.isNotEmpty(flowEntryList)) {
errorMessage = "数据验证失败,当前流程分类存在已经发布的流程数据,因此分类标识不能修改!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (flowCategoryService.existByCode(flowCategory.getCode())) {
errorMessage = "数据验证失败,当前流程分类已经存在!";
return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, errorMessage);
}
}
if (!flowCategoryService.update(flowCategory, originalFlowCategory)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除FlowCategory数据
*
* @param categoryId 删除对象主键Id
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long categoryId) {
String errorMessage;
ResponseResult<FlowCategory> verifyResult = this.doVerifyAndGet(categoryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowEntry filter = new FlowEntry();
filter.setCategoryId(categoryId);
List<FlowEntry> flowEntryList = flowEntryService.getListByFilter(filter);
if (CollUtil.isNotEmpty(flowEntryList)) {
errorMessage = "数据验证失败,请先删除当前流程分类关联的流程数据!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!flowCategoryService.remove(categoryId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的FlowCategory列表
*
* @param flowCategoryDtoFilter 过滤对象
* @param orderParam 排序参数
* @param pageParam 分页参数
* @return 应答结果对象包含查询结果集
*/
@PostMapping("/list")
public ResponseResult<MyPageData<FlowCategoryVo>> list(
@MyRequestBody FlowCategoryDto flowCategoryDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
FlowCategory flowCategoryFilter = MyModelUtil.copyTo(flowCategoryDtoFilter, FlowCategory.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowCategory.class);
List<FlowCategory> flowCategoryList = flowCategoryService.getFlowCategoryListWithRelation(flowCategoryFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(flowCategoryList, FlowCategory.INSTANCE));
}
/**
* 查看指定FlowCategory对象详情
*
* @param categoryId 指定对象主键Id
* @return 应答结果对象包含对象详情
*/
@GetMapping("/view")
public ResponseResult<FlowCategoryVo> view(@RequestParam Long categoryId) {
ResponseResult<FlowCategory> verifyResult = this.doVerifyAndGet(categoryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowCategoryVo flowCategoryVo = FlowCategory.INSTANCE.fromModel(verifyResult.getData());
return ResponseResult.success(flowCategoryVo);
}
/**
* 以字典形式返回全部FlowCategory数据集合字典的键值为[categoryId, name]
* 白名单接口登录用户均可访问
*
* @param filter 过滤对象
* @return 应答结果对象包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject FlowCategoryVo filter) {
List<FlowCategory> resultList =
flowCategoryService.getFlowCategoryList(MyModelUtil.copyTo(filter, FlowCategory.class), null);
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, FlowCategory::getCategoryId, FlowCategory::getName));
}
/**
* 根据字典Id集合获取查询后的字典数据
*
* @param dictIds 字典Id集合
* @return 应答结果对象包含字典形式的数据集合
*/
@GetMapping("/listDictByIds")
public ResponseResult<List<Map<String, Object>>> listDictByIds(@RequestParam List<Long> dictIds) {
List<FlowCategory> resultList = flowCategoryService.getInList(new HashSet<>(dictIds));
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, FlowCategory::getCategoryId, FlowCategory::getName));
}
private ResponseResult<FlowCategory> doVerifyAndGet(Long categoryId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(categoryId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
FlowCategory flowCategory = flowCategoryService.getById(categoryId);
if (flowCategory == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
TokenData tokenData = TokenData.takeFromRequest();
if (!StrUtil.equals(flowCategory.getAppCode(), tokenData.getAppCode())) {
errorMessage = "数据验证失败,当前应用并不存在该流程分类的定义!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (ObjectUtil.notEqual(flowCategory.getTenantId(), tokenData.getTenantId())) {
errorMessage = "数据验证失败,当前租户并不存在该流程分类的定义!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
return ResponseResult.success(flowCategory);
}
}

469
common/common-flow/src/main/java/apelet/common/flow/controller/FlowEntryController.java

@ -0,0 +1,469 @@ @@ -0,0 +1,469 @@
package apelet.common.flow.controller;
import apelet.common.core.annotation.MyRequestBody;
import apelet.common.core.constant.ErrorCodeEnum;
import apelet.common.core.object.*;
import apelet.common.core.util.MyCommonUtil;
import apelet.common.core.util.MyModelUtil;
import apelet.common.core.util.MyPageUtil;
import apelet.common.core.validator.UpdateGroup;
import apelet.common.flow.constant.FlowTaskType;
import apelet.common.flow.dto.FlowEntryDto;
import apelet.common.flow.model.FlowEntry;
import apelet.common.flow.model.FlowEntryPublish;
import apelet.common.flow.model.constant.FlowEntryStatus;
import apelet.common.flow.service.*;
import apelet.common.flow.vo.FlowEntryPublishVo;
import apelet.common.flow.vo.FlowEntryVo;
import apelet.common.flow.vo.TaskInfoVo;
import apelet.common.log.annotation.OperationLog;
import apelet.common.log.model.constant.SysOperationLogType;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.page.PageMethod;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import javax.validation.groups.Default;
import javax.xml.stream.XMLStreamException;
import java.util.*;
/**
* 工作流流程定义接口
*
* @author guifc
* @date 2023-08-04
*/
@Tag(name = "工作流流程定义接口")
@Slf4j
@RestController
@RequestMapping("${common-flow.urlPrefix}/flowEntry")
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
public class FlowEntryController {
@Autowired
private FlowEntryService flowEntryService;
@Autowired
private FlowCategoryService flowCategoryService;
@Autowired
private FlowEntryVariableService flowEntryVariableService;
@Autowired
private FlowApiService flowApiService;
@Autowired
private FlowTaskExtService flowTaskExtService;
/**
* 新增工作流对象数据
*
* @param flowEntryDto 新增对象
* @return 应答结果对象包含新增对象主键Id
*/
@ApiOperationSupport(ignoreParameters = {"flowEntryDto.entryId"})
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody FlowEntryDto flowEntryDto) {
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
FlowEntry flowEntry = MyModelUtil.copyTo(flowEntryDto, FlowEntry.class);
if (flowEntryService.existByProcessDefinitionKey(flowEntry.getProcessDefinitionKey())) {
errorMessage = "数据验证失败,该流程定义标识已存在!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = flowEntryService.verifyRelatedData(flowEntry, null);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
flowEntry = flowEntryService.saveNew(flowEntry);
return ResponseResult.success(flowEntry.getEntryId());
}
/**
* 更新工作流对象数据
*
* @param flowEntryDto 更新对象
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody FlowEntryDto flowEntryDto) {
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
FlowEntry flowEntry = MyModelUtil.copyTo(flowEntryDto, FlowEntry.class);
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(flowEntry.getEntryId());
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowEntry originalFlowEntry = verifyResult.getData();
if (ObjectUtil.notEqual(flowEntry.getProcessDefinitionKey(), originalFlowEntry.getProcessDefinitionKey())) {
if (originalFlowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) {
errorMessage = "数据验证失败,当前流程为发布状态,流程标识不能修改!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (flowEntryService.existByProcessDefinitionKey(flowEntry.getProcessDefinitionKey())) {
errorMessage = "数据验证失败,该流程定义标识已存在!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
}
// 验证关联Id的数据合法性
CallResult callResult = flowEntryService.verifyRelatedData(flowEntry, originalFlowEntry);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!flowEntryService.update(flowEntry, originalFlowEntry)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除工作流对象数据
*
* @param entryId 删除对象主键Id
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long entryId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(entryId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowEntry originalFlowEntry = verifyResult.getData();
if (originalFlowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) {
errorMessage = "数据验证失败,当前流程为发布状态,不能删除!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!flowEntryService.remove(entryId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 发布工作流
*
* @param entryId 流程主键Id
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.PUBLISH)
@PostMapping("/publish")
public ResponseResult<Void> publish(@MyRequestBody(required = true) Long entryId) throws XMLStreamException {
String errorMessage;
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowEntry flowEntry = verifyResult.getData();
if (StrUtil.isBlank(flowEntry.getBpmnXml())) {
errorMessage = "数据验证失败,该流程没有流程图不能被发布!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
ResponseResult<TaskInfoVo> taskInfoResult = this.verifyAndGetInitialTaskInfo(flowEntry);
if (!taskInfoResult.isSuccess()) {
return ResponseResult.errorFrom(taskInfoResult);
}
String taskInfo = taskInfoResult.getData() == null ? null : JSON.toJSONString(taskInfoResult.getData());
flowEntryService.publish(flowEntry, taskInfo);
return ResponseResult.success();
}
/**
* 列出符合过滤条件的工作流列表
*
* @param flowEntryDtoFilter 过滤对象
* @param orderParam 排序参数
* @param pageParam 分页参数
* @return 应答结果对象包含查询结果集
*/
@PostMapping("/list")
public ResponseResult<MyPageData<FlowEntryVo>> list(
@MyRequestBody FlowEntryDto flowEntryDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
FlowEntry flowEntryFilter = MyModelUtil.copyTo(flowEntryDtoFilter, FlowEntry.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowEntry.class);
List<FlowEntry> flowEntryList = flowEntryService.getFlowEntryListWithRelation(flowEntryFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(flowEntryList, FlowEntry.INSTANCE));
}
/**
* 查看指定工作流对象详情
*
* @param entryId 指定对象主键Id
* @return 应答结果对象包含对象详情
*/
@GetMapping("/view")
public ResponseResult<FlowEntryVo> view(@RequestParam Long entryId) {
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowEntry flowEntry = flowEntryService.getByIdWithRelation(entryId, MyRelationParam.full());
if (flowEntry == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
FlowEntryVo flowEntryVo = FlowEntry.INSTANCE.fromModel(flowEntry);
flowEntryVo.setStartConditions(flowEntry.getStartConditions());
return ResponseResult.success(flowEntryVo);
}
/**
* 列出指定流程的发布版本列表
*
* @param entryId 流程主键Id
* @return 应答结果对象包含流程发布列表数据
*/
@GetMapping("/listFlowEntryPublish")
public ResponseResult<List<FlowEntryPublishVo>> listFlowEntryPublish(@RequestParam Long entryId) {
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
List<FlowEntryPublish> flowEntryPublishList = flowEntryService.getFlowEntryPublishList(entryId);
return ResponseResult.success(MyModelUtil.copyCollectionTo(flowEntryPublishList, FlowEntryPublishVo.class));
}
/**
* 以字典形式返回全部FlowEntry数据集合字典的键值为[entryId, procDefinitionName]
* 白名单接口登录用户均可访问
*
* @param filter 过滤对象
* @return 应答结果对象包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据
*/
@GetMapping("/listDict")
public ResponseResult<List<Map<String, Object>>> listDict(@ParameterObject FlowEntryVo filter) {
List<FlowEntry> resultList =
flowEntryService.getFlowEntryList(MyModelUtil.copyTo(filter, FlowEntry.class), null);
return ResponseResult.success(
MyCommonUtil.toDictDataList(resultList, FlowEntry::getEntryId, FlowEntry::getProcessDefinitionName));
}
/**
* 获取所有流程分类和流程定义的列表白名单接口
*
* @return 所有流程分类和流程定义的列表
*/
@GetMapping("/listAll")
public ResponseResult<JSONObject> listAll() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("flowEntryList", flowEntryService.getFlowEntryList(null, null));
jsonObject.put("flowCategoryList", flowCategoryService.getFlowCategoryList(null, null));
return ResponseResult.success(jsonObject);
}
/**
* 白名单接口根据流程Id获取流程引擎需要的流程标识和流程名称
*
* @param entryId 流程Id
* @return 流程的部分数据
*/
@GetMapping("/viewDict")
public ResponseResult<Map<String, Object>> viewDict(@RequestParam Long entryId) {
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowEntry flowEntry = verifyResult.getData();
Map<String, Object> resultMap = new HashMap<>(2);
resultMap.put("processDefinitionKey", flowEntry.getProcessDefinitionKey());
resultMap.put("processDefinitionName", flowEntry.getProcessDefinitionName());
return ResponseResult.success(resultMap);
}
/**
* 切换指定工作的发布主版本
*
* @param entryId 工作流主键Id
* @param newEntryPublishId 新的工作流发布主版本对象的主键Id
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/updateMainVersion")
public ResponseResult<Void> updateMainVersion(
@MyRequestBody(required = true) Long entryId,
@MyRequestBody(required = true) Long newEntryPublishId) {
String errorMessage;
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(entryId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishFromCache(newEntryPublishId);
if (flowEntryPublish == null) {
errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (ObjectUtil.notEqual(entryId, flowEntryPublish.getEntryId())) {
errorMessage = "数据验证失败,当前工作流并不包含该工作流发布版本数据,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (BooleanUtil.isTrue(flowEntryPublish.getMainVersion())) {
errorMessage = "数据验证失败,该版本已经为当前工作流的发布主版本,不能重复设置!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
flowEntryService.updateFlowEntryMainVersion(flowEntryService.getById(entryId), flowEntryPublish);
return ResponseResult.success();
}
/**
* 挂起工作流的指定发布版本
*
* @param entryPublishId 工作发布Id
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.SUSPEND)
@PostMapping("/suspendFlowEntryPublish")
public ResponseResult<Void> suspendFlowEntryPublish(@MyRequestBody(required = true) Long entryPublishId) {
String errorMessage;
FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishFromCache(entryPublishId);
if (flowEntryPublish == null) {
errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(flowEntryPublish.getEntryId());
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (BooleanUtil.isFalse(flowEntryPublish.getActiveStatus())) {
errorMessage = "数据验证失败,当前流程发布版本已处于挂起状态!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
flowEntryService.suspendFlowEntryPublish(flowEntryPublish);
return ResponseResult.success();
}
/**
* 激活工作流的指定发布版本
*
* @param entryPublishId 工作发布Id
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.RESUME)
@PostMapping("/activateFlowEntryPublish")
public ResponseResult<Void> activateFlowEntryPublish(@MyRequestBody(required = true) Long entryPublishId) {
String errorMessage;
FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishFromCache(entryPublishId);
if (flowEntryPublish == null) {
errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
ResponseResult<FlowEntry> verifyResult = this.doVerifyAndGet(flowEntryPublish.getEntryId());
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (BooleanUtil.isTrue(flowEntryPublish.getActiveStatus())) {
errorMessage = "数据验证失败,当前流程发布版本已处于激活状态!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
flowEntryService.activateFlowEntryPublish(flowEntryPublish);
return ResponseResult.success();
}
private ResponseResult<FlowEntry> doVerifyAndGet(Long entryId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(entryId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
FlowEntry flowEntry = flowEntryService.getById(entryId);
if (flowEntry == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
TokenData tokenData = TokenData.takeFromRequest();
if (!StrUtil.equals(flowEntry.getAppCode(), tokenData.getAppCode())) {
errorMessage = "数据验证失败,当前应用并不存在该流程定义!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (ObjectUtil.notEqual(flowEntry.getTenantId(), tokenData.getTenantId())) {
errorMessage = "数据验证失败,当前租户并不存在该流程定义!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
return ResponseResult.success(flowEntry);
}
private ResponseResult<TaskInfoVo> verifyAndGetInitialTaskInfo(FlowEntry flowEntry) throws XMLStreamException {
String errorMessage;
BpmnModel bpmnModel = flowApiService.convertToBpmnModel(flowEntry.getBpmnXml());
Process process = bpmnModel.getMainProcess();
if (process == null) {
errorMessage = "数据验证失败,当前流程标识 [" + flowEntry.getProcessDefinitionKey() + "] 关联的流程模型并不存在!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
Collection<FlowElement> elementList = process.getFlowElements();
FlowElement startEvent = null;
// 这里我们只定位流程模型中的第二个节点。
for (FlowElement flowElement : elementList) {
if (flowElement instanceof StartEvent) {
startEvent = flowElement;
break;
}
}
if (startEvent == null) {
errorMessage = "数据验证失败,当前流程图没有包含 [开始事件] 节点,请修改流程图!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
FlowElement firstTask = this.findFirstTask(elementList, startEvent);
if (firstTask == null) {
errorMessage = "数据验证失败,当前流程图没有包含 [开始事件] 节点没有任何连线,请修改流程图!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
TaskInfoVo taskInfoVo;
if (firstTask instanceof UserTask) {
UserTask userTask = (UserTask) firstTask;
String formKey = userTask.getFormKey();
if (StrUtil.isNotBlank(formKey)) {
taskInfoVo = JSON.parseObject(formKey, TaskInfoVo.class);
} else {
taskInfoVo = new TaskInfoVo();
}
taskInfoVo.setAssignee(userTask.getAssignee());
taskInfoVo.setTaskKey(userTask.getId());
taskInfoVo.setTaskType(FlowTaskType.USER_TYPE);
Map<String, List<ExtensionElement>> extensionMap = userTask.getExtensionElements();
if (MapUtil.isNotEmpty(extensionMap)) {
taskInfoVo.setOperationList(flowTaskExtService.buildOperationListExtensionElement(extensionMap));
taskInfoVo.setVariableList(flowTaskExtService.buildVariableListExtensionElement(extensionMap));
}
} else {
taskInfoVo = new TaskInfoVo();
taskInfoVo.setTaskType(FlowTaskType.OTHER_TYPE);
}
return ResponseResult.success(taskInfoVo);
}
private FlowElement findFirstTask(Collection<FlowElement> elementList, FlowElement startEvent) {
for (FlowElement flowElement : elementList) {
if (flowElement instanceof SequenceFlow) {
SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
if (sequenceFlow.getSourceFlowElement().equals(startEvent)) {
return sequenceFlow.getTargetFlowElement();
}
}
}
return null;
}
}

156
common/common-flow/src/main/java/apelet/common/flow/controller/FlowEntryVariableController.java

@ -0,0 +1,156 @@ @@ -0,0 +1,156 @@
package apelet.common.flow.controller;
import apelet.common.core.annotation.MyRequestBody;
import apelet.common.core.constant.ErrorCodeEnum;
import apelet.common.core.object.*;
import apelet.common.core.util.MyCommonUtil;
import apelet.common.core.util.MyModelUtil;
import apelet.common.core.util.MyPageUtil;
import apelet.common.core.validator.UpdateGroup;
import apelet.common.flow.dto.FlowEntryVariableDto;
import apelet.common.flow.model.FlowEntryVariable;
import apelet.common.flow.service.FlowEntryVariableService;
import apelet.common.flow.vo.FlowEntryVariableVo;
import apelet.common.log.annotation.OperationLog;
import apelet.common.log.model.constant.SysOperationLogType;
import com.github.pagehelper.page.PageMethod;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import javax.validation.groups.Default;
import java.util.List;
/**
* 工作流流程变量接口
*
* @author guifc
* @date 2023-08-04
*/
@Tag(name = "工作流流程变量接口")
@Slf4j
@RestController
@RequestMapping("${common-flow.urlPrefix}/flowEntryVariable")
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
public class FlowEntryVariableController {
@Autowired
private FlowEntryVariableService flowEntryVariableService;
/**
* 新增流程变量数据
*
* @param flowEntryVariableDto 新增对象
* @return 应答结果对象包含新增对象主键Id
*/
@ApiOperationSupport(ignoreParameters = {"flowEntryVariableDto.variableId"})
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody FlowEntryVariableDto flowEntryVariableDto) {
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryVariableDto);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
FlowEntryVariable flowEntryVariable = MyModelUtil.copyTo(flowEntryVariableDto, FlowEntryVariable.class);
flowEntryVariable = flowEntryVariableService.saveNew(flowEntryVariable);
return ResponseResult.success(flowEntryVariable.getVariableId());
}
/**
* 更新流程变量数据
*
* @param flowEntryVariableDto 更新对象
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody FlowEntryVariableDto flowEntryVariableDto) {
String errorMessage = MyCommonUtil.getModelValidationError(flowEntryVariableDto, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
FlowEntryVariable flowEntryVariable = MyModelUtil.copyTo(flowEntryVariableDto, FlowEntryVariable.class);
FlowEntryVariable originalFlowEntryVariable = flowEntryVariableService.getById(flowEntryVariable.getVariableId());
if (originalFlowEntryVariable == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!flowEntryVariableService.update(flowEntryVariable, originalFlowEntryVariable)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除流程变量数据
*
* @param variableId 删除对象主键Id
* @return 应答结果对象
*/
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long variableId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(variableId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
FlowEntryVariable originalFlowEntryVariable = flowEntryVariableService.getById(variableId);
if (originalFlowEntryVariable == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!flowEntryVariableService.remove(variableId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的流程变量列表
*
* @param flowEntryVariableDtoFilter 过滤对象
* @param orderParam 排序参数
* @param pageParam 分页参数
* @return 应答结果对象包含查询结果集
*/
@PostMapping("/list")
public ResponseResult<MyPageData<FlowEntryVariableVo>> list(
@MyRequestBody FlowEntryVariableDto flowEntryVariableDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
FlowEntryVariable flowEntryVariableFilter = MyModelUtil.copyTo(flowEntryVariableDtoFilter, FlowEntryVariable.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowEntryVariable.class);
List<FlowEntryVariable> flowEntryVariableList =
flowEntryVariableService.getFlowEntryVariableListWithRelation(flowEntryVariableFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(flowEntryVariableList, FlowEntryVariable.INSTANCE));
}
/**
* 查看指定流程变量对象详情
*
* @param variableId 指定对象主键Id
* @return 应答结果对象包含对象详情
*/
@GetMapping("/view")
public ResponseResult<FlowEntryVariableVo> view(@RequestParam Long variableId) {
if (MyCommonUtil.existBlankArgument(variableId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
FlowEntryVariable flowEntryVariable = flowEntryVariableService.getByIdWithRelation(variableId, MyRelationParam.full());
if (flowEntryVariable == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
FlowEntryVariableVo flowEntryVariableVo = FlowEntryVariable.INSTANCE.fromModel(flowEntryVariable);
return ResponseResult.success(flowEntryVariableVo);
}
}

113
common/common-flow/src/main/java/apelet/common/flow/controller/FlowMessageController.java

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
package apelet.common.flow.controller;
import apelet.common.core.annotation.MyRequestBody;
import apelet.common.core.constant.ErrorCodeEnum;
import apelet.common.core.object.MyPageData;
import apelet.common.core.object.MyPageParam;
import apelet.common.core.object.ResponseResult;
import apelet.common.core.util.MyPageUtil;
import apelet.common.flow.model.FlowMessage;
import apelet.common.flow.model.constant.FlowMessageType;
import apelet.common.flow.service.FlowMessageService;
import apelet.common.flow.vo.FlowMessageVo;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.page.PageMethod;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 工作流消息接口
*
* @author guifc
* @date 2023-08-04
*/
@Tag(name = "工作流消息接口")
@Slf4j
@RestController
@RequestMapping("${common-flow.urlPrefix}/flowMessage")
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
public class FlowMessageController {
@Autowired
private FlowMessageService flowMessageService;
/**
* 获取当前用户的未读消息总数
* NOTE白名单接口
*
* @return 应答结果对象包含当前用户的未读消息总数
*/
@GetMapping("/getMessageCount")
public ResponseResult<JSONObject> getMessageCount() {
JSONObject resultData = new JSONObject();
resultData.put("remindingMessageCount", flowMessageService.countRemindingMessageListByUser());
resultData.put("copyMessageCount", flowMessageService.countCopyMessageByUser());
resultData.put("sysMessageCount", flowMessageService.countSysMessageByUser());
return ResponseResult.success(resultData);
}
/**
* 获取当前用户的催办消息列表
* 不仅仅包含其中包括当前用户所属角色部门和岗位的候选组催办消息
* NOTE白名单接口
*
* @return 应答结果对象包含查询结果集
*/
@PostMapping("/listRemindingTask")
public ResponseResult<MyPageData<FlowMessageVo>> listRemindingTask(@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
List<FlowMessage> flowMessageList = flowMessageService.getRemindingMessageListByUser();
return ResponseResult.success(MyPageUtil.makeResponseData(flowMessageList, FlowMessage.INSTANCE));
}
/**
* 获取当前用户的抄送消息列表
* 不仅仅包含其中包括当前用户所属角色部门和岗位的候选组抄送消息
* NOTE白名单接口
*
* @param read true表示已读false表示未读
* @return 应答结果对象包含查询结果集
*/
@PostMapping("/listCopyMessage")
public ResponseResult<MyPageData<FlowMessageVo>> listCopyMessage(
@MyRequestBody MyPageParam pageParam, @MyRequestBody Boolean read) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
}
List<FlowMessage> flowMessageList = flowMessageService.getCopyMessageListByUser(read);
return ResponseResult.success(MyPageUtil.makeResponseData(flowMessageList, FlowMessage.INSTANCE));
}
/**
* 读取抄送消息同时更新当前用户对指定抄送消息的读取状态
*
* @param messageId 消息Id
* @return 应答结果对象
*/
@PostMapping("/readCopyTask")
public ResponseResult<Void> readCopyTask(@MyRequestBody Long messageId) {
String errorMessage;
// 验证流程任务的合法性。
FlowMessage flowMessage = flowMessageService.getById(messageId);
if (flowMessage == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
if (flowMessage.getMessageType() != FlowMessageType.COPY_TYPE) {
errorMessage = "数据验证失败,当前消息不是抄送类型消息!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
if (!flowMessageService.isCandidateIdentityOnMessage(messageId)) {
errorMessage = "数据验证失败,当前用户没有权限访问该消息!";
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
flowMessageService.readCopyTask(messageId);
return ResponseResult.success();
}
}

56
common/common-flow/src/main/java/apelet/common/flow/controller/FlowNodeTasksController.java

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
package apelet.common.flow.controller;
import apelet.common.core.annotation.MyRequestBody;
import apelet.common.core.object.ResponseResult;
import apelet.common.flow.model.FlowNodeTasks;
import apelet.common.flow.service.FlowNodeTasksService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 工作流审核设置接口
*
* @author guifc
* @date 2023-08-04
*/
@Tag(name = "工作流审核设置接口")
@Slf4j
@RestController
@RequestMapping("${common-flow.urlPrefix}/flowNodeTasks")
@ConditionalOnProperty(name = "common-flow.operationEnabled", havingValue = "true")
public class FlowNodeTasksController {
@Autowired
FlowNodeTasksService flowNodeTasksService;
@PostMapping("/add")
public ResponseResult<?> add(@RequestBody FlowNodeTasks flowNodeTasks) {
flowNodeTasksService.save(flowNodeTasks);
return ResponseResult.success(flowNodeTasks.getId());
}
@GetMapping("/list")
public ResponseResult<?> getList(@RequestParam String flowId,@RequestParam String taskKey) {
LambdaQueryWrapper<FlowNodeTasks> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(FlowNodeTasks::getFlowId, flowId);
wrapper.eq(FlowNodeTasks::getTaskKey, taskKey);
List<FlowNodeTasks> list = flowNodeTasksService.list(wrapper);
return ResponseResult.success(list);
}
@PostMapping("/delete")
public ResponseResult<?> delete(@MyRequestBody Long id) {
boolean b = flowNodeTasksService.removeById(id);
return ResponseResult.success(b);
}
}

1225
common/common-flow/src/main/java/apelet/common/flow/controller/FlowOperationController.java

File diff suppressed because it is too large Load Diff

26
common/common-flow/src/main/java/apelet/common/flow/dao/FlowCategoryMapper.java

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowCategory;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* FlowCategory数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowCategoryMapper extends BaseDaoMapper<FlowCategory> {
/**
* 获取过滤后的对象列表
*
* @param flowCategoryFilter 主表过滤对象
* @param orderBy 排序字符串order by从句的参数
* @return 对象列表
*/
List<FlowCategory> getFlowCategoryList(
@Param("flowCategoryFilter") FlowCategory flowCategoryFilter, @Param("orderBy") String orderBy);
}

26
common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryMapper.java

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowEntry;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* FlowEntry数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowEntryMapper extends BaseDaoMapper<FlowEntry> {
/**
* 获取过滤后的对象列表
*
* @param flowEntryFilter 主表过滤对象
* @param orderBy 排序字符串order by从句的参数
* @return 对象列表
*/
List<FlowEntry> getFlowEntryList(
@Param("flowEntryFilter") FlowEntry flowEntryFilter, @Param("orderBy") String orderBy);
}

13
common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryPublishMapper.java

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowEntryPublish;
/**
* 数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowEntryPublishMapper extends BaseDaoMapper<FlowEntryPublish> {
}

22
common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryPublishVariableMapper.java

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowEntryPublishVariable;
import java.util.List;
/**
* 数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowEntryPublishVariableMapper extends BaseDaoMapper<FlowEntryPublishVariable> {
/**
* 批量插入流程发布的变量列表
*
* @param entryPublishVariableList 流程发布的变量列表
*/
void insertList(List<FlowEntryPublishVariable> entryPublishVariableList);
}

27
common/common-flow/src/main/java/apelet/common/flow/dao/FlowEntryVariableMapper.java

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowEntryVariable;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 流程变量数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowEntryVariableMapper extends BaseDaoMapper<FlowEntryVariable> {
/**
* 获取过滤后的对象列表
*
* @param flowEntryVariableFilter 主表过滤对象
* @param orderBy 排序字符串order by从句的参数
* @return 对象列表
*/
List<FlowEntryVariable> getFlowEntryVariableList(
@Param("flowEntryVariableFilter") FlowEntryVariable flowEntryVariableFilter,
@Param("orderBy") String orderBy);
}

21
common/common-flow/src/main/java/apelet/common/flow/dao/FlowMessageCandidateIdentityMapper.java

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowMessageCandidateIdentity;
import org.apache.ibatis.annotations.Param;
/**
* 流程任务消息的候选身份数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowMessageCandidateIdentityMapper extends BaseDaoMapper<FlowMessageCandidateIdentity> {
/**
* 删除指定流程实例的消息关联数据
*
* @param processInstanceId 流程实例Id
*/
void deleteByProcessInstanceId(@Param("processInstanceId") String processInstanceId);
}

21
common/common-flow/src/main/java/apelet/common/flow/dao/FlowMessageIdentityOperationMapper.java

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowMessageIdentityOperation;
import org.apache.ibatis.annotations.Param;
/**
* 流程任务消息所属用户的操作数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowMessageIdentityOperationMapper extends BaseDaoMapper<FlowMessageIdentityOperation> {
/**
* 删除指定流程实例的消息关联数据
*
* @param processInstanceId 流程实例Id
*/
void deleteByProcessInstanceId(@Param("processInstanceId") String processInstanceId);
}

86
common/common-flow/src/main/java/apelet/common/flow/dao/FlowMessageMapper.java

@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowMessage;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* 工作流消息数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowMessageMapper extends BaseDaoMapper<FlowMessage> {
/**
* 获取指定用户和身份分组Id集合的催办消息列表
*
* @param tenantId 租户Id
* @param appCode 应用编码
* @param loginName 用户的登录名与流程任务的assignee精确匹配
* @param groupIdSet 用户身份分组Id集合
* @return 查询后的催办消息列表
*/
List<FlowMessage> getRemindingMessageListByUser(
@Param("tenantId") Long tenantId,
@Param("appCode") String appCode,
@Param("loginName") String loginName,
@Param("groupIdSet") Set<String> groupIdSet);
/**
* 获取指定用户和身份分组Id集合的抄送消息列表
*
* @param tenantId 租户Id
* @param appCode 应用编码
* @param loginName 用户登录名
* @param groupIdSet 用户身份分组Id集合
* @param read true表示已读false表示未读
* @return 查询后的抄送消息列表
*/
List<FlowMessage> getCopyMessageListByUser(
@Param("tenantId") Long tenantId,
@Param("appCode") String appCode,
@Param("loginName") String loginName,
@Param("groupIdSet") Set<String> groupIdSet,
@Param("read") Boolean read);
/**
* 计算当前用户催办消息的数量
*
* @param tenantId 租户Id
* @param appCode 应用编码
* @param loginName 用户登录名
* @param groupIdSet 用户身份分组Id集合
* @return 数据数量
*/
int countRemindingMessageListByUser(
@Param("tenantId") Long tenantId,
@Param("appCode") String appCode,
@Param("loginName") String loginName,
@Param("groupIdSet") Set<String> groupIdSet);
/**
* 计算当前用户未读抄送消息的数量
*
* @param tenantId 租户Id
* @param appCode 应用编码
* @param loginName 用户登录名
* @param groupIdSet 用户身份分组Id集合
* @return 数据数量
*/
int countCopyMessageListByUser(
@Param("tenantId") Long tenantId,
@Param("appCode") String appCode,
@Param("loginName") String loginName,
@Param("groupIdSet") Set<String> groupIdSet);
/**
* 计算当前用户未读抄送消息的数量
*
* @param userId 用户Id
* @return 数据数量
*/
int countSysMessageListByUser(Long userId);
}

13
common/common-flow/src/main/java/apelet/common/flow/dao/FlowMultiInstanceTransMapper.java

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowMultiInstanceTrans;
/**
* 流程多实例任务执行流水访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowMultiInstanceTransMapper extends BaseDaoMapper<FlowMultiInstanceTrans> {
}

9
common/common-flow/src/main/java/apelet/common/flow/dao/FlowNodeTasksMapper.java

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowNodeTasks;
public interface FlowNodeTasksMapper extends BaseDaoMapper<FlowNodeTasks> {
}

13
common/common-flow/src/main/java/apelet/common/flow/dao/FlowTaskCommentMapper.java

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowTaskComment;
/**
* 流程任务批注数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowTaskCommentMapper extends BaseDaoMapper<FlowTaskComment> {
}

22
common/common-flow/src/main/java/apelet/common/flow/dao/FlowTaskExtMapper.java

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowTaskExt;
import java.util.List;
/**
* 流程任务扩展数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowTaskExtMapper extends BaseDaoMapper<FlowTaskExt> {
/**
* 批量插入流程任务扩展信息列表
*
* @param flowTaskExtList 流程任务扩展信息列表
*/
void insertList(List<FlowTaskExt> flowTaskExtList);
}

14
common/common-flow/src/main/java/apelet/common/flow/dao/FlowTaskTimeoutJobMapper.java

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowTaskTimeoutJob;
/**
* 超时任务作业操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowTaskTimeoutJobMapper extends BaseDaoMapper<FlowTaskTimeoutJob> {
}

13
common/common-flow/src/main/java/apelet/common/flow/dao/FlowTransProducerMapper.java

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowTransProducer;
/**
* 事务性业务数据生产者访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowTransProducerMapper extends BaseDaoMapper<FlowTransProducer> {
}

14
common/common-flow/src/main/java/apelet/common/flow/dao/FlowVariableLogMapper.java

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowVariableLog;
/**
* 流程请求变量操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowVariableLogMapper extends BaseDaoMapper<FlowVariableLog> {
}

14
common/common-flow/src/main/java/apelet/common/flow/dao/FlowWorkOrderExtMapper.java

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
package apelet.common.flow.dao;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowWorkOrderExt;
/**
* 工作流工单扩展数据操作访问接口
*
* @author guifc
* @date 2023-08-04
*/
public interface FlowWorkOrderExtMapper extends BaseDaoMapper<FlowWorkOrderExt> {
}

49
common/common-flow/src/main/java/apelet/common/flow/dao/FlowWorkOrderMapper.java

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
package apelet.common.flow.dao;
import apelet.common.core.annotation.EnableDataPerm;
import apelet.common.core.base.dao.BaseDaoMapper;
import apelet.common.flow.model.FlowWorkOrder;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 工作流工单表数据操作访问接口
* 如果当前系统支持数据权限过滤当前用户必须要能看自己的工单数据所以需要把EnableDataPerm
* 的mustIncludeUserRule参数设置为true即便当前用户的数据权限中并不包含DataPermRuleType.TYPE_USER_ONLY
* 数据过滤拦截组件也会自动补偿该类型的数据权限以便当前用户可以看到自己发起的工单
*
* @author guifc
* @date 2023-08-04
*/
@EnableDataPerm(mustIncludeUserRule = true)
public interface FlowWorkOrderMapper extends BaseDaoMapper<FlowWorkOrder> {
/**
* 获取过滤后的对象列表
*
* @param flowWorkOrderFilter 主表过滤对象
* @param orderBy 排序字符串order by从句的参数
* @return 对象列表
*/
List<FlowWorkOrder> getFlowWorkOrderList(
@Param("flowWorkOrderFilter") FlowWorkOrder flowWorkOrderFilter, @Param("orderBy") String orderBy);
/**
* 计算指定前缀工单编码的最大值
*
* @param prefix 工单编码前缀
* @return 该工单编码前缀的最大值
*/
@Select("SELECT MAX(work_order_code) FROM zz_flow_work_order WHERE work_order_code LIKE '${prefix}'")
String getMaxWorkOrderCodeByPrefix(@Param("prefix") String prefix);
/**
* 根据工单编码查询指定工单查询过程也会考虑逻辑删除的数据
* @param workOrderCode 工单编码
* @return
*/
@Select("SELECT COUNT(*) FROM zz_flow_work_order WHERE work_order_code = #{workOrderCode}")
int getCountByWorkOrderCode(@Param("workOrderCode") String workOrderCode);
}

56
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowCategoryMapper.xml

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowCategoryMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowCategory">
<id column="category_id" jdbcType="BIGINT" property="categoryId"/>
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="code" jdbcType="VARCHAR" property="code"/>
<result column="show_order" jdbcType="INTEGER" property="showOrder"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
</resultMap>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
<include refid="apelet.common.flow.dao.FlowCategoryMapper.inputFilterRef"/>
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="flowCategoryFilter != null">
<if test="flowCategoryFilter.tenantId == null">
AND zz_flow_category.tenant_id IS NULL
</if>
<if test="flowCategoryFilter.tenantId != null">
AND zz_flow_category.tenant_id = #{flowCategoryFilter.tenantId}
</if>
<if test="flowCategoryFilter.appCode == null">
AND zz_flow_category.app_code IS NULL
</if>
<if test="flowCategoryFilter.appCode != null">
AND zz_flow_category.app_code = #{flowCategoryFilter.appCode}
</if>
<if test="flowCategoryFilter.name != null and flowCategoryFilter.name != ''">
AND zz_flow_category.name = #{flowCategoryFilter.name}
</if>
<if test="flowCategoryFilter.code != null and flowCategoryFilter.code != ''">
AND zz_flow_category.code = #{flowCategoryFilter.code}
</if>
</if>
</sql>
<select id="getFlowCategoryList" resultMap="BaseResultMap" parameterType="apelet.common.flow.model.FlowCategory">
SELECT * FROM zz_flow_category
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

95
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryMapper.xml

@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowEntryMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowEntry">
<id column="entry_id" jdbcType="BIGINT" property="entryId"/>
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
<result column="process_definition_name" jdbcType="VARCHAR" property="processDefinitionName"/>
<result column="process_definition_key" jdbcType="VARCHAR" property="processDefinitionKey"/>
<result column="category_id" jdbcType="BIGINT" property="categoryId"/>
<result column="main_entry_publish_id" jdbcType="BIGINT" property="mainEntryPublishId"/>
<result column="latest_publish_time" jdbcType="TIMESTAMP" property="latestPublishTime"/>
<result column="status" jdbcType="INTEGER" property="status"/>
<result column="bpmn_xml" jdbcType="LONGVARCHAR" property="bpmnXml"/>
<result column="diagram_type" jdbcType="INTEGER" property="diagramType"/>
<result column="bind_form_type" jdbcType="INTEGER" property="bindFormType"/>
<result column="page_id" jdbcType="BIGINT" property="pageId"/>
<result column="default_form_id" jdbcType="BIGINT" property="defaultFormId"/>
<result column="default_router_name" jdbcType="VARCHAR" property="defaultRouterName"/>
<result column="encoded_rule" jdbcType="VARCHAR" property="encodedRule"/>
<result column="extension_data" jdbcType="VARCHAR" property="extensionData"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
</resultMap>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
<include refid="apelet.common.flow.dao.FlowEntryMapper.inputFilterRef"/>
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="flowEntryFilter != null">
<if test="flowEntryFilter.tenantId == null">
AND zz_flow_entry.tenant_id IS NULL
</if>
<if test="flowEntryFilter.tenantId != null">
AND zz_flow_entry.tenant_id = #{flowEntryFilter.tenantId}
</if>
<if test="flowEntryFilter.appCode == null">
AND zz_flow_entry.app_code IS NULL
</if>
<if test="flowEntryFilter.appCode != null">
AND zz_flow_entry.app_code = #{flowEntryFilter.appCode}
</if>
<if test="flowEntryFilter.processDefinitionName != null and flowEntryFilter.processDefinitionName != ''">
AND zz_flow_entry.process_definition_name = #{flowEntryFilter.processDefinitionName}
</if>
<if test="flowEntryFilter.processDefinitionKey != null and flowEntryFilter.processDefinitionKey != ''">
AND zz_flow_entry.process_definition_key = #{flowEntryFilter.processDefinitionKey}
</if>
<if test="flowEntryFilter.categoryId != null">
AND zz_flow_entry.category_id = #{flowEntryFilter.categoryId}
</if>
<if test="flowEntryFilter.status != null">
AND zz_flow_entry.status = #{flowEntryFilter.status}
</if>
</if>
</sql>
<select id="getFlowEntryList" resultMap="BaseResultMap" parameterType="apelet.common.flow.model.FlowEntry">
SELECT
entry_id,
app_code,
process_definition_name,
process_definition_key,
category_id,
main_entry_publish_id,
latest_publish_time,
status,
diagram_type,
bind_form_type,
page_id,
default_form_id,
default_router_name,
encoded_rule,
extension_data,
update_time,
update_user_id,
create_time,
create_user_id,
start_conditions
FROM
zz_flow_entry
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

18
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryPublishMapper.xml

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowEntryPublishMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowEntryPublish">
<id column="entry_publish_id" jdbcType="BIGINT" property="entryPublishId"/>
<result column="entry_id" jdbcType="BIGINT" property="entryId"/>
<result column="deploy_id" jdbcType="VARCHAR" property="deployId"/>
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
<result column="publish_version" jdbcType="INTEGER" property="publishVersion"/>
<result column="active_status" jdbcType="BOOLEAN" property="activeStatus"/>
<result column="main_version" jdbcType="BOOLEAN" property="mainVersion"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="publish_time" jdbcType="TIMESTAMP" property="publishTime"/>
<result column="init_task_info" jdbcType="VARCHAR" property="initTaskInfo"/>
<result column="analyzed_node_json" jdbcType="VARCHAR" property="analyzedNodeJson"/>
<result column="extension_data" jdbcType="VARCHAR" property="extensionData"/>
</resultMap>
</mapper>

30
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryPublishVariableMapper.xml

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowEntryPublishVariableMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowEntryPublishVariable">
<id column="variable_id" jdbcType="BIGINT" property="variableId"/>
<result column="entry_publish_id" jdbcType="BIGINT" property="entryPublishId"/>
<result column="variable_name" jdbcType="VARCHAR" property="variableName"/>
<result column="show_name" jdbcType="VARCHAR" property="showName"/>
<result column="variable_type" jdbcType="INTEGER" property="variableType"/>
<result column="bind_datasource_id" jdbcType="BIGINT" property="bindDatasourceId"/>
<result column="bind_relation_id" jdbcType="BIGINT" property="bindRelationId"/>
<result column="bind_column_id" jdbcType="BIGINT" property="bindColumnId"/>
<result column="builtin" jdbcType="BOOLEAN" property="builtin"/>
</resultMap>
<insert id="insertList">
INSERT INTO zz_flow_entry_publish_variable VALUES
<foreach collection="list" index="index" item="item" separator="," >
(#{item.variableId},
#{item.entryPublishId},
#{item.variableName},
#{item.showName},
#{item.variableType},
#{item.bindDatasourceId},
#{item.bindRelationId},
#{item.bindColumnId},
#{item.builtin})
</foreach>
</insert>
</mapper>

41
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowEntryVariableMapper.xml

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowEntryVariableMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowEntryVariable">
<id column="variable_id" jdbcType="BIGINT" property="variableId"/>
<result column="entry_id" jdbcType="BIGINT" property="entryId"/>
<result column="variable_name" jdbcType="VARCHAR" property="variableName"/>
<result column="show_name" jdbcType="VARCHAR" property="showName"/>
<result column="variable_type" jdbcType="INTEGER" property="variableType"/>
<result column="bind_datasource_id" jdbcType="BIGINT" property="bindDatasourceId"/>
<result column="bind_relation_id" jdbcType="BIGINT" property="bindRelationId"/>
<result column="bind_column_id" jdbcType="BIGINT" property="bindColumnId"/>
<result column="builtin" jdbcType="BOOLEAN" property="builtin"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
</resultMap>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
<include refid="apelet.common.flow.dao.FlowEntryVariableMapper.inputFilterRef"/>
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="flowEntryVariableFilter != null">
<if test="flowEntryVariableFilter.entryId != null">
AND zz_flow_entry_variable.entry_id = #{flowEntryVariableFilter.entryId}
</if>
</if>
</sql>
<select id="getFlowEntryVariableList" resultMap="BaseResultMap" parameterType="apelet.common.flow.model.FlowEntryVariable">
SELECT * FROM zz_flow_entry_variable
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

16
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMessageCandidateIdentityMapper.xml

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowMessageCandidateIdentityMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowMessageCandidateIdentity">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="message_id" jdbcType="BIGINT" property="messageId"/>
<result column="candidate_type" jdbcType="VARCHAR" property="candidateType"/>
<result column="candidate_id" jdbcType="VARCHAR" property="candidateId"/>
</resultMap>
<delete id="deleteByProcessInstanceId">
DELETE FROM zz_flow_msg_candidate_identity a
WHERE EXISTS (SELECT * FROM zz_flow_message b
WHERE a.message_id = b.message_id AND b.process_instance_id = #{processInstanceId})
</delete>
</mapper>

17
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMessageIdentityOperationMapper.xml

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowMessageIdentityOperationMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowMessageIdentityOperation">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="message_id" jdbcType="BIGINT" property="messageId"/>
<result column="login_name" jdbcType="VARCHAR" property="loginName"/>
<result column="operation_type" jdbcType="INTEGER" property="operationType"/>
<result column="operation_time" jdbcType="TIMESTAMP" property="operationTime"/>
</resultMap>
<delete id="deleteByProcessInstanceId">
DELETE FROM zz_flow_msg_identity_operation a
WHERE EXISTS (SELECT * FROM zz_flow_message b
WHERE a.message_id = b.message_id AND b.process_instance_id = #{processInstanceId})
</delete>
</mapper>

119
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMessageMapper.xml

@ -0,0 +1,119 @@ @@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowMessageMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowMessage">
<id column="message_id" jdbcType="BIGINT" property="messageId"/>
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
<result column="message_type" jdbcType="TINYINT" property="messageType"/>
<result column="message_content" jdbcType="VARCHAR" property="messageContent"/>
<result column="remind_count" jdbcType="INTEGER" property="remindCount"/>
<result column="work_order_id" jdbcType="BIGINT" property="workOrderId"/>
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
<result column="process_definition_key" jdbcType="VARCHAR" property="processDefinitionKey"/>
<result column="process_definition_name" jdbcType="VARCHAR" property="processDefinitionName"/>
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
<result column="process_instance_initiator" jdbcType="VARCHAR" property="processInstanceInitiator"/>
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
<result column="task_definition_key" jdbcType="VARCHAR" property="taskDefinitionKey"/>
<result column="task_name" jdbcType="VARCHAR" property="taskName"/>
<result column="task_start_time" jdbcType="TIMESTAMP" property="taskStartTime"/>
<result column="task_assignee" jdbcType="VARCHAR" property="taskAssignee"/>
<result column="task_finished" jdbcType="BOOLEAN" property="taskFinished"/>
<result column="business_data_shot" jdbcType="LONGVARCHAR" property="businessDataShot"/>
<result column="online_form_data" jdbcType="BOOLEAN" property="onlineFormData"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_username" jdbcType="VARCHAR" property="createUsername"/>
</resultMap>
<sql id="filterRef">
<if test="tenantId == null">
AND a.tenant_id IS NULL
</if>
<if test="tenantId != null">
AND a.tenant_id = #{tenantId}
</if>
<if test="appCode == null">
AND a.app_code IS NULL
</if>
<if test="appCode != null">
AND a.app_code = #{appCode}
</if>
</sql>
<select id="getRemindingMessageListByUser" resultMap="BaseResultMap">
SELECT a.* FROM zz_flow_message a
<where>
<include refid="filterRef"/>
AND a.task_finished = false
AND a.message_type = 0
AND (a.task_assignee = #{loginName} OR EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
WHERE a.message_id = b.message_id AND b.candidate_id IN
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>))
</where>
ORDER BY a.update_time DESC
</select>
<select id="getCopyMessageListByUser" resultMap="BaseResultMap">
SELECT a.* FROM zz_flow_message a
<where>
<include refid="filterRef"/>
AND a.message_type = 1
AND EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
WHERE a.message_id = b.message_id AND b.candidate_id IN
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>)
<if test="!read">
AND NOT EXISTS (SELECT * FROM zz_flow_msg_identity_operation c
WHERE a.message_id = c.message_id AND c.login_name = #{loginName})
</if>
<if test="read">
AND EXISTS (SELECT * FROM zz_flow_msg_identity_operation c
WHERE a.message_id = c.message_id AND c.login_name = #{loginName})
</if>
</where>
ORDER BY a.update_time DESC
</select>
<select id="countRemindingMessageListByUser" resultType="java.lang.Integer">
SELECT COUNT(1) FROM zz_flow_message a
<where>
<include refid="filterRef"/>
AND a.task_finished = false
AND a.message_type = 0
AND (a.task_assignee = #{loginName} OR EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
WHERE a.message_id = b.message_id AND b.candidate_id IN
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>))
</where>
</select>
<select id="countCopyMessageListByUser" resultType="java.lang.Integer">
SELECT COUNT(1) FROM zz_flow_message a
<where>
<include refid="filterRef"/>
AND a.message_type = 1
AND EXISTS (SELECT * FROM zz_flow_msg_candidate_identity b
WHERE a.message_id = b.message_id AND b.candidate_id IN
<foreach collection="groupIdSet" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>)
AND NOT EXISTS (SELECT * FROM zz_flow_msg_identity_operation c
WHERE a.message_id = c.message_id AND c.login_name = #{loginName})
</where>
</select>
<select id="countSysMessageListByUser" resultType="java.lang.Integer">
SELECT COUNT(1) FROM sys_message_entry a
<where>
AND a.read_status = 0
and a.receive_user_id=#{userId}
</where>
</select>
</mapper>

17
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowMultiInstanceTransMapper.xml

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowMultiInstanceTransMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowMultiInstanceTrans">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
<result column="multi_instance_exec_id" jdbcType="VARCHAR" property="multiInstanceExecId"/>
<result column="execution_id" jdbcType="VARCHAR" property="executionId"/>
<result column="assignee_list" jdbcType="LONGVARCHAR" property="assigneeList"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_login_name" jdbcType="VARCHAR" property="createLoginName"/>
<result column="create_username" jdbcType="VARCHAR" property="createUsername"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
</resultMap>
</mapper>

23
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskCommentMapper.xml

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowTaskCommentMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowTaskComment">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
<result column="task_name" jdbcType="VARCHAR" property="taskName"/>
<result column="target_task_key" jdbcType="VARCHAR" property="targetTaskKey"/>
<result column="execution_id" jdbcType="VARCHAR" property="executionId"/>
<result column="multi_instance_exec_id" jdbcType="VARCHAR" property="multiInstanceExecId"/>
<result column="approval_type" jdbcType="VARCHAR" property="approvalType"/>
<result column="delegate_assignee" jdbcType="VARCHAR" property="delegateAssignee"/>
<result column="custom_business_data" jdbcType="LONGVARCHAR" property="customBusinessData"/>
<result column="task_comment" jdbcType="VARCHAR" property="taskComment"/>
<result column="head_image_url" jdbcType="VARCHAR" property="headImageUrl"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_login_name" jdbcType="VARCHAR" property="createLoginName"/>
<result column="create_username" jdbcType="VARCHAR" property="createUsername"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
</resultMap>
</mapper>

36
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskExtMapper.xml

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowTaskExtMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowTaskExt">
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
<result column="operation_list_json" jdbcType="LONGVARCHAR" property="operationListJson"/>
<result column="variable_list_json" jdbcType="LONGVARCHAR" property="variableListJson"/>
<result column="assignee_list_json" jdbcType="LONGVARCHAR" property="assigneeListJson"/>
<result column="group_type" jdbcType="VARCHAR" property="groupType"/>
<result column="dept_post_list_json" jdbcType="VARCHAR" property="deptPostListJson"/>
<result column="role_ids" jdbcType="VARCHAR" property="roleIds"/>
<result column="dept_ids" jdbcType="VARCHAR" property="deptIds"/>
<result column="candidate_usernames" jdbcType="VARCHAR" property="candidateUsernames"/>
<result column="copy_list_json" jdbcType="VARCHAR" property="copyListJson"/>
<result column="extra_data_json" jdbcType="VARCHAR" property="extraDataJson"/>
</resultMap>
<insert id="insertList">
INSERT INTO zz_flow_task_ext VALUES
<foreach collection="list" index="index" item="item" separator="," >
(#{item.processDefinitionId},
#{item.taskId},
#{item.operationListJson},
#{item.variableListJson},
#{item.assigneeListJson},
#{item.groupType},
#{item.deptPostListJson},
#{item.roleIds},
#{item.deptIds},
#{item.candidateUsernames},
#{item.copyListJson},
#{item.extraDataJson})
</foreach>
</insert>
</mapper>

19
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTaskTimeoutJobMapper.xml

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowTaskTimeoutJobMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowTaskTimeoutJob">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
<result column="timeout_hours" jdbcType="INTEGER" property="timeoutHours"/>
<result column="handle_way" jdbcType="VARCHAR" property="handleWay"/>
<result column="default_assignee" jdbcType="VARCHAR" property="defaultAssignee"/>
<result column="status" jdbcType="INTEGER" property="status"/>
<result column="error_message" jdbcType="LONGVARCHAR" property="errorMessage"/>
<result column="exec_time" jdbcType="TIMESTAMP" property="execTime"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
</mapper>

23
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowTransProducerMapper.xml

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowTransProducerMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowTransProducer">
<id column="trans_id" jdbcType="BIGINT" property="transId"/>
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
<result column="dblink_id" jdbcType="BIGINT" property="dblinkId"/>
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
<result column="task_id" jdbcType="VARCHAR" property="taskId"/>
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
<result column="task_name" jdbcType="VARCHAR" property="taskName"/>
<result column="task_comment" jdbcType="VARCHAR" property="taskComment"/>
<result column="url" jdbcType="VARCHAR" property="url"/>
<result column="init_method" jdbcType="VARCHAR" property="initMethod"/>
<result column="trace_id" jdbcType="VARCHAR" property="traceId"/>
<result column="sql_data" jdbcType="LONGVARCHAR" property="sqlData"/>
<result column="try_times" jdbcType="INTEGER" property="tryTimes"/>
<result column="error_reason" jdbcType="LONGVARCHAR" property="errorReason"/>
<result column="create_login_name" jdbcType="VARCHAR" property="createUsername"/>
<result column="create_username" jdbcType="VARCHAR" property="createLoginName"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
</resultMap>
</mapper>

13
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowVariableLogMapper.xml

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowVariableLogMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowVariableLog">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="process_definition_key" jdbcType="VARCHAR" property="processDefinitionKey"/>
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
<result column="task_key" jdbcType="VARCHAR" property="taskKey"/>
<result column="variable_data" jdbcType="LONGVARCHAR" property="variableData"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="expired_time" jdbcType="TIMESTAMP" property="expiredTime"/>
</resultMap>
</mapper>

15
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowWorkOrderExtMapper.xml

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowWorkOrderExtMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowWorkOrderExt">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="work_order_id" jdbcType="BIGINT" property="workOrderId"/>
<result column="draft_data" jdbcType="LONGVARCHAR" property="draftData"/>
<result column="business_data" jdbcType="LONGVARCHAR" property="businessData"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="deleted_flag" jdbcType="INTEGER" property="deletedFlag"/>
</resultMap>
</mapper>

82
common/common-flow/src/main/java/apelet/common/flow/dao/mapper/FlowWorkOrderMapper.xml

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="apelet.common.flow.dao.FlowWorkOrderMapper">
<resultMap id="BaseResultMap" type="apelet.common.flow.model.FlowWorkOrder">
<id column="work_order_id" jdbcType="BIGINT" property="workOrderId"/>
<result column="tenant_id" jdbcType="BIGINT" property="tenantId"/>
<result column="app_code" jdbcType="VARCHAR" property="appCode"/>
<result column="work_order_code" jdbcType="VARCHAR" property="workOrderCode"/>
<result column="process_definition_key" jdbcType="VARCHAR" property="processDefinitionKey"/>
<result column="process_definition_name" jdbcType="VARCHAR" property="processDefinitionName"/>
<result column="process_definition_id" jdbcType="VARCHAR" property="processDefinitionId"/>
<result column="process_instance_id" jdbcType="VARCHAR" property="processInstanceId"/>
<result column="online_table_id" jdbcType="BIGINT" property="onlineTableId"/>
<result column="table_name" jdbcType="VARCHAR" property="tableName"/>
<result column="business_key" jdbcType="VARCHAR" property="businessKey"/>
<result column="latest_approval_status" jdbcType="INTEGER" property="latestApprovalStatus"/>
<result column="flow_status" jdbcType="INTEGER" property="flowStatus"/>
<result column="submit_username" jdbcType="VARCHAR" property="submitUsername"/>
<result column="dept_id" jdbcType="BIGINT" property="deptId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="deleted_flag" jdbcType="INTEGER" property="deletedFlag"/>
</resultMap>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
<include refid="apelet.common.flow.dao.FlowWorkOrderMapper.inputFilterRef"/>
AND zz_flow_work_order.deleted_flag = ${@apelet.common.core.constant.GlobalDeletedFlag@NORMAL}
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="flowWorkOrderFilter != null">
<if test="flowWorkOrderFilter.tenantId == null">
AND zz_flow_work_order.tenant_id IS NULL
</if>
<if test="flowWorkOrderFilter.tenantId != null">
AND zz_flow_work_order.tenant_id = #{flowWorkOrderFilter.tenantId}
</if>
<if test="flowWorkOrderFilter.appCode == null">
AND zz_flow_work_order.app_code IS NULL
</if>
<if test="flowWorkOrderFilter.appCode != null">
AND zz_flow_work_order.app_code = #{flowWorkOrderFilter.appCode}
</if>
<if test="flowWorkOrderFilter.workOrderCode != null and flowWorkOrderFilter.workOrderCode != ''">
AND zz_flow_work_order.work_order_code = #{flowWorkOrderFilter.workOrderCode}
</if>
<if test="flowWorkOrderFilter.processDefinitionKey != null and flowWorkOrderFilter.processDefinitionKey != ''">
AND zz_flow_work_order.process_definition_key = #{flowWorkOrderFilter.processDefinitionKey}
</if>
<if test="flowWorkOrderFilter.latestApprovalStatus != null">
AND zz_flow_work_order.latest_approval_status = #{flowWorkOrderFilter.latestApprovalStatus}
</if>
<if test="flowWorkOrderFilter.flowStatus != null">
AND zz_flow_work_order.flow_status = #{flowWorkOrderFilter.flowStatus}
</if>
<if test="flowWorkOrderFilter.createTimeStart != null and flowWorkOrderFilter.createTimeStart != ''">
AND zz_flow_work_order.create_time &gt;= #{flowWorkOrderFilter.createTimeStart}
</if>
<if test="flowWorkOrderFilter.createTimeEnd != null and flowWorkOrderFilter.createTimeEnd != ''">
AND zz_flow_work_order.create_time &lt;= #{flowWorkOrderFilter.createTimeEnd}
</if>
<if test="flowWorkOrderFilter.createUserId != null">
AND zz_flow_work_order.create_user_id = #{flowWorkOrderFilter.createUserId}
</if>
</if>
</sql>
<select id="getFlowWorkOrderList" resultMap="BaseResultMap" parameterType="apelet.common.flow.model.FlowWorkOrder">
SELECT * FROM zz_flow_work_order
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

47
common/common-flow/src/main/java/apelet/common/flow/dto/FlowCategoryDto.java

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
package apelet.common.flow.dto;
import apelet.common.core.validator.UpdateGroup;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 流程分类的Dto对象
*
* @author guifc
* @date 2023-08-04
*/
@Schema(description = "流程分类的Dto对象")
@Data
public class FlowCategoryDto {
/**
* 主键Id
*/
@Schema(description = "主键Id")
@NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class})
private Long categoryId;
/**
* 显示名称
*/
@Schema(description = "显示名称")
@NotBlank(message = "数据验证失败,显示名称不能为空!")
private String name;
/**
* 分类编码
*/
@Schema(description = "分类编码")
@NotBlank(message = "数据验证失败,分类编码不能为空!")
private String code;
/**
* 实现顺序
*/
@Schema(description = "实现顺序")
@NotNull(message = "数据验证失败,实现顺序不能为空!")
private Integer showOrder;
}

114
common/common-flow/src/main/java/apelet/common/flow/dto/FlowEntryDto.java

@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
package apelet.common.flow.dto;
import apelet.common.core.validator.ConstDictRef;
import apelet.common.core.validator.UpdateGroup;
import apelet.common.flow.model.constant.FlowBindFormType;
import apelet.common.flow.model.constant.FlowEntryStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 流程的Dto对象
*
* @author guifc
* @date 2023-08-04
*/
@Schema(description = "流程的Dto对象")
@Data
public class FlowEntryDto {
/**
* 主键Id
*/
@Schema(description = "主键Id")
@NotNull(message = "数据验证失败,主键不能为空!", groups = {UpdateGroup.class})
private Long entryId;
/**
* 流程名称
*/
@Schema(description = "流程名称")
@NotBlank(message = "数据验证失败,流程名称不能为空!")
private String processDefinitionName;
/**
* 流程标识Key
*/
@Schema(description = "流程标识Key")
@NotBlank(message = "数据验证失败,流程标识Key不能为空!")
private String processDefinitionKey;
/**
* 流程分类
*/
@Schema(description = "流程分类")
@NotNull(message = "数据验证失败,流程分类不能为空!")
private Long categoryId;
/**
* 流程状态
*/
@Schema(description = "流程状态")
@ConstDictRef(constDictClass = FlowEntryStatus.class, message = "数据验证失败,工作流状态为无效值!")
private Integer status;
/**
* 流程定义的xml
*/
@Schema(description = "流程定义的xml")
private String bpmnXml;
/**
* 流程图类型0: 普通流程图1: 钉钉风格的流程图
*/
@Schema(description = "流程图类型。0: 普通流程图,1: 钉钉风格的流程图。")
private Integer diagramType;
/**
* 绑定表单类型
*/
@Schema(description = "绑定表单类型")
@ConstDictRef(constDictClass = FlowBindFormType.class, message = "数据验证失败,工作流绑定表单类型为无效值!")
@NotNull(message = "数据验证失败,工作流绑定表单类型不能为空!")
private Integer bindFormType;
/**
* 在线表单的页面Id
*/
@Schema(description = "在线表单的页面Id")
private Long pageId;
/**
* 在线表单的缺省路由名称
*/
@Schema(description = "在线表单的缺省路由名称")
private String defaultRouterName;
/**
* 在线表单Id
*/
@Schema(description = "在线表单Id")
private Long defaultFormId;
/**
* 工单表编码字段的编码规则如果为空则不计算工单编码
*/
@Schema(description = "工单表编码字段的编码规则")
private String encodedRule;
/**
* 流程的自定义扩展数据(JSON格式)
*/
@Schema(description = "流程的自定义扩展数据")
private String extensionData;
/**
* 流程启动条件
*/
@Schema(description = "流程启动条件")
private String startConditions;
}

82
common/common-flow/src/main/java/apelet/common/flow/dto/FlowEntryVariableDto.java

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
package apelet.common.flow.dto;
import apelet.common.core.validator.ConstDictRef;
import apelet.common.core.validator.UpdateGroup;
import apelet.common.flow.model.constant.FlowVariableType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 流程变量Dto对象
*
* @author guifc
* @date 2023-08-04
*/
@Schema(description = "流程变量Dto对象")
@Data
public class FlowEntryVariableDto {
/**
* 主键Id
*/
@Schema(description = "主键Id")
@NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class})
private Long variableId;
/**
* 流程Id
*/
@Schema(description = "流程Id")
@NotNull(message = "数据验证失败,流程Id不能为空!")
private Long entryId;
/**
* 变量名
*/
@Schema(description = "变量名")
@NotBlank(message = "数据验证失败,变量名不能为空!")
private String variableName;
/**
* 显示名
*/
@Schema(description = "显示名")
@NotBlank(message = "数据验证失败,显示名不能为空!")
private String showName;
/**
* 流程变量类型
*/
@Schema(description = "流程变量类型")
@ConstDictRef(constDictClass = FlowVariableType.class, message = "数据验证失败,流程变量类型为无效值!")
@NotNull(message = "数据验证失败,流程变量类型不能为空!")
private Integer variableType;
/**
* 绑定数据源Id
*/
@Schema(description = "绑定数据源Id")
private Long bindDatasourceId;
/**
* 绑定数据源关联Id
*/
@Schema(description = "绑定数据源关联Id")
private Long bindRelationId;
/**
* 绑定字段Id
*/
@Schema(description = "绑定字段Id")
private Long bindColumnId;
/**
* 是否内置
*/
@Schema(description = "是否内置")
@NotNull(message = "数据验证失败,是否内置不能为空!")
private Boolean builtin;
}

51
common/common-flow/src/main/java/apelet/common/flow/dto/FlowMessageDto.java

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
package apelet.common.flow.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 工作流通知消息Dto对象
*
* @author guifc
* @date 2023-08-04
*/
@Schema(description = "工作流通知消息Dto对象")
@Data
public class FlowMessageDto {
/**
* 消息类型
*/
@Schema(description = "消息类型")
private Integer messageType;
/**
* 工单Id
*/
@Schema(description = "工单Id")
private Long workOrderId;
/**
* 流程名称
*/
@Schema(description = "流程名称")
private String processDefinitionName;
/**
* 流程任务名称
*/
@Schema(description = "流程任务名称")
private String taskName;
/**
* 更新时间范围过滤起始值(>=)
*/
@Schema(description = "updateTime 范围过滤起始值")
private String updateTimeStart;
/**
* 更新时间范围过滤结束值(<=)
*/
@Schema(description = "updateTime 范围过滤结束值")
private String updateTimeEnd;
}

38
common/common-flow/src/main/java/apelet/common/flow/dto/FlowTaskCommentDto.java

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
package apelet.common.flow.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 流程任务的批注
*
* @author guifc
* @date 2023-08-04
*/
@Schema(description = "流程任务的批注")
@Data
public class FlowTaskCommentDto {
/**
* 流程任务触发按钮类型内置值可参考FlowTaskButton
*/
@Schema(description = "流程任务触发按钮类型")
@NotNull(message = "数据验证失败,任务的审批类型不能为空!")
private String approvalType;
/**
* 流程任务的批注内容
*/
@Schema(description = "流程任务的批注内容")
@NotBlank(message = "数据验证失败,任务审批内容不能为空!")
private String taskComment;
/**
* 委托指定人比如加签转办等
*/
@Schema(description = "委托指定人,比如加签、转办等")
private String delegateAssignee;
}

39
common/common-flow/src/main/java/apelet/common/flow/dto/FlowWorkOrderDto.java

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
package apelet.common.flow.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 工作流工单Dto对象
*
* @author guifc
* @date 2023-08-04
*/
@Schema(description = "工作流工单Dto对象")
@Data
public class FlowWorkOrderDto {
/**
* 工单编码
*/
@Schema(description = "工单编码")
private String workOrderCode;
/**
* 流程状态参考FlowTaskStatus常量值对象
*/
@Schema(description = "流程状态")
private Integer flowStatus;
/**
* createTime 范围过滤起始值(>=)
*/
@Schema(description = "createTime 范围过滤起始值")
private String createTimeStart;
/**
* createTime 范围过滤结束值(<=)
*/
@Schema(description = "createTime 范围过滤结束值")
private String createTimeEnd;
}

35
common/common-flow/src/main/java/apelet/common/flow/exception/FlowEmptyUserException.java

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
package apelet.common.flow.exception;
/**
* 流程空用户异常
*
* @author guifc
* @date 2023-08-04
*/
public class FlowEmptyUserException extends RuntimeException {
/**
* 构造函数
*/
public FlowEmptyUserException() {
}
/**
* 构造函数
*
* @param throwable 引发异常对象
*/
public FlowEmptyUserException(Throwable throwable) {
super(throwable);
}
/**
* 构造函数
*
* @param msg 错误信息
*/
public FlowEmptyUserException(String msg) {
super(msg);
}
}

35
common/common-flow/src/main/java/apelet/common/flow/exception/FlowOperationException.java

@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
package apelet.common.flow.exception;
/**
* 流程操作异常
*
* @author guifc
* @date 2023-08-04
*/
public class FlowOperationException extends RuntimeException {
/**
* 构造函数
*/
public FlowOperationException() {
}
/**
* 构造函数
*
* @param throwable 引发异常对象
*/
public FlowOperationException(Throwable throwable) {
super(throwable);
}
/**
* 构造函数
*
* @param msg 错误信息
*/
public FlowOperationException(String msg) {
super(msg);
}
}

161
common/common-flow/src/main/java/apelet/common/flow/listener/AutoSkipListener.java

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
package apelet.common.flow.listener;
import apelet.common.core.object.TokenData;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.constant.FlowApprovalType;
import apelet.common.flow.constant.FlowConstant;
import apelet.common.flow.model.FlowTaskComment;
import apelet.common.flow.model.FlowTaskExt;
import apelet.common.flow.service.FlowApiService;
import apelet.common.flow.service.FlowTaskCommentService;
import apelet.common.flow.service.FlowTaskExtService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import java.util.*;
/**
* 流程任务自动审批跳过的监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class AutoSkipListener implements ExecutionListener {
private final transient FlowTaskCommentService flowTaskCommentService =
ApplicationContextHolder.getBean(FlowTaskCommentService.class);
private final transient FlowApiService flowApiService =
ApplicationContextHolder.getBean(FlowApiService.class);
private final transient FlowTaskExtService flowTaskExtService =
ApplicationContextHolder.getBean(FlowTaskExtService.class);
/**
* 流程的发起者等于当前任务的Assignee
*/
private static final String EQ_START_USER = "0";
/**
* 上一步的提交者等于当前任务的Assignee
*/
private static final String EQ_PREV_SUBMIT_USER = "1";
/**
* 当前任务的Assignee之前提交过审核
*/
private static final String EQ_HISTORIC_SUBMIT_USER = "2";
@Override
public void notify(DelegateExecution execution) {
UserTask userTask = (UserTask) execution.getCurrentFlowElement();
List<ExtensionAttribute> attributes = userTask.getAttributes().get(FlowConstant.USER_TASK_AUTO_SKIP_KEY);
Set<String> skipTypes = new HashSet<>(StrUtil.split(attributes.get(0).getValue(), ","));
String assignedUser = this.getAssignedUser(execution);
if (StrUtil.isBlank(assignedUser)) {
return;
}
for (String skipType : skipTypes) {
if (this.verifyAndHandle(execution, skipType, assignedUser)) {
return;
}
}
}
private boolean verifyAndHandle(DelegateExecution execution, String skipType, String assignedUser) {
FlowTaskComment comment = null;
switch (skipType) {
case EQ_START_USER:
Object v = execution.getVariable(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR);
if (ObjectUtil.equal(v, assignedUser)) {
comment = flowTaskCommentService.getFirstFlowTaskComment(execution.getProcessInstanceId());
}
break;
case EQ_PREV_SUBMIT_USER:
Object v2 = execution.getVariable(FlowConstant.SUBMIT_USER_VAR);
if (ObjectUtil.equal(v2, assignedUser)) {
TokenData tokenData = TokenData.takeFromRequest();
comment = new FlowTaskComment();
comment.setCreateUserId(tokenData.getUserId());
comment.setCreateLoginName(tokenData.getLoginName());
comment.setCreateUsername(tokenData.getShowName());
}
break;
case EQ_HISTORIC_SUBMIT_USER:
List<FlowTaskComment> comments =
flowTaskCommentService.getFlowTaskCommentList(execution.getProcessInstanceId());
List<FlowTaskComment> resultComments = new LinkedList<>();
for (FlowTaskComment c : comments) {
if (StrUtil.equals(c.getCreateLoginName(), assignedUser)) {
resultComments.add(c);
}
}
if (CollUtil.isNotEmpty(resultComments)) {
comment = resultComments.get(0);
}
break;
default:
break;
}
UserTask userTask = (UserTask) execution.getCurrentFlowElement();
if (comment != null) {
execution.setVariable("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
userTask.setSkipExpression("${1==1}");
comment.setTaskId(userTask.getId());
comment.setTaskKey(userTask.getId());
comment.setTaskName(userTask.getName());
comment.setProcessInstanceId(execution.getProcessInstanceId());
comment.setExecutionId(execution.getId());
comment.setApprovalType(FlowApprovalType.AGREE);
comment.setTaskComment(StrFormatter.format("自动跳过审批。审批人 [{}], 跳过原因 [{}]。",
userTask.getAssignee(), this.getMessageBySkipType(skipType)));
flowTaskCommentService.saveNew(comment);
}
return comment != null;
}
private String getAssignedUser(DelegateExecution execution) {
UserTask userTask = (UserTask) execution.getCurrentFlowElement();
String assignedUser = userTask.getAssignee();
if (StrUtil.isNotBlank(assignedUser)) {
if (assignedUser.startsWith("${") && assignedUser.endsWith("}")) {
String variableName = assignedUser.substring(2, assignedUser.length() - 1);
assignedUser = flowApiService.getExecutionVariableStringWithSafe(execution.getId(), variableName);
}
} else {
FlowTaskExt flowTaskExt = flowTaskExtService
.getByProcessDefinitionIdAndTaskId(execution.getProcessDefinitionId(), userTask.getId());
List<String> candidateUsernames;
if (StrUtil.isBlank(flowTaskExt.getCandidateUsernames())) {
candidateUsernames = Collections.emptyList();
} else if (!StrUtil.equals(flowTaskExt.getCandidateUsernames(), "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
candidateUsernames = StrUtil.split(flowTaskExt.getCandidateUsernames(), ",");
} else {
String value = flowApiService
.getExecutionVariableStringWithSafe(execution.getId(), FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
candidateUsernames = value == null ? null : StrUtil.split(value, ",");
}
if (candidateUsernames != null && candidateUsernames.size() == 1) {
assignedUser = candidateUsernames.get(0);
}
}
return assignedUser;
}
private String getMessageBySkipType(String skipType) {
switch (skipType) {
case EQ_PREV_SUBMIT_USER:
return "审批人与上一审批节点处理人相同";
case EQ_START_USER:
return "审批人为发起人";
case EQ_HISTORIC_SUBMIT_USER:
return "审批人审批过";
default:
return "";
}
}
}

156
common/common-flow/src/main/java/apelet/common/flow/listener/AutoSkipTaskListener.java

@ -0,0 +1,156 @@ @@ -0,0 +1,156 @@
package apelet.common.flow.listener;
import apelet.common.core.object.TokenData;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.constant.FlowApprovalType;
import apelet.common.flow.constant.FlowConstant;
import apelet.common.flow.model.FlowTaskComment;
import apelet.common.flow.model.FlowTaskExt;
import apelet.common.flow.service.FlowApiService;
import apelet.common.flow.service.FlowTaskCommentService;
import apelet.common.flow.service.FlowTaskExtService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.api.Task;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.*;
/**
* 流程任务自动审批跳过的监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class AutoSkipTaskListener implements TaskListener {
private final transient FlowTaskCommentService flowTaskCommentService =
ApplicationContextHolder.getBean(FlowTaskCommentService.class);
private final transient FlowApiService flowApiService =
ApplicationContextHolder.getBean(FlowApiService.class);
private final transient FlowTaskExtService flowTaskExtService =
ApplicationContextHolder.getBean(FlowTaskExtService.class);
/**
* 流程的发起者等于当前任务的Assignee
*/
private static final String EQ_START_USER = "0";
/**
* 上一步的提交者等于当前任务的Assignee
*/
private static final String EQ_PREV_SUBMIT_USER = "1";
/**
* 当前任务的Assignee之前提交过审核
*/
private static final String EQ_HISTORIC_SUBMIT_USER = "2";
@Override
public void notify(DelegateTask t) {
UserTask userTask = flowApiService.getUserTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey());
List<ExtensionAttribute> attributes = userTask.getAttributes().get(FlowConstant.USER_TASK_AUTO_SKIP_KEY);
Set<String> skipTypes = new HashSet<>(StrUtil.split(attributes.get(0).getValue(), ","));
String assignedUser = this.getAssignedUser(userTask, t.getProcessDefinitionId(), t.getExecutionId());
if (StrUtil.isBlank(assignedUser)) {
return;
}
for (String skipType : skipTypes) {
if (this.verifyAndHandle(userTask, t, skipType, assignedUser)) {
return;
}
}
}
private boolean verifyAndHandle(UserTask userTask, DelegateTask task, String skipType, String assignedUser) {
FlowTaskComment comment = null;
switch (skipType) {
case EQ_START_USER:
Object v = task.getVariable(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR);
if (ObjectUtil.equal(v, assignedUser)) {
comment = flowTaskCommentService.getFirstFlowTaskComment(task.getProcessInstanceId());
}
break;
case EQ_PREV_SUBMIT_USER:
Object v2 = task.getVariable(FlowConstant.SUBMIT_USER_VAR);
if (ObjectUtil.equal(v2, assignedUser)) {
TokenData tokenData = TokenData.takeFromRequest();
comment = new FlowTaskComment();
comment.setCreateUserId(tokenData.getUserId());
comment.setCreateLoginName(tokenData.getLoginName());
comment.setCreateUsername(tokenData.getShowName());
}
break;
case EQ_HISTORIC_SUBMIT_USER:
List<FlowTaskComment> comments =
flowTaskCommentService.getFlowTaskCommentList(task.getProcessInstanceId());
List<FlowTaskComment> resultComments = new LinkedList<>();
for (FlowTaskComment c : comments) {
if (StrUtil.equals(c.getCreateLoginName(), assignedUser)) {
resultComments.add(c);
}
}
if (CollUtil.isNotEmpty(resultComments)) {
comment = resultComments.get(0);
}
break;
default:
break;
}
if (comment != null) {
Task t = flowApiService.getTaskById(task.getId());
comment.fillWith(t);
comment.setApprovalType(FlowApprovalType.AGREE);
comment.setTaskComment(StrFormatter.format("自动跳过审批。审批人 [{}], 跳过原因 [{}]。",
userTask.getAssignee(), this.getMessageBySkipType(skipType)));
flowApiService.completeTask(t, comment, null, null);
}
return comment != null;
}
private String getAssignedUser(UserTask userTask, String processDefinitionId, String executionId) {
String assignedUser = userTask.getAssignee();
if (StrUtil.isNotBlank(assignedUser)) {
if (assignedUser.startsWith("${") && assignedUser.endsWith("}")) {
String variableName = assignedUser.substring(2, assignedUser.length() - 1);
assignedUser = flowApiService.getExecutionVariableStringWithSafe(executionId, variableName);
}
} else {
FlowTaskExt flowTaskExt = flowTaskExtService
.getByProcessDefinitionIdAndTaskId(processDefinitionId, userTask.getId());
List<String> candidateUsernames;
if (StrUtil.isBlank(flowTaskExt.getCandidateUsernames())) {
candidateUsernames = Collections.emptyList();
} else if (!StrUtil.equals(flowTaskExt.getCandidateUsernames(), "${" + FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR + "}")) {
candidateUsernames = StrUtil.split(flowTaskExt.getCandidateUsernames(), ",");
} else {
String value = flowApiService
.getExecutionVariableStringWithSafe(executionId, FlowConstant.TASK_APPOINTED_ASSIGNEE_VAR);
candidateUsernames = value == null ? null : StrUtil.split(value, ",");
}
if (candidateUsernames != null && candidateUsernames.size() == 1) {
assignedUser = candidateUsernames.get(0);
}
}
return assignedUser;
}
private String getMessageBySkipType(String skipType) {
switch (skipType) {
case EQ_PREV_SUBMIT_USER:
return "审批人与上一审批节点处理人相同";
case EQ_START_USER:
return "审批人为发起人";
case EQ_HISTORIC_SUBMIT_USER:
return "审批人审批过";
default:
return "";
}
}
}

27
common/common-flow/src/main/java/apelet/common/flow/listener/DeptPostLeaderListener.java

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
package apelet.common.flow.listener;
import apelet.common.flow.constant.FlowConstant;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.Map;
/**
* 当用户任务的候选组为本部门领导岗位时该监听器会在任务创建时获取当前流程实例发起人的部门领导
* 并将其指派为当前任务的候选组
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class DeptPostLeaderListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
Map<String, Object> variables = delegateTask.getVariables();
if (variables.get(FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR) == null) {
delegateTask.setAssignee(variables.get(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR).toString());
}
}
}

74
common/common-flow/src/main/java/apelet/common/flow/listener/FlowEmptyUserHandleListener.java

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
package apelet.common.flow.listener;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.constant.FlowApprovalType;
import apelet.common.flow.exception.FlowEmptyUserException;
import apelet.common.flow.model.FlowTaskComment;
import apelet.common.flow.model.FlowTaskExt;
import apelet.common.flow.object.FlowUserTaskExtData;
import apelet.common.flow.service.FlowApiService;
import apelet.common.flow.service.FlowTaskExtService;
import apelet.common.flow.vo.FlowUserInfoVo;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.api.Task;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.List;
/**
* 空审批人处理监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class FlowEmptyUserHandleListener implements TaskListener {
private final transient FlowTaskExtService flowTaskExtService =
ApplicationContextHolder.getBean(FlowTaskExtService.class);
private final transient FlowApiService flowApiService =
ApplicationContextHolder.getBean(FlowApiService.class);
@Override
public void notify(DelegateTask t) {
FlowTaskExt flowTaskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(
t.getProcessDefinitionId(), t.getTaskDefinitionKey());
Task task = flowApiService.getTaskById(t.getId());
List<FlowUserInfoVo> userInfoVoList =
flowTaskExtService.getCandidateUserInfoList(t.getProcessInstanceId(), flowTaskExt, task,
flowApiService.isMultiInstanceTask(t.getProcessDefinitionId(), t.getTaskDefinitionKey()), false);
if (CollUtil.isNotEmpty(userInfoVoList)) {
return;
}
FlowUserTaskExtData taskExtData =
JSON.parseObject(flowTaskExt.getExtraDataJson(), FlowUserTaskExtData.class);
if (StrUtil.isBlank(taskExtData.getEmptyUserHandleWay())) {
return;
}
switch (taskExtData.getEmptyUserHandleWay()) {
case FlowUserTaskExtData.EMPTY_USER_TO_ASSIGNEE:
t.setAssignee(taskExtData.getEmptyUserToAssignee());
break;
case FlowUserTaskExtData.EMPTY_USER_AUTO_REJECT:
case FlowUserTaskExtData.EMPTY_USER_AUTO_COMPLETE:
FlowTaskComment comment = new FlowTaskComment();
comment.fillWith(task);
if (taskExtData.getEmptyUserHandleWay().equals(FlowUserTaskExtData.EMPTY_USER_AUTO_REJECT)) {
comment.setApprovalType(FlowApprovalType.EMPTY_USER_AUTO_REJECT);
comment.setTaskComment("空审批人自动回退审批。");
throw new FlowEmptyUserException(JSON.toJSONString(comment));
} else {
comment.setApprovalType(FlowApprovalType.EMPTY_USER_AUTO_COMPLETE);
comment.setTaskComment("空审批人自动跳过审批。");
flowApiService.completeTask(task, comment, null, null);
}
break;
default:
break;
}
}
}

70
common/common-flow/src/main/java/apelet/common/flow/listener/FlowFinishedListener.java

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
package apelet.common.flow.listener;
import apelet.common.core.object.GlobalThreadLocal;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.constant.FlowTaskStatus;
import apelet.common.flow.model.FlowWorkOrder;
import apelet.common.flow.service.FlowTaskTimeoutJobService;
import apelet.common.flow.service.FlowWorkOrderService;
import apelet.common.flow.util.FlowCustomExtFactory;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
/**
* 流程实例监听器在流程实例结束的时候需要完成一些自定义的业务行为
* 1. 更新流程工单表的审批状态字段
* 2. 业务数据同步
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class FlowFinishedListener implements ExecutionListener {
private final transient FlowWorkOrderService flowWorkOrderService =
ApplicationContextHolder.getBean(FlowWorkOrderService.class);
private final transient FlowCustomExtFactory flowCustomExtFactory =
ApplicationContextHolder.getBean(FlowCustomExtFactory.class);
private final transient FlowTaskTimeoutJobService flowTaskTimeoutJobService =
ApplicationContextHolder.getBean(FlowTaskTimeoutJobService.class);
@Override
public void notify(DelegateExecution execution) {
if (!StrUtil.equals("end", execution.getEventName())) {
return;
}
boolean enabled = GlobalThreadLocal.setDataFilter(false);
try {
String processInstanceId = execution.getProcessInstanceId();
FlowWorkOrder workOrder = flowWorkOrderService.getFlowWorkOrderByProcessInstanceId(processInstanceId);
if (workOrder == null) {
return;
}
int flowStatus = FlowTaskStatus.FINISHED;
if (workOrder.getFlowStatus().equals(FlowTaskStatus.CANCELLED)
|| workOrder.getFlowStatus().equals(FlowTaskStatus.STOPPED)) {
flowStatus = workOrder.getFlowStatus();
}
workOrder.setFlowStatus(flowStatus);
// 更新流程工单中的流程状态。
flowWorkOrderService.updateFlowStatusByProcessInstanceId(processInstanceId, flowStatus);
if (workOrder.getOnlineTableId() != null) {
// 处理在线表单工作流的自定义状态更新。
flowCustomExtFactory.getOnlineBusinessDataExtHelper().updateFlowStatus(workOrder);
} else {
// 处理路由表单工作里的自定义状态更新。
flowCustomExtFactory.getBusinessDataExtHelper().updateFlowStatus(workOrder);
}
if (flowStatus == FlowTaskStatus.FINISHED) {
// 在线表单不支持该功能,仅限于路由表单工作流可用。
// 可以自行实现审批完成后,将审批中已经通过的数据,同步到业务发布表。
flowCustomExtFactory.getBusinessDataExtHelper().triggerSync(workOrder);
}
flowTaskTimeoutJobService.deleteByProcessInstanceId(execution.getProcessInstanceId());
} finally {
GlobalThreadLocal.setDataFilter(enabled);
}
}
}

80
common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskNotifyListener.java

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
package apelet.common.flow.listener;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.constant.FlowConstant;
import apelet.common.flow.model.FlowTaskExt;
import apelet.common.flow.object.FlowUserTaskExtData;
import apelet.common.flow.service.FlowApiService;
import apelet.common.flow.service.FlowTaskExtService;
import apelet.common.flow.util.BaseFlowNotifyExtHelper;
import apelet.common.flow.util.FlowCustomExtFactory;
import apelet.common.flow.vo.FlowTaskVo;
import apelet.common.flow.vo.FlowUserInfoVo;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.List;
/**
* 任务进入待办状态时的通知监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class FlowTaskNotifyListener implements TaskListener {
private final transient FlowTaskExtService flowTaskExtService =
ApplicationContextHolder.getBean(FlowTaskExtService.class);
private final transient FlowApiService flowApiService =
ApplicationContextHolder.getBean(FlowApiService.class);
private final transient FlowCustomExtFactory flowCustomExtFactory =
ApplicationContextHolder.getBean(FlowCustomExtFactory.class);
@Override
public void notify(DelegateTask delegateTask) {
String definitionId = delegateTask.getProcessDefinitionId();
String instanceId = delegateTask.getProcessInstanceId();
String taskId = delegateTask.getId();
String taskKey = delegateTask.getTaskDefinitionKey();
FlowTaskExt taskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(definitionId, taskKey);
if (StrUtil.isBlank(taskExt.getExtraDataJson())) {
return;
}
FlowUserTaskExtData extData = JSON.parseObject(taskExt.getExtraDataJson(), FlowUserTaskExtData.class);
if (CollUtil.isEmpty(extData.getFlowNotifyTypeList())) {
return;
}
ProcessInstance instance = flowApiService.getProcessInstance(instanceId);
Object initiator = flowApiService.getProcessInstanceVariable(instanceId, FlowConstant.PROC_INSTANCE_INITIATOR_VAR);
boolean isMultiInstanceTask = flowApiService.isMultiInstanceTask(definitionId, taskKey);
Task task = flowApiService.getProcessInstanceActiveTask(instanceId, taskId);
List<FlowUserInfoVo> userInfoList =
flowTaskExtService.getCandidateUserInfoList(instanceId, taskExt, task, isMultiInstanceTask, false);
if (CollUtil.isEmpty(userInfoList)) {
log.warn("ProcessDefinition [{}] Task [{}] don't find the candidate users for notification.",
instance.getProcessDefinitionName(), task.getName());
return;
}
BaseFlowNotifyExtHelper helper = flowCustomExtFactory.getFlowNotifyExtHelper();
Assert.notNull(helper);
for (String notifyType : extData.getFlowNotifyTypeList()) {
FlowTaskVo flowTaskVo = new FlowTaskVo();
flowTaskVo.setProcessDefinitionId(definitionId);
flowTaskVo.setProcessInstanceId(instanceId);
flowTaskVo.setTaskKey(taskKey);
flowTaskVo.setTaskName(delegateTask.getName());
flowTaskVo.setTaskId(delegateTask.getId());
flowTaskVo.setBusinessKey(instance.getBusinessKey());
flowTaskVo.setProcessInstanceInitiator(initiator.toString());
helper.doNotify(notifyType, userInfoList, flowTaskVo);
}
}
}

26
common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskRejectBackListener.java

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
package apelet.common.flow.listener;
import apelet.common.flow.constant.FlowConstant;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.Map;
/**
* 任务驳回后重新提交到该任务的通知监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class FlowTaskRejectBackListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
Map<String, Object> variables = delegateTask.getVariables();
if (variables.get(FlowConstant.REJECT_BACK_TO_SOURCE_DATA_VAR) != null) {
delegateTask.setAssignee(variables.get(FlowConstant.REJECT_BACK_TO_SOURCE_DATA_VAR).toString());
}
}
}

55
common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskReviveListener.java

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
package apelet.common.flow.listener;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.model.FlowEntryPublish;
import apelet.common.flow.model.FlowVariableLog;
import apelet.common.flow.object.FlowEntryExtensionData;
import apelet.common.flow.service.FlowEntryService;
import apelet.common.flow.service.FlowVariableLogService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 支持流程复活的任务监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class FlowTaskReviveListener implements TaskListener {
private final transient FlowVariableLogService flowVariableLogService =
ApplicationContextHolder.getBean(FlowVariableLogService.class);
private final transient FlowEntryService flowEntryService =
ApplicationContextHolder.getBean(FlowEntryService.class);
@Override
public void notify(DelegateTask delegateTask) {
Map<String, Object> variables = delegateTask.getVariables();
if (MapUtil.isNotEmpty(variables)) {
List<FlowEntryPublish> flowEntryPublishList =
flowEntryService.getFlowEntryPublishList(CollUtil.newHashSet(delegateTask.getProcessDefinitionId()));
FlowEntryExtensionData flowEntryExtensionData =
JSON.parseObject(flowEntryPublishList.get(0).getExtensionData(), FlowEntryExtensionData.class);
FlowVariableLog o = new FlowVariableLog();
if (flowEntryExtensionData.getKeptReviveDays() > 0) {
o.setExpiredTime(DateUtil.offset(new Date(), DateField.DAY_OF_MONTH, flowEntryExtensionData.getKeptReviveDays()));
}
o.setProcessDefinitionKey(delegateTask.getProcessDefinitionId());
o.setProcessInstanceId(delegateTask.getProcessInstanceId());
o.setTaskKey(delegateTask.getTaskDefinitionKey());
o.setVariableData(JSON.toJSONString(variables));
flowVariableLogService.saveNew(o);
}
}
}

48
common/common-flow/src/main/java/apelet/common/flow/listener/FlowTaskTimeoutListener.java

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
package apelet.common.flow.listener;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.model.FlowTaskExt;
import apelet.common.flow.model.FlowTaskTimeoutJob;
import apelet.common.flow.object.FlowUserTaskExtData;
import apelet.common.flow.service.FlowTaskExtService;
import apelet.common.flow.service.FlowTaskTimeoutJobService;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
/**
* 流程任务超时监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class FlowTaskTimeoutListener implements TaskListener {
private final transient FlowTaskExtService flowTaskExtService =
ApplicationContextHolder.getBean(FlowTaskExtService.class);
private final transient FlowTaskTimeoutJobService flowTaskTimeoutJobService =
ApplicationContextHolder.getBean(FlowTaskTimeoutJobService.class);
@Override
public void notify(DelegateTask delegateTask) {
FlowTaskExt taskExt = flowTaskExtService.getByProcessDefinitionIdAndTaskId(
delegateTask.getProcessDefinitionId(), delegateTask.getTaskDefinitionKey());
if (StrUtil.isNotBlank(taskExt.getExtraDataJson())) {
FlowUserTaskExtData taskExtData = JSON.parseObject(taskExt.getExtraDataJson(), FlowUserTaskExtData.class);
if (StrUtil.isNotBlank(taskExtData.getTimeoutHandleWay())) {
FlowTaskTimeoutJob job = new FlowTaskTimeoutJob();
job.setProcessDefinitionId(delegateTask.getProcessDefinitionId());
job.setProcessInstanceId(delegateTask.getProcessInstanceId());
job.setTaskKey(delegateTask.getTaskDefinitionKey());
job.setTaskId(delegateTask.getId());
job.setTimeoutHours(taskExtData.getTimeoutHours());
job.setHandleWay(taskExtData.getTimeoutHandleWay());
job.setDefaultAssignee(taskExtData.getDefaultAssignee());
flowTaskTimeoutJobService.saveNew(job);
}
}
}
}

32
common/common-flow/src/main/java/apelet/common/flow/listener/FlowUserTaskListener.java

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
package apelet.common.flow.listener;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.constant.FlowConstant;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.Map;
/**
* 流程任务通用监听器
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class FlowUserTaskListener implements TaskListener {
private final transient RuntimeService runtimeService =
ApplicationContextHolder.getBean(RuntimeService.class);
@Override
public void notify(DelegateTask delegateTask) {
Map<String, Object> variables = delegateTask.getVariables();
if (variables.get(FlowConstant.DELEGATE_ASSIGNEE_VAR) != null) {
delegateTask.setAssignee(variables.get(FlowConstant.DELEGATE_ASSIGNEE_VAR).toString());
runtimeService.removeVariableLocal(delegateTask.getExecutionId(), FlowConstant.DELEGATE_ASSIGNEE_VAR);
}
}
}

27
common/common-flow/src/main/java/apelet/common/flow/listener/UpDeptPostLeaderListener.java

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
package apelet.common.flow.listener;
import apelet.common.flow.constant.FlowConstant;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import java.util.Map;
/**
* 当用户任务的候选组为上级部门领导岗位时该监听器会在任务创建时获取当前流程实例发起人的部门领导
* 并将其指派为当前任务的候选组
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class UpDeptPostLeaderListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
Map<String, Object> variables = delegateTask.getVariables();
if (variables.get(FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR) == null) {
delegateTask.setAssignee(variables.get(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR).toString());
}
}
}

44
common/common-flow/src/main/java/apelet/common/flow/listener/UpdateLatestApprovalStatusListener.java

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
package apelet.common.flow.listener;
import apelet.common.core.util.ApplicationContextHolder;
import apelet.common.flow.model.FlowWorkOrder;
import apelet.common.flow.service.FlowWorkOrderService;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.impl.el.FixedValue;
/**
* 更新流程的最后审批状态的监听器目前用于排他网关到任务结束节点的连线上
* 以便于准确的判断流程实例的最后审批状态
*
* @author guifc
* @date 2023-08-04
*/
@Slf4j
public class UpdateLatestApprovalStatusListener implements ExecutionListener {
private FixedValue latestApprovalStatus;
private final transient FlowWorkOrderService flowWorkOrderService =
ApplicationContextHolder.getBean(FlowWorkOrderService.class);
public void setAutoStoreVariablesExp(FixedValue approvalStatus) {
this.latestApprovalStatus = approvalStatus;
}
@Override
public void notify(DelegateExecution execution) {
if (StrUtil.isNotBlank(latestApprovalStatus.getExpressionText())) {
FlowWorkOrder workOrder =
flowWorkOrderService.getFlowWorkOrderByProcessInstanceId(execution.getProcessInstanceId());
if (workOrder == null) {
return;
}
Integer approvalStatus = Integer.valueOf(latestApprovalStatus.getExpressionText());
String processInstanceId = execution.getProcessInstanceId();
flowWorkOrderService.updateLatestApprovalStatusByProcessInstanceId(processInstanceId, approvalStatus);
}
}
}

88
common/common-flow/src/main/java/apelet/common/flow/model/FlowCategory.java

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
package apelet.common.flow.model;
import apelet.common.core.base.mapper.BaseModelMapper;
import apelet.common.flow.vo.FlowCategoryVo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
/**
* 流程分类的实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_category")
public class FlowCategory {
/**
* 主键Id
*/
@TableId(value = "category_id")
private Long categoryId;
/**
* 租户Id
*/
@TableField(value = "tenant_id")
private Long tenantId;
/**
* 应用编码为空时表示非第三方应用接入
*/
@TableField(value = "app_code")
private String appCode;
/**
* 显示名称
*/
@TableField(value = "name")
private String name;
/**
* 分类编码
*/
@TableField(value = "code")
private String code;
/**
* 实现顺序
*/
@TableField(value = "show_order")
private Integer showOrder;
/**
* 更新时间
*/
@TableField(value = "update_time")
private Date updateTime;
/**
* 更新者Id
*/
@TableField(value = "update_user_id")
private Long updateUserId;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
/**
* 创建者Id
*/
@TableField(value = "create_user_id")
private Long createUserId;
@Mapper
public interface FlowCategoryModelMapper extends BaseModelMapper<FlowCategoryVo, FlowCategory> {
}
public static final FlowCategoryModelMapper INSTANCE = Mappers.getMapper(FlowCategoryModelMapper.class);
}

192
common/common-flow/src/main/java/apelet/common/flow/model/FlowEntry.java

@ -0,0 +1,192 @@ @@ -0,0 +1,192 @@
package apelet.common.flow.model;
import apelet.common.core.annotation.RelationOneToOne;
import apelet.common.core.base.mapper.BaseModelMapper;
import apelet.common.flow.vo.FlowEntryVo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.Date;
/**
* 流程的实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_entry")
public class FlowEntry {
/**
* 主键
*/
@TableId(value = "entry_id")
private Long entryId;
/**
* 租户Id
*/
@TableField(value = "tenant_id")
private Long tenantId;
/**
* 应用编码为空时表示非第三方应用接入
*/
@TableField(value = "app_code")
private String appCode;
/**
* 流程名称
*/
@TableField(value = "process_definition_name")
private String processDefinitionName;
/**
* 流程标识Key
*/
@TableField(value = "process_definition_key")
private String processDefinitionKey;
/**
* 流程分类
*/
@TableField(value = "category_id")
private Long categoryId;
/**
* 工作流部署的发布主版本Id
*/
@TableField(value = "main_entry_publish_id")
private Long mainEntryPublishId;
/**
* 最新发布时间
*/
@TableField(value = "latest_publish_time")
private Date latestPublishTime;
/**
* 流程状态
*/
@TableField(value = "status")
private Integer status;
/**
* 流程定义的xml
*/
@TableField(value = "bpmn_xml")
private String bpmnXml;
/**
* 流程图类型0: 普通流程图1: 钉钉风格的流程图
*/
@TableField(value = "diagram_type")
private Integer diagramType;
/**
* 绑定表单类型
*/
@TableField(value = "bind_form_type")
private Integer bindFormType;
/**
* 在线表单的页面Id
*/
@TableField(value = "page_id")
private Long pageId;
/**
* 在线表单Id
*/
@TableField(value = "default_form_id")
private Long defaultFormId;
/**
* 静态表单的缺省路由名称
*/
@TableField(value = "default_router_name")
private String defaultRouterName;
/**
* 工单表编码字段的编码规则如果为空则不计算工单编码
*/
@TableField(value = "encoded_rule")
private String encodedRule;
/**
* 流程的自定义扩展数据(JSON格式)
*/
@TableField(value = "extension_data")
private String extensionData;
/**
* 更新时间
*/
@TableField(value = "update_time")
private Date updateTime;
/**
* 更新者Id
*/
@TableField(value = "update_user_id")
private Long updateUserId;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
/**
* 创建者Id
*/
@TableField(value = "create_user_id")
private Long createUserId;
/**
* 流程启动条件
*/
@TableField(value = "start_conditions")
private String startConditions;
@TableField(exist = false)
private FlowEntryPublish mainFlowEntryPublish;
@RelationOneToOne(
masterIdField = "categoryId",
slaveModelClass = FlowCategory.class,
slaveIdField = "categoryId")
@TableField(exist = false)
private FlowCategory flowCategory;
@Mapper
public interface FlowEntryModelMapper extends BaseModelMapper<FlowEntryVo, FlowEntry> {
/**
* 转换Vo对象到实体对象
*
* @param flowEntryVo 域对象
* @return 实体对象
*/
@Mapping(target = "mainFlowEntryPublish", expression = "java(mapToBean(flowEntryVo.getMainFlowEntryPublish(), apelet.common.flow.model.FlowEntryPublish.class))")
@Mapping(target = "flowCategory", expression = "java(mapToBean(flowEntryVo.getFlowCategory(), apelet.common.flow.model.FlowCategory.class))")
@Override
FlowEntry toModel(FlowEntryVo flowEntryVo);
/**
* 转换实体对象到VO对象
*
* @param flowEntry 实体对象
* @return 域对象
*/
@Mapping(target = "mainFlowEntryPublish", expression = "java(beanToMap(flowEntry.getMainFlowEntryPublish(), false))")
@Mapping(target = "flowCategory", expression = "java(beanToMap(flowEntry.getFlowCategory(), false))")
@Override
FlowEntryVo fromModel(FlowEntry flowEntry);
}
public static final FlowEntryModelMapper INSTANCE = Mappers.getMapper(FlowEntryModelMapper.class);
}

98
common/common-flow/src/main/java/apelet/common/flow/model/FlowEntryPublish.java

@ -0,0 +1,98 @@ @@ -0,0 +1,98 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 流程发布数据的实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_entry_publish")
public class FlowEntryPublish {
/**
* 主键Id
*/
@TableId(value = "entry_publish_id")
private Long entryPublishId;
/**
* 流程Id
*/
@TableField(value = "entry_id")
private Long entryId;
/**
* 流程引擎的部署Id
*/
@TableField(value = "deploy_id")
private String deployId;
/**
* 流程引擎中的流程定义Id
*/
@TableField(value = "process_definition_id")
private String processDefinitionId;
/**
* 发布版本
*/
@TableField(value = "publish_version")
private Integer publishVersion;
/**
* 激活状态
*/
@TableField(value = "active_status")
private Boolean activeStatus;
/**
* 是否为主版本
*/
@TableField(value = "main_version")
private Boolean mainVersion;
/**
* 创建者Id
*/
@TableField(value = "create_user_id")
private Long createUserId;
/**
* 发布时间
*/
@TableField(value = "publish_time")
private Date publishTime;
/**
* 第一个非开始节点任务的附加信息
*/
@TableField(value = "init_task_info")
private String initTaskInfo;
/**
* 分析后的节点JSON信息
*/
@TableField(value = "analyzed_node_json")
private String analyzedNodeJson;
/**
* 流程的自定义扩展数据(JSON格式)
*/
@TableField(value = "extension_data")
private String extensionData;
/**
* 流程启动条件
*/
@TableField(value = "start_conditions")
private String startConditions;
}

71
common/common-flow/src/main/java/apelet/common/flow/model/FlowEntryPublishVariable.java

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* FlowEntryPublishVariable实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_entry_publish_variable")
public class FlowEntryPublishVariable {
/**
* 主键Id
*/
@TableId(value = "variable_id")
private Long variableId;
/**
* 流程Id
*/
@TableField(value = "entry_publish_id")
private Long entryPublishId;
/**
* 变量名
*/
@TableField(value = "variable_name")
private String variableName;
/**
* 显示名
*/
@TableField(value = "show_name")
private String showName;
/**
* 变量类型
*/
@TableField(value = "variable_type")
private Integer variableType;
/**
* 是否内置
*/
@TableField(value = "builtin")
private Boolean builtin;
/**
* 绑定数据源Id
*/
@TableField(value = "bind_datasource_id")
private Long bindDatasourceId;
/**
* 绑定数据源关联Id
*/
@TableField(value = "bind_relation_id")
private Long bindRelationId;
/**
* 绑定字段Id
*/
@TableField(value = "bind_column_id")
private Long bindColumnId;
}

88
common/common-flow/src/main/java/apelet/common/flow/model/FlowEntryVariable.java

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
package apelet.common.flow.model;
import apelet.common.core.base.mapper.BaseModelMapper;
import apelet.common.flow.vo.FlowEntryVariableVo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
/**
* 流程变量实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_entry_variable")
public class FlowEntryVariable {
/**
* 主键Id
*/
@TableId(value = "variable_id")
private Long variableId;
/**
* 流程Id
*/
@TableField(value = "entry_id")
private Long entryId;
/**
* 变量名
*/
@TableField(value = "variable_name")
private String variableName;
/**
* 显示名
*/
@TableField(value = "show_name")
private String showName;
/**
* 流程变量类型
*/
@TableField(value = "variable_type")
private Integer variableType;
/**
* 绑定数据源Id
*/
@TableField(value = "bind_datasource_id")
private Long bindDatasourceId;
/**
* 绑定数据源关联Id
*/
@TableField(value = "bind_relation_id")
private Long bindRelationId;
/**
* 绑定字段Id
*/
@TableField(value = "bind_column_id")
private Long bindColumnId;
/**
* 是否内置
*/
@TableField(value = "builtin")
private Boolean builtin;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
@Mapper
public interface FlowEntryVariableModelMapper extends BaseModelMapper<FlowEntryVariableVo, FlowEntryVariable> {
}
public static final FlowEntryVariableModelMapper INSTANCE = Mappers.getMapper(FlowEntryVariableModelMapper.class);
}

178
common/common-flow/src/main/java/apelet/common/flow/model/FlowMessage.java

@ -0,0 +1,178 @@ @@ -0,0 +1,178 @@
package apelet.common.flow.model;
import apelet.common.core.base.mapper.BaseModelMapper;
import apelet.common.flow.vo.FlowMessageVo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
/**
* 工作流通知消息实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_message")
public class FlowMessage {
/**
* 主键Id
*/
@TableId(value = "message_id")
private Long messageId;
/**
* 租户Id
*/
@TableField(value = "tenant_id")
private Long tenantId;
/**
* 应用编码为空时表示非第三方应用接入
*/
@TableField(value = "app_code")
private String appCode;
/**
* 消息类型
*/
@TableField(value = "message_type")
private Integer messageType;
/**
* 消息内容
*/
@TableField(value = "message_content")
private String messageContent;
/**
* 催办次数
*/
@TableField(value = "remind_count")
private Integer remindCount;
/**
* 工单Id
*/
@TableField(value = "work_order_id")
private Long workOrderId;
/**
* 流程定义Id
*/
@TableField(value = "process_definition_id")
private String processDefinitionId;
/**
* 流程定义标识
*/
@TableField(value = "process_definition_key")
private String processDefinitionKey;
/**
* 流程名称
*/
@TableField(value = "process_definition_name")
private String processDefinitionName;
/**
* 流程实例Id
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
/**
* 流程实例发起者
*/
@TableField(value = "process_instance_initiator")
private String processInstanceInitiator;
/**
* 流程任务Id
*/
@TableField(value = "task_id")
private String taskId;
/**
* 流程任务定义标识
*/
@TableField(value = "task_definition_key")
private String taskDefinitionKey;
/**
* 流程任务名称
*/
@TableField(value = "task_name")
private String taskName;
/**
* 创建时间
*/
@TableField(value = "task_start_time")
private Date taskStartTime;
/**
* 任务指派人登录名
*/
@TableField(value = "task_assignee")
private String taskAssignee;
/**
* 任务是否已完成
*/
@TableField(value = "task_finished")
private Boolean taskFinished;
/**
* 业务数据快照
*/
@TableField(value = "business_data_shot")
private String businessDataShot;
/**
* 是否为在线表单消息数据
*/
@TableField(value = "online_form_data")
private Boolean onlineFormData;
/**
* 更新时间
*/
@TableField(value = "update_time")
private Date updateTime;
/**
* 更新者Id
*/
@TableField(value = "update_user_id")
private Long updateUserId;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
/**
* 创建者Id
*/
@TableField(value = "create_user_id")
private Long createUserId;
/**
* 创建者显示名
*/
@TableField(value = "create_username")
private String createUsername;
@Mapper
public interface FlowMessageModelMapper extends BaseModelMapper<FlowMessageVo, FlowMessage> {
}
public static final FlowMessage.FlowMessageModelMapper INSTANCE = Mappers.getMapper(FlowMessage.FlowMessageModelMapper.class);
}

41
common/common-flow/src/main/java/apelet/common/flow/model/FlowMessageCandidateIdentity.java

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 流程任务消息的候选身份实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_msg_candidate_identity")
public class FlowMessageCandidateIdentity {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 任务消息Id
*/
@TableField(value = "message_id")
private Long messageId;
/**
* 候选身份类型
*/
@TableField(value = "candidate_type")
private String candidateType;
/**
* 候选身份Id
*/
@TableField(value = "candidate_id")
private String candidateId;
}

50
common/common-flow/src/main/java/apelet/common/flow/model/FlowMessageIdentityOperation.java

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 流程任务消息所属用户的操作表
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_msg_identity_operation")
public class FlowMessageIdentityOperation {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 任务消息Id
*/
@TableField(value = "message_id")
private Long messageId;
/**
* 用户登录名
*/
@TableField(value = "login_name")
private String loginName;
/**
* 操作类型
* 常量值参考FlowMessageOperationType对象
*/
@TableField(value = "operation_type")
private Integer operationType;
/**
* 操作时间
*/
@TableField(value = "operation_time")
private Date operationTime;
}

99
common/common-flow/src/main/java/apelet/common/flow/model/FlowMultiInstanceTrans.java

@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.flowable.task.api.TaskInfo;
import java.util.Date;
/**
* 流程多实例任务执行流水对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@NoArgsConstructor
@TableName(value = "zz_flow_multi_instance_trans")
public class FlowMultiInstanceTrans {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 流程实例Id
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
/**
* 任务Id
*/
@TableField(value = "task_id")
private String taskId;
/**
* 任务标识
*/
@TableField(value = "task_key")
private String taskKey;
/**
* 会签任务的执行Id
*/
@TableField(value = "multi_instance_exec_id")
private String multiInstanceExecId;
/**
* 任务的执行Id
*/
@TableField(value = "execution_id")
private String executionId;
/**
* 会签指派人列表
*/
@TableField(value = "assignee_list")
private String assigneeList;
/**
* 创建者Id
*/
@TableField(value = "create_user_id")
private Long createUserId;
/**
* 创建者登录名
*/
@TableField(value = "create_login_name")
private String createLoginName;
/**
* 创建者显示名
*/
@TableField(value = "create_username")
private String createUsername;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
public FlowMultiInstanceTrans(TaskInfo task) {
this.fillWith(task);
}
public void fillWith(TaskInfo task) {
this.taskId = task.getId();
this.taskKey = task.getTaskDefinitionKey();
this.processInstanceId = task.getProcessInstanceId();
this.executionId = task.getExecutionId();
}
}

55
common/common-flow/src/main/java/apelet/common/flow/model/FlowNodeTasks.java

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* 工作流 审批设置
*
* @author
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_node_tasks")
public class FlowNodeTasks implements Serializable {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 流程ID
*/
@TableField(value = "flow_id")
private Long flowId;
/**
* 执行时机
*/
@TableField(value = "execution_timing")
private String executionTiming;
/**
* 类型
*/
@TableField(value = "type")
private Integer type;
/**
* 操作
*/
@TableField(value = "operation")
private String operation;
/**
* task_key
*/
@TableField(value = "task_key")
private String taskKey;
}

161
common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskComment.java

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
package apelet.common.flow.model;
import apelet.common.core.base.mapper.BaseModelMapper;
import apelet.common.core.util.ContextUtil;
import apelet.common.flow.vo.FlowTaskCommentVo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.flowable.task.api.TaskInfo;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
/**
* FlowTaskComment实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@NoArgsConstructor
@TableName(value = "zz_flow_task_comment")
public class FlowTaskComment {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 流程实例Id
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
/**
* 任务Id
*/
@TableField(value = "task_id")
private String taskId;
/**
* 任务标识
*/
@TableField(value = "task_key")
private String taskKey;
/**
* 任务名称
*/
@TableField(value = "task_name")
private String taskName;
/**
* 用于驳回和自由跳的目标任务标识
*/
@TableField(value = "target_task_key")
private String targetTaskKey;
/**
* 任务的执行Id
*/
@TableField(value = "execution_id")
private String executionId;
/**
* 会签任务的执行Id
*/
@TableField(value = "multi_instance_exec_id")
private String multiInstanceExecId;
/**
* 审批类型
*/
@TableField(value = "approval_type")
private String approvalType;
/**
* 批注内容
*/
@TableField(value = "task_comment")
private String taskComment;
/**
* 委托指定人比如加签转办等
*/
@TableField(value = "delegate_assignee")
private String delegateAssignee;
/**
* 自定义数据开发者可自行扩展推荐使用JSON格式数据
*/
@TableField(value = "custom_business_data")
private String customBusinessData;
/**
* 审批人头像
*/
@TableField(value = "head_image_url")
private String headImageUrl;
/**
* 创建者Id
*/
@TableField(value = "create_user_id")
private Long createUserId;
/**
* 创建者登录名
*/
@TableField(value = "create_login_name")
private String createLoginName;
/**
* 创建者显示名
*/
@TableField(value = "create_username")
private String createUsername;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
private static final String REQ_ATTRIBUTE_KEY = "flowTaskComment";
public FlowTaskComment(TaskInfo task) {
this.fillWith(task);
}
public static void setToRequest(FlowTaskComment comment) {
if (ContextUtil.getHttpRequest() != null) {
ContextUtil.getHttpRequest().setAttribute(REQ_ATTRIBUTE_KEY, comment);
}
}
public static FlowTaskComment getFromRequest() {
if (ContextUtil.getHttpRequest() == null) {
return null;
}
return (FlowTaskComment) ContextUtil.getHttpRequest().getAttribute(REQ_ATTRIBUTE_KEY);
}
public void fillWith(TaskInfo task) {
this.taskId = task.getId();
this.taskKey = task.getTaskDefinitionKey();
this.taskName = task.getName();
this.processInstanceId = task.getProcessInstanceId();
this.executionId = task.getExecutionId();
}
@Mapper
public interface FlowTaskCommentModelMapper extends BaseModelMapper<FlowTaskCommentVo, FlowTaskComment> {
}
public static final FlowTaskCommentModelMapper INSTANCE = Mappers.getMapper(FlowTaskCommentModelMapper.class);
}

88
common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskExt.java

@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* 流程任务扩展实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_task_ext")
public class FlowTaskExt {
/**
* 流程引擎的定义Id
*/
@TableField(value = "process_definition_id")
private String processDefinitionId;
/**
* 流程引擎任务Id
*/
@TableField(value = "task_id")
private String taskId;
/**
* 操作列表JSON
*/
@TableField(value = "operation_list_json")
private String operationListJson;
/**
* 变量列表JSON
*/
@TableField(value = "variable_list_json")
private String variableListJson;
/**
* 存储多实例的assigneeList的JSON
*/
@TableField(value = "assignee_list_json")
private String assigneeListJson;
/**
* 分组类型
*/
@TableField(value = "group_type")
private String groupType;
/**
* 保存岗位相关的数据
*/
@TableField(value = "dept_post_list_json")
private String deptPostListJson;
/**
* 逗号分隔的角色Id
*/
@TableField(value = "role_ids")
private String roleIds;
/**
* 逗号分隔的部门Id
*/
@TableField(value = "dept_ids")
private String deptIds;
/**
* 逗号分隔候选用户名
*/
@TableField(value = "candidate_usernames")
private String candidateUsernames;
/**
* 抄送相关的数据
*/
@TableField(value = "copy_list_json")
private String copyListJson;
/**
* 用户任务的扩展属性存储为JSON的字符串格式
*/
@TableField(value = "extra_data_json")
private String extraDataJson;
}

97
common/common-flow/src/main/java/apelet/common/flow/model/FlowTaskTimeoutJob.java

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 超时任务作业实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_task_timeout_job")
public class FlowTaskTimeoutJob {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 流程定义Id
*/
@TableField(value = "process_definition_id")
private String processDefinitionId;
/**
* 流程实例Id
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
/**
* 流程任务标识
*/
@TableField(value = "task_key")
private String taskKey;
/**
* 流程任务Id
*/
@TableField(value = "task_id")
private String taskId;
/**
* 超时的小时数
*/
@TableField(value = "timeout_hours")
private Integer timeoutHours;
/**
* 超时处理方式
*/
@TableField(value = "handle_way")
private String handleWay;
/**
* 超时处理缺省用户名
*/
@TableField(value = "default_assignee")
private String defaultAssignee;
/**
* 处理错误信息
*/
@TableField(value = "error_message")
private String errorMessage;
/**
* 执行状态参考常量类FlowTaskTimeoutJobStatus的值
*/
@TableField(value = "status")
private Integer status;
/**
* 执行时间
*/
@TableField(value = "exec_time")
private Date execTime;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
/**
* 更新时间
*/
@TableField(value = "update_time")
private Date updateTime;
}

33
common/common-flow/src/main/java/apelet/common/flow/model/FlowTransConsumer.java

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Date;
/**
* 流程处理事务事件消费者流水实体
*
* @author guifc
* @date 2023-08-04
*/
@Data
@AllArgsConstructor
@TableName(value = "zz_flow_trans_consumer")
public class FlowTransConsumer {
/**
* 流水Id
*/
@TableId(value = "trans_id")
private Long transId;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
}

121
common/common-flow/src/main/java/apelet/common/flow/model/FlowTransProducer.java

@ -0,0 +1,121 @@ @@ -0,0 +1,121 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 流程处理事务事件生产者流水实体
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_trans_producer")
public class FlowTransProducer {
/**
* 流水Id
*/
@TableId(value = "trans_id")
private Long transId;
/**
* 应用编码为空时表示非第三方应用接入
*/
@TableField(value = "app_code")
private String appCode;
/**
* 业务数据库链接Id
*/
@TableField(value = "dblink_id")
private Long dblinkId;
/**
* 流程实例Id
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
/**
* 任务Id
*/
@TableField(value = "task_id")
private String taskId;
/**
* 任务标识
*/
@TableField(value = "task_key")
private String taskKey;
/**
* 任务名称
*/
@TableField(value = "task_name")
private String taskName;
/**
* 审批批注
*/
@TableField(value = "task_comment")
private String taskComment;
/**
* 当前请求的url
*/
@TableField(value = "url")
private String url;
/**
* 创建该事务性事件对象的初始方法格式为方法名(参数类型1,参数类型2)
*/
@TableField(value = "init_method")
private String initMethod;
/**
* 当前请求的traceId
*/
@TableField(value = "trace_id")
private String traceId;
/**
* 和SQL操作相关的数据值类型为TransactionalBusinessData.BusinessSqlData对象
*/
@TableField(value = "sql_data")
private String sqlData;
/**
* 尝试次数默认的插入值为1
*/
@TableField(value = "try_times")
private Integer tryTimes;
/**
* 提交业务数据时的错误信息如果正常提交该值为空
*/
@TableField(value = "error_reason")
private String errorReason;
/**
* 创建者登录名
*/
@TableField(value = "create_login_name")
private String createLoginName;
/**
* 创建者中文用户名
*/
@TableField(value = "create_username")
private String createUsername;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
}

61
common/common-flow/src/main/java/apelet/common/flow/model/FlowVariableLog.java

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 流程变量日志实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_variable_log")
public class FlowVariableLog {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 流程定义键
*/
@TableField(value = "process_definition_key")
private String processDefinitionKey;
/**
* 流程实例Id
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
/**
* 流程任务标识
*/
@TableField(value = "task_key")
private String taskKey;
/**
* 全部变量数据
*/
@TableField(value = "variable_data")
private String variableData;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
/**
* 过期时间
*/
@TableField(value = "expired_time")
private Date expiredTime;
}

172
common/common-flow/src/main/java/apelet/common/flow/model/FlowWorkOrder.java

@ -0,0 +1,172 @@ @@ -0,0 +1,172 @@
package apelet.common.flow.model;
import apelet.common.core.annotation.DeptFilterColumn;
import apelet.common.core.annotation.RelationConstDict;
import apelet.common.core.annotation.UserFilterColumn;
import apelet.common.core.base.mapper.BaseModelMapper;
import apelet.common.flow.constant.FlowTaskStatus;
import apelet.common.flow.vo.FlowWorkOrderVo;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Date;
import java.util.Map;
/**
* 工作流工单实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_work_order")
public class FlowWorkOrder {
/**
* 主键Id
*/
@TableId(value = "work_order_id")
private Long workOrderId;
/**
* 租户Id
*/
@TableField(value = "tenant_id")
private Long tenantId;
/**
* 应用编码为空时表示非第三方应用接入
*/
@TableField(value = "app_code")
private String appCode;
/**
* 工单编码字段
*/
@TableField(value = "work_order_code")
private String workOrderCode;
/**
* 流程定义标识
*/
@TableField(value = "process_definition_key")
private String processDefinitionKey;
/**
* 流程名称
*/
@TableField(value = "process_definition_name")
private String processDefinitionName;
/**
* 流程引擎的定义Id
*/
@TableField(value = "process_definition_id")
private String processDefinitionId;
/**
* 流程实例Id
*/
@TableField(value = "process_instance_id")
private String processInstanceId;
/**
* 在线表单的主表Id
*/
@TableField(value = "online_table_id")
private Long onlineTableId;
/**
* 静态表单所使用的数据表名
*/
@TableField(value = "table_name")
private String tableName;
/**
* 业务主键值
*/
@TableField(value = "business_key")
private String businessKey;
/**
* 最近的审批状态
*/
@TableField(value = "latest_approval_status")
private Integer latestApprovalStatus;
/**
* 流程状态参考FlowTaskStatus常量值对象
*/
@TableField(value = "flow_status")
private Integer flowStatus;
/**
* 提交用户登录名称
*/
@TableField(value = "submit_username")
private String submitUsername;
/**
* 提交用户所在部门Id
*/
@DeptFilterColumn
@TableField(value = "dept_id")
private Long deptId;
/**
* 更新时间
*/
@TableField(value = "update_time")
private Date updateTime;
/**
* 更新者Id
*/
@TableField(value = "update_user_id")
private Long updateUserId;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
/**
* 创建者Id
*/
@UserFilterColumn
@TableField(value = "create_user_id")
private Long createUserId;
/**
* 逻辑删除标记字段(1: 正常 -1: 已删除)
*/
@TableLogic
@TableField(value = "deleted_flag")
private Integer deletedFlag;
/**
* createTime 范围过滤起始值(>=)
*/
@TableField(exist = false)
private String createTimeStart;
/**
* createTime 范围过滤结束值(<=)
*/
@TableField(exist = false)
private String createTimeEnd;
@RelationConstDict(
masterIdField = "flowStatus",
constantDictClass = FlowTaskStatus.class)
@TableField(exist = false)
private Map<String, Object> flowStatusDictMap;
@Mapper
public interface FlowWorkOrderModelMapper extends BaseModelMapper<FlowWorkOrderVo, FlowWorkOrder> {
}
public static final FlowWorkOrderModelMapper INSTANCE = Mappers.getMapper(FlowWorkOrderModelMapper.class);
}

72
common/common-flow/src/main/java/apelet/common/flow/model/FlowWorkOrderExt.java

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
package apelet.common.flow.model;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;
/**
* 工作流工单扩展数据实体对象
*
* @author guifc
* @date 2023-08-04
*/
@Data
@TableName(value = "zz_flow_work_order_ext")
public class FlowWorkOrderExt {
/**
* 主键Id
*/
@TableId(value = "id")
private Long id;
/**
* 流程工单Id
*/
@TableField(value = "work_order_id")
private Long workOrderId;
/**
* 草稿数据
*/
@TableField(value = "draft_data")
private String draftData;
/**
* 业务数据
*/
@TableField(value = "business_data")
private String businessData;
/**
* 更新时间
*/
@TableField(value = "update_time")
private Date updateTime;
/**
* 更新者Id
*/
@TableField(value = "update_user_id")
private Long updateUserId;
/**
* 创建时间
*/
@TableField(value = "create_time")
private Date createTime;
/**
* 创建者Id
*/
@TableField(value = "create_user_id")
private Long createUserId;
/**
* 逻辑删除标记字段(1: 正常 -1: 已删除)
*/
@TableLogic
@TableField(value = "deleted_flag")
private Integer deletedFlag;
}

44
common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowBindFormType.java

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
package apelet.common.flow.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 工作流绑定表单类型
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowBindFormType {
/**
* 在线表单
*/
public static final int ONLINE_FORM = 0;
/**
* 路由表单
*/
public static final int ROUTER_FORM = 1;
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
static {
DICT_MAP.put(ONLINE_FORM, "在线表单");
DICT_MAP.put(ROUTER_FORM, "路由表单");
}
/**
* 判断参数是否为当前常量字典的合法值
*
* @param value 待验证的参数值
* @return 合法返回true否则false
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowBindFormType() {
}
}

44
common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowEntryStatus.java

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
package apelet.common.flow.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 工作流状态
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowEntryStatus {
/**
* 未发布
*/
public static final int UNPUBLISHED = 0;
/**
* 已发布
*/
public static final int PUBLISHED = 1;
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
static {
DICT_MAP.put(UNPUBLISHED, "未发布");
DICT_MAP.put(PUBLISHED, "已发布");
}
/**
* 判断参数是否为当前常量字典的合法值
*
* @param value 待验证的参数值
* @return 合法返回true否则false
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowEntryStatus() {
}
}

21
common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowMessageOperationType.java

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
package apelet.common.flow.model.constant;
/**
* 工作流消息操作类型
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowMessageOperationType {
/**
* 已读操作
*/
public static final int READ_FINISHED = 0;
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowMessageOperationType() {
}
}

26
common/common-flow/src/main/java/apelet/common/flow/model/constant/FlowMessageType.java

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
package apelet.common.flow.model.constant;
/**
* 工作流消息类型
*
* @author guifc
* @date 2023-08-04
*/
public final class FlowMessageType {
/**
* 催办消息
*/
public static final int REMIND_TYPE = 0;
/**
* 抄送消息
*/
public static final int COPY_TYPE = 1;
/**
* 私有构造函数明确标识该常量类的作用
*/
private FlowMessageType() {
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save