diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java index 2be6ffa91..00fdd60e8 100644 --- a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java +++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/service/impl/ProcessInstanceServiceImpl.java @@ -53,7 +53,7 @@ import java.util.stream.Collectors; *

* 该类是流程实例管理的核心服务,负责处理流程实例的完整生命周期,主要功能包括: 1. 流程实例的启动、结束等生命周期管理 2. 待办任务、已办任务的查询 3. * 我发起的流程、抄送给我的流程查询 4. 流程节点的格式化显示 5. 流程详情查询 - * + *

* 该服务整合了Flowable引擎和业务数据,为前端提供统一的流程操作接口 *

* @@ -65,516 +65,448 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class ProcessInstanceServiceImpl implements IProcessInstanceService { - private final RemoteUserService userService; - - private final TaskService taskService; - - private final RuntimeService runtimeService; - - private final HistoryService historyService; - - private final IProcessInstanceRecordService processInstanceRecordService; - - private final IProcessCopyService processCopyService; - - private final IProcessService processService; - - private final IProcessNodeRecordService processNodeRecordService; - - private final ObjectMapper objectMapper; - - /** - * 启动流程 - *

- * 根据流程定义启动一个新的流程实例。该方法会: 1. 获取当前登录用户作为流程发起人 2. 设置流程发起人信息到流程变量中 3. 调用Flowable引擎启动流程 - *

- * @param processInstanceParamDto 流程启动参数,包含: - flowId: 流程定义ID - paramMap: 流程变量 - * @return R 启动结果,包含流程实例ID等信息 - */ - @Override - public R startProcessInstance(ProcessInstanceParamDto processInstanceParamDto) { - - // 获取当前登录用户 - PigxUser user = SecurityUtils.getUser(); - - // 设置流程发起人ID - processInstanceParamDto.setStartUserId(String.valueOf(user.getId())); - Map paramMap = processInstanceParamDto.getParamMap(); - - // 将发起人信息作为root变量存入流程,用于流程节点的权限判断 - Dict rootUser = Dict.create() - .set("id", user.getId()) - .set("name", user.getUsername()) - .set("type", NodeUserTypeEnum.USER.getKey()); - paramMap.put("root", CollUtil.newArrayList(rootUser)); - - // 调用引擎启动流程 - Authentication.setAuthenticatedUserId(processInstanceParamDto.getStartUserId()); - ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId( - processInstanceParamDto.getFlowId(), processInstanceParamDto.getParamMap(), - TenantContextHolder.getTenantId().toString()); - - String processInstanceId = processInstance.getProcessInstanceId(); - return R.ok(processInstanceId); - } - - /** - * 查询当前登录用户的待办任务 - *

- * 查询分配给当前用户的待办任务列表,并补充以下信息: 1. 流程实例的详细信息(流程名称、分组等) 2. 流程发起人信息(姓名、头像等) 3. 流程启动时间 - *

- * @param taskQueryParamDto 查询参数,支持分页和条件过滤 - * @return R 包含分页后的待办任务列表 - */ - @Override - public R queryMineTask(TaskQueryParamDto taskQueryParamDto) { - taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); - - String assign = taskQueryParamDto.getAssign(); - - List taskDtoList = new ArrayList<>(); - - int pageIndex = taskQueryParamDto.getCurrent() - 1; - int pageSize = taskQueryParamDto.getSize(); - - Page pageResultDto = new Page<>(); - TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(assign).orderByTaskCreateTime().desc(); - if (StrUtil.isNotBlank(taskQueryParamDto.getProcessName())) { - List processInstanceList = runtimeService.createProcessInstanceQuery() - .processDefinitionName(taskQueryParamDto.getProcessName()) - .processInstanceTenantId(TenantContextHolder.getTenantId().toString()) - .list(); - if (CollUtil.isNotEmpty(processInstanceList)) { - taskQuery.processInstanceIdIn( - processInstanceList.stream().map(ProcessInstance::getProcessInstanceId).toList()); - } - } - - if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) { - ZoneId zoneId = ZoneId.systemDefault(); - ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId); - ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId); - Date beforeDate = Date.from(zonedBeforeDateTime.toInstant()); - Date afterDate = Date.from(zonedAfterDateTime.toInstant()); - taskQuery.taskCreatedBefore(afterDate).taskCreatedAfter(beforeDate); - } - - taskQuery.listPage(pageIndex * pageSize, pageSize).forEach(task -> { - String taskId = task.getId(); - String processInstanceId = task.getProcessInstanceId(); - log.debug("(taskId) {} processInstanceId={} executrionId={}", task.getName(), processInstanceId, - task.getExecutionId()); - - String taskDefinitionKey = task.getTaskDefinitionKey(); - String processDefinitionId = task.getProcessDefinitionId(); - String flowId = NodeUtil.getFlowId(processDefinitionId); - - TaskDto taskDto = new TaskDto(); - taskDto.setFlowId(flowId); - taskDto.setTaskCreateTime(task.getCreateTime()); - taskDto.setNodeId(taskDefinitionKey); - taskDto.setProcessInstanceId(processInstanceId); - taskDto.setTaskId(taskId); - taskDto.setAssign(task.getAssignee()); - taskDto.setTaskName(task.getName()); - taskDtoList.add(taskDto); - }); - - long count = taskQuery.count(); - - log.debug("当前有 {} 个任务:", count); - - pageResultDto.setTotal(count); - pageResultDto.setRecords(taskDtoList); - - if (CollUtil.isEmpty(taskDtoList)) { - return R.ok(); - } - - Set processInstanceIdSet = taskDtoList.stream() - .map(TaskDto::getProcessInstanceId) - .collect(Collectors.toSet()); - - // 流程实例记录 - List processInstanceRecordList = processInstanceRecordService.lambdaQuery() - .in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet) - .list(); - - // 发起人 - List collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList(); - List startUserList = userService.getUserById(collect).getData(); - - List taskNewDtoList = new ArrayList<>(); - for (TaskDto record : taskDtoList) { - ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream() - .filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())) - .findAny() - .orElse(null); - - if (processInstanceRecord != null) { - record.setProcessName(processInstanceRecord.getName()); - SysUser startUser = startUserList.stream() - .filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()) - .findAny() - .orElse(null); - - record.setRootUserId(processInstanceRecord.getUserId()); - record.setGroupName(processInstanceRecord.getGroupName()); - record.setRootUserName(startUser.getUsername()); - record.setRootUserAvatarUrl(startUser.getAvatar()); - record.setStartTime(processInstanceRecord.getCreateTime()); - - taskNewDtoList.add(record); - } - } - - pageResultDto.setRecords(taskNewDtoList); - - return R.ok(pageResultDto); - } - - /** - * 查询已办任务 - *

- * 查询当前用户已经完成的任务列表,包括: 1. 用户已审批的任务 2. 补充流程实例信息、发起人信息等 - *

