From 518ec60afd92640dd8cada261b055e4005f6ae25 Mon Sep 17 00:00:00 2001 From: superzheng Date: Fri, 21 Jan 2022 17:07:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(xdclass-workflow):=20xdclass-workflow?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=B5=81=E6=A8=A1=E5=9D=97(=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E9=80=9A=E8=BF=87=EF=BC=8C=E9=A9=B3=E5=9B=9E=EF=BC=8C?= =?UTF-8?q?=E5=8A=A0=E7=AD=BE=EF=BC=8C=E5=87=8F=E7=AD=BE=EF=BC=8C=E6=8C=87?= =?UTF-8?q?=E5=AE=9A=E5=9B=9E=E9=80=80)=20=E5=85=A8=E5=B1=80=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E4=BA=BA=E5=88=86=E9=85=8D=E6=8B=A6=E6=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xdclass-workflow工作流模块(任务通过,驳回,加签,减签,指定回退)、全局审批人分配拦截 --- .../WorkFlowActivityBehaviorFactory.java | 30 ++ .../WorkFlowUserTaskActivityBehavior.java | 37 ++ .../workflow/config/WorkFlowConfig.java | 10 - .../config/WorkFlowProcessEngineConfig.java | 20 + .../workflow/constant/WorkFlowConstant.java | 26 ++ ...mpleteTaskBO.java => OperationTaskBO.java} | 16 +- .../controller/WorkFlowAdminController.java | 90 ++++ .../controller/WorkFlowController.java | 61 ++- .../workflow/process/dto/WorkFlowNodeDTO.java | 32 ++ .../workflow/process/qo/WorkFlowAdminQO.java | 41 ++ .../process/service/WorkFlowAdminService.java | 64 +++ .../process/service/WorkFlowService.java | 70 ++- .../impl/WorkFlowAdminServiceImpl.java | 179 ++++++++ .../service/impl/WorkFlowServiceImpl.java | 427 ++++++++++++++---- .../workflow/process/vo/WorkFlowNodeVO.java | 24 + .../process/wrapper/WorkFlowNodeWrapper.java | 26 ++ .../mesmile/workflow/util/WorkFlowUtil.java | 24 +- 17 files changed, 1080 insertions(+), 97 deletions(-) create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowActivityBehaviorFactory.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowUserTaskActivityBehavior.java delete mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowConfig.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowProcessEngineConfig.java rename xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/{CompleteTaskBO.java => OperationTaskBO.java} (57%) create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowAdminController.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowNodeDTO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowAdminQO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowAdminService.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowAdminServiceImpl.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowNodeVO.java create mode 100644 xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/WorkFlowNodeWrapper.java diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowActivityBehaviorFactory.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowActivityBehaviorFactory.java new file mode 100644 index 0000000..2f5e09c --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowActivityBehaviorFactory.java @@ -0,0 +1,30 @@ +package cn.mesmile.workflow.behavior; + +import org.flowable.bpmn.model.Activity; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; +import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; +import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; + +/** + * @author zb + * @Description + */ +public class WorkFlowActivityBehaviorFactory extends DefaultActivityBehaviorFactory { + + + @Override + public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { + // 自定义所有节点相关拦截 + return new WorkFlowUserTaskActivityBehavior(userTask); + } + + @Override + public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { + // TODO 自定义多实例拦截 逻辑同上 + return super.createParallelMultiInstanceBehavior(activity, innerActivityBehavior); + } + + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowUserTaskActivityBehavior.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowUserTaskActivityBehavior.java new file mode 100644 index 0000000..beae5b4 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/behavior/WorkFlowUserTaskActivityBehavior.java @@ -0,0 +1,37 @@ +package cn.mesmile.workflow.behavior; + +import org.flowable.bpmn.model.UserTask; +import org.flowable.common.engine.impl.el.ExpressionManager; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; +import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl; +import org.flowable.task.service.TaskService; +import org.flowable.task.service.impl.persistence.entity.TaskEntity; + +import java.util.List; + +/** + * @author zb + * @Description + */ +public class WorkFlowUserTaskActivityBehavior extends UserTaskActivityBehavior { + + public WorkFlowUserTaskActivityBehavior(UserTask userTask) { + super(userTask); + } + + @Override + protected void handleAssignments(TaskService taskService, String assignee, String owner, List candidateUsers, + List candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution, + ProcessEngineConfigurationImpl processEngineConfiguration){ + + // TODO 统一拦截分配设置审批人 + //////////////////////统一拦截分配设置审批人////////////////////////// + + + super.handleAssignments(taskService, assignee, owner, candidateUsers, candidateGroups, task, expressionManager,execution,processEngineConfiguration); + + } + + +} 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 deleted file mode 100644 index fbfea19..0000000 --- a/xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.mesmile.workflow.config; - -/** - * @author zb - * @Description - */ -public class WorkFlowConfig { - - -} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowProcessEngineConfig.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowProcessEngineConfig.java new file mode 100644 index 0000000..50795ab --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/config/WorkFlowProcessEngineConfig.java @@ -0,0 +1,20 @@ +package cn.mesmile.workflow.config; + +import cn.mesmile.workflow.behavior.WorkFlowActivityBehaviorFactory; +import org.flowable.spring.SpringProcessEngineConfiguration; +import org.flowable.spring.boot.EngineConfigurationConfigurer; +import org.springframework.context.annotation.Configuration; + +/** + * @author zb + * @Description + */ +@Configuration +public class WorkFlowProcessEngineConfig implements EngineConfigurationConfigurer { + + @Override + public void configure(SpringProcessEngineConfiguration engineConfiguration) { + engineConfiguration.setActivityBehaviorFactory(new WorkFlowActivityBehaviorFactory()); + } + +} 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 2971bf4..de47f00 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 @@ -31,6 +31,32 @@ public interface WorkFlowConstant { String REFUSE_TASK = "refuseTaskComment"; String REFUSE_TASK_DESCRIBE = "驳回"; + /** 转办 */ + String TRANSFER_TASK = "transferTaskComment"; + String TRANSFER_TASK_DESCRIBE = "转办"; + + /** 委托 */ + String DELEGATE_TASK = "delegateTaskComment"; + String DELEGATE_TASK_DESCRIBE = "委托"; + + /** 终止 */ + String TERMINATION_TASK = "terminationTaskComment"; + String TERMINATION_TASK_DESCRIBE = "终止"; + + /** 加签 */ + String ADD_MULTI_INSTANCE = "addMultiInstanceComment"; + String ADD_MULTI_INSTANCE_DESCRIBE = "加签"; + + /** 减签 */ + String DELETE_MULTI_INSTANCE = "deleteMultiInstanceComment"; + String DELETE_MULTI_INSTANCE_DESCRIBE = "减签"; + + /** 回退 */ + String ROLL_BACK_TASK = "rollbackNodeTaskComment"; + String ROLL_BACK_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/OperationTaskBO.java similarity index 57% rename from xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/CompleteTaskBO.java rename to xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/OperationTaskBO.java index a6c4f43..a8db2e0 100644 --- a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/CompleteTaskBO.java +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/bo/OperationTaskBO.java @@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; +import java.util.List; import java.util.Map; /** @@ -11,7 +12,7 @@ import java.util.Map; * @Description */ @Data -public class CompleteTaskBO implements Serializable { +public class OperationTaskBO implements Serializable { private static final long serialVersionUID = 1L; @@ -27,4 +28,17 @@ public class CompleteTaskBO implements Serializable { @ApiModelProperty("评论意见") private String comment; + @ApiModelProperty("多个任务id列表") + private List taskIdList; + + @ApiModelProperty("接收人") + private String receiveUserId; + + @ApiModelProperty("多个接收人") + private List receiveUserIdList; + + @ApiModelProperty("回退目标节点id") + private String targetNodeId; + + } diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowAdminController.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowAdminController.java new file mode 100644 index 0000000..fd5c21d --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/controller/WorkFlowAdminController.java @@ -0,0 +1,90 @@ +package cn.mesmile.workflow.process.controller; + +import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.commom.R; +import cn.mesmile.workflow.process.bo.OperationTaskBO; +import cn.mesmile.workflow.process.qo.WorkFlowAdminQO; +import cn.mesmile.workflow.process.service.WorkFlowAdminService; +import cn.mesmile.workflow.process.vo.TodoTaskVO; +import cn.mesmile.workflow.process.wrapper.TodoTaskWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.AllArgsConstructor; +import org.flowable.task.api.Task; +import org.springframework.web.bind.annotation.*; + +/** + * @author zb + * @Description + */ +@Api(value = "流程运维相关接口", tags = "流程运维相关接口") +@AllArgsConstructor +@RequestMapping("/api/v1/workflow/admin") +@RestController +public class WorkFlowAdminController { + + private final WorkFlowAdminService workFlowAdminService; + + + @ApiOperation("查询 所有待办任务 列表") + @GetMapping("/listAllTodoTask") + public R listTodoTask(Query query, WorkFlowAdminQO workFlowAdminQO){ + IPage taskPage = workFlowAdminService.listAllTodoTask(query, workFlowAdminQO); + IPage todoTaskVOPage = TodoTaskWrapper.build().pageVO(taskPage); + return R.data(todoTaskVOPage); + } + + @ApiOperation("催办任务处理人,处理任务,这里是发送通知消息") + @PostMapping("/urgeTask") + public R urgeTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowAdminService.urgeTask(operationTaskBO); + return R.status(true); + } + + @ApiOperation("转办任务") + @PostMapping("/transferTask") + public R transferTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowAdminService.transferTask(operationTaskBO); + return R.success("转办任务成功"); + } + + @ApiOperation("委托任务") + @PostMapping("/delegateTask") + public R delegateTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowAdminService.delegateTask(operationTaskBO); + return R.success("委托任务成功"); + } + + @ApiOperation("终止任务,跳转流程到结束节点") + @PostMapping("/terminationTask") + public R terminationTask (@RequestBody OperationTaskBO operationTaskBO){ + workFlowAdminService.terminationTask(operationTaskBO); + return R.success("终止任务成功"); + } + + @ApiOperation("加签任务") + @PostMapping("/addMultiInstance") + public R addMultiInstance(@RequestBody OperationTaskBO operationTaskBO){ + workFlowAdminService.addMultiInstance(operationTaskBO); + return R.success("加签任务成功"); + } + + @ApiOperation("减签任务") + @PostMapping("/deleteMultiInstance") + public R deleteMultiInstance(@RequestBody OperationTaskBO operationTaskBO){ + workFlowAdminService.deleteMultiInstance(operationTaskBO); + return R.success("减签任务成功"); + } + + @ApiOperation("指定回退任务到指定节点") + @PostMapping("/rollbackTask") + public R rollbackTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowAdminService.rollbackTask(operationTaskBO); + return R.success("回退任务到指定节点成功"); + } + + + + +} 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 816db82..087ea56 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,7 +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.OperationTaskBO; import cn.mesmile.workflow.process.bo.StartProcessBO; import cn.mesmile.workflow.process.qo.WorkFlowQO; import cn.mesmile.workflow.process.service.WorkFlowService; @@ -91,10 +91,65 @@ public class WorkFlowController { @ApiOperation("完成任务 通过/驳回 ") @PostMapping("/completeTask") - public R completeTask(@RequestBody CompleteTaskBO completeTaskBO) { - return workFlowService.completeTask(completeTaskBO); + public R completeTask(@RequestBody OperationTaskBO operationTaskBO) { + return workFlowService.completeTask(operationTaskBO); } + @ApiOperation("催办任务处理人,处理任务,这里是发送通知消息") + @PostMapping("/urgeTask") + public R urgeTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowService.urgeTask(operationTaskBO); + return R.status(true); + } + + @ApiOperation("转办任务") + @PostMapping("/transferTask") + public R transferTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowService.transferTask(operationTaskBO); + return R.success("转办任务成功"); + } + + @ApiOperation("委托任务") + @PostMapping("/delegateTask") + public R delegateTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowService.delegateTask(operationTaskBO); + return R.success("委托任务成功"); + } + + @ApiOperation("终止任务,跳转流程到结束节点") + @PostMapping("/terminationTask") + public R terminationTask (@RequestBody OperationTaskBO operationTaskBO){ + workFlowService.terminationTask(operationTaskBO); + return R.success("终止任务成功"); + } + + @ApiOperation("加签任务") + @PostMapping("/addMultiInstance") + public R addMultiInstance(@RequestBody OperationTaskBO operationTaskBO){ + workFlowService.addMultiInstance(operationTaskBO); + return R.success("加签任务成功"); + } + + @ApiOperation("减签任务") + @PostMapping("/deleteMultiInstance") + public R deleteMultiInstance(@RequestBody OperationTaskBO operationTaskBO){ + workFlowService.deleteMultiInstance(operationTaskBO); + return R.success("减签任务成功"); + } + + @ApiOperation("回退任务到指定节点") + @PostMapping("/rollbackTask") + public R rollbackTask(@RequestBody OperationTaskBO operationTaskBO){ + workFlowService.rollbackTask(operationTaskBO); + return R.success("回退任务到指定节点成功"); + } + + @ApiOperation("获取可回退节点的列表") + @PostMapping("/getBackNodeList") + public R getBackNodeList(OperationTaskBO operationTaskBO){ + workFlowService.getBackNodeList(operationTaskBO); + return R.success("获取列表成功"); + } diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowNodeDTO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowNodeDTO.java new file mode 100644 index 0000000..0993c7f --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/dto/WorkFlowNodeDTO.java @@ -0,0 +1,32 @@ +package cn.mesmile.workflow.process.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author zb + * @Description + */ +@Data +public class WorkFlowNodeDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("节点id") + private String nodeId; + + @ApiModelProperty("节点名称") + private String nodeName; + + @ApiModelProperty("执行人的id") + private String userId; + + @ApiModelProperty("执行人姓名") + private String userName; + + @ApiModelProperty("任务节点结束时间") + private Date endTime; +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowAdminQO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowAdminQO.java new file mode 100644 index 0000000..8609630 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/qo/WorkFlowAdminQO.java @@ -0,0 +1,41 @@ +package cn.mesmile.workflow.process.qo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * @author zb + * @Description + */ +@Data +public class WorkFlowAdminQO extends WorkFlowQO{ + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("任务id") + private String taskId; + + @ApiModelProperty("流程实例id") + private String processInstanceId; + + @ApiModelProperty("审核人") + private String assignee; + + @ApiModelProperty("候选人") + private String candidateUsers; + + @ApiModelProperty("候选组") + private String candidateGroups; + + @ApiModelProperty("是否挂起") + private Boolean isSuspended; + + @ApiModelProperty("是否多实例") + private Boolean isMultiInstance; + + @ApiModelProperty("多个任务id") + private List taskIdList; +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowAdminService.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowAdminService.java new file mode 100644 index 0000000..ef66664 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/WorkFlowAdminService.java @@ -0,0 +1,64 @@ +package cn.mesmile.workflow.process.service; + +import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.process.bo.OperationTaskBO; +import cn.mesmile.workflow.process.qo.WorkFlowAdminQO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.flowable.task.api.Task; + +/** + * @author zb + * @Description 流程运维相关接口 + */ +public interface WorkFlowAdminService { + + /** + * 查询所有待办的任务 + * @param query 分页参数 + * @param workFlowAdminQO 查询参数 + * @return + */ + IPage listAllTodoTask(Query query, WorkFlowAdminQO workFlowAdminQO); + + /** + * 催办任务,发送通知消息 + * @param operationTaskBO + */ + void urgeTask(OperationTaskBO operationTaskBO); + + /** + * 转办任务 + * @param operationTaskBO + */ + void transferTask(OperationTaskBO operationTaskBO); + + /** + * 委托任务 + * @param operationTaskBO + */ + void delegateTask(OperationTaskBO operationTaskBO); + + /** + * 终止任务,即终止流程 跳转到任务结束点 + * @param operationTaskBO + */ + void terminationTask(OperationTaskBO operationTaskBO); + + /** + * 加签任务 + * @param operationTaskBO + */ + void addMultiInstance(OperationTaskBO operationTaskBO); + + /** + * 减签任务 + * @param operationTaskBO + */ + void deleteMultiInstance(OperationTaskBO operationTaskBO); + + /** + * 回退任务到指定节点 + * @param operationTaskBO + */ + void rollbackTask(OperationTaskBO operationTaskBO); +} 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 289bd8e..64577ea 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 @@ -2,7 +2,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.bo.OperationTaskBO; +import cn.mesmile.workflow.process.dto.WorkFlowNodeDTO; import cn.mesmile.workflow.process.qo.WorkFlowQO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.flowable.engine.history.HistoricProcessInstance; @@ -11,6 +12,7 @@ import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; +import java.util.List; import java.util.Map; /** @@ -75,8 +77,70 @@ public interface WorkFlowService { /** * 完成任务 通过或者驳回 - * @param completeTaskBO + * @param operationTaskBO 操作任务 * @return */ - R completeTask(CompleteTaskBO completeTaskBO); + R completeTask(OperationTaskBO operationTaskBO); + + /** + * 催办任务,发送通知消息 + * @param operationTaskBO + */ + void urgeTask(OperationTaskBO operationTaskBO); + + /** + * 转交任务 + * @param operationTaskBO 转办参数 + */ + void transferTask(OperationTaskBO operationTaskBO); + + /** + * 委托任务【委托任务,当被委托人完成任务后,会重新回到这个节点】 + * @param operationTaskBO + */ + void delegateTask(OperationTaskBO operationTaskBO); + + /** + * 终止流程,跳转任务到结束点 + * @param operationTaskBO + */ + void terminationTask(OperationTaskBO operationTaskBO); + + /** + * 加签任务 + * @param operationTaskBO + */ + void addMultiInstance(OperationTaskBO operationTaskBO); + + /** + * 减签任务 + * @param operationTaskBO + */ + void deleteMultiInstance(OperationTaskBO operationTaskBO); + + /** + * 回退任务到指定节点 + * @param operationTaskBO + */ + void rollbackTask(OperationTaskBO operationTaskBO); + + /** + * 签收任务 + * @param taskId + */ + void claimTask(String taskId); + + /** + * 获取可回退的节点列表 + * @param operationTaskBO 传入当前任务id + * @return 主流程中可回退的节点列表 + */ + List getBackNodeList(OperationTaskBO operationTaskBO); + + /** + * 获取上一步可回退的节点 + * @param operationTaskBO 当前任务id + * @return + */ + WorkFlowNodeDTO getPreBackNode(OperationTaskBO operationTaskBO); } diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowAdminServiceImpl.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowAdminServiceImpl.java new file mode 100644 index 0000000..4b2d1c6 --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/service/impl/WorkFlowAdminServiceImpl.java @@ -0,0 +1,179 @@ +package cn.mesmile.workflow.process.service.impl; + +import cn.mesmile.workflow.commom.Query; +import cn.mesmile.workflow.constant.WorkFlowConstant; +import cn.mesmile.workflow.process.bo.OperationTaskBO; +import cn.mesmile.workflow.process.qo.WorkFlowAdminQO; +import cn.mesmile.workflow.process.service.WorkFlowAdminService; +import cn.mesmile.workflow.process.service.WorkFlowService; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.flowable.engine.*; +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.Date; +import java.util.List; + +/** + * @author zb + * @Description + */ +@Slf4j +@AllArgsConstructor +@Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS, readOnly = true) +@Service +public class WorkFlowAdminServiceImpl implements WorkFlowAdminService { + + private final RepositoryService repositoryService; + private final RuntimeService runtimeService; + private final TaskService taskService; + private final HistoryService historyService; + private final IdentityService identityService; + + private final WorkFlowService workFlowService; + + @Override + public IPage listAllTodoTask(Query query, WorkFlowAdminQO workFlowAdminQO) { + TaskQuery taskQuery = taskService.createTaskQuery() + .orderByTaskCreateTime().desc(); + + String processDefName = workFlowAdminQO.getProcessDefName(); + String processDefKey = workFlowAdminQO.getProcessDefKey(); + String taskName = workFlowAdminQO.getTaskName(); + String applyUser = workFlowAdminQO.getApplyUser(); + Date startDate = workFlowAdminQO.getStartDate(); + Date endDate = workFlowAdminQO.getEndDate(); + String taskId = workFlowAdminQO.getTaskId(); + String assignee = workFlowAdminQO.getAssignee(); + String processInstanceId = workFlowAdminQO.getProcessInstanceId(); + Boolean isSuspended = workFlowAdminQO.getIsSuspended(); + List categoryList = workFlowAdminQO.getCategoryList(); + if (StringUtils.isNotBlank(processDefName)){ + taskQuery.processDefinitionNameLike("%"+processDefName+"%"); + } + if (StringUtils.isNotBlank(processDefKey)){ + taskQuery.processDefinitionKey(processDefName); + } + if (StringUtils.isNotBlank(taskName)){ + taskQuery.taskNameLike("%"+taskName+"%"); + } + if(StringUtils.isNotBlank(applyUser)){ + taskQuery.processVariableValueEquals(WorkFlowConstant.PROCESS_APPLY_USER, applyUser); + } + if (startDate != null){ + taskQuery.taskCreatedAfter(startDate); + } + if (endDate != null){ + taskQuery.taskCreatedBefore(endDate); + } + if (StringUtils.isNotBlank(taskId)){ + taskQuery.taskId(taskId); + } + if (StringUtils.isNotBlank(assignee)){ + taskQuery.taskAssignee(assignee); + } + if (StringUtils.isNotBlank(processInstanceId)){ + taskQuery.processInstanceId(processInstanceId); + } + if (isSuspended == null || isSuspended){ + taskQuery.active(); + } + if (categoryList != null && categoryList.size() > 0){ + taskQuery.processCategoryIn(categoryList); + } + long total = taskQuery.count(); + Integer current = query.getCurrent(); + Integer size = query.getSize(); + Page page = Page.of(current, size, total); + List tasks = taskQuery.listPage((current - 1) * size, size); + page.setRecords(tasks); + return page; + } + + @Override + public void urgeTask(OperationTaskBO operationTaskBO) { + List taskIdList = operationTaskBO.getTaskIdList(); + if (taskIdList != null && taskIdList.size() > 0){ + taskIdList.forEach(taskId ->{ + operationTaskBO.setTaskId(taskId); + // 催办任务 + workFlowService.urgeTask(operationTaskBO); + }); + } + } + + @Override + public void transferTask(OperationTaskBO operationTaskBO) { + List taskIdList = operationTaskBO.getTaskIdList(); + if (taskIdList != null && taskIdList.size() > 0){ + taskIdList.forEach(taskId -> { + operationTaskBO.setTaskId(taskId); + // 转办任务 + workFlowService.transferTask(operationTaskBO); + }); + } + } + + @Override + public void delegateTask(OperationTaskBO operationTaskBO) { + List taskIdList = operationTaskBO.getTaskIdList(); + if (taskIdList != null && taskIdList.size() > 0){ + taskIdList.forEach(taskId -> { + operationTaskBO.setTaskId(taskId); + // 委托任务 + workFlowService.delegateTask(operationTaskBO); + }); + } + } + + @Override + public void terminationTask(OperationTaskBO operationTaskBO) { + List taskIdList = operationTaskBO.getTaskIdList(); + if (taskIdList != null && taskIdList.size() > 0) { + taskIdList.forEach(taskId -> { + operationTaskBO.setTaskId(taskId); + // 终止任务 + workFlowService.terminationTask(operationTaskBO); + }); + } + } + + @Override + public void addMultiInstance(OperationTaskBO operationTaskBO) { + List taskIdList = operationTaskBO.getTaskIdList(); + if (taskIdList != null && taskIdList.size() > 0) { + taskIdList.forEach(taskId -> { + operationTaskBO.setTaskId(taskId); + // 加签任务 + workFlowService.addMultiInstance(operationTaskBO); + }); + } + } + + @Override + public void deleteMultiInstance(OperationTaskBO operationTaskBO) { + List taskIdList = operationTaskBO.getTaskIdList(); + if (taskIdList != null && taskIdList.size() > 0) { + taskIdList.forEach(taskId -> { + operationTaskBO.setTaskId(taskId); + // 减签任务 + workFlowService.deleteMultiInstance(operationTaskBO); + }); + } + } + + @Override + public void rollbackTask(OperationTaskBO operationTaskBO) { + // 回退任务 + workFlowService.rollbackTask(operationTaskBO); + } + + +} 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 ce6dbc5..323faa2 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 @@ -3,18 +3,25 @@ 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.bo.OperationTaskBO; +import cn.mesmile.workflow.process.dto.WorkFlowNodeDTO; 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 com.google.common.collect.Sets; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.constants.BpmnXMLConstants; +import org.flowable.bpmn.model.*; +import org.flowable.bpmn.model.Process; import org.flowable.engine.*; +import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.impl.util.ExecutionGraphUtil; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinitionQuery; @@ -25,6 +32,7 @@ import org.flowable.task.api.TaskQuery; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import java.util.*; import java.util.stream.Collectors; @@ -33,7 +41,8 @@ import java.util.stream.Collectors; * @author zb * @Description */ -@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS,readOnly = true) +@Slf4j +@Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS, readOnly = true) @AllArgsConstructor @Service public class WorkFlowServiceImpl implements WorkFlowService { @@ -59,10 +68,10 @@ public class WorkFlowServiceImpl implements WorkFlowService { @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, "管理员"); + identityService.setAuthenticatedUserId(WorkFlowUtil.getCurrentUserId()); + // TODO 自定义逻辑,存入申请人的 id 和 名称 + variables.put(WorkFlowConstant.PROCESS_APPLY_USER, WorkFlowUtil.getCurrentUserId()); + variables.put(WorkFlowConstant.PROCESS_APPLY_USER_NAME, WorkFlowUtil.getCurrentUserName()); ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefId, variables); String processInstanceId = processInstance.getProcessInstanceId(); @@ -71,13 +80,13 @@ public class WorkFlowServiceImpl implements WorkFlowService { BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId); // 判断是否跳过第一个节点 String skipNode = WorkFlowUtil.getProcessExtensionAttribute(bpmnModel, WorkFlowConstant.SKIP_FIRST_NODE); - if (StringUtils.isNotBlank(skipNode) && Objects.equals("true", skipNode)){ + if (StringUtils.isNotBlank(skipNode) && Objects.equals("true", skipNode)) { List list = taskService.createTaskQuery().processInstanceId(processInstanceId).list(); - if (list != null && list.size() > 0){ - list.forEach(task ->{ + 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.addComment(taskId, processInstanceId, WorkFlowConstant.AUTO_COMPLETED_TASK, WorkFlowConstant.AUTO_COMPLETED_TASK_DESCRIBE); // 自动完成 taskService.complete(taskId); }); @@ -95,16 +104,16 @@ public class WorkFlowServiceImpl implements WorkFlowService { String processDefKey = workFlowQO.getProcessDefKey(); String category = workFlowQO.getCategory(); Boolean lastVersion = workFlowQO.getLastVersion(); - if (StringUtils.isNotBlank(processDefName)){ - processDefinitionQuery.processDefinitionNameLike("%"+processDefName+"%"); + if (StringUtils.isNotBlank(processDefName)) { + processDefinitionQuery.processDefinitionNameLike("%" + processDefName + "%"); } - if (StringUtils.isNotBlank(processDefKey)){ + if (StringUtils.isNotBlank(processDefKey)) { processDefinitionQuery.processDefinitionKey(processDefKey); } - if (StringUtils.isNotBlank(category)){ + if (StringUtils.isNotBlank(category)) { processDefinitionQuery.processDefinitionCategory(category); } - if (lastVersion != null && lastVersion){ + if (lastVersion != null && lastVersion) { processDefinitionQuery.latestVersion(); } long total = processDefinitionQuery.count(); @@ -121,7 +130,7 @@ public class WorkFlowServiceImpl implements WorkFlowService { // 查审批 TaskQuery taskQuery = taskService.createTaskQuery() // todo 传入当前用户 - .taskCandidateOrAssigned("admin") + .taskCandidateOrAssigned(WorkFlowUtil.getCurrentUserId()) .taskCandidateGroupIn(new ArrayList<>()) // 候选组 .active() // 激活的 .orderByTaskCreateTime().desc(); @@ -133,25 +142,25 @@ public class WorkFlowServiceImpl implements WorkFlowService { Date startDate = workFlowQO.getStartDate(); Date endDate = workFlowQO.getEndDate(); List categoryList = workFlowQO.getCategoryList(); - if (StringUtils.isNotBlank(processDefName)){ - taskQuery.processDefinitionNameLike("%"+ processDefName + "%"); + if (StringUtils.isNotBlank(processDefName)) { + taskQuery.processDefinitionNameLike("%" + processDefName + "%"); } - if (StringUtils.isNotBlank(processDefName)){ + if (StringUtils.isNotBlank(processDefName)) { taskQuery.processDefinitionKey(processDefKey); } - if (StringUtils.isNotBlank(taskName)){ + if (StringUtils.isNotBlank(taskName)) { taskQuery.taskName(taskName); } - if (categoryList != null && categoryList.size() > 0){ + if (categoryList != null && categoryList.size() > 0) { taskQuery.processCategoryIn(categoryList); } - if (StringUtils.isNotBlank(applyUser)){ + if (StringUtils.isNotBlank(applyUser)) { taskQuery.processVariableValueEquals(WorkFlowConstant.PROCESS_APPLY_USER, applyUser); } - if (startDate != null){ + if (startDate != null) { taskQuery.taskCreatedAfter(startDate); } - if (endDate != null){ + if (endDate != null) { taskQuery.taskCreatedBefore(endDate); } long count = taskQuery.count(); @@ -169,7 +178,7 @@ public class WorkFlowServiceImpl implements WorkFlowService { // 查【候选】 TaskQuery taskQuery = taskService.createTaskQuery() // 当前用户是否存在于候选人之内 - .taskCandidateUser("admin") + .taskCandidateUser(WorkFlowUtil.getCurrentUserId()) // 查询当前用户所在的候选组 .taskCandidateGroupIn(new ArrayList<>()) .active() @@ -182,25 +191,25 @@ public class WorkFlowServiceImpl implements WorkFlowService { Date startDate = workFlowQO.getStartDate(); Date endDate = workFlowQO.getEndDate(); List categoryList = workFlowQO.getCategoryList(); - if (StringUtils.isNotBlank(processDefName)){ - taskQuery.processDefinitionNameLike("%"+ processDefName + "%"); + if (StringUtils.isNotBlank(processDefName)) { + taskQuery.processDefinitionNameLike("%" + processDefName + "%"); } - if (StringUtils.isNotBlank(processDefName)){ + if (StringUtils.isNotBlank(processDefName)) { taskQuery.processDefinitionKey(processDefKey); } - if (StringUtils.isNotBlank(taskName)){ + if (StringUtils.isNotBlank(taskName)) { taskQuery.taskName(taskName); } - if (categoryList != null && categoryList.size() > 0){ + if (categoryList != null && categoryList.size() > 0) { taskQuery.processCategoryIn(categoryList); } - if (StringUtils.isNotBlank(applyUser)){ + if (StringUtils.isNotBlank(applyUser)) { taskQuery.processVariableValueEquals(WorkFlowConstant.PROCESS_APPLY_USER, applyUser); } - if (startDate != null){ + if (startDate != null) { taskQuery.taskCreatedAfter(startDate); } - if (endDate != null){ + if (endDate != null) { taskQuery.taskCreatedBefore(endDate); } long count = taskQuery.count(); @@ -217,7 +226,7 @@ public class WorkFlowServiceImpl implements WorkFlowService { public IPage listDoneProcess(Query query, WorkFlowQO workFlowQO) { HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() // TODO 传入当前用户 查询当前用户所涉及到的流程实例 - .involvedUser("admin") + .involvedUser(WorkFlowUtil.getCurrentUserId()) .orderByProcessInstanceStartTime() .desc(); String processDefName = workFlowQO.getProcessDefName(); @@ -226,22 +235,22 @@ public class WorkFlowServiceImpl implements WorkFlowService { String applyUser = workFlowQO.getApplyUser(); Date startDate = workFlowQO.getStartDate(); Date endDate = workFlowQO.getEndDate(); - if (StringUtils.isNotBlank(processDefName)){ - processInstanceQuery.processDefinitionName("%"+processDefName+"%"); + if (StringUtils.isNotBlank(processDefName)) { + processInstanceQuery.processDefinitionName("%" + processDefName + "%"); } - if (StringUtils.isNotBlank(processDefKey)){ + if (StringUtils.isNotBlank(processDefKey)) { processInstanceQuery.processDefinitionKey(processDefKey); } - if (StringUtils.isNotBlank(category)){ + if (StringUtils.isNotBlank(category)) { processInstanceQuery.processDefinitionCategory(category); } - if (StringUtils.isNotBlank(applyUser)){ + if (StringUtils.isNotBlank(applyUser)) { processInstanceQuery.variableValueEquals(WorkFlowConstant.PROCESS_APPLY_USER, applyUser); } - if (startDate != null){ + if (startDate != null) { processInstanceQuery.startedAfter(startDate); } - if (endDate != null){ + if (endDate != null) { processInstanceQuery.startedBefore(endDate); } long total = processInstanceQuery.count(); @@ -258,26 +267,26 @@ public class WorkFlowServiceImpl implements WorkFlowService { public IPage listSendProcess(Query query, WorkFlowQO workFlowQO) { HistoricProcessInstanceQuery historyQuery = historyService.createHistoricProcessInstanceQuery() // 传入当前用户 - .startedBy("admin") + .startedBy(WorkFlowUtil.getCurrentUserId()) .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(processDefName)) { + historyQuery.processDefinitionName("%" + processDefName + "%"); } - if (StringUtils.isNotBlank(processDefKey)){ + if (StringUtils.isNotBlank(processDefKey)) { historyQuery.processDefinitionKey(processDefKey); } - if (StringUtils.isNotBlank(category)){ + if (StringUtils.isNotBlank(category)) { historyQuery.processDefinitionCategory(category); } - if (startDate != null){ + if (startDate != null) { historyQuery.startedAfter(startDate); } - if (endDate != null){ + if (endDate != null) { historyQuery.startedBefore(endDate); } long total = historyQuery.count(); @@ -290,52 +299,317 @@ public class WorkFlowServiceImpl implements WorkFlowService { return page; } + @Transactional(rollbackFor = Exception.class) @Override - public R completeTask(CompleteTaskBO completeTaskBO) { - Boolean pass = completeTaskBO.getPass(); - String taskId = completeTaskBO.getTaskId(); + public R completeTask(OperationTaskBO operationTaskBO) { + Boolean pass = operationTaskBO.getPass(); + String taskId = operationTaskBO.getTaskId(); Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); - if (task == null){ - return R.fail("当前任务不存在"+taskId); + if (task == null) { + return R.fail("当前任务不存在" + taskId); } - if (pass == null || pass){ + if (pass == null || pass) { // 默认通过 - passTask(completeTaskBO, task); - }else { + passTask(operationTaskBO, task); + } else { // 拒绝/驳回 - rejectTask(task, completeTaskBO); + rejectTask(task, operationTaskBO); } return R.data("操作成功"); } + @Override + public void urgeTask(OperationTaskBO operationTaskBO) { + String taskId = operationTaskBO.getTaskId(); + if (StringUtils.isNotBlank(taskId)) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null && StringUtils.isNotBlank(task.getAssignee())) { + // todo 发送通知消息 + log.info(">>>>>>>>>>>> 发送通知消息: {}", task.getAssignee()); + + } + } + + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void transferTask(OperationTaskBO operationTaskBO) { + String receiveUserId = operationTaskBO.getReceiveUserId(); + if (StringUtils.isBlank(receiveUserId)) { + return; + } + String taskId = operationTaskBO.getTaskId(); + if (StringUtils.isNotBlank(taskId)) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + String comment = operationTaskBO.getComment(); + if (StringUtils.isNotBlank(comment)) { + String assignee = task.getAssignee(); + String message = WorkFlowConstant.TRANSFER_TASK_DESCRIBE + ": " + assignee + " → " + receiveUserId + " " + WorkFlowUtil.getCurrentUserName() + " 操作"; + // 添加转办评论 + taskService.addComment(taskId, task.getProcessInstanceId(), WorkFlowConstant.TRANSFER_TASK, message); + } + // 设置任务归属 + taskService.setOwner(taskId, WorkFlowUtil.getCurrentUserId()); + // 指定任务审批人 + taskService.setAssignee(taskId, receiveUserId); + } + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void delegateTask(OperationTaskBO operationTaskBO) { + String receiveUserId = operationTaskBO.getReceiveUserId(); + String taskId = operationTaskBO.getTaskId(); + if (StringUtils.isNoneBlank(receiveUserId, taskId)) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + if (StringUtils.isNotBlank(operationTaskBO.getComment())) { + String assignee = task.getAssignee(); + String message = WorkFlowConstant.DELEGATE_TASK_DESCRIBE + ": " + assignee + " → " + receiveUserId + " " + WorkFlowUtil.getCurrentUserName() + " 操作"; + // 添加转办评论 + taskService.addComment(taskId, task.getProcessInstanceId(), WorkFlowConstant.DELEGATE_TASK, message); + } + // 设置任务 owner + taskService.setOwner(taskId, WorkFlowUtil.getCurrentUserId()); + // 委托任务 + taskService.delegateTask(taskId, receiveUserId); + } + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void terminationTask(OperationTaskBO operationTaskBO) { + String taskId = operationTaskBO.getTaskId(); + if (StringUtils.isNotBlank(taskId)) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + String processDefinitionId = task.getProcessDefinitionId(); + String processInstanceId = task.getProcessInstanceId(); + if (StringUtils.isNotBlank(operationTaskBO.getComment())) { + String message = WorkFlowConstant.TERMINATION_TASK_DESCRIBE + ": " + WorkFlowUtil.getCurrentUserName() + " 操作"; + // 添加终止评论 + taskService.addComment(taskId, task.getProcessInstanceId(), WorkFlowConstant.TERMINATION_TASK, message); + } + // 查找结束节点 + List endElementList = getEndFlowElement(processDefinitionId); + if (endElementList.size() > 0) { + // 跳转到结束节点 + goToTargetActivity(processInstanceId, endElementList.get(0).getId()); + } + } + } + } + + @Override + public void addMultiInstance(OperationTaskBO operationTaskBO) { + String taskId = operationTaskBO.getTaskId(); + List receiveUserIdList = operationTaskBO.getReceiveUserIdList(); + if (receiveUserIdList == null || receiveUserIdList.size() < 1) { + return; + } + if (StringUtils.isNotBlank(taskId)) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + for (String receiveUserId : receiveUserIdList) { + if (StringUtils.isBlank(operationTaskBO.getComment())) { + String message = WorkFlowConstant.ADD_MULTI_INSTANCE_DESCRIBE + ": " + WorkFlowUtil.getCurrentUserName() + " 操作"; + // 添加评论 + taskService.addComment(taskId, task.getProcessInstanceId(), WorkFlowConstant.ADD_MULTI_INSTANCE, message); + } + String taskDefinitionKey = task.getTaskDefinitionKey(); + String processInstanceId = task.getProcessInstanceId(); + // 加签 + runtimeService.addMultiInstanceExecution(taskDefinitionKey, processInstanceId, Collections.singletonMap("assignee", receiveUserId)); + } + } + } + } + + @Override + public void deleteMultiInstance(OperationTaskBO operationTaskBO) { + String taskId = operationTaskBO.getTaskId(); + if (StringUtils.isNotBlank(taskId)) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + String message = WorkFlowConstant.DELETE_MULTI_INSTANCE_DESCRIBE + ": " + WorkFlowUtil.getCurrentUserName() + " 操作"; + // 添加评论 + taskService.addComment(taskId, task.getProcessInstanceId(), WorkFlowConstant.DELETE_MULTI_INSTANCE, message); + // 减签 + runtimeService.deleteMultiInstanceExecution(task.getExecutionId(), false); + } + } + } + + @Override + public void rollbackTask(OperationTaskBO operationTaskBO) { + String taskId = operationTaskBO.getTaskId(); + String targetNodeId = operationTaskBO.getTargetNodeId(); + if (StringUtils.isNoneBlank(taskId, targetNodeId)) { + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + String assignee = task.getAssignee(); + if (StringUtils.isBlank(assignee)){ + this.claimTask(taskId); + } + String message = WorkFlowConstant.ROLL_BACK_TASK_DESCRIBE + ": " + WorkFlowUtil.getCurrentUserName() + " 操作"; + // 添加评论 + taskService.addComment(taskId, task.getProcessInstanceId(), WorkFlowConstant.ROLL_BACK_TASK, message); + // 跳转 + goToTargetActivity(task.getProcessInstanceId(), targetNodeId); + } + } + } + + @Override + public void claimTask(String taskId) { + if (StringUtils.isNotBlank(taskId)){ + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task != null) { + // 签收任务 + taskService.claim(taskId, WorkFlowUtil.getCurrentUserId()); + } + } + } + + @Override + public List getBackNodeList(OperationTaskBO operationTaskBO) { + String taskId = operationTaskBO.getTaskId(); + List result = new ArrayList<>(16); + if (StringUtils.isBlank(taskId)){ + return result; + } + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task == null){ + return result; + } + // 任务定义key 等于 + String taskDefinitionKey = task.getTaskDefinitionKey(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); + Process mainProcess = bpmnModel.getMainProcess(); + // 当前节点 + FlowNode currentFlowElement = (FlowNode) mainProcess.getFlowElement(taskDefinitionKey, true); + // 查询历史节点实例 + List activityInstanceList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(task.getProcessInstanceId()) + .finished() + .orderByHistoricActivityInstanceEndTime().asc().list(); + List activityIdList = activityInstanceList.stream() + .filter(activityInstance -> + BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType()) || BpmnXMLConstants.ELEMENT_EVENT_START.equals(activityInstance.getActivityType())) + .map(HistoricActivityInstance::getActivityId) + .filter(activityId -> !taskDefinitionKey.equals(activityId)) + .distinct() + .collect(Collectors.toList()); + for (String activityId : activityIdList) { + // 回退到主流程的节点 + FlowNode toBackFlowElement = (FlowNode) mainProcess.getFlowElement(activityId, true); + // 判断 【工具类判断是否可以从源节点 到 目标节点】 + Set set = new HashSet<>(); + if (toBackFlowElement != null && ExecutionGraphUtil.isReachable(mainProcess,toBackFlowElement,currentFlowElement, set)) { + WorkFlowNodeDTO workFlowNodeDTO = new WorkFlowNodeDTO(); + workFlowNodeDTO.setNodeId(activityId); + workFlowNodeDTO.setNodeName(toBackFlowElement.getName()); + result.add(workFlowNodeDTO); + } + } + return result; + } + + @Override + public WorkFlowNodeDTO getPreBackNode(OperationTaskBO operationTaskBO) { + String taskId = operationTaskBO.getTaskId(); + WorkFlowNodeDTO result = new WorkFlowNodeDTO(); + if (StringUtils.isBlank(taskId)){ + return result; + } + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task == null){ + return result; + } + // 任务定义key 等于 + String taskDefinitionKey = task.getTaskDefinitionKey(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); + Process mainProcess = bpmnModel.getMainProcess(); + // 当前节点 + FlowNode currentFlowElement = (FlowNode) mainProcess.getFlowElement(taskDefinitionKey, true); + // 查询历史节点实例,按照时间降序排列 + List activityInstanceList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(task.getProcessInstanceId()) + .finished() + .orderByHistoricActivityInstanceEndTime() + .desc().list(); + for (HistoricActivityInstance activityInstance : activityInstanceList) { + // 只过滤【用户任务】【开始】节点 + if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType()) || BpmnXMLConstants.ELEMENT_EVENT_START.equals(activityInstance.getActivityType())) { + String activityId = activityInstance.getActivityId(); + if (!Objects.equals(taskDefinitionKey, activityId)) { + FlowNode backFlowElement = (FlowNode) mainProcess.getFlowElement(activityId, true); + Set set = new HashSet<>(); + if (backFlowElement != null && ExecutionGraphUtil.isReachable(mainProcess, backFlowElement, currentFlowElement, set)) { + result.setNodeId(activityId); + result.setNodeName(backFlowElement.getName()); + return result; + } + } + } + } + return result; + } + + /** + * 查找主流程中的结束节点 + * @param processDefinitionId 流程定义id + * @return + */ + private List getEndFlowElement(String processDefinitionId) { + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + Process mainProcess = bpmnModel.getMainProcess(); + Collection flowElements = mainProcess.getFlowElements(); + List endElementList = new ArrayList<>(10); + if (flowElements != null && flowElements.size() > 0) { + for (FlowElement element : flowElements) { + if (element instanceof EndEvent) { + endElementList.add((EndEvent) element); + } + } + } + return endElementList; + } + /** - * 驳回/拒绝 操作 - * @param task 当前任务 - * @param completeTaskBO 完成任务参数 + * 驳回/拒绝 操作 + * + * @param task 当前任务 + * @param operationTaskBO 完成任务参数 */ - private void rejectTask(Task task,CompleteTaskBO completeTaskBO) { + private void rejectTask(Task task, OperationTaskBO operationTaskBO) { 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)){ + if (StringUtils.isNotBlank(processExtensionAttribute) && Objects.equals("true", processExtensionAttribute)) { String processInstanceId = task.getProcessInstanceId(); - if (StringUtils.isNotBlank(completeTaskBO.getComment())){ + if (StringUtils.isNotBlank(operationTaskBO.getComment())) { // 添加驳回评论 - taskService.addComment(task.getId(),processInstanceId, WorkFlowConstant.REFUSE_TASK,completeTaskBO.getComment()); + taskService.addComment(task.getId(), processInstanceId, WorkFlowConstant.REFUSE_TASK, operationTaskBO.getComment()); } // 回退到指定节点 goToTargetActivity(processInstanceId, processExtensionAttribute); - }else { + } else { // todo 若没有默认回退节点,则回退到上一步 } } /** - * 流转到指定的节点 + * 流转到指定的节点 + * * @param processInstanceId 流程实例id - * @param targetNodeId 目标节点id + * @param targetNodeId 目标节点id */ private void goToTargetActivity(String processInstanceId, String targetNodeId) { List list = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list(); @@ -346,19 +620,20 @@ public class WorkFlowServiceImpl implements WorkFlowService { } /** - * 完成通过任务 - * @param completeTaskBO 完成任务参数 - * @param task 当前任务 + * 完成通过任务 + * + * @param operationTaskBO 完成任务参数 + * @param task 当前任务 */ - private void passTask(CompleteTaskBO completeTaskBO, Task task) { + private void passTask(OperationTaskBO operationTaskBO, Task task) { String processInstanceId = task.getProcessInstanceId(); String taskId = task.getId(); - if (StringUtils.isNotBlank(completeTaskBO.getComment())){ + if (StringUtils.isNotBlank(operationTaskBO.getComment())) { // 添加评论 - taskService.addComment(taskId, processInstanceId, completeTaskBO.getComment()); + taskService.addComment(taskId, processInstanceId, operationTaskBO.getComment()); } - Map variables = completeTaskBO.getVariables(); - if (variables == null){ + Map variables = operationTaskBO.getVariables(); + if (variables == null) { variables = new HashMap<>(2); } // 完成任务 diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowNodeVO.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowNodeVO.java new file mode 100644 index 0000000..50b198f --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/vo/WorkFlowNodeVO.java @@ -0,0 +1,24 @@ +package cn.mesmile.workflow.process.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author zb + * @Description + * 可回退节点的下拉列表 + */ +@Data +public class WorkFlowNodeVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("节点id") + private String nodeId; + + @ApiModelProperty("节点名称") + private String nodeName; + +} diff --git a/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/WorkFlowNodeWrapper.java b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/WorkFlowNodeWrapper.java new file mode 100644 index 0000000..bf32b7e --- /dev/null +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/process/wrapper/WorkFlowNodeWrapper.java @@ -0,0 +1,26 @@ +package cn.mesmile.workflow.process.wrapper; + +import cn.mesmile.workflow.process.dto.WorkFlowNodeDTO; +import cn.mesmile.workflow.process.vo.WorkFlowNodeVO; +import cn.mesmile.workflow.support.BaseEntityWrapper; +import org.springframework.beans.BeanUtils; + +/** + * @author zb + * @Description + */ +public class WorkFlowNodeWrapper extends BaseEntityWrapper { + + public static WorkFlowNodeWrapper build() { + return new WorkFlowNodeWrapper(); + } + + @Override + public WorkFlowNodeVO entityVO(WorkFlowNodeDTO entity) { + WorkFlowNodeVO workFlowNodeVO = new WorkFlowNodeVO(); + if (entity != null) { + BeanUtils.copyProperties(entity, workFlowNodeVO); + } + return workFlowNodeVO; + } +} 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 index 890c0e7..02e339a 100644 --- a/xdclass-workflow/src/main/java/cn/mesmile/workflow/util/WorkFlowUtil.java +++ b/xdclass-workflow/src/main/java/cn/mesmile/workflow/util/WorkFlowUtil.java @@ -16,9 +16,25 @@ public class WorkFlowUtil { private WorkFlowUtil(){} /** - * xml转bpmnModel对象 + * TODO 实现自己的逻辑,获取当前用户 + * @return 当前操作用户的id + */ + public static String getCurrentUserId(){ + return "admin"; + } + + /** + * TODO 实现自己的逻辑,获取当前用户 + * @return 当前操作用户的名称 + */ + public static String getCurrentUserName(){ + return "管理员"; + } + + /** + * 字符串xml转bpmnModel对象 * @param xml xml - * @return bpmnModel对象 + * @return BpmnModel对象 */ public static BpmnModel getBpmnModel(String xml) { BpmnXMLConverter converter = new BpmnXMLConverter(); @@ -27,8 +43,8 @@ public class WorkFlowUtil { /** - * 获取根节点扩展属性 - * @param model bpmnModel对象 + * 获取根节点扩展属性value + * @param model BpmnModel对象 * @param key 扩展元素key */ public static String getProcessExtensionAttribute(BpmnModel model, String key) { -- Gitee