From 309044f5b1aceddb98a232ba47c35c34bb5502b2 Mon Sep 17 00:00:00 2001 From: superzheng Date: Mon, 17 Jan 2022 10:32:13 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(xdclass-activity):=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89activity=E5=A4=9A=E5=AE=9E=E4=BE=8B=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 自定义activity多实例拦截器 --- .../config/WfActivityBehaviorFactory.java | 20 +++++++++++ ...ParallelMultiInstanceActivityBehavior.java | 34 +++++++++++++++++++ ...quentialMultiInstanceActivityBehavior.java | 29 ++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfParallelMultiInstanceActivityBehavior.java create mode 100644 xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfSequentialMultiInstanceActivityBehavior.java diff --git a/xdclass-activity/src/main/java/cn/mesmile/activity/config/WfActivityBehaviorFactory.java b/xdclass-activity/src/main/java/cn/mesmile/activity/config/WfActivityBehaviorFactory.java index 06ea273..5b69855 100644 --- a/xdclass-activity/src/main/java/cn/mesmile/activity/config/WfActivityBehaviorFactory.java +++ b/xdclass-activity/src/main/java/cn/mesmile/activity/config/WfActivityBehaviorFactory.java @@ -1,6 +1,12 @@ package cn.mesmile.activity.config; +import cn.mesmile.activity.config.multi.WfParallelMultiInstanceActivityBehavior; +import cn.mesmile.activity.config.multi.WfSequentialMultiInstanceActivityBehavior; +import org.activiti.bpmn.model.Activity; import org.activiti.bpmn.model.UserTask; +import org.activiti.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior; import org.activiti.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; @@ -16,4 +22,18 @@ public class WfActivityBehaviorFactory extends DefaultActivityBehaviorFactory { public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { return new WfUserTaskActivityBehavior(userTask); } + + @Override + public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { + // 自定义拦截并行多实例 + return new WfParallelMultiInstanceActivityBehavior(activity, innerActivityBehavior); + } + + @Override + public SequentialMultiInstanceBehavior createSequentialMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { + // 自定义拦截串行多实例 + return new WfSequentialMultiInstanceActivityBehavior(activity, innerActivityBehavior); + } + + } \ No newline at end of file diff --git a/xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfParallelMultiInstanceActivityBehavior.java b/xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfParallelMultiInstanceActivityBehavior.java new file mode 100644 index 0000000..83cb3bb --- /dev/null +++ b/xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfParallelMultiInstanceActivityBehavior.java @@ -0,0 +1,34 @@ +package cn.mesmile.activity.config.multi; + +import org.activiti.bpmn.model.Activity; +import org.activiti.engine.delegate.DelegateExecution; +import org.activiti.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.activiti.engine.impl.delegate.ActivityBehavior; + +/** + * @author zb + * @date 2022/1/17 10:15 + * @Copyright © 沃飞长空科技(成都)有限公司 + * @Description + */ +public class WfParallelMultiInstanceActivityBehavior extends ParallelMultiInstanceBehavior { + + /** + * @param activity + * @param innerActivityBehavior + * The original {@link ActivityBehavior} of the activity that will be wrapped inside this behavior. + */ + public WfParallelMultiInstanceActivityBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { + super(activity, innerActivityBehavior); + } + + @Override + protected int createInstances(DelegateExecution execution) { + // 自定义多实例拦截器 + // 自定义逻辑 + + return super.createInstances(execution); + } + +} diff --git a/xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfSequentialMultiInstanceActivityBehavior.java b/xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfSequentialMultiInstanceActivityBehavior.java new file mode 100644 index 0000000..ae2c777 --- /dev/null +++ b/xdclass-activity/src/main/java/cn/mesmile/activity/config/multi/WfSequentialMultiInstanceActivityBehavior.java @@ -0,0 +1,29 @@ +package cn.mesmile.activity.config.multi; + +import org.activiti.bpmn.model.Activity; +import org.activiti.engine.delegate.DelegateExecution; +import org.activiti.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.activiti.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; + +/** + * @author zb + * @date 2022/1/17 10:27 + * @Copyright © 沃飞长空科技(成都)有限公司 + * @Description + */ +public class WfSequentialMultiInstanceActivityBehavior extends SequentialMultiInstanceBehavior { + + public WfSequentialMultiInstanceActivityBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { + super(activity, innerActivityBehavior); + } + + @Override + protected int createInstances(DelegateExecution multiInstanceExecution) { + // 自定义多实例拦截器 + // 自定义逻辑 + + return super.createInstances(multiInstanceExecution); + } + + +} -- Gitee From c567db4ec6add5d0a09c81db5196c9f1f302f4b3 Mon Sep 17 00:00:00 2001 From: superzheng Date: Mon, 17 Jan 2022 19:00:14 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat(xdclass-activity):=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89activity=E5=A4=9A=E5=AE=9E=E4=BE=8B=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 自定义activity多实例拦截器 --- .../listener1/ActivityCompleteListener.java | 67 +++++++++++++++++++ .../listener1/ActivityListenerConfig.java | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java diff --git a/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java b/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java new file mode 100644 index 0000000..daf23e3 --- /dev/null +++ b/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java @@ -0,0 +1,67 @@ +package cn.mesmile.activity.listener1; + +import cn.mesmile.activity.util.CustomSpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.activiti.engine.TaskService; +import org.activiti.engine.delegate.event.ActivitiEvent; +import org.activiti.engine.delegate.event.ActivitiEventListener; +import org.activiti.engine.delegate.event.ActivitiEventType; +import org.activiti.engine.delegate.event.impl.ActivitiActivityEventImpl; +import org.activiti.engine.delegate.event.impl.ActivitiEntityEventImpl; +import org.activiti.engine.impl.persistence.entity.TaskEntity; +import org.activiti.engine.task.Task; +import org.activiti.spring.integration.Activiti; +import org.springframework.stereotype.Component; +import org.w3c.dom.ls.LSException; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author zb + * @date 2021/01/27 17:10 + * @Copyright © 沃飞长空科技(成都)有限公司 + * @Description 节点完成监听器 + */ +@Component +public class ActivityCompleteListener implements ActivitiEventListener { + + @Override + public void onEvent(ActivitiEvent event) { + ActivitiEventType type = event.getType(); + if(ActivitiEventType.ACTIVITY_COMPLETED.equals(type)){ + if (event instanceof ActivitiActivityEventImpl) { + ActivitiActivityEventImpl eventImpl = (ActivitiActivityEventImpl) event; + String activityId = eventImpl.getActivityId(); + + String processInstanceId = eventImpl.getProcessInstanceId(); + String activityType = eventImpl.getActivityType(); + String executionId = eventImpl.getExecutionId(); + + TaskService taskService = CustomSpringUtils.getBean(TaskService.class); + + // 看看这里能查询到几个任务 + List list = taskService.createTaskQuery() + .taskDefinitionKey(activityId) + .processInstanceId(processInstanceId) + .list(); + // 通知PS审批通过, 大于1代表有多个实例 + if (list != null && list.size() > 1){ + // 通知PS审批通过 + + } + } + } + } + + /** + * 监听异常处理策略 + * @return + */ + @Override + public boolean isFailOnException() { + return false; + } + +} diff --git a/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityListenerConfig.java b/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityListenerConfig.java index aa10a0f..c7bb5b4 100644 --- a/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityListenerConfig.java +++ b/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityListenerConfig.java @@ -45,7 +45,7 @@ public class ActivityListenerConfig implements ApplicationListener Date: Mon, 17 Jan 2022 19:08:25 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(xdclass-activity):=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89activity=E5=A4=9A=E5=AE=9E=E4=BE=8B=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 自定义activity多实例拦截器 --- .../listener1/ActivityCompleteListener.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java b/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java index daf23e3..a335bc8 100644 --- a/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java +++ b/xdclass-activity/src/main/java/cn/mesmile/activity/listener1/ActivityCompleteListener.java @@ -17,6 +17,7 @@ import org.w3c.dom.ls.LSException; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; /** * @author zb @@ -33,23 +34,26 @@ public class ActivityCompleteListener implements ActivitiEventListener { if(ActivitiEventType.ACTIVITY_COMPLETED.equals(type)){ if (event instanceof ActivitiActivityEventImpl) { ActivitiActivityEventImpl eventImpl = (ActivitiActivityEventImpl) event; + // 这里 activityId 等于 taskDefinitionId String activityId = eventImpl.getActivityId(); - String processInstanceId = eventImpl.getProcessInstanceId(); - String activityType = eventImpl.getActivityType(); + // 当前完成的任务 String executionId = eventImpl.getExecutionId(); - TaskService taskService = CustomSpringUtils.getBean(TaskService.class); - - // 看看这里能查询到几个任务 List list = taskService.createTaskQuery() .taskDefinitionKey(activityId) .processInstanceId(processInstanceId) .list(); // 通知PS审批通过, 大于1代表有多个实例 if (list != null && list.size() > 1){ - // 通知PS审批通过 + for (Task task : list) { + String executionIdStr = task.getExecutionId(); + // 这里排查当前完成人的任务,避免重复通知 + if ( !Objects.equals(executionId,executionIdStr) ){ + // todo 通知PS审批通过 + } + } } } } -- Gitee From ddbb1fcb372fa1586c77dfb3d3c983cdf6045f85 Mon Sep 17 00:00:00 2001 From: superzheng Date: Thu, 20 Jan 2022 18:56:50 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(xdclass-workflow):=20=E5=AE=8C?= =?UTF-8?q?=E6=88=90workflow=E7=9B=B8=E5=85=B3=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完成workflow相关查询 --- pom.xml | 1 + xdclass-workflow/pom.xml | 107 +++++++ .../mesmile/workflow/WorkFlowApplication.java | 17 + .../mesmile/workflow/commom/CustomCode.java | 33 ++ .../mesmile/workflow/commom/IResultCode.java | 22 ++ .../cn/mesmile/workflow/commom/Query.java | 21 ++ .../java/cn/mesmile/workflow/commom/R.java | 155 ++++++++++ .../mesmile/workflow/commom/ResultCode.java | 43 +++ .../workflow/config/WorkFlowConfig.java | 10 + .../workflow/constant/WorkFlowConstant.java | 36 +++ .../workflow/process/bo/StartProcessBO.java | 26 ++ .../controller/WorkFlowController.java | 95 ++++++ .../workflow/process/dto/WorkFlowDTO.java | 8 + .../mesmile/workflow/process/entity/test.java | 10 + .../workflow/process/mapper/TestMapper.java | 8 + .../workflow/process/qo/WorkFlowQO.java | 49 +++ .../process/service/WorkFlowService.java | 73 +++++ .../service/impl/WorkFlowServiceImpl.java | 290 ++++++++++++++++++ .../workflow/process/vo/ClaimTaskVO.java | 75 +++++ .../workflow/process/vo/DoneProcessVO.java | 75 +++++ .../process/vo/ProcessDefinitionVO.java | 52 ++++ .../workflow/process/vo/SendProcessVO.java | 75 +++++ .../workflow/process/vo/TodoTaskVO.java | 75 +++++ .../workflow/process/vo/WorkFlowVO.java | 9 + .../process/wrapper/ClaimTaskWrapper.java | 24 ++ .../process/wrapper/DoneProcessWrapper.java | 24 ++ .../wrapper/ProcessDefinitionWrapper.java | 25 ++ .../process/wrapper/SendProcessWrapper.java | 24 ++ .../process/wrapper/TodoTaskWrapper.java | 24 ++ .../workflow/support/BaseEntityWrapper.java | 37 +++ .../mesmile/workflow/util/WorkFlowUtil.java | 42 +++ .../src/main/resources/application-dev.yml | 49 +++ .../src/main/resources/application.yml | 33 ++ .../src/main/resources/leave.bpmn20.xml | 107 +++++++ .../workflow/WorkFlowApplicationTest.java | 18 ++ 35 files changed, 1772 insertions(+) create mode 100644 xdclass-workflow/pom.xml create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/WorkFlowApplication.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/CustomCode.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/IResultCode.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/Query.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/R.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/ResultCode.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowConfig.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/StartProcessBO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowDTO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/entity/test.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/mapper/TestMapper.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowQO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ClaimTaskVO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/DoneProcessVO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ProcessDefinitionVO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/SendProcessVO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/TodoTaskVO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowVO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ClaimTaskWrapper.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/DoneProcessWrapper.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ProcessDefinitionWrapper.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/SendProcessWrapper.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/TodoTaskWrapper.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/support/BaseEntityWrapper.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/util/WorkFlowUtil.java create mode 100644 xdclass-workflow/src/main/resources/application-dev.yml create mode 100644 xdclass-workflow/src/main/resources/application.yml create mode 100644 xdclass-workflow/src/main/resources/leave.bpmn20.xml create mode 100644 xdclass-workflow/src/test/java/cn/mesmile/workflow/WorkFlowApplicationTest.java diff --git a/pom.xml b/pom.xml index 78e58bd..2f024af 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,7 @@ xdclass-activity xdclass-groovy-plus xdclass-forest + xdclass-workflow diff --git a/xdclass-workflow/pom.xml b/xdclass-workflow/pom.xml new file mode 100644 index 0000000..0680d06 --- /dev/null +++ b/xdclass-workflow/pom.xml @@ -0,0 +1,107 @@ + + + + xdclass-cloud + cn.mesmile + 1.0-SNAPSHOT + + 4.0.0 + + xdclass-workflow + + + UTF-8 + UTF-8 + 1.8 + 1.8 + 1.8 + UTF-8 + 6.6.0 + 3.5.0 + 2.8.0 + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + mysql + mysql-connector-java + + + + + org.flowable + flowable-spring-boot-starter + ${flowable.version} + + + org.flowable + flowable-json-converter + ${flowable.version} + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + + + io.springfox + springfox-swagger2 + ${swagger.verision} + + + io.springfox + springfox-swagger-ui + ${swagger.verision} + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + repackage + + + + + true + true + + + + + + \ No newline at end of file diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/WorkFlowApplication.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/WorkFlowApplication.java new file mode 100644 index 0000000..9728862 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/WorkFlowApplication.java @@ -0,0 +1,17 @@ +package cn.mesmile.workflow; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author zb + * @Description 工作流 + */ +@SpringBootApplication +public class WorkFlowApplication { + + public static void main(String[] args) { + SpringApplication.run(WorkFlowApplication.class, args); + } + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/CustomCode.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/CustomCode.java new file mode 100644 index 0000000..db35534 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/CustomCode.java @@ -0,0 +1,33 @@ +package cn.mesmile.workflow.commom; + +/** + * @author zb + * @Description + */ +public enum CustomCode implements IResultCode{ + + /** + * 返回状态码,以及返回消息 + */ + SUCCESS(200, "成功"); + + + private final String message; + + private final int code; + + CustomCode(int code, String message){ + this.code = code; + this.message = message; + } + + @Override + public String getMessage() { + return this.message; + } + + @Override + public int getCode() { + return this.code; + } +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/IResultCode.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/IResultCode.java new file mode 100644 index 0000000..35e417a --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/IResultCode.java @@ -0,0 +1,22 @@ +package cn.mesmile.workflow.commom; + +import java.io.Serializable; + +/** + * 返回结果类 + */ +public interface IResultCode extends Serializable { + + /** + * 获取结果消息 + * @return 结果消息 + */ + String getMessage(); + + /** + * 获取返回状态码 + * @return 结果状态码 + */ + int getCode(); + +} \ No newline at end of file diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/Query.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/Query.java new file mode 100644 index 0000000..43e26ed --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/Query.java @@ -0,0 +1,21 @@ +package cn.mesmile.workflow.commom; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author zb + * @Description + */ +@Data +@ApiModel(description = "查询条件") +public class Query { + + @ApiModelProperty("当前页") + private Integer current = 1; + + @ApiModelProperty("每页的数量") + private Integer size = 10; + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/R.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/R.java new file mode 100644 index 0000000..88cbbb7 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/R.java @@ -0,0 +1,155 @@ +package cn.mesmile.workflow.commom; + +import cn.hutool.core.util.ObjectUtil; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.springframework.lang.Nullable; + +import java.io.Serializable; +import java.util.Optional; + +@ApiModel( + description = "返回信息" +) +public class R implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty( + value = "状态码", + required = true + ) + private int code; + + @ApiModelProperty( + value = "是否成功", + required = true + ) + private boolean success; + + @ApiModelProperty("承载数据") + private T data; + + @ApiModelProperty( + value = "返回消息", + required = true + ) + private String msg; + + private R(IResultCode resultCode) { + this(resultCode, null, resultCode.getMessage()); + } + + private R(IResultCode resultCode, String msg) { + this(resultCode, null, msg); + } + + private R(IResultCode resultCode, T data) { + this(resultCode, data, resultCode.getMessage()); + } + + private R(IResultCode resultCode, T data, String msg) { + this(resultCode.getCode(), data, msg); + } + + private R(int code, T data, String msg) { + this.code = code; + this.data = data; + this.msg = msg; + this.success = ResultCode.SUCCESS.code == code; + } + + public static boolean isSuccess(@Nullable R result) { + return (Boolean) Optional.ofNullable(result).map((x) -> { + return ObjectUtil.equal(ResultCode.SUCCESS.code, x.code); + }).orElse(Boolean.FALSE); + } + + public static boolean isNotSuccess(@Nullable R result) { + return !isSuccess(result); + } + + public static R data(T data) { + return data(data, "操作成功"); + } + + public static R data(T data, String msg) { + return data(200, data, msg); + } + + public static R data(int code, T data, String msg) { + return new R(code, data, data == null ? "暂无承载数据" : msg); + } + + public static R success(String msg) { + return new R(ResultCode.SUCCESS, msg); + } + + public static R success(IResultCode resultCode) { + return new R(resultCode); + } + + public static R success(IResultCode resultCode, String msg) { + return new R(resultCode, msg); + } + + public static R fail(String msg) { + return new R(ResultCode.FAILURE, msg); + } + + public static R fail(int code, String msg) { + return new R(code, (Object)null, msg); + } + + public static R fail(IResultCode resultCode) { + return new R(resultCode); + } + + public static R fail(IResultCode resultCode, String msg) { + return new R(resultCode, msg); + } + + public static R status(boolean flag) { + return flag ? success("操作成功") : fail("操作失败"); + } + + public int getCode() { + return this.code; + } + + public boolean isSuccess() { + return this.success; + } + + public T getData() { + return this.data; + } + + public String getMsg() { + return this.msg; + } + + public void setCode(final int code) { + this.code = code; + } + + public void setSuccess(final boolean success) { + this.success = success; + } + + public void setData(final T data) { + this.data = data; + } + + public void setMsg(final String msg) { + this.msg = msg; + } + + @Override + public String toString() { + return "R(code=" + this.getCode() + ", success=" + this.isSuccess() + ", data=" + this.getData() + ", msg=" + this.getMsg() + ")"; + } + + public R() { + } +} \ No newline at end of file diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/ResultCode.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/ResultCode.java new file mode 100644 index 0000000..dce16c9 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/commom/ResultCode.java @@ -0,0 +1,43 @@ +package cn.mesmile.workflow.commom; + +/** + * @author + * 返回状态码,和消息 + */ +public enum ResultCode implements IResultCode { + /** + * 返回状态码,以及返回消息 + */ + SUCCESS(200, "操作成功"), + FAILURE(400, "业务异常"), + UN_AUTHORIZED(401, "请求未授权"), + CLIENT_UN_AUTHORIZED(401, "客户端请求未授权"), + NOT_FOUND(404, "404 没找到请求"), + MSG_NOT_READABLE(400, "消息不能读取"), + METHOD_NOT_SUPPORTED(405, "不支持当前请求方法"), + MEDIA_TYPE_NOT_SUPPORTED(415, "不支持当前媒体类型"), + REQ_REJECT(403, "请求被拒绝"), + INTERNAL_SERVER_ERROR(500, "服务器异常"), + PARAM_MISS(400, "缺少必要的请求参数"), + PARAM_TYPE_ERROR(400, "请求参数类型错误"), + PARAM_BIND_ERROR(400, "请求参数绑定错误"), + PARAM_VALID_ERROR(400, "参数校验失败"); + + final int code; + final String message; + + @Override + public int getCode() { + return this.code; + } + + @Override + public String getMessage() { + return this.message; + } + + private ResultCode(final int code, final String message) { + this.code = code; + this.message = message; + } +} \ No newline at end of file diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowConfig.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowConfig.java new file mode 100644 index 0000000..fbfea19 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowConfig.java @@ -0,0 +1,10 @@ +package cn.mesmile.workflow.config; + +/** + * @author zb + * @Description + */ +public class WorkFlowConfig { + + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java new file mode 100644 index 0000000..13620db --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java @@ -0,0 +1,36 @@ +package cn.mesmile.workflow.constant; + +/** + * @author zb + * @Description 通用常量 + */ +public interface WorkFlowConstant { + + /** 申请人 */ + String PROCESS_APPLY_USER = "processApplyUser"; + + /** 申请人姓名 */ + String PROCESS_APPLY_USER_NAME = "processApplyUserName"; + + /** 跳过第一个节点 */ + String SKIP_FIRST_NODE = "skipFirstNode"; + + /** 默认回退节点 */ + String ROLLBACK_NODE = "rollbackNode"; + + //////////////////////////自定义任务完成类型///////////////////////////// + /** 自动完成 */ + String AUTO_COMPLETED_TASK = "autoCompletedTask"; + String AUTO_COMPLETED_TASK_DESCRIBE = "自动完成"; + + /** 同意 */ + String PASS_TASK = "passTask"; + String PASS_TASK_DESCRIBE = "同意"; + + /** 驳回 */ + String REFUSE_TASK = "refuseTask"; + String REFUSE_TASK_DESCRIBE = "驳回"; + + + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/StartProcessBO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/StartProcessBO.java new file mode 100644 index 0000000..82d7c84 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/StartProcessBO.java @@ -0,0 +1,26 @@ +package cn.mesmile.workflow.process.bo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Map; + +/** + * @author zb + * @Description + */ +@ApiModel(description = "启动流程实例入参") +@Data +public class StartProcessBO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("流程定义id") + private String processDefId; + + @ApiModelProperty("发起表单值") + private Map variables; + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java new file mode 100644 index 0000000..02bca2c --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java @@ -0,0 +1,95 @@ +package cn.mesmile.workflow.process.controller; + +import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.commom.R; +import cn.mesmile.workflow.process.bo.StartProcessBO; +import cn.mesmile.workflow.process.qo.WorkFlowQO; +import cn.mesmile.workflow.process.service.WorkFlowService; +import cn.mesmile.workflow.process.vo.*; +import cn.mesmile.workflow.process.wrapper.*; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zb + * @Description + */ +@Api(value = "工作流相关接口", tags = "工作流相关接口") +@AllArgsConstructor +@RequestMapping("/api/v1/workflow") +@RestController +public class WorkFlowController { + + private final WorkFlowService workFlowService; + + @ApiOperation("查询流程定义列表") + @GetMapping("/listProcessDefinition") + public R listProcessDefinition(Query query, WorkFlowQO workFlowQO) { + IPage processDefinitionPage = workFlowService.listProcessDefinition(query, workFlowQO); + IPage processDefinitionVO = ProcessDefinitionWrapper.build().pageVO(processDefinitionPage); + return R.data(processDefinitionVO); + } + + @ApiOperation("发起流程") + @PostMapping("/startProcessById") + public R startProcessById(@RequestBody StartProcessBO startProcessBO){ + String processDefId = startProcessBO.getProcessDefId(); + Map variables = startProcessBO.getVariables(); + if (StringUtils.isNotBlank(processDefId)){ + R.fail("缺少必要参数流程定义id(processDefId)"); + } + if (variables == null){ + variables = new HashMap<>(16); + } + ProcessInstance processInstance = workFlowService.startProcessInstanceByDefId(processDefId, variables); + return R.data(processInstance.getId()); + } + + @ApiOperation("查询 我的待办任务 列表") + @GetMapping("/listTodoTask") + public R listTodoTask(Query query, WorkFlowQO workFlowQO){ + IPage taskPage = workFlowService.listTodoTask(query, workFlowQO); + IPage todoTaskVOPage = TodoTaskWrapper.build().pageVO(taskPage); + return R.data(todoTaskVOPage); + } + + @ApiOperation("查询 我的待签任务 列表") + @GetMapping("/listClaimTask") + public R listClaimTask(Query query, WorkFlowQO workFlowQO){ + IPage taskIPage = workFlowService.listClaimTask(query, workFlowQO); + IPage claimTaskVOIPage = ClaimTaskWrapper.build().pageVO(taskIPage); + return R.data(claimTaskVOIPage); + } + + @ApiOperation("查询 我的已办流程实例 列表") + @GetMapping("/listDoneProcess") + public R listDoneProcess (Query query, WorkFlowQO workFlowQO){ + IPage historicProcessInstancePage = workFlowService.listDoneProcess(query, workFlowQO); + IPage doneProcessVOPage = DoneProcessWrapper.build().pageVO(historicProcessInstancePage); + return R.data(doneProcessVOPage); + } + + @ApiOperation("查询 我发起的流程实例 列表") + @GetMapping("/listSendProcess") + public R listSendProcess(Query query, WorkFlowQO workFlowQO){ + IPage historicProcessInstancePage = workFlowService.listSendProcess(query, workFlowQO); + IPage sendProcessVOPage = SendProcessWrapper.build().pageVO(historicProcessInstancePage); + return R.data(sendProcessVOPage); + } + + + + + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowDTO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowDTO.java new file mode 100644 index 0000000..3dcefa2 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowDTO.java @@ -0,0 +1,8 @@ +package cn.mesmile.workflow.process.dto; + +/** + * @author zb + * @Description + */ +public class WorkFlowDTO { +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/entity/test.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/entity/test.java new file mode 100644 index 0000000..9a698c4 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/entity/test.java @@ -0,0 +1,10 @@ +package cn.mesmile.workflow.process.entity; + +/** + * @author zb + * @date 2022/1/20 11:15 + * @Copyright © 沃飞长空科技(成都)有限公司 + * @Description + */ +public class test { +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/mapper/TestMapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/mapper/TestMapper.java new file mode 100644 index 0000000..e73f89b --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/mapper/TestMapper.java @@ -0,0 +1,8 @@ +package cn.mesmile.workflow.process.mapper; + +/** + * @author zb + * @Description + */ +public interface TestMapper { +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowQO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowQO.java new file mode 100644 index 0000000..c43b816 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowQO.java @@ -0,0 +1,49 @@ +package cn.mesmile.workflow.process.qo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * @author zb + * @Description + */ +@ApiModel(description = "通用查询") +@Data +public class WorkFlowQO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("流程定义key") + private String processDefKey; + + @ApiModelProperty("流程定义名称") + private String processDefName; + + @ApiModelProperty("流程分类") + private String category; + + @ApiModelProperty("流程分类列表") + private List categoryList; + + @ApiModelProperty("是否查询最新版本的流程定义") + private Boolean lastVersion; + + @ApiModelProperty("任务名称") + private String taskName; + + @ApiModelProperty("开始时间") + private Date startDate; + + @ApiModelProperty("结束时间") + private Date endDate; + + @ApiModelProperty("申请人id") + private String applyUser; + + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java new file mode 100644 index 0000000..c7c6fcd --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java @@ -0,0 +1,73 @@ +package cn.mesmile.workflow.process.service; + +import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.process.qo.WorkFlowQO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; + +import java.util.Map; + +/** + * @author zb + * @Description + */ +public interface WorkFlowService { + + /** + * 部署流程 + * @return 部署结果 + */ + Deployment deploy(); + + /** + * 查询所有版本流程定义列表 + * @param query 查询分页参数 + * @param workFlowQO 查询条件 + * @return 查询结果 + */ + IPage listProcessDefinition(Query query, WorkFlowQO workFlowQO); + + /** + * 根据流程定义id发起流程实例 + * @param processDefId 流程定义id + * @param variables 表单值 + * @return 流程实例 + */ + ProcessInstance startProcessInstanceByDefId(String processDefId, Map variables); + + /** + * 查询我待办任务列表 + * @param query 查询分页参数 + * @param workFlowQO 查询条件 + * @return 查询结果 + */ + IPage listTodoTask(Query query, WorkFlowQO workFlowQO); + + /** + * 查询我待签任务列表 + * @param query 查询分页参数 + * @param workFlowQO 查询条件 + * @return 查询结果 + */ + IPage listClaimTask(Query query, WorkFlowQO workFlowQO); + + /** + * 查询我已办任务列表 + * @param query 查询分页参数 + * @param workFlowQO 查询条件 + * @return 查询结果 + */ + IPage listDoneProcess(Query query, WorkFlowQO workFlowQO); + + /** + * 查询我发起的流程实例列表 + * @param query 查询分页参数 + * @param workFlowQO 查询条件 + * @return 查询结果 + */ + IPage listSendProcess(Query query, WorkFlowQO workFlowQO); +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java new file mode 100644 index 0000000..ff5e204 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java @@ -0,0 +1,290 @@ +package cn.mesmile.workflow.process.service.impl; + +import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.constant.WorkFlowConstant; +import cn.mesmile.workflow.process.qo.WorkFlowQO; +import cn.mesmile.workflow.process.service.WorkFlowService; +import cn.mesmile.workflow.util.WorkFlowUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.AllArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.engine.*; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +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.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * @author zb + * @Description + */ +@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS,readOnly = true) +@AllArgsConstructor +@Service +public class WorkFlowServiceImpl implements WorkFlowService { + + private final RepositoryService repositoryService; + private final RuntimeService runtimeService; + private final TaskService taskService; + private final HistoryService historyService; + private final IdentityService identityService; + + @Transactional(rollbackFor = Exception.class) + @Override + public Deployment deploy() { + Deployment deploy = repositoryService.createDeployment() + .key("leave") // 流程定义key + .name("请假流程") // 流程定义名称 + .category("hr") // 模型分类 + .addClasspathResource("leave.bpmn20.xml").deploy(); + return deploy; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public ProcessInstance startProcessInstanceByDefId(String processDefId, Map variables) { + // 设置流程发起人 + identityService.setAuthenticatedUserId("admin"); + // TODO 自定义逻辑 + variables.put(WorkFlowConstant.PROCESS_APPLY_USER, "admin"); + variables.put(WorkFlowConstant.PROCESS_APPLY_USER_NAME, "管理员"); + + ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefId, variables); + String processInstanceId = processInstance.getProcessInstanceId(); + +// runtimeService.setProcessInstanceName(processInstance.getId(),processInstance.getProcessDefinitionName()); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId); + // 判断是否跳过第一个节点 + String skipNode = WorkFlowUtil.getProcessExtensionAttribute(bpmnModel, WorkFlowConstant.SKIP_FIRST_NODE); + if (StringUtils.isNotBlank(skipNode) && Objects.equals("true", skipNode)){ + List list = taskService.createTaskQuery().processInstanceId(processInstanceId).list(); + if (list != null && list.size() > 0){ + list.forEach(task ->{ + String taskId = task.getId(); + // 添加评论 + taskService.addComment(taskId,processInstanceId, WorkFlowConstant.AUTO_COMPLETED_TASK, WorkFlowConstant.AUTO_COMPLETED_TASK_DESCRIBE); + // 自动完成 + taskService.complete(taskId); + }); + } + } + + return processInstance; + } + + @Override + public IPage listProcessDefinition(Query query, WorkFlowQO workFlowQO) { + ProcessDefinitionQuery processDefinitionQuery = + repositoryService.createProcessDefinitionQuery(); + String processDefName = workFlowQO.getProcessDefName(); + String processDefKey = workFlowQO.getProcessDefKey(); + String category = workFlowQO.getCategory(); + Boolean lastVersion = workFlowQO.getLastVersion(); + if (StringUtils.isNotBlank(processDefName)){ + processDefinitionQuery.processDefinitionNameLike("%"+processDefName+"%"); + } + if (StringUtils.isNotBlank(processDefKey)){ + processDefinitionQuery.processDefinitionKey(processDefKey); + } + if (StringUtils.isNotBlank(category)){ + processDefinitionQuery.processDefinitionCategory(category); + } + if (lastVersion != null && lastVersion){ + processDefinitionQuery.latestVersion(); + } + long total = processDefinitionQuery.count(); + Integer current = query.getCurrent(); + Integer size = query.getSize(); + List processDefinitionList = processDefinitionQuery.listPage((current - 1) * size, size); + Page page = Page.of(current, size, total); + page.setRecords(processDefinitionList); + return page; + } + + @Override + public IPage listTodoTask(Query query, WorkFlowQO workFlowQO) { + // 查审批 + TaskQuery taskQuery = taskService.createTaskQuery() + // todo 传入当前用户 + .taskCandidateOrAssigned("admin") + .taskCandidateGroupIn(new ArrayList<>()) // 候选组 + .active() // 激活的 + .orderByTaskCreateTime().desc(); + + String processDefName = workFlowQO.getProcessDefName(); + String processDefKey = workFlowQO.getProcessDefKey(); + String taskName = workFlowQO.getTaskName(); + String applyUser = workFlowQO.getApplyUser(); + Date startDate = workFlowQO.getStartDate(); + Date endDate = workFlowQO.getEndDate(); + List categoryList = workFlowQO.getCategoryList(); + if (StringUtils.isNotBlank(processDefName)){ + taskQuery.processDefinitionNameLike("%"+ processDefName + "%"); + } + if (StringUtils.isNotBlank(processDefName)){ + taskQuery.processDefinitionKey(processDefKey); + } + if (StringUtils.isNotBlank(taskName)){ + taskQuery.taskName(taskName); + } + if (categoryList != null && categoryList.size() > 0){ + taskQuery.processCategoryIn(categoryList); + } + if (StringUtils.isNotBlank(applyUser)){ + taskQuery.processVariableValueEquals(WorkFlowConstant.PROCESS_APPLY_USER, applyUser); + } + if (startDate != null){ + taskQuery.taskCreatedAfter(startDate); + } + if (endDate != null){ + taskQuery.taskCreatedBefore(endDate); + } + long count = taskQuery.count(); + + Integer current = query.getCurrent(); + Integer size = query.getSize(); + List tasks = taskQuery.listPage((current - 1) * size, size); + Page page = Page.of(current, size, count); + page.setRecords(tasks); + return page; + } + + @Override + public IPage listClaimTask(Query query, WorkFlowQO workFlowQO) { + // 查【候选】 + TaskQuery taskQuery = taskService.createTaskQuery() + // 当前用户是否存在于候选人之内 + .taskCandidateUser("admin") + // 查询当前用户所在的候选组 + .taskCandidateGroupIn(new ArrayList<>()) + .active() + .orderByTaskCreateTime() + .desc(); + String processDefName = workFlowQO.getProcessDefName(); + String processDefKey = workFlowQO.getProcessDefKey(); + String taskName = workFlowQO.getTaskName(); + String applyUser = workFlowQO.getApplyUser(); + Date startDate = workFlowQO.getStartDate(); + Date endDate = workFlowQO.getEndDate(); + List categoryList = workFlowQO.getCategoryList(); + if (StringUtils.isNotBlank(processDefName)){ + taskQuery.processDefinitionNameLike("%"+ processDefName + "%"); + } + if (StringUtils.isNotBlank(processDefName)){ + taskQuery.processDefinitionKey(processDefKey); + } + if (StringUtils.isNotBlank(taskName)){ + taskQuery.taskName(taskName); + } + if (categoryList != null && categoryList.size() > 0){ + taskQuery.processCategoryIn(categoryList); + } + if (StringUtils.isNotBlank(applyUser)){ + taskQuery.processVariableValueEquals(WorkFlowConstant.PROCESS_APPLY_USER, applyUser); + } + if (startDate != null){ + taskQuery.taskCreatedAfter(startDate); + } + if (endDate != null){ + taskQuery.taskCreatedBefore(endDate); + } + long count = taskQuery.count(); + + Integer current = query.getCurrent(); + Integer size = query.getSize(); + List tasks = taskQuery.listPage((current - 1) * size, size); + Page page = Page.of(current, size, count); + page.setRecords(tasks); + return page; + } + + @Override + public IPage listDoneProcess(Query query, WorkFlowQO workFlowQO) { + HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() + // TODO 传入当前用户 查询当前用户所涉及到的流程实例 + .involvedUser("admin") + .orderByProcessInstanceStartTime() + .desc(); + String processDefName = workFlowQO.getProcessDefName(); + String processDefKey = workFlowQO.getProcessDefKey(); + String category = workFlowQO.getCategory(); + String applyUser = workFlowQO.getApplyUser(); + Date startDate = workFlowQO.getStartDate(); + Date endDate = workFlowQO.getEndDate(); + if (StringUtils.isNotBlank(processDefName)){ + processInstanceQuery.processDefinitionName("%"+processDefName+"%"); + } + if (StringUtils.isNotBlank(processDefKey)){ + processInstanceQuery.processDefinitionKey(processDefKey); + } + if (StringUtils.isNotBlank(category)){ + processInstanceQuery.processDefinitionCategory(category); + } + if (StringUtils.isNotBlank(applyUser)){ + processInstanceQuery.variableValueEquals(WorkFlowConstant.PROCESS_APPLY_USER, applyUser); + } + if (startDate != null){ + processInstanceQuery.startedAfter(startDate); + } + if (endDate != null){ + processInstanceQuery.startedBefore(endDate); + } + long total = processInstanceQuery.count(); + Integer current = query.getCurrent(); + Integer size = query.getSize(); + + List historicProcessInstances = processInstanceQuery.listPage((current - 1) * size, size); + Page page = Page.of(current, size, total); + page.setRecords(historicProcessInstances); + return page; + } + + @Override + public IPage listSendProcess(Query query, WorkFlowQO workFlowQO) { + HistoricProcessInstanceQuery historyQuery = historyService.createHistoricProcessInstanceQuery() + // 传入当前用户 + .startedBy("admin") + .orderByProcessInstanceStartTime().desc(); + String processDefName = workFlowQO.getProcessDefName(); + String processDefKey = workFlowQO.getProcessDefKey(); + String category = workFlowQO.getCategory(); + Date startDate = workFlowQO.getStartDate(); + Date endDate = workFlowQO.getEndDate(); + if (StringUtils.isNotBlank(processDefName)){ + historyQuery.processDefinitionName("%"+processDefName+"%"); + } + if (StringUtils.isNotBlank(processDefKey)){ + historyQuery.processDefinitionKey(processDefKey); + } + if (StringUtils.isNotBlank(category)){ + historyQuery.processDefinitionCategory(category); + } + if (startDate != null){ + historyQuery.startedAfter(startDate); + } + if (endDate != null){ + historyQuery.startedBefore(endDate); + } + long total = historyQuery.count(); + Integer current = query.getCurrent(); + Integer size = query.getSize(); + + List historicProcessInstances = historyQuery.listPage((current - 1) * size, size); + Page page = Page.of(current, size, total); + page.setRecords(historicProcessInstances); + return page; + } + + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ClaimTaskVO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ClaimTaskVO.java new file mode 100644 index 0000000..79d7ac1 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ClaimTaskVO.java @@ -0,0 +1,75 @@ +package cn.mesmile.workflow.process.vo; + +import cn.mesmile.workflow.constant.WorkFlowConstant; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.flowable.task.api.Task; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +/** + * @author zb + * @Description + */ +@Data +public class ClaimTaskVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("任务id") + private String taskId; + + @ApiModelProperty("流程实例id") + private String processInstanceId; + + @ApiModelProperty("流程定义key,就是流程节点id") + private String taskDefinitionKey; + + @ApiModelProperty("任务名称") + private String name; + + @ApiModelProperty("values") + private Map variables; + + @ApiModelProperty("审批人") + private String assignee; + + @ApiModelProperty("分类") + private String category; + + @ApiModelProperty("创建时间") + private Date createTime; + + @ApiModelProperty("发起人") + private String applyUser; + + @ApiModelProperty("发起人名称") + private String applyUserName; + + @ApiModelProperty("执行id") + private String executionId; + + @ApiModelProperty("到期时间") + private Date dueDate; + + + public ClaimTaskVO(Task task){ + this.taskId = task.getId(); + this.processInstanceId = task.getProcessInstanceId(); + this.taskDefinitionKey = task.getTaskDefinitionKey(); + this.name = task.getName(); + this.variables = task.getProcessVariables(); + this.assignee = task.getAssignee(); + this.category = task.getCategory(); + this.createTime = task.getCreateTime(); + this.executionId = task.getExecutionId(); + this.dueDate = task.getDueDate(); + this.applyUser = (String) variables.get(WorkFlowConstant.PROCESS_APPLY_USER); + this.applyUserName = (String) variables.get(WorkFlowConstant.PROCESS_APPLY_USER_NAME); + } + + public ClaimTaskVO(){} + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/DoneProcessVO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/DoneProcessVO.java new file mode 100644 index 0000000..b338dd3 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/DoneProcessVO.java @@ -0,0 +1,75 @@ +package cn.mesmile.workflow.process.vo; + +import cn.mesmile.workflow.constant.WorkFlowConstant; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.flowable.engine.history.HistoricProcessInstance; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +/** + * @author zb + * @Description + */ +@ApiModel(description = "流程定义相关") +@Data +public class DoneProcessVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("流程定义key") + private String processDefKey; + + @ApiModelProperty("流程定义名称") + private String processDefName; + + @ApiModelProperty("开始时间") + private Date startTime; + + @ApiModelProperty("结束时间") + private Date endTime; + + @ApiModelProperty("结束流程累计用时,单位毫秒") + private Long durationInMillis; + + @ApiModelProperty("流程实例名称") + private String name; + + @ApiModelProperty("历史变量") + private Map variables; + + @ApiModelProperty("发起人") + private String applyUser; + + @ApiModelProperty("发起人姓名") + private String applyUserName; + + @ApiModelProperty("删除原因") + private String deleteReason; + + @ApiModelProperty("流程实例id") + private String processInstanceId; + + @ApiModelProperty("流程定义id") + private String processDefinitionId; + + public DoneProcessVO(HistoricProcessInstance instance) { + this.durationInMillis = instance.getDurationInMillis(); + this.startTime = instance.getStartTime(); + this.processDefKey = instance.getProcessDefinitionKey(); + this.processDefName = instance.getProcessDefinitionName(); + this.endTime = instance.getEndTime(); + this.name = instance.getName(); + this.variables = instance.getProcessVariables(); + this.applyUser = instance.getStartUserId(); + this.applyUserName = (String) variables.get(WorkFlowConstant.PROCESS_APPLY_USER_NAME); + this.deleteReason = instance.getDeleteReason(); + this.processInstanceId = instance.getId(); + this.processDefinitionId = instance.getProcessDefinitionId(); + } + + public DoneProcessVO(){} +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ProcessDefinitionVO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ProcessDefinitionVO.java new file mode 100644 index 0000000..0876208 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/ProcessDefinitionVO.java @@ -0,0 +1,52 @@ +package cn.mesmile.workflow.process.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.flowable.engine.repository.ProcessDefinition; + +import java.io.Serializable; + +/** + * @author zb + * @Description + */ +@ApiModel(description = "流程定义相关") +@Data +public class ProcessDefinitionVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("流程定义id") + private String processDefId; + + @ApiModelProperty("流程定义Key") + private String processDefKey; + + @ApiModelProperty("流程定义名称") + private String processDefName; + + @ApiModelProperty("流程定义分类") + private String processDefCategory; + + @ApiModelProperty("流程定义对应的部署id") + private String deploymentId; + + @ApiModelProperty("流程定义版本") + private Integer version; + + @ApiModelProperty("描述") + private String description; + + public ProcessDefinitionVO(ProcessDefinition processDefinition){ + this.processDefId = processDefinition.getId(); + this.processDefKey = processDefinition.getKey(); + this.processDefName = processDefinition.getName(); + this.processDefCategory = processDefinition.getCategory(); + this.deploymentId = processDefinition.getDeploymentId(); + this.version = processDefinition.getVersion(); + this.description = processDefinition.getDescription(); + } + + public ProcessDefinitionVO(){} +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/SendProcessVO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/SendProcessVO.java new file mode 100644 index 0000000..a9e31c1 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/SendProcessVO.java @@ -0,0 +1,75 @@ +package cn.mesmile.workflow.process.vo; + +import cn.mesmile.workflow.constant.WorkFlowConstant; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.flowable.engine.history.HistoricProcessInstance; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +/** + * @author zb + * @Description + */ +@ApiModel(description = "流程定义相关") +@Data +public class SendProcessVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("流程定义key") + private String processDefKey; + + @ApiModelProperty("流程定义名称") + private String processDefName; + + @ApiModelProperty("开始时间") + private Date startTime; + + @ApiModelProperty("结束时间") + private Date endTime; + + @ApiModelProperty("结束流程累计用时,单位毫秒") + private Long durationInMillis; + + @ApiModelProperty("流程实例名称") + private String name; + + @ApiModelProperty("历史变量") + private Map variables; + + @ApiModelProperty("发起人") + private String applyUser; + + @ApiModelProperty("发起人姓名") + private String applyUserName; + + @ApiModelProperty("删除原因") + private String deleteReason; + + @ApiModelProperty("流程实例id") + private String processInstanceId; + + @ApiModelProperty("流程定义id") + private String processDefinitionId; + + public SendProcessVO(HistoricProcessInstance instance) { + this.durationInMillis = instance.getDurationInMillis(); + this.startTime = instance.getStartTime(); + this.processDefKey = instance.getProcessDefinitionKey(); + this.processDefName = instance.getProcessDefinitionName(); + this.endTime = instance.getEndTime(); + this.name = instance.getName(); + this.variables = instance.getProcessVariables(); + this.applyUser = instance.getStartUserId(); + this.applyUserName = (String) variables.get(WorkFlowConstant.PROCESS_APPLY_USER_NAME); + this.deleteReason = instance.getDeleteReason(); + this.processInstanceId = instance.getId(); + this.processDefinitionId = instance.getProcessDefinitionId(); + } + + public SendProcessVO(){} +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/TodoTaskVO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/TodoTaskVO.java new file mode 100644 index 0000000..c168c2b --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/TodoTaskVO.java @@ -0,0 +1,75 @@ +package cn.mesmile.workflow.process.vo; + +import cn.mesmile.workflow.constant.WorkFlowConstant; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.flowable.task.api.Task; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +/** + * @author zb + * @Description + */ +@Data +public class TodoTaskVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("任务id") + private String taskId; + + @ApiModelProperty("流程实例id") + private String processInstanceId; + + @ApiModelProperty("流程定义key,就是流程节点id") + private String taskDefinitionKey; + + @ApiModelProperty("任务名称") + private String name; + + @ApiModelProperty("values") + private Map variables; + + @ApiModelProperty("审批人") + private String assignee; + + @ApiModelProperty("分类") + private String category; + + @ApiModelProperty("创建时间") + private Date createTime; + + @ApiModelProperty("发起人") + private String applyUser; + + @ApiModelProperty("发起人名称") + private String applyUserName; + + @ApiModelProperty("执行id") + private String executionId; + + @ApiModelProperty("到期时间") + private Date dueDate; + + + public TodoTaskVO(Task task){ + this.taskId = task.getId(); + this.processInstanceId = task.getProcessInstanceId(); + this.taskDefinitionKey = task.getTaskDefinitionKey(); + this.name = task.getName(); + this.variables = task.getProcessVariables(); + this.assignee = task.getAssignee(); + this.category = task.getCategory(); + this.createTime = task.getCreateTime(); + this.executionId = task.getExecutionId(); + this.dueDate = task.getDueDate(); + this.applyUser = (String) variables.get(WorkFlowConstant.PROCESS_APPLY_USER); + this.applyUserName = (String) variables.get(WorkFlowConstant.PROCESS_APPLY_USER_NAME); + } + + public TodoTaskVO(){} + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowVO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowVO.java new file mode 100644 index 0000000..c1e9223 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowVO.java @@ -0,0 +1,9 @@ +package cn.mesmile.workflow.process.vo; + +/** + * @author zb + * @Description + */ +public class WorkFlowVO { + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ClaimTaskWrapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ClaimTaskWrapper.java new file mode 100644 index 0000000..a8f1603 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ClaimTaskWrapper.java @@ -0,0 +1,24 @@ +package cn.mesmile.workflow.process.wrapper; + +import cn.mesmile.workflow.process.vo.ClaimTaskVO; +import cn.mesmile.workflow.support.BaseEntityWrapper; +import org.flowable.task.api.Task; + +/** + * @author zb + * @Description + */ +public class ClaimTaskWrapper extends BaseEntityWrapper { + + public static ClaimTaskWrapper build() { + return new ClaimTaskWrapper(); + } + + + @Override + public ClaimTaskVO entityVO(Task entity) { + ClaimTaskVO claimTaskVO = new ClaimTaskVO(entity); + + return claimTaskVO; + } +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/DoneProcessWrapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/DoneProcessWrapper.java new file mode 100644 index 0000000..de51c92 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/DoneProcessWrapper.java @@ -0,0 +1,24 @@ +package cn.mesmile.workflow.process.wrapper; + +import cn.mesmile.workflow.process.vo.DoneProcessVO; +import cn.mesmile.workflow.support.BaseEntityWrapper; +import org.flowable.engine.history.HistoricProcessInstance; + +/** + * @author zb + * @Description + */ +public class DoneProcessWrapper extends BaseEntityWrapper { + + public static DoneProcessWrapper build() { + return new DoneProcessWrapper(); + } + + + @Override + public DoneProcessVO entityVO(HistoricProcessInstance entity) { + DoneProcessVO doneProcessVO = new DoneProcessVO(entity); + + return doneProcessVO; + } +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ProcessDefinitionWrapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ProcessDefinitionWrapper.java new file mode 100644 index 0000000..17b4c33 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/ProcessDefinitionWrapper.java @@ -0,0 +1,25 @@ +package cn.mesmile.workflow.process.wrapper; + +import cn.mesmile.workflow.process.vo.ProcessDefinitionVO; +import cn.mesmile.workflow.support.BaseEntityWrapper; +import org.flowable.engine.repository.ProcessDefinition; + +/** + * @author zb + * @Description + */ +public class ProcessDefinitionWrapper extends BaseEntityWrapper { + + public static ProcessDefinitionWrapper build() { + return new ProcessDefinitionWrapper(); + } + + @Override + public ProcessDefinitionVO entityVO(ProcessDefinition entity) { + ProcessDefinitionVO processDefinitionVO = new ProcessDefinitionVO(entity); + + return processDefinitionVO; + } + + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/SendProcessWrapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/SendProcessWrapper.java new file mode 100644 index 0000000..429c781 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/SendProcessWrapper.java @@ -0,0 +1,24 @@ +package cn.mesmile.workflow.process.wrapper; + +import cn.mesmile.workflow.process.vo.SendProcessVO; +import cn.mesmile.workflow.support.BaseEntityWrapper; +import org.flowable.engine.history.HistoricProcessInstance; + +/** + * @author zb + * @Description + */ +public class SendProcessWrapper extends BaseEntityWrapper { + + public static SendProcessWrapper build() { + return new SendProcessWrapper(); + } + + + @Override + public SendProcessVO entityVO(HistoricProcessInstance entity) { + SendProcessVO sendProcessVO = new SendProcessVO(entity); + + return sendProcessVO; + } +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/TodoTaskWrapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/TodoTaskWrapper.java new file mode 100644 index 0000000..5843d2e --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/TodoTaskWrapper.java @@ -0,0 +1,24 @@ +package cn.mesmile.workflow.process.wrapper; + +import cn.mesmile.workflow.process.vo.TodoTaskVO; +import cn.mesmile.workflow.support.BaseEntityWrapper; +import org.flowable.task.api.Task; + +/** + * @author zb + * @Description + */ +public class TodoTaskWrapper extends BaseEntityWrapper { + + public static TodoTaskWrapper build() { + return new TodoTaskWrapper(); + } + + + @Override + public TodoTaskVO entityVO(Task entity) { + TodoTaskVO todoTaskVO = new TodoTaskVO(entity); + + return todoTaskVO; + } +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/support/BaseEntityWrapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/support/BaseEntityWrapper.java new file mode 100644 index 0000000..47c05c0 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/support/BaseEntityWrapper.java @@ -0,0 +1,37 @@ +package cn.mesmile.workflow.support; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author + * 返回视图层所需的字段 + * @param + * @param + */ +public abstract class BaseEntityWrapper { + + public BaseEntityWrapper() { + } + + /** + * 将实体类中部门字段转换为,视图层可看懂的字段,例如 性别 0 -> 女 , 1 -> 男 + * @param entity + * @return + */ + public abstract V entityVO(E entity); + + public List listVO(List list) { + return (List)list.stream().map(this::entityVO).collect(Collectors.toList()); + } + + public IPage pageVO(IPage pages) { + List records = this.listVO(pages.getRecords()); + Page pageVo = Page.of(pages.getCurrent(), pages.getSize(), pages.getTotal()); + pageVo.setRecords(records); + return pageVo; + } +} \ No newline at end of file diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/util/WorkFlowUtil.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/util/WorkFlowUtil.java new file mode 100644 index 0000000..890c0e7 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/util/WorkFlowUtil.java @@ -0,0 +1,42 @@ +package cn.mesmile.workflow.util; + +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.ExtensionAttribute; +import org.flowable.common.engine.impl.util.io.StringStreamSource; + +import java.util.List; + +/** + * @author zb + * @Description + */ +public class WorkFlowUtil { + + private WorkFlowUtil(){} + + /** + * xml转bpmnModel对象 + * @param xml xml + * @return bpmnModel对象 + */ + public static BpmnModel getBpmnModel(String xml) { + BpmnXMLConverter converter = new BpmnXMLConverter(); + return converter.convertToBpmnModel(new StringStreamSource(xml), false, false); + } + + + /** + * 获取根节点扩展属性 + * @param model bpmnModel对象 + * @param key 扩展元素key + */ + public static String getProcessExtensionAttribute(BpmnModel model, String key) { + List attributes = model.getMainProcess().getAttributes().get(key); + if (attributes != null && attributes.size() > 0) { + return attributes.get(0).getValue(); + } + return null; + } + +} diff --git a/xdclass-workflow/src/main/resources/application-dev.yml b/xdclass-workflow/src/main/resources/application-dev.yml new file mode 100644 index 0000000..6e74b85 --- /dev/null +++ b/xdclass-workflow/src/main/resources/application-dev.yml @@ -0,0 +1,49 @@ +server: + port: 9090 + +spring: + # 数据库配置 + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://81.69.43.78:3306/workflow?useUnicode=true&characterEncoding=utf-8&nullCatalogMeansCurrent=true&useSSL=false&serverTimezone=Asia/Shanghai + username: root + password: task,.123 + # json序列化时间 + jackson: + time-zone: GMT+8 + date-format: yyyy-MM-dd HH:mm:ss + +# 打印 sql 日志 +logging: + level: + org.flowable.engine.impl.persistence.entity.*: debug + org.flowable.task.service.impl.persistence.entity.*: debug + +# mybatis-plus配置 +mybatis-plus: + # 配置 xml 文件所在位置 + mapper-locations: classpath:cn/mesmile/workflow/**/mapper/*Mapper.xml + #实体扫描,多个package用逗号或者分号分隔.mapper + typeAliasesPackage: cn.mesmile.workflow.**.entity + global-config: + # 关闭 LOGO + banner: false + db-config: + # 配置全局的 主键策略,默认为 ASSIGN_ID 默认为 【雪花算法】 + id-type: assign_id + #字段策略 + insert-strategy: not_null + update-strategy: not_null + whereStrategy: not_empty + #驼峰下划线转换 + table-underline: true + #全局逻辑删除 + logic-not-delete-value: 0 + logic-delete-value: 1 + # 开启驼峰命名 默认开启驼峰命名 + # mybatis-plus配置控制台打印完整带参数SQL语句 + configuration: + map-underscore-to-camel-case: true + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + + diff --git a/xdclass-workflow/src/main/resources/application.yml b/xdclass-workflow/src/main/resources/application.yml new file mode 100644 index 0000000..1eb4b9c --- /dev/null +++ b/xdclass-workflow/src/main/resources/application.yml @@ -0,0 +1,33 @@ +# 默认使用 dev 分支 +spring: + profiles: + active: dev + +#flowable配置 +flowable: + # 字体均用宋体 + activity-font-name: \u5B8B\u4F53 + label-font-name: \u5B8B\u4F53 + annotation-font-name: \u5B8B\u4F53 + # 是否需要自动部署流程定义 + check-process-definitions: false + # 开启表⾃动更新 + database-schema-update: true + # 关闭 flowable 定时任务 【异步执行器激活】关闭 + # 关闭异步,不关闭历史数据的插入就是异步的,会在同一个事物里面,无法回滚 + # 开发可开启[true]会提高些效率,上线需要关闭[false] + async-executor-activate: false + app: + enabled: false + cmmn: + enabled: false + idm: + enabled: false + dmn: + enabled: false + form: + enabled: false + content: + enabled: false + eventregistry: + enabled: false diff --git a/xdclass-workflow/src/main/resources/leave.bpmn20.xml b/xdclass-workflow/src/main/resources/leave.bpmn20.xml new file mode 100644 index 0000000..39d763f --- /dev/null +++ b/xdclass-workflow/src/main/resources/leave.bpmn20.xml @@ -0,0 +1,107 @@ + + + + + + + + Flow_01ptaql + + + + + + + + + + + + + + + + Flow_01ptaql + Flow_1j3nllx + + + + + + + + + + + + + + + + + Flow_1j3nllx + Flow_0g0rggk + + + + + + + + + + + + + + + + + Flow_0g0rggk + Flow_1av5bro + + + + Flow_1av5bro + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xdclass-workflow/src/test/java/cn/mesmile/workflow/WorkFlowApplicationTest.java b/xdclass-workflow/src/test/java/cn/mesmile/workflow/WorkFlowApplicationTest.java new file mode 100644 index 0000000..a22eceb --- /dev/null +++ b/xdclass-workflow/src/test/java/cn/mesmile/workflow/WorkFlowApplicationTest.java @@ -0,0 +1,18 @@ +package cn.mesmile.workflow; + +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * @author zb + * @Description + */ +@SpringBootTest +public class WorkFlowApplicationTest { + + @Test + public void test() { + System.out.println("hello workflow"); + } + +} -- Gitee From b72f84178fd95ca4494b7ed46e69c2d86fe94d5e Mon Sep 17 00:00:00 2001 From: superzheng Date: Thu, 20 Jan 2022 23:04:50 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=AE=8C=E6=88=90xdclass-workflow=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E5=92=8C=E5=9B=9E=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/mesmile/juc/reentry/Test.java | 40 ++++++++++ .../workflow/constant/WorkFlowConstant.java | 6 +- .../workflow/process/bo/CompleteTaskBO.java | 30 +++++++ .../controller/WorkFlowController.java | 7 ++ .../process/service/WorkFlowService.java | 9 +++ .../service/impl/WorkFlowServiceImpl.java | 79 +++++++++++++++++++ 6 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 xdclass-juc/src/main/java/cn/mesmile/juc/reentry/Test.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/CompleteTaskBO.java diff --git a/xdclass-juc/src/main/java/cn/mesmile/juc/reentry/Test.java b/xdclass-juc/src/main/java/cn/mesmile/juc/reentry/Test.java new file mode 100644 index 0000000..3c85628 --- /dev/null +++ b/xdclass-juc/src/main/java/cn/mesmile/juc/reentry/Test.java @@ -0,0 +1,40 @@ +package cn.mesmile.juc.reentry; + +import cn.hutool.core.io.FileUtil; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + +/** + * @author zb + * @date 2021/10/14 20:32 + * @Copyright © 沃飞长空科技(成都)有限公司 + * @Description + */ +public class Test { + + public static void main(String[] args) { + FutureTask futureTask = new FutureTask<>(()->{ + System.out.println("通过Callable实现多线程,名称:"+Thread.currentThread().getName()); + return "这是返回值"; + }); +// MyTask myTask = new MyTask(); +// FutureTask futureTask = new FutureTask<>(myTask); + //FutureTask继承了Runnable,可以放在Thread中启动执行 + Thread thread = new Thread(futureTask); + thread.setName("demo3"); + thread.start(); + System.out.println("主线程名称:"+Thread.currentThread().getName()); + try { + System.out.println(futureTask.get()); + } catch (InterruptedException e) { + //阻塞等待中被中断,则抛出 + e.printStackTrace(); + } catch (ExecutionException e) { + //执行过程发送异常被抛出 + e.printStackTrace(); + } + System.out.println("----------------------------"); + } +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java index 13620db..2971bf4 100644 --- a/xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/constant/WorkFlowConstant.java @@ -20,15 +20,15 @@ public interface WorkFlowConstant { //////////////////////////自定义任务完成类型///////////////////////////// /** 自动完成 */ - String AUTO_COMPLETED_TASK = "autoCompletedTask"; + String AUTO_COMPLETED_TASK = "autoCompletedTaskComment"; String AUTO_COMPLETED_TASK_DESCRIBE = "自动完成"; /** 同意 */ - String PASS_TASK = "passTask"; + String PASS_TASK = "passTaskComment"; String PASS_TASK_DESCRIBE = "同意"; /** 驳回 */ - String REFUSE_TASK = "refuseTask"; + String REFUSE_TASK = "refuseTaskComment"; String REFUSE_TASK_DESCRIBE = "驳回"; diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/CompleteTaskBO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/CompleteTaskBO.java new file mode 100644 index 0000000..a6c4f43 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/CompleteTaskBO.java @@ -0,0 +1,30 @@ +package cn.mesmile.workflow.process.bo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Map; + +/** + * @author zb + * @Description + */ +@Data +public class CompleteTaskBO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("任务id") + private String taskId; + + @ApiModelProperty("表单变量") + private Map variables; + + @ApiModelProperty("是否通过") + private Boolean pass; + + @ApiModelProperty("评论意见") + private String comment; + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java index 02bca2c..816db82 100644 --- a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowController.java @@ -2,6 +2,7 @@ package cn.mesmile.workflow.process.controller; import cn.mesmile.workflow.commom.Query; import cn.mesmile.workflow.commom.R; +import cn.mesmile.workflow.process.bo.CompleteTaskBO; import cn.mesmile.workflow.process.bo.StartProcessBO; import cn.mesmile.workflow.process.qo.WorkFlowQO; import cn.mesmile.workflow.process.service.WorkFlowService; @@ -88,6 +89,12 @@ public class WorkFlowController { return R.data(sendProcessVOPage); } + @ApiOperation("完成任务 通过/驳回 ") + @PostMapping("/completeTask") + public R completeTask(@RequestBody CompleteTaskBO completeTaskBO) { + return workFlowService.completeTask(completeTaskBO); + } + diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java index c7c6fcd..289bd8e 100644 --- a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowService.java @@ -1,6 +1,8 @@ package cn.mesmile.workflow.process.service; import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.commom.R; +import cn.mesmile.workflow.process.bo.CompleteTaskBO; import cn.mesmile.workflow.process.qo.WorkFlowQO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.flowable.engine.history.HistoricProcessInstance; @@ -70,4 +72,11 @@ public interface WorkFlowService { * @return 查询结果 */ IPage listSendProcess(Query query, WorkFlowQO workFlowQO); + + /** + * 完成任务 通过或者驳回 + * @param completeTaskBO + * @return + */ + R completeTask(CompleteTaskBO completeTaskBO); } diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java index ff5e204..ce6dbc5 100644 --- a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowServiceImpl.java @@ -1,7 +1,9 @@ package cn.mesmile.workflow.process.service.impl; import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.commom.R; import cn.mesmile.workflow.constant.WorkFlowConstant; +import cn.mesmile.workflow.process.bo.CompleteTaskBO; import cn.mesmile.workflow.process.qo.WorkFlowQO; import cn.mesmile.workflow.process.service.WorkFlowService; import cn.mesmile.workflow.util.WorkFlowUtil; @@ -16,6 +18,7 @@ import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinitionQuery; +import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.flowable.task.api.TaskQuery; @@ -24,6 +27,7 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.stream.Collectors; /** * @author zb @@ -286,5 +290,80 @@ public class WorkFlowServiceImpl implements WorkFlowService { return page; } + @Override + public R completeTask(CompleteTaskBO completeTaskBO) { + Boolean pass = completeTaskBO.getPass(); + String taskId = completeTaskBO.getTaskId(); + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task == null){ + return R.fail("当前任务不存在"+taskId); + } + if (pass == null || pass){ + // 默认通过 + passTask(completeTaskBO, task); + }else { + // 拒绝/驳回 + rejectTask(task, completeTaskBO); + } + return R.data("操作成功"); + } + + /** + * 驳回/拒绝 操作 + * @param task 当前任务 + * @param completeTaskBO 完成任务参数 + */ + private void rejectTask(Task task,CompleteTaskBO completeTaskBO) { + String processDefinitionId = task.getProcessDefinitionId(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + // 找默认回退节点 + String processExtensionAttribute = WorkFlowUtil.getProcessExtensionAttribute(bpmnModel, WorkFlowConstant.ROLLBACK_NODE); + if (StringUtils.isNotBlank(processExtensionAttribute) && Objects.equals("true", processExtensionAttribute)){ + String processInstanceId = task.getProcessInstanceId(); + if (StringUtils.isNotBlank(completeTaskBO.getComment())){ + // 添加驳回评论 + taskService.addComment(task.getId(),processInstanceId, WorkFlowConstant.REFUSE_TASK,completeTaskBO.getComment()); + } + // 回退到指定节点 + goToTargetActivity(processInstanceId, processExtensionAttribute); + }else { + // todo 若没有默认回退节点,则回退到上一步 + + } + } + + /** + * 流转到指定的节点 + * @param processInstanceId 流程实例id + * @param targetNodeId 目标节点id + */ + private void goToTargetActivity(String processInstanceId, String targetNodeId) { + List list = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list(); + Set currentActivityIds = list.stream().map(Execution::getActivityId).collect(Collectors.toSet()); + runtimeService.createChangeActivityStateBuilder() + .moveActivityIdsToSingleActivityId(new ArrayList<>(currentActivityIds), targetNodeId) + .changeState(); + } + + /** + * 完成通过任务 + * @param completeTaskBO 完成任务参数 + * @param task 当前任务 + */ + private void passTask(CompleteTaskBO completeTaskBO, Task task) { + String processInstanceId = task.getProcessInstanceId(); + String taskId = task.getId(); + if (StringUtils.isNotBlank(completeTaskBO.getComment())){ + // 添加评论 + taskService.addComment(taskId, processInstanceId, completeTaskBO.getComment()); + } + Map variables = completeTaskBO.getVariables(); + if (variables == null){ + variables = new HashMap<>(2); + } + // 完成任务 + taskService.complete(taskId, variables); + } + } -- Gitee