- * @param taskQueryParamDto 查询参数,支持分页和时间范围过滤 - * @return R 包含分页后的已办任务列表 - */ - @Override - public R queryMineEndTask(TaskQueryParamDto taskQueryParamDto) { - taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); - - HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService - .createHistoricActivityInstanceQuery(); - HistoricActivityInstanceQuery activityInstanceQuery = historicActivityInstanceQuery - .taskAssignee(taskQueryParamDto.getAssign()) - .finished() - .orderByHistoricActivityInstanceEndTime() - .desc(); - - if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) { - ZoneId zoneId = ZoneId.systemDefault(); - ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId); - ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId); - Date beforeDate = Date.from(zonedBeforeDateTime.toInstant()); - Date afterDate = Date.from(zonedAfterDateTime.toInstant()); - activityInstanceQuery.finishedBefore(afterDate).finishedAfter(beforeDate); - } - - List list = activityInstanceQuery - .listPage((taskQueryParamDto.getCurrent() - 1) * taskQueryParamDto.getSize(), taskQueryParamDto.getSize()); - - long count = activityInstanceQuery.count(); - List taskDtoList = new ArrayList<>(); - - for (HistoricActivityInstance historicActivityInstance : list) { - String activityId = historicActivityInstance.getActivityId(); - String activityName = historicActivityInstance.getActivityName(); - String executionId = historicActivityInstance.getExecutionId(); - String taskId = historicActivityInstance.getTaskId(); - Date startTime = historicActivityInstance.getStartTime(); - Date endTime = historicActivityInstance.getEndTime(); - Long durationInMillis = historicActivityInstance.getDurationInMillis(); - String processInstanceId = historicActivityInstance.getProcessInstanceId(); - - String processDefinitionId = historicActivityInstance.getProcessDefinitionId(); - // 流程id - String flowId = NodeUtil.getFlowId(processDefinitionId); - - TaskDto taskDto = new TaskDto(); - taskDto.setFlowId(flowId); - taskDto.setTaskCreateTime(startTime); - taskDto.setTaskEndTime(endTime); - taskDto.setNodeId(activityId); - taskDto.setExecutionId(executionId); - taskDto.setProcessInstanceId(processInstanceId); - taskDto.setDurationInMillis(durationInMillis); - taskDto.setTaskId(taskId); - taskDto.setAssign(historicActivityInstance.getAssignee()); - taskDto.setTaskName(activityName); - - taskDtoList.add(taskDto); - } - - Page pageResultDto = new Page<>(); - pageResultDto.setTotal(count); - pageResultDto.setRecords(taskDtoList); - - List records = pageResultDto.getRecords(); - if (CollUtil.isEmpty(records)) { - return R.ok(pageResultDto); - - } - - Set processInstanceIdSet = records.stream() - .map(TaskDto::getProcessInstanceId) - .collect(Collectors.toSet()); - - // 流程实例记录 - List processInstanceRecordList = processInstanceRecordService.lambdaQuery() - .in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet) - .list(); - - // 发起人 - List collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList(); - List startUserList = userService.getUserById(collect).getData(); - - List taskNewDtoList = new ArrayList<>(); - for (TaskDto record : records) { - - ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream() - .filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())) - .findAny() - .orElse(null); - - if (processInstanceRecord != null) { - - record.setProcessName(processInstanceRecord.getName()); - - SysUser startUser = startUserList.stream() - .filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()) - .findAny() - .orElse(null); - - record.setRootUserId(processInstanceRecord.getUserId()); - record.setGroupName(processInstanceRecord.getGroupName()); - record.setRootUserName(startUser.getName()); - record.setRootUserAvatarUrl(startUser.getAvatar()); - record.setTaskId(record.getTaskId()); - record.setStartTime(processInstanceRecord.getCreateTime()); - taskNewDtoList.add(record); - } - } - - pageResultDto.setRecords(taskNewDtoList); - - return R.ok(pageResultDto); - } - - /** - * 结束流程实例 - *

- * 手动结束一个流程实例,通常用于: 1. 流程审批完成,正常结束 2. 流程被终止或取消 - * - * 该方法会更新流程实例记录的结束时间、状态和结束原因 - *

- * @param processInstanceParamDto 流程实例参数,包含: - processInstanceId: 流程实例ID - paramMap: - * 可能包含approve_condition等结束原因 - * @return R 操作结果 - */ - @Override - public R end(ProcessInstanceParamDto processInstanceParamDto) { - - // 从参数中提取审批条件,用于判断流程结束原因(通过/拒绝) - Optional objectOptional = processInstanceParamDto.getParamMap() - .keySet() - .stream() - .filter(key -> key.contains("approve_condition")) - .reduce((first, second) -> second) - .map(key -> MapUtil.getBool(processInstanceParamDto.getParamMap(), key, true)); - - // 构建更新条件 - LambdaUpdateChainWrapper lambdaUpdateChainWrapper = processInstanceRecordService - .lambdaUpdate() - .set(ProcessInstanceRecord::getEndTime, new Date()) - .set(ProcessInstanceRecord::getStatus, NodeStatusEnum.YJS.getCode()); - - // 如果有审批结果,设置结束原因 - objectOptional - .ifPresent(aBoolean -> lambdaUpdateChainWrapper.set(ProcessInstanceRecord::getFinishReason, aBoolean)); - - // 执行更新 - lambdaUpdateChainWrapper - .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceParamDto.getProcessInstanceId()) - .update(new ProcessInstanceRecord()); - return R.ok(); - } - - /** - * 查询我发起的流程 - *

- * 查询当前用户发起的所有流程实例,支持: 1. 按状态过滤(进行中、已完成等) 2. 按时间范围过滤 3. 分页查询 - *

- * @param taskQueryParamDto 查询条件,包含状态、时间范围、分页参数 - * @return R 包含分页后的流程实例列表 - */ - @Override - public R queryMineStarted(TaskQueryParamDto taskQueryParamDto) { - - long userId = SecurityUtils.getUser().getId(); - - Page instanceRecordPage = processInstanceRecordService.lambdaQuery() - .eq(ProcessInstanceRecord::getUserId, userId) - .eq(ProcessInstanceRecord::getStatus, taskQueryParamDto.getStatus()) - .between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessInstanceRecord::getCreateTime, - ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, - ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null) - .orderByDesc(ProcessInstanceRecord::getCreateTime) - .page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize())); - - return R.ok(instanceRecordPage); - } - - /** - * 查询抄送给我的流程 - *

- * 查询抄送给当前用户的流程列表。抄送功能允许流程参与者将流程信息 通知给其他相关人员,被抄送人可以查看流程但不参与审批 - *

- * @param taskQueryParamDto 查询参数,支持时间范围过滤和分页 - * @return R 包含分页后的抄送记录,包括发起人信息 - */ - @Override - public R queryMineCC(TaskQueryParamDto taskQueryParamDto) { - - long userId = SecurityUtils.getUser().getId(); - - Page page = processCopyService.lambdaQuery() - .eq(ProcessCopy::getUserId, userId) - .between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessCopy::getCreateTime, - ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, - ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null) - .orderByDesc(ProcessCopy::getNodeTime) - .page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize())); - - List records = page.getRecords(); - - List processCopyVoList = BeanUtil.copyToList(records, ProcessCopyVo.class); - - if (CollUtil.isNotEmpty(records)) { - // 发起人 - List userIdList = records.stream().map(ProcessCopy::getStartUserId).toList(); - List startUserList = userService.getUserById(userIdList).getData(); - - for (ProcessCopyVo record : processCopyVoList) { - SysUser startUser = startUserList.stream() - .filter(w -> w.getUserId().longValue() == record.getStartUserId()) - .findAny() - .orElse(null); - record.setStartUserName(startUser.getUsername()); - } - } - - Page p = BeanUtil.copyProperties(page, Page.class); - p.setRecords(processCopyVoList); - return R.ok(p); - } - - /** - * 格式化流程显示 - *

- * 将流程定义数据格式化为前端可展示的节点结构,主要功能: 1. 解析流程定义的JSON数据 2. 标记已完成的节点 3. 根据流程变量计算条件节点的显示状态 4. - * 处理节点权限和表单权限 - * - * 该方法用于流程图的可视化展示 - *

- * @param nodeFormatParamVo 格式化参数,包含: - flowId: 流程定义ID - processInstanceId: 流程实例ID - - * taskId: 任务ID(可选) - paramMap: 流程变量 - * @return R 包含格式化后的节点列表 - */ - @SneakyThrows - @Override - public R formatStartNodeShow(NodeFormatParamVo nodeFormatParamVo) { - String flowId = nodeFormatParamVo.getFlowId(); - String processInstanceId = nodeFormatParamVo.getProcessInstanceId(); - if (StrUtil.isAllBlank(flowId, processInstanceId)) { - return R.ok(new ArrayList<>()); - } - - if (StrUtil.isBlankIfStr(flowId) && StrUtil.isNotBlank(processInstanceId)) { - ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() - .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) - .one(); - flowId = processInstanceRecord.getFlowId(); - - } - Map paramMap = nodeFormatParamVo.getParamMap(); - if (StrUtil.isNotBlank(nodeFormatParamVo.getTaskId())) { - VariableQueryParamDto variableQueryParamDto = new VariableQueryParamDto(); - variableQueryParamDto.setTaskId(nodeFormatParamVo.getTaskId()); - Map variables; - List keyList = variableQueryParamDto.getKeyList(); - if (CollUtil.isEmpty(keyList)) { - TaskQuery taskQuery = taskService.createTaskQuery(); - - Task task = taskQuery.taskId(variableQueryParamDto.getTaskId()).singleResult(); - if (task == null) { - return R.failed("任务不存在"); - } - - variables = runtimeService.getVariables(task.getExecutionId()); - } - else { - variables = taskService.getVariables(variableQueryParamDto.getTaskId(), keyList); - } - paramMap.putAll(variables); - } - - Set completeNodeSet = new HashSet<>(); - - if (StrUtil.isNotBlank(processInstanceId)) { - List processNodeRecordList = processNodeRecordService.lambdaQuery() - .eq(ProcessNodeRecord::getProcessInstanceId, processInstanceId) - .eq(ProcessNodeRecord::getStatus, NodeStatusEnum.YJS.getCode()) - .list(); - Set collect = processNodeRecordList.stream() - .map(ProcessNodeRecord::getNodeId) - .collect(Collectors.toSet()); - completeNodeSet.addAll(collect); - } - - Process oaForms = processService.getByFlowId(flowId); - String process = oaForms.getProcess(); - Node nodeDto = objectMapper.readValue(process, new TypeReference<>() { - }); - - List processNodeShowDtos = NodeFormatUtil.formatProcessNodeShow(nodeDto, completeNodeSet, - new HashSet<>(), processInstanceId, paramMap); - - return R.ok(processNodeShowDtos); - } - - /** - * 流程详情 - *

- * 查询流程实例的详细信息,包括: 1. 流程定义信息(流程结构) 2. 表单项定义 3. 表单数据(用户填写的数据) 4. 表单权限配置 5. 流程状态信息 - * - * 该方法主要用于流程详情页面的数据展示 - *

- * @param processInstanceId 流程实例ID - * @return R 包含流程详情的Dict对象 - * @throws Exception 当解析JSON数据失败时抛出异常 - */ - @SneakyThrows - @Override - public R detail(String processInstanceId) { - ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() - .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) - .one(); - - Process oaForms = processService.getByFlowId(processInstanceRecord.getFlowId()); - if (oaForms == null) { - return R.failed("流程不存在"); - } - - // 发起人变量数据 - String formData = processInstanceRecord.getFormData(); - String process = oaForms.getProcess(); - - Node nodeDto = objectMapper.readValue(process, Node.class); - Map formPerms1 = nodeDto.getFormPerms(); - - Dict set = Dict.create() - .set(ProcessInstanceRecord.Fields.processInstanceId, processInstanceId) - .set(ProcessInstanceRecord.Fields.status, processInstanceRecord.getStatus()) - .set("process", oaForms.getProcess()) - .set("formItems", oaForms.getFormItems()) - .set("formData", formData) - .set("formData", formData) - .set("formConfig", oaForms.getFormConfig()) - .set("formPerms", formPerms1); - - return R.ok(set); - } + private final RemoteUserService userService; + + private final TaskService taskService; + + private final RuntimeService runtimeService; + + private final HistoryService historyService; + + private final IProcessInstanceRecordService processInstanceRecordService; + + private final IProcessCopyService processCopyService; + + private final IProcessService processService; + + private final IProcessNodeRecordService processNodeRecordService; + + private final ObjectMapper objectMapper; + + /** + * 启动流程 + *

