Merge branch 'release-20241030' into 'master'
Release 20241030 See merge request universal/infrastructure/backend/workflow-engine!10
This commit is contained in:
commit
e8fe58f85a
46
pom.xml
46
pom.xml
@ -16,7 +16,7 @@
|
||||
<name>workflow-engine</name>
|
||||
|
||||
<properties>
|
||||
<revision>1.4.2-SNAPSHOT</revision>
|
||||
<revision>1.5.0-SNAPSHOT</revision>
|
||||
<axzo-bom.version>2.0.0-SNAPSHOT</axzo-bom.version>
|
||||
<axzo-dependencies.version>2.0.0-SNAPSHOT</axzo-dependencies.version>
|
||||
<feign-httpclient.version>11.8</feign-httpclient.version>
|
||||
@ -27,6 +27,8 @@
|
||||
<arthas.version>3.7.1</arthas.version>
|
||||
<apache-maven.version>3.2.5</apache-maven.version>
|
||||
<javaparse.version>3.26.0</javaparse.version>
|
||||
<elasticsearch.version>7.14.0</elasticsearch.version>
|
||||
<easy-es.version>2.0.0</easy-es.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -56,6 +58,11 @@
|
||||
<artifactId>workflow-engine-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<artifactId>workflow-engine-axzo-ext</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>workflow-engine-common</artifactId>
|
||||
@ -66,11 +73,11 @@
|
||||
<artifactId>workflow-engine-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!--<dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>workflow-auto-gen</artifactId>
|
||||
<version>1.3.3-SNAPSHOT</version>
|
||||
</dependency>-->
|
||||
<artifactId>workflow-engine-elasticsearch</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>workflow-engine-server</artifactId>
|
||||
@ -116,6 +123,33 @@
|
||||
<artifactId>javaparser-core</artifactId>
|
||||
<version>${javaparse.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
<version>${elasticsearch.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
<version>${elasticsearch.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.easy-es</groupId>
|
||||
<artifactId>easy-es-boot-starter</artifactId>
|
||||
<version>${easy-es.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.easy-es</groupId>
|
||||
<artifactId>easy-es-annotation</artifactId>
|
||||
<version>${easy-es.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo</groupId>
|
||||
<artifactId>riven-api</artifactId>
|
||||
<version>${axzo-dependencies.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@ -157,8 +191,10 @@
|
||||
</repositories>
|
||||
<modules>
|
||||
<module>workflow-engine-api</module>
|
||||
<module>workflow-engine-axzo-ext</module>
|
||||
<module>workflow-engine-common</module>
|
||||
<module>workflow-engine-core</module>
|
||||
<module>workflow-engine-elasticsearch</module>
|
||||
<module>workflow-engine-server</module>
|
||||
<module>workflow-engine-support</module>
|
||||
<module>workflow-engine-spring-boot-starter</module>
|
||||
|
||||
@ -62,9 +62,12 @@ public class WorkflowEngineClientAutoConfiguration {
|
||||
log.error("get version error: {}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
String serviceVersion = Objects.isNull(version) ? "1.2.0-SNAPSHOT" : version;
|
||||
String serviceVersion = Objects.isNull(version) ? "1.2.0" : version;
|
||||
log.info("client current version: {}", serviceVersion);
|
||||
return serviceVersion;
|
||||
return serviceVersion
|
||||
.replaceAll("-SNAPSHOT", "")
|
||||
.replaceAll("-RELEASE", "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
private String getVersionFromPod(URL location) throws URISyntaxException {
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.axzo.workflow.client.feign.es;
|
||||
|
||||
import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient;
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.annotation.Manageable;
|
||||
import cn.axzo.workflow.common.model.request.es.InstanceSearchReqDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.es.ProcessInstanceDocumentVO;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
|
||||
|
||||
/**
|
||||
* 操作 ES 的流程实例 API
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-07 21:12
|
||||
*/
|
||||
@WorkflowEngineFeignClient
|
||||
@Manageable
|
||||
public interface EsProcessInstanceApi {
|
||||
|
||||
/**
|
||||
* 从 ES 中搜索符合条件的实例纬度数据
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/es/instance/search")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<BpmPageResult<ProcessInstanceDocumentVO>> searchInstanceInEs(@Validated @RequestBody InstanceSearchReqDTO dto);
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package cn.axzo.workflow.client.feign.manage;
|
||||
|
||||
import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient;
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.annotation.Manageable;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminDeleteDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminQueryDTO;
|
||||
import cn.axzo.workflow.common.model.response.admin.ProcessAdminVo;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
|
||||
|
||||
@WorkflowEngineFeignClient
|
||||
@Manageable
|
||||
public interface ProcessAdminApi {
|
||||
|
||||
/**
|
||||
* 查询管理员
|
||||
* @param dto 管理员数据
|
||||
* @return 管理员id
|
||||
*/
|
||||
@PostMapping("/api/process/admin/query")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<List<ProcessAdminVo>> queryProcessAdmins(@RequestBody ProcessAdminQueryDTO dto);
|
||||
|
||||
/**
|
||||
* 查询管理员
|
||||
* @param dto 管理员数据
|
||||
* @return 管理员id
|
||||
*/
|
||||
@PostMapping("/api/process/admin/query/count")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Integer> queryProcessAdminsCount(@RequestBody ProcessAdminQueryDTO dto);
|
||||
|
||||
/**
|
||||
* 添加管理员
|
||||
* @param dto 管理员数据
|
||||
* @return 管理员id
|
||||
*/
|
||||
@PostMapping("/api/process/admin/create")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Long> createProcessAdmin(@RequestBody ProcessAdminCreateDTO dto);
|
||||
|
||||
/**
|
||||
* 批量添加管理员
|
||||
* @param dtos
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/admin/batch/create")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Void> batchCreateProcessAdmin(@RequestBody List<ProcessAdminCreateDTO> dtos);
|
||||
|
||||
/**
|
||||
* 删除管理员
|
||||
* @param id 配置表id
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping("/api/process/admin/delete")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Integer> deleteCommonProcessAdmin(@RequestParam Long id);
|
||||
|
||||
/**
|
||||
* 根据条件删除管理员
|
||||
* @param dto 删除条件
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping("/api/process/admin/delete/criteria")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Integer> deleteProcessAdminCriteria(@RequestBody ProcessAdminDeleteDTO dto);
|
||||
|
||||
/**
|
||||
* 删除管理员
|
||||
* @param ids 管理员配置id列表
|
||||
* @return
|
||||
*/
|
||||
@DeleteMapping("/api/process/admin/batch/delete")
|
||||
@InvokeMode(SYNC)
|
||||
CommonResponse<Integer> batchDeleteProcessAdmin(@RequestBody List<Long> ids);
|
||||
}
|
||||
39
workflow-engine-axzo-ext/pom.xml
Normal file
39
workflow-engine-axzo-ext/pom.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>workflow-engine</artifactId>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>workflow-engine-axzo-ext</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Workflow Engine Axzo Extension</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<artifactId>workflow-engine-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-processor-spring-boot-starter</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-mybatisplus-spring-boot-starter</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,65 @@
|
||||
package cn.axzo.workflow.admin.repository.entity;
|
||||
|
||||
import cn.axzo.framework.data.mybatisplus.model.BaseEntity;
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.AdminRoleType;
|
||||
import cn.axzo.workflow.common.enums.AdminTypeEnum;
|
||||
import cn.axzo.workflow.common.enums.WorkspaceType;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "ext_ax_process_admin", autoResultMap = true)
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
public class ExtAxProcessAdmin extends BaseEntity<ExtAxProcessAdmin> {
|
||||
|
||||
private static final long serialVersionUID = 7342715107163876733L;
|
||||
|
||||
/**
|
||||
* 自然人id
|
||||
*/
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long organizationalUnitId;
|
||||
|
||||
/**
|
||||
* 工作台ID
|
||||
*/
|
||||
private Long workspaceId;
|
||||
|
||||
/**
|
||||
* 工作台类型,1-企业, 2-项目, 3-政务监管平台, 6-oms工作台,参考 WorkspaceType枚举
|
||||
*/
|
||||
private Integer workspaceType;
|
||||
|
||||
/**
|
||||
* 管理员类型, SUPER_ADMIN-超级管理员, COMMON_ADMIN-普通管理员
|
||||
*/
|
||||
private AdminTypeEnum adminType;
|
||||
|
||||
/**
|
||||
* 角色类型, ORGANIZATION_ADMIN-单位超管, ORG_WORKSPACE_ADMIN-项目内单位负责人, WORKSPACE_ADMIN-项目超管,OTHER-其他用户
|
||||
*/
|
||||
private AdminRoleType roleType;
|
||||
|
||||
/**
|
||||
* 数据来源, SYSTEM_ENTRY-系统录入, USER_ENTRY-用户手动录入
|
||||
*/
|
||||
private AdminDataSource dataSource;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package cn.axzo.workflow.admin.repository.mapper;
|
||||
|
||||
import cn.axzo.workflow.admin.repository.entity.ExtAxProcessAdmin;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface ExtAxProcessAdminMapper extends BaseMapper<ExtAxProcessAdmin> {
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package cn.axzo.workflow.admin.service;
|
||||
|
||||
import cn.axzo.workflow.admin.repository.entity.ExtAxProcessAdmin;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminDeleteDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminQueryDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ExtAxProcessAdminService {
|
||||
|
||||
/**
|
||||
* 新增管理员
|
||||
* @param processAdmin 流程配置管理员
|
||||
* @return id
|
||||
*/
|
||||
Long insert(ExtAxProcessAdmin processAdmin);
|
||||
|
||||
/**
|
||||
* 批量新增
|
||||
* @param processAdmins 配置管理员列表
|
||||
*/
|
||||
void batchInsert(List<ExtAxProcessAdmin> processAdmins);
|
||||
|
||||
/**
|
||||
* 根据条件查询
|
||||
* @param queryDTO
|
||||
* @return
|
||||
*/
|
||||
List<ExtAxProcessAdmin> query(ProcessAdminQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 根据条件查询数量
|
||||
* @param queryDTO
|
||||
* @return
|
||||
*/
|
||||
Integer queryCount(ProcessAdminQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 根据条件删除管理员配置
|
||||
* @param deleteDTO 删除条件
|
||||
*/
|
||||
Integer delete(ProcessAdminDeleteDTO deleteDTO);
|
||||
|
||||
/**
|
||||
* 批量删除管理员
|
||||
* @param ids 配置表id列表
|
||||
*/
|
||||
Integer deleteCommonAdminsByIds(List<Long> ids);
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
package cn.axzo.workflow.admin.service.impl;
|
||||
|
||||
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
|
||||
import cn.axzo.framework.domain.ServiceException;
|
||||
import cn.axzo.workflow.admin.repository.entity.ExtAxProcessAdmin;
|
||||
import cn.axzo.workflow.admin.repository.mapper.ExtAxProcessAdminMapper;
|
||||
import cn.axzo.workflow.admin.service.ExtAxProcessAdminService;
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.AdminTypeEnum;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminDeleteDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminQueryDTO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class ExtAxProcessAdminServiceImpl implements ExtAxProcessAdminService {
|
||||
|
||||
@Resource
|
||||
private ExtAxProcessAdminMapper extAxProcessAdminMapper;
|
||||
|
||||
@Override
|
||||
public Long insert(ExtAxProcessAdmin processAdmin) {
|
||||
extAxProcessAdminMapper.insert(processAdmin);
|
||||
return processAdmin.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void batchInsert(List<ExtAxProcessAdmin> processAdmins) {
|
||||
if (CollectionUtils.isEmpty(processAdmins)) {
|
||||
return;
|
||||
}
|
||||
processAdmins.forEach(this::insert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExtAxProcessAdmin> query(ProcessAdminQueryDTO queryDTO) {
|
||||
if (queryDTO == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return extAxProcessAdminMapper.selectList(getQueryWrapper(queryDTO));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer queryCount(ProcessAdminQueryDTO queryDTO) {
|
||||
return extAxProcessAdminMapper.selectCount(getQueryWrapper(queryDTO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer delete(ProcessAdminDeleteDTO deleteDTO) {
|
||||
if (deleteDTO == null) {
|
||||
return 0;
|
||||
}
|
||||
return extAxProcessAdminMapper.delete(getDeleteWrapper(deleteDTO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer deleteCommonAdminsByIds(List<Long> ids) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return 0;
|
||||
}
|
||||
List<ExtAxProcessAdmin> extAxProcessAdmins = extAxProcessAdminMapper.selectBatchIds(ids);
|
||||
if (CollectionUtils.isEmpty(extAxProcessAdmins)) {
|
||||
return 0;
|
||||
}
|
||||
validateDeleteCommonAdmins(extAxProcessAdmins);
|
||||
return extAxProcessAdminMapper.deleteBatchIds(ids);
|
||||
}
|
||||
|
||||
private void validateDeleteCommonAdmins(List<ExtAxProcessAdmin> extAxProcessAdmins) {
|
||||
if (CollectionUtils.isEmpty(extAxProcessAdmins)) {
|
||||
return;
|
||||
}
|
||||
if (extAxProcessAdmins.stream().anyMatch(ad -> ad.getAdminType() == AdminTypeEnum.SUPER_ADMIN)) {
|
||||
throw new ServiceException("超级管理员不允许删除");
|
||||
}
|
||||
if (extAxProcessAdmins.stream().anyMatch(ad -> ad.getDataSource() == AdminDataSource.SYSTEM_ENTRY)) {
|
||||
throw new ServiceException("系统数据不允许删除");
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ExtAxProcessAdmin> getQueryWrapper(ProcessAdminQueryDTO queryDTO) {
|
||||
return new LambdaQueryWrapper<ExtAxProcessAdmin>()
|
||||
.in(!CollectionUtils.isEmpty(queryDTO.getProcessAdminIds()), ExtAxProcessAdmin::getId, queryDTO.getProcessAdminIds())
|
||||
.eq(Objects.nonNull(queryDTO.getWorkspaceId()), ExtAxProcessAdmin::getWorkspaceId, queryDTO.getWorkspaceId())
|
||||
.eq(queryDTO.getAdminType() != null, ExtAxProcessAdmin::getAdminType, queryDTO.getAdminType())
|
||||
.eq(Objects.nonNull(queryDTO.getOrganizationalUnitId()), ExtAxProcessAdmin::getOrganizationalUnitId, queryDTO.getOrganizationalUnitId())
|
||||
.in(!CollectionUtils.isEmpty(queryDTO.getPersonIds()), ExtAxProcessAdmin::getPersonId, queryDTO.getPersonIds())
|
||||
.eq(Objects.nonNull(queryDTO.getDataSource()), ExtAxProcessAdmin::getDataSource, queryDTO.getDataSource())
|
||||
.eq(ExtAxProcessAdmin::getIsDelete, TableIsDeleteEnum.NORMAL.value);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ExtAxProcessAdmin> getDeleteWrapper(ProcessAdminDeleteDTO deleteDTO) {
|
||||
return new LambdaQueryWrapper<ExtAxProcessAdmin>()
|
||||
.in(!CollectionUtils.isEmpty(deleteDTO.getProcessAdminIds()), ExtAxProcessAdmin::getId, deleteDTO.getProcessAdminIds())
|
||||
.eq(Objects.nonNull(deleteDTO.getWorkspaceId()), ExtAxProcessAdmin::getWorkspaceId, deleteDTO.getWorkspaceId())
|
||||
.eq(deleteDTO.getAdminType() != null, ExtAxProcessAdmin::getAdminType, deleteDTO.getAdminType())
|
||||
.eq(Objects.nonNull(deleteDTO.getOrganizationalUnitId()), ExtAxProcessAdmin::getOrganizationalUnitId, deleteDTO.getOrganizationalUnitId())
|
||||
.in(!CollectionUtils.isEmpty(deleteDTO.getWorkspaceIds()), ExtAxProcessAdmin::getWorkspaceId, deleteDTO.getWorkspaceIds())
|
||||
.in(!CollectionUtils.isEmpty(deleteDTO.getOrganizationalUnitIds()), ExtAxProcessAdmin::getOrganizationalUnitId, deleteDTO.getOrganizationalUnitIds())
|
||||
.in(!CollectionUtils.isEmpty(deleteDTO.getPersonIds()), ExtAxProcessAdmin::getPersonId, deleteDTO.getPersonIds())
|
||||
.eq(Objects.nonNull(deleteDTO.getDataSource()), ExtAxProcessAdmin::getDataSource, deleteDTO.getDataSource())
|
||||
.eq(ExtAxProcessAdmin::getIsDelete, TableIsDeleteEnum.NORMAL.value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -29,6 +29,10 @@
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dromara.easy-es</groupId>
|
||||
<artifactId>easy-es-annotation</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -58,6 +58,8 @@ public interface BpmnConstants {
|
||||
String FLOW_SERVER_VERSION = "serverVersion";
|
||||
String FLOW_SERVER_VERSION_121 = "1.2.1";
|
||||
String FLOW_SERVER_VERSION_130 = "1.3.0";
|
||||
// 1.4.2 开始启用新版本日志
|
||||
String FLOW_SERVER_VERSION_142 = "1.4.2";
|
||||
String CONFIG_NOTICE = "noticeConfig";
|
||||
String CONFIG_APPROVE = "approveConfig";
|
||||
String TEMPLATE_NOTICE_MESSAGE_CONFIG = "noticeMessageConfig";
|
||||
@ -187,4 +189,14 @@ public interface BpmnConstants {
|
||||
* 回退操作次数上限
|
||||
*/
|
||||
Integer MAX_BACKED_OPERATE_COUNT = 20;
|
||||
String LATEST_SYNC_TO_ELASTICSEARCH_TIME = "latest.sync.to.elasticsearch.time";
|
||||
/**
|
||||
* 固定父子文档在相同分片
|
||||
*/
|
||||
String ES_FIXED_ROUTING = "workflow_engine_join_routing";
|
||||
|
||||
/**
|
||||
* ouId+workspaceId 下限制人员数量为20
|
||||
*/
|
||||
Integer MAX_ORG_WORKSPACE_ADMIN_COUNT = 20;
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum AdminDataSource {
|
||||
SYSTEM_ENTRY("systemEntry", "系统录入"),
|
||||
USER_ENTRY("userEntry", "用户手动录入");
|
||||
|
||||
private final String type;
|
||||
private final String desc;
|
||||
|
||||
AdminDataSource(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum AdminRoleType {
|
||||
ORGANIZATION_ADMIN("organizationAdmin", "单位超管"),
|
||||
ORG_WORKSPACE_ADMIN("organizationWorkspaceAdmin", "项目内单位负责人"),
|
||||
WORKSPACE_ADMIN("workspaceAdmin", "项目超管"),
|
||||
OTHER("other", "其他用户");
|
||||
|
||||
private final String type;
|
||||
private final String desc;
|
||||
|
||||
AdminRoleType(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 审批管理员类型
|
||||
*/
|
||||
@Getter
|
||||
public enum AdminTypeEnum {
|
||||
SUPER_ADMIN("super_admin", "超级管理员"),
|
||||
COMMON_ADMIN("common_admin", "普通管理员");
|
||||
|
||||
private final String type;
|
||||
private final String desc;
|
||||
|
||||
AdminTypeEnum(String type, String desc) {
|
||||
this.type = type;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@ -39,7 +39,12 @@ public enum BpmnButtonEnum {
|
||||
/**
|
||||
* 抄送按钮
|
||||
*/
|
||||
BPMN_COPY(8, "BPMN_COPY", "抄送");
|
||||
BPMN_COPY(8, "BPMN_COPY", "抄送"),
|
||||
/**
|
||||
* 管理员转交按钮
|
||||
*/
|
||||
BPMN_ADMIN_TRANSFER(9, "BPMN_ADMIN_TRANSFER", "管理员转交");
|
||||
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.axzo.workflow.common.enums;
|
||||
|
||||
/**
|
||||
* 时间查询方向
|
||||
* <p>
|
||||
* 注意: 该枚举用在查询 flowable 引擎数据时, 都是包含自身时间点的.
|
||||
* 例如, 使用 Before 时,也就是说在某个时间点之前,是包含"某个时间"自身的.
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-29 09:56
|
||||
*/
|
||||
public enum TimeQueryDirection {
|
||||
BEFORE,
|
||||
AFTER,
|
||||
;
|
||||
}
|
||||
@ -24,8 +24,8 @@ public enum WorkspaceType {
|
||||
UN_KNOW(0, "未知"),
|
||||
;
|
||||
|
||||
private Integer code;
|
||||
private String desc;
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
public static WorkspaceType getType(Integer code) {
|
||||
return Arrays.stream(values()).filter(it -> it.getCode().equals(code))
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package cn.axzo.workflow.common.model.dto.es;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 数据同步 ES 的结果统计
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-30 14:42
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DataSyncSummaryDTO {
|
||||
|
||||
private Long processInstanceCount;
|
||||
|
||||
private Long processTaskCount;
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package cn.axzo.workflow.common.model.dto.es;
|
||||
|
||||
import cn.axzo.workflow.common.enums.TimeQueryDirection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 历史流程实例的搜索对象
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 14:03
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class HistoricProcessInstanceSearchForEsDTO {
|
||||
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 业务传参关键
|
||||
*/
|
||||
private String businessKey;
|
||||
|
||||
/**
|
||||
* 流程定义 KEY
|
||||
*/
|
||||
private String processDefinitionKey;
|
||||
|
||||
/**
|
||||
* 流程实例名称
|
||||
*/
|
||||
private String processInstanceName;
|
||||
|
||||
/**
|
||||
* 流程实例状态
|
||||
*/
|
||||
private String businessStatus;
|
||||
|
||||
/**
|
||||
* 租户 ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 实例是否已结束
|
||||
*
|
||||
*/
|
||||
private Boolean finished;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 控制查询开始时间的方向,包含自身的时间点
|
||||
* <p>
|
||||
* 默认是查询开始时间之后
|
||||
*/
|
||||
private TimeQueryDirection startTimeDirection = TimeQueryDirection.AFTER;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 控制查询结束时间的方向,包含自身的时间点
|
||||
* <p>
|
||||
* 默认是查询结束时间点之前
|
||||
*/
|
||||
private TimeQueryDirection endTimeDirection = TimeQueryDirection.BEFORE;
|
||||
|
||||
/**
|
||||
* 是否包含流程变量
|
||||
*/
|
||||
private Boolean hasVariables = false;
|
||||
|
||||
/**
|
||||
* 用于覆盖同步逻辑中的PageSize,一般不需要传
|
||||
*/
|
||||
private Integer overPageSize = 50;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
package cn.axzo.workflow.common.model.request.admin;
|
||||
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.AdminRoleType;
|
||||
import cn.axzo.workflow.common.enums.AdminTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 新增管理员模型
|
||||
*/
|
||||
@ApiModel("新增管理员模型")
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ProcessAdminCreateDTO {
|
||||
|
||||
/**
|
||||
* 自然人id
|
||||
*/
|
||||
@ApiModelProperty(value = "自然人id")
|
||||
@NotNull(message = "人员不能为空")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@ApiModelProperty(value = "单位id")
|
||||
@NotNull(message = "单位id不能为空")
|
||||
private Long organizationalUnitId;
|
||||
|
||||
/**
|
||||
* 工作台ID
|
||||
*/
|
||||
@ApiModelProperty(value = "工作台id")
|
||||
@NotNull(message = "工作台id不能为空")
|
||||
private Long workspaceId;
|
||||
|
||||
/**
|
||||
* 工作台类型,1-企业, 2-项目, 3-政务监管平台, 6-oms工作台,参考 WorkspaceType枚举
|
||||
*/
|
||||
@ApiModelProperty(value = "工作台类型")
|
||||
@NotNull(message = "工作台类型不能为空")
|
||||
private Integer workspaceType;
|
||||
|
||||
/**
|
||||
* 管理员类型, SUPER_ADMIN-超级管理员, COMMON_ADMIN-普通管理员
|
||||
*/
|
||||
@ApiModelProperty(value = "管理员类型, super_admin-超级管理员, common_admin-普通管理员")
|
||||
private AdminTypeEnum adminType;
|
||||
|
||||
/**
|
||||
* 角色类型, ORGANIZATION_ADMIN-单位超管, ORG_WORKSPACE_ADMIN-项目内单位负责人, WORKSPACE_ADMIN-项目超管,OTHER-其他用户
|
||||
*/
|
||||
@ApiModelProperty(value = "角色类型, organization_admin-单位超管, organization_workspace_admin-项目内单位负责人, workspace_admin-项目超管,other-其他用户")
|
||||
private AdminRoleType roleType;
|
||||
|
||||
/**
|
||||
* 数据来源, SYSTEM_ENTRY-系统录入, USER_ENTRY-用户手动录入
|
||||
*/
|
||||
@ApiModelProperty(value = "数据来源, system-系统录入, user-用户手动录入")
|
||||
private AdminDataSource dataSource;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@ApiModelProperty(value = "创建者")
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@ApiModelProperty(value = "更新者")
|
||||
private Long updateBy;
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package cn.axzo.workflow.common.model.request.admin;
|
||||
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.AdminTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ApiModel("删除管理员模型")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProcessAdminDeleteDTO {
|
||||
|
||||
/**
|
||||
* 流程管理员配置id列表
|
||||
*/
|
||||
@ApiModelProperty(value = "流程管理员配置id列表")
|
||||
private List<Long> processAdminIds;
|
||||
|
||||
/**
|
||||
* 自然人id
|
||||
*/
|
||||
@ApiModelProperty(value = "自然人id列表")
|
||||
private List<Long> personIds;
|
||||
|
||||
/**
|
||||
* 工作台ID
|
||||
*/
|
||||
@ApiModelProperty(value = "工作台id")
|
||||
private Long workspaceId;
|
||||
|
||||
/**
|
||||
* 工作台id列表
|
||||
*/
|
||||
@ApiModelProperty(value = "工作台id列表")
|
||||
private List<Long> workspaceIds;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@ApiModelProperty(value = "单位id")
|
||||
private Long organizationalUnitId;
|
||||
|
||||
/**
|
||||
* 单位id列表
|
||||
*/
|
||||
@ApiModelProperty(value = "单位id列表")
|
||||
private List<Long> organizationalUnitIds;
|
||||
|
||||
/**
|
||||
* 数据来源, SYSTEM_ENTRY-系统录入, USER_ENTRY-用户手动录入
|
||||
*/
|
||||
@ApiModelProperty(value = "数据来源")
|
||||
private AdminDataSource dataSource;
|
||||
|
||||
/**
|
||||
* 管理员类型
|
||||
*/
|
||||
@ApiModelProperty(value = "管理员类型")
|
||||
private AdminTypeEnum adminType;
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package cn.axzo.workflow.common.model.request.admin;
|
||||
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.AdminTypeEnum;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 查询管理员模型
|
||||
*/
|
||||
@ApiModel("查询管理员模型")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProcessAdminQueryDTO {
|
||||
|
||||
/**
|
||||
* 流程管理员配置id列表
|
||||
*/
|
||||
@ApiModelProperty(value = "流程管理员配置id列表")
|
||||
private List<Long> processAdminIds;
|
||||
|
||||
/**
|
||||
* 自然人id
|
||||
*/
|
||||
@ApiModelProperty(value = "自然人id列表")
|
||||
private List<Long> personIds;
|
||||
|
||||
/**
|
||||
* 工作台ID
|
||||
*/
|
||||
@ApiModelProperty(value = "工作台id")
|
||||
private Long workspaceId;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@ApiModelProperty(value = "单位id")
|
||||
private Long organizationalUnitId;
|
||||
|
||||
/**
|
||||
* 数据来源, system-系统录入, user-用户手动录入
|
||||
*/
|
||||
@ApiModelProperty(value = "数据来源")
|
||||
private AdminDataSource dataSource;
|
||||
|
||||
/**
|
||||
* 管理员类型
|
||||
*/
|
||||
@ApiModelProperty(value = "管理员类型")
|
||||
private AdminTypeEnum adminType;
|
||||
}
|
||||
@ -10,6 +10,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.HashMap;
|
||||
@ -46,6 +47,7 @@ public class BpmnProcessInstanceCreateDTO {
|
||||
* <h1 color=red>建议都传值,在安心筑中对应工作台 ID</h1>
|
||||
*/
|
||||
@ApiModelProperty(value = "发起的审批是属于哪个租户")
|
||||
@NotBlank(message = "工作台 ID 不能为空")
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
|
||||
@ -7,6 +7,8 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.dromara.easyes.annotation.IndexField;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
@ -29,6 +31,7 @@ public class AttachmentDTO implements Serializable {
|
||||
/**
|
||||
* 附件 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
@ -36,6 +39,7 @@ public class AttachmentDTO implements Serializable {
|
||||
*/
|
||||
@ApiModelProperty(value = "附件类型")
|
||||
@NotNull(message = "附件类型不能为空")
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private AttachmentTypeEnum type;
|
||||
|
||||
/**
|
||||
@ -43,12 +47,14 @@ public class AttachmentDTO implements Serializable {
|
||||
*/
|
||||
@ApiModelProperty(value = "文件名称不能为空")
|
||||
@NotBlank(message = "文件名称不能为空")
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 文件描述
|
||||
*/
|
||||
@ApiModelProperty(value = "文件描述")
|
||||
@IndexField(exist = false)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
@ -56,6 +62,7 @@ public class AttachmentDTO implements Serializable {
|
||||
*/
|
||||
@ApiModelProperty(value = "附件地址")
|
||||
@NotBlank(message = "附件地址不能为空")
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String url;
|
||||
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.easyes.annotation.IndexField;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@ -50,6 +52,7 @@ public class BpmnTaskDelegateAssigner implements Serializable {
|
||||
* 安心筑:身份 ID
|
||||
*/
|
||||
@Deprecated
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String assignee;
|
||||
|
||||
/**
|
||||
@ -59,6 +62,7 @@ public class BpmnTaskDelegateAssigner implements Serializable {
|
||||
* 安心筑:身份 Type 应该必传
|
||||
*/
|
||||
@Deprecated
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String assigneeType;
|
||||
|
||||
/**
|
||||
@ -67,6 +71,7 @@ public class BpmnTaskDelegateAssigner implements Serializable {
|
||||
* 枢智:用户姓名
|
||||
* 安心筑:用户姓名
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String assignerName;
|
||||
|
||||
/**
|
||||
@ -74,6 +79,7 @@ public class BpmnTaskDelegateAssigner implements Serializable {
|
||||
* <p>
|
||||
* 仅安心筑使用, 应该必传
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String personId;
|
||||
|
||||
/**
|
||||
@ -82,18 +88,21 @@ public class BpmnTaskDelegateAssigner implements Serializable {
|
||||
* 枢智: 企业 ID
|
||||
* 安心筑: 工作台 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 人所在的单位 ID
|
||||
* 仅安心筑使用, 工人可以没有, 其他身份一定需要
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String ouId;
|
||||
|
||||
/**
|
||||
* 该属性业务接入时无需关心. 尽量保证其他属性都设值.
|
||||
* 头像
|
||||
*/
|
||||
@IndexField(exist = false)
|
||||
private String avatar;
|
||||
|
||||
public final String buildAssigneeId_1_2_1() {
|
||||
|
||||
@ -56,6 +56,12 @@ public class BpmnTaskTransferDTO {
|
||||
@ApiModelProperty(value = "审批任务转交给谁", notes = "可以为空,意义在于如果分配给某离职的人,可能需要置为空")
|
||||
private BpmnTaskDelegateAssigner targetAssigner;
|
||||
|
||||
/**
|
||||
* 转交描述
|
||||
*/
|
||||
@ApiModelProperty(value = "转交描述", notes = "正常是'xx转交给xx',该字段值追加在后面")
|
||||
private String additionalOpeDesc;
|
||||
|
||||
/**
|
||||
* 是否异步执行
|
||||
*/
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
package cn.axzo.workflow.common.model.request.es;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.BpmPageParam;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 搜索 Es 中实例纬度的数据
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-08 14:03
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("搜索 Es 中实例纬度的数据")
|
||||
@Data
|
||||
public class InstanceSearchReqDTO extends BpmPageParam {
|
||||
|
||||
@ApiModelProperty(value = "审批人所属租户 ID")
|
||||
private String tenantId;
|
||||
|
||||
@ApiModelProperty(value = "审批人所属单位 ID")
|
||||
private String ouId;
|
||||
|
||||
@ApiModelProperty(value = "审批人自然人 ID")
|
||||
private String personId;
|
||||
|
||||
@ApiModelProperty(value = "审批人姓名")
|
||||
private String assigneeName;
|
||||
|
||||
@ApiModelProperty(value = "流程实例状态", notes = "参考 BpmnProcessInstanceResultEnum 枚举")
|
||||
private String businessStatus;
|
||||
|
||||
@ApiModelProperty(value = "流程实例名称")
|
||||
private String processInstanceName;
|
||||
|
||||
private Date beginStartTime;
|
||||
private Date overStartTime;
|
||||
|
||||
private Date beginEndTime;
|
||||
private Date overEndTime;
|
||||
|
||||
/**
|
||||
* 流程实例 ID, 与其它所有的属性互斥
|
||||
*/
|
||||
@ApiModelProperty(value = "流程实例 ID 集合")
|
||||
private List<String> processInstanceIds;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package cn.axzo.workflow.common.model.request.es;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.BpmPageParam;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 搜索 Es 中任务纬度的数据
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-08 09:49
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel("搜索 Es 中任务纬度的数据")
|
||||
@Data
|
||||
public class TaskSearchReqDTO extends BpmPageParam {
|
||||
private static final long serialVersionUID = -1L;
|
||||
|
||||
@ApiModelProperty(value = "流程实例 ID")
|
||||
private String processInstanceId;
|
||||
/**
|
||||
* 搜索含有指定该租户的任务
|
||||
*/
|
||||
@ApiModelProperty(value = "租户 ID")
|
||||
private String assigneeTenantId;
|
||||
|
||||
/**
|
||||
* 搜索含有指定单位的任务
|
||||
*/
|
||||
@ApiModelProperty(value = "单位 ID")
|
||||
private String assigneeOuId;
|
||||
|
||||
/**
|
||||
* 搜索含有指定自然人的任务
|
||||
*/
|
||||
@ApiModelProperty(value = "自然人 ID")
|
||||
private String assigneePersonId;
|
||||
|
||||
/**
|
||||
* 搜索含有指定自然人名称的任务
|
||||
*/
|
||||
@ApiModelProperty(value = "自然人姓名")
|
||||
private String assigneeName;
|
||||
|
||||
/**
|
||||
* 与上面三个属性互斥
|
||||
* <p>
|
||||
* 成对是数据项
|
||||
*/
|
||||
@ApiModelProperty(value = "审批人信息集合")
|
||||
private List<BpmnTaskDelegateAssigner> assigners;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package cn.axzo.workflow.common.model.response.admin;
|
||||
|
||||
import cn.axzo.workflow.common.enums.AdminDataSource;
|
||||
import cn.axzo.workflow.common.enums.AdminRoleType;
|
||||
import cn.axzo.workflow.common.enums.AdminTypeEnum;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class ProcessAdminVo {
|
||||
|
||||
/**
|
||||
* 管理员配置id
|
||||
*/
|
||||
@ApiModelProperty("管理员配置id")
|
||||
private Long processAdminId;
|
||||
|
||||
/**
|
||||
* 自然人id
|
||||
*/
|
||||
@ApiModelProperty("自然人id")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@ApiModelProperty("单位id")
|
||||
private Long organizationalUnitId;
|
||||
|
||||
/**
|
||||
* 工作台ID
|
||||
*/
|
||||
@ApiModelProperty("工作台ID")
|
||||
private Long workspaceId;
|
||||
|
||||
/**
|
||||
* 工作台类型,1-企业, 2-项目, 3-政务监管平台, 6-oms工作台,参考 WorkspaceType枚举
|
||||
*/
|
||||
@ApiModelProperty("工作台ID")
|
||||
private Integer workspaceType;
|
||||
|
||||
/**
|
||||
* 管理员类型, super_admin-超级管理员, common_admin-普通管理员
|
||||
*/
|
||||
@ApiModelProperty("管理员类型")
|
||||
private AdminTypeEnum adminType;
|
||||
|
||||
/**
|
||||
* 角色类型, organization_admin-单位超管, organization_worksapce_admin-项目内单位负责人, workspace_admin-项目超管,other-其他用户
|
||||
*/
|
||||
@ApiModelProperty("角色类型")
|
||||
private AdminRoleType roleType;
|
||||
|
||||
/**
|
||||
* 数据来源, system-系统录入, user-用户手动录入
|
||||
*/
|
||||
@ApiModelProperty("数据来源")
|
||||
private AdminDataSource dataSource;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@ApiModelProperty("创建者")
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ApiModelProperty("创建时间")
|
||||
private Date createAt;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
@ApiModelProperty("更新者")
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ApiModelProperty("更新时间")
|
||||
private Date updateAt;
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
package cn.axzo.workflow.common.model.response.es;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 搜索 ES 的流程实例相关数据模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-09 14:26
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("搜索 ES 的流程实例相关数据模型")
|
||||
public class ProcessInstanceDocumentVO {
|
||||
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
private String instanceId;
|
||||
|
||||
/**
|
||||
* 流程实例名称
|
||||
*/
|
||||
private String processInstanceName;
|
||||
|
||||
/**
|
||||
* 业务传入业务信息
|
||||
*/
|
||||
private String businessKey;
|
||||
|
||||
/**
|
||||
* 流程实例使用的定义 ID
|
||||
*/
|
||||
private String processDefinitionId;
|
||||
|
||||
/**
|
||||
* 流程对应业务分类的类型,项目/单位/监管/OMS
|
||||
*/
|
||||
private String processCategoryType;
|
||||
|
||||
/**
|
||||
* 流程实例的发起时间
|
||||
*/
|
||||
private Date instanceStartTime;
|
||||
|
||||
/**
|
||||
* 流程实例的结束时间
|
||||
*/
|
||||
private Date instanceEndTime;
|
||||
|
||||
/**
|
||||
* 流程实例的持续时间 ms
|
||||
*/
|
||||
private Long durationInMillis;
|
||||
|
||||
/**
|
||||
* 该流程中上次操作完成的时间, 如果是已完成的实例, 就清空该值
|
||||
*/
|
||||
private Date lastOperationTime;
|
||||
|
||||
/**
|
||||
* 租户 ID
|
||||
*/
|
||||
private String instanceTenantId;
|
||||
|
||||
/**
|
||||
* 流程实例业务状态
|
||||
*/
|
||||
private String businessStatus;
|
||||
|
||||
/**
|
||||
* 发起人姓名
|
||||
*/
|
||||
private String initiatorName;
|
||||
|
||||
/**
|
||||
* 实例对应的流程引擎服务端迭代版本
|
||||
*/
|
||||
private String workflowEngineVersion;
|
||||
|
||||
/**
|
||||
* 是否代运营
|
||||
*/
|
||||
private Boolean agent;
|
||||
|
||||
/**
|
||||
* 是否支持批量操作任务
|
||||
*/
|
||||
private Boolean supportBatch;
|
||||
|
||||
/**
|
||||
* 是否开启同意操作时的签名
|
||||
*/
|
||||
private Boolean userAgreeSignature;
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
package cn.axzo.workflow.common.model.response.es;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 搜索 ES 的流程任务相关数据模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-12 21:53
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("搜索 ES 的流程任务相关数据模型")
|
||||
public class ProcessTaskDocumentVO {
|
||||
|
||||
/**
|
||||
* 任务 ID
|
||||
*/
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 所属实例 ID
|
||||
*/
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 任务定义 KEY,对应节点 ID
|
||||
*/
|
||||
private String taskDefinitionKey;
|
||||
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 任务状态:审批中/通过/驳回/转交/加签...
|
||||
*/
|
||||
private String taskStatus;
|
||||
|
||||
/**
|
||||
* 操作建议
|
||||
*/
|
||||
private String advice;
|
||||
|
||||
/**
|
||||
* 操作描述
|
||||
*/
|
||||
private String operationDesc;
|
||||
|
||||
/**
|
||||
* 流程实例的发起时间
|
||||
*/
|
||||
private Date taskStartTime;
|
||||
|
||||
/**
|
||||
* 流程实例的结束时间
|
||||
*/
|
||||
private Date taskEndTime;
|
||||
|
||||
/**
|
||||
* 流程实例的持续时间 ms
|
||||
*/
|
||||
private Long duration;
|
||||
|
||||
/**
|
||||
* 归属租户,与 processInstance#tenantId 一致
|
||||
*/
|
||||
private String taskTenantId;
|
||||
|
||||
/**
|
||||
* 审批人姓名
|
||||
*/
|
||||
private String assigneeName;
|
||||
|
||||
/**
|
||||
* 审批人自然人 ID
|
||||
*/
|
||||
private String assigneePersonId;
|
||||
|
||||
/**
|
||||
* 审批人所属单位 ID
|
||||
*/
|
||||
private String assigneeOuId;
|
||||
|
||||
/**
|
||||
* 审批人所属租户 ID
|
||||
*/
|
||||
private String assigneeTenantId;
|
||||
|
||||
/**
|
||||
* 审批方式:配置审批人/业务指定/业务触发(不含人)
|
||||
*/
|
||||
private String approvalMethod;
|
||||
|
||||
/**
|
||||
* 节点类型:审批节点/业务节点/评论节点/抄送节点
|
||||
*/
|
||||
private String nodeType;
|
||||
|
||||
/**
|
||||
* 节点模式:会签/或签
|
||||
*/
|
||||
private String nodeMode;
|
||||
}
|
||||
@ -72,6 +72,6 @@ public class SupportRefreshProperties {
|
||||
/**
|
||||
* 用于控制转交管理员的 API
|
||||
*/
|
||||
@Value("${workflow.useNewToAdminApi:true}")
|
||||
@Value("${workflow.useNewToAdminApi:false}")
|
||||
private Boolean useNewToAdminApi;
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import org.flowable.common.engine.impl.interceptor.Command;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.common.engine.impl.persistence.entity.PropertyEntity;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 操作 ACT_GE_PROPERTY 表的删除指定属性的命令
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-30 15:15
|
||||
*/
|
||||
public class CustomClearPropertyCmd implements Command<Void> {
|
||||
private final String propertyName;
|
||||
|
||||
public CustomClearPropertyCmd(String propertyName) {
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void execute(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
PropertyEntity entity = processEngineConfiguration.getPropertyEntityManager().findById(propertyName);
|
||||
if (Objects.nonNull(entity)) {
|
||||
processEngineConfiguration.getPropertyEntityManager().delete(entity.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
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.ManagementService;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
import org.flowable.variable.api.history.HistoricVariableInstance;
|
||||
import org.flowable.variable.api.history.NativeHistoricVariableInstanceQuery;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义指定实例下的指定名称的变量数据
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-14 13:43
|
||||
*/
|
||||
public class CustomGetHistoricVariablesCmd implements Command<List<HistoricVariableInstance>> {
|
||||
|
||||
private final String processInstanceId;
|
||||
private final List<String> variableNames;
|
||||
|
||||
public CustomGetHistoricVariablesCmd(String processInstanceId, List<String> variableNames) {
|
||||
this.processInstanceId = processInstanceId;
|
||||
this.variableNames = variableNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HistoricVariableInstance> execute(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
HistoryService historyService = processEngineConfiguration.getHistoryService();
|
||||
|
||||
if (StringUtils.hasText(processInstanceId) && !CollectionUtils.isEmpty(variableNames)) {
|
||||
NativeHistoricVariableInstanceQuery query = historyService.createNativeHistoricVariableInstanceQuery()
|
||||
.sql(buildQuerySql(commandContext))
|
||||
.parameter("processInstanceId", processInstanceId);
|
||||
if (!CollectionUtils.isEmpty(variableNames)) {
|
||||
for (int i = 0; i < variableNames.size(); i++) {
|
||||
query.parameter("variableName" + i, variableNames.get(i));
|
||||
}
|
||||
}
|
||||
return query.list();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private String buildQuerySql(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
ManagementService managementService = processEngineConfiguration.getManagementService();
|
||||
StringBuilder baseQuerySql = new StringBuilder("SELECT * ")
|
||||
.append(" FROM ")
|
||||
.append(managementService.getTableName(HistoricVariableInstance.class))
|
||||
.append(" WHERE 1 = 1")
|
||||
.append(" AND PROC_INST_ID_ = #{processInstanceId}");
|
||||
|
||||
if (!CollectionUtils.isEmpty(variableNames)) {
|
||||
baseQuerySql.append(" AND (");
|
||||
for (int i = 0; i < variableNames.size(); i++) {
|
||||
if (i != 0) {
|
||||
baseQuerySql.append(" OR ");
|
||||
}
|
||||
baseQuerySql.append(" NAME_ = #{variableName").append(i).append("}");
|
||||
}
|
||||
}
|
||||
return baseQuerySql.append(")").toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import org.flowable.common.engine.impl.interceptor.Command;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.common.engine.impl.persistence.entity.PropertyEntity;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 获取 ACT_GE_PROPERTY 表的指定属性值的命令
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-30 15:15
|
||||
*/
|
||||
public class CustomGetPropertyCmd implements Command<Date> {
|
||||
private final String propertyName;
|
||||
|
||||
public CustomGetPropertyCmd(String propertyName) {
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date execute(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
PropertyEntity entity = processEngineConfiguration.getPropertyEntityManager().findById(propertyName);
|
||||
if (Objects.nonNull(entity)) {
|
||||
return DateUtil.parseDate(entity.getValue());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package cn.axzo.workflow.core.engine.cmd;
|
||||
|
||||
import org.flowable.common.engine.impl.interceptor.Command;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.common.engine.impl.persistence.entity.PropertyEntity;
|
||||
import org.flowable.common.engine.impl.persistence.entity.PropertyEntityImpl;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 操作 ACT_GE_PROPERTY 表的写命令
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-30 15:15
|
||||
*/
|
||||
public class CustomInsertPropertyCmd implements Command<Void> {
|
||||
private final String propertyName;
|
||||
private final String propertyValue;
|
||||
|
||||
public CustomInsertPropertyCmd(String propertyName, String propertyValue) {
|
||||
this.propertyName = propertyName;
|
||||
this.propertyValue = propertyValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void execute(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
PropertyEntity entity = processEngineConfiguration.getPropertyEntityManager().findById(propertyName);
|
||||
if (Objects.nonNull(entity)) {
|
||||
entity.setValue(propertyValue);
|
||||
processEngineConfiguration.getPropertyEntityManager().update(entity);
|
||||
} else {
|
||||
entity = new PropertyEntityImpl();
|
||||
entity.setName(propertyName);
|
||||
entity.setValue(propertyValue);
|
||||
processEngineConfiguration.getPropertyEntityManager().insert(entity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.flowable.common.engine.impl.identity.Authentication;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
@ -46,19 +47,23 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
|
||||
*/
|
||||
public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8011156125774066571L;
|
||||
private final String originTaskId;
|
||||
private final BpmnTaskDelegateAssigner originTaskAssignee;
|
||||
private final String advice;
|
||||
private final List<AttachmentDTO> attachmentList;
|
||||
private final BpmnTaskDelegateAssigner targetTaskAssignee;
|
||||
private final String additionalOpeDesc;
|
||||
|
||||
public CustomTransferUserTaskCmd(String originTaskId, BpmnTaskDelegateAssigner originTaskAssignee, String advice,
|
||||
List<AttachmentDTO> attachmentList, BpmnTaskDelegateAssigner targetTaskAssignee) {
|
||||
List<AttachmentDTO> attachmentList, BpmnTaskDelegateAssigner targetTaskAssignee,
|
||||
String additionalOpeDesc) {
|
||||
this.originTaskId = originTaskId;
|
||||
this.originTaskAssignee = originTaskAssignee;
|
||||
this.advice = advice;
|
||||
this.attachmentList = attachmentList;
|
||||
this.targetTaskAssignee = targetTaskAssignee;
|
||||
this.additionalOpeDesc = additionalOpeDesc;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,9 +80,9 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
|
||||
@Override
|
||||
public Void execute(CommandContext commandContext) {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration =
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
HistoricTaskInstanceQuery taskQuery =
|
||||
processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
|
||||
processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
|
||||
HistoricTaskInstance historicTaskInstance = taskQuery.taskId(originTaskId).singleResult();
|
||||
|
||||
TaskService taskService = processEngineConfiguration.getTaskService();
|
||||
@ -93,7 +98,7 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
|
||||
// 对被转交的任务进行建议和附件的处理
|
||||
resolveOriginTask(commandContext, taskService, task);
|
||||
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList,
|
||||
originTaskAssignee);
|
||||
originTaskAssignee);
|
||||
|
||||
// 生成转交任务
|
||||
addMultiTask(commandContext, task, targetTaskAssignee);
|
||||
@ -110,7 +115,7 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
|
||||
task.setScopeType("TRANSFER");
|
||||
|
||||
Authentication.setAuthenticatedUserId(originTaskAssignee.buildAssigneeId());
|
||||
addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "转交给" + targetTaskAssignee.getAssignerName());
|
||||
addComment(commandContext, task, COMMENT_TYPE_OPERATION_DESC, "转交给" + targetTaskAssignee.getAssignerName() + (StringUtils.isNotBlank(additionalOpeDesc) ? additionalOpeDesc : ""));
|
||||
addComment(commandContext, task, COMMENT_TYPE_ADVICE, advice);
|
||||
Authentication.setAuthenticatedUserId(null);
|
||||
|
||||
@ -120,9 +125,9 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
|
||||
public void processAssignee(ProcessEngineConfigurationImpl processEngineConfiguration, Task task) {
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
List<BpmnTaskDelegateAssigner> originAssingeeList = runtimeService.getVariable(task.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class);
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class);
|
||||
Optional<BpmnTaskDelegateAssigner> exists = originAssingeeList.stream()
|
||||
.filter(i -> Objects.equals(i.buildAssigneeId(), targetTaskAssignee.buildAssigneeId())).findAny();
|
||||
.filter(i -> Objects.equals(i.buildAssigneeId(), targetTaskAssignee.buildAssigneeId())).findAny();
|
||||
if (exists.isPresent()) {
|
||||
throw new WorkflowEngineException(ASSIGNEE_HAS_BEEN_EXISTS);
|
||||
}
|
||||
@ -135,8 +140,8 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
|
||||
}
|
||||
originAssingeeList.add(targetTaskAssignee);
|
||||
runtimeService.setVariable(task.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(),
|
||||
originAssingeeList);
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(),
|
||||
originAssingeeList);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -29,6 +29,6 @@ public class AsyncTransferUserTaskJobHandler extends AbstractJobHandler implemen
|
||||
CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
BpmnTaskTransferDTO dto = JSONUtil.toBean(job.getCustomValues(), BpmnTaskTransferDTO.class);
|
||||
processEngineConfiguration.getCommandExecutor().execute(new CustomTransferUserTaskCmd(dto.getTaskId(),
|
||||
dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssigner()));
|
||||
dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssigner(), dto.getAdditionalOpeDesc()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventT
|
||||
import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.ENTITY_UPDATED;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* 引擎内的 Entity 事件监听处理
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-02 15:34
|
||||
@ -33,20 +33,19 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener {
|
||||
|
||||
private final List<EntityEventHandle> handles;
|
||||
public static final Set<FlowableEngineEventType> SUPPORTED =
|
||||
ImmutableSet.<FlowableEngineEventType>builder()
|
||||
.add(ENTITY_CREATED)
|
||||
.add(ENTITY_INITIALIZED)
|
||||
.add(ENTITY_UPDATED)
|
||||
.add(ENTITY_DELETED)
|
||||
.add(ENTITY_SUSPENDED)
|
||||
.add(ENTITY_ACTIVATED)
|
||||
.build();
|
||||
ImmutableSet.<FlowableEngineEventType>builder()
|
||||
.add(ENTITY_CREATED)
|
||||
.add(ENTITY_INITIALIZED)
|
||||
.add(ENTITY_UPDATED)
|
||||
.add(ENTITY_DELETED)
|
||||
.add(ENTITY_SUSPENDED)
|
||||
.add(ENTITY_ACTIVATED)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public void onEvent(FlowableEvent event) {
|
||||
if (event instanceof FlowableEntityEvent && SUPPORTED.contains(event.getType())) {
|
||||
FlowableEntityEvent entityEvent = (FlowableEntityEvent) event;
|
||||
// log.warn("entity event type: {}, class: {}",entityEvent.getType(), entityEvent.getEntity().getClass());
|
||||
handles.forEach(handle -> {
|
||||
Object entity = entityEvent.getEntity();
|
||||
if (handle.support(entity)) {
|
||||
@ -66,48 +65,10 @@ public class EngineEntityEventListener extends AbstractFlowableEventListener {
|
||||
}
|
||||
}
|
||||
});
|
||||
// if (entityEvent.getEntity() instanceof TaskEntity) {
|
||||
// TaskEntity taskEntity = (TaskEntity) entityEvent.getEntity();
|
||||
// log.error("event taskId :{}, taskDefKey: {}", taskEntity.getId(), taskEntity.getTaskDefinitionKey());
|
||||
//
|
||||
// if (Objects.equals(event.getType(), ENTITY_CREATED)) {
|
||||
// onCreate(taskEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_INITIALIZED)) {
|
||||
// onInitialized(taskEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_UPDATED)) {
|
||||
// onUpdated(taskEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_DELETED)) {
|
||||
// onDeleted(taskEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_SUSPENDED)) {
|
||||
// onSuspended(taskEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_ACTIVATED)) {
|
||||
// onActivated(taskEntity);
|
||||
// }
|
||||
// } else if(entityEvent.getEntity() instanceof CommentEntity) {
|
||||
// CommentEntity commentEntity = (CommentEntity) entityEvent.getEntity();
|
||||
// log.error("event taskId :{}", commentEntity.getId());
|
||||
//
|
||||
// if (Objects.equals(event.getType(), ENTITY_CREATED)) {
|
||||
// onCreate(commentEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_INITIALIZED)) {
|
||||
// onInitialized(commentEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_UPDATED)) {
|
||||
// onUpdated(commentEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_DELETED)) {
|
||||
// onDeleted(commentEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_SUSPENDED)) {
|
||||
// onSuspended(commentEntity);
|
||||
// } else if (Objects.equals(event.getType(), ENTITY_ACTIVATED)) {
|
||||
// onActivated(commentEntity);
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isFailOnException() {
|
||||
return true;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package cn.axzo.workflow.core.engine.listener.entity;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* Entity life cycle
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-06 00:03
|
||||
@ -12,16 +12,22 @@ public interface EntityEventHandle<T> {
|
||||
|
||||
T convert(Object entity);
|
||||
|
||||
void onCreate(T entity);
|
||||
default void onCreate(T entity) {
|
||||
}
|
||||
|
||||
void onInitialized(T entity);
|
||||
default void onInitialized(T entity) {
|
||||
}
|
||||
|
||||
void onUpdated(T entity);
|
||||
default void onUpdated(T entity) {
|
||||
}
|
||||
|
||||
void onDeleted(T entity);
|
||||
default void onDeleted(T entity) {
|
||||
}
|
||||
|
||||
void onSuspended(T entity);
|
||||
default void onSuspended(T entity) {
|
||||
}
|
||||
|
||||
void onActivated(T entity);
|
||||
default void onActivated(T entity) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -22,7 +22,6 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERAT
|
||||
//@Component
|
||||
@AllArgsConstructor
|
||||
public class CommentEntityEventHandle implements EntityEventHandle<CommentEntity> {
|
||||
private final ExtAxProcessLogService processLogService;
|
||||
|
||||
@Override
|
||||
public boolean support(Object entity) {
|
||||
@ -37,45 +36,30 @@ public class CommentEntityEventHandle implements EntityEventHandle<CommentEntity
|
||||
@Override
|
||||
public void onCreate(CommentEntity entity) {
|
||||
log.info("comment event onCreate: {}", entity.getId());
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(entity.getProcessInstanceId());
|
||||
queryLog.setTaskId(entity.getId());
|
||||
ExtAxProcessLog update = new ExtAxProcessLog();
|
||||
if (Objects.equals(COMMENT_TYPE_ADVICE, entity.getType())) {
|
||||
update.setAdvice(entity.getFullMessage());
|
||||
} else if (Objects.equals(COMMENT_TYPE_OPERATION_DESC, entity.getType())) {
|
||||
update.setOperationDesc(entity.getFullMessage());
|
||||
}
|
||||
processLogService.update(queryLog, update);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitialized(CommentEntity entity) {
|
||||
log.info("comment event onInitialized: {}", entity.getId());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdated(CommentEntity entity) {
|
||||
log.info("comment event onUpdated: {}", entity.getId());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(CommentEntity entity) {
|
||||
log.info("comment event onDeleted: {}", entity.getId());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuspended(CommentEntity entity) {
|
||||
log.info("comment event onSuspended: {}", entity.getId());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivated(CommentEntity entity) {
|
||||
log.info("comment event onSuspended: {}", entity.getId());
|
||||
|
||||
log.info("comment event onActivated: {}", entity.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package cn.axzo.workflow.core.engine.listener.entity.type;
|
||||
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeMode;
|
||||
import cn.axzo.workflow.common.enums.BpmnFlowNodeType;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
@ -15,7 +14,6 @@ import org.apache.commons.collections4.ListUtils;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.bpmn.model.UserTask;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
@ -75,16 +73,67 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivated(TaskEntity taskEntity) {
|
||||
log.debug("onActivated");
|
||||
public void onCreate(TaskEntity taskEntity) {
|
||||
// 记录发起人
|
||||
boolean isNodeStarter = Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType());
|
||||
|
||||
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(taskEntity.getProcessDefinitionId());
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(taskEntity.getTaskDefinitionKey());
|
||||
|
||||
ExtAxProcessLog log = new ExtAxProcessLog();
|
||||
log.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
log.setTenantId(taskEntity.getTenantId());
|
||||
log.setActivityId(taskEntity.getTaskDefinitionKey());
|
||||
log.setActivityName(taskEntity.getName());
|
||||
log.setApprovalMethod((isNodeStarter ? nobody : getApprovalMethod(flowElement).orElse(nobody)).getType());
|
||||
log.setNodeType((getNodeType(flowElement).orElse(BpmnFlowNodeType.NODE_EMPTY)).getType());
|
||||
log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType());
|
||||
log.setTaskId(taskEntity.getId());
|
||||
log.setOperationDesc(PENDING.getDesc());
|
||||
log.setStartTime(taskEntity.getCreateTime());
|
||||
log.setStatus(PROCESSING.getStatus());
|
||||
|
||||
processLogService.insert(log);
|
||||
}
|
||||
|
||||
public void onSuspended(TaskEntity taskEntity) {
|
||||
log.debug("onSuspended");
|
||||
@Override
|
||||
public void onInitialized(TaskEntity taskEntity) {
|
||||
BpmnMetaParserHelper.getButtonConfig(ProcessDefinitionUtil.getProcess(taskEntity.getProcessDefinitionId()), taskEntity.getTaskDefinitionKey())
|
||||
.ifPresent(buttons -> {
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
|
||||
ExtAxProcessLog updateLog = new ExtAxProcessLog();
|
||||
updateLog.setButtonConf(buttons);
|
||||
processLogService.update(queryLog, updateLog);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdated(TaskEntity taskEntity) {
|
||||
if (Objects.equals(HIDDEN_ASSIGNEE_ID, taskEntity.getAssignee())) {
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
processLogService.delete(queryLog);
|
||||
} else {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
List<BpmnTaskDelegateAssigner> assigneeList = runtimeService.getVariable(taskEntity.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class);
|
||||
ListUtils.emptyIfNull(assigneeList).stream().filter(e -> Objects.equals(e.buildAssigneeId(), taskEntity.getAssignee())).findAny()
|
||||
.ifPresent(assignee -> {
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
processLogService.updateAssignee(queryLog, assignee);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(TaskEntity taskEntity) {
|
||||
log.debug("onDeleted");
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
@ -109,23 +158,18 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
|
||||
Object advice = taskEntity.getTransientVariableLocal(COMMENT_TYPE_ADVICE);
|
||||
if (Objects.nonNull(advice) && StringUtils.hasText(advice.toString())) {
|
||||
log.info("COMMENT_TYPE_ADVICE: {}", advice);
|
||||
update.setAdvice(advice.toString());
|
||||
}
|
||||
Object operationDesc = taskEntity.getTransientVariableLocal(COMMENT_TYPE_OPERATION_DESC);
|
||||
if (Objects.nonNull(operationDesc) && StringUtils.hasText(operationDesc.toString())) {
|
||||
log.info("COMMENT_TYPE_OPERATION_DESC: {}", operationDesc);
|
||||
update.setOperationDesc(Objects.nonNull(assignee) ? assignee.getAssignerName() + operationDesc : operationDesc.toString());
|
||||
} else {
|
||||
update.setOperationDesc(Objects.nonNull(assignee) ? assignee.getAssignerName() : "");
|
||||
// 评论节点会给 operationDesc 赋 COMMENTED 的值,所以注释
|
||||
// update.setOperationDesc(BpmnProcessInstanceResultEnum.valueOfStatus(completionType).getDesc());
|
||||
}
|
||||
|
||||
|
||||
String completionType = taskEntity.getVariable(TASK_COMPLETE_OPERATION_TYPE + taskEntity.getId(), String.class);
|
||||
if (StringUtils.hasText(completionType) && !Objects.equals(DELETED.getStatus(), completionType)) {
|
||||
log.info("TASK_COMPLETE_OPERATION_TYPE: {}", completionType);
|
||||
update.setStatus(completionType);
|
||||
} else {
|
||||
// 多实例除操作人以外的任务,直接删除日志, 例如一个节点有两个人或签,A 人驳回了,那么 B 人不再需要操作,任务自动删除。而会签也同理
|
||||
@ -162,69 +206,6 @@ public class TaskEntityEventHandle implements EntityEventHandle<TaskEntity> {
|
||||
return Objects.equals(logs.get(0).getNodeType(), BpmnFlowNodeType.NODE_CARBON_COPY.getType());
|
||||
}
|
||||
|
||||
public void onUpdated(TaskEntity taskEntity) {
|
||||
log.debug("onUpdated");
|
||||
if (Objects.equals(HIDDEN_ASSIGNEE_ID, taskEntity.getAssignee())) {
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
processLogService.delete(queryLog);
|
||||
} else {
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
|
||||
List<BpmnTaskDelegateAssigner> assigneeList = runtimeService.getVariable(taskEntity.getProcessInstanceId(),
|
||||
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey(), List.class);
|
||||
ListUtils.emptyIfNull(assigneeList).stream().filter(e -> Objects.equals(e.buildAssigneeId(), taskEntity.getAssignee())).findAny()
|
||||
.ifPresent(assignee -> {
|
||||
log.debug("审批人: {}", JSON.toJSONString(assignee));
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
processLogService.updateAssignee(queryLog, assignee);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void onInitialized(TaskEntity taskEntity) {
|
||||
log.debug("onInitialized");
|
||||
BpmnMetaParserHelper.getButtonConfig(ProcessDefinitionUtil.getProcess(taskEntity.getProcessDefinitionId()), taskEntity.getTaskDefinitionKey())
|
||||
.ifPresent(buttons -> {
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
queryLog.setTaskId(taskEntity.getId());
|
||||
|
||||
ExtAxProcessLog updateLog = new ExtAxProcessLog();
|
||||
updateLog.setButtonConf(buttons);
|
||||
processLogService.update(queryLog, updateLog);
|
||||
});
|
||||
}
|
||||
|
||||
public void onCreate(TaskEntity taskEntity) {
|
||||
log.debug("onCreate");
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
|
||||
// 记录发起人
|
||||
boolean isNodeStarter = Objects.equals(taskEntity.getTaskDefinitionKey(), NODE_STARTER.getType());
|
||||
|
||||
RepositoryService repositoryService = processEngineConfiguration.getRepositoryService();
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(taskEntity.getProcessDefinitionId());
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(taskEntity.getTaskDefinitionKey());
|
||||
|
||||
ExtAxProcessLog log = new ExtAxProcessLog();
|
||||
log.setProcessInstanceId(taskEntity.getProcessInstanceId());
|
||||
log.setTenantId(taskEntity.getTenantId());
|
||||
log.setActivityId(taskEntity.getTaskDefinitionKey());
|
||||
log.setActivityName(taskEntity.getName());
|
||||
log.setApprovalMethod((isNodeStarter ? nobody : getApprovalMethod(flowElement).orElse(nobody)).getType());
|
||||
log.setNodeType((getNodeType(flowElement).orElse(BpmnFlowNodeType.NODE_EMPTY)).getType());
|
||||
log.setNodeMode((isNodeStarter ? BpmnFlowNodeMode.GENERAL : getNodeMode(flowElement)).getType());
|
||||
log.setTaskId(taskEntity.getId());
|
||||
log.setOperationDesc(PENDING.getDesc());
|
||||
log.setStartTime(taskEntity.getCreateTime());
|
||||
log.setStatus(PROCESSING.getStatus());
|
||||
|
||||
processLogService.insert(log);
|
||||
}
|
||||
|
||||
private BpmnFlowNodeMode getNodeMode(FlowElement flowElement) {
|
||||
BpmnFlowNodeMode node = GENERAL;
|
||||
if (flowElement instanceof UserTask) {
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package cn.axzo.workflow.core.service;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.es.HistoricProcessInstanceSearchForEsDTO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 专用与对接 ES 的流程实例相关操作
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 14:23
|
||||
*/
|
||||
public interface BpmnProcessInstanceForEsService {
|
||||
|
||||
Long queryHistoricProcessInstanceTotalCount(HistoricProcessInstanceSearchForEsDTO search);
|
||||
|
||||
List<HistoricProcessInstance> queryHistoricProcessInstance(HistoricProcessInstanceSearchForEsDTO search, IPage page);
|
||||
|
||||
BpmnModel queryBpmnModel(String processDefinitionId);
|
||||
|
||||
Map<String, Object> queryInstanceVariables(String processInstanceId, List<String> variableNames);
|
||||
|
||||
Long queryHistoricProcessInstanceByUnfinishedAndAlterEndTimeTotalCount(Date endTime);
|
||||
|
||||
/**
|
||||
* 查询指定时间点之后的完成的审批,和还未完成的审批
|
||||
* @param endTime
|
||||
* @param page
|
||||
* @return
|
||||
*/
|
||||
List<HistoricProcessInstance> queryHistoricProcessInstanceByUnfinishedAndAlterEndTime(Date endTime, IPage page);
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package cn.axzo.workflow.core.service;
|
||||
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import org.flowable.engine.task.Attachment;
|
||||
import org.flowable.engine.task.Comment;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专用与对接 ES 的流程任务相关操作
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-29 10:55
|
||||
*/
|
||||
public interface BpmnProcessTaskForEsService {
|
||||
|
||||
List<HistoricTaskInstance> queryHistoricProcessTaskByProcessInstanceId(String processInstanceId);
|
||||
|
||||
List<ExtAxHiTaskInst> queryExtAxHiTaskInstByProcessInstanceId(String processInstanceId);
|
||||
|
||||
List<Comment> queryCommentByProcessInstanceId(String processInstanceId);
|
||||
|
||||
List<Attachment> queryAttachmentByProcessInstanceId(String processInstanceId);
|
||||
|
||||
List<ExtAxProcessLog> queryProcessLogByProcessInstanceId(String processInstanceId);
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
package cn.axzo.workflow.core.service.impl;
|
||||
|
||||
import cn.axzo.workflow.common.model.dto.es.HistoricProcessInstanceSearchForEsDTO;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetHistoricVariablesCmd;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceForEsService;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
import org.flowable.engine.HistoryService;
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstanceQuery;
|
||||
import org.flowable.engine.impl.HistoryServiceImpl;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.flowable.variable.api.history.HistoricVariableInstance;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 专用与对接 ES 的流程实例相关操作
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 14:23
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BpmnProcessInstanceForEsServiceImpl implements BpmnProcessInstanceForEsService {
|
||||
@Resource
|
||||
@Lazy
|
||||
private HistoryService historyService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private RepositoryService repositoryService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private SpringProcessEngineConfiguration processEngineConfiguration;
|
||||
|
||||
@Override
|
||||
public Long queryHistoricProcessInstanceTotalCount(HistoricProcessInstanceSearchForEsDTO search) {
|
||||
if (Objects.isNull(search)) {
|
||||
return 0L;
|
||||
}
|
||||
return buildHistoricProcessInstanceQuery(search).count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HistoricProcessInstance> queryHistoricProcessInstance(HistoricProcessInstanceSearchForEsDTO search, IPage page) {
|
||||
if (Objects.isNull(search)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
HistoricProcessInstanceQuery query = buildHistoricProcessInstanceQuery(search)
|
||||
.orderByProcessInstanceId().asc();
|
||||
if (Objects.nonNull(page)) {
|
||||
int firstResult = Math.toIntExact((page.getCurrent() - 1) * page.getSize());
|
||||
int maxResult = Math.toIntExact(page.getSize());
|
||||
return query.listPage(firstResult, maxResult);
|
||||
}
|
||||
return query.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BpmnModel queryBpmnModel(String processDefinitionId) {
|
||||
return repositoryService.getBpmnModel(processDefinitionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> queryInstanceVariables(String processInstanceId, List<String> variableNames) {
|
||||
CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
|
||||
List<HistoricVariableInstance> variables = commandExecutor.execute(new CustomGetHistoricVariablesCmd(processInstanceId, variableNames));
|
||||
return variables.stream().collect(Collectors.toMap(HistoricVariableInstance::getVariableName, HistoricVariableInstance::getValue, (s, t) -> s));
|
||||
}
|
||||
|
||||
private HistoricProcessInstanceQuery buildHistoricProcessInstanceQuery(HistoricProcessInstanceSearchForEsDTO search) {
|
||||
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
|
||||
if (StringUtils.hasText(search.getProcessInstanceId())) {
|
||||
historicProcessInstanceQuery.processInstanceId(search.getProcessInstanceId());
|
||||
}
|
||||
if (StringUtils.hasText(search.getBusinessKey())) {
|
||||
historicProcessInstanceQuery.processInstanceBusinessKey(search.getBusinessKey());
|
||||
}
|
||||
if (StringUtils.hasText(search.getProcessDefinitionKey())) {
|
||||
historicProcessInstanceQuery.processDefinitionKey(search.getProcessDefinitionKey());
|
||||
}
|
||||
if (StringUtils.hasText(search.getProcessInstanceName())) {
|
||||
historicProcessInstanceQuery.processInstanceName(search.getProcessInstanceName());
|
||||
}
|
||||
if (StringUtils.hasText(search.getBusinessStatus())) {
|
||||
historicProcessInstanceQuery.processInstanceBusinessStatus(search.getBusinessStatus());
|
||||
}
|
||||
if (StringUtils.hasText(search.getTenantId())) {
|
||||
historicProcessInstanceQuery.processInstanceTenantId(search.getTenantId());
|
||||
}
|
||||
// 只有传值后, 才加入查询条件
|
||||
if (Objects.equals(Boolean.TRUE, search.getFinished())) {
|
||||
historicProcessInstanceQuery.finished();
|
||||
} else if (Objects.equals(Boolean.FALSE, search.getFinished())) {
|
||||
historicProcessInstanceQuery.unfinished();
|
||||
}
|
||||
if (Objects.nonNull(search.getStartTime())) {
|
||||
// 引擎默认仅支持两种
|
||||
switch (search.getStartTimeDirection()) {
|
||||
case BEFORE:
|
||||
historicProcessInstanceQuery.startedBefore(search.getStartTime());
|
||||
break;
|
||||
default:
|
||||
historicProcessInstanceQuery.startedAfter(search.getStartTime());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Objects.nonNull(search.getEndTime())) {
|
||||
// 引擎默认仅支持两种
|
||||
switch (search.getEndTimeDirection()) {
|
||||
case AFTER:
|
||||
historicProcessInstanceQuery.finishedAfter(search.getEndTime());
|
||||
break;
|
||||
default:
|
||||
historicProcessInstanceQuery.finishedBefore(search.getEndTime());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (search.getHasVariables()) {
|
||||
historicProcessInstanceQuery.includeProcessVariables();
|
||||
}
|
||||
return historicProcessInstanceQuery;
|
||||
}
|
||||
|
||||
public Long queryHistoricProcessInstanceByUnfinishedAndAlterEndTimeTotalCount(Date endTime) {
|
||||
return historyService.createHistoricProcessInstanceQuery()
|
||||
.or()
|
||||
.unfinished()
|
||||
.finishedAfter(endTime)
|
||||
.endOr()
|
||||
.count();
|
||||
}
|
||||
|
||||
public List<HistoricProcessInstance> queryHistoricProcessInstanceByUnfinishedAndAlterEndTime(Date endTime, IPage page) {
|
||||
HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery()
|
||||
.or()
|
||||
.unfinished()
|
||||
.finishedAfter(endTime)
|
||||
.endOr();
|
||||
if (Objects.nonNull(page)) {
|
||||
int firstResult = Math.toIntExact((page.getCurrent() - 1) * page.getSize());
|
||||
int maxResult = Math.toIntExact(page.getSize());
|
||||
return query.listPage(firstResult, maxResult);
|
||||
}
|
||||
return query.list();
|
||||
}
|
||||
}
|
||||
@ -1061,6 +1061,7 @@ public class BpmnProcessInstanceServiceImpl implements BpmnProcessInstanceServic
|
||||
.orElse(variables.getOrDefault(OLD_INTERNAL_INITIATOR, null))))
|
||||
.tenantId(historicProcessInstance.getTenantId())
|
||||
.agented((Boolean) Optional.ofNullable(variables.get(INTERNAL_PROCESS_AGENT)).orElse(false))
|
||||
// 任务
|
||||
.taskDetails(genericTaskLogVos(historicProcessInstance.getId(), logs, forecasting, dto))
|
||||
.defaultButtonConf(getButtonConfig(bpmnModel.getMainProcess()).orElse(new BpmnButtonConf()))
|
||||
.supportBatchOperation(getProcessApproveConf(bpmnModel.getMainProcess()).orElse(new BpmnApproveConf()).getSupportBatchOperation())
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
package cn.axzo.workflow.core.service.impl;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.ExtHiTaskSearchDTO;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessTaskForEsService;
|
||||
import cn.axzo.workflow.core.service.ExtAxHiTaskInstService;
|
||||
import cn.axzo.workflow.core.service.ExtAxProcessLogService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.HistoryService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.task.Attachment;
|
||||
import org.flowable.engine.task.Comment;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 专用与对接 ES 的流程任务相关操作
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-29 10:55
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BpmnProcessTaskForEsServiceImpl implements BpmnProcessTaskForEsService {
|
||||
@Resource
|
||||
@Lazy
|
||||
private HistoryService historyService;
|
||||
@Resource
|
||||
@Lazy
|
||||
private TaskService taskService;
|
||||
@Resource
|
||||
private ExtAxHiTaskInstService extAxHiTaskInstService;
|
||||
@Resource
|
||||
private ExtAxProcessLogService extAxProcessLogService;
|
||||
|
||||
@Override
|
||||
public List<HistoricTaskInstance> queryHistoricProcessTaskByProcessInstanceId(String processInstanceId) {
|
||||
// List<BpmnHistoricTaskInstanceVO> historicTaskListByProcessInstanceId = bpmnProcessTaskService.getHistoricTaskListByProcessInstanceId(processInstanceId, null);
|
||||
if (!StringUtils.hasText(processInstanceId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return historyService.createHistoricTaskInstanceQuery()
|
||||
.processInstanceId(processInstanceId)
|
||||
.list();
|
||||
}
|
||||
|
||||
public List<ExtAxHiTaskInst> queryExtAxHiTaskInstByProcessInstanceId(String processInstanceId) {
|
||||
if (!StringUtils.hasText(processInstanceId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ExtHiTaskSearchDTO searchDTO = new ExtHiTaskSearchDTO();
|
||||
searchDTO.setProcessInstanceId(processInstanceId);
|
||||
return extAxHiTaskInstService.queryList(searchDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Comment> queryCommentByProcessInstanceId(String processInstanceId) {
|
||||
if (!StringUtils.hasText(processInstanceId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return taskService.getProcessInstanceComments(processInstanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Attachment> queryAttachmentByProcessInstanceId(String processInstanceId) {
|
||||
if (!StringUtils.hasText(processInstanceId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return taskService.getProcessInstanceAttachments(processInstanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ExtAxProcessLog> queryProcessLogByProcessInstanceId(String processInstanceId) {
|
||||
if(!StringUtils.hasText(processInstanceId)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ExtAxProcessLog queryLog = new ExtAxProcessLog();
|
||||
queryLog.setProcessInstanceId(processInstanceId);
|
||||
return extAxProcessLogService.genericQuery(queryLog);
|
||||
}
|
||||
}
|
||||
@ -684,7 +684,7 @@ public class BpmnProcessTaskServiceImpl implements BpmnProcessTaskService {
|
||||
commandExecutor.execute(new CustomTransferUserTaskAsyncCmd(dto));
|
||||
} else {
|
||||
commandExecutor.execute(new CustomTransferUserTaskCmd(dto.getTaskId(),
|
||||
dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssigner()));
|
||||
dto.getOriginAssigner(), dto.getAdvice(), dto.getAttachmentList(), dto.getTargetAssigner(), dto.getAdditionalOpeDesc()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ import static cn.axzo.workflow.core.common.code.BpmnModelRespCode.MODEL_ID_NOT_E
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class ExtAxAxReModelServiceImpl implements ExtAxReModelService {
|
||||
public class ExtAxReModelServiceImpl implements ExtAxReModelService {
|
||||
@Resource
|
||||
private ExtAxReModelMapper extAxReModelMapper;
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
create table ext_ax_process_admin
|
||||
(
|
||||
id bigint auto_increment comment '主键' primary key,
|
||||
person_id bigint default 0 not null comment '自然人id',
|
||||
organizational_unit_id bigint default 0 not null comment '单位id',
|
||||
workspace_id bigint default 0 not null comment '工作台ID',
|
||||
workspace_type tinyint default 0 not null comment '工作台类型,1-企业, 2-项目, 3-政务监管平台, 6-oms工作台,参考 WorkspaceType枚举',
|
||||
admin_type varchar(15) default 'COMMON_ADMIN' not null comment '管理员类型, SUPER_ADMIN-超级管理员, COMMON_ADMIN-普通管理员',
|
||||
role_type varchar(20) default 'OTHER' not null comment '角色类型, ORGANIZATION_ADMIN-单位超管, ORG_WORKSPACE_ADMIN-项目内单位负责人, WORKSPACE_ADMIN-项目超管,OTHER-其他用户',
|
||||
data_source varchar(15) default 'USER_ENTRY' not null comment '数据来源, SYSTEM_ENTRY-系统录入, USER_ENTRY-用户手动录入',
|
||||
update_by bigint default 0 not null comment '更新人',
|
||||
update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
|
||||
create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间',
|
||||
create_by bigint default 0 not null comment '创建人',
|
||||
is_delete bigint default 0 not null comment '是否删除:0否,1是'
|
||||
);
|
||||
create index EXT_IDX_PROCESS_ADMIN_CONFIG_USER on ext_ax_process_admin (person_id,organizational_unit_id,workspace_id);
|
||||
43
workflow-engine-elasticsearch/pom.xml
Normal file
43
workflow-engine-elasticsearch/pom.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<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/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>workflow-engine</artifactId>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>workflow-engine-elasticsearch</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Workflow Engine ElasticSearch</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<artifactId>workflow-engine-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.data</groupId>
|
||||
<artifactId>axzo-data-mybatis-plus</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara.easy-es</groupId>
|
||||
<artifactId>easy-es-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.axzo.workflow.es.common.code;
|
||||
|
||||
import cn.axzo.framework.domain.web.code.IModuleRespCode;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* ES 相关操作响应码
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/12/14 16:25
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ElasticSearchRespCode implements IModuleRespCode {
|
||||
ES_SEARCH_ERROR("001", "ES 搜索时发生未知异常,信息: {}"),
|
||||
/**
|
||||
* 该异常的解决方式
|
||||
* PUT _cluster/settings
|
||||
* {
|
||||
* "transient": {
|
||||
* "search.allow_expensive_queries": "true"
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
ES_EXPENSIVE_QUERIES_NOT_SUPPORTED("002", "ES 集群设置不允许 expensive 查询."),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String message;
|
||||
|
||||
@Override
|
||||
public String getModuleCode() {
|
||||
return "13";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectCode() {
|
||||
return "998";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package cn.axzo.workflow.es.mapper;
|
||||
|
||||
import cn.axzo.workflow.es.model.ProcessInstanceDocument;
|
||||
import org.dromara.easyes.core.kernel.BaseEsMapper;
|
||||
|
||||
/**
|
||||
* 流程实例的 EsMapper
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-23 10:52
|
||||
*/
|
||||
public interface EsProcessInstanceMapper extends BaseEsMapper<ProcessInstanceDocument> {
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package cn.axzo.workflow.es.mapper;
|
||||
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import org.dromara.easyes.core.kernel.BaseEsMapper;
|
||||
|
||||
/**
|
||||
* 流程任务的 EsMapper
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-23 10:52
|
||||
*/
|
||||
public interface EsProcessTaskMapper extends BaseEsMapper<ProcessTaskDocument> {
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
package cn.axzo.workflow.es.model;
|
||||
|
||||
import cn.axzo.workflow.es.setting.CustomIndexSettingProvider;
|
||||
import lombok.Data;
|
||||
import org.dromara.easyes.annotation.IndexField;
|
||||
import org.dromara.easyes.annotation.IndexId;
|
||||
import org.dromara.easyes.annotation.IndexName;
|
||||
import org.dromara.easyes.annotation.Join;
|
||||
import org.dromara.easyes.annotation.Node;
|
||||
import org.dromara.easyes.annotation.Settings;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
import org.dromara.easyes.annotation.rely.IdType;
|
||||
import org.dromara.easyes.annotation.rely.RefreshPolicy;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static org.dromara.easyes.annotation.rely.Analyzer.IK_MAX_WORD;
|
||||
|
||||
/**
|
||||
* 流程实例文档模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-25 20:32
|
||||
*/
|
||||
@Data
|
||||
@Settings(settingsProvider = CustomIndexSettingProvider.class)
|
||||
@IndexName(value = "process_instance_document", keepGlobalPrefix = true, refreshPolicy = RefreshPolicy.IMMEDIATE)
|
||||
@Join(nodes = {@Node(parentClass = ProcessInstanceDocument.class, parentAlias = "process_instance_document", childClasses = {ProcessTaskDocument.class}, childAliases = {"process_task_document"})})
|
||||
public class ProcessInstanceDocument {
|
||||
|
||||
/**
|
||||
* 流程实例 ID
|
||||
*/
|
||||
@IndexId(type = IdType.CUSTOMIZE)
|
||||
private String id;
|
||||
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String instanceId;
|
||||
|
||||
/**
|
||||
* 流程实例名称
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = IK_MAX_WORD, searchAnalyzer = IK_MAX_WORD)
|
||||
private String processInstanceName;
|
||||
|
||||
/**
|
||||
* 业务传入业务信息
|
||||
*/
|
||||
private String businessKey;
|
||||
|
||||
/**
|
||||
* 流程实例使用的定义 ID
|
||||
*/
|
||||
private String processDefinitionId;
|
||||
|
||||
/**
|
||||
* 流程对应业务分类的类型,项目/单位/监管/OMS
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String processCategoryType;
|
||||
|
||||
/**
|
||||
* 流程实例的发起时间
|
||||
*/
|
||||
@IndexField(dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
|
||||
private Date instanceStartTime;
|
||||
|
||||
/**
|
||||
* 流程实例的结束时间
|
||||
*/
|
||||
@IndexField(dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
|
||||
private Date instanceEndTime;
|
||||
|
||||
/**
|
||||
* 流程实例的持续时间 ms
|
||||
*/
|
||||
private Long durationInMillis;
|
||||
|
||||
/**
|
||||
* 该流程中上次操作完成的时间, 如果是已完成的实例, 就清空该值
|
||||
*/
|
||||
@IndexField(dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
|
||||
private Date lastOperationTime;
|
||||
|
||||
/**
|
||||
* 租户 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String instanceTenantId;
|
||||
|
||||
/**
|
||||
* 流程实例业务状态
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String businessStatus;
|
||||
|
||||
/**
|
||||
* 发起人姓名
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String initiatorName;
|
||||
|
||||
/**
|
||||
* 实例对应的流程引擎服务端迭代版本
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String workflowEngineVersion;
|
||||
|
||||
/**
|
||||
* 是否代运营
|
||||
*/
|
||||
private Boolean agent;
|
||||
|
||||
/**
|
||||
* 是否支持批量操作任务
|
||||
*/
|
||||
private Boolean supportBatch;
|
||||
|
||||
/**
|
||||
* 是否开启同意操作时的签名
|
||||
*/
|
||||
private Boolean userAgreeSignature;
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
package cn.axzo.workflow.es.model;
|
||||
|
||||
import lombok.Data;
|
||||
import org.dromara.easyes.annotation.IndexField;
|
||||
import org.dromara.easyes.annotation.IndexId;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
import org.dromara.easyes.annotation.rely.IdType;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程任务文档模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-25 20:32
|
||||
*/
|
||||
@Data
|
||||
//@IndexName("process_task_document")
|
||||
public class ProcessTaskDocument {
|
||||
|
||||
/**
|
||||
* 任务 ID
|
||||
*/
|
||||
@IndexId(type = IdType.CUSTOMIZE)
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 任务归属的实例 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String processInstanceId;
|
||||
|
||||
/**
|
||||
* 任务定义 KEY,对应节点 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String taskDefinitionKey;
|
||||
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String taskName;
|
||||
|
||||
/**
|
||||
* 任务状态:审批中/通过/驳回/转交/加签...
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String taskStatus;
|
||||
|
||||
/**
|
||||
* 操作建议
|
||||
*/
|
||||
private String advice;
|
||||
|
||||
/**
|
||||
* 操作描述
|
||||
*/
|
||||
private String operationDesc;
|
||||
|
||||
/**
|
||||
* 流程实例的发起时间
|
||||
*/
|
||||
@IndexField(dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
|
||||
private Date taskStartTime;
|
||||
|
||||
/**
|
||||
* 流程实例的结束时间
|
||||
*/
|
||||
@IndexField(dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
|
||||
private Date taskEndTime;
|
||||
|
||||
/**
|
||||
* 流程实例的持续时间 ms
|
||||
*/
|
||||
private Long duration;
|
||||
|
||||
/**
|
||||
* 归属租户,与 processInstance#tenantId 一致
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String taskTenantId;
|
||||
|
||||
/**
|
||||
* 审批人姓名
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD_TEXT, analyzer = "ngram_analyzer", searchAnalyzer = "ngram_analyzer")
|
||||
private String assigneeName;
|
||||
|
||||
/**
|
||||
* 审批人自然人 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String assigneePersonId;
|
||||
|
||||
/**
|
||||
* 审批人所属单位 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String assigneeOuId;
|
||||
|
||||
/**
|
||||
* 审批人所属租户 ID
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String assigneeTenantId;
|
||||
|
||||
/**
|
||||
* 任务关联的附件(含文件,图片,签名)
|
||||
*/
|
||||
// @IndexField(fieldType = FieldType.NESTED, nestedClass = AttachmentDTO.class)
|
||||
// private List<AttachmentDTO> attachments;
|
||||
|
||||
/**
|
||||
* 审批方式:配置审批人/业务指定/业务触发(不含人)
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String approvalMethod;
|
||||
|
||||
/**
|
||||
* 节点类型:审批节点/业务节点/评论节点/抄送节点
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String nodeType;
|
||||
|
||||
/**
|
||||
* 节点模式:会签/或签
|
||||
*/
|
||||
@IndexField(fieldType = FieldType.KEYWORD)
|
||||
private String nodeMode;
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package cn.axzo.workflow.es.service;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.es.InstanceSearchReqDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.es.model.ProcessInstanceDocument;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 操作流程实例的 ES Service
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 11:06
|
||||
*/
|
||||
public interface EsProcessInstanceService {
|
||||
|
||||
/**
|
||||
* 创建索引
|
||||
* <p>
|
||||
* 由于采用的是父子文档, 所以该接口会一并创建
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Boolean createIndex();
|
||||
|
||||
/**
|
||||
* 删除流程实例索引
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Boolean deleteIndex();
|
||||
|
||||
/**
|
||||
* 新增流程实例文档
|
||||
*
|
||||
* @param processInstanceDocument
|
||||
* @return 成功的条数
|
||||
*/
|
||||
Integer insert(String routing, ProcessInstanceDocument processInstanceDocument);
|
||||
|
||||
/**
|
||||
* 批量新增流程实例文档
|
||||
*
|
||||
* @param processInstanceDocuments
|
||||
* @return
|
||||
*/
|
||||
Integer insertBatch(String routing, Collection<ProcessInstanceDocument> processInstanceDocuments);
|
||||
|
||||
/**
|
||||
* 更新流程实例文档
|
||||
*
|
||||
* @param routing
|
||||
* @param processInstanceDocument
|
||||
*/
|
||||
Integer update(String routing, ProcessInstanceDocument processInstanceDocument);
|
||||
|
||||
/**
|
||||
* 删除指定文档
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
Integer delete(String processInstanceId);
|
||||
|
||||
BpmPageResult<ProcessInstanceDocument> search(InstanceSearchReqDTO dto);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package cn.axzo.workflow.es.service;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.es.TaskSearchReqDTO;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 操作流程任务的 ES Service
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 11:07
|
||||
*/
|
||||
public interface EsProcessTaskService {
|
||||
|
||||
/**
|
||||
* 删除流程实例索引
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Boolean deleteIndex();
|
||||
|
||||
/**
|
||||
* 新增子文档(重复调用等于更新)
|
||||
*
|
||||
* @param routing
|
||||
* @param parentId
|
||||
* @param processTaskDocument
|
||||
* @return
|
||||
*/
|
||||
Integer insert(String routing, String parentId, ProcessTaskDocument processTaskDocument);
|
||||
|
||||
/**
|
||||
* 批量新增子文档(重复调用等于更新)
|
||||
*
|
||||
* @param routing
|
||||
* @param parentId
|
||||
* @param processTaskDocuments
|
||||
* @return
|
||||
*/
|
||||
Integer insertBatch(String routing, String parentId, Collection<ProcessTaskDocument> processTaskDocuments);
|
||||
|
||||
List<ProcessTaskDocument> search(TaskSearchReqDTO dto);
|
||||
|
||||
Integer delete(String routing, String processInstanceId);
|
||||
}
|
||||
@ -0,0 +1,165 @@
|
||||
package cn.axzo.workflow.es.service.aggregation;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.workflow.common.enums.WorkspaceType;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.common.model.request.es.InstanceSearchReqDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.es.ProcessInstanceDocumentVO;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceForEsService;
|
||||
import cn.axzo.workflow.es.model.ProcessInstanceDocument;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.EsProcessInstanceService;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ES_FIXED_ROUTING;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_142;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_AGENT;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_PROCESS_WORKSPACE_TYPE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_INTERNAL_INITIATOR;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.WORKFLOW_ENGINE_VERSION;
|
||||
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;
|
||||
|
||||
/**
|
||||
* 实例纬度的聚合操作
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-30 11:46
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class AggregateProcessInstanceService {
|
||||
private final BpmnProcessInstanceForEsService bpmnProcessInstanceForEsService;
|
||||
private final EsProcessInstanceService esProcessInstanceService;
|
||||
private final AggregateProcessTaskService aggregateProcessTaskService;
|
||||
|
||||
/**
|
||||
* 同步结束审批的数据至 ES
|
||||
*/
|
||||
public List<ProcessTaskDocument> syncProcessInstance(HistoricProcessInstance hpi, Function<List<BpmnTaskDelegateAssigner>, Map<Long, BpmnTaskDelegateAssigner>> function) {
|
||||
if (Objects.isNull(hpi)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ProcessInstanceDocument processInstanceDocument = new ProcessInstanceDocument();
|
||||
processInstanceDocument.setId(hpi.getId());
|
||||
processInstanceDocument.setInstanceId(hpi.getId());
|
||||
processInstanceDocument.setProcessInstanceName(hpi.getName());
|
||||
processInstanceDocument.setBusinessKey(hpi.getBusinessKey());
|
||||
processInstanceDocument.setProcessDefinitionId(hpi.getProcessDefinitionId());
|
||||
processInstanceDocument.setInstanceStartTime(hpi.getStartTime());
|
||||
processInstanceDocument.setInstanceEndTime(hpi.getEndTime());
|
||||
processInstanceDocument.setDurationInMillis(hpi.getDurationInMillis());
|
||||
processInstanceDocument.setInstanceTenantId(hpi.getTenantId());
|
||||
processInstanceDocument.setBusinessStatus(hpi.getBusinessStatus());
|
||||
|
||||
Map<String, Object> variables = hpi.getProcessVariables();
|
||||
if (CollectionUtils.isEmpty(variables)) {
|
||||
variables.putAll(bpmnProcessInstanceForEsService.queryInstanceVariables(hpi.getId(),
|
||||
Lists.newArrayList(WORKFLOW_ENGINE_VERSION, INTERNAL_PROCESS_WORKSPACE_TYPE, INTERNAL_PROCESS_AGENT, INTERNAL_INITIATOR, OLD_INTERNAL_INITIATOR)));
|
||||
}
|
||||
|
||||
BpmnTaskDelegateAssigner initiator = BpmnTaskDelegateAssigner.toObjectCompatible(variables.getOrDefault(INTERNAL_INITIATOR, variables.getOrDefault(OLD_INTERNAL_INITIATOR, null)));
|
||||
if (Objects.nonNull(initiator)) {
|
||||
BpmnTaskDelegateAssigner fullAssigner = null;
|
||||
if (Objects.nonNull(function) && !StringUtils.hasText(initiator.getAssignerName()) && NumberUtil.isNumber(initiator.getPersonId())) {
|
||||
fullAssigner = function.apply(Lists.newArrayList(initiator)).getOrDefault(Long.parseLong(initiator.getPersonId()), null);
|
||||
}
|
||||
processInstanceDocument.setInitiatorName(Objects.nonNull(fullAssigner) ? fullAssigner.getAssignerName() : StringUtils.hasText(initiator.getAssignerName()) ? initiator.getAssignerName() : "未知");
|
||||
}
|
||||
processInstanceDocument.setWorkflowEngineVersion(String.valueOf(variables.getOrDefault(WORKFLOW_ENGINE_VERSION, FLOW_SERVER_VERSION_121)));
|
||||
processInstanceDocument.setProcessCategoryType(WorkspaceType.getType((Integer) variables.getOrDefault(INTERNAL_PROCESS_WORKSPACE_TYPE, WorkspaceType.UN_KNOW.getCode())).getDesc());
|
||||
processInstanceDocument.setAgent((Boolean) variables.getOrDefault(INTERNAL_PROCESS_AGENT, false));
|
||||
|
||||
BpmnModel bpmnModel = bpmnProcessInstanceForEsService.queryBpmnModel(hpi.getProcessDefinitionId());
|
||||
BpmnMetaParserHelper.getProcessApproveConf(bpmnModel.getMainProcess()).ifPresent(cfg -> {
|
||||
processInstanceDocument.setSupportBatch(cfg.getSupportBatchOperation());
|
||||
processInstanceDocument.setUserAgreeSignature(cfg.getUserAgreeSignature());
|
||||
});
|
||||
|
||||
// 实例纬度数据同步 ES
|
||||
esProcessInstanceService.insert(ES_FIXED_ROUTING, processInstanceDocument);
|
||||
|
||||
String instanceVersion = String.valueOf(variables.getOrDefault(WORKFLOW_ENGINE_VERSION, FLOW_SERVER_VERSION_121))
|
||||
.replaceAll("-SNAPSHOT","")
|
||||
.replaceAll("-RELEASE", "");
|
||||
DefaultArtifactVersion version = new DefaultArtifactVersion(instanceVersion);
|
||||
DefaultArtifactVersion supportVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_142);
|
||||
List<ProcessTaskDocument> toEsProcessTaskDocuments = new ArrayList<>();
|
||||
if (version.compareTo(supportVersion) >= 0) {
|
||||
log.info("通过新日志表进行任务纬度的数据同步");
|
||||
// 用新日志表数据任务同步
|
||||
toEsProcessTaskDocuments.addAll(aggregateProcessTaskService.syncProcessTaskForNew(hpi, instanceVersion));
|
||||
} else {
|
||||
log.info("通过引擎的任务表进行任务纬度的数据同步");
|
||||
// 用引擎的任务表处理任务同步
|
||||
toEsProcessTaskDocuments.addAll(aggregateProcessTaskService.syncProcessTaskForOld(hpi, instanceVersion, bpmnModel, function));
|
||||
}
|
||||
|
||||
//更新实例上的最后操作时间
|
||||
if (Objects.equals(PROCESSING.getStatus(), hpi.getBusinessStatus())) {
|
||||
toEsProcessTaskDocuments.stream()
|
||||
.filter(i -> StringUtils.hasText(i.getTaskStatus()) && !Objects.equals(i.getTaskStatus(), PROCESSING.getStatus()))
|
||||
.filter(i -> Objects.nonNull(i.getTaskEndTime()))
|
||||
.max(Comparator.comparing(ProcessTaskDocument::getTaskEndTime))
|
||||
.ifPresent(processTaskDocument -> {
|
||||
processInstanceDocument.setLastOperationTime(processTaskDocument.getTaskEndTime());
|
||||
});
|
||||
} else {
|
||||
processInstanceDocument.setLastOperationTime(null);
|
||||
}
|
||||
|
||||
// 更新实例维度的 LastOperationTime 字段为 null
|
||||
esProcessInstanceService.update(ES_FIXED_ROUTING, processInstanceDocument);
|
||||
return toEsProcessTaskDocuments;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 ES 中搜索数据, 并转换响应模型
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
public BpmPageResult<ProcessInstanceDocumentVO> search(InstanceSearchReqDTO dto) {
|
||||
BpmPageResult<ProcessInstanceDocument> searchResult = esProcessInstanceService.search(dto);
|
||||
List<ProcessInstanceDocumentVO> vos = BeanMapper.copyList(searchResult.getList(), ProcessInstanceDocumentVO.class);
|
||||
return new BpmPageResult<>(vos, searchResult.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定流程实例的父子文档
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
public Boolean deleteDocumentParentAndChild(String processInstanceId) {
|
||||
try {
|
||||
esProcessInstanceService.delete(processInstanceId);
|
||||
aggregateProcessTaskService.deleteByParentId(processInstanceId);
|
||||
} catch (Exception e) {
|
||||
log.warn("删除文档失败:{}", e.getMessage(), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,254 @@
|
||||
package cn.axzo.workflow.es.service.aggregation;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.common.model.request.es.TaskSearchReqDTO;
|
||||
import cn.axzo.workflow.common.model.response.es.ProcessTaskDocumentVO;
|
||||
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxHiTaskInst;
|
||||
import cn.axzo.workflow.core.repository.entity.ExtAxProcessLog;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceForEsService;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessTaskForEsService;
|
||||
import cn.axzo.workflow.core.service.converter.BpmnHistoricAttachmentConverter;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.EsProcessTaskService;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.impl.persistence.entity.CommentEntityImpl;
|
||||
import org.flowable.engine.task.Comment;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ES_FIXED_ROUTING;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_130;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_142;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.HIDDEN_ASSIGNEE_ID;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_INFO;
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.OLD_TASK_ASSIGNEE_SKIP_FLAT;
|
||||
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_CARBON_COPY;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.MI_END;
|
||||
import static cn.axzo.workflow.core.common.enums.BpmnProcessTaskResultEnum.REJECTION_AUTO_COMPLETED;
|
||||
|
||||
/**
|
||||
* 任务纬度的聚合操作
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-30 11:46
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class AggregateProcessTaskService {
|
||||
private final static DefaultArtifactVersion SUPPORT_VERSION = new DefaultArtifactVersion(FLOW_SERVER_VERSION_142);
|
||||
private final EsProcessTaskService esProcessTaskService;
|
||||
private final BpmnProcessInstanceForEsService bpmnProcessInstanceForEsService;
|
||||
private final BpmnProcessTaskForEsService bpmnProcessTaskForEsService;
|
||||
private final BpmnHistoricAttachmentConverter attachmentConverter;
|
||||
|
||||
/**
|
||||
* 通过新的日志表进行任务纬度的数据同步至 ES
|
||||
*/
|
||||
public List<ProcessTaskDocument> syncProcessTaskForNew(HistoricProcessInstance hpi, String instanceVersion) {
|
||||
DefaultArtifactVersion currentVersion = new DefaultArtifactVersion(instanceVersion);
|
||||
if (currentVersion.compareTo(SUPPORT_VERSION) < 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ExtAxProcessLog> logs = bpmnProcessTaskForEsService.queryProcessLogByProcessInstanceId(hpi.getId());
|
||||
// Map<String, List<Attachment>> attachmentMap = bpmnProcessTaskForEsService.queryAttachmentByProcessInstanceId(hpi.getId())
|
||||
// .stream().collect(Collectors.groupingBy(Attachment::getTaskId, Collectors.mapping(Function.identity(), Collectors.toList())));
|
||||
|
||||
List<ProcessTaskDocument> toEsProcessTaskDocuments = new ArrayList<>();
|
||||
logs.stream()
|
||||
.filter(i -> !Objects.equals(NODE_CARBON_COPY.getType(), i.getNodeType()))
|
||||
.forEach(log -> {
|
||||
ProcessTaskDocument processTaskDocument = new ProcessTaskDocument();
|
||||
processTaskDocument.setTaskId(log.getTaskId());
|
||||
processTaskDocument.setProcessInstanceId(hpi.getId());
|
||||
processTaskDocument.setTaskDefinitionKey(log.getActivityId());
|
||||
processTaskDocument.setTaskName(log.getActivityName());
|
||||
processTaskDocument.setTaskStatus(log.getStatus());
|
||||
processTaskDocument.setAdvice(log.getAdvice());
|
||||
processTaskDocument.setOperationDesc(log.getOperationDesc());
|
||||
processTaskDocument.setTaskStartTime(log.getStartTime());
|
||||
processTaskDocument.setTaskEndTime(log.getEndTime());
|
||||
if (Objects.nonNull(log.getEndTime())) {
|
||||
processTaskDocument.setDuration(DateUtil.betweenMs(log.getEndTime(), log.getStartTime()));
|
||||
}
|
||||
processTaskDocument.setTaskTenantId(log.getTenantId());
|
||||
BpmnTaskDelegateAssigner assigner = CollectionUtils.isEmpty(log.getAssigneeFull()) ? null : log.getAssigneeFull().get(0);
|
||||
if (Objects.nonNull(assigner)) {
|
||||
processTaskDocument.setAssigneeName(assigner.getAssignerName());
|
||||
processTaskDocument.setAssigneeOuId(assigner.getOuId());
|
||||
processTaskDocument.setAssigneePersonId(assigner.getPersonId());
|
||||
processTaskDocument.setAssigneeTenantId(assigner.getTenantId());
|
||||
}
|
||||
// esProcessTask.setAttachments(attachmentConverter.toVos(attachmentMap.getOrDefault(log.getTaskId(), Collections.emptyList())));
|
||||
processTaskDocument.setApprovalMethod(log.getApprovalMethod());
|
||||
processTaskDocument.setNodeType(log.getNodeType());
|
||||
processTaskDocument.setNodeMode(log.getNodeMode());
|
||||
toEsProcessTaskDocuments.add(processTaskDocument);
|
||||
});
|
||||
|
||||
esProcessTaskService.insertBatch(ES_FIXED_ROUTING, hpi.getId(), toEsProcessTaskDocuments);
|
||||
return toEsProcessTaskDocuments;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先使用三个参数的同步方法.
|
||||
* <p>
|
||||
* 通过原本引擎表进行任务纬度的数据同步至 ES
|
||||
*/
|
||||
public List<ProcessTaskDocument> syncProcessTaskForOld(HistoricProcessInstance hpi, String instanceVersion) {
|
||||
BpmnModel bpmnModel = bpmnProcessInstanceForEsService.queryBpmnModel(hpi.getProcessDefinitionId());
|
||||
return syncProcessTaskForOld(hpi, instanceVersion, bpmnModel, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过原本引擎表进行任务纬度的数据同步至 ES
|
||||
*
|
||||
* @param hpi
|
||||
* @param instanceVersion
|
||||
* @param bpmnModel
|
||||
* @param function
|
||||
*/
|
||||
public List<ProcessTaskDocument> syncProcessTaskForOld(HistoricProcessInstance hpi, String instanceVersion,
|
||||
BpmnModel bpmnModel,
|
||||
Function<List<BpmnTaskDelegateAssigner>, Map<Long, BpmnTaskDelegateAssigner>> function) {
|
||||
|
||||
List<HistoricTaskInstance> tasks = bpmnProcessTaskForEsService.queryHistoricProcessTaskByProcessInstanceId(hpi.getId());
|
||||
|
||||
Map<String, ExtAxHiTaskInst> extTaskMap = bpmnProcessTaskForEsService.queryExtAxHiTaskInstByProcessInstanceId(hpi.getId())
|
||||
.stream().collect(Collectors.toMap(ExtAxHiTaskInst::getTaskId, Function.identity(), (s, t) -> s));
|
||||
|
||||
Map<String, List<Comment>> commentMap = bpmnProcessTaskForEsService.queryCommentByProcessInstanceId(hpi.getId())
|
||||
.stream().collect(Collectors.groupingBy(Comment::getTaskId, Collectors.mapping(Function.identity(), Collectors.toList())));
|
||||
|
||||
// 父子文档中子文档不支持 Nested 类型字段
|
||||
// Map<String, List<Attachment>> attachmentMap = bpmnProcessTaskForEsService.queryAttachmentByProcessInstanceId(hpi.getId())
|
||||
// .stream().collect(Collectors.groupingBy(Attachment::getTaskId, Collectors.mapping(Function.identity(), Collectors.toList())));
|
||||
|
||||
// 过滤出有效任务, 比如同节点的多实例下或签, 一个人操作了同节点的一个任务,会把同节点的其他任务处理了,此时被处理的任务认为非人工处理
|
||||
List<HistoricTaskInstance> filteredEffectiveTasks = filterEffectiveTasks(tasks, instanceVersion);
|
||||
|
||||
List<String> taskIds = filteredEffectiveTasks.stream().map(i -> INTERNAL_TASK_RELATION_ASSIGNEE_INFO + i.getId()).distinct().collect(Collectors.toList());
|
||||
Map<String, Object> taskAssigneeMap = bpmnProcessInstanceForEsService.queryInstanceVariables(hpi.getId(), taskIds);
|
||||
|
||||
List<ProcessTaskDocument> toEsProcessTaskDocuments = new ArrayList<>();
|
||||
for (HistoricTaskInstance task : filteredEffectiveTasks) {
|
||||
ExtAxHiTaskInst extTask = extTaskMap.getOrDefault(task.getId(), new ExtAxHiTaskInst());
|
||||
List<Comment> comments = commentMap.getOrDefault(task.getId(), Collections.emptyList());
|
||||
// List<Attachment> attachments = attachmentMap.getOrDefault(task.getId(), Collections.emptyList());
|
||||
|
||||
ProcessTaskDocument processTaskDocument = new ProcessTaskDocument();
|
||||
processTaskDocument.setTaskId(task.getId());
|
||||
processTaskDocument.setProcessInstanceId(hpi.getId());
|
||||
processTaskDocument.setTaskDefinitionKey(task.getTaskDefinitionKey());
|
||||
processTaskDocument.setTaskName(task.getName());
|
||||
processTaskDocument.setTaskStatus(extTask.getStatus());
|
||||
// 处理 advice
|
||||
processTaskDocument.setAdvice(comments.stream().filter(i -> Objects.equals(i.getType(), COMMENT_TYPE_ADVICE))
|
||||
.findFirst().orElse(new CommentEntityImpl()).getFullMessage());
|
||||
// 处理 operationDesc
|
||||
processTaskDocument.setOperationDesc(comments.stream().filter(i -> Objects.equals(COMMENT_TYPE_OPERATION_DESC, i.getType()))
|
||||
.max(Comparator.comparing(Comment::getTime))
|
||||
.orElse(new CommentEntityImpl()).getFullMessage());
|
||||
processTaskDocument.setTaskStartTime(task.getCreateTime());
|
||||
processTaskDocument.setTaskEndTime(task.getEndTime());
|
||||
processTaskDocument.setDuration(task.getDurationInMillis());
|
||||
processTaskDocument.setTaskTenantId(task.getTenantId());
|
||||
BpmnTaskDelegateAssigner assigner = BpmnTaskDelegateAssigner.toObjectCompatible(taskAssigneeMap.getOrDefault(INTERNAL_TASK_RELATION_ASSIGNEE_INFO + task.getId(), null));
|
||||
if (Objects.nonNull(assigner)) {
|
||||
BpmnTaskDelegateAssigner fullAssigner = null;
|
||||
if (Objects.nonNull(function) && !StringUtils.hasText(assigner.getAssignerName()) && NumberUtil.isNumber(assigner.getPersonId())) {
|
||||
fullAssigner = function.apply(Lists.newArrayList(assigner)).getOrDefault(Long.parseLong(assigner.getPersonId()), null);
|
||||
}
|
||||
processTaskDocument.setAssigneeName(Objects.nonNull(fullAssigner) ? fullAssigner.getAssignerName() : StringUtils.hasText(assigner.getAssignerName()) ? assigner.getAssignerName() : "未知");
|
||||
processTaskDocument.setAssigneeOuId(assigner.getOuId());
|
||||
processTaskDocument.setAssigneePersonId(assigner.getPersonId());
|
||||
processTaskDocument.setAssigneeTenantId(assigner.getTenantId());
|
||||
}
|
||||
if (Objects.nonNull(bpmnModel)) {
|
||||
FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
|
||||
BpmnMetaParserHelper.getApprovalMethod(flowElement)
|
||||
.ifPresent(e -> processTaskDocument.setApprovalMethod(e.getType()));
|
||||
BpmnMetaParserHelper.getNodeType(flowElement)
|
||||
.ifPresent(e -> processTaskDocument.setNodeType(e.getType()));
|
||||
}
|
||||
if (!Objects.equals(processTaskDocument.getNodeType(), NODE_CARBON_COPY.getType())) {
|
||||
toEsProcessTaskDocuments.add(processTaskDocument);
|
||||
}
|
||||
}
|
||||
esProcessTaskService.insertBatch(ES_FIXED_ROUTING, hpi.getId(), toEsProcessTaskDocuments);
|
||||
return toEsProcessTaskDocuments;
|
||||
}
|
||||
|
||||
private List<HistoricTaskInstance> filterEffectiveTasks(List<HistoricTaskInstance> tasks, String instanceVersion) {
|
||||
List<HistoricTaskInstance> effectiveTasks = new ArrayList<>();
|
||||
if (CollectionUtils.isEmpty(tasks)) {
|
||||
return effectiveTasks;
|
||||
}
|
||||
Stream<HistoricTaskInstance> taskInstanceStream = tasks.stream()
|
||||
.filter(i -> !Objects.equals(i.getAssignee(), HIDDEN_ASSIGNEE_ID))
|
||||
.filter(i -> !Objects.equals(i.getDeleteReason(), HIDDEN_ASSIGNEE_ID))
|
||||
.filter(i -> !Objects.equals(i.getDeleteReason(), MI_END.getStatus()));
|
||||
if (Objects.isNull(instanceVersion)) {
|
||||
compatibleVersion(taskInstanceStream).forEach(effectiveTasks::add);
|
||||
} else {
|
||||
if (StringUtils.hasText(instanceVersion)) {
|
||||
DefaultArtifactVersion version = new DefaultArtifactVersion(instanceVersion);
|
||||
DefaultArtifactVersion supportVersion = new DefaultArtifactVersion(FLOW_SERVER_VERSION_130);
|
||||
if (version.compareTo(supportVersion) < 0) {
|
||||
compatibleVersion(taskInstanceStream).forEach(effectiveTasks::add);
|
||||
} else {
|
||||
taskInstanceStream.forEach(effectiveTasks::add);
|
||||
}
|
||||
} else {
|
||||
taskInstanceStream.forEach(effectiveTasks::add);
|
||||
}
|
||||
}
|
||||
return effectiveTasks;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 兼容 1.2.1 版本的审批日志
|
||||
*
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
private Stream<HistoricTaskInstance> compatibleVersion(Stream<HistoricTaskInstance> stream) {
|
||||
return stream.filter(i -> (!Objects.equals(REJECTION_AUTO_COMPLETED.getDesc(), i.getDeleteReason()))
|
||||
|| (Objects.equals(i.getAssignee(), OLD_TASK_ASSIGNEE_SKIP_FLAT) && Objects.equals(REJECTION_AUTO_COMPLETED.getDesc(), i.getDeleteReason()))
|
||||
).filter(i -> !(!Objects.equals(i.getAssignee(), OLD_TASK_ASSIGNEE_SKIP_FLAT) && Objects.equals(MI_END.getStatus(), i.getDeleteReason())));
|
||||
}
|
||||
|
||||
public List<ProcessTaskDocumentVO> search(TaskSearchReqDTO dto) {
|
||||
return BeanMapper.copyList(esProcessTaskService.search(dto), ProcessTaskDocumentVO.class);
|
||||
}
|
||||
|
||||
public Integer deleteByParentId(String processInstanceId) {
|
||||
return esProcessTaskService.delete(ES_FIXED_ROUTING, processInstanceId);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,157 @@
|
||||
package cn.axzo.workflow.es.service.impl;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.es.InstanceSearchReqDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
|
||||
import cn.axzo.workflow.es.mapper.EsProcessInstanceMapper;
|
||||
import cn.axzo.workflow.es.model.ProcessInstanceDocument;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.EsProcessInstanceService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.easyes.annotation.IndexName;
|
||||
import org.dromara.easyes.core.biz.EsPageInfo;
|
||||
import org.dromara.easyes.core.cache.GlobalConfigCache;
|
||||
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
|
||||
import org.dromara.easyes.core.config.GlobalConfig;
|
||||
import org.dromara.easyes.core.toolkit.FieldUtils;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ES_FIXED_ROUTING;
|
||||
import static cn.axzo.workflow.es.common.code.ElasticSearchRespCode.ES_EXPENSIVE_QUERIES_NOT_SUPPORTED;
|
||||
import static cn.axzo.workflow.es.common.code.ElasticSearchRespCode.ES_SEARCH_ERROR;
|
||||
|
||||
/**
|
||||
* 操作流程实例的 ES Service 实现
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 11:09
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class EsProcessInstanceServiceImpl implements EsProcessInstanceService {
|
||||
|
||||
private final EsProcessInstanceMapper esProcessInstanceMapper;
|
||||
|
||||
/**
|
||||
* 创建索引
|
||||
* <p>
|
||||
* 由于采用的是父子文档, 所以该接口会一并创建
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean createIndex() {
|
||||
IndexName annotation = AnnotationUtils.findAnnotation(ProcessInstanceDocument.class, IndexName.class);
|
||||
if (esProcessInstanceMapper.existsIndex(annotation.value())) {
|
||||
return false;
|
||||
}
|
||||
return esProcessInstanceMapper.createIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程实例索引
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteIndex() {
|
||||
GlobalConfig globalConfig = GlobalConfigCache.getGlobalConfig();
|
||||
IndexName annotation = AnnotationUtils.findAnnotation(ProcessInstanceDocument.class, IndexName.class);
|
||||
return esProcessInstanceMapper.deleteIndex(globalConfig.getDbConfig().getIndexPrefix() + annotation.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程实例文档文档
|
||||
*
|
||||
* @param processInstanceDocument
|
||||
* @return 成功的条数
|
||||
*/
|
||||
@Override
|
||||
public Integer insert(String routing, ProcessInstanceDocument processInstanceDocument) {
|
||||
return esProcessInstanceMapper.insert(routing, processInstanceDocument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer insertBatch(String routing, Collection<ProcessInstanceDocument> processInstanceDocuments) {
|
||||
return esProcessInstanceMapper.insertBatch(routing, processInstanceDocuments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新流程实例文档
|
||||
*
|
||||
* @param routing
|
||||
* @param processInstanceDocument
|
||||
*/
|
||||
@Override
|
||||
public Integer update(String routing, ProcessInstanceDocument processInstanceDocument) {
|
||||
return esProcessInstanceMapper.updateById(ES_FIXED_ROUTING, processInstanceDocument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer delete(String processInstanceId) {
|
||||
return esProcessInstanceMapper.deleteById(ES_FIXED_ROUTING, processInstanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BpmPageResult<ProcessInstanceDocument> search(InstanceSearchReqDTO dto) {
|
||||
if (!CollectionUtils.isEmpty(dto.getProcessInstanceIds())) {
|
||||
List<ProcessInstanceDocument> processInstanceDocuments = esProcessInstanceMapper
|
||||
.selectList(new LambdaEsQueryWrapper<ProcessInstanceDocument>()
|
||||
.in(FieldUtils.val(ProcessInstanceDocument::getId), dto.getProcessInstanceIds()));
|
||||
return new BpmPageResult<>(processInstanceDocuments, (long) processInstanceDocuments.size());
|
||||
}
|
||||
|
||||
LambdaEsQueryWrapper<ProcessInstanceDocument> wrapper = new LambdaEsQueryWrapper<>();
|
||||
wrapper.hasChild("process_task_document",
|
||||
w -> w.matchPhrase(StringUtils.hasText(dto.getAssigneeName()), FieldUtils.val(ProcessTaskDocument::getAssigneeName), dto.getAssigneeName())
|
||||
.eq(StringUtils.hasText(dto.getTenantId()), FieldUtils.val(ProcessTaskDocument::getAssigneeTenantId), dto.getTenantId())
|
||||
.eq(StringUtils.hasText(dto.getOuId()), FieldUtils.val(ProcessTaskDocument::getAssigneeOuId), dto.getOuId())
|
||||
.eq(StringUtils.hasText(dto.getPersonId()), FieldUtils.val(ProcessTaskDocument::getAssigneePersonId), dto.getPersonId())
|
||||
)
|
||||
.eq(StringUtils.hasText(dto.getBusinessStatus()), FieldUtils.val(ProcessInstanceDocument::getBusinessStatus), dto.getBusinessStatus())
|
||||
.and(StringUtils.hasText(dto.getProcessInstanceName()),
|
||||
w -> w.or(i -> i.eq(FieldUtils.val(ProcessInstanceDocument::getProcessInstanceName), dto.getProcessInstanceName(), 1.2F))
|
||||
.or(j->j.match(FieldUtils.val(ProcessInstanceDocument::getProcessInstanceName), dto.getProcessInstanceName()))
|
||||
)
|
||||
.in(CollectionUtils.isEmpty(dto.getProcessInstanceIds()), FieldUtils.val(ProcessInstanceDocument::getId), dto.getProcessInstanceIds())
|
||||
.ge(Objects.nonNull(dto.getBeginStartTime()), ProcessInstanceDocument::getInstanceStartTime, dto.getBeginStartTime())
|
||||
.le(Objects.nonNull(dto.getOverStartTime()), ProcessInstanceDocument::getInstanceStartTime, dto.getOverStartTime())
|
||||
.ge(Objects.nonNull(dto.getBeginEndTime()), ProcessInstanceDocument::getInstanceEndTime, dto.getBeginEndTime())
|
||||
.le(Objects.nonNull(dto.getOverEndTime()), ProcessInstanceDocument::getInstanceEndTime, dto.getOverEndTime())
|
||||
.sortByScore()
|
||||
.orderByDesc(FieldUtils.val(ProcessInstanceDocument::getInstanceStartTime))
|
||||
.trackScores()
|
||||
.routing(ES_FIXED_ROUTING)
|
||||
;
|
||||
EsPageInfo<ProcessInstanceDocument> pageInfo;
|
||||
try {
|
||||
pageInfo = esProcessInstanceMapper.pageQuery(wrapper, dto.getPageNo(), dto.getPageSize());
|
||||
} catch (Exception e) {
|
||||
Throwable rootCause = getRootCause(e);
|
||||
if (rootCause instanceof ElasticsearchException && rootCause.getMessage().contains("search.allow_expensive_queries")) {
|
||||
// 该问题涉及到集群参数调整,调整方法参考异常 CODE 中的说明
|
||||
throw new WorkflowEngineException(ES_EXPENSIVE_QUERIES_NOT_SUPPORTED);
|
||||
}
|
||||
log.warn("ES 搜索时发生异常:{}", e.getMessage(), e);
|
||||
throw new WorkflowEngineException(ES_SEARCH_ERROR, e.getMessage());
|
||||
}
|
||||
return new BpmPageResult<>(pageInfo.getList(), pageInfo.getTotal());
|
||||
}
|
||||
|
||||
private Throwable getRootCause(Throwable throwable) {
|
||||
if (Objects.nonNull(throwable) && Objects.nonNull(throwable.getCause())) {
|
||||
return getRootCause(throwable.getCause());
|
||||
}
|
||||
return throwable;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
package cn.axzo.workflow.es.service.impl;
|
||||
|
||||
import cn.axzo.workflow.common.model.request.es.TaskSearchReqDTO;
|
||||
import cn.axzo.workflow.es.mapper.EsProcessTaskMapper;
|
||||
import cn.axzo.workflow.es.model.ProcessInstanceDocument;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.EsProcessTaskService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.easyes.annotation.IndexName;
|
||||
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
|
||||
import org.dromara.easyes.core.toolkit.FieldUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.ES_FIXED_ROUTING;
|
||||
|
||||
/**
|
||||
* 操作流程任务的 ES Service 实现
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 11:09
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class EsProcessTaskServiceImpl implements EsProcessTaskService {
|
||||
|
||||
private final EsProcessTaskMapper esProcessTaskMapper;
|
||||
|
||||
/**
|
||||
* 删除流程实例索引
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteIndex() {
|
||||
IndexName annotation = AnnotationUtils.findAnnotation(ProcessTaskDocument.class, IndexName.class);
|
||||
return esProcessTaskMapper.deleteIndex(annotation.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增流程实例文档文档
|
||||
*
|
||||
* @param processTaskDocument
|
||||
* @return 成功的条数
|
||||
*/
|
||||
public Integer insert(String routing, String parentId, ProcessTaskDocument processTaskDocument) {
|
||||
return esProcessTaskMapper.insert(routing, parentId, processTaskDocument);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer insertBatch(String routing, String parentId, Collection<ProcessTaskDocument> processTaskDocuments) {
|
||||
return esProcessTaskMapper.insertBatch(routing, parentId, processTaskDocuments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProcessTaskDocument> search(TaskSearchReqDTO dto) {
|
||||
LambdaEsQueryWrapper<ProcessTaskDocument> wrapper = new LambdaEsQueryWrapper<ProcessTaskDocument>()
|
||||
.eq(StringUtils.hasText(dto.getAssigneeOuId()), ProcessTaskDocument::getAssigneeOuId, dto.getAssigneeOuId())
|
||||
.eq(StringUtils.hasText(dto.getAssigneeTenantId()), ProcessTaskDocument::getAssigneeTenantId, dto.getAssigneeTenantId())
|
||||
.eq(StringUtils.hasText(dto.getAssigneePersonId()), ProcessTaskDocument::getAssigneePersonId, dto.getAssigneePersonId())
|
||||
.matchPhrase(StringUtils.hasText(dto.getAssigneeName()), ProcessTaskDocument::getAssigneeName, dto.getAssigneeName())
|
||||
.hasParent(StringUtils.hasText(dto.getProcessInstanceId()), "process_instance_document",
|
||||
w-> w.eq(FieldUtils.val(ProcessInstanceDocument::getInstanceId), dto.getProcessInstanceId()))
|
||||
// .parentId(StringUtils.hasText(dto.getProcessInstanceId()), dto.getProcessInstanceId(), "process_instance_document")
|
||||
.routing(ES_FIXED_ROUTING)
|
||||
;
|
||||
return esProcessTaskMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer delete(String routing, String processInstanceId) {
|
||||
LambdaEsQueryWrapper<ProcessTaskDocument> wrapper = new LambdaEsQueryWrapper<ProcessTaskDocument>()
|
||||
.eq(FieldUtils.val(ProcessTaskDocument::getProcessInstanceId), processInstanceId)
|
||||
.routing(ES_FIXED_ROUTING);
|
||||
return esProcessTaskMapper.delete(wrapper);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package cn.axzo.workflow.es.setting;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.dromara.easyes.annotation.rely.DefaultSettingsProvider;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 对索引这是自定义的 Settings
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-12 10:00
|
||||
*/
|
||||
public class CustomIndexSettingProvider extends DefaultSettingsProvider {
|
||||
@Override
|
||||
public Map<String, Object> getSettings() {
|
||||
Map<String, Object> settings = new HashMap<>();
|
||||
settings.put("analysis.analyzer.ngram_analyzer.tokenizer", "ngram_tokenizer");
|
||||
settings.put("analysis.tokenizer.ngram_tokenizer.token_chars", Lists.newArrayList("letter", "digit"));
|
||||
settings.put("analysis.tokenizer.ngram_tokenizer.type", "ngram");
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,20 @@
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-web-spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -53,6 +67,14 @@
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>workflow-engine-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>workflow-engine-elasticsearch</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>workflow-engine-axzo-ext</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
@ -116,6 +138,10 @@
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo</groupId>
|
||||
<artifactId>riven-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.workflow.server;
|
||||
|
||||
import org.dromara.easyes.starter.register.EsMapperScan;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@ -10,12 +11,13 @@ import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
|
||||
@MapperScan({"cn.axzo.workflow.core.**.mapper"})
|
||||
@MapperScan({"cn.axzo.workflow.core.**.mapper", "cn.axzo.workflow.admin.**.mapper"})
|
||||
@ComponentScan({"cn.axzo.workflow"})
|
||||
@EnableFeignClients("cn.axzo.oss")
|
||||
@SpringBootApplication(exclude = RabbitAutoConfiguration.class)
|
||||
@EnableTransactionManagement
|
||||
@EnableCaching
|
||||
@EsMapperScan("cn.axzo.workflow.es.**.mapper")
|
||||
public class WorkflowEngineApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@ -91,13 +91,13 @@ public class ErrorReportAspect implements Ordered {
|
||||
if (!signature.toShortString().contains("ExtAxApiLogServiceImpl")) {
|
||||
String type = getType(joinPoint);
|
||||
ApiLogEvent event = new ApiLogEvent(MDC.get(CTX_LOG_ID_MDC),
|
||||
signature.toShortString(),
|
||||
Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_SERVER_NAME),
|
||||
Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_API_VERSION),
|
||||
Objects.equals(type, "Controller") ? joinPoint.getArgs() : null,
|
||||
Objects.equals(type, "Controller") ? result : null,
|
||||
watch.getTotalTimeSeconds(),
|
||||
type);
|
||||
signature.toShortString(),
|
||||
Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_SERVER_NAME),
|
||||
Objects.isNull(getOriginRequest()) ? "" : getOriginRequest().getHeader(HEADER_API_VERSION),
|
||||
Objects.equals(type, "Controller") ? joinPoint.getArgs() : null,
|
||||
Objects.equals(type, "Controller") ? result : null,
|
||||
watch.getTotalTimeSeconds(),
|
||||
type);
|
||||
|
||||
applicationEventPublisher.publishEvent(event);
|
||||
}
|
||||
@ -148,13 +148,13 @@ public class ErrorReportAspect implements Ordered {
|
||||
|
||||
log.warn("request header server name: {}", getHeader());
|
||||
envConfig.type().executeAction(profile,
|
||||
operation.summary(),
|
||||
filterSendDingTalk,
|
||||
joinPoint.getArgs(),
|
||||
joinPoint.getSignature().toShortString(),
|
||||
getHeader(),
|
||||
e,
|
||||
workflowProperties.getFilterOperations().contains(operation.summary()));
|
||||
operation.summary(),
|
||||
filterSendDingTalk,
|
||||
joinPoint.getArgs(),
|
||||
joinPoint.getSignature().toShortString(),
|
||||
getHeader(),
|
||||
e,
|
||||
workflowProperties.getFilterOperations().contains(operation.summary()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ public class XxlJobConfiguration {
|
||||
@Value("")
|
||||
private String accessToken;
|
||||
|
||||
@Value("")
|
||||
@Value("${xxl.job.executor.logpath:}")
|
||||
private String logPath;
|
||||
|
||||
@Value("-1")
|
||||
|
||||
@ -0,0 +1,124 @@
|
||||
package cn.axzo.workflow.server.common.util;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import liquibase.pro.packaged.D;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 一个一次性 JVM 外部进程执行,并返回结果的 Shell 工具
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-22 15:05
|
||||
*/
|
||||
@Slf4j
|
||||
public class ShellUtil {
|
||||
|
||||
private ShellUtil() {
|
||||
}
|
||||
|
||||
public static String grepDateLog(String profile, String keyword, String dateStr) {
|
||||
return grepLog(profile, keyword, DateUtil.parseDate(dateStr), null);
|
||||
}
|
||||
|
||||
public static String grepDateLog(String profile, String keyword, Date date) {
|
||||
return grepLog(profile, keyword, date, null);
|
||||
}
|
||||
|
||||
public static String grepTodayLog(String profile, String keyword) {
|
||||
return grepLog(profile, keyword, new Date(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 入参示例 zgrep '9812ea104cf643c4908e772a46abac17' workflowEngine.log | grep 'checkDeath()'
|
||||
* @param profile 环境
|
||||
* @param keyword 具体的命令
|
||||
* @return
|
||||
*/
|
||||
public static String grepRealTimeLog(String profile, String keyword) {
|
||||
return grepLog(profile, keyword, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param profile
|
||||
* @param keyword
|
||||
* @param date
|
||||
* @param grepKeyword
|
||||
* @return
|
||||
*/
|
||||
public static String grepLog(String profile, String keyword, Date date, String grepKeyword) {
|
||||
return executeCmd("cd " + getLogPath(profile) + " && zgrep '" + keyword + "' workflowEngine.log" +
|
||||
(Objects.nonNull(date) ? "." + DateUtil.formatDate(date) + ".*" : "") +
|
||||
(StringUtils.hasText(grepKeyword) ? " | grep '" + grepKeyword + "'": "")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 入参示例 cd /mnt/app-logdata/java-dev/workflowEngine && zgrep '9812ea104cf643c4908e772a46abac17' workflowEngine.log | grep 'checkDeath()'
|
||||
* @param fullCommand
|
||||
* @return
|
||||
*/
|
||||
private static String executeCmd(String fullCommand) {
|
||||
if (!StringUtils.hasText(fullCommand)) {
|
||||
return "命令不能为空";
|
||||
}
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", fullCommand);
|
||||
Process process = pb.start();
|
||||
InputStream inputStream = process.getInputStream();
|
||||
InputStream errorStream = process.getErrorStream();
|
||||
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
// 读取命令输出的线程
|
||||
Thread outputReader = new Thread(() -> {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
outputBuilder.append(line).append("\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("outputReader 发生异常: {}", e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
outputReader.start();
|
||||
|
||||
// 读取命令错误输出的线程
|
||||
Thread errorReader = new Thread(() -> {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
outputBuilder.append("Error: ").append(line).append("\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("errorReader 发生异常: {}", e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
errorReader.start();
|
||||
|
||||
// 等待命令执行完成
|
||||
outputReader.join();
|
||||
errorReader.join();
|
||||
|
||||
return outputBuilder.toString();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
log.error("Execute command 发生异常: {}", e.getMessage(), e);
|
||||
return "Error executing command.";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getLogPath(String profile) {
|
||||
String logSegment = profile;
|
||||
if (Objects.equals("dev", profile)) {
|
||||
logSegment = "java-dev";
|
||||
}
|
||||
return "/mnt/app-logdata/" + logSegment + "/workflowEngine/";
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
package cn.axzo.workflow.server.controller.delegate;
|
||||
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.axzo.karma.client.model.request.ListFlowTaskAssignerReq;
|
||||
import cn.axzo.karma.client.model.response.FlowTaskAssignerResp;
|
||||
import cn.axzo.workflow.common.enums.ApproverSpecifyEnum;
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
package cn.axzo.workflow.server.controller.listener.process;
|
||||
|
||||
import cn.axzo.workflow.core.common.context.ProcessOperationContext;
|
||||
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
|
||||
import cn.axzo.workflow.core.listener.BpmnProcessEventListener;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessInstanceService;
|
||||
import cn.axzo.workflow.server.controller.listener.tx.OnTxCommittedSyncToEsListener;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
|
||||
import org.flowable.common.engine.impl.cfg.TransactionState;
|
||||
import org.flowable.common.engine.impl.context.Context;
|
||||
import org.flowable.engine.delegate.event.FlowableCancelledEvent;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 流程实例结束后,同步最新数据至 ES
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-18 11:09
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
@AllArgsConstructor
|
||||
public class SyncToEsProcessEventListener extends AbstractBpmnEventListener<ProcessOperationContext> implements BpmnProcessEventListener, Ordered {
|
||||
private final AggregateProcessInstanceService aggregateProcessInstanceService;
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程实例被撤回后回调
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void onCancelled(FlowableCancelledEvent event) {
|
||||
syncToEs(event.getProcessInstanceId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程实例被驳回后回调
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void onRejected(FlowableCancelledEvent event) {
|
||||
syncToEs(event.getProcessInstanceId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程实例被中止后回调
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void onAborted(FlowableCancelledEvent event) {
|
||||
syncToEs(event.getProcessInstanceId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程实例运行完成后回调
|
||||
* <p>
|
||||
* 注意: 完成只是说明流程实例已停止运行
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
@Override
|
||||
public void onCompleted(FlowableEngineEntityEvent event) {
|
||||
syncToEs(event.getProcessInstanceId());
|
||||
}
|
||||
|
||||
private void syncToEs(String processInstanceId) {
|
||||
String uuid = UUID.fastUUID().toString();
|
||||
Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED,
|
||||
new OnTxCommittedSyncToEsListener(aggregateProcessInstanceService, processInstanceId, null, uuid));
|
||||
}
|
||||
}
|
||||
@ -34,7 +34,7 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELAT
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
@AllArgsConstructor
|
||||
public class SnapshotBpmnTaskTaskEvent_100_Listener extends AbstractBpmnEventListener<TaskOperationContext> implements BpmnTaskEventListener, Ordered {
|
||||
public class SnapshotBpmnTaskEvent_100_Listener extends AbstractBpmnEventListener<TaskOperationContext> implements BpmnTaskEventListener, Ordered {
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE + 100;
|
||||
@ -0,0 +1,47 @@
|
||||
package cn.axzo.workflow.server.controller.listener.task;
|
||||
|
||||
import cn.axzo.workflow.core.common.context.TaskOperationContext;
|
||||
import cn.axzo.workflow.core.listener.AbstractBpmnEventListener;
|
||||
import cn.axzo.workflow.core.listener.BpmnTaskEventListener;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessInstanceService;
|
||||
import cn.axzo.workflow.server.controller.listener.tx.OnTxCommittedSyncToEsListener;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.cfg.TransactionState;
|
||||
import org.flowable.common.engine.impl.context.Context;
|
||||
import org.flowable.task.service.delegate.DelegateTask;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 同步任务相关数据至 ES
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-16 16:50
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
@AllArgsConstructor
|
||||
public class SyncToEsTaskEvent_104_Listener extends AbstractBpmnEventListener<TaskOperationContext> implements BpmnTaskEventListener, Ordered {
|
||||
private final AggregateProcessInstanceService aggregateProcessInstanceService;
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE + 104;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户任务已指派审核人
|
||||
*
|
||||
* @param delegateTask
|
||||
*/
|
||||
@Override
|
||||
public void onAssigned(DelegateTask delegateTask) {
|
||||
String uuid = UUID.fastUUID().toString();
|
||||
Context.getTransactionContext().addTransactionListener(TransactionState.COMMITTED,
|
||||
new OnTxCommittedSyncToEsListener(aggregateProcessInstanceService, delegateTask.getProcessInstanceId(), delegateTask.getId(), uuid));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package cn.axzo.workflow.server.controller.listener.tx;
|
||||
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessInstanceService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.cfg.TransactionListener;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandContext;
|
||||
import org.flowable.engine.HistoryService;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
|
||||
import org.flowable.engine.impl.util.CommandContextUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 引擎内的动作事务提交后执行同步 ES
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-18 16:34
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class OnTxCommittedSyncToEsListener implements TransactionListener {
|
||||
private final AggregateProcessInstanceService aggregateProcessInstanceService;
|
||||
private final String processInstanceId;
|
||||
private final String taskId;
|
||||
private final String uuid;
|
||||
|
||||
@Override
|
||||
public void execute(CommandContext commandContext) {
|
||||
log.info("SyncEsTaskEntityEventHandle onInitialized uuid:{}, processInstanceId:{}, taskId: {}", uuid, processInstanceId, taskId);
|
||||
|
||||
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
|
||||
HistoryService historyService = processEngineConfiguration.getHistoryService();
|
||||
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
|
||||
.processInstanceId(processInstanceId)
|
||||
.singleResult();
|
||||
// 删除指定实例的父子文档
|
||||
log.info("delete document processInstanceId: {}", processInstanceId);
|
||||
aggregateProcessInstanceService.deleteDocumentParentAndChild(processInstanceId);
|
||||
log.info("reInsert document processInstanceId: {}", processInstanceId);
|
||||
List<ProcessTaskDocument> processTaskDocuments = aggregateProcessInstanceService.syncProcessInstance(historicProcessInstance, null);
|
||||
log.info("Insert Summary: ProcessInstance Count: {}, ProcessTask Count: {}", 1, processTaskDocuments.size());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,22 +1,14 @@
|
||||
package cn.axzo.workflow.server.controller.web;
|
||||
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.axzo.karma.client.model.request.PersonProfileQueryReq;
|
||||
import cn.axzo.karma.client.model.response.PersonProfileResp;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.server.common.util.RpcExternalUtil;
|
||||
import cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.populateNameAndAvatar;
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
|
||||
import cn.axzo.workflow.core.service.support.FlowNodeForecastService;
|
||||
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
|
||||
import cn.axzo.workflow.server.common.util.ShellUtil;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.bpmn.model.FlowElement;
|
||||
@ -18,6 +19,8 @@ import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -44,7 +47,8 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCES
|
||||
@RestController
|
||||
@Validated
|
||||
public class TestController {
|
||||
|
||||
@Value("${spring.profiles.active}")
|
||||
private String profile;
|
||||
@Autowired
|
||||
private FlowNodeForecastService forecastService;
|
||||
@Autowired
|
||||
@ -242,4 +246,12 @@ public class TestController {
|
||||
List<String> tenantIds = workflowManageService.sync().getTenantIds();
|
||||
return CommonResponse.success(tenantIds);
|
||||
}*/
|
||||
|
||||
@GetMapping("log")
|
||||
public String log(@RequestParam String keyword) throws Exception {
|
||||
if (!StringUtils.hasText(keyword)) {
|
||||
return "命令不能为空";
|
||||
}
|
||||
return ShellUtil.grepRealTimeLog(profile, keyword);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
package cn.axzo.workflow.server.controller.web.bpmn;
|
||||
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.axzo.karma.client.model.request.PersonProfileQueryReq;
|
||||
import cn.axzo.karma.client.model.response.PersonProfileResp;
|
||||
import cn.axzo.workflow.client.feign.bpmn.ProcessTaskApi;
|
||||
import cn.axzo.workflow.common.enums.AttachmentTypeEnum;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.AttachmentDTO;
|
||||
@ -28,7 +25,6 @@ import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessTaskService;
|
||||
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
|
||||
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
|
||||
import cn.axzo.workflow.server.common.util.RpcExternalUtil;
|
||||
import cn.axzo.workflow.server.controller.web.BasicPopulateAvatarController;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
@ -52,7 +48,6 @@ import javax.validation.constraints.NotEmpty;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.azxo.framework.common.model.CommonResponse.success;
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
package cn.axzo.workflow.server.controller.web.es;
|
||||
|
||||
import cn.axzo.workflow.client.feign.es.EsProcessInstanceApi;
|
||||
import cn.axzo.workflow.common.model.request.es.InstanceSearchReqDTO;
|
||||
import cn.axzo.workflow.common.model.request.es.TaskSearchReqDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.es.ProcessInstanceDocumentVO;
|
||||
import cn.axzo.workflow.common.model.response.es.ProcessTaskDocumentVO;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessInstanceService;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessTaskService;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ES 搜索相关操作
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-26 14:47
|
||||
*/
|
||||
@Slf4j
|
||||
@RequestMapping({"/web/v1/api/es", "/api/es"})
|
||||
@RestController
|
||||
@Validated
|
||||
public class ElasticSearchController implements EsProcessInstanceApi {
|
||||
@Resource
|
||||
private AggregateProcessInstanceService aggregateProcessInstanceService;
|
||||
@Autowired
|
||||
private AggregateProcessTaskService aggregateProcessTaskService;
|
||||
|
||||
/**
|
||||
* 审批数据搜索
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/instance/search")
|
||||
public CommonResponse<BpmPageResult<ProcessInstanceDocumentVO>> searchInstanceInEs(@Validated @RequestBody InstanceSearchReqDTO dto) {
|
||||
log.info("审批数据搜索 searchInstanceInEs===>>>参数:{}", JSONUtil.toJsonStr(dto));
|
||||
return CommonResponse.success(aggregateProcessInstanceService.search(dto));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批任务数据搜索
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/task/search")
|
||||
public CommonResponse<List<ProcessTaskDocumentVO>> searchTaskInEs(@Validated @RequestBody TaskSearchReqDTO dto) {
|
||||
log.info("审批任务数据搜索 searchTaskInEs===>>>参数:{}", JSONUtil.toJsonStr(dto));
|
||||
return CommonResponse.success(aggregateProcessTaskService.search(dto));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
package cn.axzo.workflow.server.controller.web.manage;
|
||||
|
||||
import cn.axzo.framework.domain.ServiceException;
|
||||
import cn.axzo.workflow.admin.repository.entity.ExtAxProcessAdmin;
|
||||
import cn.axzo.workflow.admin.service.ExtAxProcessAdminService;
|
||||
import cn.axzo.workflow.client.feign.manage.ProcessAdminApi;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminDeleteDTO;
|
||||
import cn.axzo.workflow.common.model.request.admin.ProcessAdminQueryDTO;
|
||||
import cn.axzo.workflow.common.model.response.admin.ProcessAdminVo;
|
||||
import cn.axzo.workflow.server.common.annotation.ErrorReporter;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.MAX_ORG_WORKSPACE_ADMIN_COUNT;
|
||||
|
||||
/**
|
||||
* 流程管理员控制器
|
||||
*/
|
||||
@Slf4j
|
||||
@RequestMapping({"/web/v1/api/process/admin", "/api/process/admin"})
|
||||
@RestController
|
||||
@ErrorReporter
|
||||
@Validated
|
||||
public class ProcessAdminController implements ProcessAdminApi {
|
||||
|
||||
@Resource
|
||||
private ExtAxProcessAdminService extAxProcessAdminService;
|
||||
|
||||
@PostMapping("/query")
|
||||
@Override
|
||||
public CommonResponse<List<ProcessAdminVo>> queryProcessAdmins(@RequestBody ProcessAdminQueryDTO dto) {
|
||||
List<ExtAxProcessAdmin> extAxProcessAdmins = extAxProcessAdminService.query(dto);
|
||||
if (CollectionUtils.isEmpty(extAxProcessAdmins)) {
|
||||
return CommonResponse.success();
|
||||
}
|
||||
List<ProcessAdminVo> adminVos = extAxProcessAdmins.stream()
|
||||
.map(ad -> {
|
||||
ProcessAdminVo vo = new ProcessAdminVo();
|
||||
vo.setProcessAdminId(ad.getId());
|
||||
BeanUtils.copyProperties(ad, vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return CommonResponse.success(adminVos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping("/query/count")
|
||||
public CommonResponse<Integer> queryProcessAdminsCount(ProcessAdminQueryDTO dto) {
|
||||
return CommonResponse.success(extAxProcessAdminService.queryCount(dto));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Override
|
||||
public CommonResponse<Long> createProcessAdmin(@RequestBody ProcessAdminCreateDTO dto) {
|
||||
List<ExtAxProcessAdmin> extAxProcessAdmins = extAxProcessAdminService.query(ProcessAdminQueryDTO
|
||||
.builder()
|
||||
.organizationalUnitId(dto.getOrganizationalUnitId())
|
||||
.workspaceId(dto.getWorkspaceId())
|
||||
.build());
|
||||
if (!CollectionUtils.isEmpty(extAxProcessAdmins) && extAxProcessAdmins.size() > MAX_ORG_WORKSPACE_ADMIN_COUNT) {
|
||||
throw new ServiceException(String.format("管理员最多不超过%d人", MAX_ORG_WORKSPACE_ADMIN_COUNT));
|
||||
}
|
||||
ExtAxProcessAdmin processAdmin = new ExtAxProcessAdmin();
|
||||
BeanUtils.copyProperties(dto, processAdmin);
|
||||
Long id = extAxProcessAdminService.insert(processAdmin);
|
||||
return CommonResponse.success(id);
|
||||
}
|
||||
|
||||
@PostMapping("/batch/create")
|
||||
@Override
|
||||
public CommonResponse<Void> batchCreateProcessAdmin(@RequestBody List<ProcessAdminCreateDTO> dtos) {
|
||||
if (CollectionUtils.isEmpty(dtos)) {
|
||||
return CommonResponse.success();
|
||||
}
|
||||
List<ExtAxProcessAdmin> extAxProcessAdmins = dtos.stream()
|
||||
.map(d -> {
|
||||
ExtAxProcessAdmin processAdmin = new ExtAxProcessAdmin();
|
||||
BeanUtils.copyProperties(d, processAdmin);
|
||||
return processAdmin;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
extAxProcessAdminService.batchInsert(extAxProcessAdmins);
|
||||
return CommonResponse.success();
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Override
|
||||
public CommonResponse<Integer> deleteCommonProcessAdmin(@RequestParam Long id) {
|
||||
return CommonResponse.success(extAxProcessAdminService.deleteCommonAdminsByIds(Collections.singletonList(id)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete/criteria")
|
||||
@Override
|
||||
public CommonResponse<Integer> deleteProcessAdminCriteria(@RequestBody ProcessAdminDeleteDTO dto) {
|
||||
return CommonResponse.success(extAxProcessAdminService.delete(dto));
|
||||
}
|
||||
|
||||
@DeleteMapping("/batch/delete")
|
||||
@Override
|
||||
public CommonResponse<Integer> batchDeleteProcessAdmin(@RequestBody List<Long> ids) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return CommonResponse.success();
|
||||
}
|
||||
return CommonResponse.success(extAxProcessAdminService.deleteCommonAdminsByIds(ids));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package cn.axzo.workflow.server.outside.mq;
|
||||
|
||||
import cn.axzo.framework.rocketmq.BaseListener;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventProducer;
|
||||
import cn.axzo.framework.rocketmq.RocketMQEventProducer;
|
||||
import cn.axzo.workflow.server.outside.mq.producer.DingtalkSendProducer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.annotation.SelectorType;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 钉钉消息 Rocket 配置
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-25 13:39
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class DingtalkRocketConfiguration {
|
||||
@Value("${spring.profiles.active:dev}")
|
||||
private String activeProfile;
|
||||
private static final String DEFAULT_MODULE = "workflowEngine";
|
||||
private static final String DEFAULT_EVENT = "topic_third_party_sync_event_";
|
||||
private static final String MODULE_NAME_SUFFIX = "_dingtalk_message";
|
||||
|
||||
@Bean
|
||||
public DingtalkSendProducer dingtalkSendProducer(RocketMQTemplate rocketMQTemplate) {
|
||||
return new DingtalkSendProducer(rocketMQTemplate,
|
||||
DEFAULT_MODULE,
|
||||
DEFAULT_MODULE + MODULE_NAME_SUFFIX,
|
||||
EventProducer.Context.<RocketMQEventProducer.RocketMQMessageMeta>builder()
|
||||
.meta(RocketMQEventProducer.RocketMQMessageMeta.builder()
|
||||
.topic(DEFAULT_EVENT + activeProfile)
|
||||
.build())
|
||||
.headers(new HashMap<>())
|
||||
.syncSending(Boolean.TRUE)
|
||||
.exceptionHandler(context -> {
|
||||
log.error("MQ, send event error: {}, event: {}",
|
||||
context.getThrowable().getCause().getMessage(),
|
||||
context.getEvent().toPrettyJsonString(),
|
||||
context.getThrowable());
|
||||
})
|
||||
.build(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(name = "rocketmq.name-server")
|
||||
@RocketMQMessageListener(topic = "topic_third_party_sync_event_${spring.profiles.active}",
|
||||
consumerGroup = "GID_${spring.application.name}_riven_consumer",
|
||||
consumeMode = ConsumeMode.CONCURRENTLY,
|
||||
selectorType = SelectorType.TAG,
|
||||
selectorExpression = "riven-dingtalk-receive",
|
||||
maxReconsumeTimes = 0,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class ReplyMessageRocketConsumer extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
@Resource
|
||||
private EventConsumer eventConsumer;
|
||||
|
||||
@Override
|
||||
public void onMessage(MessageExt message) {
|
||||
super.onEvent(message, eventConsumer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package cn.axzo.workflow.server.outside.mq.consumer;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.riven.client.common.enums.DingtalkEventEnum;
|
||||
import cn.axzo.riven.client.model.DingtalkReceiveMqModel;
|
||||
import cn.axzo.riven.client.model.DingtalkSendMqModel;
|
||||
import cn.axzo.riven.client.model.SampleText;
|
||||
import cn.axzo.workflow.server.outside.mq.producer.DingtalkSendProducer;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 监听钉钉群消息的事件
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-25 11:16
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DingtalkReceiveListener implements EventHandler, InitializingBean {
|
||||
@Value("${spring.application.name}")
|
||||
private String applicationName;
|
||||
@Resource
|
||||
private EventConsumer eventConsumer;
|
||||
@Resource
|
||||
private DingtalkSendProducer dingtalkSendProducer;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event, EventConsumer.Context context) {
|
||||
log.info("receive dingding message: {}", event.getTargetId());
|
||||
|
||||
if (!Objects.equals(applicationName, event.getTargetType())) {
|
||||
return;
|
||||
}
|
||||
DingtalkReceiveMqModel data = event.normalizedData(DingtalkReceiveMqModel.class);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("message data: {}", JSON.toJSONString(data));
|
||||
}
|
||||
|
||||
DingtalkSendMqModel<SampleText> sendModel = new DingtalkSendMqModel<>();
|
||||
sendModel.setTraceId(data.getTraceId());
|
||||
sendModel.setConversationId(data.getConversationId());
|
||||
sendModel.setMsgId(data.getMsgId());
|
||||
sendModel.setRobotCode(data.getRobotCode());
|
||||
sendModel.setMessage(SampleText.from("由 WorkflowEngine 处理的消息: " + data.getContent()));
|
||||
|
||||
dingtalkSendProducer.send(sendModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(DingtalkEventEnum.receive.getEventCode(), this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package cn.axzo.workflow.server.outside.mq.producer;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.RocketMQEventProducer;
|
||||
import cn.axzo.riven.client.common.enums.DingtalkEventEnum;
|
||||
import cn.axzo.riven.client.model.DingtalkSendMqModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* 回复钉钉消息给 Riven 的事件生产者
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-25 11:33
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DingtalkSendProducer extends RocketMQEventProducer {
|
||||
@Value("${spring.application.name}")
|
||||
private String applicationName;
|
||||
public DingtalkSendProducer(RocketMQTemplate rocketMQTemplate, String defaultModule, String appName, Context<RocketMQMessageMeta> defaultContext, BiConsumer<Event, Context<RocketMQMessageMeta>> sendCallback) {
|
||||
super(rocketMQTemplate, defaultModule, appName, defaultContext, sendCallback);
|
||||
}
|
||||
|
||||
public void send(DingtalkSendMqModel model) {
|
||||
send(Event.builder()
|
||||
.shardingKey(applicationName)
|
||||
.eventCode(DingtalkEventEnum.send.getEventCode())
|
||||
.targetId(model.getTraceId())
|
||||
.targetType(DingtalkEventEnum.send.getTag())
|
||||
.data(model)
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
package cn.axzo.workflow.server.xxljob;
|
||||
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.axzo.karma.client.model.request.PersonProfileQueryReq;
|
||||
import cn.axzo.karma.client.model.response.PersonProfileResp;
|
||||
import cn.axzo.workflow.common.model.dto.es.DataSyncSummaryDTO;
|
||||
import cn.axzo.workflow.common.model.dto.es.HistoricProcessInstanceSearchForEsDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomInsertPropertyCmd;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceForEsService;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessInstanceService;
|
||||
import cn.axzo.workflow.server.controller.listener.task.SyncToEsTaskEvent_104_Listener;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import com.xxl.job.core.log.XxlJobLogger;
|
||||
import com.xxl.job.core.util.ShardingUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.LATEST_SYNC_TO_ELASTICSEARCH_TIME;
|
||||
import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.parseApiResult;
|
||||
|
||||
/**
|
||||
* 审批结束的流程实例数据同步至 ES
|
||||
* <p>
|
||||
* 在途的,或新发起的流程实例,均通过 {@link SyncToEsTaskEvent_104_Listener} 进行实时同步,
|
||||
* 但由于用户的操作时间不可控,所以统一由 {@link OtherProcessInstanceSyncEsJobHandler} 单独进行一次同步
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 11:03
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CompletedProcessInstanceSyncEsJobHandler extends IJobHandler {
|
||||
private final BpmnProcessInstanceForEsService bpmnProcessInstanceForEsService;
|
||||
private final AggregateProcessInstanceService aggregateProcessInstanceService;
|
||||
private final SpringProcessEngineConfiguration springProcessEngineConfiguration;
|
||||
private final ApplicationContext context;
|
||||
private final SupportRefreshProperties refreshProperties;
|
||||
private final FlowSupportApi flowSupportApi;
|
||||
|
||||
@XxlJob("completedProcessInstanceSyncToEs")
|
||||
public ReturnT<String> execute(String s) {
|
||||
// 分片参数
|
||||
ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
|
||||
if (Objects.nonNull(shardingVO) && shardingVO.getTotal() > 1) {
|
||||
log.info("分片参数:当前分片序号 = {}, 总分片数 = {}", shardingVO.getIndex(), shardingVO.getTotal());
|
||||
XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardingVO.getIndex(), shardingVO.getTotal());
|
||||
}
|
||||
|
||||
log.debug("start exec finished process instance data sync... ");
|
||||
XxlJobLogger.log("start exec finished process instance data sync... ");
|
||||
|
||||
HistoricProcessInstanceSearchForEsDTO search = new HistoricProcessInstanceSearchForEsDTO();
|
||||
search.setFinished(true);
|
||||
Date endTime = new Date();
|
||||
search.setEndTime(endTime);
|
||||
|
||||
try {
|
||||
if (StringUtils.hasText(s)) {
|
||||
search = JSON.parseObject(s, HistoricProcessInstanceSearchForEsDTO.class);
|
||||
log.info("根据入参转换后的查询入参:{}", JSON.toJSONString(search));
|
||||
XxlJobLogger.log("根据入参转换后的查询入参:{}", JSON.toJSONString(search));
|
||||
} else {
|
||||
log.info("入参为空, 将以默认条件执行");
|
||||
XxlJobLogger.log("入参为空, 将以默认条件执行");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("无法解析传参, 入参必须是 JSON 格式, 入参可参考 HistoricProcessInstanceSearchForEsDTO 模型");
|
||||
XxlJobLogger.log("无法解析传参, 入参必须是 JSON 格式, 入参可参考 HistoricProcessInstanceSearchForEsDTO 模型");
|
||||
return ReturnT.FAIL;
|
||||
}
|
||||
|
||||
// 开始同步完成的实例到 ES
|
||||
DataSyncSummaryDTO summary = doSync(search, shardingVO.getTotal() > 1 ? shardingVO : null);
|
||||
|
||||
// 执行完同步后的一些额外操作
|
||||
afterSync(endTime);
|
||||
|
||||
log.info("Insert Summary: ProcessInstance Count: {}, ProcessTask Count: {}", summary.getProcessInstanceCount(), summary.getProcessTaskCount());
|
||||
XxlJobLogger.log("Insert Summary: ProcessInstance Count: {}, ProcessTask Count: {}", summary.getProcessInstanceCount(), summary.getProcessTaskCount());
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. 记录本次操作的时间点
|
||||
*/
|
||||
private void afterSync(Date endTime) {
|
||||
//1. 记录本次操作的时间点, 多次执行也会自动更新操作时间点
|
||||
CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor();
|
||||
commandExecutor.execute(new CustomInsertPropertyCmd(LATEST_SYNC_TO_ELASTICSEARCH_TIME, DateUtil.formatDateTime(endTime)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步指定查询结果的数据至 ES
|
||||
* <p>
|
||||
* 内部自动分页循环同步
|
||||
*
|
||||
* @param search
|
||||
* @param shardingVO 分片信息, 可能为 null
|
||||
* @return 应同步至 ES 的统计数据
|
||||
*/
|
||||
private DataSyncSummaryDTO doSync(HistoricProcessInstanceSearchForEsDTO search, ShardingUtil.ShardingVO shardingVO) {
|
||||
Long totalProcessInstanceCount = bpmnProcessInstanceForEsService.queryHistoricProcessInstanceTotalCount(search);
|
||||
log.info("查询到待同步实例维度数据量: {} 条", totalProcessInstanceCount);
|
||||
XxlJobLogger.log("查询到待同步实例维度数据量: {} 条", totalProcessInstanceCount);
|
||||
AtomicLong totalProcessTaskCount = new AtomicLong(0);
|
||||
IntStream.iterate(0, i -> i + search.getOverPageSize()).limit((totalProcessInstanceCount + search.getOverPageSize() - 1) / search.getOverPageSize())
|
||||
.forEach(skipRows -> {
|
||||
log.info("处理进度: {} %, current startRow: {}, endRow: {}", String.format("%.2f", (double) skipRows / totalProcessInstanceCount * 100),
|
||||
skipRows, skipRows + search.getOverPageSize());
|
||||
XxlJobLogger.log("处理进度: {} %, current startRow: {}, endRow: {}", String.format("%.2f", (double) skipRows / totalProcessInstanceCount * 100),
|
||||
skipRows, skipRows + search.getOverPageSize());
|
||||
int pageNo = skipRows / search.getOverPageSize() + 1;
|
||||
List<HistoricProcessInstance> instances = bpmnProcessInstanceForEsService.queryHistoricProcessInstance(search, new Page<HistoricProcessInstance>(pageNo, search.getOverPageSize()));
|
||||
|
||||
instances.parallelStream().filter(hpi -> {
|
||||
if (Objects.nonNull(shardingVO)) {
|
||||
if (hpi.getId().contains("-")) {
|
||||
// 最开始的实例编号是 UUID,无法取模,所以统一交给第一个节点处理
|
||||
return shardingVO.getIndex() == 0;
|
||||
}
|
||||
return Long.parseLong(hpi.getId().substring(12)) % shardingVO.getTotal() == shardingVO.getIndex();
|
||||
}
|
||||
// 如果配置的非分片广播的方式,那么 shardingVO 将是 null
|
||||
return true;
|
||||
}).forEach(hpi -> {
|
||||
List<ProcessTaskDocument> processTaskDocuments = aggregateProcessInstanceService.syncProcessInstance(hpi, this::queryPersonByIds);
|
||||
totalProcessTaskCount.getAndSet(totalProcessTaskCount.get() + processTaskDocuments.size());
|
||||
});
|
||||
});
|
||||
return new DataSyncSummaryDTO(totalProcessInstanceCount, totalProcessTaskCount.get());
|
||||
}
|
||||
|
||||
private Map<Long, BpmnTaskDelegateAssigner> queryPersonByIds(List<BpmnTaskDelegateAssigner> users) {
|
||||
Map<Long, BpmnTaskDelegateAssigner> result = new HashMap<>();
|
||||
if (CollectionUtils.isEmpty(users)) {
|
||||
return result;
|
||||
}
|
||||
Map<Long, BpmnTaskDelegateAssigner> map = users.stream()
|
||||
.filter(i -> StringUtils.hasText(i.getPersonId()) && !Objects.equals("null", i.getPersonId()) && NumberUtil.isNumber(i.getPersonId()))
|
||||
.collect(Collectors.toMap(i -> NumberUtil.parseLong(i.getPersonId()), Function.identity(), (s, t) -> s));
|
||||
|
||||
PersonProfileQueryReq query = new PersonProfileQueryReq();
|
||||
ArrayList<Long> personIds = Lists.newArrayList(map.keySet());
|
||||
query.setPersonIds(personIds);
|
||||
Map<Long, PersonProfileResp> personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()),
|
||||
"根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds)
|
||||
.stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s));
|
||||
|
||||
personProfileMap.forEach((k, v) -> {
|
||||
result.put(k, BpmnTaskDelegateAssigner.builder()
|
||||
.personId(String.valueOf(v.getId()))
|
||||
.assignerName(v.getRealName())
|
||||
.avatar(v.getAvatarUrl())
|
||||
.build());
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package cn.axzo.workflow.server.xxljob;
|
||||
|
||||
import cn.axzo.workflow.es.service.EsProcessInstanceService;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import com.xxl.job.core.log.XxlJobLogger;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* 生产环境下手动创建索引
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-09 11:34
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class EsIndexOperationJobHandler extends IJobHandler {
|
||||
private final EsProcessInstanceService esProcessInstanceService;
|
||||
|
||||
@Override
|
||||
@XxlJob("esIndexOperation")
|
||||
public ReturnT<String> execute(String param) {
|
||||
if (!StringUtils.hasText(param)) {
|
||||
createIndex();
|
||||
} else {
|
||||
deleteIndex();
|
||||
}
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除索引
|
||||
*/
|
||||
private void deleteIndex() {
|
||||
log.info("开始删除父子文档索引...");
|
||||
XxlJobLogger.log("开始删除父子文档索引...");
|
||||
Boolean index = esProcessInstanceService.deleteIndex();
|
||||
log.info("删除完成. 响应结果: {}", index);
|
||||
XxlJobLogger.log("删除完成. 响应结果: {}", index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建索引
|
||||
*/
|
||||
private void createIndex() {
|
||||
log.info("开始创建父子文档索引...");
|
||||
XxlJobLogger.log("开始创建父子文档索引...");
|
||||
Boolean index = esProcessInstanceService.createIndex();
|
||||
// 如果重复调用,避免报错,在创建的逻辑中,内置了判断是否存在指定索引,如果存在则不再创建,直接返回 false.
|
||||
log.info("创建完成. 响应结果: {}", index);
|
||||
XxlJobLogger.log("创建完成. 响应结果: {}", index);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,168 @@
|
||||
package cn.axzo.workflow.server.xxljob;
|
||||
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.axzo.karma.client.model.request.PersonProfileQueryReq;
|
||||
import cn.axzo.karma.client.model.response.PersonProfileResp;
|
||||
import cn.axzo.workflow.common.model.dto.es.DataSyncSummaryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.engine.cmd.CustomGetPropertyCmd;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceForEsService;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessInstanceService;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import com.xxl.job.core.log.XxlJobLogger;
|
||||
import com.xxl.job.core.util.ShardingUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static cn.axzo.workflow.common.constant.BpmnConstants.LATEST_SYNC_TO_ELASTICSEARCH_TIME;
|
||||
import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.parseApiResult;
|
||||
|
||||
/**
|
||||
* 在途的和新发起的流程实例数据同步至 ES
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 11:03
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class OtherProcessInstanceSyncEsJobHandler extends IJobHandler {
|
||||
private final BpmnProcessInstanceForEsService bpmnProcessInstanceForEsService;
|
||||
private final AggregateProcessInstanceService aggregateProcessInstanceService;
|
||||
private final SpringProcessEngineConfiguration springProcessEngineConfiguration;
|
||||
private final ApplicationContext context;
|
||||
private final SupportRefreshProperties refreshProperties;
|
||||
private final FlowSupportApi flowSupportApi;
|
||||
|
||||
@XxlJob("otherProcessInstanceSyncToEs")
|
||||
public ReturnT<String> execute(String param) {
|
||||
// 分片参数
|
||||
ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
|
||||
if (Objects.nonNull(shardingVO) && shardingVO.getTotal() > 1) {
|
||||
log.info("分片参数:当前分片序号 = {}, 总分片数 = {}", shardingVO.getIndex(), shardingVO.getTotal());
|
||||
XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardingVO.getIndex(), shardingVO.getTotal());
|
||||
}
|
||||
|
||||
log.debug("start exec other process instance data sync... ");
|
||||
XxlJobLogger.log("start exec other process instance data sync... ");
|
||||
|
||||
// 同步前的一些额外动作
|
||||
Date endTime = beforeSync();
|
||||
if (Objects.isNull(endTime)) {
|
||||
log.info("请先执行“流程实例数据同步 ES 第一步”, Bean Name:completedProcessInstanceSyncToEs。 待其执行完成后再执行该任务!");
|
||||
XxlJobLogger.log("请先执行“流程实例数据同步 ES 第一步”, Bean Name:completedProcessInstanceSyncToEs。 待其执行完成后再执行该任务!");
|
||||
return ReturnT.FAIL;
|
||||
}
|
||||
|
||||
// 开始同步流程数据到 ES
|
||||
DataSyncSummaryDTO summary = doSync(endTime, param, shardingVO.getTotal() > 1 ? shardingVO : null);
|
||||
|
||||
log.info("Insert Summary: ProcessInstance Count: {}, ProcessTask Count: {}", summary.getProcessInstanceCount(), summary.getProcessTaskCount());
|
||||
XxlJobLogger.log("Insert Summary: ProcessInstance Count: {}, ProcessTask Count: {}", summary.getProcessInstanceCount(), summary.getProcessTaskCount());
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
private Date beforeSync() {
|
||||
CommandExecutor commandExecutor = springProcessEngineConfiguration.getCommandExecutor();
|
||||
return commandExecutor.execute(new CustomGetPropertyCmd(LATEST_SYNC_TO_ELASTICSEARCH_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始处理的入口
|
||||
*
|
||||
* @param endTime
|
||||
* @param pageSizeStr
|
||||
*/
|
||||
private DataSyncSummaryDTO doSync(Date endTime, String pageSizeStr, ShardingUtil.ShardingVO shardingVO) {
|
||||
Long totalCount = bpmnProcessInstanceForEsService.queryHistoricProcessInstanceByUnfinishedAndAlterEndTimeTotalCount(endTime);
|
||||
log.info("查询到待同步实例维度数据量: {} 条", totalCount);
|
||||
XxlJobLogger.log("查询到待同步实例维度数据量: {} 条", totalCount);
|
||||
AtomicInteger pageSize = new AtomicInteger(50);
|
||||
if (StringUtils.hasText(pageSizeStr)) {
|
||||
try {
|
||||
pageSize.set(Integer.parseInt(pageSizeStr));
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
AtomicLong totalProcessTaskCount = new AtomicLong(0);
|
||||
IntStream.iterate(0, i -> i + pageSize.get()).limit((totalCount + pageSize.get() - 1) / pageSize.get())
|
||||
.forEach(skipRows -> {
|
||||
log.info("处理进度: {} %, current startRow: {}, endRow: {}", String.format("%.2f", (double) skipRows / totalCount * 100),
|
||||
skipRows, skipRows + pageSize.get());
|
||||
XxlJobLogger.log("处理进度: {} %, current startRow: {}, endRow: {}", String.format("%.2f", (double) skipRows / totalCount * 100),
|
||||
skipRows, skipRows + pageSize.get());
|
||||
int pageNo = skipRows / pageSize.get() + 1;
|
||||
List<HistoricProcessInstance> instances = bpmnProcessInstanceForEsService.queryHistoricProcessInstanceByUnfinishedAndAlterEndTime(endTime, new Page<HistoricProcessInstance>(pageNo, pageSize.get()));
|
||||
|
||||
instances.parallelStream().filter(hpi -> {
|
||||
if (Objects.nonNull(shardingVO)) {
|
||||
if (hpi.getId().contains("-")) {
|
||||
// 最开始的实例编号是 UUID,无法取模,所以统一交给第一个节点处理
|
||||
return shardingVO.getIndex() == 0;
|
||||
}
|
||||
return Long.parseLong(hpi.getId().substring(12)) % shardingVO.getTotal() == shardingVO.getIndex();
|
||||
}
|
||||
// 如果配置的非分片广播的方式,那么 shardingVO 将是 null
|
||||
return true;
|
||||
}).forEach(hpi -> {
|
||||
List<ProcessTaskDocument> processTaskDocuments = aggregateProcessInstanceService.syncProcessInstance(hpi, this::queryPersonByIds);
|
||||
totalProcessTaskCount.getAndSet(totalProcessTaskCount.get() + processTaskDocuments.size());
|
||||
});
|
||||
});
|
||||
return new DataSyncSummaryDTO(totalCount, totalProcessTaskCount.get());
|
||||
}
|
||||
|
||||
private Map<Long, BpmnTaskDelegateAssigner> queryPersonByIds(List<BpmnTaskDelegateAssigner> users) {
|
||||
Map<Long, BpmnTaskDelegateAssigner> result = new HashMap<>();
|
||||
if (CollectionUtils.isEmpty(users)) {
|
||||
return result;
|
||||
}
|
||||
Map<Long, BpmnTaskDelegateAssigner> map = users.stream()
|
||||
.filter(i -> StringUtils.hasText(i.getPersonId()) && !Objects.equals("null", i.getPersonId()) && NumberUtil.isNumber(i.getPersonId()))
|
||||
.collect(Collectors.toMap(i -> NumberUtil.parseLong(i.getPersonId()), Function.identity(), (s, t) -> s));
|
||||
|
||||
PersonProfileQueryReq query = new PersonProfileQueryReq();
|
||||
ArrayList<Long> personIds = Lists.newArrayList(map.keySet());
|
||||
query.setPersonIds(personIds);
|
||||
Map<Long, PersonProfileResp> personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()),
|
||||
"根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds)
|
||||
.stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s));
|
||||
|
||||
personProfileMap.forEach((k, v) -> {
|
||||
result.put(k, BpmnTaskDelegateAssigner.builder()
|
||||
.personId(String.valueOf(v.getId()))
|
||||
.assignerName(v.getRealName())
|
||||
.avatar(v.getAvatarUrl())
|
||||
.build());
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
package cn.axzo.workflow.server.xxljob;
|
||||
|
||||
import cn.axzo.karma.client.feign.FlowSupportApi;
|
||||
import cn.axzo.karma.client.model.request.PersonProfileQueryReq;
|
||||
import cn.axzo.karma.client.model.response.PersonProfileResp;
|
||||
import cn.axzo.workflow.common.model.dto.es.DataSyncSummaryDTO;
|
||||
import cn.axzo.workflow.common.model.dto.es.HistoricProcessInstanceSearchForEsDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
|
||||
import cn.axzo.workflow.core.conf.SupportRefreshProperties;
|
||||
import cn.axzo.workflow.core.service.BpmnProcessInstanceForEsService;
|
||||
import cn.axzo.workflow.es.model.ProcessTaskDocument;
|
||||
import cn.axzo.workflow.es.service.aggregation.AggregateProcessInstanceService;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import com.xxl.job.core.log.XxlJobLogger;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.workflow.server.controller.delegate.AbstractBpmnTaskAssigneeSelector.parseApiResult;
|
||||
|
||||
/**
|
||||
* 在途的和新发起的流程实例数据同步至 ES
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-09-27 11:03
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class SpecifyProcessInstanceSyncEsJobHandler extends IJobHandler {
|
||||
private final BpmnProcessInstanceForEsService bpmnProcessInstanceForEsService;
|
||||
private final AggregateProcessInstanceService aggregateProcessInstanceService;
|
||||
private final SpringProcessEngineConfiguration springProcessEngineConfiguration;
|
||||
private final ApplicationContext context;
|
||||
private final SupportRefreshProperties refreshProperties;
|
||||
private final FlowSupportApi flowSupportApi;
|
||||
|
||||
@XxlJob("specifyProcessInstanceSyncToEs")
|
||||
public ReturnT<String> execute(String processInstanceId) {
|
||||
log.info("Sync specify processInstance id: {}", processInstanceId);
|
||||
XxlJobLogger.log("Sync specify processInstance id: {}", processInstanceId);
|
||||
|
||||
// 开始同步流程数据到 ES
|
||||
DataSyncSummaryDTO summary = doSync(processInstanceId);
|
||||
|
||||
log.info("Insert Summary: ProcessInstance Count: {}, ProcessTask Count: {}", summary.getProcessInstanceCount(), summary.getProcessTaskCount());
|
||||
XxlJobLogger.log("Insert Summary: ProcessInstance Count: {}, ProcessTask Count: {}", summary.getProcessInstanceCount(), summary.getProcessTaskCount());
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始处理的入口
|
||||
*
|
||||
* @param processInstanceId
|
||||
*/
|
||||
private DataSyncSummaryDTO doSync(String processInstanceId) {
|
||||
HistoricProcessInstanceSearchForEsDTO search = new HistoricProcessInstanceSearchForEsDTO();
|
||||
search.setProcessInstanceId(processInstanceId);
|
||||
List<HistoricProcessInstance> instances = bpmnProcessInstanceForEsService.queryHistoricProcessInstance(search, null);
|
||||
AtomicLong totalProcessTaskCount = new AtomicLong(0);
|
||||
instances.forEach(hpi -> {
|
||||
aggregateProcessInstanceService.deleteDocumentParentAndChild(hpi.getId());
|
||||
List<ProcessTaskDocument> processTaskDocuments = aggregateProcessInstanceService.syncProcessInstance(hpi, this::queryPersonByIds);
|
||||
totalProcessTaskCount.getAndSet(totalProcessTaskCount.get() + processTaskDocuments.size());
|
||||
});
|
||||
return new DataSyncSummaryDTO(1L, totalProcessTaskCount.get());
|
||||
|
||||
}
|
||||
|
||||
private Map<Long, BpmnTaskDelegateAssigner> queryPersonByIds(List<BpmnTaskDelegateAssigner> users) {
|
||||
Map<Long, BpmnTaskDelegateAssigner> result = new HashMap<>();
|
||||
if (CollectionUtils.isEmpty(users)) {
|
||||
return result;
|
||||
}
|
||||
Map<Long, BpmnTaskDelegateAssigner> map = users.stream()
|
||||
.filter(i -> StringUtils.hasText(i.getPersonId()) && !Objects.equals("null", i.getPersonId()) && NumberUtil.isNumber(i.getPersonId()))
|
||||
.collect(Collectors.toMap(i -> NumberUtil.parseLong(i.getPersonId()), Function.identity(), (s, t) -> s));
|
||||
|
||||
PersonProfileQueryReq query = new PersonProfileQueryReq();
|
||||
ArrayList<Long> personIds = Lists.newArrayList(map.keySet());
|
||||
query.setPersonIds(personIds);
|
||||
Map<Long, PersonProfileResp> personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()),
|
||||
"根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds)
|
||||
.stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s));
|
||||
|
||||
personProfileMap.forEach((k, v) -> {
|
||||
result.put(k, BpmnTaskDelegateAssigner.builder()
|
||||
.personId(String.valueOf(v.getId()))
|
||||
.assignerName(v.getRealName())
|
||||
.avatar(v.getAvatarUrl())
|
||||
.build());
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@ -36,9 +36,8 @@
|
||||
<version>4.9.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<artifactId>workflow-engine-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
|
||||
@ -5,42 +5,11 @@ import cn.axzo.workflow.common.util.ThreadUtil;
|
||||
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.ASYNC;
|
||||
import static cn.axzo.workflow.common.enums.RpcInvokeModeEnum.SYNC;
|
||||
import cn.axzo.workflow.client.annotation.WorkflowEngineFeignClient;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.annotation.Manageable;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import cn.axzo.workflow.common.annotation.InvokeMode;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnOptionalNodeDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCompleteDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnRobotTaskCreateDTO;
|
||||
@ -52,12 +21,45 @@ import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskCountersignDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskPageSearchDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskRemindDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO;
|
||||
import cn.axzo.workflow.common.model.response.BpmPageResult;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.BatchOperationResultVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceGroupVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnHistoricTaskInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskDonePageItemVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskTodoPageItemVO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAdminPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCancelDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCarbonCopyDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCheckApproverDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceCreateWithFormDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceLogQueryDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceMyPageReqVO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceAdminPageItemVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceLogVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstancePageItemVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO;
|
||||
import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutCallbackDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.activity.BpmnActivityTimeoutTriggerDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivitySetAssigneeDTO;
|
||||
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO;
|
||||
|
||||
/**
|
||||
* Workflow Engine Starter Core Service
|
||||
@ -69,135 +71,6 @@ import javax.validation.constraints.NotEmpty;
|
||||
@org.springframework.cloud.openfeign.FeignClient(name = "workflow-engine-starter-core", url = "${axzo.service.workflow-engine:http://workflow-engine:8080}", configuration = WorkflowEngineStarterFeignConfiguration.class)
|
||||
public interface WorkflowCoreService {
|
||||
|
||||
/**
|
||||
* 业务节点唤醒, 该节点废弃,请换成 {@link ProcessActivityApi#trigger(cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO)} 接口
|
||||
* <p>
|
||||
* 当模型中使用了“业务节点”,且设置了“不设置审批人”模式,则当业务监听到 PROCESS_ACTIVITY_START 事件时,可通过该接口推动流程继续运行
|
||||
*/
|
||||
@Deprecated
|
||||
@GetMapping("/api/process/activity/trigger")
|
||||
Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId);
|
||||
|
||||
/**
|
||||
* 业务节点唤醒
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/activity/trigger")
|
||||
Boolean trigger(@Validated @RequestBody BpmnActivityTriggerDTO dto);
|
||||
|
||||
/**
|
||||
* 业务节点设置审批人, 不支持重复设置
|
||||
* <p>
|
||||
* 当模型中使用了“业务节点”,且设置了“业务指定审批人”模式,则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时,可通过该接口设置动态设置审批人
|
||||
* <p>
|
||||
* <strong color=orange>注意:如果调用接口时,传入的审批人集合为空,流程引擎将对该审批流程实例自动中止。</strong>
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/activity/assignee/set")
|
||||
@Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人")
|
||||
Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto);
|
||||
|
||||
/**
|
||||
* 创建审批流程
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
|
||||
* 2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
|
||||
* </pre>
|
||||
*
|
||||
* @param dto {@link BpmnProcessInstanceCreateDTO}
|
||||
*/
|
||||
@Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件")
|
||||
@PostMapping("/api/process/instance/create")
|
||||
@InvokeMode(SYNC)
|
||||
String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto);
|
||||
|
||||
/**
|
||||
* 发起人主动撤回审核
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
|
||||
* 2. 当前流程实例会触发 process-instance-cancelled 事件
|
||||
* </pre>
|
||||
*
|
||||
* @param dto {@link BpmnProcessInstanceCancelDTO}
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件")
|
||||
@DeleteMapping("/api/process/instance/cancel")
|
||||
Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto);
|
||||
|
||||
/**
|
||||
* 中止流程实例
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "中止流程实例")
|
||||
@DeleteMapping("/api/process/instance/abort")
|
||||
Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto);
|
||||
|
||||
/**
|
||||
* 批量中止流程实例
|
||||
*
|
||||
* @param dtos
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "批量中止流程实例")
|
||||
@DeleteMapping("/api/process/instance/batch/abort")
|
||||
BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List<BpmnProcessInstanceAbortDTO> dtos);
|
||||
|
||||
/**
|
||||
* 抄送流程实例(未实现)
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "抄送流程实例")
|
||||
@PostMapping("/api/process/instance/carbon-copy")
|
||||
@Deprecated
|
||||
Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto);
|
||||
|
||||
/**
|
||||
* 获得流程实例
|
||||
*
|
||||
* @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询
|
||||
* @return 流程实例, 租户Id不必传
|
||||
*/
|
||||
@Operation(summary = "获得流程实例")
|
||||
@GetMapping("/api/process/instance/get")
|
||||
@InvokeMode(SYNC)
|
||||
BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例的流程变量
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @param tenantId
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "获取指定流程实例的流程变量")
|
||||
@GetMapping("/api/process/instance/cooperation-org")
|
||||
@InvokeMode(SYNC)
|
||||
Map<String, Object> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId);
|
||||
|
||||
/**
|
||||
* 获取指定流程的日志
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "获取指定流程的日志")
|
||||
@PostMapping("/api/process/instance/logs")
|
||||
@InvokeMode(SYNC)
|
||||
BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto);
|
||||
|
||||
/**
|
||||
* 同意
|
||||
*
|
||||
@ -323,6 +196,135 @@ public interface WorkflowCoreService {
|
||||
@PostMapping("/api/process/task/robot/complete")
|
||||
Boolean completeRobotTask(@Validated @RequestBody BpmnRobotTaskCompleteDTO dto);
|
||||
|
||||
/**
|
||||
* 创建审批流程
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件
|
||||
* 2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件
|
||||
* </pre>
|
||||
*
|
||||
* @param dto {@link BpmnProcessInstanceCreateDTO}
|
||||
*/
|
||||
@Operation(summary = "创建审批流程, MQ 触发规则:1. 当前流程实例会依次触发 process-instance-created 和 process-instance-started 事件,2. 第一个审批任务会依次触发 process-task-assigned 和 process-task-created 事件")
|
||||
@PostMapping("/api/process/instance/create")
|
||||
@InvokeMode(SYNC)
|
||||
String createProcessInstance(@Validated @RequestBody BpmnProcessInstanceCreateDTO dto);
|
||||
|
||||
/**
|
||||
* 发起人主动撤回审核
|
||||
*
|
||||
* <pre>
|
||||
* MQ 触发规则:
|
||||
* 1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件
|
||||
* 2. 当前流程实例会触发 process-instance-cancelled 事件
|
||||
* </pre>
|
||||
*
|
||||
* @param dto {@link BpmnProcessInstanceCancelDTO}
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "发起人主动撤回审核,MQ 触发规则:1. 当前流程实例中现存的任务会依次触发 process-task-deleted 事件,2. 当前流程实例会触发 process-instance-cancelled 事件")
|
||||
@DeleteMapping("/api/process/instance/cancel")
|
||||
Boolean cancelProcessInstance(@Validated @RequestBody BpmnProcessInstanceCancelDTO dto);
|
||||
|
||||
/**
|
||||
* 中止流程实例
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "中止流程实例")
|
||||
@DeleteMapping("/api/process/instance/abort")
|
||||
Boolean abortProcessInstance(@Validated @RequestBody BpmnProcessInstanceAbortDTO dto);
|
||||
|
||||
/**
|
||||
* 批量中止流程实例
|
||||
*
|
||||
* @param dtos
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "批量中止流程实例")
|
||||
@DeleteMapping("/api/process/instance/batch/abort")
|
||||
BatchOperationResultVO batchAbortProcessInstance(@Validated @RequestBody List<BpmnProcessInstanceAbortDTO> dtos);
|
||||
|
||||
/**
|
||||
* 抄送流程实例(未实现)
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "抄送流程实例")
|
||||
@PostMapping("/api/process/instance/carbon-copy")
|
||||
@Deprecated
|
||||
Boolean carbonCopyProcessInstance(@Validated @RequestBody BpmnProcessInstanceCarbonCopyDTO dto);
|
||||
|
||||
/**
|
||||
* 获得流程实例
|
||||
*
|
||||
* @param dto {@link BpmnProcessInstanceQueryDTO} 可根据 Id,BusinessKey进行查询
|
||||
* @return 流程实例, 租户Id不必传
|
||||
*/
|
||||
@Operation(summary = "获得流程实例")
|
||||
@GetMapping("/api/process/instance/get")
|
||||
@InvokeMode(SYNC)
|
||||
BpmnProcessInstanceVO getProcessInstanceVO(@Validated @RequestBody BpmnProcessInstanceQueryDTO dto);
|
||||
|
||||
/**
|
||||
* 获取指定流程实例的流程变量
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @param tenantId
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "获取指定流程实例的流程变量")
|
||||
@GetMapping("/api/process/instance/cooperation-org")
|
||||
@InvokeMode(SYNC)
|
||||
Map<String, Object> getProcessVariables(@NotBlank(message = "流程实例 ID 不能为空") @RequestParam String processInstanceId, @Nullable @RequestParam(required = false) String tenantId);
|
||||
|
||||
/**
|
||||
* 获取指定流程的日志
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@Operation(summary = "获取指定流程的日志")
|
||||
@PostMapping("/api/process/instance/logs")
|
||||
@InvokeMode(SYNC)
|
||||
BpmnProcessInstanceLogVO getProcessInstanceLogs(@Validated @RequestBody BpmnProcessInstanceLogQueryDTO dto);
|
||||
|
||||
/**
|
||||
* 业务节点唤醒, 该节点废弃,请换成 {@link ProcessActivityApi#trigger(cn.axzo.workflow.common.model.request.bpmn.task.BpmnActivityTriggerDTO)} 接口
|
||||
* <p>
|
||||
* 当模型中使用了“业务节点”,且设置了“不设置审批人”模式,则当业务监听到 PROCESS_ACTIVITY_START 事件时,可通过该接口推动流程继续运行
|
||||
*/
|
||||
@Deprecated
|
||||
@GetMapping("/api/process/activity/trigger")
|
||||
Boolean trigger(@NotBlank(message = "触发 ID 不能为空") @RequestParam String triggerId);
|
||||
|
||||
/**
|
||||
* 业务节点唤醒
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/activity/trigger")
|
||||
Boolean trigger(@Validated @RequestBody BpmnActivityTriggerDTO dto);
|
||||
|
||||
/**
|
||||
* 业务节点设置审批人, 不支持重复设置
|
||||
* <p>
|
||||
* 当模型中使用了“业务节点”,且设置了“业务指定审批人”模式,则当业务监听到 PROCESS_ACTIVITY_WAIT_ASSIGNEE 事件时,可通过该接口设置动态设置审批人
|
||||
* <p>
|
||||
* <strong color=orange>注意:如果调用接口时,传入的审批人集合为空,流程引擎将对该审批流程实例自动中止。</strong>
|
||||
*
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/process/activity/assignee/set")
|
||||
@Operation(summary = "业务节点设置审批人,不支持重复调用设置审批人,需一次性传入所有审批人")
|
||||
Boolean setAssignee(@Validated @RequestBody BpmnActivitySetAssigneeDTO dto);
|
||||
|
||||
/**
|
||||
* 强制使用‘异步’模式调用该方法,请在调用真实方法前调用该方法
|
||||
* <pre>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user