From 91c0c423c09e40005a3c3070e1b99361b6d7af93 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Fri, 12 Nov 2021 20:37:27 +0800 Subject: [PATCH] 修改 code review --- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java | 19 +++++++++---------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java | 4 ++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java | 28 ++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/oa/OAErrorCodeConstants.java | 26 -------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/impl/OALeaveServiceImpl.java | 26 +++++--------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/TaskService.java | 59 ----------------------------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/TaskServiceImpl.java | 289 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysUserMapper.java | 12 ++++++------ yudao-admin-server/src/main/resources/application.yaml | 1 + 11 files changed, 390 insertions(+), 411 deletions(-) create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/oa/OAErrorCodeConstants.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/TaskService.java create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/TaskServiceImpl.java diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java index a379332..45ef6c9 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/workflow/TaskController.java @@ -1,8 +1,7 @@ package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow; -import cn.hutool.core.io.IoUtil; import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; -import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.TaskService; +import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.BpmTaskService; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; @@ -25,40 +24,40 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; public class TaskController { @Resource - private TaskService taskService; + private BpmTaskService bpmTaskService; @GetMapping("/todo/page") @ApiOperation("获取待办任务分页") public CommonResult> getTodoTaskPage(@Valid TodoTaskPageReqVO pageVO) { - return success(taskService.getTodoTaskPage(pageVO)); + return success(bpmTaskService.getTodoTaskPage(pageVO)); } @GetMapping("/claim") @ApiOperation("签收任务") public CommonResult claimTask(@RequestParam("id") String taskId) { - taskService.claimTask(taskId); + bpmTaskService.claimTask(taskId); return success(true); } @PostMapping("/task-steps") public CommonResult getTaskSteps(@RequestBody TaskQueryReqVO taskQuery) { - return success(taskService.getTaskSteps(taskQuery)); + return success(bpmTaskService.getTaskSteps(taskQuery)); } @PostMapping("/formKey") public CommonResult getTaskFormKey(@RequestBody TaskQueryReqVO taskQuery) { - return success(taskService.getTaskFormKey(taskQuery)); + return success(bpmTaskService.getTaskFormKey(taskQuery)); } @PostMapping("/complete") public CommonResult complete(@RequestBody TaskReqVO taskReq) { - taskService.completeTask(taskReq); + bpmTaskService.completeTask(taskReq); return success(true); } @GetMapping("/process/history-steps") public CommonResult> getHistorySteps(@RequestParam("id") String processInstanceId) { - return success(taskService.getHistorySteps(processInstanceId)); + return success(bpmTaskService.getHistorySteps(processInstanceId)); } // TODO @Li: 项目里,暂时不使用 path 路径参数,监控等麻烦 @@ -68,7 +67,7 @@ public class TaskController { */ @GetMapping("/process/highlight-img/{id}") public void getHighlightImg(@PathVariable("id") String processInstanceId, HttpServletResponse response) throws IOException { - FileResp fileResp = taskService.getHighlightImg(processInstanceId); + FileResp fileResp = bpmTaskService.getHighlightImg(processInstanceId); ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte()); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java index 8d2bd63..bcbb137 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/convert/workflow/TaskConvert.java @@ -25,6 +25,10 @@ public interface TaskConvert { }) TodoTaskRespVO convert(Task task, ProcessDefinition definition); + @Mappings(value = { + @Mapping(source = "assignee", target = "status",qualifiedByName = "convertAssigneeToStatus") + }) + TodoTaskRespVO convert(Task task); @Named("convertAssigneeToStatus") default Integer convertAssigneeToStatus(String assignee) { diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java new file mode 100644 index 0000000..8891abd --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.enums; + +import cn.iocoder.yudao.framework.common.exception.ErrorCode; + +/** + * 工作流 错误码枚举类 + * + * 工作流系统,使用 1-003-000-000 段 + */ +public interface BpmErrorCodeConstants { + + // ========== 通用流程处理 模块 1-003-000-000 ========== + ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1003000001, "流程实例不存在"); + ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1003000002, "获取高亮流程图异常"); + + + // ========== OA 流程模块 1-003-001-000 ========== + ErrorCode LEAVE_NOT_EXISTS = new ErrorCode(1003001001, "请假申请不存在"); + ErrorCode PM_POST_NOT_EXISTS = new ErrorCode(1003001002, "项目经理岗位未设置"); + ErrorCode DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1003001003, "部门的项目经理不存在"); + ErrorCode BM_POST_NOT_EXISTS = new ErrorCode(1003001004, "部门经理岗位未设置"); + ErrorCode DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1003001005, "部门的部门经理不存在"); + ErrorCode HR_POST_NOT_EXISTS = new ErrorCode(1003001006, "HR岗位未设置"); + ErrorCode DAY_LEAVE_ERROR = new ErrorCode(1003001007, "请假天数必须>=1"); + + + +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/oa/OAErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/oa/OAErrorCodeConstants.java deleted file mode 100644 index 6790edd..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/oa/OAErrorCodeConstants.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.enums.oa; - -import cn.iocoder.yudao.framework.common.exception.ErrorCode; - -// TODO @jason:错误码整理下,和其它模块保持一致。包括前缀 -/** - * activiti 系统 错误码枚举类 - * - * 003 activiti - * 001 oa - * activiti 系统,使用 1-003-000-000 段 - */ -public interface OAErrorCodeConstants { - - ErrorCode LEAVE_NOT_EXISTS = new ErrorCode(1003001001, "请假申请不存在"); - ErrorCode PM_POST_NOT_EXISTS = new ErrorCode(1003001002, "项目经理岗位未设置"); - ErrorCode DEPART_PM_POST_NOT_EXISTS = new ErrorCode(1003001003, "部门的项目经理不存在"); - ErrorCode BM_POST_NOT_EXISTS = new ErrorCode(1003001004, "部门经理岗位未设置"); - ErrorCode DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1003001005, "部门的部门经理不存在"); - ErrorCode HR_POST_NOT_EXISTS = new ErrorCode(1003001006, "HR岗位未设置"); - ErrorCode DAY_LEAVE_ERROR = new ErrorCode(1003001007, "请假天数必须大于0"); - - ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1003001008, "流程实例不存在"); - ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1003001009, "获取高亮流程图异常"); - -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/impl/OALeaveServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/impl/OALeaveServiceImpl.java index 9ccc281..243b8f8 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/impl/OALeaveServiceImpl.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/oa/impl/OALeaveServiceImpl.java @@ -28,7 +28,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.util.*; -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.oa.OAErrorCodeConstants.*; +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** @@ -164,12 +164,7 @@ public class OALeaveServiceImpl implements OALeaveService { throw ServiceExceptionUtil.exception(PM_POST_NOT_EXISTS); } SysUserDO userDO = sysUserMapper.selectById(id); - Set postIds = new HashSet<>(8); - postIds.add( pmPostDO.getId()); - SysUserBaseVO baseVO = new SysUserBaseVO(); - baseVO.setDeptId(userDO.getDeptId()) - .setPostIds(postIds); - final List pmUsers = sysUserMapper.selectListByBaseVO(baseVO); + final List pmUsers = sysUserMapper.selectListByDepartIdAndPostId(userDO.getDeptId(), pmPostDO.getId()); if (CollUtil.isEmpty(pmUsers)) { throw ServiceExceptionUtil.exception(DEPART_PM_POST_NOT_EXISTS); } @@ -179,13 +174,8 @@ public class OALeaveServiceImpl implements OALeaveService { if (Objects.isNull(bmPostDO)) { throw ServiceExceptionUtil.exception(BM_POST_NOT_EXISTS); } - userDO = sysUserMapper.selectById(id); - postIds = new HashSet<>(8); - postIds.add( bmPostDO.getId()); - baseVO = new SysUserBaseVO(); - baseVO.setDeptId(userDO.getDeptId()) - .setPostIds(postIds); - final List bmUsers = sysUserMapper.selectListByBaseVO(baseVO); + + final List bmUsers = sysUserMapper.selectListByDepartIdAndPostId(userDO.getDeptId(), bmPostDO.getId()); if (CollUtil.isEmpty(bmUsers)) { throw ServiceExceptionUtil.exception(DEPART_BM_POST_NOT_EXISTS); } @@ -194,13 +184,7 @@ public class OALeaveServiceImpl implements OALeaveService { if (Objects.isNull(hrPostDO)) { throw ServiceExceptionUtil.exception(HR_POST_NOT_EXISTS); } - userDO = sysUserMapper.selectById(id); - postIds = new HashSet<>(8); - postIds.add( hrPostDO.getId()); - baseVO = new SysUserBaseVO(); - baseVO.setDeptId(userDO.getDeptId()) - .setPostIds(postIds); - final List hrUsers = sysUserMapper.selectListByBaseVO(baseVO); + final List hrUsers = sysUserMapper.selectListByDepartIdAndPostId(userDO.getDeptId(), hrPostDO.getId()); if (CollUtil.isEmpty(hrUsers)) { throw ServiceExceptionUtil.exception(DEPART_BM_POST_NOT_EXISTS); } diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java new file mode 100644 index 0000000..b13db06 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/BpmTaskService.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow; + +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 工作流用户任务服务接口 + */ +public interface BpmTaskService { + + + /** + * 获取当前用户的待办任务, 分页 + */ + PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO); + + + /** + * 签收任务 + * @param taskId 用户任务id + */ + void claimTask(String taskId); + + + /** + * 工作流,完成 userTask, 完成用户任务 一般传入参数 1。是否同意(variables). 2. 评论(comment) + * variables 变量名 和 评论 由前台传入 + * @param taskReq 任务参数 + */ + void completeTask(TaskReqVO taskReq); + + /** + * 根据任务id, 查询已经完成的用户任务,未完成的用户任务 + * @param taskQuery 查询参数 一般 taskId + */ + TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery); + + /** + * 根据流程实例id, 查询历史用户任务,包括已完成,未完成 + * @param processInstanceId 流程实例id + */ + List getHistorySteps(String processInstanceId); + + /** + * 获取用户任务的 formKey, 对应外置表单, 需要根据formKey 对应业务表单 + * @param taskQuery 查询参数 ,一般taskId + */ + TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery); + + + /** + * 返回高亮的流转进程 + * @param processInstanceId 实例Id + */ + FileResp getHighlightImg(String processInstanceId); +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/TaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/TaskService.java deleted file mode 100644 index 6d131d1..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/TaskService.java +++ /dev/null @@ -1,59 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow; - -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; -import cn.iocoder.yudao.framework.common.pojo.PageResult; - -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -// TODO @jason:前缀 -/** - * 用户任务服务接口 - */ -public interface TaskService { - - - /** - * 获取当前用户的待办任务, 分页 - */ - PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO); - - - /** - * 签收任务 - * @param taskId 用户任务id - */ - void claimTask(String taskId); - - // TODO @jason:可以把实现方法的注释,统一写到接口里 - /** - * 办理完成用户任务 - * @param taskReq 任务参数, 包含任务的参数,和 评论 - */ - void completeTask(TaskReqVO taskReq); - - /** - * 根据任务id, 查询已经完成的用户任务,未完成的用户任务 - * @param taskQuery 查询参数 一般 taskId - */ - TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery); - - /** - * 根据流程实例id, 查询历史用户任务,包括已完成,未完成 - * @param processInstanceId 流程实例id - */ - List getHistorySteps(String processInstanceId); - - /** - * 获取用户任务的 formKey, 对应外置表单, 需要根据formKey 对应业务表单 - * @param taskQuery 查询参数 ,一般taskId - */ - TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery); - - - /** - * 返回高亮的流转进程 - * @param processInstanceId 实例Id - */ - FileResp getHighlightImg(String processInstanceId); -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java new file mode 100644 index 0000000..973f929 --- /dev/null +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/BpmTaskServiceImpl.java @@ -0,0 +1,278 @@ +package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; +import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert; +import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.BpmTaskService; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import lombok.extern.slf4j.Slf4j; +import org.activiti.api.runtime.shared.query.Page; +import org.activiti.api.runtime.shared.query.Pageable; +import org.activiti.api.task.model.Task; +import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder; +import org.activiti.api.task.model.builders.TaskPayloadBuilder; +import org.activiti.api.task.runtime.TaskRuntime; +import org.activiti.bpmn.constants.BpmnXMLConstants; +import org.activiti.bpmn.model.BpmnModel; +import org.activiti.bpmn.model.FlowNode; +import org.activiti.bpmn.model.SequenceFlow; +import org.activiti.engine.HistoryService; +import org.activiti.engine.RepositoryService; +import org.activiti.engine.RuntimeService; +import org.activiti.engine.history.HistoricActivityInstance; +import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.task.Comment; +import org.activiti.image.ProcessDiagramGenerator; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.HIGHLIGHT_IMG_ERROR; +import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +@Slf4j +@Service +public class BpmTaskServiceImpl implements BpmTaskService { + + @Resource + private TaskRuntime taskRuntime; + + @Resource + private org.activiti.engine.TaskService activitiTaskService; + + @Resource + private HistoryService historyService; + + @Resource + private RepositoryService repositoryService; + + @Resource + private RuntimeService runtimeService; + + @Resource + private ProcessDiagramGenerator processDiagramGenerator; + + @Override + public PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO) { + // TODO @jason:封装一个方法,用于转换成 activiti 的分页对象 + final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize()); + Page pageTasks = taskRuntime.tasks(pageable); + int totalItems = pageTasks.getTotalItems(); + List tasks = pageTasks.getContent(); + final List respVOList = tasks.stream().map(task -> { + ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId()); + return TaskConvert.INSTANCE.convert(task, definition); + }).collect(Collectors.toList()); + return new PageResult<>(respVOList, (long)totalItems); + } + + + @Override + public void claimTask(String taskId) { + taskRuntime.claim(new ClaimTaskPayloadBuilder() + .withTaskId(taskId) + .withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername()) + .build()); + } + + + + @Override + @Transactional + public void completeTask(TaskReqVO taskReq) { + final Task task = taskRuntime.task(taskReq.getTaskId()); + + activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment()); + + taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId()) + .withVariables(taskReq.getVariables()) + .build()); + } + + + + @Override + public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) { + TaskHandleVO handleVO = new TaskHandleVO(); + final Task task = taskRuntime.task(taskQuery.getTaskId()); + List steps = getTaskSteps(task.getProcessInstanceId()); + handleVO.setHistoryTask(steps); + return handleVO; + } + + + private List getTaskSteps(String processInstanceId) { + // 获得已完成的活动 + List finished = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId) + .activityType("userTask") + .finished() + .orderByHistoricActivityInstanceStartTime().asc().list(); + // 获得对应的步骤 + List steps = new ArrayList<>(); + finished.forEach(instance -> { + TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); + stepVO.setStatus(1); // TODO @jason:1 这个 magic number 要枚举起来。 + // TODO @jason:可以考虑把 comments 读取后,在统一调用 convert 拼接。另外 Comment 是废弃的类,有没其它可以使用的哈? + List comments = activitiTaskService.getTaskComments(instance.getTaskId()); + if (!CollUtil.isEmpty(comments)) { + stepVO.setComment(Optional.ofNullable(comments.get(0)).map(Comment::getFullMessage).orElse("")); + } + steps.add(stepVO); + }); + + // 获得未完成的活动 + List unfinished = historyService + .createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId) + .activityType("userTask") + .unfinished().list(); + // 获得对应的步骤 + for (HistoricActivityInstance instance : unfinished) { + TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); + stepVO.setComment(""); + stepVO.setStatus(0); + steps.add(stepVO); + } + return steps; + } + + + @Override + public List getHistorySteps(String processInstanceId) { + return getTaskSteps(processInstanceId); + } + + @Override + public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) { + final Task task = taskRuntime.task(taskQuery.getTaskId()); + return TaskConvert.INSTANCE.convert(task); + } + + @Override + public FileResp getHighlightImg(String processInstanceId) { + // 查询历史 + //TODO 云扬四海 貌似流程结束后,点击审批进度会报错 + // TODO @Li:一些 historyService 的查询,貌似比较通用,是不是抽一些小方法出来 + HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + // 如果不存在实例。 说明数据异常 + if (hpi == null) { + throw exception(PROCESS_INSTANCE_NOT_EXISTS); + } + // 没有结束时间。说明流程在执行过程中 + // TODO @Li:一些 runtimeService 的查询,貌似比较通用,是不是抽一些小方法出来 + ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + + List highLightedActivities = new ArrayList<>(); + // 获取所有活动节点 + List finishedInstances = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId).finished().list(); + finishedInstances.stream().map(HistoricActivityInstance::getActivityId) + .forEach(highLightedActivities::add); + // 已完成的节点+当前节点 + highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId)); + + BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); + // 经过的流 + List highLightedFlowIds = getHighLightedFlows(bpmnModel, processInstanceId); + + //设置"宋体" + try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds, + "宋体", "宋体", "宋体")){ + FileResp fileResp = new FileResp(); + String picName = hpi.getProcessDefinitionName() + ".svg"; // TODO @Li:一次性的变量,可以直接 set 的时候,直接拼接 + fileResp.setFileName(picName); + fileResp.setFileByte(IoUtil.readBytes(inputStream)); + return fileResp; + } catch (IOException e) { + // TODO @Li:log.error("[getHighlightImg][流程({}) 生成图表失败]", processInstanceId, e) + log.error(ExceptionUtils.getStackTrace(e)); + throw exception(HIGHLIGHT_IMG_ERROR); + } + } + + // TODO @Li:这个方法的可读性还有一定的优化空间,可以思考下哈。 + /** + * 获取指定 processInstanceId 已经高亮的Flows + * 获取已经流转的线 参考: https://blog.csdn.net/qiuxinfa123/article/details/119579863 + * @param bpmnModel model + * @param processInstanceId 流程实例Id + * @return 获取已经流转的列表 + */ + private List getHighLightedFlows(BpmnModel bpmnModel, String processInstanceId) { + // 获取所有的线条 + List historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId) + .orderByHistoricActivityInstanceId().asc().list(); + // 高亮流程已发生流转的线id集合 + List highLightedFlowIds = new ArrayList<>(); + // 全部活动节点 + List historicActivityNodes = new ArrayList<>(); + // 已完成的历史活动节点 + List finishedActivityInstances = new ArrayList<>(); + + for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { + FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true); + historicActivityNodes.add(flowNode); + // 结束时间不为空,则是已完成节点 + if (historicActivityInstance.getEndTime() != null) { + finishedActivityInstances.add(historicActivityInstance); + } + } + // 提取活动id 是唯一的。塞入Map + Map historicActivityInstanceMap = CollectionUtils.convertMap(historicActivityInstances, HistoricActivityInstance::getActivityId); + // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的 + for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) { + // 获得当前活动对应的节点信息及outgoingFlows信息 + FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true); + List sequenceFlows = currentFlowNode.getOutgoingFlows(); + + // 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转: + // 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 + // 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转 + if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(currentActivityInstance.getActivityType()) + || BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE.equals(currentActivityInstance.getActivityType())) { + // 遍历历史活动节点,找到匹配流程目标节点的 + for (SequenceFlow sequenceFlow : sequenceFlows) { + FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true); + if (historicActivityNodes.contains(targetFlowNode)) { + highLightedFlowIds.add(targetFlowNode.getId()); + } + } + } else { + long earliestStamp = 0L; + String highLightedFlowId = null; + // 循环流出的流 + for (SequenceFlow sequenceFlow : sequenceFlows) { + HistoricActivityInstance historicActivityInstance = historicActivityInstanceMap.get(sequenceFlow.getTargetRef()); + if (historicActivityInstance == null) { + continue; + } + final long startTime = historicActivityInstance.getStartTime().getTime(); + // 遍历匹配的集合,取得开始时间最早的一个 + if (earliestStamp == 0 || earliestStamp >= startTime) { + highLightedFlowId = sequenceFlow.getId(); + earliestStamp = startTime; + } + } + highLightedFlowIds.add(highLightedFlowId); + } + + } + return highLightedFlowIds; + } +} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/TaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/TaskServiceImpl.java deleted file mode 100644 index ac10c45..0000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/workflow/impl/TaskServiceImpl.java +++ /dev/null @@ -1,289 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.impl; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.io.IoUtil; -import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*; -import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert; -import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.TaskService; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import lombok.extern.slf4j.Slf4j; -import org.activiti.api.runtime.shared.query.Page; -import org.activiti.api.runtime.shared.query.Pageable; -import org.activiti.api.task.model.Task; -import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder; -import org.activiti.api.task.model.builders.TaskPayloadBuilder; -import org.activiti.api.task.runtime.TaskRuntime; -import org.activiti.bpmn.constants.BpmnXMLConstants; -import org.activiti.bpmn.model.BpmnModel; -import org.activiti.bpmn.model.FlowNode; -import org.activiti.bpmn.model.SequenceFlow; -import org.activiti.engine.HistoryService; -import org.activiti.engine.RepositoryService; -import org.activiti.engine.RuntimeService; -import org.activiti.engine.history.HistoricActivityInstance; -import org.activiti.engine.history.HistoricProcessInstance; -import org.activiti.engine.repository.ProcessDefinition; -import org.activiti.engine.runtime.ProcessInstance; -import org.activiti.engine.task.Comment; -import org.activiti.image.ProcessDiagramGenerator; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Resource; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.oa.OAErrorCodeConstants.HIGHLIGHT_IMG_ERROR; -import static cn.iocoder.yudao.adminserver.modules.bpm.enums.oa.OAErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS; -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; - -@Slf4j -@Service -public class TaskServiceImpl implements TaskService { - - @Resource - private TaskRuntime taskRuntime; - - @Resource - private org.activiti.engine.TaskService activitiTaskService; - - @Resource - private HistoryService historyService; - - @Resource - private RepositoryService repositoryService; - - @Resource - private RuntimeService runtimeService; - - @Resource - private ProcessDiagramGenerator processDiagramGenerator; - - @Override - public PageResult getTodoTaskPage(TodoTaskPageReqVO pageReqVO) { - // TODO @jason:封装一个方法,用于转换成 activiti 的分页对象 - final Pageable pageable = Pageable.of((pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(), pageReqVO.getPageSize()); - Page pageTasks = taskRuntime.tasks(pageable); - int totalItems = pageTasks.getTotalItems(); - List tasks = pageTasks.getContent(); - final List respVOList = tasks.stream().map(task -> { - ProcessDefinition definition = repositoryService.getProcessDefinition(task.getProcessDefinitionId()); - definition.getId(); - return TaskConvert.INSTANCE.convert(task, definition); - }).collect(Collectors.toList()); - return new PageResult<>(respVOList, (long)totalItems); - } - - - @Override - public void claimTask(String taskId) { - taskRuntime.claim(new ClaimTaskPayloadBuilder() - .withTaskId(taskId) - .withAssignee(SecurityFrameworkUtils.getLoginUser().getUsername()) - .build()); - } - - - /** - * 工作流,完成 userTask, 完成用户任务 一般传入参数 1。是否同意(variables). 2. 评论(comment) - * variables 变量名 和 评论 由前台传入 - * @param taskReq 任务参数 - */ - @Override - @Transactional - public void completeTask(TaskReqVO taskReq) { - final Task task = taskRuntime.task(taskReq.getTaskId()); - - activitiTaskService.addComment(taskReq.getTaskId(), task.getProcessInstanceId(), taskReq.getComment()); - - taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskReq.getTaskId()) - .withVariables(taskReq.getVariables()) - .build()); - } - - - - @Override - public TaskHandleVO getTaskSteps(TaskQueryReqVO taskQuery) { - TaskHandleVO handleVO = new TaskHandleVO(); - final Task task = taskRuntime.task(taskQuery.getTaskId()); - List steps = getTaskSteps(task.getProcessInstanceId()); - handleVO.setHistoryTask(steps); - return handleVO; - } - - - private List getTaskSteps(String processInstanceId) { - // 获得已完成的活动 - List finished = historyService.createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId) - .activityType("userTask") - .finished() - .orderByHistoricActivityInstanceStartTime().asc().list(); - // 获得对应的步骤 - List steps = new ArrayList<>(); - finished.forEach(instance -> { - TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); - stepVO.setStatus(1); // TODO @jason:1 这个 magic number 要枚举起来。 - // TODO @jason:可以考虑把 comments 读取后,在统一调用 convert 拼接。另外 Comment 是废弃的类,有没其它可以使用的哈? - List comments = activitiTaskService.getTaskComments(instance.getTaskId()); - if (!CollUtil.isEmpty(comments)) { - stepVO.setComment(Optional.ofNullable(comments.get(0)).map(Comment::getFullMessage).orElse("")); - } - steps.add(stepVO); - }); - - // 获得未完成的活动 - List unfinished = historyService - .createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId) - .activityType("userTask") - .unfinished().list(); - // 获得对应的步骤 - for (HistoricActivityInstance instance : unfinished) { - TaskStepVO stepVO = TaskConvert.INSTANCE.convert(instance); - stepVO.setComment(""); - stepVO.setStatus(0); - steps.add(stepVO); - } - return steps; - } - - - @Override - public List getHistorySteps(String processInstanceId) { - return getTaskSteps(processInstanceId); - } - - @Override - public TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery) { - final Task task = taskRuntime.task(taskQuery.getTaskId()); - // 转换结果 TODO @jason:放到 convert 类里 - TodoTaskRespVO respVO = new TodoTaskRespVO(); - respVO.setFormKey(task.getFormKey()); - respVO.setBusinessKey(task.getBusinessKey()); - respVO.setId(task.getId()); - respVO.setProcessInstanceId(task.getProcessInstanceId()); - return respVO; - } - - @Override - public FileResp getHighlightImg(String processInstanceId) { - // 查询历史 - //TODO 云扬四海 貌似流程结束后,点击审批进度会报错 - // TODO @Li:一些 historyService 的查询,貌似比较通用,是不是抽一些小方法出来 - HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); - // 如果不存在实例。 说明数据异常 - if (hpi == null) { - throw exception(PROCESS_INSTANCE_NOT_EXISTS); - } - // 没有结束时间。说明流程在执行过程中 - // TODO @Li:一些 runtimeService 的查询,貌似比较通用,是不是抽一些小方法出来 - ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); - - List highLightedActivities = new ArrayList<>(); - // 获取所有活动节点 - List finishedInstances = historyService.createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId).finished().list(); - finishedInstances.stream().map(HistoricActivityInstance::getActivityId) - .forEach(highLightedActivities::add); - // 已完成的节点+当前节点 - highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId)); - - BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); - // 经过的流 - List highLightedFlowIds = getHighLightedFlows(bpmnModel, processInstanceId); - - //设置"宋体" - try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds, - "宋体", "宋体", "宋体")){ - FileResp fileResp = new FileResp(); - String picName = hpi.getProcessDefinitionName() + ".svg"; // TODO @Li:一次性的变量,可以直接 set 的时候,直接拼接 - fileResp.setFileName(picName); - fileResp.setFileByte(IoUtil.readBytes(inputStream)); - return fileResp; - } catch (IOException e) { - // TODO @Li:log.error("[getHighlightImg][流程({}) 生成图表失败]", processInstanceId, e) - log.error(ExceptionUtils.getStackTrace(e)); - throw exception(HIGHLIGHT_IMG_ERROR); - } - } - - // TODO @Li:这个方法的可读性还有一定的优化空间,可以思考下哈。 - /** - * 获取指定 processInstanceId 已经高亮的Flows - * 获取已经流转的线 参考: https://blog.csdn.net/qiuxinfa123/article/details/119579863 - * @param bpmnModel model - * @param processInstanceId 流程实例Id - * @return 获取已经流转的列表 - */ - private List getHighLightedFlows(BpmnModel bpmnModel, String processInstanceId) { - // 获取所有的线条 - List historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId) - .orderByHistoricActivityInstanceId().asc().list(); - // 高亮流程已发生流转的线id集合 - List highLightedFlowIds = new ArrayList<>(); - // 全部活动节点 - List historicActivityNodes = new ArrayList<>(); - // 已完成的历史活动节点 - List finishedActivityInstances = new ArrayList<>(); - - for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { - FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true); - historicActivityNodes.add(flowNode); - // 结束时间不为空,则是已完成节点 - if (historicActivityInstance.getEndTime() != null) { - finishedActivityInstances.add(historicActivityInstance); - } - } - // 提取活动id 是唯一的。塞入Map - Map historicActivityInstanceMap = CollectionUtils.convertMap(historicActivityInstances, HistoricActivityInstance::getActivityId); - // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的 - for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) { - // 获得当前活动对应的节点信息及outgoingFlows信息 - FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true); - List sequenceFlows = currentFlowNode.getOutgoingFlows(); - - // 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转: - // 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 - // 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转 - if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(currentActivityInstance.getActivityType()) - || BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE.equals(currentActivityInstance.getActivityType())) { - // 遍历历史活动节点,找到匹配流程目标节点的 - for (SequenceFlow sequenceFlow : sequenceFlows) { - FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true); - if (historicActivityNodes.contains(targetFlowNode)) { - highLightedFlowIds.add(targetFlowNode.getId()); - } - } - } else { - long earliestStamp = 0L; - String highLightedFlowId = null; - // 循环流出的流 - for (SequenceFlow sequenceFlow : sequenceFlows) { - HistoricActivityInstance historicActivityInstance = historicActivityInstanceMap.get(sequenceFlow.getTargetRef()); - if (historicActivityInstance == null) { - continue; - } - final long startTime = historicActivityInstance.getStartTime().getTime(); - // 遍历匹配的集合,取得开始时间最早的一个 - if (earliestStamp == 0 || earliestStamp >= startTime) { - highLightedFlowId = sequenceFlow.getId(); - earliestStamp = startTime; - } - } - highLightedFlowIds.add(highLightedFlowId); - } - - } - return highLightedFlowIds; - } -} diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysUserMapper.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysUserMapper.java index 85f7b5f..ee5969a 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysUserMapper.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/user/SysUserMapper.java @@ -15,6 +15,7 @@ import org.apache.logging.log4j.util.Strings; import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.Set; @Mapper public interface SysUserMapper extends BaseMapperX { @@ -56,13 +57,12 @@ public interface SysUserMapper extends BaseMapperX { return selectList(new QueryWrapperX().like("username", username)); } - // TODO jason:变量平铺比较好 - default List selectListByBaseVO(SysUserBaseVO reqVO) { - return selectList(new QueryWrapperX().likeIfPresent("username", reqVO.getUsername()) - .likeIfPresent("nickname", reqVO.getNickname()) + + default List selectListByDepartIdAndPostId(Long departId, Long postId) { + return selectList(new QueryWrapperX() .eq("status", CommonStatusEnum.ENABLE.getStatus()) - .eq("dept_id", reqVO.getDeptId()) - .likeIfPresent("post_ids", Optional.ofNullable(reqVO.getPostIds()).map(t -> Strings.join(t, ',')).orElse(""))); + .eq("dept_id", departId) + .likeIfPresent("post_ids", Optional.ofNullable(postId).map(t -> String.valueOf(postId)).orElse(""))); } } diff --git a/yudao-admin-server/src/main/resources/application.yaml b/yudao-admin-server/src/main/resources/application.yaml index 8674452..39a2e9f 100644 --- a/yudao-admin-server/src/main/resources/application.yaml +++ b/yudao-admin-server/src/main/resources/application.yaml @@ -73,5 +73,6 @@ yudao: constants-class-list: - cn.iocoder.yudao.adminserver.modules.infra.enums.InfErrorCodeConstants - cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants + - cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants debug: false -- libgit2 0.21.4