增加挂起和激活流程

This commit is contained in:
459816669@qq.com 2021-03-08 15:05:44 +08:00
parent bbac3fac46
commit 846476de3c
21 changed files with 225 additions and 43 deletions

View File

@ -59,7 +59,7 @@
</table>
## 版本发布
v1.0 2021-2-24 ding-flow首发
v1.0 2021-02-24 ding-flow首发
- 1.0 集成flowable官方设计器
- 2.0 抛弃官方设计器用户组使用ding-flow自带用户流程角色。流程角色实现向下兼容即流程某节点配置父角色其父角色下所有子角色都具有流程审批权限
- 3.0 系统自带请假申请和采购单申请采用类form表单提交保存流程资源表。反序列化表单实现流程中取业务数据。接口通用一个接口按照规定格式设计流程即可。
@ -69,11 +69,24 @@ v1.0 2021-2-24 ding-flow首发
- 7.0 钉钉修改用户和部门,系统异步监听数据变化,实时修改系统数据。实现钉钉和系统数据同步。
- 8.0 账单管理,导出支付宝,微信账单。一键导入系统,系统轻松管理账单数据,日常消费明了清晰。
v1.1 2021-2-26
v1.1 2021-02-26
- 1.0 集成ding-flow数据大屏智能化科技大屏实时了解钉钉数据流程数据状态
- 2.0 修复流程历史数据保存失败问题
- 3.0 调整待办,增加已办功能
v1.2 2021-03-08
- 1.0 新增消息管理
(1) 消息节点树形配置
(2) 消息节点触发配置,可实时对流程消息推送做开关配置
(3) 新增消息模板在线设计dingTalk和邮件模板。消息内容支持参数化配置(使用${}识别参数)
- 2.0 新增流程发起和流程完结消息推送功能
- 3.0 新增转办任务功能(直接将办理人换成其他人)
- 4.0 新增委派任务功能(将任务节点分配给其他人处理,等其他人处理完之后,委派任务会自动回到委派人的任务中)
- 5.0 挂起流程
- 6.0 激活流程
## 未来规划
- 1.0 角色与钉钉打通
@ -89,5 +102,7 @@ v1.1 2021-2-26
## 我有话说
开源离不开您的参与、支持与鼓励。开源不易如果您觉得项目对您有帮助请您动动小手star一下也是对作者的最大帮助。
## 友情链接
博客
## 感谢诺依系统提供框架
诺依系统地址: http://ruoyi.vip

View File

@ -30,6 +30,8 @@
<commons.fileupload.version>1.3.3</commons.fileupload.version>
<poi.version>3.17</poi.version>
<velocity.version>1.7</velocity.version>
<flowable.version>6.4.1</flowable.version>
<dingtalk.version>dingtalk-SNAPSHOT</dingtalk.version>
</properties>
<!-- 依赖声明 -->

View File

@ -70,7 +70,6 @@
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-framework</artifactId>
<version>4.3.1</version>
</dependency>
<!-- 定时任务-->
@ -83,21 +82,18 @@
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-generator</artifactId>
<version>4.3.1</version>
</dependency>
<!--dingtalk-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-dingtalk</artifactId>
<version>4.3.1</version>
</dependency>
<!--工作流-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-flowable</artifactId>
<version>4.3.1</version>
</dependency>
</dependencies>

View File

@ -7,6 +7,7 @@ import com.snow.common.core.controller.BaseController;
import com.snow.common.core.domain.AjaxResult;
import com.snow.common.core.page.PageModel;
import com.snow.common.core.page.TableDataInfo;
import com.snow.flowable.common.enums.FlowInstanceEnum;
import com.snow.flowable.domain.*;
import com.snow.flowable.service.AppFormService;
import com.snow.flowable.service.FlowableTaskService;
@ -217,6 +218,7 @@ public class FlowController extends BaseController {
return AjaxResult.success();
}
/**
* 选择用户
*/
@ -227,4 +229,26 @@ public class FlowController extends BaseController {
mmap.put("flag",flag);
return prefix + "/selectUser";
}
@PostMapping("/activeProcessInstance")
@RequiresPermissions("flow:process:activeProcessInstance")
@ResponseBody
@RepeatSubmit
public AjaxResult activeProcessInstance(String id)
{
flowableService.suspendOrActiveProcessInstance(id,FlowInstanceEnum.ACTIVATE.getCode());
return AjaxResult.success();
}
@PostMapping("/suspendProcessInstance")
@RequiresPermissions("flow:process:suspendProcessInstance")
@ResponseBody
@RepeatSubmit
public AjaxResult suspendProcessInstance(String id)
{
flowableService.suspendOrActiveProcessInstance(id,FlowInstanceEnum.SUSPEND.getCode());
return AjaxResult.success();
}
}

