diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfInstanceController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfInstanceController.java index 0cb54e8c..3194ebcd 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfInstanceController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfInstanceController.java @@ -11,8 +11,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; -import java.util.Map; - /** * 工作流流程实例管理 * @@ -26,29 +24,20 @@ import java.util.Map; @RequestMapping("/workflow/instance") public class WfInstanceController { - private final IWfInstanceService flowInstanceService; - - @ApiOperation(value = "根据流程定义id启动流程实例") - @PostMapping("/startBy/{procDefId}") - public R startById(@ApiParam(value = "流程定义id") @PathVariable(value = "procDefId") String procDefId, - @ApiParam(value = "变量集合,json对象") @RequestBody Map variables) { - flowInstanceService.startProcessInstanceById(procDefId, variables); - return R.ok("流程启动成功"); - } - + private final IWfInstanceService instanceService; @ApiOperation(value = "激活或挂起流程实例") @PostMapping(value = "/updateState") public R updateState(@ApiParam(value = "1:激活,2:挂起", required = true) @RequestParam Integer state, @ApiParam(value = "流程实例ID", required = true) @RequestParam String instanceId) { - flowInstanceService.updateState(state, instanceId); + instanceService.updateState(state, instanceId); return R.ok(); } @ApiOperation("结束流程实例") @PostMapping(value = "/stopProcessInstance") public R stopProcessInstance(@RequestBody WfTaskBo bo) { - flowInstanceService.stopProcessInstance(bo); + instanceService.stopProcessInstance(bo); return R.ok(); } @@ -56,7 +45,13 @@ public class WfInstanceController { @DeleteMapping(value = "/delete") public R delete(@ApiParam(value = "流程实例ID", required = true) @RequestParam String instanceId, @ApiParam(value = "删除原因") @RequestParam(required = false) String deleteReason) { - flowInstanceService.delete(instanceId, deleteReason); + instanceService.delete(instanceId, deleteReason); return R.ok(); } + + @ApiOperation(value = "查询流程实例详情信息") + @GetMapping("/detail") + public R detail(String procInsId, String deployId) { + return R.ok(instanceService.queryDetailProcess(procInsId, deployId)); + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java index 51621875..2e212486 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfProcessController.java @@ -6,6 +6,7 @@ import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.workflow.domain.vo.WfDefinitionVo; +import com.ruoyi.workflow.domain.vo.WfTaskVo; import com.ruoyi.workflow.service.IWfProcessService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -47,4 +48,10 @@ public class WfProcessController extends BaseController { return R.ok("流程启动成功"); } + + @ApiOperation(value = "我拥有的流程", response = WfTaskVo.class) + @GetMapping(value = "/own") + public TableDataInfo ownProcess(PageQuery pageQuery) { + return processService.queryPageOwnProcessList(pageQuery); + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfTaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfTaskController.java index 256a3103..e1eff0f7 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfTaskController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/workflow/WfTaskController.java @@ -36,6 +36,7 @@ public class WfTaskController { private final IWfTaskService flowTaskService; + @Deprecated @ApiOperation(value = "我发起的流程", response = WfTaskVo.class) @GetMapping(value = "/myProcess") public TableDataInfo myProcess(PageQuery pageQuery) { @@ -62,6 +63,7 @@ public class WfTaskController { return flowTaskService.todoList(pageQuery); } + @Deprecated @ApiOperation(value = "获取已办任务", response = WfTaskVo.class) @GetMapping(value = "/finishedList") public TableDataInfo finishedList(PageQuery pageQuery) { diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfInstanceService.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfInstanceService.java index 195fe0b8..e4d154ad 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfInstanceService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfInstanceService.java @@ -46,12 +46,11 @@ public interface IWfInstanceService { */ HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId); + /** - * 根据流程定义ID启动流程实例 - * - * @param procDefId 流程定义Id - * @param variables 流程变量 - * @return + * 查询流程详情信息 + * @param procInsId 流程实例ID + * @param deployId 流程部署ID */ - void startProcessInstanceById(String procDefId, Map variables); + Map queryDetailProcess(String procInsId, String deployId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java index 4d1b3274..095b5d5c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfProcessService.java @@ -3,6 +3,7 @@ package com.ruoyi.workflow.service; import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.workflow.domain.vo.WfDefinitionVo; +import com.ruoyi.workflow.domain.vo.WfTaskVo; import java.util.Map; @@ -32,4 +33,11 @@ public interface IWfProcessService { * @param variables 扩展参数 */ void startProcessByDefKey(String procDefKey, Map variables); + + /** + * 查询我的流程列表 + * @param pageQuery 分页参数 + */ + TableDataInfo queryPageOwnProcessList(PageQuery pageQuery); + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java index 0d17518f..389e398d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java @@ -91,6 +91,7 @@ public interface IWfTaskService { * * @return */ + @Deprecated TableDataInfo myProcess(PageQuery pageQuery); /** @@ -129,6 +130,7 @@ public interface IWfTaskService { * @param procInsId 流程实例Id * @return */ + @Deprecated Map flowRecord(String procInsId, String deployId); /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfInstanceServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfInstanceServiceImpl.java index ab31f52c..9c7dcbae 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfInstanceServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfInstanceServiceImpl.java @@ -1,22 +1,35 @@ package com.ruoyi.workflow.service.impl; +import cn.hutool.core.date.BetweenFormatter; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.core.domain.entity.SysRole; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.exception.ServiceException; -import com.ruoyi.common.helper.LoginHelper; -import com.ruoyi.flowable.common.constant.ProcessConstants; +import com.ruoyi.common.utils.JsonUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.flowable.factory.FlowServiceFactory; +import com.ruoyi.system.service.ISysRoleService; +import com.ruoyi.system.service.ISysUserService; import com.ruoyi.workflow.domain.bo.WfTaskBo; +import com.ruoyi.workflow.domain.dto.WfCommentDto; +import com.ruoyi.workflow.domain.vo.WfFormVo; +import com.ruoyi.workflow.domain.vo.WfTaskVo; +import com.ruoyi.workflow.service.IWfDeployFormService; import com.ruoyi.workflow.service.IWfInstanceService; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.api.FlowableObjectNotFoundException; +import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.task.Comment; +import org.flowable.identitylink.api.history.HistoricIdentityLink; import org.flowable.task.api.Task; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; /** * 工作流流程实例管理 @@ -24,10 +37,14 @@ import java.util.Objects; * @author KonBAI * @createTime 2022/3/10 00:12 */ +@RequiredArgsConstructor @Service @Slf4j public class WfInstanceServiceImpl extends FlowServiceFactory implements IWfInstanceService { + private final IWfDeployFormService deployFormService; + private final ISysUserService userService; + private final ISysRoleService roleService; @Override public List queryListByInstanceId(String instanceId) { @@ -102,25 +119,85 @@ public class WfInstanceServiceImpl extends FlowServiceFactory implements IWfInst return historicProcessInstance; } + /** - * 根据流程定义ID启动流程实例 + * 流程历史流转记录 * - * @param procDefId 流程定义Id - * @param variables 流程变量 + * @param procInsId 流程实例Id * @return */ @Override - public void startProcessInstanceById(String procDefId, Map variables) { - try { - // 设置流程发起人Id到流程中 - String userIdStr = LoginHelper.getUserId().toString(); - // identityService.setAuthenticatedUserId(userId.toString()); - variables.put(ProcessConstants.PROCESS_INITIATOR, userIdStr); - variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true); - runtimeService.startProcessInstanceById(procDefId, variables); - } catch (Exception e) { - e.printStackTrace(); - throw new ServiceException("流程启动错误"); + public Map queryDetailProcess(String procInsId, String deployId) { + Map map = new HashMap<>(); + if (StringUtils.isNotBlank(procInsId)) { + List list = historyService + .createHistoricActivityInstanceQuery() + .processInstanceId(procInsId) + .orderByHistoricActivityInstanceStartTime() + .desc().list(); + List hisFlowList = new ArrayList<>(); + for (HistoricActivityInstance histIns : list) { + if (StringUtils.isNotBlank(histIns.getTaskId())) { + WfTaskVo flowTask = new WfTaskVo(); + flowTask.setProcDefId(histIns.getProcessDefinitionId()); + flowTask.setTaskId(histIns.getTaskId()); + flowTask.setTaskName(histIns.getActivityName()); + flowTask.setCreateTime(histIns.getStartTime()); + flowTask.setFinishTime(histIns.getEndTime()); + if (StringUtils.isNotBlank(histIns.getAssignee())) { + SysUser user = userService.selectUserById(Long.parseLong(histIns.getAssignee())); + flowTask.setAssigneeId(user.getUserId()); + flowTask.setAssigneeName(user.getNickName()); + flowTask.setDeptName(user.getDept().getDeptName()); + } + // 展示审批人员 + List linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId()); + StringBuilder stringBuilder = new StringBuilder(); + for (HistoricIdentityLink identityLink : linksForTask) { + if ("candidate".equals(identityLink.getType())) { + if (StringUtils.isNotBlank(identityLink.getUserId())) { + SysUser user = userService.selectUserById(Long.parseLong(identityLink.getUserId())); + stringBuilder.append(user.getNickName()).append(","); + } + if (StringUtils.isNotBlank(identityLink.getGroupId())) { + SysRole role = roleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); + stringBuilder.append(role.getRoleName()).append(","); + } + } + } + if (StringUtils.isNotBlank(stringBuilder)) { + flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); + } + if (ObjectUtil.isNotNull(histIns.getDurationInMillis())) { + flowTask.setDuration(DateUtil.formatBetween(histIns.getDurationInMillis(), BetweenFormatter.Level.SECOND)); + } + // 获取意见评论内容 + List commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId()); + commentList.forEach(comment -> { + if (histIns.getTaskId().equals(comment.getTaskId())) { + flowTask.setComment(WfCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build()); + } + }); + hisFlowList.add(flowTask); + } + } + map.put("flowList", hisFlowList); +// // 查询当前任务是否完成 +// List taskList = taskService.createTaskQuery().processInstanceId(procInsId).list(); +// if (CollectionUtils.isNotEmpty(taskList)) { +// map.put("finished", true); +// } else { +// map.put("finished", false); +// } } + // 第一次申请获取初始化表单 + if (StringUtils.isNotBlank(deployId)) { + WfFormVo formVo = deployFormService.selectDeployFormByDeployId(deployId); + if (Objects.isNull(formVo)) { + throw new ServiceException("请先配置流程表单"); + } + map.put("formData", JsonUtils.parseObject(formVo.getContent(), Map.class)); + } + return map; } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java index fb9c70c9..19e6bef1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfProcessServiceImpl.java @@ -1,24 +1,28 @@ package com.ruoyi.workflow.service.impl; -import cn.hutool.core.util.StrUtil; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.helper.LoginHelper; +import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.flowable.common.constant.ProcessConstants; -import com.ruoyi.flowable.common.enums.FlowComment; import com.ruoyi.flowable.factory.FlowServiceFactory; import com.ruoyi.workflow.domain.vo.WfDefinitionVo; +import com.ruoyi.workflow.domain.vo.WfTaskVo; import com.ruoyi.workflow.service.IWfProcessService; import com.ruoyi.workflow.service.IWfTaskService; import lombok.RequiredArgsConstructor; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinitionQuery; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -133,6 +137,54 @@ public class WfProcessServiceImpl extends FlowServiceFactory implements IWfProce } } + @Override + public TableDataInfo queryPageOwnProcessList(PageQuery pageQuery) { + Page page = new Page<>(); + Long userId = LoginHelper.getUserId(); + HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery() + .startedBy(userId.toString()) + .orderByProcessInstanceStartTime() + .desc(); + int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1); + List historicProcessInstances = historicProcessInstanceQuery + .listPage(offset, pageQuery.getPageSize()); + page.setTotal(historicProcessInstanceQuery.count()); + List taskVoList = new ArrayList<>(); + for (HistoricProcessInstance hisIns : historicProcessInstances) { + WfTaskVo taskVo = new WfTaskVo(); + taskVo.setCreateTime(hisIns.getStartTime()); + taskVo.setFinishTime(hisIns.getEndTime()); + taskVo.setProcInsId(hisIns.getId()); + + // 计算耗时 + if (Objects.nonNull(hisIns.getEndTime())) { + taskVo.setDuration(DateUtils.getDatePoor(hisIns.getEndTime(), hisIns.getStartTime())); + } else { + taskVo.setDuration(DateUtils.getDatePoor(DateUtils.getNowDate(), hisIns.getStartTime())); + } + // 流程部署实例信息 + Deployment deployment = repositoryService.createDeploymentQuery() + .deploymentId(hisIns.getDeploymentId()).singleResult(); + taskVo.setDeployId(hisIns.getDeploymentId()); + taskVo.setProcDefId(hisIns.getProcessDefinitionId()); + taskVo.setProcDefName(hisIns.getProcessDefinitionName()); + taskVo.setProcDefVersion(hisIns.getProcessDefinitionVersion()); + taskVo.setCategory(deployment.getCategory()); + // 当前所处流程 + List taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list(); + if (CollUtil.isNotEmpty(taskList)) { + taskVo.setTaskId(taskList.get(0).getId()); + } else { + List historicTaskInstance = historyService.createHistoricTaskInstanceQuery() + .processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list(); + taskVo.setTaskId(historicTaskInstance.get(0).getId()); + } + taskVoList.add(taskVo); + } + page.setRecords(taskVoList); + return TableDataInfo.build(page); + } + /** * 扩展参数构建 * @param variables 扩展参数 diff --git a/ruoyi-ui/src/api/workflow/instance.js b/ruoyi-ui/src/api/workflow/instance.js new file mode 100644 index 00000000..8f417958 --- /dev/null +++ b/ruoyi-ui/src/api/workflow/instance.js @@ -0,0 +1,10 @@ +import request from '@/utils/request' + +// 查询流程实例详情信息 +export function getDetailInstance(query) { + return request({ + url: '/workflow/instance/detail', + method: 'get', + params: query + }) +} diff --git a/ruoyi-ui/src/api/workflow/process.js b/ruoyi-ui/src/api/workflow/process.js index 5c97c9d8..0a8cd08e 100644 --- a/ruoyi-ui/src/api/workflow/process.js +++ b/ruoyi-ui/src/api/workflow/process.js @@ -20,9 +20,9 @@ export function startProcess(processDefId, data) { } // 我的发起的流程 -export function myProcessList(query) { +export function listOwnProcess(query) { return request({ - url: '/workflow/task/myProcess', + url: '/workflow/process/own', method: 'get', params: query }) diff --git a/ruoyi-ui/src/views/workflow/work/detail.vue b/ruoyi-ui/src/views/workflow/work/detail.vue index 12fade27..dd592691 100644 --- a/ruoyi-ui/src/views/workflow/work/detail.vue +++ b/ruoyi-ui/src/views/workflow/work/detail.vue @@ -1,21 +1,37 @@