+ * 根据流程定义启动一个新的流程实例。该方法会: 1. 获取当前登录用户作为流程发起人 2. 设置流程发起人信息到流程变量中 3. 调用Flowable引擎启动流程 + *

+ * + * @param processInstanceParamDto 流程启动参数,包含: - flowId: 流程定义ID - paramMap: 流程变量 + * @return R 启动结果,包含流程实例ID等信息 + */ + @Override + public R startProcessInstance(ProcessInstanceParamDto processInstanceParamDto) { + + // 获取当前登录用户 + PigxUser user = SecurityUtils.getUser(); + + // 设置流程发起人ID + processInstanceParamDto.setStartUserId(String.valueOf(user.getId())); + Map paramMap = processInstanceParamDto.getParamMap(); + + // 将发起人信息作为root变量存入流程,用于流程节点的权限判断 + Dict rootUser = Dict.create().set("id", user.getId()).set("name", user.getUsername()).set("type", NodeUserTypeEnum.USER.getKey()); + paramMap.put("root", CollUtil.newArrayList(rootUser)); + + // 调用引擎启动流程 + Authentication.setAuthenticatedUserId(processInstanceParamDto.getStartUserId()); + ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(processInstanceParamDto.getFlowId(), processInstanceParamDto.getParamMap(), TenantContextHolder.getTenantId().toString()); + + String processInstanceId = processInstance.getProcessInstanceId(); + return R.ok(processInstanceId); + } + + /** + * 查询当前登录用户的待办任务 + *

+ * 查询分配给当前用户的待办任务列表,并补充以下信息: 1. 流程实例的详细信息(流程名称、分组等) 2. 流程发起人信息(姓名、头像等) 3. 流程启动时间 + *

+ * + * @param taskQueryParamDto 查询参数,支持分页和条件过滤 + * @return R 包含分页后的待办任务列表 + */ + @Override + public R queryMineTask(TaskQueryParamDto taskQueryParamDto) { + taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); + + String assign = taskQueryParamDto.getAssign(); + + List taskDtoList = new ArrayList<>(); + + int pageIndex = taskQueryParamDto.getCurrent() - 1; + int pageSize = taskQueryParamDto.getSize(); + + Page pageResultDto = new Page<>(); + TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(assign).orderByTaskCreateTime().desc(); + if (StrUtil.isNotBlank(taskQueryParamDto.getProcessName())) { + List processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionName(taskQueryParamDto.getProcessName()).processInstanceTenantId(TenantContextHolder.getTenantId().toString()).list(); + if (CollUtil.isNotEmpty(processInstanceList)) { + taskQuery.processInstanceIdIn(processInstanceList.stream().map(ProcessInstance::getProcessInstanceId).toList()); + } + } + + if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) { + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId); + ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId); + Date beforeDate = Date.from(zonedBeforeDateTime.toInstant()); + Date afterDate = Date.from(zonedAfterDateTime.toInstant()); + taskQuery.taskCreatedBefore(afterDate).taskCreatedAfter(beforeDate); + } + + taskQuery.listPage(pageIndex * pageSize, pageSize).forEach(task -> { + String taskId = task.getId(); + String processInstanceId = task.getProcessInstanceId(); + log.debug("(taskId) {} processInstanceId={} executrionId={}", task.getName(), processInstanceId, task.getExecutionId()); + + String taskDefinitionKey = task.getTaskDefinitionKey(); + String processDefinitionId = task.getProcessDefinitionId(); + String flowId = NodeUtil.getFlowId(processDefinitionId); + + TaskDto taskDto = new TaskDto(); + taskDto.setFlowId(flowId); + taskDto.setTaskCreateTime(task.getCreateTime()); + taskDto.setNodeId(taskDefinitionKey); + taskDto.setProcessInstanceId(processInstanceId); + taskDto.setTaskId(taskId); + taskDto.setAssign(task.getAssignee()); + taskDto.setTaskName(task.getName()); + taskDtoList.add(taskDto); + }); + + long count = taskQuery.count(); + + log.debug("当前有 {} 个任务:", count); + + pageResultDto.setTotal(count); + pageResultDto.setRecords(taskDtoList); + + if (CollUtil.isEmpty(taskDtoList)) { + return R.ok(); + } + + Set processInstanceIdSet = taskDtoList.stream().map(TaskDto::getProcessInstanceId).collect(Collectors.toSet()); + + // 流程实例记录 + List processInstanceRecordList = processInstanceRecordService.lambdaQuery().in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet).list(); + + // 发起人 + List collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList(); + List startUserList = userService.getUserById(collect).getData(); + + List taskNewDtoList = new ArrayList<>(); + for (TaskDto record : taskDtoList) { + ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream().filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())).findAny().orElse(null); + + if (processInstanceRecord != null) { + record.setProcessName(processInstanceRecord.getName()); + SysUser startUser = startUserList.stream().filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()).findAny().orElse(null); + + record.setRootUserId(processInstanceRecord.getUserId()); + record.setGroupName(processInstanceRecord.getGroupName()); + record.setRootUserName(startUser.getUsername()); + record.setRootUserAvatarUrl(startUser.getAvatar()); + record.setStartTime(processInstanceRecord.getCreateTime()); + + taskNewDtoList.add(record); + } + } + + pageResultDto.setRecords(taskNewDtoList); + + return R.ok(pageResultDto); + } + + /** + * 查询已办任务 + *

