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.common.enums.FileNameType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.device.mapper.DeviceAreaMapper; import com.ruoyi.device.mapper.DeviceLedgerMapper; import com.ruoyi.device.mapper.DeviceRepairMapper; import com.ruoyi.device.pojo.DeviceArea; import com.ruoyi.device.pojo.DeviceLedger; import com.ruoyi.device.pojo.DeviceRepair; import com.ruoyi.inspectiontask.dto.InspectionTaskDto; import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper; import com.ruoyi.inspectiontask.pojo.InspectionTask; 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.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; /** * @author :yys * @date : 2025/9/19 10:54 */ @Service @Slf4j public class InspectionTaskServiceImpl extends ServiceImpl implements InspectionTaskService { private static final int INSPECTION_STATUS_PENDING = 1; private static final int INSPECTION_STATUS_COMPLETED = 2; private static final int INSPECTION_RESULT_NORMAL = 1; private static final int INSPECTION_RESULT_ABNORMAL = 2; private static final int DEVICE_REPAIR_STATUS_PENDING = 0; private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); @Autowired private InspectionTaskMapper inspectionTaskMapper; @Autowired private SysUserMapper sysUserMapper; @Autowired private CommonFileMapper commonFileMapper; @Autowired private CommonFileServiceImpl commonFileService; @Autowired private DeviceLedgerMapper deviceLedgerMapper; @Autowired private DeviceAreaMapper deviceAreaMapper; @Autowired private DeviceRepairMapper deviceRepairMapper; @Override public IPage selectInspectionTaskList(Page page, InspectionTaskDto inspectionTaskDto) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.orderByAsc(InspectionTask::getTimingId); queryWrapper.orderByDesc(InspectionTask::getCreateTime); if (StringUtils.isNotBlank(inspectionTaskDto.getTaskName())) { queryWrapper.like(InspectionTask::getTaskName, inspectionTaskDto.getTaskName()); } if (inspectionTaskDto.getAreaId() != null) { queryWrapper.eq(InspectionTask::getAreaId, inspectionTaskDto.getAreaId()); } LocalDateTime createTimeStart = inspectionTaskDto.getCreateTimeStart(); LocalDateTime createTimeEnd = inspectionTaskDto.getCreateTimeEnd(); if (createTimeStart == null && createTimeEnd == null) { LocalDate today = LocalDate.now(); createTimeStart = today.atStartOfDay(); createTimeEnd = today.atTime(23, 59, 59); } if (createTimeStart != null) { queryWrapper.ge(InspectionTask::getCreateTime, createTimeStart); } if (createTimeEnd != null) { queryWrapper.le(InspectionTask::getCreateTime, createTimeEnd); } List inspectionTasks = inspectionTaskMapper.selectList(queryWrapper); if (CollectionUtils.isEmpty(inspectionTasks)) { return new Page<>(page.getCurrent(), page.getSize(), 0); } List mergedRecords = mergeInspectionTasksByTimingId(inspectionTasks); return buildPagedResult(page, mergedRecords); } @Override public List selectInspectionTaskRecordListByTimingId(Long timingId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); LocalDate today = LocalDate.now(); queryWrapper.eq(InspectionTask::getTimingId, timingId); queryWrapper.ge(InspectionTask::getCreateTime, today.atStartOfDay()); queryWrapper.le(InspectionTask::getCreateTime, today.atTime(23, 59, 59)); queryWrapper.orderByDesc(InspectionTask::getCreateTime); queryWrapper.orderByDesc(InspectionTask::getId); List records = inspectionTaskMapper.selectList(queryWrapper); if (CollectionUtils.isEmpty(records)) { return new ArrayList<>(); } return buildInspectionTaskDtoList(records); } @Override @Transactional(rollbackFor = Exception.class) public int addOrEditInspectionTask(List inspectionTaskDtoList) throws IOException { if (CollectionUtils.isEmpty(inspectionTaskDtoList)) { return 0; } int affected = 0; // 同一次提交里同一区域只保留一条异常记录,用于后续生成一张维修单。 Map abnormalAreaTaskMap = new LinkedHashMap<>(); for (InspectionTaskDto inspectionTaskDto : inspectionTaskDtoList) { if (inspectionTaskDto == null) { continue; } InspectionTask savedTask = saveOrUpdateInspectionTask(inspectionTaskDto); affected++; if (Objects.equals(savedTask.getInspectionResult(), INSPECTION_RESULT_ABNORMAL) && savedTask.getAreaId() != null) { abnormalAreaTaskMap.putIfAbsent(savedTask.getAreaId(), copyRepairSourceTask(inspectionTaskDto, savedTask)); } } createDeviceRepairRecords(abnormalAreaTaskMap); return affected; } private InspectionTask saveOrUpdateInspectionTask(InspectionTaskDto inspectionTaskDto) throws IOException { InspectionTask inspectionTask = new InspectionTask(); BeanUtils.copyProperties(inspectionTaskDto, inspectionTask); boolean hasUploadedFiles = CollectionUtils.isNotEmpty(inspectionTaskDto.getTempFileIds()); if (inspectionTask.getAreaId() == null && inspectionTask.getTaskId() != null) { DeviceLedger deviceLedger = deviceLedgerMapper.selectById(Long.valueOf(inspectionTask.getTaskId())); if (deviceLedger != null) { inspectionTask.setAreaId(deviceLedger.getAreaId()); } } inspectionTask.setRegistrantId(SecurityUtils.getLoginUser().getUserId()); inspectionTask.setRegistrant(SecurityUtils.getLoginUser().getUsername()); if (inspectionTaskDto.getId() == null) { inspectionTask.setInspectionStatus(hasUploadedFiles ? INSPECTION_STATUS_COMPLETED : INSPECTION_STATUS_PENDING); inspectionTaskMapper.insert(inspectionTask); } else { if (hasUploadedFiles) { inspectionTask.setInspectionStatus(INSPECTION_STATUS_COMPLETED); } else if (inspectionTask.getInspectionStatus() == null) { InspectionTask existingTask = inspectionTaskMapper.selectById(inspectionTaskDto.getId()); if (existingTask != null) { inspectionTask.setInspectionStatus(existingTask.getInspectionStatus()); } } inspectionTaskMapper.updateById(inspectionTask); } commonFileService.migrateTempFilesToFormal(inspectionTask.getId(), inspectionTaskDto.getTempFileIds()); return inspectionTask; } private InspectionTaskDto copyRepairSourceTask(InspectionTaskDto sourceDto, InspectionTask savedTask) { InspectionTaskDto taskDto = new InspectionTaskDto(); BeanUtils.copyProperties(sourceDto, taskDto); taskDto.setId(savedTask.getId()); taskDto.setAreaId(savedTask.getAreaId()); taskDto.setTaskId(savedTask.getTaskId()); taskDto.setTaskName(savedTask.getTaskName()); taskDto.setRemarks(savedTask.getRemarks()); taskDto.setInspectionLocation(savedTask.getInspectionLocation()); return taskDto; } private void createDeviceRepairRecords(Map abnormalAreaTaskMap) { if (abnormalAreaTaskMap.isEmpty()) { return; } LocalDate today = LocalDate.now(); LocalDateTime startOfDay = today.atStartOfDay(); LocalDateTime endOfDay = today.atTime(23, 59, 59); for (Map.Entry entry : abnormalAreaTaskMap.entrySet()) { Long areaId = entry.getKey(); InspectionTaskDto inspectionTaskDto = entry.getValue(); // 当天该区域已经有待维修单时直接跳过,避免重复生成。 Long count = deviceRepairMapper.selectCount(new LambdaQueryWrapper() .eq(DeviceRepair::getAreaId, areaId) .eq(DeviceRepair::getStatus, DEVICE_REPAIR_STATUS_PENDING) .ge(DeviceRepair::getCreateTime, startOfDay) .le(DeviceRepair::getCreateTime, endOfDay)); if (count != null && count > 0) { continue; } DeviceRepair deviceRepair = new DeviceRepair(); deviceRepair.setAreaId(areaId); if (inspectionTaskDto.getTaskId() != null) { deviceRepair.setDeviceLedgerId(Long.valueOf(inspectionTaskDto.getTaskId())); } deviceRepair.setRepairName(SecurityUtils.getLoginUser().getUsername()); deviceRepair.setRepairTime(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())); deviceRepair.setStatus(DEVICE_REPAIR_STATUS_PENDING); deviceRepair.setRemark(buildRepairRemark(inspectionTaskDto)); deviceRepairMapper.insert(deviceRepair); } } private String buildRepairRemark(InspectionTaskDto inspectionTaskDto) { List parts = new ArrayList<>(); if (StringUtils.isNotBlank(inspectionTaskDto.getTaskName())) { parts.add("巡检任务:" + inspectionTaskDto.getTaskName()); } if (StringUtils.isNotBlank(inspectionTaskDto.getInspectionLocation())) { parts.add("巡检地点:" + inspectionTaskDto.getInspectionLocation()); } if (StringUtils.isNotBlank(inspectionTaskDto.getRemarks())) { parts.add("异常说明:" + inspectionTaskDto.getRemarks()); } else { parts.add("异常说明:巡检异常自动生成维修单"); } return String.join(";", parts); } private IPage buildPagedResult(Page page, List mergedRecords) { long requestedSize = page.getSize(); long size = requestedSize <= 0 ? mergedRecords.size() : requestedSize; long current = page.getCurrent() <= 0 ? 1 : page.getCurrent(); int fromIndex = (int) Math.min((current - 1) * size, mergedRecords.size()); int toIndex = (int) Math.min(fromIndex + size, mergedRecords.size()); Page resultPage = new Page<>(current, size, mergedRecords.size()); resultPage.setRecords(mergedRecords.subList(fromIndex, toIndex)); return resultPage; } private List mergeInspectionTasksByTimingId(List inspectionTasks) { Map areaNameMap = buildAreaNameMap(inspectionTasks.stream() .map(InspectionTask::getAreaId) .filter(Objects::nonNull) .collect(Collectors.toSet())); Map registrantMap = buildRegistrantMap(inspectionTasks); Map inspectorNameMap = buildInspectorNameMap(inspectionTasks); Map> commonFileMap = buildCommonFileMap(inspectionTasks); Map> groupedTasks = inspectionTasks.stream() .collect(Collectors.groupingBy(this::buildTimingGroupKey, LinkedHashMap::new, Collectors.toList())); // 列表接口按 timingId 聚合,同一个定时任务只返回一条。 return groupedTasks.values().stream() .map(tasks -> buildMergedInspectionTaskDto(tasks, areaNameMap, registrantMap, inspectorNameMap, commonFileMap)) .sorted(Comparator.comparing(InspectionTaskDto::getTimingId, Comparator.nullsLast(Long::compareTo)) .thenComparing(InspectionTaskDto::getCreateTime, Comparator.nullsLast(Comparator.reverseOrder()))) .collect(Collectors.toList()); } private List buildInspectionTaskDtoList(List records) { Map areaNameMap = buildAreaNameMap(records.stream() .map(InspectionTask::getAreaId) .filter(Objects::nonNull) .collect(Collectors.toSet())); Map registrantMap = buildRegistrantMap(records); Map inspectorNameMap = buildInspectorNameMap(records); Map> commonFileMap = buildCommonFileMap(records); return records.stream() .map(task -> buildInspectionTaskDto(task, areaNameMap, registrantMap, inspectorNameMap, commonFileMap)) .collect(Collectors.toList()); } private Map buildRegistrantMap(List tasks) { List registrantIds = tasks.stream() .map(InspectionTask::getRegistrantId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); if (registrantIds.isEmpty()) { return new HashMap<>(); } return sysUserMapper.selectUsersByIds(registrantIds).stream() .collect(Collectors.toMap(SysUser::getUserId, Function.identity())); } private Map buildInspectorNameMap(List tasks) { Set allUserIds = tasks.stream() .map(InspectionTask::getInspectorId) .filter(StringUtils::isNotBlank) .flatMap(idsStr -> Arrays.stream(idsStr.split(","))) .map(String::trim) .map(this::parseLongSafely) .filter(Objects::nonNull) .collect(Collectors.toSet()); if (allUserIds.isEmpty()) { return Collections.emptyMap(); } return sysUserMapper.selectUsersByIds(new ArrayList<>(allUserIds)).stream() .collect(Collectors.toMap(SysUser::getUserId, SysUser::getNickName, (left, right) -> left)); } private Map> buildCommonFileMap(List tasks) { List ids = tasks.stream() .map(InspectionTask::getId) .filter(Objects::nonNull) .collect(Collectors.toList()); if (ids.isEmpty()) { return Collections.emptyMap(); } 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.isEmpty()) { return Collections.emptyMap(); } return commonFiles.stream().collect(Collectors.groupingBy(CommonFile::getCommonId)); } private String buildTimingGroupKey(InspectionTask inspectionTask) { return inspectionTask.getTimingId() != null ? "TIMING_" + inspectionTask.getTimingId() : "TASK_" + inspectionTask.getId(); } private InspectionTaskDto buildMergedInspectionTaskDto(List tasks, Map areaNameMap, Map registrantMap, Map inspectorNameMap, Map> commonFileMap) { List sortedTasks = tasks.stream() .sorted(Comparator.comparing(InspectionTask::getCreateTime, Comparator.nullsLast(Comparator.reverseOrder())) .thenComparing(InspectionTask::getId, Comparator.nullsLast(Comparator.reverseOrder()))) .collect(Collectors.toList()); InspectionTask latestTask = sortedTasks.get(0); InspectionTaskDto dto = new InspectionTaskDto(); BeanUtils.copyProperties(latestTask, dto); dto.setAreaName(areaNameMap.get(latestTask.getAreaId())); dto.setTaskName(joinDistinctValues(sortedTasks.stream().map(InspectionTask::getTaskName).collect(Collectors.toList()))); dto.setInspectorId(joinDistinctValues(sortedTasks.stream() .map(InspectionTask::getInspectorId) .filter(StringUtils::isNotBlank) .flatMap(idsStr -> Arrays.stream(idsStr.split(","))) .map(String::trim) .collect(Collectors.toList()))); dto.setInspector(joinDistinctValues(sortedTasks.stream() .map(InspectionTask::getInspectorId) .filter(StringUtils::isNotBlank) .flatMap(idsStr -> Arrays.stream(idsStr.split(","))) .map(String::trim) .map(idStr -> resolveInspectorName(idStr, inspectorNameMap)) .collect(Collectors.toList()))); dto.setRegistrant(joinDistinctValues(sortedTasks.stream() .map(InspectionTask::getRegistrantId) .filter(Objects::nonNull) .map(registrantMap::get) .filter(Objects::nonNull) .map(SysUser::getNickName) .collect(Collectors.toList()))); dto.setRemarks(joinDistinctValues(sortedTasks.stream().map(InspectionTask::getRemarks).collect(Collectors.toList()))); dto.setInspectionLocation(joinDistinctValues(sortedTasks.stream().map(InspectionTask::getInspectionLocation).collect(Collectors.toList()))); dto.setFrequencyType(joinDistinctValues(sortedTasks.stream().map(InspectionTask::getFrequencyType).collect(Collectors.toList()))); dto.setFrequencyDetail(joinDistinctValues(sortedTasks.stream().map(InspectionTask::getFrequencyDetail).collect(Collectors.toList()))); dto.setInspectionStatus(sortedTasks.stream().allMatch(task -> Objects.equals(task.getInspectionStatus(), INSPECTION_STATUS_COMPLETED)) ? INSPECTION_STATUS_COMPLETED : INSPECTION_STATUS_PENDING); List inspectionResults = sortedTasks.stream() .map(InspectionTask::getInspectionResult) .filter(Objects::nonNull) .collect(Collectors.toList()); if (inspectionResults.isEmpty()) { dto.setInspectionResult(null); } else { dto.setInspectionResult(inspectionResults.stream().anyMatch(result -> Objects.equals(result, INSPECTION_RESULT_ABNORMAL)) ? INSPECTION_RESULT_ABNORMAL : INSPECTION_RESULT_NORMAL); } if (dto.getCreateTime() != null) { dto.setDateStr(dto.getCreateTime().format(DATE_FORMATTER)); } List mergedFiles = sortedTasks.stream() .map(InspectionTask::getId) .filter(Objects::nonNull) .map(commonFileMap::get) .filter(Objects::nonNull) .flatMap(List::stream) .collect(Collectors.toList()); dto.setCommonFileList(filterCommonFilesByType(mergedFiles, FileNameType.INSPECTION.getValue())); dto.setCommonFileListBefore(filterCommonFilesByType(mergedFiles, FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue())); dto.setCommonFileListAfter(filterCommonFilesByType(mergedFiles, FileNameType.INSPECTION_PRODUCTION_AFTER.getValue())); return dto; } private InspectionTaskDto buildInspectionTaskDto(InspectionTask task, Map areaNameMap, Map registrantMap, Map inspectorNameMap, Map> commonFileMap) { InspectionTaskDto dto = new InspectionTaskDto(); BeanUtils.copyProperties(task, dto); dto.setAreaName(areaNameMap.get(task.getAreaId())); SysUser registrant = registrantMap.get(task.getRegistrantId()); if (registrant != null) { dto.setRegistrant(registrant.getNickName()); } if (StringUtils.isNotBlank(task.getInspectorId())) { dto.setInspector(Arrays.stream(task.getInspectorId().split(",")) .map(String::trim) .map(idStr -> resolveInspectorName(idStr, inspectorNameMap)) .collect(Collectors.joining(","))); } if (task.getCreateTime() != null) { dto.setDateStr(task.getCreateTime().format(DATE_FORMATTER)); } List commonFiles = commonFileMap.getOrDefault(task.getId(), Collections.emptyList()); dto.setCommonFileList(filterCommonFilesByType(commonFiles, FileNameType.INSPECTION.getValue())); dto.setCommonFileListBefore(filterCommonFilesByType(commonFiles, FileNameType.INSPECTION_PRODUCTION_BEFORE.getValue())); dto.setCommonFileListAfter(filterCommonFilesByType(commonFiles, FileNameType.INSPECTION_PRODUCTION_AFTER.getValue())); return dto; } private Long parseLongSafely(String value) { try { return Long.parseLong(value); } catch (NumberFormatException e) { return null; } } private String resolveInspectorName(String idStr, Map inspectorNameMap) { Long userId = parseLongSafely(idStr); if (userId == null) { return "无效ID(" + idStr + ")"; } return inspectorNameMap.getOrDefault(userId, "未知用户(" + idStr + ")"); } private String joinDistinctValues(List values) { return values.stream() .filter(StringUtils::isNotBlank) .map(String::trim) .distinct() .collect(Collectors.joining(",")); } private List filterCommonFilesByType(List commonFiles, Integer type) { return commonFiles.stream() .filter(commonFile -> Objects.equals(commonFile.getType(), type)) .collect(Collectors.toList()); } private Map buildAreaNameMap(Set areaIds) { if (areaIds == null || areaIds.isEmpty()) { return Collections.emptyMap(); } return deviceAreaMapper.selectBatchIds(new ArrayList<>(areaIds)).stream() .collect(Collectors.toMap(DeviceArea::getId, DeviceArea::getAreaName, (left, right) -> left)); } @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)); } }