From c6202c6b72613e714a7b32717259b2f8ad532596 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 02 九月 2026 20:38:57 +0800
Subject: [PATCH] 按设备时间归属采集器工步观测
---
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 105 insertions(+), 0 deletions(-)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java
index b8fcfd2..8f4b5dc 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestDataQueryServiceImpl.java
@@ -1,6 +1,13 @@
package com.ruoyi.system.service.impl;
import java.util.List;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.HashMap;
@@ -33,6 +40,7 @@
List<Map<String, Object>> collector = mapper.selectPersistedCollectorRecords(testId);
if (cabinet != null) source.addAll(cabinet);
if (collector != null) source.addAll(collector);
+ attachCollectorStepContext(source);
return applyEffectiveData(testId, "REALTIME", source);
}
@@ -116,6 +124,103 @@
return "cycle:" + channelIdentity + ":" + cycleNo;
}
+ /** 按检测柜实际工步的设备时间边界给采集器样本补充筛选上下文,不配对采样点。 */
+ private void attachCollectorStepContext(List<Map<String, Object>> rows)
+ {
+ List<StepWindow> windows = new ArrayList<>();
+ Map<String, StepWindowBuilder> builders = new LinkedHashMap<>();
+ for (Map<String, Object> row : rows)
+ {
+ if ("COLLECTOR".equals(String.valueOf(row.get("sourceType")))) continue;
+ Instant time = toInstant(row.get("deviceTime"));
+ if (time == null || row.get("stepNo") == null) continue;
+ String key = String.join("|", text(row, "batteryNo"), text(row, "cycleNo"), text(row, "stepNo"));
+ StepWindowBuilder builder = builders.computeIfAbsent(key, ignored -> new StepWindowBuilder(row, time));
+ builder.start = builder.start.isAfter(time) ? time : builder.start;
+ builder.end = builder.end == null || builder.end.isBefore(time) ? time : builder.end;
+ }
+ for (StepWindowBuilder builder : builders.values()) windows.add(builder.build());
+ windows.sort(Comparator.comparing(StepWindow::start));
+ for (int index = 0; index < windows.size(); index++)
+ {
+ StepWindow current = windows.get(index);
+ Instant nextStart = windows.stream()
+ .filter(window -> window.batteryNo().equals(current.batteryNo()) && window.start().isAfter(current.start()))
+ .map(StepWindow::start).min(Comparator.naturalOrder()).orElse(null);
+ windows.set(index, current.withNextStart(nextStart));
+ }
+ for (Map<String, Object> row : rows)
+ {
+ if (!"COLLECTOR".equals(String.valueOf(row.get("sourceType")))) continue;
+ Instant time = toInstant(row.get("deviceTime"));
+ if (time == null) continue;
+ StepWindow match = windows.stream()
+ .filter(window -> text(row, "batteryNo").equals(window.batteryNo()))
+ .filter(window -> !time.isBefore(window.start())
+ && (window.nextStart() == null || time.isBefore(window.nextStart())))
+ .findFirst().orElse(null);
+ if (match == null) continue;
+ row.put("cycleNo", match.cycleNo());
+ row.put("stepNo", match.stepNo());
+ row.put("stepName", match.stepName());
+ row.put("actualStepLabel", match.stepName());
+ }
+ }
+
+ private String text(Map<String, Object> row, String key)
+ {
+ Object value = row.get(key);
+ return value == null ? "" : String.valueOf(value);
+ }
+
+ private Instant toInstant(Object value)
+ {
+ if (value instanceof Instant instant) return instant;
+ if (value instanceof Date date) return date.toInstant();
+ if (value == null) return null;
+ String text = String.valueOf(value);
+ try { return Instant.parse(text); }
+ catch (RuntimeException ignored) { }
+ try { return OffsetDateTime.parse(text).toInstant(); }
+ catch (RuntimeException ignored) { }
+ try { return LocalDateTime.parse(text).toInstant(ZoneOffset.UTC); }
+ catch (RuntimeException ignored) { return null; }
+ }
+
+ private static final class StepWindowBuilder
+ {
+ private final String batteryNo;
+ private final String cycleNo;
+ private final String stepNo;
+ private final String stepName;
+ private Instant start;
+ private Instant end;
+
+ private StepWindowBuilder(Map<String, Object> row, Instant time)
+ {
+ batteryNo = row.get("batteryNo") == null ? "" : String.valueOf(row.get("batteryNo"));
+ cycleNo = row.get("cycleNo") == null ? "" : String.valueOf(row.get("cycleNo"));
+ stepNo = row.get("stepNo") == null ? "" : String.valueOf(row.get("stepNo"));
+ stepName = row.get("stepName") == null ? "-" : String.valueOf(row.get("stepName"));
+ start = time;
+ end = time;
+ }
+
+ private StepWindow build()
+ {
+ return new StepWindow(batteryNo, cycleNo, stepNo, stepName, start, end, null);
+ }
+ }
+
+ private record StepWindow(String batteryNo, String cycleNo, String stepNo, String stepName,
+ Instant start, Instant end, Instant nextStart)
+ {
+ private StepWindow withNextStart(Instant value)
+ {
+ return new StepWindow(batteryNo, cycleNo, stepNo, stepName, start, end, value);
+ }
+ }
+
private String identityPart(Map<String, Object> row, String key)
{
Object value = row == null ? null : row.get(key);
--
Gitblit v1.7.1