package com.ruoyi.inspectiontask.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.basic.dto.StorageBlobDTO; import com.ruoyi.basic.mapper.StorageAttachmentMapper; import com.ruoyi.basic.mapper.StorageBlobMapper; import com.ruoyi.basic.pojo.StorageAttachment; import com.ruoyi.basic.pojo.StorageBlob; import com.ruoyi.basic.service.StorageAttachmentService; import com.ruoyi.common.enums.FileNameType; import com.ruoyi.common.utils.MinioUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.inspectiontask.dto.InspectionTaskDto; import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper; import com.ruoyi.inspectiontask.mapper.TimingTaskMapper; import com.ruoyi.inspectiontask.pojo.InspectionTask; import com.ruoyi.inspectiontask.pojo.TimingTask; import com.ruoyi.inspectiontask.service.InspectionTaskService; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.sales.mapper.CommonFileMapper; import com.ruoyi.sales.pojo.CommonFile; import com.ruoyi.sales.service.impl.CommonFileServiceImpl; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import static com.ruoyi.common.constant.StorageAttachmentConstants.StorageAttachmentFile; import static com.ruoyi.common.enums.StorageAttachmentRecordType.InspectionTasks; /** * @author :yys * @date : 2025/9/19 10:54 */ @Service @Slf4j public class InspectionTaskServiceImpl extends ServiceImpl implements InspectionTaskService { @Autowired private InspectionTaskMapper inspectionTaskMapper; @Autowired private StorageAttachmentService storageAttachmentService; @Autowired private StorageBlobMapper storageBlobMapper; @Autowired private StorageAttachmentMapper storageAttachmentMapper; @Autowired private MinioUtils minioUtils; @Autowired private SysUserMapper sysUserMapper; @Autowired private CommonFileMapper commonFileMapper; @Autowired private CommonFileServiceImpl commonFileService; @Autowired private TimingTaskMapper timingTaskMapper; @Override public IPage selectInspectionTaskList(Page page, InspectionTaskDto inspectionTaskDto) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByDesc(InspectionTask::getCreateTime); if (StringUtils.isNotBlank(inspectionTaskDto.getTaskName())) { queryWrapper.like(InspectionTask::getTaskName, inspectionTaskDto.getTaskName()); } IPage entityPage = inspectionTaskMapper.selectPage(page, queryWrapper); // 无数据提前返回 if (CollectionUtils.isEmpty(entityPage.getRecords())) { return new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal()); } // 获取id集合 List ids = entityPage.getRecords().stream().map(InspectionTask::getId).collect(Collectors.toList()); //登记人ids List registrantIds = entityPage.getRecords().stream().map(InspectionTask::getRegistrantId).collect(Collectors.toList()); // 批量查询登记人 Map sysUserMap; if (!registrantIds.isEmpty()) { List sysUsers = sysUserMapper.selectUsersByIds(registrantIds); sysUserMap = sysUsers.stream().collect(Collectors.toMap(SysUser::getUserId, Function.identity())); } else { sysUserMap = new HashMap<>(); } //巡检人ids List inspectorIds = entityPage.getRecords().stream().map(InspectionTask::getInspectorId).collect(Collectors.toList()); //获取所有不重复的用户ID Set allUserIds = entityPage.getRecords().stream() .map(InspectionTask::getInspectorId) // 获取"2,3"这样的字符串 .filter(StringUtils::isNotBlank) .flatMap(idsStr -> Arrays.stream(idsStr.split(","))) .map(idStr -> { try { return Long.parseLong(idStr.trim()); } catch (NumberFormatException e) { return null; } }) .filter(Objects::nonNull) .collect(Collectors.toSet()); // 使用SQL批量查询用户信息 Map userIdToNameMap = allUserIds.isEmpty() ? Collections.emptyMap() : sysUserMapper.selectUsersByIds(new ArrayList<>(allUserIds)) .stream() .collect(Collectors.toMap( SysUser::getUserId, SysUser::getNickName, (existing, replacement) -> existing)); //处理附件 List commonFiles = commonFileMapper.selectList(new LambdaQueryWrapper() .in(CommonFile::getCommonId, ids) .in(CommonFile::getType, Arrays.asList(FileNameType.INSPECTION.getValue(), FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue(), FileNameType.INSPECTION_PRODUCTION_AFTER.getValue()))); if(commonFiles == null){ commonFiles = new ArrayList<>(); } List finalCommonFiles = commonFiles; // 批量查询定时任务获取nextExecutionTime List timingTaskIds = entityPage.getRecords().stream() .map(InspectionTask::getTimingTaskId) .filter(Objects::nonNull) .collect(Collectors.toList()); Map timingTaskMap = new HashMap<>(); if (!timingTaskIds.isEmpty()) { List timingTasks = timingTaskMapper.selectBatchIds(timingTaskIds); timingTaskMap = timingTasks.stream() .collect(Collectors.toMap(TimingTask::getId, Function.identity())); } final Map finalTimingTaskMap = timingTaskMap; final LocalDateTime now = LocalDateTime.now(); List dtoList = entityPage.getRecords().stream().map(inspectionTask -> { InspectionTaskDto dto = new InspectionTaskDto(); BeanUtils.copyProperties(inspectionTask, dto); // 复制主对象属性 // 设置登记人 SysUser sysUser = sysUserMap.get(inspectionTask.getRegistrantId()); if (sysUser != null) { dto.setRegistrant(sysUser.getNickName()); } // 处理巡检人名称 if (StringUtils.isNotBlank(inspectionTask.getInspectorId())) { String inspectorNames = Arrays.stream(inspectionTask.getInspectorId().split(",")) .map(String::trim) .map(idStr -> { try { Long userId = Long.parseLong(idStr); return userIdToNameMap.getOrDefault(userId, "未知用户(" + idStr + ")"); } catch (NumberFormatException e) { return "无效ID(" + idStr + ")"; } }) .collect(Collectors.joining(",")); dto.setInspector(inspectorNames); } dto.setDateStr(inspectionTask.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); // 初始化三个附件列表,按commonId和type过滤 Long taskId = inspectionTask.getId(); dto.setCommonFileList(finalCommonFiles.stream() .filter(commonFile -> commonFile.getCommonId().equals(taskId) && commonFile.getType().equals(FileNameType.INSPECTION.getValue())) .collect(Collectors.toList())); dto.setCommonFileListAfter(finalCommonFiles.stream() .filter(commonFile -> commonFile.getCommonId().equals(taskId) && commonFile.getType().equals(FileNameType.INSPECTION_PRODUCTION_AFTER.getValue())) .collect(Collectors.toList())); dto.setCommonFileListBefore(finalCommonFiles.stream() .filter(commonFile -> commonFile.getCommonId().equals(taskId) && commonFile.getType().equals(FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue())) .collect(Collectors.toList())); // 计算状态:已过期 > 巡检中 > 待巡检 String status = calculateStatus(inspectionTask, finalTimingTaskMap, now); dto.setStatus(status); // 设置nextExecutionTime用于前端展示 if (inspectionTask.getTimingTaskId() != null) { TimingTask timingTask = finalTimingTaskMap.get(inspectionTask.getTimingTaskId()); if (timingTask != null) { dto.setNextExecutionTime(timingTask.getNextExecutionTime()); } } return dto; }).collect(Collectors.toList()); // 7. 构建返回分页对象 IPage resultPage = new Page<>(); BeanUtils.copyProperties(entityPage, resultPage); resultPage.setRecords(dtoList); return resultPage; } // 提取创建BlobDTO的公共方法 private StorageBlobDTO createBlobDto(StorageBlob blob) { StorageBlobDTO dto = new StorageBlobDTO(); BeanUtils.copyProperties(blob, dto); // 设置URL dto.setUrl(minioUtils.getPreviewUrls( blob.getBucketFilename(), blob.getBucketName(), true )); // 设置下载URL dto.setDownloadUrl(minioUtils.getDownloadUrls( blob.getBucketFilename(), blob.getBucketName(), blob.getOriginalFilename(), true )); return dto; } /** * 计算巡检任务状态 * 优先级:已完成巡检 > 巡检中(已过期) > 巡检中 > 已过期 > 待巡检 * @param inspectionTask 巡检任务 * @param timingTaskMap 定时任务Map * @param now 当前时间 * @return 状态:COMPLETED-已完成巡检,IN_PROGRESS_EXPIRED-巡检中(已过期),IN_PROGRESS-巡检中,EXPIRED-已过期,PENDING-待巡检 */ private String calculateStatus(InspectionTask inspectionTask, Map timingTaskMap, LocalDateTime now) { if(inspectionTask.getTimingTaskId() == null){ return "EXPIRED"; } boolean isExpired = false; // 判断是否已过期 if (inspectionTask.getTimingTaskId() != null) { TimingTask timingTask = timingTaskMap.get(inspectionTask.getTimingTaskId()); if (timingTask != null && timingTask.getNextExecutionTime() != null) { isExpired = now.isAfter(timingTask.getNextExecutionTime()); } } // 1. 判断是否已完成巡检(三个异常字段都不为null) if (inspectionTask.getHasExceptionBefore() != null && inspectionTask.getHasExceptionAfter() != null && inspectionTask.getHasExceptionIssue() != null) { return "COMPLETED"; } // 2. 判断是否巡检中(任一异常字段不为null) if (inspectionTask.getHasExceptionBefore() != null || inspectionTask.getHasExceptionAfter() != null || inspectionTask.getHasExceptionIssue() != null) { return isExpired ? "IN_PROGRESS_EXPIRED" : "IN_PROGRESS"; } // 3. 已过期 if (isExpired) { return "EXPIRED"; } // 4. 待巡检 return "PENDING"; } @Override @Transactional(rollbackFor = Exception.class) public int addOrEditInspectionTask(InspectionTaskDto inspectionTaskDto) throws IOException { InspectionTask inspectionTask = new InspectionTask(); BeanUtils.copyProperties(inspectionTaskDto, inspectionTask); inspectionTask.setRegistrantId(SecurityUtils.getLoginUser().getUserId()); inspectionTask.setRegistrant(SecurityUtils.getLoginUser().getUsername()); int i; if (Objects.isNull(inspectionTaskDto.getId())) { i = inspectionTaskMapper.insert(inspectionTask); } else { i = inspectionTaskMapper.updateById(inspectionTask); // 编辑时处理附件删除逻辑 handleFileDeletion(inspectionTask.getId(), inspectionTaskDto); } commonFileService.migrateTempFilesToFormal(inspectionTask.getId(),inspectionTaskDto.getTempFileIds()); return i; } /** * 处理附件删除逻辑:对比原有附件和传入的附件,删除被移除的附件 */ private void handleFileDeletion(Long taskId, InspectionTaskDto inspectionTaskDto) { // 查询原有的三种类型附件 List existingFiles = commonFileMapper.selectList(new LambdaQueryWrapper() .eq(CommonFile::getCommonId, taskId) .in(CommonFile::getType, Arrays.asList( FileNameType.INSPECTION.getValue(), FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue(), FileNameType.INSPECTION_PRODUCTION_AFTER.getValue()))); if (CollectionUtils.isEmpty(existingFiles)) { return; } // 获取前端传入的附件ID集合 Set submittedFileIds = new HashSet<>(); if (inspectionTaskDto.getCommonFileList() != null) { inspectionTaskDto.getCommonFileList().stream() .map(CommonFile::getId) .filter(Objects::nonNull) .forEach(submittedFileIds::add); } if (inspectionTaskDto.getCommonFileListBefore() != null) { inspectionTaskDto.getCommonFileListBefore().stream() .map(CommonFile::getId) .filter(Objects::nonNull) .forEach(submittedFileIds::add); } if (inspectionTaskDto.getCommonFileListAfter() != null) { inspectionTaskDto.getCommonFileListAfter().stream() .map(CommonFile::getId) .filter(Objects::nonNull) .forEach(submittedFileIds::add); } // 找出需要删除的附件ID(原有但前端没传的) List toDeleteIds = existingFiles.stream() .map(CommonFile::getId) .filter(id -> !submittedFileIds.contains(id)) .collect(Collectors.toList()); // 删除附件 if (!toDeleteIds.isEmpty()) { commonFileService.delCommonFileByIds(toDeleteIds.toArray(new Long[0])); } } @Override @Transactional(rollbackFor = Exception.class) public int delByIds(Long[] ids) { // 检查参数 if (ids == null || ids.length == 0) { return 0; } commonFileService.deleteByBusinessIds(Arrays.asList(ids),FileNameType.INSPECTION.getValue()); commonFileService.deleteByBusinessIds(Arrays.asList(ids),FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue()); commonFileService.deleteByBusinessIds(Arrays.asList(ids),FileNameType.INSPECTION_PRODUCTION_AFTER.getValue()); return inspectionTaskMapper.deleteBatchIds(Arrays.asList(ids)); } }