init
This commit is contained in:
15
blade-ops/blade-flow/Dockerfile
Normal file
15
blade-ops/blade-flow/Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM bladex/alpine-java:openjdk17_cn_slim
|
||||
|
||||
LABEL maintainer="bladejava@qq.com"
|
||||
|
||||
RUN mkdir -p /blade/flow
|
||||
|
||||
WORKDIR /blade/flow
|
||||
|
||||
EXPOSE 8008
|
||||
|
||||
COPY ./target/blade-flow.jar ./app.jar
|
||||
|
||||
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
|
||||
|
||||
CMD ["--spring.profiles.active=test"]
|
||||
45
blade-ops/blade-flow/doc/nacos/blade-flow-dev.yaml
Normal file
45
blade-ops/blade-flow/doc/nacos/blade-flow-dev.yaml
Normal file
@@ -0,0 +1,45 @@
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
#driver-class-name: org.postgresql.Driver
|
||||
#driver-class-name: oracle.jdbc.OracleDriver
|
||||
#driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||
#driver-class-name: dm.jdbc.driver.DmDriver
|
||||
druid:
|
||||
# MySql、PostgreSQL、SqlServer、DaMeng校验
|
||||
validation-query: select 1
|
||||
# Oracle校验
|
||||
#validation-query: select 1 from dual
|
||||
|
||||
#项目模块集中配置
|
||||
blade:
|
||||
#多租户配置
|
||||
tenant:
|
||||
#关闭动态数据源功能
|
||||
dynamic-datasource: false
|
||||
#关闭动态数据源全局扫描
|
||||
dynamic-global: false
|
||||
#工作流模块开发生产环境数据库地址
|
||||
datasource:
|
||||
flow:
|
||||
dev:
|
||||
# MySql
|
||||
url: jdbc:mysql://localhost:3306/bladex_flow?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: root
|
||||
# PostgreSQL
|
||||
#url: jdbc:postgresql://127.0.0.1:5432/bladex_flow
|
||||
#username: postgres
|
||||
#password: 123456
|
||||
# Oracle
|
||||
#url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
|
||||
#username: BLADEX_FLOW
|
||||
#password: BLADEX_FLOW
|
||||
# SqlServer
|
||||
#url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=bladex_flow
|
||||
#username: bladex_flow
|
||||
#password: bladex_flow
|
||||
# DaMeng
|
||||
#url: jdbc:dm://127.0.0.1:5236/BLADEX_FLOW?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
|
||||
#username: BLADEX_FLOW
|
||||
#password: BLADEX_FLOW
|
||||
83
blade-ops/blade-flow/pom.xml
Normal file
83
blade-ops/blade-flow/pom.xml
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>blade-ops</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>blade-flow</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- Blade -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-boot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-swagger</artifactId>
|
||||
</dependency>
|
||||
<!--<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-transaction</artifactId>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-dict-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-scope-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-user-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-flow-api</artifactId>
|
||||
</dependency>
|
||||
<!-- 工作流 -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-flowable</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>${docker.fabric.skip}</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow;
|
||||
|
||||
import org.springblade.core.cloud.client.BladeCloudApplication;
|
||||
import org.springblade.core.launch.BladeApplication;
|
||||
import org.springblade.core.launch.constant.AppConstant;
|
||||
|
||||
/**
|
||||
* Flowable启动器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
//@SeataCloudApplication
|
||||
@BladeCloudApplication
|
||||
public class FlowApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
BladeApplication.run(AppConstant.APPLICATION_FLOW_NAME, FlowApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.business.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.springblade.core.launch.constant.AppConstant;
|
||||
import org.springblade.core.mp.support.Condition;
|
||||
import org.springblade.core.mp.support.Query;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.flow.business.service.FlowBusinessService;
|
||||
import org.springblade.flow.core.pojo.entity.BladeFlow;
|
||||
import org.springblade.flow.core.utils.TaskUtil;
|
||||
import org.springblade.flow.engine.entity.FlowProcess;
|
||||
import org.springblade.flow.engine.service.FlowEngineService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 流程事务通用接口
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/work")
|
||||
@Tag(name = "流程事务通用接口", description = "流程事务通用接口")
|
||||
public class WorkController {
|
||||
|
||||
private final TaskService taskService;
|
||||
private final FlowEngineService flowEngineService;
|
||||
private final FlowBusinessService flowBusinessService;
|
||||
|
||||
/**
|
||||
* 发起事务列表页
|
||||
*/
|
||||
@GetMapping("start-list")
|
||||
@ApiOperationSupport(order = 1)
|
||||
@Operation(summary = "发起事务列表页", description = "传入流程类型")
|
||||
public R<IPage<FlowProcess>> startList(@Parameter(description = "流程类型") String category, Query query, @RequestParam(required = false, defaultValue = "1") Integer mode) {
|
||||
IPage<FlowProcess> pages = flowEngineService.selectProcessPage(Condition.getPage(query), category, mode);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 待签事务列表页
|
||||
*/
|
||||
@GetMapping("claim-list")
|
||||
@ApiOperationSupport(order = 2)
|
||||
@Operation(summary = "待签事务列表页", description = "传入流程信息")
|
||||
public R<IPage<BladeFlow>> claimList(@Parameter(description = "流程信息") BladeFlow bladeFlow, Query query) {
|
||||
IPage<BladeFlow> pages = flowBusinessService.selectClaimPage(Condition.getPage(query), bladeFlow);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 待办事务列表页
|
||||
*/
|
||||
@GetMapping("todo-list")
|
||||
@ApiOperationSupport(order = 3)
|
||||
@Operation(summary = "待办事务列表页", description = "传入流程信息")
|
||||
public R<IPage<BladeFlow>> todoList(@Parameter(description = "流程信息") BladeFlow bladeFlow, Query query) {
|
||||
IPage<BladeFlow> pages = flowBusinessService.selectTodoPage(Condition.getPage(query), bladeFlow);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 已发事务列表页
|
||||
*/
|
||||
@GetMapping("send-list")
|
||||
@ApiOperationSupport(order = 4)
|
||||
@Operation(summary = "已发事务列表页", description = "传入流程信息")
|
||||
public R<IPage<BladeFlow>> sendList(@Parameter(description = "流程信息") BladeFlow bladeFlow, Query query) {
|
||||
IPage<BladeFlow> pages = flowBusinessService.selectSendPage(Condition.getPage(query), bladeFlow);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 办结事务列表页
|
||||
*/
|
||||
@GetMapping("done-list")
|
||||
@ApiOperationSupport(order = 5)
|
||||
@Operation(summary = "办结事务列表页", description = "传入流程信息")
|
||||
public R<IPage<BladeFlow>> doneList(@Parameter(description = "流程信息") BladeFlow bladeFlow, Query query) {
|
||||
IPage<BladeFlow> pages = flowBusinessService.selectDonePage(Condition.getPage(query), bladeFlow);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 签收事务
|
||||
*
|
||||
* @param taskId 任务id
|
||||
*/
|
||||
@PostMapping("claim-task")
|
||||
@ApiOperationSupport(order = 6)
|
||||
@Operation(summary = "签收事务", description = "传入流程信息")
|
||||
public R claimTask(@Parameter(description = "任务id") String taskId) {
|
||||
taskService.claim(taskId, TaskUtil.getTaskUser());
|
||||
return R.success("签收事务成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成任务
|
||||
*
|
||||
* @param flow 请假信息
|
||||
*/
|
||||
@PostMapping("complete-task")
|
||||
@ApiOperationSupport(order = 7)
|
||||
@Operation(summary = "完成任务", description = "传入流程信息")
|
||||
public R completeTask(@Parameter(description = "任务信息") @RequestBody BladeFlow flow) {
|
||||
return R.status(flowBusinessService.completeTask(flow));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*
|
||||
* @param taskId 任务id
|
||||
* @param reason 删除原因
|
||||
*/
|
||||
@PostMapping("delete-task")
|
||||
@ApiOperationSupport(order = 8)
|
||||
@Operation(summary = "删除任务", description = "传入流程信息")
|
||||
public R deleteTask(@Parameter(description = "任务id") String taskId, @Parameter(description = "删除原因") String reason) {
|
||||
taskService.deleteTask(taskId, reason);
|
||||
return R.success("删除任务成功");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.business.feign;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.flowable.engine.IdentityService;
|
||||
import org.flowable.engine.RuntimeService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springblade.core.tenant.annotation.NonDS;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.support.Kv;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.flow.core.pojo.entity.BladeFlow;
|
||||
import org.springblade.flow.core.feign.IFlowClient;
|
||||
import org.springblade.flow.core.utils.TaskUtil;
|
||||
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.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程远程调用实现类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@NonDS
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
public class FlowClient implements IFlowClient {
|
||||
|
||||
private final RuntimeService runtimeService;
|
||||
private final IdentityService identityService;
|
||||
private final TaskService taskService;
|
||||
|
||||
@Override
|
||||
@PostMapping(START_PROCESS_INSTANCE_BY_ID)
|
||||
public R<BladeFlow> startProcessInstanceById(String processDefinitionId, String businessKey, @RequestBody Map<String, Object> variables) {
|
||||
// 设置流程启动用户
|
||||
identityService.setAuthenticatedUserId(TaskUtil.getTaskUser());
|
||||
// 开启流程
|
||||
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, businessKey, variables);
|
||||
// 组装流程通用类
|
||||
BladeFlow flow = new BladeFlow();
|
||||
flow.setProcessInstanceId(processInstance.getId());
|
||||
return R.data(flow);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping(START_PROCESS_INSTANCE_BY_KEY)
|
||||
public R<BladeFlow> startProcessInstanceByKey(String processDefinitionKey, String businessKey, @RequestBody Map<String, Object> variables) {
|
||||
// 设置流程启动用户
|
||||
identityService.setAuthenticatedUserId(TaskUtil.getTaskUser());
|
||||
// 开启流程
|
||||
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
|
||||
// 组装流程通用类
|
||||
BladeFlow flow = new BladeFlow();
|
||||
flow.setProcessInstanceId(processInstance.getId());
|
||||
return R.data(flow);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping(COMPLETE_TASK)
|
||||
public R completeTask(String taskId, String processInstanceId, String comment, @RequestBody Map<String, Object> variables) {
|
||||
// 增加评论
|
||||
if (StringUtil.isNoneBlank(processInstanceId, comment)) {
|
||||
taskService.addComment(taskId, processInstanceId, comment);
|
||||
}
|
||||
// 非空判断
|
||||
if (Func.isEmpty(variables)) {
|
||||
variables = Kv.create();
|
||||
}
|
||||
// 完成任务
|
||||
taskService.complete(taskId, variables);
|
||||
return R.success("流程提交成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping(TASK_VARIABLE)
|
||||
public R<Object> taskVariable(String taskId, String variableName) {
|
||||
return R.data(taskService.getVariable(taskId, variableName));
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping(TASK_VARIABLES)
|
||||
public R<Map<String, Object>> taskVariables(String taskId) {
|
||||
return R.data(taskService.getVariables(taskId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.business.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springblade.flow.core.pojo.entity.BladeFlow;
|
||||
|
||||
/**
|
||||
* 流程业务类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface FlowBusinessService {
|
||||
|
||||
/**
|
||||
* 流程待签列表
|
||||
*
|
||||
* @param page 分页工具
|
||||
* @param bladeFlow 流程类
|
||||
* @return
|
||||
*/
|
||||
IPage<BladeFlow> selectClaimPage(IPage<BladeFlow> page, BladeFlow bladeFlow);
|
||||
|
||||
/**
|
||||
* 流程待办列表
|
||||
*
|
||||
* @param page 分页工具
|
||||
* @param bladeFlow 流程类
|
||||
* @return
|
||||
*/
|
||||
IPage<BladeFlow> selectTodoPage(IPage<BladeFlow> page, BladeFlow bladeFlow);
|
||||
|
||||
/**
|
||||
* 流程已发列表
|
||||
*
|
||||
* @param page 分页工具
|
||||
* @param bladeFlow 流程类
|
||||
* @return
|
||||
*/
|
||||
IPage<BladeFlow> selectSendPage(IPage<BladeFlow> page, BladeFlow bladeFlow);
|
||||
|
||||
/**
|
||||
* 流程办结列表
|
||||
*
|
||||
* @param page 分页工具
|
||||
* @param bladeFlow 流程类
|
||||
* @return
|
||||
*/
|
||||
IPage<BladeFlow> selectDonePage(IPage<BladeFlow> page, BladeFlow bladeFlow);
|
||||
|
||||
/**
|
||||
* 完成任务
|
||||
*
|
||||
* @param leave 请假信息
|
||||
* @return boolean
|
||||
*/
|
||||
boolean completeTask(BladeFlow leave);
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.business.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.flowable.engine.HistoryService;
|
||||
import org.flowable.engine.TaskService;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstanceQuery;
|
||||
import org.flowable.task.api.TaskQuery;
|
||||
import org.flowable.task.api.history.HistoricTaskInstance;
|
||||
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.support.Kv;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.flow.business.service.FlowBusinessService;
|
||||
import org.springblade.flow.core.constant.ProcessConstant;
|
||||
import org.springblade.flow.core.pojo.entity.BladeFlow;
|
||||
import org.springblade.flow.core.utils.TaskUtil;
|
||||
import org.springblade.flow.engine.constant.FlowEngineConstant;
|
||||
import org.springblade.flow.engine.entity.FlowProcess;
|
||||
import org.springblade.flow.engine.utils.FlowCache;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程业务实现类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class FlowBusinessServiceImpl implements FlowBusinessService {
|
||||
|
||||
private final TaskService taskService;
|
||||
private final HistoryService historyService;
|
||||
|
||||
@Override
|
||||
public IPage<BladeFlow> selectClaimPage(IPage<BladeFlow> page, BladeFlow bladeFlow) {
|
||||
String taskUser = TaskUtil.getTaskUser();
|
||||
String taskGroup = TaskUtil.getCandidateGroup();
|
||||
List<BladeFlow> flowList = new LinkedList<>();
|
||||
|
||||
// 个人等待签收的任务
|
||||
TaskQuery claimUserQuery = taskService.createTaskQuery().taskCandidateUser(taskUser)
|
||||
.includeProcessVariables().active().orderByTaskCreateTime().desc();
|
||||
// 定制流程等待签收的任务
|
||||
TaskQuery claimRoleWithTenantIdQuery = taskService.createTaskQuery().taskTenantId(AuthUtil.getTenantId()).taskCandidateGroupIn(Func.toStrList(taskGroup))
|
||||
.includeProcessVariables().active().orderByTaskCreateTime().desc();
|
||||
// 通用流程等待签收的任务
|
||||
TaskQuery claimRoleWithoutTenantIdQuery = taskService.createTaskQuery().taskWithoutTenantId().taskCandidateGroupIn(Func.toStrList(taskGroup))
|
||||
.includeProcessVariables().active().orderByTaskCreateTime().desc();
|
||||
|
||||
// 构建列表数据
|
||||
buildFlowTaskList(bladeFlow, flowList, claimUserQuery, FlowEngineConstant.STATUS_CLAIM);
|
||||
buildFlowTaskList(bladeFlow, flowList, claimRoleWithTenantIdQuery, FlowEngineConstant.STATUS_CLAIM);
|
||||
buildFlowTaskList(bladeFlow, flowList, claimRoleWithoutTenantIdQuery, FlowEngineConstant.STATUS_CLAIM);
|
||||
|
||||
// 计算总数
|
||||
long count = claimUserQuery.count() + claimRoleWithTenantIdQuery.count() + claimRoleWithoutTenantIdQuery.count();
|
||||
// 设置页数
|
||||
page.setSize(count);
|
||||
// 设置总数
|
||||
page.setTotal(count);
|
||||
// 设置数据
|
||||
page.setRecords(flowList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<BladeFlow> selectTodoPage(IPage<BladeFlow> page, BladeFlow bladeFlow) {
|
||||
String taskUser = TaskUtil.getTaskUser();
|
||||
List<BladeFlow> flowList = new LinkedList<>();
|
||||
|
||||
// 已签收的任务
|
||||
TaskQuery todoQuery = taskService.createTaskQuery().taskAssignee(taskUser).active()
|
||||
.includeProcessVariables().orderByTaskCreateTime().desc();
|
||||
|
||||
// 构建列表数据
|
||||
buildFlowTaskList(bladeFlow, flowList, todoQuery, FlowEngineConstant.STATUS_TODO);
|
||||
|
||||
// 计算总数
|
||||
long count = todoQuery.count();
|
||||
// 设置页数
|
||||
page.setSize(count);
|
||||
// 设置总数
|
||||
page.setTotal(count);
|
||||
// 设置数据
|
||||
page.setRecords(flowList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<BladeFlow> selectSendPage(IPage<BladeFlow> page, BladeFlow bladeFlow) {
|
||||
String taskUser = TaskUtil.getTaskUser();
|
||||
List<BladeFlow> flowList = new LinkedList<>();
|
||||
|
||||
HistoricProcessInstanceQuery historyQuery = historyService.createHistoricProcessInstanceQuery().startedBy(taskUser).orderByProcessInstanceStartTime().desc();
|
||||
|
||||
if (bladeFlow.getCategory() != null) {
|
||||
historyQuery.processDefinitionCategory(bladeFlow.getCategory());
|
||||
}
|
||||
if (bladeFlow.getProcessDefinitionName() != null) {
|
||||
historyQuery.processDefinitionName(bladeFlow.getProcessDefinitionName());
|
||||
}
|
||||
if (bladeFlow.getBeginDate() != null) {
|
||||
historyQuery.startedAfter(bladeFlow.getBeginDate());
|
||||
}
|
||||
if (bladeFlow.getEndDate() != null) {
|
||||
historyQuery.startedBefore(bladeFlow.getEndDate());
|
||||
}
|
||||
|
||||
// 查询列表
|
||||
List<HistoricProcessInstance> historyList = historyQuery.listPage(Func.toInt((page.getCurrent() - 1) * page.getSize()), Func.toInt(page.getSize()));
|
||||
|
||||
historyList.forEach(historicProcessInstance -> {
|
||||
BladeFlow flow = new BladeFlow();
|
||||
// historicProcessInstance
|
||||
flow.setCreateTime(historicProcessInstance.getStartTime());
|
||||
flow.setEndTime(historicProcessInstance.getEndTime());
|
||||
flow.setVariables(historicProcessInstance.getProcessVariables());
|
||||
String[] businessKey = Func.toStrArray(StringPool.COLON, historicProcessInstance.getBusinessKey());
|
||||
if (businessKey.length > 1) {
|
||||
flow.setBusinessTable(businessKey[0]);
|
||||
flow.setBusinessId(businessKey[1]);
|
||||
}
|
||||
flow.setHistoryActivityName(historicProcessInstance.getName());
|
||||
flow.setProcessInstanceId(historicProcessInstance.getId());
|
||||
flow.setHistoryProcessInstanceId(historicProcessInstance.getId());
|
||||
// ProcessDefinition
|
||||
FlowProcess processDefinition = FlowCache.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
|
||||
flow.setProcessDefinitionId(processDefinition.getId());
|
||||
flow.setProcessDefinitionName(processDefinition.getName());
|
||||
flow.setProcessDefinitionVersion(processDefinition.getVersion());
|
||||
flow.setProcessDefinitionKey(processDefinition.getKey());
|
||||
flow.setCategory(processDefinition.getCategory());
|
||||
flow.setCategoryName(FlowCache.getCategoryName(processDefinition.getCategory()));
|
||||
flow.setProcessInstanceId(historicProcessInstance.getId());
|
||||
// HistoricTaskInstance
|
||||
List<HistoricTaskInstance> historyTasks = historyService.createHistoricTaskInstanceQuery().processInstanceId(historicProcessInstance.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
|
||||
if (Func.isNotEmpty(historyTasks)) {
|
||||
HistoricTaskInstance historyTask = historyTasks.iterator().next();
|
||||
flow.setTaskId(historyTask.getId());
|
||||
flow.setTaskName(historyTask.getName());
|
||||
flow.setTaskDefinitionKey(historyTask.getTaskDefinitionKey());
|
||||
}
|
||||
// Status
|
||||
if (historicProcessInstance.getEndActivityId() != null) {
|
||||
flow.setProcessIsFinished(FlowEngineConstant.STATUS_FINISHED);
|
||||
} else {
|
||||
flow.setProcessIsFinished(FlowEngineConstant.STATUS_UNFINISHED);
|
||||
}
|
||||
flow.setStatus(FlowEngineConstant.STATUS_FINISH);
|
||||
flowList.add(flow);
|
||||
});
|
||||
|
||||
// 计算总数
|
||||
long count = historyQuery.count();
|
||||
// 设置总数
|
||||
page.setTotal(count);
|
||||
page.setRecords(flowList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<BladeFlow> selectDonePage(IPage<BladeFlow> page, BladeFlow bladeFlow) {
|
||||
String taskUser = TaskUtil.getTaskUser();
|
||||
List<BladeFlow> flowList = new LinkedList<>();
|
||||
|
||||
HistoricTaskInstanceQuery doneQuery = historyService.createHistoricTaskInstanceQuery().taskAssignee(taskUser).finished()
|
||||
.includeProcessVariables().orderByHistoricTaskInstanceEndTime().desc();
|
||||
|
||||
if (bladeFlow.getCategory() != null) {
|
||||
doneQuery.processCategoryIn(Func.toStrList(bladeFlow.getCategory()));
|
||||
}
|
||||
if (bladeFlow.getProcessDefinitionName() != null) {
|
||||
doneQuery.processDefinitionName(bladeFlow.getProcessDefinitionName());
|
||||
}
|
||||
if (bladeFlow.getBeginDate() != null) {
|
||||
doneQuery.taskCompletedAfter(bladeFlow.getBeginDate());
|
||||
}
|
||||
if (bladeFlow.getEndDate() != null) {
|
||||
doneQuery.taskCompletedBefore(bladeFlow.getEndDate());
|
||||
}
|
||||
|
||||
// 查询列表
|
||||
List<HistoricTaskInstance> doneList = doneQuery.listPage(Func.toInt((page.getCurrent() - 1) * page.getSize()), Func.toInt(page.getSize()));
|
||||
doneList.forEach(historicTaskInstance -> {
|
||||
BladeFlow flow = new BladeFlow();
|
||||
flow.setTaskId(historicTaskInstance.getId());
|
||||
flow.setTaskDefinitionKey(historicTaskInstance.getTaskDefinitionKey());
|
||||
flow.setTaskName(historicTaskInstance.getName());
|
||||
flow.setAssignee(historicTaskInstance.getAssignee());
|
||||
flow.setCreateTime(historicTaskInstance.getCreateTime());
|
||||
flow.setExecutionId(historicTaskInstance.getExecutionId());
|
||||
flow.setHistoryTaskEndTime(historicTaskInstance.getEndTime());
|
||||
flow.setVariables(historicTaskInstance.getProcessVariables());
|
||||
|
||||
FlowProcess processDefinition = FlowCache.getProcessDefinition(historicTaskInstance.getProcessDefinitionId());
|
||||
flow.setProcessDefinitionId(processDefinition.getId());
|
||||
flow.setProcessDefinitionName(processDefinition.getName());
|
||||
flow.setProcessDefinitionKey(processDefinition.getKey());
|
||||
flow.setProcessDefinitionVersion(processDefinition.getVersion());
|
||||
flow.setCategory(processDefinition.getCategory());
|
||||
flow.setCategoryName(FlowCache.getCategoryName(processDefinition.getCategory()));
|
||||
|
||||
flow.setProcessInstanceId(historicTaskInstance.getProcessInstanceId());
|
||||
flow.setHistoryProcessInstanceId(historicTaskInstance.getProcessInstanceId());
|
||||
HistoricProcessInstance historicProcessInstance = getHistoricProcessInstance((historicTaskInstance.getProcessInstanceId()));
|
||||
if (Func.isNotEmpty(historicProcessInstance)) {
|
||||
String[] businessKey = Func.toStrArray(StringPool.COLON, historicProcessInstance.getBusinessKey());
|
||||
flow.setBusinessTable(businessKey[0]);
|
||||
flow.setBusinessId(businessKey[1]);
|
||||
if (historicProcessInstance.getEndActivityId() != null) {
|
||||
flow.setProcessIsFinished(FlowEngineConstant.STATUS_FINISHED);
|
||||
} else {
|
||||
flow.setProcessIsFinished(FlowEngineConstant.STATUS_UNFINISHED);
|
||||
}
|
||||
}
|
||||
flow.setStatus(FlowEngineConstant.STATUS_FINISH);
|
||||
flowList.add(flow);
|
||||
});
|
||||
// 计算总数
|
||||
long count = doneQuery.count();
|
||||
// 设置总数
|
||||
page.setTotal(count);
|
||||
page.setRecords(flowList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean completeTask(BladeFlow flow) {
|
||||
String taskId = flow.getTaskId();
|
||||
String processInstanceId = flow.getProcessInstanceId();
|
||||
String comment = Func.toStr(flow.getComment(), ProcessConstant.PASS_COMMENT);
|
||||
// 增加评论
|
||||
if (StringUtil.isNoneBlank(processInstanceId, comment)) {
|
||||
taskService.addComment(taskId, processInstanceId, comment);
|
||||
}
|
||||
// 创建变量
|
||||
Map<String, Object> variables = flow.getVariables();
|
||||
if (variables == null) {
|
||||
variables = Kv.create();
|
||||
}
|
||||
variables.put(ProcessConstant.PASS_KEY, flow.isPass());
|
||||
// 完成任务
|
||||
taskService.complete(taskId, variables);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建流程
|
||||
*
|
||||
* @param bladeFlow 流程通用类
|
||||
* @param flowList 流程列表
|
||||
* @param taskQuery 任务查询类
|
||||
* @param status 状态
|
||||
*/
|
||||
private void buildFlowTaskList(BladeFlow bladeFlow, List<BladeFlow> flowList, TaskQuery taskQuery, String status) {
|
||||
if (bladeFlow.getCategory() != null) {
|
||||
taskQuery.processCategoryIn(Func.toStrList(bladeFlow.getCategory()));
|
||||
}
|
||||
if (bladeFlow.getProcessDefinitionName() != null) {
|
||||
taskQuery.processDefinitionName(bladeFlow.getProcessDefinitionName());
|
||||
}
|
||||
if (bladeFlow.getBeginDate() != null) {
|
||||
taskQuery.taskCreatedAfter(bladeFlow.getBeginDate());
|
||||
}
|
||||
if (bladeFlow.getEndDate() != null) {
|
||||
taskQuery.taskCreatedBefore(bladeFlow.getEndDate());
|
||||
}
|
||||
taskQuery.list().forEach(task -> {
|
||||
BladeFlow flow = new BladeFlow();
|
||||
flow.setTaskId(task.getId());
|
||||
flow.setTaskDefinitionKey(task.getTaskDefinitionKey());
|
||||
flow.setTaskName(task.getName());
|
||||
flow.setAssignee(task.getAssignee());
|
||||
flow.setCreateTime(task.getCreateTime());
|
||||
flow.setClaimTime(task.getClaimTime());
|
||||
flow.setExecutionId(task.getExecutionId());
|
||||
flow.setVariables(task.getProcessVariables());
|
||||
|
||||
HistoricProcessInstance historicProcessInstance = getHistoricProcessInstance(task.getProcessInstanceId());
|
||||
if (Func.isNotEmpty(historicProcessInstance)) {
|
||||
String[] businessKey = Func.toStrArray(StringPool.COLON, historicProcessInstance.getBusinessKey());
|
||||
flow.setBusinessTable(businessKey[0]);
|
||||
flow.setBusinessId(businessKey[1]);
|
||||
}
|
||||
|
||||
FlowProcess processDefinition = FlowCache.getProcessDefinition(task.getProcessDefinitionId());
|
||||
flow.setCategory(processDefinition.getCategory());
|
||||
flow.setCategoryName(FlowCache.getCategoryName(processDefinition.getCategory()));
|
||||
flow.setProcessDefinitionId(processDefinition.getId());
|
||||
flow.setProcessDefinitionName(processDefinition.getName());
|
||||
flow.setProcessDefinitionKey(processDefinition.getKey());
|
||||
flow.setProcessDefinitionVersion(processDefinition.getVersion());
|
||||
flow.setProcessInstanceId(task.getProcessInstanceId());
|
||||
flow.setStatus(status);
|
||||
flowList.add(flow);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取历史流程
|
||||
*
|
||||
* @param processInstanceId 流程实例id
|
||||
* @return HistoricProcessInstance
|
||||
*/
|
||||
private HistoricProcessInstance getHistoricProcessInstance(String processInstanceId) {
|
||||
return historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||
import org.flowable.spring.boot.EngineConfigurationConfigurer;
|
||||
import org.flowable.spring.boot.FlowableProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Flowable配置类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AllArgsConstructor
|
||||
@EnableConfigurationProperties(FlowableProperties.class)
|
||||
public class FlowableConfiguration implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
|
||||
private final FlowableProperties flowableProperties;
|
||||
|
||||
@Override
|
||||
public void configure(SpringProcessEngineConfiguration engineConfiguration) {
|
||||
engineConfiguration.setActivityFontName(flowableProperties.getActivityFontName());
|
||||
engineConfiguration.setLabelFontName(flowableProperties.getLabelFontName());
|
||||
engineConfiguration.setAnnotationFontName(flowableProperties.getAnnotationFontName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.constant;
|
||||
|
||||
/**
|
||||
* 流程常量.
|
||||
*
|
||||
* @author zhuangqian
|
||||
*/
|
||||
public interface FlowEngineConstant {
|
||||
|
||||
String FLOWABLE_BASE_PACKAGES = "org.flowable.ui";
|
||||
|
||||
String SUFFIX = ".bpmn20.xml";
|
||||
|
||||
String ACTIVE = "active";
|
||||
|
||||
String SUSPEND = "suspend";
|
||||
|
||||
String STATUS_TODO = "todo";
|
||||
|
||||
String STATUS_CLAIM = "claim";
|
||||
|
||||
String STATUS_SEND = "send";
|
||||
|
||||
String STATUS_DONE = "done";
|
||||
|
||||
String STATUS_FINISHED = "finished";
|
||||
|
||||
String STATUS_UNFINISHED = "unfinished";
|
||||
|
||||
String STATUS_FINISH = "finish";
|
||||
|
||||
String START_EVENT = "startEvent";
|
||||
|
||||
String END_EVENT = "endEvent";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.core.mp.support.Condition;
|
||||
import org.springblade.core.mp.support.Query;
|
||||
import org.springblade.core.secure.annotation.IsAdministrator;
|
||||
import org.springblade.core.tenant.annotation.NonDS;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.flow.engine.entity.FlowExecution;
|
||||
import org.springblade.flow.engine.service.FlowEngineService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 流程状态控制器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@NonDS
|
||||
@RestController
|
||||
@RequestMapping("/follow")
|
||||
@AllArgsConstructor
|
||||
@IsAdministrator
|
||||
@Hidden
|
||||
public class FlowFollowController {
|
||||
|
||||
private final FlowEngineService flowEngineService;
|
||||
|
||||
/**
|
||||
* 流程状态列表
|
||||
*/
|
||||
@GetMapping("list")
|
||||
@ApiOperationSupport(order = 1)
|
||||
@Operation(summary = "分页", description = "传入notice")
|
||||
public R<IPage<FlowExecution>> list(Query query, @Parameter(description = "流程实例id") String processInstanceId, @Parameter(description = "流程key") String processDefinitionKey) {
|
||||
IPage<FlowExecution> pages = flowEngineService.selectFollowPage(Condition.getPage(query), processInstanceId, processDefinitionKey);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除流程实例
|
||||
*/
|
||||
@PostMapping("delete-process-instance")
|
||||
@ApiOperationSupport(order = 2)
|
||||
@Operation(summary = "删除", description = "传入主键集合")
|
||||
public R deleteProcessInstance(@Parameter(description = "流程实例id") @RequestParam String processInstanceId, @Parameter(description = "删除原因") @RequestParam String deleteReason) {
|
||||
boolean temp = flowEngineService.deleteProcessInstance(processInstanceId, deleteReason);
|
||||
return R.status(temp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.core.mp.support.Condition;
|
||||
import org.springblade.core.mp.support.Query;
|
||||
import org.springblade.core.secure.annotation.IsAdministrator;
|
||||
import org.springblade.core.tenant.annotation.NonDS;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.support.Kv;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.flow.engine.constant.FlowEngineConstant;
|
||||
import org.springblade.flow.engine.entity.FlowProcess;
|
||||
import org.springblade.flow.engine.service.FlowEngineService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 流程管理接口
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@NonDS
|
||||
@RestController
|
||||
@RequestMapping("/manager")
|
||||
@AllArgsConstructor
|
||||
@Tag(name = "流程管理接口", description = "流程管理接口")
|
||||
@IsAdministrator
|
||||
@Hidden
|
||||
public class FlowManagerController {
|
||||
|
||||
private final FlowEngineService flowEngineService;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
@GetMapping("list")
|
||||
@ApiOperationSupport(order = 1)
|
||||
@Operation(summary = "分页", description = "传入流程类型")
|
||||
public R<IPage<FlowProcess>> list(@Parameter(description = "流程类型") String category, Query query, @RequestParam(required = false, defaultValue = "1") Integer mode) {
|
||||
IPage<FlowProcess> pages = flowEngineService.selectProcessPage(Condition.getPage(query), category, mode);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 变更流程状态
|
||||
*
|
||||
* @param state 状态
|
||||
* @param processId 流程id
|
||||
*/
|
||||
@PostMapping("change-state")
|
||||
@ApiOperationSupport(order = 2)
|
||||
@Operation(summary = "变更流程状态", description = "传入state,processId")
|
||||
public R changeState(@RequestParam String state, @RequestParam String processId) {
|
||||
String msg = flowEngineService.changeState(state, processId);
|
||||
return R.success(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除部署流程
|
||||
*
|
||||
* @param deploymentIds 部署流程id集合
|
||||
*/
|
||||
@PostMapping("delete-deployment")
|
||||
@ApiOperationSupport(order = 3)
|
||||
@Operation(summary = "删除部署流程", description = "部署流程id集合")
|
||||
public R deleteDeployment(String deploymentIds) {
|
||||
return R.status(flowEngineService.deleteDeployment(deploymentIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查流程文件格式
|
||||
*
|
||||
* @param file 流程文件
|
||||
*/
|
||||
@PostMapping("check-upload")
|
||||
@ApiOperationSupport(order = 4)
|
||||
@Operation(summary = "上传部署流程文件", description = "传入文件")
|
||||
public R checkUpload(@RequestParam MultipartFile file) {
|
||||
boolean temp = Objects.requireNonNull(file.getOriginalFilename()).endsWith(FlowEngineConstant.SUFFIX);
|
||||
return R.data(Kv.create().set("name", file.getOriginalFilename()).set("success", temp));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传部署流程文件
|
||||
*
|
||||
* @param files 流程文件
|
||||
* @param category 类型
|
||||
*/
|
||||
@PostMapping("deploy-upload")
|
||||
@ApiOperationSupport(order = 5)
|
||||
@Operation(summary = "上传部署流程文件", description = "传入文件")
|
||||
public R deployUpload(@RequestParam List<MultipartFile> files,
|
||||
@RequestParam String category,
|
||||
@RequestParam(required = false, defaultValue = "") String tenantIds) {
|
||||
return R.status(flowEngineService.deployUpload(files, category, Func.toStrList(tenantIds)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.core.mp.support.Condition;
|
||||
import org.springblade.core.mp.support.Query;
|
||||
import org.springblade.core.secure.annotation.IsAdministrator;
|
||||
import org.springblade.core.tenant.annotation.NonDS;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.xss.annotation.XssIgnore;
|
||||
import org.springblade.flow.engine.entity.FlowModel;
|
||||
import org.springblade.flow.engine.service.FlowEngineService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 流程模型控制器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@NonDS
|
||||
@RestController
|
||||
@RequestMapping("/model")
|
||||
@AllArgsConstructor
|
||||
@IsAdministrator
|
||||
@Hidden
|
||||
public class FlowModelController {
|
||||
|
||||
private final FlowEngineService flowEngineService;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Parameters({
|
||||
@Parameter(name = "modelKey", description = "模型标识", in = ParameterIn.QUERY, schema = @Schema(type = "string")),
|
||||
@Parameter(name = "name", description = "模型名称", in = ParameterIn.QUERY, schema = @Schema(type = "string"))
|
||||
})
|
||||
@ApiOperationSupport(order = 1)
|
||||
@Operation(summary = "分页", description = "传入notice")
|
||||
public R<IPage<FlowModel>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> flow, Query query) {
|
||||
IPage<FlowModel> pages = flowEngineService.page(Condition.getPage(query), Condition.getQueryWrapper(flow, FlowModel.class)
|
||||
.select("id,model_key modelKey,name,description,version,created,last_updated lastUpdated")
|
||||
.orderByDesc("last_updated"));
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
@PostMapping("/remove")
|
||||
@ApiOperationSupport(order = 2)
|
||||
@Operation(summary = "删除", description = "传入主键集合")
|
||||
public R remove(@Parameter(description = "主键集合") @RequestParam String ids) {
|
||||
boolean temp = flowEngineService.removeByIds(Func.toStrList(ids));
|
||||
return R.status(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署
|
||||
*/
|
||||
@PostMapping("/deploy")
|
||||
@ApiOperationSupport(order = 3)
|
||||
@Operation(summary = "部署", description = "传入模型id和分类")
|
||||
public R deploy(@Parameter(description = "模型id") @RequestParam String modelId,
|
||||
@Parameter(description = "工作流分类") @RequestParam String category,
|
||||
@Parameter(description = "租户ID") @RequestParam(required = false, defaultValue = "") String tenantIds) {
|
||||
boolean temp = flowEngineService.deployModel(modelId, category, Func.toStrList(tenantIds));
|
||||
return R.status(temp);
|
||||
}
|
||||
|
||||
@XssIgnore
|
||||
@PostMapping("submit")
|
||||
@ApiOperationSupport(order = 4)
|
||||
@Operation(summary = "保存/编辑")
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "模型id"),
|
||||
@Parameter(name = "name", description = "模型名称", required = true),
|
||||
@Parameter(name = "modelKey", description = "模型key", required = true),
|
||||
@Parameter(name = "description", description = "模型描述"),
|
||||
@Parameter(name = "xml", description = "模型xml", required = true),
|
||||
})
|
||||
public R<FlowModel> submit(@RequestBody @Parameter(hidden = true) FlowModel model) {
|
||||
return R.data(flowEngineService.submitModel(model));
|
||||
}
|
||||
|
||||
@GetMapping("detail")
|
||||
@Operation(summary = "详情")
|
||||
@ApiOperationSupport(order = 5)
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "模型id", required = true),
|
||||
})
|
||||
public R<FlowModel> detail(String id) {
|
||||
return R.data(flowEngineService.getById(id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.launch.constant.AppConstant;
|
||||
import org.springblade.core.tenant.annotation.NonDS;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.flow.core.pojo.entity.BladeFlow;
|
||||
import org.springblade.flow.engine.service.FlowEngineService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 流程通用控制器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@NonDS
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/process")
|
||||
@Hidden
|
||||
public class FlowProcessController {
|
||||
|
||||
private static final String IMAGE_NAME = "image";
|
||||
private final FlowEngineService flowEngineService;
|
||||
|
||||
/**
|
||||
* 获取流转历史列表
|
||||
*
|
||||
* @param processInstanceId 流程实例id
|
||||
* @param startActivityId 开始节点id
|
||||
* @param endActivityId 结束节点id
|
||||
*/
|
||||
@GetMapping(value = "history-flow-list")
|
||||
public R<List<BladeFlow>> historyFlowList(@RequestParam String processInstanceId, String startActivityId, String endActivityId) {
|
||||
return R.data(flowEngineService.historyFlowList(processInstanceId, startActivityId, endActivityId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程节点进程图
|
||||
*
|
||||
* @param processDefinitionId 流程id
|
||||
* @param processInstanceId 流程实例id
|
||||
*/
|
||||
@GetMapping(value = "model-view")
|
||||
public R modelView(String processDefinitionId, String processInstanceId) {
|
||||
return R.data(flowEngineService.modelView(processDefinitionId, processInstanceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程节点进程图
|
||||
*
|
||||
* @param processInstanceId 流程实例id
|
||||
* @param httpServletResponse http响应
|
||||
*/
|
||||
@GetMapping(value = "diagram-view")
|
||||
public void diagramView(String processInstanceId, HttpServletResponse httpServletResponse) {
|
||||
flowEngineService.diagramView(processInstanceId, httpServletResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程图展示
|
||||
*
|
||||
* @param processDefinitionId 流程id
|
||||
* @param processInstanceId 实例id
|
||||
* @param resourceType 资源类型
|
||||
* @param response 响应
|
||||
*/
|
||||
@GetMapping("resource-view")
|
||||
public void resourceView(@RequestParam String processDefinitionId, String processInstanceId, @RequestParam(defaultValue = IMAGE_NAME) String resourceType, HttpServletResponse response) {
|
||||
flowEngineService.resourceView(processDefinitionId, processInstanceId, resourceType, response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 运行实体类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
public class FlowExecution implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String startUserId;
|
||||
private String startUser;
|
||||
private Date startTime;
|
||||
private String taskDefinitionId;
|
||||
private String taskDefinitionKey;
|
||||
private String category;
|
||||
private String categoryName;
|
||||
private String processInstanceId;
|
||||
private String processDefinitionId;
|
||||
private String processDefinitionKey;
|
||||
private String activityId;
|
||||
private int suspensionState;
|
||||
private String executionId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 流程模型
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@TableName("ACT_DE_MODEL")
|
||||
public class FlowModel implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int MODEL_TYPE_BPMN = 0;
|
||||
public static final int MODEL_TYPE_FORM = 2;
|
||||
public static final int MODEL_TYPE_APP = 3;
|
||||
public static final int MODEL_TYPE_DECISION_TABLE = 4;
|
||||
public static final int MODEL_TYPE_CMMN = 5;
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private String modelKey;
|
||||
private String description;
|
||||
private Date created;
|
||||
private Date lastUpdated;
|
||||
private String createdBy;
|
||||
private String lastUpdatedBy;
|
||||
private Integer version;
|
||||
private String modelEditorJson;
|
||||
private String modelComment;
|
||||
private Integer modelType;
|
||||
private String tenantId;
|
||||
private byte[] thumbnail;
|
||||
private String modelEditorXml;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntityImpl;
|
||||
import org.springblade.flow.engine.utils.FlowCache;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* FlowProcess
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class FlowProcess implements Serializable {
|
||||
|
||||
private String id;
|
||||
private String tenantId;
|
||||
private String name;
|
||||
private String key;
|
||||
private String category;
|
||||
private String categoryName;
|
||||
private Integer version;
|
||||
private String deploymentId;
|
||||
private String resourceName;
|
||||
private String diagramResourceName;
|
||||
private Integer suspensionState;
|
||||
private Date deploymentTime;
|
||||
|
||||
public FlowProcess(ProcessDefinitionEntityImpl entity) {
|
||||
if (entity != null) {
|
||||
this.id = entity.getId();
|
||||
this.tenantId = entity.getTenantId();
|
||||
this.name = entity.getName();
|
||||
this.key = entity.getKey();
|
||||
this.category = entity.getCategory();
|
||||
this.categoryName = FlowCache.getCategoryName(entity.getCategory());
|
||||
this.version = entity.getVersion();
|
||||
this.deploymentId = entity.getDeploymentId();
|
||||
this.resourceName = entity.getResourceName();
|
||||
this.diagramResourceName = entity.getDiagramResourceName();
|
||||
this.suspensionState = entity.getSuspensionState();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springblade.flow.engine.entity.FlowModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* FlowMapper.
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface FlowMapper extends BaseMapper<FlowModel> {
|
||||
|
||||
/**
|
||||
* 自定义分页
|
||||
* @param page
|
||||
* @param flowModel
|
||||
* @return
|
||||
*/
|
||||
List<FlowModel> selectFlowPage(IPage page, FlowModel flowModel);
|
||||
|
||||
/**
|
||||
* 获取模型
|
||||
* @param parentModelId
|
||||
* @return
|
||||
*/
|
||||
List<FlowModel> findByParentModelId(String parentModelId);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.springblade.flow.engine.mapper.FlowMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="flowModelResultMap" type="org.springblade.flow.engine.entity.FlowModel">
|
||||
<result column="id" property="id"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="model_key" property="modelKey"/>
|
||||
<result column="description" property="description"/>
|
||||
<result column="model_comment" property="modelComment"/>
|
||||
<result column="created" property="created"/>
|
||||
<result column="created_by" property="createdBy"/>
|
||||
<result column="last_updated" property="lastUpdated"/>
|
||||
<result column="last_updated_by" property="lastUpdatedBy"/>
|
||||
<result column="version" property="version"/>
|
||||
<result column="model_editor_json" property="modelEditorJson"/>
|
||||
<result column="thumbnail" property="thumbnail"/>
|
||||
<result column="model_type" property="modelType"/>
|
||||
<result column="tenant_id" property="tenantId"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectFlowPage" resultMap="flowModelResultMap">
|
||||
SELECT
|
||||
a.id,
|
||||
a.name,
|
||||
a.model_key,
|
||||
a.description,
|
||||
a.model_comment,
|
||||
a.created,
|
||||
a.created_by,
|
||||
a.last_updated,
|
||||
a.last_updated_by,
|
||||
a.version,
|
||||
a.model_editor_json,
|
||||
a.thumbnail,
|
||||
a.model_type,
|
||||
a.tenant_id
|
||||
FROM
|
||||
ACT_DE_MODEL a
|
||||
WHERE
|
||||
1 = 1
|
||||
ORDER BY
|
||||
a.created DESC
|
||||
</select>
|
||||
|
||||
<select id="findByParentModelId" parameterType="string" resultMap="flowModelResultMap">
|
||||
select model.* from ACT_DE_MODEL_RELATION modelrelation
|
||||
inner join ACT_DE_MODEL model on modelrelation.model_id = model.id
|
||||
where modelrelation.parent_model_id = #{_parameter}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springblade.flow.core.pojo.entity.BladeFlow;
|
||||
import org.springblade.flow.engine.entity.FlowExecution;
|
||||
import org.springblade.flow.engine.entity.FlowModel;
|
||||
import org.springblade.flow.engine.entity.FlowProcess;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* FlowEngineService
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface FlowEngineService extends IService<FlowModel> {
|
||||
|
||||
/**
|
||||
* 自定义分页
|
||||
*
|
||||
* @param page 分页工具
|
||||
* @param flowModel 流程模型
|
||||
* @return
|
||||
*/
|
||||
IPage<FlowModel> selectFlowPage(IPage<FlowModel> page, FlowModel flowModel);
|
||||
|
||||
/**
|
||||
* 流程管理列表
|
||||
*
|
||||
* @param page 分页工具
|
||||
* @param category 分类
|
||||
* @param mode 形态
|
||||
* @return
|
||||
*/
|
||||
IPage<FlowProcess> selectProcessPage(IPage<FlowProcess> page, String category, Integer mode);
|
||||
|
||||
/**
|
||||
* 流程管理列表
|
||||
*
|
||||
* @param page 分页工具
|
||||
* @param processInstanceId 流程实例id
|
||||
* @param processDefinitionKey 流程key
|
||||
* @return
|
||||
*/
|
||||
IPage<FlowExecution> selectFollowPage(IPage<FlowExecution> page, String processInstanceId, String processDefinitionKey);
|
||||
|
||||
/**
|
||||
* 获取流转历史列表
|
||||
*
|
||||
* @param processInstanceId 流程实例id
|
||||
* @param startActivityId 开始节点id
|
||||
* @param endActivityId 结束节点id
|
||||
* @return
|
||||
*/
|
||||
List<BladeFlow> historyFlowList(String processInstanceId, String startActivityId, String endActivityId);
|
||||
|
||||
/**
|
||||
* 变更流程状态
|
||||
*
|
||||
* @param state 状态
|
||||
* @param processId 流程ID
|
||||
* @return
|
||||
*/
|
||||
String changeState(String state, String processId);
|
||||
|
||||
/**
|
||||
* 删除部署流程
|
||||
*
|
||||
* @param deploymentIds 部署流程id集合
|
||||
* @return
|
||||
*/
|
||||
boolean deleteDeployment(String deploymentIds);
|
||||
|
||||
/**
|
||||
* 上传部署流程
|
||||
*
|
||||
* @param files 流程配置文件
|
||||
* @param category 流程分类
|
||||
* @param tenantIdList 租户id集合
|
||||
* @return
|
||||
*/
|
||||
boolean deployUpload(List<MultipartFile> files, String category, List<String> tenantIdList);
|
||||
|
||||
/**
|
||||
* 部署流程
|
||||
*
|
||||
* @param modelId 模型id
|
||||
* @param category 分类
|
||||
* @param tenantIdList 租户id集合
|
||||
* @return
|
||||
*/
|
||||
boolean deployModel(String modelId, String category, List<String> tenantIdList);
|
||||
|
||||
/**
|
||||
* 删除流程实例
|
||||
*
|
||||
* @param processInstanceId 流程实例id
|
||||
* @param deleteReason 删除原因
|
||||
* @return
|
||||
*/
|
||||
boolean deleteProcessInstance(String processInstanceId, String deleteReason);
|
||||
|
||||
/**
|
||||
* 保存/更新模型
|
||||
*
|
||||
* @param model 模型
|
||||
* @return 模型
|
||||
*/
|
||||
FlowModel submitModel(FlowModel model);
|
||||
|
||||
/**
|
||||
* 流程节点进程图
|
||||
*
|
||||
* @param processDefinitionId
|
||||
* @param processInstanceId
|
||||
* @return
|
||||
*/
|
||||
Map<String, Object> modelView(String processDefinitionId, String processInstanceId);
|
||||
|
||||
/**
|
||||
* 流程节点进程图
|
||||
*
|
||||
* @param processInstanceId
|
||||
* @param httpServletResponse
|
||||
*/
|
||||
void diagramView(String processInstanceId, HttpServletResponse httpServletResponse);
|
||||
|
||||
/**
|
||||
* 流程图展示
|
||||
*
|
||||
* @param processDefinitionId
|
||||
* @param processInstanceId
|
||||
* @param resourceType
|
||||
* @param response
|
||||
*/
|
||||
void resourceView(String processDefinitionId, String processInstanceId, String resourceType, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 获取XML
|
||||
*
|
||||
* @param model
|
||||
* @return
|
||||
*/
|
||||
byte[] getModelEditorXML(FlowModel model);
|
||||
}
|
||||
@@ -0,0 +1,568 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||
import org.flowable.bpmn.model.BpmnModel;
|
||||
import org.flowable.bpmn.model.Process;
|
||||
import org.flowable.common.engine.impl.util.IoUtil;
|
||||
import org.flowable.common.engine.impl.util.io.StringStreamSource;
|
||||
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
|
||||
import org.flowable.editor.language.json.converter.BpmnJsonConverterContext;
|
||||
import org.flowable.editor.language.json.converter.CustomBpmnJsonConverterContext;
|
||||
import org.flowable.engine.*;
|
||||
import org.flowable.engine.history.HistoricActivityInstance;
|
||||
import org.flowable.engine.history.HistoricProcessInstance;
|
||||
import org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl;
|
||||
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntityImpl;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
import org.flowable.engine.repository.ProcessDefinitionQuery;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.flowable.engine.runtime.ProcessInstanceQuery;
|
||||
import org.flowable.engine.task.Comment;
|
||||
import org.flowable.image.ProcessDiagramGenerator;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.FileUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.flow.core.pojo.entity.BladeFlow;
|
||||
import org.springblade.flow.core.pojo.enums.FlowModeEnum;
|
||||
import org.springblade.flow.core.utils.TaskUtil;
|
||||
import org.springblade.flow.engine.constant.FlowEngineConstant;
|
||||
import org.springblade.flow.engine.entity.FlowExecution;
|
||||
import org.springblade.flow.engine.entity.FlowModel;
|
||||
import org.springblade.flow.engine.entity.FlowProcess;
|
||||
import org.springblade.flow.engine.mapper.FlowMapper;
|
||||
import org.springblade.flow.engine.service.FlowEngineService;
|
||||
import org.springblade.flow.engine.utils.FlowCache;
|
||||
import org.springblade.system.cache.UserCache;
|
||||
import org.springblade.system.pojo.entity.User;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工作流服务实现类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class FlowEngineServiceImpl extends ServiceImpl<FlowMapper, FlowModel> implements FlowEngineService {
|
||||
private static final String ALREADY_IN_STATE = "already in state";
|
||||
private static final String USR_TASK = "userTask";
|
||||
private static final String IMAGE_NAME = "image";
|
||||
private static final String XML_NAME = "xml";
|
||||
private static final Integer INT_1024 = 1024;
|
||||
private static final BpmnJsonConverter BPMN_JSON_CONVERTER = new BpmnJsonConverter();
|
||||
private static final BpmnXMLConverter BPMN_XML_CONVERTER = new BpmnXMLConverter();
|
||||
private final ObjectMapper objectMapper;
|
||||
private final RepositoryService repositoryService;
|
||||
private final RuntimeService runtimeService;
|
||||
private final HistoryService historyService;
|
||||
private final TaskService taskService;
|
||||
private final ProcessEngine processEngine;
|
||||
|
||||
@Override
|
||||
public IPage<FlowModel> selectFlowPage(IPage<FlowModel> page, FlowModel flowModel) {
|
||||
return page.setRecords(baseMapper.selectFlowPage(page, flowModel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<FlowProcess> selectProcessPage(IPage<FlowProcess> page, String category, Integer mode) {
|
||||
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionKey().asc();
|
||||
// 通用流程
|
||||
if (mode == FlowModeEnum.COMMON.getMode()) {
|
||||
processDefinitionQuery.processDefinitionWithoutTenantId();
|
||||
}
|
||||
// 定制流程
|
||||
else if (!AuthUtil.isAdministrator()) {
|
||||
processDefinitionQuery.processDefinitionTenantId(AuthUtil.getTenantId());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(category)) {
|
||||
processDefinitionQuery.processDefinitionCategory(category);
|
||||
}
|
||||
List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(Func.toInt((page.getCurrent() - 1) * page.getSize()), Func.toInt(page.getSize()));
|
||||
List<FlowProcess> flowProcessList = new ArrayList<>();
|
||||
processDefinitionList.forEach(processDefinition -> {
|
||||
String deploymentId = processDefinition.getDeploymentId();
|
||||
Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
|
||||
FlowProcess flowProcess = new FlowProcess((ProcessDefinitionEntityImpl) processDefinition);
|
||||
flowProcess.setDeploymentTime(deployment.getDeploymentTime());
|
||||
flowProcessList.add(flowProcess);
|
||||
});
|
||||
page.setTotal(processDefinitionQuery.count());
|
||||
page.setRecords(flowProcessList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<FlowExecution> selectFollowPage(IPage<FlowExecution> page, String processInstanceId, String processDefinitionKey) {
|
||||
ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
|
||||
if (StringUtil.isNotBlank(processInstanceId)) {
|
||||
processInstanceQuery.processInstanceId(processInstanceId);
|
||||
}
|
||||
if (StringUtil.isNotBlank(processDefinitionKey)) {
|
||||
processInstanceQuery.processDefinitionKey(processDefinitionKey);
|
||||
}
|
||||
List<FlowExecution> flowList = new ArrayList<>();
|
||||
List<ProcessInstance> procInsList = processInstanceQuery.listPage(Func.toInt((page.getCurrent() - 1) * page.getSize()), Func.toInt(page.getSize()));
|
||||
procInsList.forEach(processInstance -> {
|
||||
ExecutionEntityImpl execution = (ExecutionEntityImpl) processInstance;
|
||||
FlowExecution flowExecution = new FlowExecution();
|
||||
flowExecution.setId(execution.getId());
|
||||
flowExecution.setName(execution.getName());
|
||||
flowExecution.setStartUserId(execution.getStartUserId());
|
||||
User taskUser = UserCache.getUserByTaskUser(execution.getStartUserId());
|
||||
if (taskUser != null) {
|
||||
flowExecution.setStartUser(taskUser.getName());
|
||||
}
|
||||
flowExecution.setStartTime(execution.getStartTime());
|
||||
flowExecution.setExecutionId(execution.getId());
|
||||
flowExecution.setProcessInstanceId(execution.getProcessInstanceId());
|
||||
flowExecution.setProcessDefinitionId(execution.getProcessDefinitionId());
|
||||
flowExecution.setProcessDefinitionKey(execution.getProcessDefinitionKey());
|
||||
flowExecution.setSuspensionState(execution.getSuspensionState());
|
||||
FlowProcess processDefinition = FlowCache.getProcessDefinition(execution.getProcessDefinitionId());
|
||||
flowExecution.setCategory(processDefinition.getCategory());
|
||||
flowExecution.setCategoryName(FlowCache.getCategoryName(processDefinition.getCategory()));
|
||||
flowList.add(flowExecution);
|
||||
});
|
||||
page.setTotal(processInstanceQuery.count());
|
||||
page.setRecords(flowList);
|
||||
return page;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BladeFlow> historyFlowList(String processInstanceId, String startActivityId, String endActivityId) {
|
||||
List<BladeFlow> flowList = new LinkedList<>();
|
||||
List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().orderByHistoricActivityInstanceEndTime().asc().list();
|
||||
boolean start = false;
|
||||
Map<String, Integer> activityMap = new HashMap<>(16);
|
||||
for (int i = 0; i < historicActivityInstanceList.size(); i++) {
|
||||
HistoricActivityInstance historicActivityInstance = historicActivityInstanceList.get(i);
|
||||
// 过滤开始节点前的节点
|
||||
if (StringUtil.isNotBlank(startActivityId) && startActivityId.equals(historicActivityInstance.getActivityId())) {
|
||||
start = true;
|
||||
}
|
||||
if (StringUtil.isNotBlank(startActivityId) && !start) {
|
||||
continue;
|
||||
}
|
||||
// 显示开始节点和结束节点,并且执行人不为空的任务
|
||||
if (StringUtils.equals(USR_TASK, historicActivityInstance.getActivityType())
|
||||
|| FlowEngineConstant.START_EVENT.equals(historicActivityInstance.getActivityType())
|
||||
|| FlowEngineConstant.END_EVENT.equals(historicActivityInstance.getActivityType())) {
|
||||
// 给节点增加序号
|
||||
activityMap.computeIfAbsent(historicActivityInstance.getActivityId(), k -> activityMap.size());
|
||||
BladeFlow flow = new BladeFlow();
|
||||
flow.setHistoryActivityId(historicActivityInstance.getActivityId());
|
||||
flow.setHistoryActivityName(historicActivityInstance.getActivityName());
|
||||
flow.setCreateTime(historicActivityInstance.getStartTime());
|
||||
flow.setEndTime(historicActivityInstance.getEndTime());
|
||||
String durationTime = DateUtil.secondToTime(Func.toLong(historicActivityInstance.getDurationInMillis(), 0L) / 1000);
|
||||
flow.setHistoryActivityDurationTime(durationTime);
|
||||
// 获取流程发起人名称
|
||||
if (FlowEngineConstant.START_EVENT.equals(historicActivityInstance.getActivityType())) {
|
||||
List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).orderByProcessInstanceStartTime().asc().list();
|
||||
if (!processInstanceList.isEmpty()) {
|
||||
if (StringUtil.isNotBlank(processInstanceList.get(0).getStartUserId())) {
|
||||
String taskUser = processInstanceList.get(0).getStartUserId();
|
||||
User user = UserCache.getUser(TaskUtil.getUserId(taskUser));
|
||||
if (user != null) {
|
||||
flow.setAssignee(historicActivityInstance.getAssignee());
|
||||
flow.setAssigneeName(user.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 获取任务执行人名称
|
||||
if (StringUtil.isNotBlank(historicActivityInstance.getAssignee())) {
|
||||
User user = UserCache.getUser(TaskUtil.getUserId(historicActivityInstance.getAssignee()));
|
||||
if (user != null) {
|
||||
flow.setAssignee(historicActivityInstance.getAssignee());
|
||||
flow.setAssigneeName(user.getName());
|
||||
}
|
||||
}
|
||||
// 获取意见评论内容
|
||||
if (StringUtil.isNotBlank(historicActivityInstance.getTaskId())) {
|
||||
List<Comment> commentList = taskService.getTaskComments(historicActivityInstance.getTaskId());
|
||||
if (!commentList.isEmpty()) {
|
||||
flow.setComment(commentList.get(0).getFullMessage());
|
||||
}
|
||||
}
|
||||
flowList.add(flow);
|
||||
}
|
||||
// 过滤结束节点后的节点
|
||||
if (StringUtils.isNotBlank(endActivityId) && endActivityId.equals(historicActivityInstance.getActivityId())) {
|
||||
boolean temp = false;
|
||||
Integer activityNum = activityMap.get(historicActivityInstance.getActivityId());
|
||||
// 该活动节点,后续节点是否在结束节点之前,在后续节点中是否存在
|
||||
for (int j = i + 1; j < historicActivityInstanceList.size(); j++) {
|
||||
HistoricActivityInstance hi = historicActivityInstanceList.get(j);
|
||||
Integer activityNumA = activityMap.get(hi.getActivityId());
|
||||
boolean numberTemp = activityNumA != null && activityNumA < activityNum;
|
||||
boolean equalsTemp = StringUtils.equals(hi.getActivityId(), historicActivityInstance.getActivityId());
|
||||
if (numberTemp || equalsTemp) {
|
||||
temp = true;
|
||||
}
|
||||
}
|
||||
if (!temp) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flowList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String changeState(String state, String processId) {
|
||||
try {
|
||||
if (state.equals(FlowEngineConstant.ACTIVE)) {
|
||||
repositoryService.activateProcessDefinitionById(processId, true, null);
|
||||
return StringUtil.format("激活ID为 [{}] 的流程成功", processId);
|
||||
} else if (state.equals(FlowEngineConstant.SUSPEND)) {
|
||||
repositoryService.suspendProcessDefinitionById(processId, true, null);
|
||||
return StringUtil.format("挂起ID为 [{}] 的流程成功", processId);
|
||||
} else {
|
||||
return "暂无流程变更";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage().contains(ALREADY_IN_STATE)) {
|
||||
return StringUtil.format("ID为 [{}] 的流程已是此状态,无需操作", processId);
|
||||
}
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteDeployment(String deploymentIds) {
|
||||
Func.toStrList(deploymentIds).forEach(deploymentId -> repositoryService.deleteDeployment(deploymentId, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deployUpload(List<MultipartFile> files, String category, List<String> tenantIdList) {
|
||||
files.forEach(file -> {
|
||||
try {
|
||||
String fileName = file.getOriginalFilename();
|
||||
InputStream fileInputStream = file.getInputStream();
|
||||
byte[] bytes = FileUtil.copyToByteArray(fileInputStream);
|
||||
if (Func.isNotEmpty(tenantIdList)) {
|
||||
tenantIdList.forEach(tenantId -> {
|
||||
Deployment deployment = repositoryService.createDeployment().addBytes(fileName, bytes).tenantId(tenantId).deploy();
|
||||
deploy(deployment, category);
|
||||
});
|
||||
} else {
|
||||
Deployment deployment = repositoryService.createDeployment().addBytes(fileName, bytes).deploy();
|
||||
deploy(deployment, category);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deployModel(String modelId, String category, List<String> tenantIdList) {
|
||||
FlowModel model = this.getById(modelId);
|
||||
if (model == null) {
|
||||
throw new ServiceException("未找到模型 id: " + modelId);
|
||||
}
|
||||
byte[] bytes = getBpmnXML(model);
|
||||
String processName = model.getName();
|
||||
if (!StringUtil.endsWithIgnoreCase(processName, FlowEngineConstant.SUFFIX)) {
|
||||
processName += FlowEngineConstant.SUFFIX;
|
||||
}
|
||||
String finalProcessName = processName;
|
||||
if (Func.isNotEmpty(tenantIdList)) {
|
||||
tenantIdList.forEach(tenantId -> {
|
||||
Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes).name(model.getName()).key(model.getModelKey()).tenantId(tenantId).deploy();
|
||||
deploy(deployment, category);
|
||||
});
|
||||
} else {
|
||||
Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes).name(model.getName()).key(model.getModelKey()).deploy();
|
||||
deploy(deployment, category);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteProcessInstance(String processInstanceId, String deleteReason) {
|
||||
runtimeService.deleteProcessInstance(processInstanceId, deleteReason);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void deploy(Deployment deployment, String category) {
|
||||
log.debug("流程部署--------deploy: " + deployment + " 分类---------->" + category);
|
||||
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
|
||||
StringBuilder logBuilder = new StringBuilder(500);
|
||||
List<Object> logArgs = new ArrayList<>();
|
||||
// 设置流程分类
|
||||
for (ProcessDefinition processDefinition : list) {
|
||||
if (StringUtil.isNotBlank(category)) {
|
||||
repositoryService.setProcessDefinitionCategory(processDefinition.getId(), category);
|
||||
}
|
||||
logBuilder.append("部署成功,流程ID={} \n");
|
||||
logArgs.add(processDefinition.getId());
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
throw new ServiceException("部署失败,未找到流程");
|
||||
} else {
|
||||
log.info(logBuilder.toString(), logArgs.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowModel submitModel(FlowModel model) {
|
||||
FlowModel flowModel = new FlowModel();
|
||||
flowModel.setId(model.getId());
|
||||
flowModel.setVersion(Func.toInt(model.getVersion(), 0) + 1);
|
||||
flowModel.setName(model.getName());
|
||||
flowModel.setModelKey(model.getModelKey());
|
||||
flowModel.setModelType(FlowModel.MODEL_TYPE_BPMN);
|
||||
flowModel.setCreatedBy(TaskUtil.getTaskUser());
|
||||
flowModel.setDescription(model.getDescription());
|
||||
flowModel.setLastUpdated(Calendar.getInstance().getTime());
|
||||
flowModel.setLastUpdatedBy(TaskUtil.getTaskUser());
|
||||
flowModel.setTenantId(AuthUtil.getTenantId());
|
||||
flowModel.setModelEditorXml(model.getModelEditorXml());
|
||||
if (StringUtil.isBlank(model.getId())) {
|
||||
flowModel.setCreated(Calendar.getInstance().getTime());
|
||||
}
|
||||
if (StringUtil.isNotBlank(model.getModelEditorXml())) {
|
||||
flowModel.setModelEditorJson(getBpmnJson(model.getModelEditorXml()));
|
||||
}
|
||||
this.saveOrUpdate(flowModel);
|
||||
return flowModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> modelView(String processDefinitionId, String processInstanceId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
// 节点标记
|
||||
if (StringUtil.isNotBlank(processInstanceId)) {
|
||||
result.put("flow", this.historyFlowList(processInstanceId, null, null));
|
||||
HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
|
||||
.processInstanceId(processInstanceId)
|
||||
.singleResult();
|
||||
processDefinitionId = processInstance.getProcessDefinitionId();
|
||||
}
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
||||
// 流程图展示
|
||||
result.put("xml", new String(new BpmnXMLConverter().convertToXML(bpmnModel)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void diagramView(String processInstanceId, HttpServletResponse httpServletResponse) {
|
||||
// 获得当前活动的节点
|
||||
String processDefinitionId;
|
||||
// 如果流程已经结束,则得到结束节点
|
||||
if (this.isFinished(processInstanceId)) {
|
||||
HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
processDefinitionId = pi.getProcessDefinitionId();
|
||||
} else {
|
||||
// 如果流程没有结束,则取当前活动节点
|
||||
// 根据流程实例ID获得当前处于活动状态的ActivityId合集
|
||||
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
processDefinitionId = pi.getProcessDefinitionId();
|
||||
}
|
||||
List<String> highLightedActivities = new ArrayList<>();
|
||||
|
||||
// 获得活动的节点
|
||||
List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
|
||||
|
||||
for (HistoricActivityInstance tempActivity : highLightedActivityList) {
|
||||
String activityId = tempActivity.getActivityId();
|
||||
highLightedActivities.add(activityId);
|
||||
}
|
||||
|
||||
List<String> flows = new ArrayList<>();
|
||||
// 获取流程图
|
||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
||||
ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
|
||||
|
||||
ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();
|
||||
InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivities, flows, engConf.getActivityFontName(),
|
||||
engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
|
||||
OutputStream out = null;
|
||||
byte[] buf = new byte[1024];
|
||||
int length;
|
||||
try {
|
||||
out = httpServletResponse.getOutputStream();
|
||||
while ((length = in.read(buf)) != -1) {
|
||||
out.write(buf, 0, length);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("操作异常", e);
|
||||
} finally {
|
||||
IoUtil.closeSilently(out);
|
||||
IoUtil.closeSilently(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceView(String processDefinitionId, String processInstanceId, String resourceType, HttpServletResponse response) {
|
||||
if (StringUtil.isAllBlank(processDefinitionId, processInstanceId)) {
|
||||
return;
|
||||
}
|
||||
if (StringUtil.isBlank(processDefinitionId)) {
|
||||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||
processDefinitionId = processInstance.getProcessDefinitionId();
|
||||
}
|
||||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
|
||||
String resourceName = "";
|
||||
if (resourceType.equals(IMAGE_NAME)) {
|
||||
resourceName = processDefinition.getDiagramResourceName();
|
||||
} else if (resourceType.equals(XML_NAME)) {
|
||||
resourceName = processDefinition.getResourceName();
|
||||
}
|
||||
try {
|
||||
InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
|
||||
byte[] b = new byte[1024];
|
||||
int len;
|
||||
while ((len = resourceAsStream.read(b, 0, INT_1024)) != -1) {
|
||||
response.getOutputStream().write(b, 0, len);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getModelEditorXML(FlowModel model) {
|
||||
return getBpmnXML(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已完结
|
||||
*
|
||||
* @param processInstanceId 流程实例id
|
||||
* @return bool
|
||||
*/
|
||||
private boolean isFinished(String processInstanceId) {
|
||||
return historyService.createHistoricProcessInstanceQuery().finished()
|
||||
.processInstanceId(processInstanceId).count() > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* xml转bpmn json
|
||||
*
|
||||
* @param xml xml
|
||||
* @return json
|
||||
*/
|
||||
private String getBpmnJson(String xml) {
|
||||
return BPMN_JSON_CONVERTER.convertToJson(getBpmnModel(xml)).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* xml转bpmnModel
|
||||
*
|
||||
* @param xml xml
|
||||
* @return bpmnModel
|
||||
*/
|
||||
private BpmnModel getBpmnModel(String xml) {
|
||||
return BPMN_XML_CONVERTER.convertToBpmnModel(new StringStreamSource(xml), false, false);
|
||||
}
|
||||
|
||||
private byte[] getBpmnXML(FlowModel model) {
|
||||
BpmnModel bpmnModel = getBpmnModel(model);
|
||||
return getBpmnXML(bpmnModel);
|
||||
}
|
||||
|
||||
private byte[] getBpmnXML(BpmnModel bpmnModel) {
|
||||
for (Process process : bpmnModel.getProcesses()) {
|
||||
if (StringUtils.isNotEmpty(process.getId())) {
|
||||
char firstCharacter = process.getId().charAt(0);
|
||||
if (Character.isDigit(firstCharacter)) {
|
||||
process.setId("a" + process.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return BPMN_XML_CONVERTER.convertToXML(bpmnModel);
|
||||
}
|
||||
|
||||
private BpmnModel getBpmnModel(FlowModel model) {
|
||||
BpmnModel bpmnModel;
|
||||
try {
|
||||
Map<String, FlowModel> formMap = new HashMap<>(16);
|
||||
Map<String, FlowModel> decisionTableMap = new HashMap<>(16);
|
||||
|
||||
List<FlowModel> referencedModels = baseMapper.findByParentModelId(model.getId());
|
||||
for (FlowModel childModel : referencedModels) {
|
||||
if (FlowModel.MODEL_TYPE_FORM == childModel.getModelType()) {
|
||||
formMap.put(childModel.getId(), childModel);
|
||||
|
||||
} else if (FlowModel.MODEL_TYPE_DECISION_TABLE == childModel.getModelType()) {
|
||||
decisionTableMap.put(childModel.getId(), childModel);
|
||||
}
|
||||
}
|
||||
bpmnModel = getBpmnModel(model, formMap, decisionTableMap);
|
||||
} catch (Exception e) {
|
||||
log.error("Could not generate BPMN 2.0 model for {}", model.getId(), e);
|
||||
throw new ServiceException("Could not generate BPMN 2.0 model");
|
||||
}
|
||||
return bpmnModel;
|
||||
}
|
||||
|
||||
private BpmnModel getBpmnModel(FlowModel model, Map<String, FlowModel> formMap, Map<String, FlowModel> decisionTableMap) {
|
||||
try {
|
||||
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(model.getModelEditorJson());
|
||||
Map<String, String> formKeyMap = new HashMap<>(16);
|
||||
for (FlowModel formModel : formMap.values()) {
|
||||
formKeyMap.put(formModel.getId(), formModel.getModelKey());
|
||||
}
|
||||
Map<String, String> decisionTableKeyMap = new HashMap<>(16);
|
||||
for (FlowModel decisionTableModel : decisionTableMap.values()) {
|
||||
decisionTableKeyMap.put(decisionTableModel.getId(), decisionTableModel.getModelKey());
|
||||
}
|
||||
BpmnJsonConverterContext converterContext = new CustomBpmnJsonConverterContext(formKeyMap, decisionTableKeyMap);
|
||||
return BPMN_JSON_CONVERTER.convertToBpmnModel(editorJsonNode, converterContext);
|
||||
} catch (Exception e) {
|
||||
log.error("Could not generate BPMN 2.0 model for {}", model.getId(), e);
|
||||
throw new ServiceException("Could not generate BPMN 2.0 model");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.flow.engine.utils;
|
||||
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntityImpl;
|
||||
import org.flowable.engine.repository.ProcessDefinition;
|
||||
import org.springblade.core.cache.utils.CacheUtil;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.flow.engine.entity.FlowProcess;
|
||||
import org.springblade.system.cache.DictCache;
|
||||
|
||||
/**
|
||||
* 流程缓存
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class FlowCache {
|
||||
|
||||
private static final String FLOW_CACHE = "flow:process";
|
||||
private static final String FLOW_DEFINITION_ID = "definition:id";
|
||||
private static RepositoryService repositoryService;
|
||||
|
||||
private static RepositoryService getRepositoryService() {
|
||||
if (repositoryService == null) {
|
||||
repositoryService = SpringUtil.getBean(RepositoryService.class);
|
||||
}
|
||||
return repositoryService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得流程定义对象
|
||||
*
|
||||
* @param processDefinitionId 流程对象id
|
||||
* @return
|
||||
*/
|
||||
public static FlowProcess getProcessDefinition(String processDefinitionId) {
|
||||
return CacheUtil.get(FLOW_CACHE, FLOW_DEFINITION_ID, processDefinitionId, () -> {
|
||||
ProcessDefinition processDefinition = getRepositoryService().createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
|
||||
ProcessDefinitionEntityImpl processDefinitionEntity = BeanUtil.copyProperties(processDefinition, ProcessDefinitionEntityImpl.class);
|
||||
return new FlowProcess(processDefinitionEntity);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程类型名
|
||||
*
|
||||
* @param category 流程类型
|
||||
* @return
|
||||
*/
|
||||
public static String getCategoryName(String category) {
|
||||
if (Func.isEmpty(category)) {
|
||||
return StringPool.EMPTY;
|
||||
}
|
||||
String[] categoryArr = category.split(StringPool.UNDERSCORE);
|
||||
if (categoryArr.length <= 1) {
|
||||
return StringPool.EMPTY;
|
||||
} else {
|
||||
return DictCache.getValue(category.split(StringPool.UNDERSCORE)[0], Func.toInt(category.split(StringPool.UNDERSCORE)[1]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: ${blade.datasource.flow.dev.url}
|
||||
username: ${blade.datasource.flow.dev.username}
|
||||
password: ${blade.datasource.flow.dev.password}
|
||||
@@ -0,0 +1,6 @@
|
||||
#数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: ${blade.datasource.flow.prod.url}
|
||||
username: ${blade.datasource.flow.prod.username}
|
||||
password: ${blade.datasource.flow.prod.password}
|
||||
@@ -0,0 +1,6 @@
|
||||
#数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
url: ${blade.datasource.flow.test.url}
|
||||
username: ${blade.datasource.flow.test.username}
|
||||
password: ${blade.datasource.flow.test.password}
|
||||
13
blade-ops/blade-flow/src/main/resources/application.yml
Normal file
13
blade-ops/blade-flow/src/main/resources/application.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
#服务器端口
|
||||
server:
|
||||
port: 8008
|
||||
|
||||
#flowable配置
|
||||
flowable:
|
||||
activity-font-name: \u5B8B\u4F53
|
||||
label-font-name: \u5B8B\u4F53
|
||||
annotation-font-name: \u5B8B\u4F53
|
||||
check-process-definitions: false
|
||||
database-schema-update: false
|
||||
async-executor-activate: false
|
||||
async-history-executor-activate: false
|
||||
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
|
||||
<process id="Leave" name="请假流程" isExecutable="true">
|
||||
<documentation>请假流程</documentation>
|
||||
<startEvent id="start" name="开始" flowable:initiator="applyUser"></startEvent>
|
||||
<userTask id="hrTask" name="人事审批" flowable:assignee="${taskUser}">
|
||||
<extensionElements>
|
||||
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
|
||||
</extensionElements>
|
||||
</userTask>
|
||||
<exclusiveGateway id="judgeTask"></exclusiveGateway>
|
||||
<userTask id="managerTak" name="经理审批" flowable:candidateGroups="manager"></userTask>
|
||||
<userTask id="bossTask" name="老板审批" flowable:candidateGroups="boss"></userTask>
|
||||
<endEvent id="end" name="结束"></endEvent>
|
||||
<sequenceFlow id="flow1" sourceRef="start" targetRef="hrTask"></sequenceFlow>
|
||||
<sequenceFlow id="managerPassFlow" name="通过" sourceRef="managerTak" targetRef="end">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<userTask id="userTask" name="调整申请" flowable:assignee="${applyUser}">
|
||||
<extensionElements>
|
||||
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
|
||||
</extensionElements>
|
||||
</userTask>
|
||||
<sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="judgeMore" name="大于3天" sourceRef="judgeTask" targetRef="bossTask">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${days > 3}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="managerNotPassFlow" name="驳回" sourceRef="managerTak" targetRef="userTask">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="userTask">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="hrPassFlow" name="同意" sourceRef="hrTask" targetRef="judgeTask">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="hrNotPassFlow" name="驳回" sourceRef="hrTask" targetRef="userTask">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="judgeLess" name="小于3天" sourceRef="judgeTask" targetRef="managerTak">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${days <= 3}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="userPassFlow" name="重新申请" sourceRef="userTask" targetRef="hrTask">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
<sequenceFlow id="userNotPassFlow" name="关闭申请" sourceRef="userTask" targetRef="end">
|
||||
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
|
||||
</sequenceFlow>
|
||||
</process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_Leave">
|
||||
<bpmndi:BPMNPlane bpmnElement="Leave" id="BPMNPlane_Leave">
|
||||
<bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
|
||||
<omgdc:Bounds height="30.0" width="30.0" x="300.0" y="135.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="hrTask" id="BPMNShape_hrTask">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="360.0" y="165.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
|
||||
<omgdc:Bounds height="40.0" width="40.0" x="255.0" y="300.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="managerTak" id="BPMNShape_managerTak">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="555.0" y="75.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="bossTask" id="BPMNShape_bossTask">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="450.0" y="420.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
|
||||
<omgdc:Bounds height="28.0" width="28.0" x="705.0" y="390.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape bpmnElement="userTask" id="BPMNShape_userTask">
|
||||
<omgdc:Bounds height="80.0" width="100.0" x="510.0" y="270.0"></omgdc:Bounds>
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
|
||||
<omgdi:waypoint x="327.9390183144677" y="157.4917313275668"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="360.0" y="176.05263157894737"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="hrPassFlow" id="BPMNEdge_hrPassFlow">
|
||||
<omgdi:waypoint x="363.04347826086956" y="244.95000000000002"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="285.77299999999997" y="310.79999999999995"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="hrNotPassFlow" id="BPMNEdge_hrNotPassFlow">
|
||||
<omgdi:waypoint x="459.95" y="236.21875000000006"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="513.9794844818516" y="270.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
|
||||
<omgdi:waypoint x="274.3359375" y="300.66397214564284"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="274.3359375" y="115.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="554.9999999999982" y="115.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="userPassFlow" id="BPMNEdge_userPassFlow">
|
||||
<omgdi:waypoint x="510.0" y="310.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="411.0" y="310.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="411.0" y="244.95000000000002"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="bossPassFlow" id="BPMNEdge_bossPassFlow">
|
||||
<omgdi:waypoint x="549.9499999999998" y="447.2146118721461"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="705.4331577666419" y="407.4567570622598"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
|
||||
<omgdi:waypoint x="287.29730895645025" y="327.65205479452055"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="450.0" y="428.8888888888889"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="managerPassFlow" id="BPMNEdge_managerPassFlow">
|
||||
<omgdi:waypoint x="620.7588235294118" y="154.95"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="713.8613704477151" y="390.96328050279476"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="userNotPassFlow" id="BPMNEdge_userNotPassFlow">
|
||||
<omgdi:waypoint x="609.95" y="339.5301886792453"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="706.9383699359797" y="396.87411962686997"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="bossNotPassFlow" id="BPMNEdge_bossNotPassFlow">
|
||||
<omgdi:waypoint x="515.98" y="420.0"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="544.0" y="349.95000000000005"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge bpmnElement="managerNotPassFlow" id="BPMNEdge_managerNotPassFlow">
|
||||
<omgdi:waypoint x="595.438344721373" y="154.95"></omgdi:waypoint>
|
||||
<omgdi:waypoint x="567.9366337262223" y="270.0"></omgdi:waypoint>
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</definitions>
|
||||
Reference in New Issue
Block a user