diff --git a/inspect-job/src/main/java/com/inspect/job/client/ReportArchiveClient.java b/inspect-job/src/main/java/com/inspect/job/client/ReportArchiveClient.java new file mode 100644 index 0000000..76758bc --- /dev/null +++ b/inspect-job/src/main/java/com/inspect/job/client/ReportArchiveClient.java @@ -0,0 +1,26 @@ +package com.inspect.job.client; + +import com.inspect.base.core.web.domain.AjaxResult; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * 巡检报告定时归档客户端(调用 inspect-main 的动环归档按时间窗口接口)。 + * + * @author inspect + */ +@FeignClient(name = "inspect-main", contextId = "inspect-report-archive") +public interface ReportArchiveClient { + + /** + * 归档 [startTime, endTime) 窗口内“已完成且未归档”的巡检执行: + * 合并生成一份动环报告,报告生成上传后自动推送外部平台;无待归档任务时不生成不推送。 + * + * @param startTime 窗口开始时间 yyyy-MM-dd HH:mm:ss(含) + * @param endTime 窗口结束时间 yyyy-MM-dd HH:mm:ss(不含) + */ + @PostMapping({"/resultmain/archiveByTime"}) + AjaxResult archiveByTime(@RequestParam("startTime") String startTime, + @RequestParam("endTime") String endTime); +} diff --git a/inspect-job/src/main/java/com/inspect/job/task/ReportArchiveScheduleTask.java b/inspect-job/src/main/java/com/inspect/job/task/ReportArchiveScheduleTask.java new file mode 100644 index 0000000..5b248da --- /dev/null +++ b/inspect-job/src/main/java/com/inspect/job/task/ReportArchiveScheduleTask.java @@ -0,0 +1,81 @@ +package com.inspect.job.task; + +import com.inspect.base.core.web.domain.AjaxResult; +import com.inspect.job.client.ReportArchiveClient; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +/** + * 巡检报告定时归档任务(sys_job 在数据库灵活控制)。 + *

+ * 由 sql/sys_job_report_archive.sql 预置两条 sys_job 调用: + *

+ * 窗口截止点(07:00 / 16:00)即为报告批次语义,若后续确认新的生成时间点, + * 需同时调整 sys_job 的 cron_expression 与下方 {@link #MORNING_END}/{@link #EVENING_END} 截止点。 + * + * @author inspect + */ +@Slf4j +@Component("reportArchiveScheduleTask") +public class ReportArchiveScheduleTask { + + /** 数据窗口截止时间:早晨批次 = 当日 07:00 */ + private static final LocalTime MORNING_END = LocalTime.of(7, 0, 0); + /** 数据窗口截止时间:下午批次 = 当日 16:00 */ + private static final LocalTime EVENING_END = LocalTime.of(16, 0, 0); + + private static final DateTimeFormatter DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private final ReportArchiveClient reportArchiveClient; + + public ReportArchiveScheduleTask(ReportArchiveClient reportArchiveClient) { + this.reportArchiveClient = reportArchiveClient; + } + + /** + * sys_job:每日 07:00 归档 前一日16:00 ~ 当日07:00 的巡检数据。 + */ + public void archiveMorning() { + LocalDate today = LocalDate.now(); + // 前一日 16:00 + LocalDateTime start = LocalDateTime.of(today.minusDays(1), EVENING_END); + // 当日 07:00 + LocalDateTime end = LocalDateTime.of(today, MORNING_END); + archiveByWindow("早晨批次(前一日16:00~当日07:00)", start, end); + } + + /** + * sys_job:每日 16:00 归档 当日07:00 ~ 当日16:00 的巡检数据。 + */ + public void archiveEvening() { + LocalDate today = LocalDate.now(); + LocalDateTime start = LocalDateTime.of(today, MORNING_END); + LocalDateTime end = LocalDateTime.of(today, EVENING_END); + archiveByWindow("下午批次(当日07:00~当日16:00)", start, end); + } + + /** + * 按窗口触发 inspect-main 定时归档;无待归档任务时主服务会跳过(不生成不推送)。 + * 调用失败直接抛出异常,由 sys_job_log 记录失败。 + */ + private void archiveByWindow(String batchName, LocalDateTime start, LocalDateTime end) { + String startTime = start.format(DATE_TIME); + String endTime = end.format(DATE_TIME); + log.info("[定时归档] {} 开始, 数据窗口: {} ~ {}", batchName, startTime, endTime); + AjaxResult result = reportArchiveClient.archiveByTime(startTime, endTime); + Object code = result == null ? null : result.get(AjaxResult.CODE_TAG); + Object msg = result == null ? null : result.get(AjaxResult.MSG_TAG); + log.info("[定时归档] {} 完成, code={}, msg={}", batchName, code, msg); + if (result == null || !(code instanceof Number) || ((Number) code).intValue() != 200) { + throw new RuntimeException("定时归档调用失败: " + (msg == null ? "无响应" : msg)); + } + } +} diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/insreport/controller/InspectionReportController.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreport/controller/InspectionReportController.java index 85eb8fa..6ce2ffc 100644 --- a/inspect-main/inspect-main-task/src/main/java/com/inspect/insreport/controller/InspectionReportController.java +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreport/controller/InspectionReportController.java @@ -19,6 +19,7 @@ import com.inspect.insreport.domain.InspectionReport; import com.inspect.insreport.service.IInspectionReportService; import com.inspect.insreportdata.domain.InspectionReportData; import com.inspect.insreportdata.service.IInspectionReportDataService; +import com.inspect.insreporttask.service.IInspectionReportTaskService; import com.inspect.message.MessageUtils; import com.inspect.taskftp.domain.PatrolTaskFtp; import com.inspect.taskftp.service.IPatrolTaskFtpService; @@ -39,7 +40,6 @@ import java.io.*; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; import java.util.zip.Adler32; import java.util.zip.CheckedOutputStream; @@ -52,6 +52,7 @@ public class InspectionReportController extends BaseController { private final IInspectionReportService inspectionReportService; private final IInspectionReportDataService inspectionReportDataService; private final IInspectionReportImgService inspectionReportImgService; + private final IInspectionReportTaskService inspectionReportTaskService; private final SftpClient sftpClient; private final IPatrolTaskFtpService patrolTaskFtpService; @@ -61,10 +62,11 @@ public class InspectionReportController extends BaseController { @Autowired private MessageUtils MessageUtils; - public InspectionReportController(IInspectionReportService inspectionReportService, IInspectionReportDataService inspectionReportDataService, IInspectionReportImgService inspectionReportImgService, SftpClient sftpClient, IPatrolTaskFtpService patrolTaskFtpService) { + public InspectionReportController(IInspectionReportService inspectionReportService, IInspectionReportDataService inspectionReportDataService, IInspectionReportImgService inspectionReportImgService, IInspectionReportTaskService inspectionReportTaskService, SftpClient sftpClient, IPatrolTaskFtpService patrolTaskFtpService) { this.inspectionReportService = inspectionReportService; this.inspectionReportDataService = inspectionReportDataService; this.inspectionReportImgService = inspectionReportImgService; + this.inspectionReportTaskService = inspectionReportTaskService; this.sftpClient = sftpClient; this.patrolTaskFtpService = patrolTaskFtpService; } @@ -75,31 +77,18 @@ public class InspectionReportController extends BaseController { List inspectionReportList = inspectionReportService.selectByAllList(inspectionReport); logger.info("[REPORT] inspectionReportList size: {}", inspectionReportList.size()); - // 根据 inspectionTaskName 和 inspectionDate 组合去重 - List distinctList = inspectionReportList.stream() - .collect(Collectors.collectingAndThen( - Collectors.toMap( - report -> report.getInspectionTaskName() + "_" + - (report.getInspectionDate() != null ? DateUtils.format("yyyy-MM-dd",report.getInspectionDate()) : "null"), - Function.identity(), - (existing, replacement) -> existing - ), - map -> map.values().stream() - .sorted(Comparator.comparing(InspectionReport::getInspectionDate, - Comparator.nullsLast(Comparator.reverseOrder()))) - .collect(Collectors.toList()) - )); - + // 归档已改为一次归档(单个任务/多个任务合并)只生成一条 inspection_report, + // 报告列表即“每条报告一行”,无需再按任务名+日期去重 PageDomain pageDomain = TableSupport.buildPageRequest(); int pageNum = pageDomain.getPageNum(); int pageSize = pageDomain.getPageSize(); - int toNum = Math.min(distinctList.size(), pageNum * pageSize); - List pageList = distinctList.subList((pageNum - 1) * pageSize, toNum); + int toNum = Math.min(inspectionReportList.size(), pageNum * pageSize); + List pageList = inspectionReportList.subList((pageNum - 1) * pageSize, toNum); TableDataInfo rspData = new TableDataInfo(); rspData.setCode(200); rspData.setRows(pageList); rspData.setMsg("查询成功"); - rspData.setTotal((new PageInfo<>(distinctList)).getTotal()); + rspData.setTotal((new PageInfo<>(inspectionReportList)).getTotal()); return rspData; } @@ -135,11 +124,18 @@ public class InspectionReportController extends BaseController { // 暂时这么处理(进度条报告入口,lineId传的是patrolTaskStatus的lineId) PatrolTaskStatus patrolTaskStatus = patrolTaskStatusService.selectPatrolTaskStatusByLineId(lineId); String taskPatrolledId = patrolTaskStatus.getTaskPatrolledId(); - inspectionReport = new InspectionReport(); - inspectionReport.setTaskPatrolledId(taskPatrolledId); - inspectionReport.setFilter(filter); logger.info("进度条报告查看,filter:{},taskPatrolledId:{}", filter, taskPatrolledId); - List inspectionReports = inspectionReportService.selectInspectionReportList(inspectionReport); + // 合并归档后一次归档只生成一条报告,多个任务经 inspection_report_task 关联同一条报告, + // 故先按任务执行标识查关联报告 + List inspectionReports = + inspectionReportTaskService.selectInspectionReportsByTaskPatrolledId(taskPatrolledId, filter); + if (inspectionReports.isEmpty()) { + // 兼容历史数据:旧归档按任务各生成一条报告,回退按报告头 task_patrolled_id 等值匹配 + inspectionReport = new InspectionReport(); + inspectionReport.setTaskPatrolledId(taskPatrolledId); + inspectionReport.setFilter(filter); + inspectionReports = inspectionReportService.selectInspectionReportList(inspectionReport); + } if (inspectionReports.size() > 0) { inspectionReport = inspectionReports.get(0); lineId = inspectionReport.getLineId(); @@ -203,10 +199,17 @@ public class InspectionReportController extends BaseController { // 暂时这么处理(进度条报告入口,lineId传的是patrolTaskStatus的lineId) PatrolTaskStatus patrolTaskStatus = patrolTaskStatusService.selectPatrolTaskStatusByLineId(lineId); String taskPatrolledId = patrolTaskStatus.getTaskPatrolledId(); - inspectionReport.setTaskPatrolledId(taskPatrolledId); - inspectionReport.setFilter(filter); logger.info("进度条报告查看,filter:{},taskPatrolledId:{}", filter, taskPatrolledId); - List inspectionReports = inspectionReportService.selectInspectionReportList(inspectionReport); + // 合并归档后一次归档只生成一条报告,多个任务经 inspection_report_task 关联同一条报告, + // 故先按任务执行标识查关联报告 + List inspectionReports = + inspectionReportTaskService.selectInspectionReportsByTaskPatrolledId(taskPatrolledId, filter); + if (inspectionReports.isEmpty()) { + // 兼容历史数据:旧归档按任务各生成一条报告,回退按报告头 task_patrolled_id 等值匹配 + inspectionReport.setTaskPatrolledId(taskPatrolledId); + inspectionReport.setFilter(filter); + inspectionReports = inspectionReportService.selectInspectionReportList(inspectionReport); + } if (inspectionReports.size() > 0) { inspectionReport = inspectionReports.get(0); lineId = inspectionReport.getLineId(); diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/domain/InspectionReportTask.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/domain/InspectionReportTask.java new file mode 100644 index 0000000..1e0973c --- /dev/null +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/domain/InspectionReportTask.java @@ -0,0 +1,32 @@ +package com.inspect.insreporttask.domain; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * 巡检报告-任务关联表。 + *

+ * 归档改造后,一次归档(单个任务 / 多个任务合并归档)只生成一条 + * {@link com.inspect.insreport.domain.InspectionReport},被归档的每个任务执行 + * (patrol_task_result_main.line_id)都通过本表关联到同一条报告。 + * + * @author inspect + */ +@Getter +@Setter +public class InspectionReportTask { + /** 主键 */ + private Long id; + /** 报告主键 inspection_report.line_id */ + private Long reportLineId; + /** 归档任务执行主键 patrol_task_result_main.line_id */ + private Long taskResultLineId; + /** 任务执行标识 patrol_task_result_main.task_patrolled_id */ + private String taskPatrolledId; + /** 任务名称 patrol_task_result_main.task_name */ + private String taskName; + /** 创建时间 */ + private Date createTime; +} diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/mapper/InspectionReportTaskMapper.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/mapper/InspectionReportTaskMapper.java new file mode 100644 index 0000000..0fd85ce --- /dev/null +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/mapper/InspectionReportTaskMapper.java @@ -0,0 +1,28 @@ +package com.inspect.insreporttask.mapper; + +import com.inspect.insreport.domain.InspectionReport; +import com.inspect.insreporttask.domain.InspectionReportTask; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface InspectionReportTaskMapper { + + /** + * 批量写入 报告-任务 关联。 + * + * @param inspectionReportTasks 关联记录(一次归档一条报告,任务逐条关联) + */ + int batchInsertInspectionReportTask(@Param("list") List inspectionReportTasks); + + /** + * 按任务执行标识查询其关联的报告(合并归档时多个任务关联同一条报告)。 + * + * @param taskPatrolledId 任务执行标识 patrol_task_result_main.task_patrolled_id + * @param filter 报告类型过滤(可为空/不传,表示不过滤) + */ + List selectInspectionReportsByTaskPatrolledId(@Param("taskPatrolledId") String taskPatrolledId, + @Param("filter") String filter); +} diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/service/IInspectionReportTaskService.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/service/IInspectionReportTaskService.java new file mode 100644 index 0000000..6848930 --- /dev/null +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/service/IInspectionReportTaskService.java @@ -0,0 +1,24 @@ +package com.inspect.insreporttask.service; + +import com.inspect.insreport.domain.InspectionReport; +import com.inspect.insreporttask.domain.InspectionReportTask; + +import java.util.List; + +public interface IInspectionReportTaskService { + + /** + * 写入 报告-任务 关联记录。 + * + * @param inspectionReportTasks 关联记录列表 + */ + int batchInsert(List inspectionReportTasks); + + /** + * 按任务执行标识查询其关联的报告(多个任务可能关联同一条合并报告)。 + * + * @param taskPatrolledId 任务执行标识 + * @param filter 报告类型过滤(可空) + */ + List selectInspectionReportsByTaskPatrolledId(String taskPatrolledId, String filter); +} diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/service/impl/InspectionReportTaskServiceImpl.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/service/impl/InspectionReportTaskServiceImpl.java new file mode 100644 index 0000000..b68a283 --- /dev/null +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/insreporttask/service/impl/InspectionReportTaskServiceImpl.java @@ -0,0 +1,32 @@ +package com.inspect.insreporttask.service.impl; + +import com.inspect.insreport.domain.InspectionReport; +import com.inspect.insreporttask.domain.InspectionReportTask; +import com.inspect.insreporttask.mapper.InspectionReportTaskMapper; +import com.inspect.insreporttask.service.IInspectionReportTaskService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class InspectionReportTaskServiceImpl implements IInspectionReportTaskService { + + private final InspectionReportTaskMapper inspectionReportTaskMapper; + + public InspectionReportTaskServiceImpl(InspectionReportTaskMapper inspectionReportTaskMapper) { + this.inspectionReportTaskMapper = inspectionReportTaskMapper; + } + + @Override + public int batchInsert(List inspectionReportTasks) { + if (inspectionReportTasks == null || inspectionReportTasks.isEmpty()) { + return 0; + } + return this.inspectionReportTaskMapper.batchInsertInspectionReportTask(inspectionReportTasks); + } + + @Override + public List selectInspectionReportsByTaskPatrolledId(String taskPatrolledId, String filter) { + return this.inspectionReportTaskMapper.selectInspectionReportsByTaskPatrolledId(taskPatrolledId, filter); + } +} diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/partrolresult/service/impl/PatrolResultServiceImpl.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/partrolresult/service/impl/PatrolResultServiceImpl.java index 9e52a3f..3942975 100644 --- a/inspect-main/inspect-main-task/src/main/java/com/inspect/partrolresult/service/impl/PatrolResultServiceImpl.java +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/partrolresult/service/impl/PatrolResultServiceImpl.java @@ -22,6 +22,8 @@ import com.inspect.insreport.domain.InspectionReport; import com.inspect.insreport.mapper.InspectionReportMapper; import com.inspect.insreportdata.domain.InspectionReportData; import com.inspect.insreportdata.mapper.InspectionReportDataMapper; +import com.inspect.insreporttask.domain.InspectionReportTask; +import com.inspect.insreporttask.mapper.InspectionReportTaskMapper; import com.inspect.message.MessageUtils; import com.inspect.partrolresult.domain.*; import com.inspect.partrolresult.mapper.PatrolResultMapper; @@ -76,6 +78,7 @@ public class PatrolResultServiceImpl implements IPatrolResultService { private final InspectionReportMapper inspectionReportMapper; private final InspectionReportImgMapper inspectionReportImgMapper; private final InspectionReportDataMapper inspectionReportDataMapper; + private final InspectionReportTaskMapper inspectionReportTaskMapper; private final ResultAnalysisMapper resultAnalysisMapper; private final FeignBasedataAreaService feignBasedataAreaService; @Value("${inspect.task.report.voltage:±800kv}") @@ -87,7 +90,7 @@ public class PatrolResultServiceImpl implements IPatrolResultService { @Resource private ResultAnalysisUtils resultAnalysisUtils; - public PatrolResultServiceImpl(PatrolResultMapper patrolResultMapper, PatrolResultDefaultValueMapper patrolResultDefaultvalueMapper, PatrolTaskResultMainMapper patrolTaskResultMainMapper, PatrolTaskStatusMapper patrolTaskStatusMapper, PatrolTaskMapper patrolTaskMapper, InspectionReportMapper inspectionReportMapper, InspectionReportImgMapper inspectionReportImgMapper, InspectionReportDataMapper inspectionReportDataMapper, ResultAnalysisMapper resultAnalysisMapper, FeignBasedataAreaService feignBasedataAreaService) { + public PatrolResultServiceImpl(PatrolResultMapper patrolResultMapper, PatrolResultDefaultValueMapper patrolResultDefaultvalueMapper, PatrolTaskResultMainMapper patrolTaskResultMainMapper, PatrolTaskStatusMapper patrolTaskStatusMapper, PatrolTaskMapper patrolTaskMapper, InspectionReportMapper inspectionReportMapper, InspectionReportImgMapper inspectionReportImgMapper, InspectionReportDataMapper inspectionReportDataMapper, InspectionReportTaskMapper inspectionReportTaskMapper, ResultAnalysisMapper resultAnalysisMapper, FeignBasedataAreaService feignBasedataAreaService) { this.patrolResultMapper = patrolResultMapper; this.patrolResultDefaultvalueMapper = patrolResultDefaultvalueMapper; this.patrolTaskResultMainMapper = patrolTaskResultMainMapper; @@ -96,6 +99,7 @@ public class PatrolResultServiceImpl implements IPatrolResultService { this.inspectionReportMapper = inspectionReportMapper; this.inspectionReportImgMapper = inspectionReportImgMapper; this.inspectionReportDataMapper = inspectionReportDataMapper; + this.inspectionReportTaskMapper = inspectionReportTaskMapper; this.resultAnalysisMapper = resultAnalysisMapper; this.feignBasedataAreaService = feignBasedataAreaService; } @@ -743,59 +747,81 @@ public class PatrolResultServiceImpl implements IPatrolResultService { } else { patrolStatistics = String.format(messageUtils.get("本次任务巡视总结果数量:%d个,正常结果数量:%d个,缺陷结果数量:%d个"), total, okNum, defectNum); } - for (Long lineId : lineIds) { + // 一次归档(单个任务 / 多个任务合并归档)只生成一份报告: + // 1) 报告头(inspection_report)只插一条,明细数据(inspection_report_data)覆盖本次归档的全部任务; + // 2) 被归档的每个任务执行都通过 inspection_report_task 关联到这一条报告, + // 任务粒度与明细行中的 task_patrolled_id / task_name 保持一致, + // 便于从任意任务/进度入口定位到这条合并报告。 + List reportTasks = new ArrayList<>(); + Long reportLineId = null; + for (int idx = 0; idx < lineIds.size(); idx++) { + Long lineId = lineIds.get(idx); resultMain.setLineId(lineId); resultMain.setCheckTime(new Date()); resultMain.setFileStatus("1"); String mainId = String.valueOf(resultMain.getLineId()); - // 查询当前的结果信息 - PatrolResult patrolResult = resultList.stream().filter(item -> mainId.equals(item.getMainId())).findFirst().orElse(null); - assert patrolResult != null; - String taskCode = patrolResult.getTaskCode(); PatrolTaskResultMain main = patrolTaskResultMainMapper.selectPatrolTaskResultMainByLineId(lineId); String taskPatrolId = main.getTaskPatrolledId(); if (StringUtils.isEmpty(taskPatrolId)) { throw new ServiceException("LACK PLAN ID: " + mainId); - } else { + } + + if (reportLineId == null) { + // 以本次归档第一个执行任务的信息生成报告头 + PatrolResult patrolResult = resultList.stream().filter(item -> mainId.equals(item.getMainId())).findFirst().orElse(null); + assert patrolResult != null; + String taskCode = patrolResult.getTaskCode(); List taskStatuses = this.patrolTaskStatusMapper.selectPatrolTaskStatusList(PatrolTaskStatus.builder().taskPatrolledId(taskPatrolId).build()); if (taskStatuses.isEmpty()) { throw new ServiceException("LACKING STATUS: " + mainId); + } + List list = patrolTaskMapper.selectPatrolTaskList(PatrolTask.builder().taskCode(taskCode).build()); + PatrolTask task = new PatrolTask(); + if (list.isEmpty()) { + log.error("TASK PLAN LOST: " + taskCode); } else { - List list = patrolTaskMapper.selectPatrolTaskList(PatrolTask.builder().taskCode(taskCode).build()); - PatrolTask task = new PatrolTask(); - if (list.isEmpty()) { - log.error("TASK PLAN LOST: " + taskCode); - } else { - task = list.get(0); - } - InspectionReport report = new InspectionReport(); - report.setPatrolStatistics(patrolStatistics); - report.setInspectionDate(new Date()); - report.setTaskResultId(mainId); - report.setInspectionStartTime(startTimes.get(0)); - report.setInspectionEndTime(DateUtils.parseDate(endTimes.get(endTimes.size() - 1))); - report.setTaskId(task.getTaskId() == null ? "" : String.valueOf(task.getTaskId())); - report.setEnvInfo(StringUtils.join(envoList, ",")); - report.setTaskPatrolledId(taskPatrolId); - report.setInspectionTaskName(taskName); - report.setDescription(resultMain.getTaskResult()); - report.setCheckPerson(resultMain.getCheckPerson()); - report.setCheckTime(resultMain.getCheckTime()); - report.setStationName(stationName); - report.setVoltLevel(StringUtils.isEmpty(voltLevel) ? voltage : voltLevel); - report.setFilter("0"); - report.setStationType(stationType); - // 位置 = 省份 + 地市(如 四川省成都市) - report.setLocation(buildLocation(provinceName, cityName)); - inspectionReportMapper.insertInspectionReport(report); - // 为每个报告生成数据 - batchInsertReportData_shaoxing(String.valueOf(report.getLineId()), patrolResultRefs, basePointAreaInfoList, lineIds); - reportIds.add(report.getLineId()); + task = list.get(0); } + InspectionReport report = new InspectionReport(); + report.setPatrolStatistics(patrolStatistics); + report.setInspectionDate(startTimes.get(0)); + report.setTaskResultId(mainId); + report.setInspectionStartTime(startTimes.get(0)); + report.setInspectionEndTime(DateUtils.parseDate(endTimes.get(endTimes.size() - 1))); + report.setTaskId(task.getTaskId() == null ? "" : String.valueOf(task.getTaskId())); + report.setEnvInfo(StringUtils.join(envoList, ",")); + report.setTaskPatrolledId(taskPatrolId); + report.setInspectionTaskName(taskName); + report.setDescription(resultMain.getTaskResult()); + report.setCheckPerson(resultMain.getCheckPerson()); + report.setCheckTime(resultMain.getCheckTime()); + report.setStationName(stationName); + report.setVoltLevel(StringUtils.isEmpty(voltLevel) ? voltage : voltLevel); + report.setFilter("0"); + report.setStationType(stationType); + // 位置 = 省份 + 地市(如 四川省成都市) + report.setLocation(buildLocation(provinceName, cityName)); + inspectionReportMapper.insertInspectionReport(report); + // 为这一份报告生成明细数据(覆盖本次归档的所有任务) + batchInsertReportData_shaoxing(String.valueOf(report.getLineId()), patrolResultRefs, basePointAreaInfoList, lineIds); + reportLineId = report.getLineId(); + reportIds.add(reportLineId); } this.patrolTaskResultMainMapper.updatePatrolTaskResultMain(resultMain); this.patrolResultMapper.updatePatrolResultByMainId(String.valueOf(lineId)); + + // 记录 任务-报告 关联(同一份报告下每个任务一条) + InspectionReportTask reportTask = new InspectionReportTask(); + reportTask.setReportLineId(reportLineId); + reportTask.setTaskResultLineId(lineId); + reportTask.setTaskPatrolledId(taskPatrolId); + reportTask.setTaskName(main.getTaskName()); + reportTask.setCreateTime(new Date()); + reportTasks.add(reportTask); + } + if (!reportTasks.isEmpty()) { + inspectionReportTaskMapper.batchInsertInspectionReportTask(reportTasks); } startTime = PrintUtil.useTime("导出报告:全部数据入库", startTime); return reportIds; diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/DonghuanReportExportController.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/DonghuanReportExportController.java index 965ac11..569b56b 100644 --- a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/DonghuanReportExportController.java +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/DonghuanReportExportController.java @@ -18,6 +18,7 @@ import com.inspect.partrolresult.domain.PatrolResult; import com.inspect.partrolresult.service.IPatrolResultService; import com.inspect.partrolresult.util.PrintUtil; import com.inspect.reportfont.ReportFontEmbedder; +import com.inspect.reportpush.config.ReportPushProperties; import com.inspect.reportpush.service.ReportPushService; import com.inspect.resultmain.domain.PatrolTaskResultMain; import com.inspect.resultmain.service.IPatrolTaskResultMainService; @@ -41,6 +42,7 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -126,6 +128,7 @@ public class DonghuanReportExportController extends BaseController { private final IInspectionReportService inspectionReportService; private final SftpClient sftpClient; private final ReportPushService reportPushService; + private final ReportPushProperties reportPushProperties; private final ReportFontEmbedder reportFontEmbedder; private static final ExecutorService executor = Executors.newFixedThreadPool(10); @@ -140,6 +143,7 @@ public class DonghuanReportExportController extends BaseController { IInspectionReportService inspectionReportService, SftpClient sftpClient, ReportPushService reportPushService, + ReportPushProperties reportPushProperties, ReportFontEmbedder reportFontEmbedder) { this.patrolTaskResultMainService = patrolTaskResultMainService; this.patrolResultService = patrolResultService; @@ -148,6 +152,7 @@ public class DonghuanReportExportController extends BaseController { this.inspectionReportService = inspectionReportService; this.sftpClient = sftpClient; this.reportPushService = reportPushService; + this.reportPushProperties = reportPushProperties; this.reportFontEmbedder = reportFontEmbedder; } @@ -160,8 +165,9 @@ public class DonghuanReportExportController extends BaseController { // 报告发起人:当前登录账号 final String username = SecurityUtils.getUsername(); logger.info("[ARCHIVE] 动环归档触发, 发起人: {}", username); - CompletableFuture> saveReportFuture = CompletableFuture.>supplyAsync(() -> { - List taskPatrolledIds = resultMain.getTaskPatrolledIds(); + final List taskPatrolledIds = resultMain.getTaskPatrolledIds(); + // 手动归档:按勾选任务展开统一任务下的相关执行后归档 + submitDonghuanArchive(() -> { logger.info("-----------patrolTaskResultMains taskPatrolledIds: {}", taskPatrolledIds); List patrolTaskResultMains = patrolTaskResultMainService.selectPatrolTaskResultMainByTaskPatrolledIds(taskPatrolledIds); @@ -176,6 +182,63 @@ public class DonghuanReportExportController extends BaseController { lineIds.addAll(longs); } lineIds = lineIds.stream().distinct().collect(Collectors.toList()); + return lineIds; + }, resultMain, username, startTime); + return toAjax(1); + } + + /** + * 定时归档入口(由 inspect-job 的 sys_job 定时任务调用,如每日 08:00 / 17:00)。 + *

+ * 将 [startTime, endTime) 窗口内“已完成且未归档”的巡检执行合并归档为一份动环报告, + * 报告生成上传后自动推送外部平台;窗口内无待归档任务时跳过,不生成、不推送。 + *

+ * 无登录态:审核人/巡视结论取 {@code inspect.report-push.*} 配置(与旧自动归档一致)。 + * + * @param startTime 窗口开始时间 yyyy-MM-dd HH:mm:ss(含) + * @param endTime 窗口结束时间 yyyy-MM-dd HH:mm:ss(不含) + */ + @PostMapping({"/archiveByTime"}) + public AjaxResult archiveByTime(@RequestParam("startTime") String startTime, + @RequestParam("endTime") String endTime) { + long start = System.currentTimeMillis(); + logger.info("[ARCHIVE-SCHEDULE] 定时归档触发, 数据窗口: {} ~ {}", startTime, endTime); + List lineIds = patrolTaskResultMainService + .selectNotArchivedDoneLineIdsByStartWindow(DateUtils.parseDate(startTime), DateUtils.parseDate(endTime)); + logger.info("[ARCHIVE-SCHEDULE] 窗口内已完成未归档执行数: {}", lineIds == null ? 0 : lineIds.size()); + if (lineIds == null || lineIds.isEmpty()) { + logger.info("[ARCHIVE-SCHEDULE] 窗口内无待归档任务,跳过本次归档: {} ~ {}", startTime, endTime); + return AjaxResult.success("窗口内无待归档任务,跳过本次归档"); + } + PatrolTaskResultMain resultMain = new PatrolTaskResultMain(); + resultMain.setCheckPerson(reportPushProperties.getCheckPerson()); + resultMain.setTaskResult(reportPushProperties.getTaskResult()); + final List windowLineIds = lineIds; + submitDonghuanArchive(() -> windowLineIds, resultMain, null, start); + PrintUtil.useTime("提交定时归档", start); + return AjaxResult.success("定时归档已提交,待归档执行数: " + lineIds.size()); + } + + /** + * 提交一次动环归档并异步导出(手动归档 / 定时归档共用)。 + *

+ * lineIds 在异步线程内解析,保证请求快速返回;归档成功保存后异步生成 Word 并推送平台。 + * + * @param lineIdsSupplier 待归档执行 lineId(patrol_task_result_main.line_id)解析器 + * @param resultMain 归档参数(审核人 / 巡视结论) + * @param username 报告发起人(定时归档无登录态时传 null) + * @param startTime 调用开始时间(日志用) + */ + private void submitDonghuanArchive(Supplier> lineIdsSupplier, + PatrolTaskResultMain resultMain, + String username, + long startTime) { + CompletableFuture> saveReportFuture = CompletableFuture.>supplyAsync(() -> { + List lineIds = lineIdsSupplier.get(); + if (lineIds == null || lineIds.isEmpty()) { + logger.error("[归档]失败, 数据采集中..."); + return Collections.emptyList(); + } List resultList = patrolResultService.selectPatrolResultListByMainIds(lineIds); if (resultList == null || resultList.isEmpty()) { logger.error("[归档]失败, 数据采集中..."); @@ -207,14 +270,13 @@ public class DonghuanReportExportController extends BaseController { logger.error("Error occurred during saveReport: ", ex); return null; }); - return toAjax(1); } // ============================================================================ // 二、导出:动环 Word + 图片 ZIP // ============================================================================ public void exportDonghuanReport(List reportIds, String username) { - // 合并报告,所有报告内容一致,取第一个导出即可 + // 一次归档(单个任务 / 多个任务合并)只生成一条报告,多个任务经 inspection_report_task 关联同一条报告 Long lineId = reportIds.get(0); List tempFiles = new ArrayList<>(); Map tempFileMap = new LinkedHashMap<>(); diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/PatrolTaskResultMainController.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/PatrolTaskResultMainController.java index a6cfa70..944b7c4 100644 --- a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/PatrolTaskResultMainController.java +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/controller/PatrolTaskResultMainController.java @@ -1491,7 +1491,7 @@ public class PatrolTaskResultMainController extends BaseController { } public void exportExcelWordAndZipShaoxing(List reportIds) { - // 合并报告,所有报告都是一样的,所以随便取一个报告导出,这样就避免多次生成同样报告,影响性能 + // 一次归档(单个任务 / 多个任务合并)只生成一条报告,多个任务经 inspection_report_task 关联同一条报告 Long lineId = reportIds.get(0); logMemoryUsage("START exportExcelWordAndZipShaoxing"); List images = new ArrayList<>(); diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/mapper/PatrolTaskResultMainMapper.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/mapper/PatrolTaskResultMainMapper.java index 96967ca..50a3694 100644 --- a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/mapper/PatrolTaskResultMainMapper.java +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/mapper/PatrolTaskResultMainMapper.java @@ -4,6 +4,7 @@ import com.inspect.resultmain.domain.PatrolTaskResultMain; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.util.Date; import java.util.List; @Mapper @@ -34,5 +35,18 @@ public interface PatrolTaskResultMainMapper { List selectLineIdsByList(@Param("lineIds") List lineIds); + /** + * 定时归档用:查询指定时间窗口内“已完成且未归档”的巡检执行(patrol_task_result_main.line_id)。 + *

+ * 判定口径(按任务状态开始时间归批次): + * 任务状态已完成(patrol_task_status.task_state='1')且开始时间落在 [startTime, endTime), + * 且该执行尚未归档(file_status 不为 1)。 + * + * @param startTime 窗口开始时间(含) + * @param endTime 窗口结束时间(不含) + */ + List selectNotArchivedDoneLineIdsByStartWindow(@Param("startTime") Date startTime, + @Param("endTime") Date endTime); + PatrolTaskResultMain selectPatrolTaskResultMainOne(String patrolTaskId); } diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/IPatrolTaskResultMainService.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/IPatrolTaskResultMainService.java index f2a8003..0bce61b 100644 --- a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/IPatrolTaskResultMainService.java +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/IPatrolTaskResultMainService.java @@ -2,6 +2,7 @@ package com.inspect.resultmain.service; import com.inspect.resultmain.domain.PatrolTaskResultMain; +import java.util.Date; import java.util.List; public interface IPatrolTaskResultMainService { @@ -31,5 +32,13 @@ public interface IPatrolTaskResultMainService { List selectLineIdsByList(List lineIds); + /** + * 定时归档:查询指定时间窗口内“已完成且未归档”的巡检执行 lineId 列表。 + * + * @param startTime 窗口开始时间(含) + * @param endTime 窗口结束时间(不含) + */ + List selectNotArchivedDoneLineIdsByStartWindow(Date startTime, Date endTime); + PatrolTaskResultMain selectPatrolTaskResultMainOne(String patrolTaskId); } diff --git a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/impl/PatrolTaskResultMainServiceImpl.java b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/impl/PatrolTaskResultMainServiceImpl.java index 7ab2ce2..d8a8d95 100644 --- a/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/impl/PatrolTaskResultMainServiceImpl.java +++ b/inspect-main/inspect-main-task/src/main/java/com/inspect/resultmain/service/impl/PatrolTaskResultMainServiceImpl.java @@ -5,6 +5,7 @@ import com.inspect.resultmain.domain.PatrolTaskResultMain; import com.inspect.resultmain.mapper.PatrolTaskResultMainMapper; import com.inspect.resultmain.service.IPatrolTaskResultMainService; +import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; @@ -74,6 +75,11 @@ public class PatrolTaskResultMainServiceImpl implements IPatrolTaskResultMainSer return this.patrolTaskResultMainMapper.selectLineIdsByList(lineIds); } + @Override + public List selectNotArchivedDoneLineIdsByStartWindow(Date startTime, Date endTime) { + return this.patrolTaskResultMainMapper.selectNotArchivedDoneLineIdsByStartWindow(startTime, endTime); + } + @Override public PatrolTaskResultMain selectPatrolTaskResultMainOne(String patrolTaskId) { return this.patrolTaskResultMainMapper.selectPatrolTaskResultMainOne(patrolTaskId); diff --git a/inspect-main/inspect-main-task/src/main/resources/mapper/task/InspectionReportTaskMapper.xml b/inspect-main/inspect-main-task/src/main/resources/mapper/task/InspectionReportTaskMapper.xml new file mode 100644 index 0000000..9e5df03 --- /dev/null +++ b/inspect-main/inspect-main-task/src/main/resources/mapper/task/InspectionReportTaskMapper.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into inspection_report_task + (report_line_id, task_result_line_id, task_patrolled_id, task_name) + values + + (#{t.reportLineId}, #{t.taskResultLineId}, #{t.taskPatrolledId}, #{t.taskName}) + + + + + diff --git a/inspect-main/inspect-main-task/src/main/resources/mapper/task/PatrolTaskResultMainMapper.xml b/inspect-main/inspect-main-task/src/main/resources/mapper/task/PatrolTaskResultMainMapper.xml index 8be83dd..65a81f4 100644 --- a/inspect-main/inspect-main-task/src/main/resources/mapper/task/PatrolTaskResultMainMapper.xml +++ b/inspect-main/inspect-main-task/src/main/resources/mapper/task/PatrolTaskResultMainMapper.xml @@ -162,6 +162,18 @@ ) + + +