View File

@ -143,6 +143,7 @@ xss:
swagger:
# 是否开启swagger
enabled: true
flowable:
#关闭定时任务JOB
async-executor-activate: false
@ -157,7 +158,7 @@ flowable:
#上传文件的方式
sys:
file:
active: aliyun
active: local
log4j:
logger:

View File

@ -1164,7 +1164,6 @@ var table = {
},
// 发布信息
deployment: function(id,type) {
console.log("=======>"+type);
table.set();
$.modal.confirm("确定发布该条" + table.options.modalName + "信息吗?", function() {
var url = $.common.isEmpty(id) ? table.options.deploymentUrl : table.options.deploymentUrl.replace("{id}", id);
@ -1176,6 +1175,34 @@ var table = {
}
});
},
// 激活流程
activeProcessInstance: function(id) {
table.set();
$.modal.confirm("确定激活该条流程信息吗?", function() {
var url = $.common.isEmpty(id) ? table.options.activeFlowUrl : table.options.activeProcessInstanceUrl.replace("{id}", id);
if(table.options.type == table_type.bootstrapTreeTable) {
$.operate.get(url);
} else {
var data = { "id": id };
$.operate.submit(url, "post", "json", data);
}
});
},
// 挂起流程
suspendProcessInstance: function(id) {
table.set();
$.modal.confirm("确定挂起该条流程信息吗?", function() {
var url = $.common.isEmpty(id) ? table.options.suspendProcessInstanceUrl : table.options.suspendProcessInstanceUrl.replace("{id}", id);
if(table.options.type == table_type.bootstrapTreeTable) {
$.operate.get(url);
} else {
var data = { "id": id };
$.operate.submit(url, "post", "json", data);
}
});
},
// 清空信息
clean: function() {

View File

@ -41,10 +41,14 @@
<script th:inline="javascript">
var detailFlag = [[${@permission.hasPermi('system:flow:myStartProcessDetail')}]];
var processInstanceStatusDatas = [[${@dict.getType('process_instance_status')}]];
var activeProcessInstanceFlag = [[${@permission.hasPermi('system:flow:activeProcessInstance')}]];
var suspendProcessInstanceFlag = [[${@permission.hasPermi('system:flow:suspendProcessInstance')}]];
var prefixFlow = ctx + "flow";
$(function() {
var options = {
url: prefixFlow + "/getMyHistoricProcessInstance",
activeProcessInstanceUrl: prefixFlow+"/activeProcessInstance",
suspendProcessInstanceUrl: prefixFlow+"/suspendProcessInstance",
modalName: "我发起的流程",
striped: true, //是否显示行间隔色
showToggle: false,
@ -103,6 +107,14 @@
align: 'center',
formatter: function(value, row, index) {
var actions = [];
var isFinished= row.isFinished;
var processInstanceStatus= row.processInstanceStatus;
if(processInstanceStatus==1&&isFinished==0){
actions.push('<a class="btn btn-danger btn-xs ' + suspendProcessInstanceFlag + '" href="javascript:void(0)" onclick="$.operate.suspendProcessInstance(\'' + row.id + '\')"><i class="fa fa-eye"></i>挂起</a> ');
}
if(processInstanceStatus==2&&isFinished==0){
actions.push('<a class="btn btn-success btn-xs ' + activeProcessInstanceFlag + '" href="javascript:void(0)" onclick="$.operate.activeProcessInstance(\'' + row.id + '\')"><i class="fa fa-eye"></i>激活</a> ');
}
actions.push('<a class="btn btn-info btn-xs ' + detailFlag + '" href="javascript:void(0)" onclick="getProcessDiagram(\'' + row.id + '\')"><i class="fa fa-eye"></i>详情</a>');
return actions.join('');
}
@ -118,6 +130,7 @@
function fromDetailUrl(detailUrl) {
$.modal.openTab("详情", detailUrl);
}
</script>

View File

@ -17,18 +17,12 @@
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-framework</artifactId>
<version>4.3.1</version>
<version>${snow.version}</version>
</dependency>
<!-- <dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>1.0.1</version>
</dependency>-->
<dependency>
<groupId>com.taobao.top</groupId>
<artifactId>lippi-oapi-encrpt</artifactId>
<version>dingtalk-SNAPSHOT</version>
<version>${dingtalk.version}</version>
<scope>system</scope>
<systemPath>${pom.basedir}/src/main/resources/lib/lippi-oapi-encrpt.jar</systemPath>
</dependency>
@ -36,7 +30,7 @@
<dependency>
<groupId>com.dingtalk.sdk</groupId>
<artifactId>dingtalk-sdk-java</artifactId>
<version>dingtalk-SNAPSHOT</version>
<version>${dingtalk.version}</version>
<scope>system</scope>
<systemPath>${pom.basedir}/src/main/resources/lib/taobao-sdk-java.jar</systemPath>
</dependency>

View File

@ -18,30 +18,27 @@
<artifactId>snow-dingtalk</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<!--flowable工作流-->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.4.1</version>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-modeler-rest</artifactId>
<version>6.4.1</version>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-json-converter</artifactId>
<version>6.4.1</version>
<version>${flowable.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,34 @@
package com.snow.flowable.common.enums;
/**
* @program: snow
* @description 流程实例状态挂起或者激活
* @author: 没用的阿吉
* @create: 2020-12-13 19:54
**/
public enum FlowInstanceEnum {
ACTIVATE(1, "激活"),
SUSPEND(2, "挂起");
private final Integer code;
private final String info;
FlowInstanceEnum(Integer code, String info)
{
this.code = code;
this.info = info;
}
public Integer getCode()
{
return code;
}
public String getInfo()
{
return info;
}
}

View File

@ -72,6 +72,9 @@ public class ProcessInstanceVO implements Serializable {
*/
private String startUserName;
/**
* 开始活动节点id
*/
private String startActivityId;
/**
@ -87,6 +90,9 @@ public class ProcessInstanceVO implements Serializable {
*/
private String superProcessInstanceId;
/**
* 租户id
*/
private String tenantId;
@ -119,6 +125,11 @@ public class ProcessInstanceVO implements Serializable {
private String processDefinitionCategory;
/**
* 流程状态1--激活2--挂起
*/
private Integer processInstanceStatus;
public static List<ProcessInstanceVO> warpList(List<HistoricProcessInstance> historicProcessInstanceList){
return historicProcessInstanceList.stream().map(t->{
ProcessInstanceVO processInstanceVO=new ProcessInstanceVO();

View File

@ -171,4 +171,11 @@ public interface FlowableService {
FlowGeneralSituationVO getFlowGeneralSituation(String userId);
/**
* 挂起或激活流程 0--激活1--挂起
* @param instanceId
* @param suspendState
*/
void suspendOrActiveProcessInstance(String instanceId, Integer suspendState);
}

View File

@ -72,12 +72,5 @@ public interface FlowableTaskService {
*/
void delegateTask(String taskId,String curUserId,String targetUserId);
/**
* 挂起或激活流程
* @param instanceId
* @param suspendState
*/
void suspendOrActiveApply(String instanceId, String suspendState);
}

View File

@ -16,6 +16,7 @@ import com.snow.common.enums.WorkRecordStatus;
import com.snow.common.exception.BusinessException;
import com.snow.flowable.common.constants.FlowConstants;
import com.snow.flowable.common.enums.FlowDefEnum;
import com.snow.flowable.common.enums.FlowInstanceEnum;
import com.snow.flowable.common.enums.FlowStatusEnum;
import com.snow.flowable.config.ICustomProcessDiagramGenerator;
import com.snow.flowable.domain.*;
@ -44,6 +45,7 @@ import org.flowable.engine.history.HistoricProcessInstanceQuery;
import org.flowable.engine.impl.RepositoryServiceImpl;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.flowable.engine.repository.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Attachment;
import org.flowable.engine.task.Comment;
@ -660,7 +662,7 @@ public class FlowableServiceImpl implements FlowableService {
* 构建查询条件
* @param processInstanceDTO
*/
public HistoricProcessInstanceQuery buildHistoricProcessInstanceCondition(ProcessInstanceDTO processInstanceDTO){
private HistoricProcessInstanceQuery buildHistoricProcessInstanceCondition(ProcessInstanceDTO processInstanceDTO){
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();
if(!StringUtils.isEmpty(processInstanceDTO.getBusinessKey())){
historicProcessInstanceQuery.processInstanceBusinessKey(processInstanceDTO.getBusinessKey());
@ -693,7 +695,7 @@ public class FlowableServiceImpl implements FlowableService {
* 赋值ProcessInstanceVOs
* @param processInstanceVOS
*/
public void setProcessInstanceVOs(List<ProcessInstanceVO> processInstanceVOS){
private void setProcessInstanceVOs(List<ProcessInstanceVO> processInstanceVOS){
processInstanceVOS.parallelStream().forEach(t->{
Map<String, Object> processVariables = t.getProcessVariables();
@ -716,6 +718,19 @@ public class FlowableServiceImpl implements FlowableService {
String startUserId = t.getStartUserId();
SysUser sysUser = sysUserService.selectUserById(Long.parseLong(startUserId));
t.setStartUserName(sysUser.getUserName());
//流程状态查询 ACT_RU_EXECUTION
List<Execution> list = runtimeService.createExecutionQuery().processInstanceId(t.getId()).list();
if(CollectionUtils.isEmpty(list)){
t.setProcessInstanceStatus(FlowInstanceEnum.ACTIVATE.getCode());
}else {
Execution execution=list.get(0);
if(execution.isSuspended()){
t.setProcessInstanceStatus(FlowInstanceEnum.SUSPEND.getCode());
}else {
t.setProcessInstanceStatus(FlowInstanceEnum.ACTIVATE.getCode());
}
}
});
}
@Override
@ -947,9 +962,7 @@ public class FlowableServiceImpl implements FlowableService {
return taskVOList;
}
public String getUserNameById(String id){
return sysUserService.selectUserById(Long.parseLong(id)).getUserName();
}
/**
* 获取流程图像已执行节点和流程线高亮显示
@ -1060,6 +1073,16 @@ public class FlowableServiceImpl implements FlowableService {
}
@Override
public void suspendOrActiveProcessInstance(String instanceId, Integer suspendState) {
if(suspendState==FlowInstanceEnum.ACTIVATE.getCode()){
runtimeService.activateProcessInstanceById(instanceId);
//TODO 保存流程记录
}else {
runtimeService.suspendProcessInstanceById(instanceId);
}
}
/**
* 获取高亮的线
* @param bpmnModel
@ -1137,4 +1160,10 @@ public class FlowableServiceImpl implements FlowableService {
}
return highFlows;
}
private String getUserNameById(String id){
return sysUserService.selectUserById(Long.parseLong(id)).getUserName();
}
}

View File

@ -7,6 +7,7 @@ import com.snow.common.core.page.PageModel;
import com.snow.common.exception.BusinessException;
import com.snow.flowable.common.constants.FlowConstants;
import com.snow.flowable.common.enums.FlowDefEnum;
import com.snow.flowable.common.enums.FlowInstanceEnum;
import com.snow.flowable.domain.*;
import com.snow.flowable.service.FlowableService;
import com.snow.flowable.service.FlowableTaskService;
@ -285,10 +286,5 @@ public class FlowableTaskServiceImpl implements FlowableTaskService {
}
}
@Override
public void suspendOrActiveApply(String instanceId, String suspendState) {
}
}

View File

@ -21,6 +21,12 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions><!-- 去掉默认配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- SpringBoot 拦截器 -->
@ -89,6 +95,8 @@
<artifactId>snow-system</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -11,7 +11,7 @@ import org.springframework.context.annotation.Configuration;
/**
* @author qimingjin
* @Title: 初始化对象
* @Title: 文件上传配置类
* @Description:
* @date 2021/1/11 11:22
*/

View File

@ -22,6 +22,7 @@ public class LocalStorage implements Storage {
private final Log logger = LogFactory.getLog(LocalStorage.class);
private String storagePath;
private String address;
private Path rootLocation;

View File

@ -25,10 +25,24 @@ public interface Storage {
Stream<Path> loadAll();
/**
* 获取文件路径
* @param keyName
* @return
*/
Path load(String keyName);
/**
* 下载文件
* @param keyName
* @return
*/
Resource loadAsResource(String keyName);
/**
* 删除
* @param keyName
*/
void delete(String keyName);
String generateUrl(String keyName);

View File

@ -19,7 +19,9 @@ import java.util.stream.Stream;
* @date 2021/1/11 11:23
*/
public class StorageService {
private String active;
private Storage storage;
@Autowired

View File

@ -2,6 +2,7 @@ package com.snow.framework.web.exception;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.AuthorizationException;
//import org.flowable.common.engine.api.FlowableException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
@ -15,6 +16,8 @@ import com.snow.common.exception.DemoModeException;
import com.snow.common.utils.ServletUtils;
import com.snow.common.utils.security.PermissionUtils;
import java.util.Optional;
/**
* 全局异常处理器
*
@ -74,6 +77,21 @@ public class GlobalExceptionHandler
return AjaxResult.error("服务器错误,请联系管理员");
}
/**
* 流程异常
* @param e
* @return
*/
//@ExceptionHandler(FlowableException.class)
public AjaxResult flowableException(Exception e)
{
String errMessage=Optional.ofNullable(e.getMessage()).orElse("");
if(e.getMessage().contains("")){
return AjaxResult.error("服务器错误,请联系管理员");
}
return AjaxResult.error(errMessage);
}
/**
* 业务异常
*/