+ * 查询当前用户已经完成的任务列表,包括: 1. 用户已审批的任务 2. 补充流程实例信息、发起人信息等 + *

+ * + * @param taskQueryParamDto 查询参数,支持分页和时间范围过滤 + * @return R 包含分页后的已办任务列表 + */ + @Override + public R queryMineEndTask(TaskQueryParamDto taskQueryParamDto) { + taskQueryParamDto.setAssign(SecurityUtils.getUser().getId().toString()); + + HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery(); + HistoricActivityInstanceQuery activityInstanceQuery = historicActivityInstanceQuery.taskAssignee(taskQueryParamDto.getAssign()).finished().orderByHistoricActivityInstanceEndTime().desc(); + + if (ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime())) { + ZoneId zoneId = ZoneId.systemDefault(); + ZonedDateTime zonedBeforeDateTime = taskQueryParamDto.getTaskTime()[0].atZone(zoneId); + ZonedDateTime zonedAfterDateTime = taskQueryParamDto.getTaskTime()[1].atZone(zoneId); + Date beforeDate = Date.from(zonedBeforeDateTime.toInstant()); + Date afterDate = Date.from(zonedAfterDateTime.toInstant()); + activityInstanceQuery.finishedBefore(afterDate).finishedAfter(beforeDate); + } + + List list = activityInstanceQuery.listPage((taskQueryParamDto.getCurrent() - 1) * taskQueryParamDto.getSize(), taskQueryParamDto.getSize()); + + long count = activityInstanceQuery.count(); + List taskDtoList = new ArrayList<>(); + + for (HistoricActivityInstance historicActivityInstance : list) { + String activityId = historicActivityInstance.getActivityId(); + String activityName = historicActivityInstance.getActivityName(); + String executionId = historicActivityInstance.getExecutionId(); + String taskId = historicActivityInstance.getTaskId(); + Date startTime = historicActivityInstance.getStartTime(); + Date endTime = historicActivityInstance.getEndTime(); + Long durationInMillis = historicActivityInstance.getDurationInMillis(); + String processInstanceId = historicActivityInstance.getProcessInstanceId(); + + String processDefinitionId = historicActivityInstance.getProcessDefinitionId(); + // 流程id + String flowId = NodeUtil.getFlowId(processDefinitionId); + + TaskDto taskDto = new TaskDto(); + taskDto.setFlowId(flowId); + taskDto.setTaskCreateTime(startTime); + taskDto.setTaskEndTime(endTime); + taskDto.setNodeId(activityId); + taskDto.setExecutionId(executionId); + taskDto.setProcessInstanceId(processInstanceId); + taskDto.setDurationInMillis(durationInMillis); + taskDto.setTaskId(taskId); + taskDto.setAssign(historicActivityInstance.getAssignee()); + taskDto.setTaskName(activityName); + + taskDtoList.add(taskDto); + } + + Page pageResultDto = new Page<>(); + pageResultDto.setTotal(count); + pageResultDto.setRecords(taskDtoList); + + List records = pageResultDto.getRecords(); + if (CollUtil.isEmpty(records)) { + return R.ok(pageResultDto); + + } + + Set processInstanceIdSet = records.stream().map(TaskDto::getProcessInstanceId).collect(Collectors.toSet()); + + // 流程实例记录 + List processInstanceRecordList = processInstanceRecordService.lambdaQuery().in(ProcessInstanceRecord::getProcessInstanceId, processInstanceIdSet).list(); + + // 发起人 + List collect = processInstanceRecordList.stream().map(ProcessInstanceRecord::getUserId).toList(); + List startUserList = userService.getUserById(collect).getData(); + + List taskNewDtoList = new ArrayList<>(); + for (TaskDto record : records) { + + ProcessInstanceRecord processInstanceRecord = processInstanceRecordList.stream().filter(w -> StrUtil.equals(w.getProcessInstanceId(), record.getProcessInstanceId())).findAny().orElse(null); + + if (processInstanceRecord != null) { + + record.setProcessName(processInstanceRecord.getName()); + + SysUser startUser = startUserList.stream().filter(w -> w.getUserId().longValue() == processInstanceRecord.getUserId()).findAny().orElse(null); + + record.setRootUserId(processInstanceRecord.getUserId()); + record.setGroupName(processInstanceRecord.getGroupName()); + record.setRootUserName(startUser.getName()); + record.setRootUserAvatarUrl(startUser.getAvatar()); + record.setTaskId(record.getTaskId()); + record.setStartTime(processInstanceRecord.getCreateTime()); + taskNewDtoList.add(record); + } + } + + pageResultDto.setRecords(taskNewDtoList); + + return R.ok(pageResultDto); + } + + /** + * 结束流程实例 + *

+ * 手动结束一个流程实例,通常用于: 1. 流程审批完成,正常结束 2. 流程被终止或取消 + *

+ * 该方法会更新流程实例记录的结束时间、状态和结束原因 + *

+ * + * @param processInstanceParamDto 流程实例参数,包含: - processInstanceId: 流程实例ID - paramMap: + * 可能包含approve_condition等结束原因 + * @return R 操作结果 + */ + @Override + public R end(ProcessInstanceParamDto processInstanceParamDto) { + + // 从参数中提取审批条件,用于判断流程结束原因(通过/拒绝) + Optional objectOptional = processInstanceParamDto.getParamMap().keySet().stream().filter(key -> key.contains("approve_condition")).reduce((first, second) -> second).map(key -> MapUtil.getBool(processInstanceParamDto.getParamMap(), key, true)); + + // 构建更新条件 + LambdaUpdateChainWrapper lambdaUpdateChainWrapper = processInstanceRecordService.lambdaUpdate().set(ProcessInstanceRecord::getEndTime, new Date()).set(ProcessInstanceRecord::getStatus, NodeStatusEnum.YJS.getCode()); + + // 如果有审批结果,设置结束原因 + objectOptional.ifPresent(aBoolean -> lambdaUpdateChainWrapper.set(ProcessInstanceRecord::getFinishReason, aBoolean)); + + // 执行更新 + lambdaUpdateChainWrapper.eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceParamDto.getProcessInstanceId()).update(new ProcessInstanceRecord()); + return R.ok(); + } + + /** + * 查询我发起的流程 + *

+ * 查询当前用户发起的所有流程实例,支持: 1. 按状态过滤(进行中、已完成等) 2. 按时间范围过滤 3. 分页查询 + *

+ * + * @param taskQueryParamDto 查询条件,包含状态、时间范围、分页参数 + * @return R 包含分页后的流程实例列表 + */ + @Override + public R queryMineStarted(TaskQueryParamDto taskQueryParamDto) { + + long userId = SecurityUtils.getUser().getId(); + + Page instanceRecordPage = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getUserId, userId).eq(ProcessInstanceRecord::getStatus, taskQueryParamDto.getStatus()).between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessInstanceRecord::getCreateTime, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null).orderByDesc(ProcessInstanceRecord::getCreateTime).page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize())); + + return R.ok(instanceRecordPage); + } + + /** + * 查询抄送给我的流程 + *

+ * 查询抄送给当前用户的流程列表。抄送功能允许流程参与者将流程信息 通知给其他相关人员,被抄送人可以查看流程但不参与审批 + *

+ * + * @param taskQueryParamDto 查询参数,支持时间范围过滤和分页 + * @return R 包含分页后的抄送记录,包括发起人信息 + */ + @Override + public R queryMineCC(TaskQueryParamDto taskQueryParamDto) { + + long userId = SecurityUtils.getUser().getId(); + + Page page = processCopyService.lambdaQuery().eq(ProcessCopy::getUserId, userId).between(ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()), ProcessCopy::getCreateTime, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[0] : null, ArrayUtil.isNotEmpty(taskQueryParamDto.getTaskTime()) ? taskQueryParamDto.getTaskTime()[1] : null).orderByDesc(ProcessCopy::getNodeTime).page(new Page<>(taskQueryParamDto.getCurrent(), taskQueryParamDto.getSize())); + + List records = page.getRecords(); + + List processCopyVoList = BeanUtil.copyToList(records, ProcessCopyVo.class); + + if (CollUtil.isNotEmpty(records)) { + // 发起人 + List userIdList = records.stream().map(ProcessCopy::getStartUserId).toList(); + List startUserList = userService.getUserById(userIdList).getData(); + + for (ProcessCopyVo record : processCopyVoList) { + SysUser startUser = startUserList.stream().filter(w -> w.getUserId().longValue() == record.getStartUserId()).findAny().orElse(null); + record.setStartUserName(startUser.getUsername()); + } + } + + Page p = BeanUtil.copyProperties(page, Page.class); + p.setRecords(processCopyVoList); + return R.ok(p); + } + + /** + * 格式化流程显示 + *

+ * 将流程定义数据格式化为前端可展示的节点结构,主要功能: 1. 解析流程定义的JSON数据 2. 标记已完成的节点 3. 根据流程变量计算条件节点的显示状态 4. + * 处理节点权限和表单权限 + *

+ * 该方法用于流程图的可视化展示 + *

+ * + * @param nodeFormatParamVo 格式化参数,包含: - flowId: 流程定义ID - processInstanceId: 流程实例ID - + * taskId: 任务ID(可选) - paramMap: 流程变量 + * @return R 包含格式化后的节点列表 + */ + @SneakyThrows + @Override + public R formatStartNodeShow(NodeFormatParamVo nodeFormatParamVo) { + String flowId = nodeFormatParamVo.getFlowId(); + String processInstanceId = nodeFormatParamVo.getProcessInstanceId(); + if (StrUtil.isAllBlank(flowId, processInstanceId)) { + return R.ok(new ArrayList<>()); + } + + if (StrUtil.isBlankIfStr(flowId) && StrUtil.isNotBlank(processInstanceId)) { + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one(); + flowId = processInstanceRecord.getFlowId(); + + } + Map paramMap = nodeFormatParamVo.getParamMap(); + if (StrUtil.isNotBlank(nodeFormatParamVo.getTaskId())) { + VariableQueryParamDto variableQueryParamDto = new VariableQueryParamDto(); + variableQueryParamDto.setTaskId(nodeFormatParamVo.getTaskId()); + Map variables; + List keyList = variableQueryParamDto.getKeyList(); + if (CollUtil.isEmpty(keyList)) { + TaskQuery taskQuery = taskService.createTaskQuery(); + + Task task = taskQuery.taskId(variableQueryParamDto.getTaskId()).singleResult(); + if (task == null) { + return R.failed("任务不存在"); + } + + variables = runtimeService.getVariables(task.getExecutionId()); + } else { + variables = taskService.getVariables(variableQueryParamDto.getTaskId(), keyList); + } + paramMap.putAll(variables); + } + + Set completeNodeSet = new HashSet<>(); + Set continueNodeSet = new HashSet<>(); + if (StrUtil.isNotBlank(processInstanceId)) { + List processNodeRecordList = processNodeRecordService.lambdaQuery().eq(ProcessNodeRecord::getProcessInstanceId, processInstanceId).eq(ProcessNodeRecord::getStatus, NodeStatusEnum.YJS.getCode()).list(); + Set collect = processNodeRecordList.stream().map(ProcessNodeRecord::getNodeId).collect(Collectors.toSet()); + + + List jxzNodeRecordList = processNodeRecordService.lambdaQuery().eq(ProcessNodeRecord::getProcessInstanceId, processInstanceId).eq(ProcessNodeRecord::getStatus, NodeStatusEnum.JXZ.getCode()).list(); + + Set jxzCollect = jxzNodeRecordList.stream().map(ProcessNodeRecord::getNodeId).collect(Collectors.toSet()); + continueNodeSet.addAll(jxzCollect); + completeNodeSet.addAll(collect); + } + + Process oaForms = processService.getByFlowId(flowId); + String process = oaForms.getProcess(); + Node nodeDto = objectMapper.readValue(process, new TypeReference<>() { + }); + + List processNodeShowDtos = NodeFormatUtil.formatProcessNodeShow(nodeDto, completeNodeSet, continueNodeSet, processInstanceId, paramMap); + + return R.ok(processNodeShowDtos); + } + + /** + * 流程详情 + *

+ * 查询流程实例的详细信息,包括: 1. 流程定义信息(流程结构) 2. 表单项定义 3. 表单数据(用户填写的数据) 4. 表单权限配置 5. 流程状态信息 + *

+ * 该方法主要用于流程详情页面的数据展示 + *

+ * + * @param processInstanceId 流程实例ID + * @return R 包含流程详情的Dict对象 + * @throws Exception 当解析JSON数据失败时抛出异常 + */ + @SneakyThrows + @Override + public R detail(String processInstanceId) { + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one(); + + Process oaForms = processService.getByFlowId(processInstanceRecord.getFlowId()); + if (oaForms == null) { + return R.failed("流程不存在"); + } + + // 发起人变量数据 + String formData = processInstanceRecord.getFormData(); + String process = oaForms.getProcess(); + + Node nodeDto = objectMapper.readValue(process, Node.class); + Map formPerms1 = nodeDto.getFormPerms(); + + Dict set = Dict.create().set(ProcessInstanceRecord.Fields.processInstanceId, processInstanceId).set(ProcessInstanceRecord.Fields.status, processInstanceRecord.getStatus()).set("process", oaForms.getProcess()).set("formItems", oaForms.getFormItems()).set("formData", formData).set("formData", formData).set("formConfig", oaForms.getFormConfig()).set("formPerms", formPerms1); + + return R.ok(set); + } } diff --git a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/support/utils/NodeFormatUtil.java b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/support/utils/NodeFormatUtil.java index 643063c9a..35e142123 100644 --- a/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/support/utils/NodeFormatUtil.java +++ b/pigx-flow/pigx-flow-biz/src/main/java/com/pig4cloud/pigx/flow/support/utils/NodeFormatUtil.java @@ -42,305 +42,272 @@ import java.util.stream.Collectors; */ public class NodeFormatUtil { - /** - * 格式化流程节点为可视化展示结构 - *

- * 递归处理流程节点树,生成包含节点状态、执行人信息的展示数据。 支持处理各种节点类型,包括审批节点、抄送节点、网关节点等。 - * @param node 当前处理的节点对象 - * @param completeNodeSet 已完成的节点ID集合 - * @param continueNodeSet 进行中的节点ID集合 - * @param processInstanceId 流程实例ID,用于查询历史数据,可为null - * @param paramMap 流程变量Map,包含表单数据和执行人选择信息 - * @return 格式化后的节点展示对象列表 - */ - @SneakyThrows - public static List formatProcessNodeShow(Node node, Set completeNodeSet, - Set continueNodeSet, String processInstanceId, Map paramMap) { - List list = new ArrayList<>(); + /** + * 格式化流程节点为可视化展示结构 + *

+ * 递归处理流程节点树,生成包含节点状态、执行人信息的展示数据。 支持处理各种节点类型,包括审批节点、抄送节点、网关节点等。 + * + * @param node 当前处理的节点对象 + * @param completeNodeSet 已完成的节点ID集合 + * @param continueNodeSet 进行中的节点ID集合 + * @param processInstanceId 流程实例ID,用于查询历史数据,可为null + * @param paramMap 流程变量Map,包含表单数据和执行人选择信息 + * @return 格式化后的节点展示对象列表 + */ + @SneakyThrows + public static List formatProcessNodeShow(Node node, Set completeNodeSet, Set continueNodeSet, String processInstanceId, Map paramMap) { + List list = new ArrayList<>(); - if (!NodeUtil.isNode(node)) { - return list; - } + if (!NodeUtil.isNode(node)) { + return list; + } - String name = node.getName(); - Integer type = node.getType(); + String name = node.getName(); + Integer type = node.getType(); - // SELF_SELECT + // SELF_SELECT - NodeVo nodeVo = new NodeVo(); - nodeVo.setId(node.getId()); - nodeVo.setName(name); - nodeVo.setType(type); - nodeVo.setStatus(NodeStatusEnum.WKS.getCode()); - if (completeNodeSet.contains(node.getId())) { - nodeVo.setStatus(NodeStatusEnum.YJS.getCode()); + NodeVo nodeVo = new NodeVo(); + nodeVo.setId(node.getId()); + nodeVo.setName(name); + nodeVo.setType(type); + nodeVo.setStatus(NodeStatusEnum.WKS.getCode()); + if (completeNodeSet.contains(node.getId())) { + nodeVo.setStatus(NodeStatusEnum.YJS.getCode()); - } - if (continueNodeSet.contains(node.getId())) { - nodeVo.setStatus(NodeStatusEnum.JXZ.getCode()); + } + if (continueNodeSet.contains(node.getId())) { + nodeVo.setStatus(NodeStatusEnum.JXZ.getCode()); - } + } - { - nodeVo.setPlaceholder(node.getPlaceHolder()); - } + nodeVo.setPlaceholder(node.getPlaceHolder()); - List userVoList = new ArrayList<>(); - if (type == NodeTypeEnum.APPROVAL.getValue().intValue()) { + List userVoList = new ArrayList<>(); + if (type == NodeTypeEnum.APPROVAL.getValue().intValue()) { - Integer assignedType = node.getAssignedType(); + Integer assignedType = node.getAssignedType(); - boolean selfSelect = assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT; - nodeVo.setSelectUser(selfSelect); - if (selfSelect) { - nodeVo.setMultiple(node.getMultiple()); - } + boolean selfSelect = assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT; + nodeVo.setSelectUser(selfSelect); + if (selfSelect) { + nodeVo.setMultiple(node.getMultiple()); + } - // 用户列表 - if (StrUtil.isNotBlank(processInstanceId)) { - IProcessNodeRecordAssignUserService processNodeRecordAssignUserService = SpringUtil - .getBean(IProcessNodeRecordAssignUserService.class); - List processNodeRecordAssignUserList = processNodeRecordAssignUserService - .lambdaQuery() - .eq(ProcessNodeRecordAssignUser::getNodeId, node.getId()) - .eq(ProcessNodeRecordAssignUser::getProcessInstanceId, processInstanceId) - .orderByAsc(ProcessNodeRecordAssignUser::getCreateTime) - .list(); - Map> map = processNodeRecordAssignUserList.stream() - .collect(Collectors.groupingBy(ProcessNodeRecordAssignUser::getTaskId)); + // 用户列表 + if (StrUtil.isNotBlank(processInstanceId)) { + IProcessNodeRecordAssignUserService processNodeRecordAssignUserService = SpringUtil.getBean(IProcessNodeRecordAssignUserService.class); + List processNodeRecordAssignUserList = processNodeRecordAssignUserService.lambdaQuery().eq(ProcessNodeRecordAssignUser::getNodeId, node.getId()).eq(ProcessNodeRecordAssignUser::getProcessInstanceId, processInstanceId).orderByAsc(ProcessNodeRecordAssignUser::getCreateTime).list(); + Map> map = processNodeRecordAssignUserList.stream().collect(Collectors.groupingBy(ProcessNodeRecordAssignUser::getTaskId)); - for (Map.Entry> entry : map.entrySet()) { - List value = entry.getValue(); - List collect = value.stream().map(w -> { - UserVo userVo = buildUser(w.getUserId()); - if (userVo == null) { - return null; - } + for (Map.Entry> entry : map.entrySet()) { + List value = entry.getValue(); + List collect = value.stream().map(w -> { + UserVo userVo = buildUser(w.getUserId()); + if (userVo == null) { + return null; + } - userVo.setShowTime(w.getEndTime()); - userVo.setApproveDesc(w.getApproveDesc()); - userVo.setStatus(w.getStatus()); - userVo.setOperType(w.getTaskType()); - return userVo; - }).filter(Objects::nonNull).toList(); - userVoList.addAll(collect); - } + userVo.setShowTime(w.getEndTime()); + userVo.setApproveDesc(w.getApproveDesc()); + userVo.setStatus(w.getStatus()); + userVo.setOperType(w.getTaskType()); + return userVo; + }).filter(Objects::nonNull).toList(); + userVoList.addAll(collect); + } - if (processNodeRecordAssignUserList.isEmpty()) { - if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) { - // 发起人自己 - userVoList.addAll(CollUtil.newArrayList(buildRootUser(processInstanceId))); - } - if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT) { - // 发起人自选 - Object variable = paramMap.get(StrUtil.format("{}_assignee_select", node.getId())); + if (processNodeRecordAssignUserList.isEmpty()) { + if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) { + // 发起人自己 + userVoList.addAll(CollUtil.newArrayList(buildRootUser(processInstanceId))); + } + if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF_SELECT) { + // 发起人自选 + Object variable = paramMap.get(StrUtil.format("{}_assignee_select", node.getId())); - ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class); - List nodeUserDtos = objectMapper.readValue(objectMapper.writeValueAsString(variable), - new TypeReference<>() { - }); + ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class); + List nodeUserDtos = objectMapper.readValue(objectMapper.writeValueAsString(variable), new TypeReference<>() { + }); - if (CollUtil.isNotEmpty(nodeUserDtos)) { - List collect = nodeUserDtos.stream().map(NodeUser::getId).toList(); - for (Long aLong : collect) { - UserVo userVo = buildUser(aLong); - userVoList.addAll(CollUtil.newArrayList(userVo)); - } - } + if (CollUtil.isNotEmpty(nodeUserDtos)) { + List collect = nodeUserDtos.stream().map(NodeUser::getId).toList(); + for (Long aLong : collect) { + UserVo userVo = buildUser(aLong); + userVoList.addAll(CollUtil.newArrayList(userVo)); + } + } - } - } + } + } - } - else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.USER) { - // 指定用户 + } else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.USER) { + // 指定用户 - List nodeUserList = node.getNodeUserList(); - List tempList = buildUser(nodeUserList); - userVoList.addAll(tempList); + List nodeUserList = node.getNodeUserList(); + List tempList = buildUser(nodeUserList); + userVoList.addAll(tempList); - } - else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.FORM_USER) { - // 表单人员 - String formUser = node.getFormUserId(); + } else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.FORM_USER) { + // 表单人员 + String formUser = node.getFormUserId(); - Object o = paramMap.get(formUser); - if (o != null) { - ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class); - String jsonString = objectMapper.writeValueAsString(o); - if (StrUtil.isNotBlank(jsonString)) { - List nodeUserDtoList = objectMapper.readValue(jsonString, new TypeReference<>() { - }); - List userIdList = nodeUserDtoList.stream().map(NodeUser::getId).toList(); - for (Long aLong : userIdList) { - userVoList.addAll(CollUtil.newArrayList(buildUser(aLong))); - } - } - } + Object o = paramMap.get(formUser); + if (o != null) { + ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class); + String jsonString = objectMapper.writeValueAsString(o); + if (StrUtil.isNotBlank(jsonString)) { + List nodeUserDtoList = objectMapper.readValue(jsonString, new TypeReference<>() { + }); + List userIdList = nodeUserDtoList.stream().map(NodeUser::getId).toList(); + for (Long aLong : userIdList) { + userVoList.addAll(CollUtil.newArrayList(buildUser(aLong))); + } + } + } - } - else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) { - // 发起人自己 - userVoList.addAll(CollUtil.newArrayList(buildUser(SecurityUtils.getUser().getId()))); - } + } else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.SELF) { + // 发起人自己 + userVoList.addAll(CollUtil.newArrayList(buildUser(SecurityUtils.getUser().getId()))); + } else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.EXPRESSION) { + // 表达式 + // Object result = getExpressionValue(paramMap, node.getAssignExpress()); + // List userVos = Convert.toList(Long.class, result) + // .stream() + // .map(NodeFormatUtil::buildUser) + // .toList(); + // userVoList.addAll(userVos); + } - else if (assignedType == ProcessInstanceConstant.AssignedTypeClass.EXPRESSION) { - // 表达式 - // Object result = getExpressionValue(paramMap, node.getAssignExpress()); - // List userVos = Convert.toList(Long.class, result) - // .stream() - // .map(NodeFormatUtil::buildUser) - // .toList(); - // userVoList.addAll(userVos); - } + } else if (Objects.equals(node.getType(), NodeTypeEnum.ROOT.getValue())) { + // 发起节点 + if (StrUtil.isBlank(processInstanceId)) { + UserVo userVo = buildUser(SecurityUtils.getUser().getId()); + userVoList.addAll(CollUtil.newArrayList(userVo)); + } else { - } - else if (Objects.equals(node.getType(), NodeTypeEnum.ROOT.getValue())) { - // 发起节点 - if (StrUtil.isBlank(processInstanceId)) { - UserVo userVo = buildUser(SecurityUtils.getUser().getId()); - userVoList.addAll(CollUtil.newArrayList(userVo)); - } - else { + IProcessInstanceRecordService processInstanceRecordService = SpringUtil.getBean(IProcessInstanceRecordService.class); + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one(); - IProcessInstanceRecordService processInstanceRecordService = SpringUtil - .getBean(IProcessInstanceRecordService.class); - ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() - .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) - .one(); + UserVo userVo = buildRootUser(processInstanceId); + userVo.setShowTime(processInstanceRecord.getCreateTime()); + userVo.setStatus(NodeStatusEnum.YJS.getCode()); + userVoList.addAll(CollUtil.newArrayList(userVo)); - UserVo userVo = buildRootUser(processInstanceId); - userVo.setShowTime(processInstanceRecord.getCreateTime()); - userVo.setStatus(NodeStatusEnum.YJS.getCode()); - userVoList.addAll(CollUtil.newArrayList(userVo)); + } + } else if (Objects.equals(node.getType(), NodeTypeEnum.CC.getValue())) { + // 抄送节点 - } - } - else if (Objects.equals(node.getType(), NodeTypeEnum.CC.getValue())) { - // 抄送节点 + List nodeUserList = node.getNodeUserList(); - List nodeUserList = node.getNodeUserList(); + List tempList = buildUser(nodeUserList); + userVoList.addAll(tempList); - List tempList = buildUser(nodeUserList); - userVoList.addAll(tempList); + } - } + // 根据userVo 的ID 去重userVoList + nodeVo.setUserVoList(CollUtil.distinct(userVoList, UserVo::getId, true)); - // 根据userVo 的ID 去重userVoList - nodeVo.setUserVoList(CollUtil.distinct(userVoList, UserVo::getId, true)); + List branchList = new ArrayList<>(); - List branchList = new ArrayList<>(); + if (type == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue() || type == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) { + // 条件分支 + List branchs = node.getConditionNodes(); - if (type == NodeTypeEnum.EXCLUSIVE_GATEWAY.getValue().intValue() - || type == NodeTypeEnum.PARALLEL_GATEWAY.getValue().intValue()) { - // 条件分支 - List branchs = node.getConditionNodes(); + for (Node branch : branchs) { + Node children = branch.getChildren(); + List processNodeShowDtos = formatProcessNodeShow(children, completeNodeSet, continueNodeSet, processInstanceId, paramMap); - for (Node branch : branchs) { - Node children = branch.getChildren(); - List processNodeShowDtos = formatProcessNodeShow(children, completeNodeSet, continueNodeSet, - processInstanceId, paramMap); + NodeVo p = new NodeVo(); + p.setChildren(processNodeShowDtos); - NodeVo p = new NodeVo(); - p.setChildren(processNodeShowDtos); + p.setPlaceholder(branch.getPlaceHolder()); + branchList.add(p); + } + } + nodeVo.setBranch(branchList); - p.setPlaceholder(branch.getPlaceHolder()); - branchList.add(p); - } - } - nodeVo.setBranch(branchList); + list.add(nodeVo); - list.add(nodeVo); + List next = formatProcessNodeShow(node.getChildren(), completeNodeSet, continueNodeSet, processInstanceId, paramMap); + list.addAll(next); - List next = formatProcessNodeShow(node.getChildren(), completeNodeSet, continueNodeSet, - processInstanceId, paramMap); - list.addAll(next); + return list; + } - return list; - } + /** + * 根据流程实例ID构建发起人用户信息 + *

+ * 查询流程实例记录,获取发起人的用户ID,并构建用户展示对象。 主要用于展示流程的发起人信息。 + * + * @param processInstanceId 流程实例ID + * @return 发起人的用户展示对象 + */ + private static UserVo buildRootUser(String processInstanceId) { - /** - * 根据流程实例ID构建发起人用户信息 - *

- * 查询流程实例记录,获取发起人的用户ID,并构建用户展示对象。 主要用于展示流程的发起人信息。 - * @param processInstanceId 流程实例ID - * @return 发起人的用户展示对象 - */ - private static UserVo buildRootUser(String processInstanceId) { + IProcessInstanceRecordService processInstanceRecordService = SpringUtil.getBean(IProcessInstanceRecordService.class); + ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery().eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId).one(); + Long userId = processInstanceRecord.getUserId(); + return buildUser(userId); + } - IProcessInstanceRecordService processInstanceRecordService = SpringUtil - .getBean(IProcessInstanceRecordService.class); - ProcessInstanceRecord processInstanceRecord = processInstanceRecordService.lambdaQuery() - .eq(ProcessInstanceRecord::getProcessInstanceId, processInstanceId) - .one(); - Long userId = processInstanceRecord.getUserId(); - return buildUser(userId); - } + /** + * 根据用户ID构建用户展示信息 + *

+ * 通过远程服务获取用户详细信息,并构建用户展示对象。 如果用户不存在或为空执行人ID,返回特殊处理的对象。 + * + * @param userId 用户ID + * @return 用户展示对象,如果用户不存在则返回null + */ + private static UserVo buildUser(long userId) { + if (ProcessInstanceConstant.DEFAULT_EMPTY_ASSIGN == userId) { + return UserVo.builder().id(userId).build(); + } - /** - * 根据用户ID构建用户展示信息 - *

- * 通过远程服务获取用户详细信息,并构建用户展示对象。 如果用户不存在或为空执行人ID,返回特殊处理的对象。 - * @param userId 用户ID - * @return 用户展示对象,如果用户不存在则返回null - */ - private static UserVo buildUser(long userId) { - if (ProcessInstanceConstant.DEFAULT_EMPTY_ASSIGN == userId) { - return UserVo.builder().id(userId).build(); - } + RemoteUserService userService = SpringUtil.getBean(RemoteUserService.class); + SysUser user = RetOps.of(userService.getUserById(CollUtil.newArrayList(userId))).getData().map(sysUsers -> sysUsers.isEmpty() ? null : sysUsers.get(0)).orElse(null); + if (user == null) { + return null; + } - RemoteUserService userService = SpringUtil.getBean(RemoteUserService.class); - SysUser user = RetOps.of(userService.getUserById(CollUtil.newArrayList(userId))) - .getData() - .map(sysUsers -> sysUsers.isEmpty() ? null : sysUsers.get(0)) - .orElse(null); - if (user == null) { - return null; - } + return UserVo.builder().id(userId).name(user.getName()).avatar(user.getAvatar()).build(); + } - return UserVo.builder().id(userId).name(user.getName()).avatar(user.getAvatar()).build(); - } + /** + * 批量构建用户展示信息 + *

+ * 根据节点用户配置列表,批量获取用户信息并构建展示对象。 支持处理用户类型和部门类型: - 用户类型:直接获取用户信息 - 部门类型:获取部门下的所有用户 + * + * @param nodeUserList 节点用户配置列表,包含用户ID和部门ID + * @return 用户展示对象列表 + */ + private static List buildUser(List nodeUserList) { + List userVoList = new ArrayList<>(); + // 用户id + List userIdList = nodeUserList.stream().filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey())).map(w -> Convert.toLong(w.getId())).toList(); + // 部门id + List deptIdList = nodeUserList.stream().filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey())).map(w -> Convert.toLong(w.getId())).toList(); - /** - * 批量构建用户展示信息 - *

- * 根据节点用户配置列表,批量获取用户信息并构建展示对象。 支持处理用户类型和部门类型: - 用户类型:直接获取用户信息 - 部门类型:获取部门下的所有用户 - * @param nodeUserList 节点用户配置列表,包含用户ID和部门ID - * @return 用户展示对象列表 - */ - private static List buildUser(List nodeUserList) { - List userVoList = new ArrayList<>(); - // 用户id - List userIdList = nodeUserList.stream() - .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.USER.getKey())) - .map(w -> Convert.toLong(w.getId())) - .toList(); - // 部门id - List deptIdList = nodeUserList.stream() - .filter(w -> StrUtil.equals(w.getType(), NodeUserTypeEnum.DEPT.getKey())) - .map(w -> Convert.toLong(w.getId())) - .toList(); + if (CollUtil.isNotEmpty(deptIdList)) { - if (CollUtil.isNotEmpty(deptIdList)) { + IRemoteService iRemoteService = SpringUtil.getBean(IRemoteService.class); - IRemoteService iRemoteService = SpringUtil.getBean(IRemoteService.class); + List data = iRemoteService.queryUserIdListByDepIdList(deptIdList).getData(); - List data = iRemoteService.queryUserIdListByDepIdList(deptIdList).getData(); - - if (CollUtil.isNotEmpty(data)) { - for (long datum : data) { - if (!userIdList.contains(datum)) { - userIdList.add(datum); - } - } - } - } - { - for (Long aLong : userIdList) { - userVoList.addAll(CollUtil.newArrayList(buildUser(aLong))); - } - } - return userVoList; - } + if (CollUtil.isNotEmpty(data)) { + for (long datum : data) { + if (!userIdList.contains(datum)) { + userIdList.add(datum); + } + } + } + } + { + for (Long aLong : userIdList) { + userVoList.addAll(CollUtil.newArrayList(buildUser(aLong))); + } + } + return userVoList; + } }