| | |
| | | package com.ycl.service.impl; |
| | | |
| | | |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; |
| | | import com.ycl.common.annotation.DataScope; |
| | | import com.ycl.common.base.Result; |
| | | import com.ycl.common.constant.ProcessOverTimeConstants; |
| | | import com.ycl.common.core.domain.BaseEntity; |
| | |
| | | import com.ycl.domain.entity.ProjectInfo; |
| | | import com.ycl.domain.entity.ProjectProcess; |
| | | import com.ycl.domain.form.ProjectProgressStatisticsForm; |
| | | import com.ycl.domain.query.WaitTodoQuery; |
| | | import com.ycl.domain.vo.*; |
| | | import com.ycl.factory.FlowServiceFactory; |
| | | import com.ycl.mapper.ProcessCodingMapper; |
| | | import com.ycl.mapper.ProcessLogMapper; |
| | | import com.ycl.mapper.ProjectInfoMapper; |
| | | import com.ycl.mapper.ProjectProcessMapper; |
| | | import com.ycl.service.IndexHomeService; |
| | | import com.ycl.service.ProjectProcessService; |
| | | import com.ycl.service.common.TaskCommonService; |
| | | import com.ycl.system.mapper.SysDeptMapper; |
| | | import com.ycl.system.service.ISysDeptService; |
| | | import com.ycl.system.service.ISysRoleService; |
| | |
| | | import org.flowable.engine.runtime.ProcessInstance; |
| | | import org.flowable.identitylink.api.IdentityLink; |
| | | import org.flowable.identitylink.api.IdentityLinkInfo; |
| | | import org.flowable.identitylink.api.IdentityLinkType; |
| | | import org.flowable.task.api.Task; |
| | | import org.flowable.task.api.TaskQuery; |
| | | import org.flowable.task.api.history.HistoricTaskInstance; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.CollectionUtils; |
| | |
| | | private final ISysDeptService sysDeptService; |
| | | |
| | | private final ISysRoleService sysRoleService; |
| | | |
| | | private final TaskCommonService taskCommonService; |
| | | |
| | | |
| | | @Override |
| | | public Result projectCodingStatusCount() { |
| | | //权限控制 |
| | | List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo(); |
| | | |
| | | |
| | | |
| | | |
| | | Map<String,Integer> map = new HashMap<>(); |
| | | map.put(ProcessOverTimeConstants.GREEN,0); |
| | |
| | | return Result.ok().data(map); |
| | | } |
| | | |
| | | @Override |
| | | public List<ProjectInfo> getLoginUserOwnProjectInfo(){ |
| | | //权限控制 |
| | | Long userId = SecurityUtils.getUserId(); |
| | |
| | | |
| | | return Result.ok().data(projectInfoAndFunding); |
| | | } |
| | | @Override |
| | | public int countWaitTask() { |
| | | Long userId = SecurityUtils.getUserId(); |
| | | List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo(); |
| | | if (CollectionUtils.isEmpty(loginUserOwnProjectInfo)) { |
| | | return 0; |
| | | } |
| | | List<Long> ids = loginUserOwnProjectInfo.stream() |
| | | .filter(Objects::nonNull) |
| | | .map(ProjectInfo::getId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(ids)) { |
| | | return 0; |
| | | } |
| | | List<ProjectProcess> projectProcessList = new LambdaQueryChainWrapper<>(projectProcessService.getBaseMapper()) |
| | | .eq(ProjectProcess::getDeleted, Boolean.FALSE) |
| | | .in(ProjectProcess::getProjectId, ids) |
| | | .list(); |
| | | if (CollectionUtils.isEmpty(projectProcessList)) { |
| | | return 0; |
| | | } |
| | | List<String> targetProcessInsIds = projectProcessList.stream() |
| | | .filter(Objects::nonNull) // 过滤null的ProjectProcess对象 |
| | | .map(ProjectProcess::getProcessInsId) |
| | | .filter(defId -> defId != null && !defId.trim().isEmpty()) // 先判null再trim,修复风险3 |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(targetProcessInsIds)) { |
| | | return 0; |
| | | } |
| | | |
| | | List<Task> allRunningTasks = taskService.createTaskQuery().active().list(); |
| | | if (CollectionUtils.isEmpty(allRunningTasks)) { |
| | | return 0; |
| | | } |
| | | List<Task> targetRunningTasks = allRunningTasks.stream() |
| | | .filter(Objects::nonNull) |
| | | .filter(task -> { |
| | | // 先判null,再匹配,修复风险1 |
| | | String processInsId = task.getProcessInstanceId(); |
| | | return processInsId != null && targetProcessInsIds.contains(processInsId); |
| | | }) |
| | | .filter(task -> { |
| | | String assignee = task.getAssignee(); |
| | | return assignee == null || userId.toString().equals(assignee);//排除领取人 |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | |
| | | |
| | | return targetRunningTasks.size(); |
| | | } |
| | | |
| | | @Override |
| | | public Result projectAdvanceCheckPoint() { |
| | |
| | | List<ProjectProcess> projectProcessList = new LambdaQueryChainWrapper<>(projectProcessService.getBaseMapper()) |
| | | .eq(ProjectProcess::getDeleted, Boolean.FALSE) |
| | | .in(ProjectProcess::getProjectId, ids).list(); |
| | | |
| | | Long userId = SecurityUtils.getUserId(); |
| | | //流程实例id集合 |
| | | List<String> targetProcessInsIds = projectProcessList.stream() |
| | | .map(ProjectProcess::getProcessInsId) |
| | |
| | | |
| | | |
| | | List<Task> allRunningTasks = taskService.createTaskQuery().active().list(); |
| | | |
| | | List<Task> targetRunningTasks = allRunningTasks.stream() |
| | | // 关键匹配:任务的流程定义ID 存在于 projectProcessList 的流程定义ID列表中 |
| | | .filter(task -> targetProcessInsIds.contains(task.getProcessInstanceId())) |
| | | .filter(task -> { |
| | | String assignee = task.getAssignee(); |
| | | log.info("assignee:{}",assignee); |
| | | return assignee == null || userId.toString().equals(assignee); |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | |
| | | |
| | | List<TaskInfoVo> list = new ArrayList<>(); |
| | | // 按流程实例id分组 |
| | |
| | | .eq(ProcessCoding::getDeleted, Boolean.FALSE) |
| | | .in(ProcessCoding::getTaskId, taskIds) |
| | | .list(); |
| | | log.info("processCodingList.size():{}", processCodingList.size()); // 看日志是否为0 |
| | | Map<String, ProcessCoding> processCodingMap = new HashMap<>(); |
| | | //按taskId转换为map方面下面获取 |
| | | if (!CollectionUtils.isEmpty(processCodingList)){ |
| | | Map<String, ProcessCoding> processCodingMap = processCodingList.stream() |
| | | processCodingMap = processCodingList.stream() |
| | | .filter(Objects::nonNull) // 避免null元素导致NPE(可选保留) |
| | | .filter(vo -> vo.getTaskId() != null) // 过滤taskId为null的无效数据 |
| | | .collect(Collectors.toMap( |
| | |
| | | return newCreateTime.getTime() > oldCreateTime.getTime() ? newVal : oldVal; |
| | | } |
| | | )); |
| | | } |
| | | for (Task task : targetRunningTasks) { |
| | | |
| | | for (Task task : targetRunningTasks) { |
| | | TaskInfoVo taskVo = new TaskInfoVo(); |
| | | |
| | | TaskInfoVo taskVo = new TaskInfoVo(); |
| | | |
| | | taskVo.setId(task.getId()); |
| | | taskVo.setTaskName(task.getName()); |
| | | taskVo.setStartTime(task.getCreateTime()); |
| | | taskVo.setEndTime(task.getDueDate()); |
| | | taskVo.setId(task.getId()); |
| | | taskVo.setTaskName(task.getName()); |
| | | taskVo.setStartTime(task.getCreateTime()); |
| | | taskVo.setEndTime(task.getDueDate()); |
| | | // taskVo.setTaskType(); |
| | | |
| | | List<Long> handlerIds = new ArrayList<>(2); |
| | | List<String> handlerNames = new ArrayList<>(2); |
| | | List<Long> handlerUnitIds = new ArrayList<>(2); |
| | | List<String> handlerUnitNames = new ArrayList<>(2); |
| | | List<String> promoterNames = new ArrayList<>(2); |
| | | List<String> promoterUnitNames = new ArrayList<>(2); |
| | | CustomerTaskVO customerTaskVO = new CustomerTaskVO(); |
| | | customerTaskVO.setHandlerId(handlerIds); |
| | | customerTaskVO.setHandlerName(handlerNames); |
| | | customerTaskVO.setHandlerUnitId(handlerUnitIds); |
| | | customerTaskVO.setHandlerUnitName(handlerUnitNames); |
| | | customerTaskVO.setPromoterName(promoterNames); |
| | | customerTaskVO.setPromoterUnitName(promoterUnitNames); |
| | | List<Long> handlerIds = new ArrayList<>(2); |
| | | List<String> handlerNames = new ArrayList<>(2); |
| | | List<Long> handlerUnitIds = new ArrayList<>(2); |
| | | List<String> handlerUnitNames = new ArrayList<>(2); |
| | | List<String> promoterNames = new ArrayList<>(2); |
| | | List<String> promoterUnitNames = new ArrayList<>(2); |
| | | CustomerTaskVO customerTaskVO = new CustomerTaskVO(); |
| | | customerTaskVO.setHandlerId(handlerIds); |
| | | customerTaskVO.setHandlerName(handlerNames); |
| | | customerTaskVO.setHandlerUnitId(handlerUnitIds); |
| | | customerTaskVO.setHandlerUnitName(handlerUnitNames); |
| | | customerTaskVO.setPromoterName(promoterNames); |
| | | customerTaskVO.setPromoterUnitName(promoterUnitNames); |
| | | |
| | | // 流程处理人信息 |
| | | List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(task.getId()); |
| | | for (IdentityLinkInfo identityLink : identityLinksForTask) { |
| | | // 绑定的是用户,查出用户姓名、部门 |
| | | if (StringUtils.isNotBlank(identityLink.getUserId())) { |
| | | // 处理变量表达式,运行中的任务无需再处理表达式了,flowable已经自动根据变量设置了 |
| | | customerTaskVO.setHandlerType(HandlerTypeEnum.USER); |
| | | SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId())); |
| | | if (Objects.nonNull(sysUser)) { |
| | | customerTaskVO.getHandlerId().add(sysUser.getUserId()); |
| | | customerTaskVO.getHandlerName().add(this.getUserShowName(sysUser)); |
| | | if (Objects.nonNull(sysUser.getDept())) { |
| | | customerTaskVO.getHandlerUnitId().add(sysUser.getDept().getDeptId()); |
| | | customerTaskVO.getHandlerUnitName().add(sysUser.getDept().getDeptName()); |
| | | customerTaskVO.getPromoterName().add(this.getUserShowName(sysUser)); |
| | | String[] str = sysUser.getDept().getAncestors().split(","); |
| | | if (str.length >= 4){ |
| | | customerTaskVO.getPromoterUnitName().add(sysUser.getDept().getParentName() +"-"+sysUser.getDept().getDeptName()); |
| | | }else { |
| | | customerTaskVO.getPromoterUnitName().add(sysUser.getDept().getDeptName()); |
| | | } |
| | | |
| | | // 流程处理人信息 |
| | | List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(task.getId()); |
| | | for (IdentityLinkInfo identityLink : identityLinksForTask) { |
| | | // 绑定的是用户,查出用户姓名、部门 |
| | | if (StringUtils.isNotBlank(identityLink.getUserId())) { |
| | | // 处理变量表达式,运行中的任务无需再处理表达式了,flowable已经自动根据变量设置了 |
| | | customerTaskVO.setHandlerType(HandlerTypeEnum.USER); |
| | | SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId())); |
| | | if (Objects.nonNull(sysUser)) { |
| | | customerTaskVO.getHandlerId().add(sysUser.getUserId()); |
| | | customerTaskVO.getHandlerName().add(this.getUserShowName(sysUser)); |
| | | if (Objects.nonNull(sysUser.getDept())) { |
| | | customerTaskVO.getHandlerUnitId().add(sysUser.getDept().getDeptId()); |
| | | customerTaskVO.getHandlerUnitName().add(sysUser.getDept().getDeptName()); |
| | | customerTaskVO.getPromoterName().add(this.getUserShowName(sysUser)); |
| | | String[] str = sysUser.getDept().getAncestors().split(","); |
| | | if (str.length >= 4){ |
| | | customerTaskVO.getPromoterUnitName().add(sysUser.getDept().getParentName() +"-"+sysUser.getDept().getDeptName()); |
| | | }else { |
| | | customerTaskVO.getPromoterUnitName().add(sysUser.getDept().getDeptName()); |
| | | } |
| | | } |
| | | // 绑定的是角色或者部门 |
| | | } else if (StringUtils.isNotBlank(identityLink.getGroupId())) { |
| | | if (identityLink.getGroupId().startsWith("dept")) { // 部门的id是加了前缀的如:dept:1 |
| | | customerTaskVO.setHandlerType(HandlerTypeEnum.DEPT); |
| | | String[] split = identityLink.getGroupId().split(":"); |
| | | if (split.length > 1) { |
| | | // 部门 |
| | | SysDept dept = sysDeptService.selectDeptById(Long.parseLong(split[1])); |
| | | if (Objects.nonNull(dept)) { |
| | | customerTaskVO.getHandlerUnitId().add(dept.getDeptId()); |
| | | customerTaskVO.getHandlerUnitName().add(dept.getDeptName()); |
| | | customerTaskVO.getPromoterName().add(this.getDeptLeaderShowName(dept)); |
| | | customerTaskVO.getPromoterUnitName().add(this.setDeptNameWithParentName(dept)); |
| | | } |
| | | } |
| | | } else { |
| | | customerTaskVO.setHandlerType(HandlerTypeEnum.ROLE); |
| | | SysRole role = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); |
| | | if (Objects.nonNull(role)) { |
| | | customerTaskVO.getHandlerUnitId().add(Long.parseLong(identityLink.getGroupId())); |
| | | customerTaskVO.getHandlerUnitName().add(role.getRoleName()); |
| | | } |
| | | } |
| | | } |
| | | this.distinctVo(customerTaskVO); |
| | | } |
| | | taskVo.setCustomerTaskInfo(customerTaskVO); |
| | | |
| | | //组装任务信息 |
| | | CheckPointVO checkPointVO = processInfoMap.get(task.getProcessInstanceId()); |
| | | if (checkPointVO != null) { |
| | | taskVo.setCheckPointInfo(checkPointVO); |
| | | } |
| | | //超时时间和次数在 processCodingList中 这里需要更具taskId来获得对应信息 |
| | | ProcessCoding processCoding = processCodingMap.get(task.getId()); |
| | | //设置超时信息 |
| | | if (processCoding != null) { |
| | | |
| | | String overTimeTotalStr = processCoding.getOverTimeTotal(); |
| | | long overTimeTotal = 0L; |
| | | if (StringUtils.isNotBlank(overTimeTotalStr)) { |
| | | try { |
| | | overTimeTotal = Long.parseLong(overTimeTotalStr.trim()); |
| | | } catch (NumberFormatException e) { |
| | | |
| | | } |
| | | } |
| | | String overTimeDesc = convertHoursToDayHourStr(overTimeTotal); |
| | | taskVo.setTotalOverTime(overTimeDesc); |
| | | |
| | | // 2. 提取红码阈值 如: 0-22 天-小时 并转换为小时 |
| | | String redTimeStr = processCoding.getRedTime(); |
| | | Long redTimeSec = getTime(redTimeStr); |
| | | Double redTimeHour = null; |
| | | if (redTimeSec != null && redTimeSec > 0) { |
| | | redTimeHour = redTimeSec / 3600.0; |
| | | // 绑定的是角色或者部门 |
| | | } else if (StringUtils.isNotBlank(identityLink.getGroupId())) { |
| | | if (identityLink.getGroupId().startsWith("dept")) { // 部门的id是加了前缀的如:dept:1 |
| | | customerTaskVO.setHandlerType(HandlerTypeEnum.DEPT); |
| | | String[] split = identityLink.getGroupId().split(":"); |
| | | if (split.length > 1) { |
| | | // 部门 |
| | | SysDept dept = sysDeptService.selectDeptById(Long.parseLong(split[1])); |
| | | if (Objects.nonNull(dept)) { |
| | | customerTaskVO.getHandlerUnitId().add(dept.getDeptId()); |
| | | customerTaskVO.getHandlerUnitName().add(dept.getDeptName()); |
| | | customerTaskVO.getPromoterName().add(this.getDeptLeaderShowName(dept)); |
| | | customerTaskVO.getPromoterUnitName().add(this.setDeptNameWithParentName(dept)); |
| | | } |
| | | } |
| | | } else { |
| | | customerTaskVO.setHandlerType(HandlerTypeEnum.ROLE); |
| | | SysRole role = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); |
| | | if (Objects.nonNull(role)) { |
| | | customerTaskVO.getHandlerUnitId().add(Long.parseLong(identityLink.getGroupId())); |
| | | customerTaskVO.getHandlerUnitName().add(role.getRoleName()); |
| | | } |
| | | } |
| | | long overTimeCount = 0L; |
| | | // 判断超时次数 |
| | | if (overTimeTotal > 0 && redTimeHour != null && redTimeHour > 0) { |
| | | overTimeCount = (long) (overTimeTotal / redTimeHour); |
| | | } |
| | | |
| | | |
| | | taskVo.setOverTimeCount(overTimeCount); |
| | | }else { |
| | | //为null 说明未配置超时时间 默认未超时 |
| | | taskVo.setOverTimeCount(0L); |
| | | taskVo.setTotalOverTime("0小时"); |
| | | } |
| | | list.add(taskVo); |
| | | this.distinctVo(customerTaskVO); |
| | | } |
| | | taskVo.setCustomerTaskInfo(customerTaskVO); |
| | | |
| | | //组装任务信息 |
| | | CheckPointVO checkPointVO = processInfoMap.get(task.getProcessInstanceId()); |
| | | if (checkPointVO != null) { |
| | | taskVo.setCheckPointInfo(checkPointVO); |
| | | } |
| | | //超时时间和次数在 processCodingList中 这里需要更具taskId来获得对应信息 |
| | | ProcessCoding processCoding = processCodingMap.get(task.getId()); |
| | | //设置超时信息 |
| | | if (processCoding != null) { |
| | | |
| | | String overTimeTotalStr = processCoding.getOverTimeTotal(); |
| | | long overTimeTotal = 0L; |
| | | if (StringUtils.isNotBlank(overTimeTotalStr)) { |
| | | try { |
| | | overTimeTotal = Long.parseLong(overTimeTotalStr.trim()); |
| | | } catch (NumberFormatException e) { |
| | | |
| | | } |
| | | } |
| | | String overTimeDesc = convertHoursToDayHourStr(overTimeTotal); |
| | | taskVo.setTotalOverTime(overTimeDesc); |
| | | |
| | | // 2. 提取红码阈值 如: 0-22 天-小时 并转换为小时 |
| | | String redTimeStr = processCoding.getRedTime(); |
| | | Long redTimeSec = getTime(redTimeStr); |
| | | Double redTimeHour = null; |
| | | if (redTimeSec != null && redTimeSec > 0) { |
| | | redTimeHour = redTimeSec / 3600.0; |
| | | } |
| | | long overTimeCount = 0L; |
| | | // 判断超时次数 |
| | | if (overTimeTotal > 0 && redTimeHour != null && redTimeHour > 0) { |
| | | overTimeCount = (long) (overTimeTotal / redTimeHour); |
| | | } |
| | | |
| | | |
| | | taskVo.setOverTimeCount(overTimeCount); |
| | | }else { |
| | | //为null 说明未配置超时时间 默认未超时 |
| | | taskVo.setOverTimeCount(0L); |
| | | taskVo.setTotalOverTime("0小时"); |
| | | } |
| | | list.add(taskVo); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | return Result.ok().data(list); |
| | | } |
| | | |
| | | public HashMap<String,Object> buildEmptyResultMap(){ |
| | | HashMap<String,Object> map = new HashMap<>(); |
| | | map.put("data", new ArrayList<>()); |
| | | map.put("total", 0L); |
| | | return map; |
| | | } |
| | | @Override |
| | | public Result getWaitTaskList(WaitTodoQuery baseQuery) { |
| | | int pageNum = (int) baseQuery.getCurrentPage(); |
| | | int pageSize = (int) baseQuery.getPageSize(); |
| | | Long userId = SecurityUtils.getUserId(); // 当前用户ID |
| | | boolean isAdmin = SecurityUtils.getLoginUser().getUser().isAdmin(); // 是否管理员 |
| | | List<String> userGroups = taskCommonService.getCurrentUserGroups(); // 当前用户所属组 |
| | | List<ProjectInfo> targetProjectList = new ArrayList<>(); |
| | | String queryProjectId = baseQuery.getProjectId(); |
| | | |
| | | if ("all".equals(queryProjectId) || StringUtils.isBlank(queryProjectId)){ |
| | | // 查询全部 |
| | | targetProjectList = getLoginUserOwnProjectInfo(); |
| | | }else{ |
| | | try { |
| | | Long projectId = Long.parseLong(queryProjectId); |
| | | // ① 查询该项目基础信息(替换为实际查询方法) |
| | | ProjectInfo projectInfo = projectInfoMapper.selectById(projectId); |
| | | if (projectInfo == null) { |
| | | // 项目不存在,返回空数据 |
| | | return Result.ok().data(buildEmptyResultMap()); |
| | | } |
| | | targetProjectList.add(projectInfo); |
| | | } catch (NumberFormatException e) { |
| | | // 项目ID格式错误,返回空数据 |
| | | return Result.ok().data(buildEmptyResultMap()); |
| | | } |
| | | } |
| | | |
| | | List<Long> projectIds = targetProjectList.stream().map(ProjectInfo::getId).collect(Collectors.toList()); |
| | | |
| | | List<ProjectProcess> projectProcessList = new LambdaQueryChainWrapper<>(projectProcessService.getBaseMapper()) |
| | | .eq(ProjectProcess::getDeleted, Boolean.FALSE) |
| | | .in(ProjectProcess::getProjectId, projectIds).list(); |
| | | // 4. 提取有效的流程实例ID(去重+非空过滤) |
| | | List<String> targetProcessInsIds = projectProcessList.stream() |
| | | .map(ProjectProcess::getProcessInsId) |
| | | .distinct() |
| | | .filter(defId -> defId != null && !defId.trim().isEmpty()) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (CollectionUtils.isEmpty(targetProcessInsIds)) { |
| | | return Result.ok().data(new HashMap<String, Object>() {{ |
| | | put("data", new ArrayList<>()); |
| | | put("total", 0L); |
| | | }}); |
| | | } |
| | | |
| | | // 5. 构建processInfoMap(核心:项目ID→CheckPointVO,再关联流程信息) |
| | | Map<String, CheckPointVO> map = new HashMap<>(); |
| | | // 先填充项目基础信息 |
| | | for (ProjectInfo projectInfo : targetProjectList) { |
| | | CheckPointVO checkPointVO = new CheckPointVO(); |
| | | checkPointVO.setId(projectInfo.getId()); |
| | | checkPointVO.setProjectName(projectInfo.getProjectName()); |
| | | map.put(String.valueOf(projectInfo.getId()), checkPointVO); |
| | | } |
| | | // 再填充流程信息(部署ID、流程名称等) |
| | | for (ProjectProcess projectProcess : projectProcessList) { |
| | | CheckPointVO checkPointVO = map.get(projectProcess.getProjectId().toString()); // 修复:projectId是Long,需转字符串 |
| | | if (checkPointVO == null) { |
| | | continue; // 无匹配项目,跳过 |
| | | } |
| | | checkPointVO.setProcessDefinitionId(projectProcess.getProcessDefId()); |
| | | checkPointVO.setProcessInstanceId(projectProcess.getProcessInsId()); |
| | | |
| | | // 获得流程部署id和流程名称(兼容运行中/已结束流程) |
| | | ProcessInstance process = runtimeService.createProcessInstanceQuery() |
| | | .processInstanceId(projectProcess.getProcessInsId()).singleResult(); |
| | | if (Objects.nonNull(process)) { |
| | | checkPointVO.setDeployId(process.getDeploymentId()); |
| | | checkPointVO.setProcessName(process.getProcessDefinitionName()); |
| | | } else { |
| | | HistoricProcessInstance hisProcess = historyService.createHistoricProcessInstanceQuery() |
| | | .processInstanceId(projectProcess.getProcessInsId()).singleResult(); |
| | | if (Objects.nonNull(hisProcess)) { // 避免历史流程为null的NPE |
| | | checkPointVO.setDeployId(hisProcess.getDeploymentId()); |
| | | checkPointVO.setProcessName(hisProcess.getProcessDefinitionName()); |
| | | } |
| | | } |
| | | map.put(projectProcess.getProjectId().toString(), checkPointVO); // 修复:projectId转字符串 |
| | | } |
| | | Map<String, CheckPointVO> processInfoMap = map.values().stream() |
| | | .filter(Objects::nonNull) |
| | | .filter(vo -> vo.getProcessInstanceId() != null) |
| | | .collect(Collectors.toMap( |
| | | CheckPointVO::getProcessInstanceId, |
| | | vo -> vo, |
| | | (oldVal, newVal) -> newVal // 重复流程实例ID保留后者 |
| | | )); |
| | | |
| | | TaskQuery query = getTaskService().createTaskQuery() |
| | | .active() // 未完成、未挂起的活跃任务 |
| | | .processInstanceIdIn(targetProcessInsIds); // 仅查项目关联的流程实例任务 |
| | | |
| | | // 权限过滤:非管理员仅查自己有权限的任务(已领取+候选) |
| | | if (!isAdmin) { |
| | | query.or() |
| | | .taskAssignee(userId+"") // 自己已领取的任务 |
| | | .taskCandidateUser(userId+"") // 自己是候选用户的任务 |
| | | .taskCandidateGroupIn(userGroups) // 自己在候选组的任务 |
| | | .endOr(); |
| | | } |
| | | |
| | | query.orderByTaskCreateTime().desc(); |
| | | List<Task> allTaskList = query.list(); |
| | | // 排除领取人问题 |
| | | allTaskList = allTaskList.stream() |
| | | .filter(Objects::nonNull) // 空任务防护 |
| | | .filter(task -> { |
| | | String assignee = task.getAssignee(); |
| | | return assignee == null || userId.toString().equals(assignee); |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | // 任务去重 |
| | | Set<String> taskIdSet = new HashSet<>(); |
| | | List<Task> distinctAllTaskList = new ArrayList<>(); |
| | | for (Task task : allTaskList) { |
| | | if (!taskIdSet.contains(task.getId())) { |
| | | taskIdSet.add(task.getId()); |
| | | distinctAllTaskList.add(task); |
| | | } |
| | | } |
| | | |
| | | // ========== 修复点1:提前查询任务状态,过滤已完成任务(分页前执行) ========== |
| | | // 查询任务状态 |
| | | final HashMap<String, ProcessLog> taskInfoMap = new HashMap<>(); |
| | | |
| | | List<String> allTaskIds = distinctAllTaskList.stream().map(Task::getId).collect(Collectors.toList()); |
| | | if (!CollectionUtils.isEmpty(allTaskIds)) { |
| | | // 2. 不再重新赋值,而是先查询出结果,再放入已初始化的map中 |
| | | List<ProcessLog> processLogs = new LambdaQueryChainWrapper<>(processLogMapper) |
| | | .eq(ProcessLog::getDeleted, Boolean.FALSE) |
| | | .in(ProcessLog::getTaskId, allTaskIds) |
| | | .list(); |
| | | |
| | | // 3. 填充数据到taskInfoMap,引用未改变 |
| | | Map<String, ProcessLog> tempMap = processLogs.stream() |
| | | .filter(processLog -> processLog.getTaskId() != null && processLog.getGmtCreate() != null) |
| | | .collect(Collectors.toMap( |
| | | ProcessLog::getTaskId, |
| | | processLog -> processLog, |
| | | (existing, replacement) -> replacement.getGmtCreate().after(existing.getGmtCreate()) ? replacement : existing, |
| | | HashMap::new |
| | | )); |
| | | taskInfoMap.putAll(tempMap); |
| | | } |
| | | |
| | | // 过滤已完成任务,得到有效任务列表(分页的依据) |
| | | List<Task> validTaskList = distinctAllTaskList.stream() |
| | | .filter(task -> { |
| | | ProcessLog processLog = taskInfoMap.get(task.getId()); |
| | | // 未查询到日志 → 待完成;日志状态不是FINISHED → 有效 |
| | | return processLog == null || !ProcessLogEventTypeEnum.FINISHED.getDesc().equals(processLog.getEventType().getDesc()); |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 有效数据总条数 |
| | | long validTotal = validTaskList.size(); |
| | | System.out.println("有效任务总数(排除已完成):" + validTotal); |
| | | |
| | | // ========== 修复点2:分页合法性校验 ========== |
| | | // 计算最大有效页码 |
| | | int maxPageNum = (int) (validTotal % pageSize == 0 ? validTotal / pageSize : (validTotal / pageSize) + 1); |
| | | // 若总条数为0,直接返回空数据 |
| | | if (validTotal == 0) { |
| | | return Result.ok().data(new HashMap<String, Object>() {{ |
| | | put("data", new ArrayList<>()); |
| | | put("total", 0L); |
| | | }}); |
| | | } |
| | | // 若请求页码超过最大页码,默认返回最后一页 |
| | | if (pageNum > maxPageNum) { |
| | | pageNum = maxPageNum; |
| | | } |
| | | |
| | | // ========== 修复点3:优化内存分页 ========== |
| | | int startIndex = (pageNum - 1) * pageSize; |
| | | int endIndex = Math.min(startIndex + pageSize, validTaskList.size()); |
| | | // 转为新列表,避免subList视图的风险 |
| | | List<Task> pageTaskList = new ArrayList<>(validTaskList.subList(startIndex, endIndex)); |
| | | |
| | | // 组装返回VO |
| | | List<TaskInfoVo> taskInfoVoList = new ArrayList<>(); |
| | | for (Task task : pageTaskList) { |
| | | TaskInfoVo taskVo = new TaskInfoVo(); |
| | | taskVo.setId(task.getId()); |
| | | taskVo.setTaskName(task.getName()); |
| | | taskVo.setStartTime(task.getCreateTime()); |
| | | taskVo.setEndTime(task.getDueDate()); |
| | | // 填充任务状态字段 |
| | | taskVo.setTaskType("待完成"); |
| | | ProcessLog processLog = taskInfoMap.get(task.getId()); |
| | | if (Objects.nonNull(processLog)) { |
| | | taskVo.setTaskType(processLog.getEventType().getDesc()); |
| | | } |
| | | |
| | | CheckPointVO checkPointVO = processInfoMap.get(task.getProcessInstanceId()); |
| | | if (checkPointVO != null) { |
| | | taskVo.setCheckPointInfo(checkPointVO); |
| | | } |
| | | |
| | | taskInfoVoList.add(taskVo); |
| | | } |
| | | return Result.ok().data(taskInfoVoList).total(validTotal); |
| | | } |
| | | |
| | | |
| | | |
| | | private String convertHoursToDayHourStr(long totalHours) { |
| | | if (totalHours < 0) { |
| | | return "0小时"; // 防御性处理负数场景 |
| | |
| | | } |
| | | |
| | | @Override |
| | | public Result getProjectList(){ |
| | | List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo(); |
| | | return Result.ok().data(loginUserOwnProjectInfo); |
| | | } |
| | | |
| | | @Override |
| | | public Result getProjectSelectList() { |
| | | List<ProjectInfo> loginUserOwnProjectInfo = getLoginUserOwnProjectInfo(); |
| | | if (CollectionUtils.isEmpty(loginUserOwnProjectInfo)) { |
| | | return Result.ok().data(loginUserOwnProjectInfo); |
| | | } |
| | | |
| | | Map<String, String> projectMap = loginUserOwnProjectInfo.stream() |
| | | .collect(Collectors.toMap( |
| | | projectInfo -> String.valueOf(projectInfo.getId()), // key: 项目ID |
| | |
| | | )); |
| | | return Result.ok().data(projectMap); |
| | | } |
| | | |
| | | |
| | | } |