package com.sckj.iron.service.impl; import com.sckj.common.util.TimeUtils; import com.sckj.iron.dto.IronTrendL1DTO; import com.sckj.iron.dto.IronTrendL2DTO; import com.sckj.iron.dto.RealtimeData; import com.sckj.l2.dto.TrendRequest; import com.sckj.l2.entity.TL2Data; import com.sckj.l2.service.impl.TL2DataServiceImpl; import com.sckj.opc.entity.OPCData; import com.sckj.opc.service.OPCDataServiceImpl; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @Slf4j @Service public class TIronVisualScreenServiceImpl { @Resource OPCDataServiceImpl opcDataService; @Resource TL2DataServiceImpl tl2DataService; private static final SimpleDateFormat sdfMinute = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:00"); /*** * 实时数据图图例 * @param result * @return */ public synchronized Map getIronLegend(Map result) { result = new LinkedHashMap<>(); // // 1. 计算起止时间 // int hours = 24; // //给固定时间,24小时之内 // java.util.Date endTime = new java.util.Date(); // java.util.Calendar cal = java.util.Calendar.getInstance(); // cal.setTime(endTime); // cal.add(java.util.Calendar.HOUR_OF_DAY, -hours); // java.util.Date startTime = cal.getTime(); // 1. 计算起止时间 // 临时调试用,固定时间范围 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); final java.util.Date startTime; final java.util.Date endTime; try { startTime = sdf.parse("2025-07-13 02:15:00"); endTime = sdf.parse("2025-07-14 00:20:00"); } catch (Exception e) { throw new RuntimeException("时间解析失败", e); } // 1. 生成完整的每一分钟时间点 java.util.List xAxis = new java.util.ArrayList<>(); java.util.Calendar cursor = java.util.Calendar.getInstance(); cursor.setTime(startTime); while (!cursor.getTime().after(endTime)) { xAxis.add(sdfMinute.format(cursor.getTime())); cursor.add(java.util.Calendar.MINUTE, 1); } //最新L2数据 CompletableFuture latestL2Future = CompletableFuture.supplyAsync(() -> tl2DataService.lambdaQuery() //.le(TL2Data::getIronStarttime, new SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date())) .eq(TL2Data::getTapholeId, "1") .orderByDesc(TL2Data::getIronStarttime) .last("limit 1").one() ); //获取指定时间范围内的数据 CompletableFuture> opcDataFuture = CompletableFuture.supplyAsync(() -> opcDataService.lambdaQuery() .in(OPCData::getPointName, Arrays.asList( "BF4_1_IRONNOTCH_MIR_TEMP", // 温度 "BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED1", // 1车流速 "BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED2", // 2车流速 "BF4_1TH_1_MIR_NWT", // 四高炉1TH-1号车铁水净重 "BF4_1TH_2_MIR_NWT", // 四高炉1TH-2号车铁水净重 "BF4_1_IRONNOTCH_TAPPING", // 四高炉1号铁口出铁状态 "BF4_1TH_2_TPC_CARNO", // 1TH-2号车混铁车车号 "BF4_1TH_1_TPC_CARNO" // 1TH-1号车混铁车车号 )) .between(OPCData::getServerTime, startTime, endTime) .orderByAsc(OPCData::getServerTime) .list() ); //获取指定时间范围的L2数据 CompletableFuture> l2DataFuture = CompletableFuture.supplyAsync(() -> tl2DataService.lambdaQuery() .between(TL2Data::getIronStarttime, new SimpleDateFormat("yyyyMMddHHmmss").format(startTime), new SimpleDateFormat("yyyyMMddHHmmss").format(endTime)) .eq(TL2Data::getTapholeId, "1") .orderByAsc(TL2Data::getIronStarttime) .list() ); //获取上一个有效状态数据 CompletableFuture preTappingFuture = CompletableFuture.supplyAsync(() -> opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1_IRONNOTCH_TAPPING") .isNotNull(OPCData::getData) .lt(OPCData::getServerTime, startTime) .orderByDesc(OPCData::getServerTime) .last("limit 1").one() ); //获取当前有效出铁状态数据 CompletableFuture currentTappingFuture = CompletableFuture.supplyAsync(() -> opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1_IRONNOTCH_TAPPING") .isNotNull(OPCData::getData) .orderByDesc(OPCData::getServerTime) .last("limit 1").one() ); Integer preTappingVal = null; Integer currentTappingVal = 0; try { CompletableFuture.allOf(preTappingFuture, latestL2Future, opcDataFuture,currentTappingFuture,l2DataFuture).join(); Map> opcDataMap = opcDataFuture.get().stream() .collect(Collectors.groupingBy(OPCData::getPointName)); TL2Data latestL2 = latestL2Future.get(); result.put("elementS", RealtimeData.builder().desc("铁水成分-硫").value(latestL2.getElementS()).build()); result.put("elementSi", RealtimeData.builder().desc("铁水成分-硅").value(latestL2.getElementSi()).build()); result.put("mudWeight", RealtimeData.builder().desc("打泥量").value(latestL2.getMudWeight()).unit("L").build()); result.put("pollMm", RealtimeData.builder().desc("钻杆直径").value(latestL2.getPollMm()).unit("mm").build()); result.put("openDepth", RealtimeData.builder().desc("开口深度").value(latestL2.getOpenDepth()).unit("mm").build()); OPCData currentTapping = currentTappingFuture.get(); if (currentTapping != null && currentTapping.getData() != null) { Object v = currentTapping.getData(); if (v instanceof Number) currentTappingVal = ((Number) v).intValue(); else if (v instanceof String) { String str = ((String) v).trim(); if (!str.isEmpty()) { try { currentTappingVal = Integer.parseInt(str); } catch (Exception ignore) { } } } } List tl2DataList = l2DataFuture.get(); RealtimeData ironCosttime = (RealtimeData) result.getOrDefault("ironCosttime", RealtimeData.builder().desc("出铁时间").unit("min").value(0).build()); if (ObjectUtils.isNotEmpty(tl2DataList)) { List>> collect = tl2DataList.stream().map(item -> { List> mapList = new ArrayList<>(); Map map = new HashMap<>(); map.put("name", String.format("第%s次出铁\n(%s号铁口)%s分钟", item.getIronNo(), item.getTapholeId(), item.getIronCosttime())); map.put("xAxis", TimeUtils.formatPartialDateString(item.getIronStarttime())); mapList.add(map); map = new HashMap<>(); map.put("xAxis", TimeUtils.formatPartialDateString(item.getIronEndtime())); mapList.add(map); return mapList; }).collect(Collectors.toList()); Map extraMap = new HashMap<>(); extraMap.put("mark", collect); ironCosttime.setExtra(extraMap); } result.put("ironCosttime", ironCosttime); if(0 == currentTappingVal || 1 == currentTappingVal){ result.put("ironWeight", RealtimeData.builder().desc("累计出铁量").unit("t").value(0).build()); result.put("ironSpeed", RealtimeData.builder().desc("铁水流速").value(0).unit("t/min").build()); result.put("ironTemp", RealtimeData.builder().desc("铁水温度").value(0).unit("℃").build()); // result.put("ironCosttime", RealtimeData.builder().desc("出铁时间").value(0).unit("min").build()); return result; } //如果开始时间点没有值就从最近的获取 OPCData preTapping = preTappingFuture.get(); if (preTapping != null && preTapping.getData() != null) { Object v = preTapping.getData(); if (v instanceof Number) preTappingVal = ((Number) v).intValue(); else if (v instanceof String) { String str = ((String) v).trim(); if (!str.isEmpty()) { try { preTappingVal = Integer.parseInt(str); } catch (Exception ignore) { } } } } //BF4_1TH_1_MIR_NWT 1号车净重 CompletableFuture> weight1ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1TH_1_MIR_NWT", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //BF4_1TH_2_MIR_NWT 2号车净重 CompletableFuture> weight2ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1TH_2_MIR_NWT", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //BF4_1TH_1_TPC_CARNO 2号车 CompletableFuture> car1ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1TH_1_TPC_CARNO", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //BF4_1TH_2_TPC_CARNO 2号车 CompletableFuture> car2ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1TH_2_TPC_CARNO", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //1号铁口状态 CompletableFuture> tapping1ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1_IRONNOTCH_TAPPING", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); // 等待所有转换完成 CompletableFuture.allOf( car1ListFuture, car2ListFuture, tapping1ListFuture, weight1ListFuture, weight2ListFuture ).join(); // 构建每分钟tappingMap Map tappingMap = new LinkedHashMap<>(); List tappingList = opcDataMap.getOrDefault("BF4_1_IRONNOTCH_TAPPING", new ArrayList<>()); Map rawTappingMap = new LinkedHashMap<>(); for (OPCData item : tappingList) { if (item.getServerTime() != null && item.getData() != null) { String min = sdfMinute.format(item.getServerTime()); Integer val = null; Object v = item.getData(); if (v instanceof Number) val = ((Number) v).intValue(); else if (v instanceof String) { String str = ((String) v).trim(); if (!str.isEmpty()) { try { val = Integer.parseInt(str); } catch (Exception ignore) { } } } if (val != null) rawTappingMap.put(min, val); } } Integer last = preTappingVal; for (String t : xAxis) { Integer v = rawTappingMap.getOrDefault(t, last); tappingMap.put(t, v); if (v != null) last = v; } List weight1List = weight1ListFuture.get(); List weight2List = weight2ListFuture.get(); List car1List = car1ListFuture.get(); List car2List = car2ListFuture.get(); int ironWeightScale = 2; // 可调整为0、1、2等 List> ironWeightArr = buildIronWeightMinuteArray(xAxis, tappingMap, weight1List, weight2List, ironWeightScale); if (ObjectUtils.isNotEmpty(ironWeightArr)) { List> mapList = new ArrayList<>(); for (List objects : ironWeightArr) { String string = objects.get(0).toString(); String data = objects.get(1).toString(); for (IronTrendL1DTO ironTrendL1DTO : car1List) { if (sdfMinute.format(ironTrendL1DTO.getCreateTime()).equals(string)) { Map map = new HashMap<>(); map.put("value", ironTrendL1DTO.getData() + "#"); map.put("xAxis", sdfMinute.format(ironTrendL1DTO.getCreateTime())); map.put("yAxis", data); mapList.add(map); } } for (IronTrendL1DTO ironTrendL1DTO : car2List) { if (sdfMinute.format(ironTrendL1DTO.getCreateTime()).equals(string)) { Map map = new HashMap<>(); map.put("value", ironTrendL1DTO.getData() + "#"); map.put("xAxis", sdfMinute.format(ironTrendL1DTO.getCreateTime())); map.put("yAxis", data); mapList.add(map); } } } RealtimeData ironWeight = (RealtimeData) result.getOrDefault("ironWeight", RealtimeData.builder().desc("累计出铁量").unit("t").value(0).build()); Map extraMap = new HashMap<>(); extraMap.put("mark", new ArrayList<>()); ironWeight.setExtra(extraMap); result.put("ironWeight", ironWeight); } } catch (Exception e) { e.printStackTrace(); } return result; } /*** * 实时折线图数据, * BF4_1_IRONNOTCH_TAPPING表示出铁状态,数值只有0和1,1表示正在出铁,0表示未出铁 * BF4_1TH_1_MIR_NWT表示四高炉1TH-1号车铁水净重,BF4_1TH_2_MIR_NWT表示四高炉1TH-2号车铁水净重,这2车一开始的重量为0,然后装入铁水重量不断增加,直到满载,然后减为0,然后继续增加,以此往复 * * @param queryDateType * @return */ public synchronized Map getIronChart(TrendRequest queryDateType) { // // 1. 计算起止时间 // int hours = Objects.isNull(queryDateType.getQueryHourBefore()) ? 24 : queryDateType.getQueryHourBefore(); // //给固定时间,24小时之内 // java.util.Date endTime = new java.util.Date(); // java.util.Calendar cal = java.util.Calendar.getInstance(); // cal.setTime(endTime); // cal.add(java.util.Calendar.HOUR_OF_DAY, -hours); // java.util.Date startTime = cal.getTime(); // 临时调试用,固定时间范围 final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); final java.util.Date startTime; final java.util.Date endTime; try { startTime = sdf.parse("2025-07-13 02:15:00"); endTime = sdf.parse("2025-07-14 00:20:00"); } catch (Exception e) { throw new RuntimeException("时间解析失败", e); } // 2. 异步查询所有数据 CompletableFuture> opcDataFuture = CompletableFuture.supplyAsync(() -> opcDataService.lambdaQuery() .in(OPCData::getPointName, Arrays.asList( "BF4_1_IRONNOTCH_MIR_TEMP", // 温度 "BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED1", // 1车流速 "BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED2", // 2车流速 "BF4_1TH_1_MIR_NWT", // 四高炉1TH-1号车铁水净重 "BF4_1TH_2_MIR_NWT", // 四高炉1TH-2号车铁水净重 "BF4_1_IRONNOTCH_TAPPING", // 1号铁口出铁状态 "BF4_1TH_2_TPC_CARNO", // 1TH-2号车混铁车车号 "BF4_1TH_1_TPC_CARNO" // 1TH-1号车混铁车车号 )) .between(OPCData::getServerTime, startTime, endTime) .orderByAsc(OPCData::getServerTime) .list() ); CompletableFuture> l2DataFuture = CompletableFuture.supplyAsync(() -> tl2DataService.lambdaQuery() .between(TL2Data::getIronStarttime, new SimpleDateFormat("yyyyMMddHHmmss").format(startTime), new SimpleDateFormat("yyyyMMddHHmmss").format(endTime)) .eq(TL2Data::getTapholeId, "1") .orderByAsc(TL2Data::getIronStarttime) .list() ); // 3. 等待所有查询完成并转换数据 try { // 4. 按pointName分类OPC数据并转换为DTO Map> opcDataMap = opcDataFuture.get().stream() .collect(Collectors.groupingBy(OPCData::getPointName)); List l2DataList = l2DataFuture.get(); // 并行转换所有数据 //铁水温度 CompletableFuture> tempListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1_IRONNOTCH_MIR_TEMP", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //1TH-1号车受铁速度 CompletableFuture> speed1ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED1", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //1TH-2号车受铁速度 CompletableFuture> speed2ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED2", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //BF4_1TH_1_MIR_NWT 1号车净重 CompletableFuture> weight1ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1TH_1_MIR_NWT", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //BF4_1TH_2_MIR_NWT 2号车净重 CompletableFuture> weight2ListFuture = CompletableFuture.supplyAsync(() -> opcDataMap.getOrDefault("BF4_1TH_2_MIR_NWT", new ArrayList<>()) .stream().map(item -> { IronTrendL1DTO dto = new IronTrendL1DTO(); dto.setData(item.getData()); dto.setCreateTime(item.getSourceTime()); return dto; }).collect(Collectors.toList()) ); //L2 CompletableFuture> elemenListFuture = CompletableFuture.supplyAsync(() -> l2DataList.stream().map(item -> { IronTrendL2DTO dto = new IronTrendL2DTO(); try { dto.setElementS(item.getElementS() != null ? Double.parseDouble(item.getElementS()) : null); } catch (NumberFormatException e) { dto.setElementS(null); } try { dto.setElementSi(item.getElementSi() != null ? Double.parseDouble(item.getElementSi()) : null); } catch (NumberFormatException e) { dto.setElementSi(null); } dto.setIronStarttime(item.getIronStarttime()); dto.setIronEndtime(item.getIronEndtime()); dto.setPollMm(item.getPollMm()); dto.setOpenDepth(item.getOpenDepth()); dto.setMudWeight(item.getMudWeight()); dto.setIronCosttime(item.getIronCosttime()); return dto; }).collect(Collectors.toList()) ); // 等待所有转换完成 CompletableFuture.allOf( tempListFuture, speed1ListFuture, speed2ListFuture, weight1ListFuture, weight2ListFuture, elemenListFuture ).join(); // 5. 封装返回 List tempList = tempListFuture.get(); List speed1List = speed1ListFuture.get(); List speed2List = speed2ListFuture.get(); List weight1List = weight1ListFuture.get(); List weight2List = weight2ListFuture.get(); List elemenList = elemenListFuture.get(); // 1. 生成完整的每一分钟时间点 java.util.List xAxis = new java.util.ArrayList<>(); java.util.Calendar cursor = java.util.Calendar.getInstance(); cursor.setTime(startTime); while (!cursor.getTime().after(endTime)) { xAxis.add(sdfMinute.format(cursor.getTime())); cursor.add(java.util.Calendar.MINUTE, 1); } // 查询区间前的最近一条历史数据(前置值) // OPC类 OPCData preTemp = opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1_IRONNOTCH_MIR_TEMP") .isNotNull(OPCData::getData) .lt(OPCData::getServerTime, startTime) .orderByDesc(OPCData::getServerTime) .last("limit 1").one(); OPCData preSpeed1 = opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED1") .isNotNull(OPCData::getData) .lt(OPCData::getServerTime, startTime) .orderByDesc(OPCData::getServerTime) .last("limit 1").one(); OPCData preSpeed2 = opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1_IRONNOTCH_RAILLINE_ACPIRON_SPEED2") .isNotNull(OPCData::getData) .lt(OPCData::getServerTime, startTime) .orderByDesc(OPCData::getServerTime) .last("limit 1").one(); OPCData preWeight1 = opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1TH_1_MIR_NWT") .isNotNull(OPCData::getData) .lt(OPCData::getServerTime, startTime) .orderByDesc(OPCData::getServerTime) .last("limit 1").one(); OPCData preWeight2 = opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1TH_2_MIR_NWT") .isNotNull(OPCData::getData) .lt(OPCData::getServerTime, startTime) .orderByDesc(OPCData::getServerTime) .last("limit 1").one(); // tappingMap补齐每一分钟,前面无数据用前置值补齐 // 先查区间前最近一条tapping Integer preTappingVal = 0; OPCData preTapping = opcDataService.lambdaQuery() .eq(OPCData::getPointName, "BF4_1_IRONNOTCH_TAPPING") .isNotNull(OPCData::getData) .lt(OPCData::getServerTime, startTime) .orderByDesc(OPCData::getServerTime) .last("limit 1").one(); // L2类 TL2Data preL2 = tl2DataService.lambdaQuery() .lt(TL2Data::getIronStarttime, new SimpleDateFormat("yyyyMMddHHmmss").format(startTime)) .eq(TL2Data::getTapholeId, "1") .orderByDesc(TL2Data::getIronStarttime) .last("limit 1").one(); // 2. 构建每分钟补全的二维数组 java.util.Map result = new java.util.LinkedHashMap<>(); // if (preTapping != null && preTapping.getData() != null) { Object v = preTapping.getData(); if (v instanceof Number) preTappingVal = ((Number) v).intValue(); else if (v instanceof String) { String str = ((String) v).trim(); if (!str.isEmpty()) { try { preTappingVal = Integer.parseInt(str); } catch (Exception ignore) { } } } } // 构建每分钟tappingMap Map tappingMap = new LinkedHashMap<>(); List tappingList = opcDataMap.getOrDefault("BF4_1_IRONNOTCH_TAPPING", new ArrayList<>()); Map rawTappingMap = new LinkedHashMap<>(); for (OPCData item : tappingList) { if (item.getServerTime() != null && item.getData() != null) { String min = sdfMinute.format(item.getServerTime()); Integer val = null; Object v = item.getData(); if (v instanceof Number) val = ((Number) v).intValue(); else if (v instanceof String) { String str = ((String) v).trim(); if (!str.isEmpty()) { try { val = Integer.parseInt(str); } catch (Exception ignore) { } } } if (val != null) rawTappingMap.put(min, val); } } Integer last = preTappingVal; for (String t : xAxis) { Integer v = rawTappingMap.getOrDefault(t, last); tappingMap.put(t, v); if (v != null) last = v; } int ironWeightScale = 2; // 可调整为0、1、2等 List> ironFlowArr = buildIronWeightMinuteArray(xAxis, tappingMap, weight1List, weight2List, ironWeightScale); result.put("ironWeight", ironFlowArr); // 处理铁水流速,出铁中按原逻辑,出铁结束后为0 List> ironSpeedArr = buildMinuteArrayForSpeed(xAxis, speed1List, speed2List, tappingMap); List> ironTempArr = buildMinuteArray(tempList, xAxis, preTemp != null ? preTemp.getData() : null); for (int i = 0; i < xAxis.size(); i++) { String t = xAxis.get(i); Integer tapping = tappingMap.getOrDefault(t, 0); if (tapping == 0 && ironSpeedArr.get(i).size() > 1) { ironSpeedArr.get(i).set(1, 0); ironTempArr.get(i).set(1, 0); } } result.put("ironSpeed", ironSpeedArr); result.put("ironTemp", ironTempArr); // 处理L2类数据,tapping=0时设为0 List> elementSArr = buildL2MinuteArray(elemenList, xAxis, "elementS", preL2 != null ? preL2.getElementS() : null); List> elementSiArr = buildL2MinuteArray(elemenList, xAxis, "elementSi", preL2 != null ? preL2.getElementSi() : null); List> mudWeightArr = buildL2MinuteArray(elemenList, xAxis, "mudWeight", preL2 != null ? preL2.getMudWeight() : null); List> pollMmArr = buildL2MinuteArray(elemenList, xAxis, "pollMm", preL2 != null ? preL2.getPollMm() : null); List> openDepthArr = buildL2MinuteArray(elemenList, xAxis, "openDepth", preL2 != null ? preL2.getOpenDepth() : null); List> ironCosttimeArr = buildL2MinuteArray(elemenList, xAxis, "ironCosttime", preL2 != null ? preL2.getIronCosttime() : null); for (int i = 0; i < xAxis.size(); i++) { String t = xAxis.get(i); Integer tapping = tappingMap.getOrDefault(t, 0); if (tapping == 0) { if (elementSArr.get(i).size() > 1) elementSArr.get(i).set(1, 0); if (elementSiArr.get(i).size() > 1) elementSiArr.get(i).set(1, 0); if (mudWeightArr.get(i).size() > 1) mudWeightArr.get(i).set(1, 0); if (pollMmArr.get(i).size() > 1) pollMmArr.get(i).set(1, 0); if (openDepthArr.get(i).size() > 1) openDepthArr.get(i).set(1, 0); if (ironCosttimeArr.get(i).size() > 1) ironCosttimeArr.get(i).set(1, 0); } } result.put("elementS", elementSArr); result.put("elementSi", elementSiArr); result.put("mudWeight", mudWeightArr); result.put("pollMm", pollMmArr); result.put("openDepth", openDepthArr); result.put("ironCosttime", ironCosttimeArr); return result; } catch (Exception e) { e.printStackTrace(); } return null; } // 新增工具方法:L1类型 private java.util.List> buildMinuteArray(java.util.List list, java.util.List xAxis, Object preValue) { java.util.Map timeValueMap = new java.util.LinkedHashMap<>(); for (IronTrendL1DTO e : list) { if (e.getCreateTime() != null) { String min = sdfMinute.format(e.getCreateTime()); timeValueMap.put(min, e.getData()); } } java.util.List> arr = new java.util.ArrayList<>(); Object last = preValue; for (String t : xAxis) { Object v = timeValueMap.getOrDefault(t, last); arr.add(java.util.Arrays.asList(t, v)); if (v != null) last = v; } return arr; } // 铁水流速(重写:合并取最大值,出铁周期内补齐空值,且出铁周期内流速不允许为0) private java.util.List> buildMinuteArrayForSpeed(java.util.List xAxis, java.util.List speed1List, java.util.List speed2List, java.util.Map tappingMap) { java.util.Map speed1Map = new java.util.LinkedHashMap<>(); java.util.Map speed2Map = new java.util.LinkedHashMap<>(); for (IronTrendL1DTO e : speed1List) { if (e.getCreateTime() != null) { String min = sdfMinute.format(e.getCreateTime()); Object v = e.getData(); Double value = null; if (v instanceof Number) value = ((Number) v).doubleValue(); else if (v instanceof String) { try { value = Double.parseDouble((String) v); } catch (Exception ignore) { } } if (value != null) speed1Map.put(min, value); } } for (IronTrendL1DTO e : speed2List) { if (e.getCreateTime() != null) { String min = sdfMinute.format(e.getCreateTime()); Object v = e.getData(); Double value = null; if (v instanceof Number) value = ((Number) v).doubleValue(); else if (v instanceof String) { try { value = Double.parseDouble((String) v); } catch (Exception ignore) { } } if (value != null) speed2Map.put(min, value); } } // 合并为最大值map java.util.Map speedMap = new java.util.LinkedHashMap<>(); for (String key : speed1Map.keySet()) { speedMap.put(key, speed1Map.get(key)); } for (String key : speed2Map.keySet()) { double v2 = speed2Map.get(key); speedMap.put(key, Math.max(speedMap.getOrDefault(key, 0d), v2)); } java.util.List> arr = new java.util.ArrayList<>(); Double last = null; for (String t : xAxis) { Integer tapping = tappingMap.getOrDefault(t, 0); Double v = speedMap.get(t); if (tapping == 1) { if (v == null || v == 0) { // 出铁周期内流速不允许为0,用上一个非0值 v = last != null ? last : 0d; } arr.add(java.util.Arrays.asList(t, v)); if (v != null && v != 0) last = v; } else { arr.add(java.util.Arrays.asList(t, 0)); } } return arr; } //L2 private java.util.List> buildL2MinuteArray(java.util.List list, java.util.List xAxis, String field, Object preValue) { java.util.Map timeValueMap = new java.util.LinkedHashMap<>(); for (IronTrendL2DTO e : list) { String min = e.getIronStarttime(); if (min != null) { Object v = null; switch (field) { case "elementS": v = e.getElementS(); break; case "elementSi": v = e.getElementSi(); break; case "mudWeight": v = e.getMudWeight(); break; case "pollMm": v = e.getPollMm(); break; case "openDepth": v = e.getOpenDepth(); break; case "ironCosttime": v = e.getIronCosttime(); break; } timeValueMap.put(TimeUtils.formatPartialDateString(min), v); } } java.util.List> arr = new java.util.ArrayList<>(); Object last = preValue; for (String t : xAxis) { Object v = timeValueMap.getOrDefault(t, last); arr.add(java.util.Arrays.asList(t, v)); if (v != null) last = v; } return arr; } //铁水重量 private List> buildIronWeightMinuteArray(List xAxis, Map tappingMap, List weight1List, List weight2List, int scale) { Map weight1Map = new LinkedHashMap<>(); for (IronTrendL1DTO e : weight1List) { if (e.getCreateTime() != null) { String min = sdfMinute.format(e.getCreateTime()); Object v = e.getData(); Double value = null; if (v instanceof Number) value = ((Number) v).doubleValue(); else if (v instanceof String) { String str = ((String) v).trim(); if (!str.isEmpty()) { try { value = Double.parseDouble(str); } catch (Exception ignore) { } } } if (value != null) { weight1Map.put(min, value); } } } Map weight2Map = new LinkedHashMap<>(); for (IronTrendL1DTO e : weight2List) { if (e.getCreateTime() != null) { String min = sdfMinute.format(e.getCreateTime()); Object v = e.getData(); Double value = null; if (v instanceof Number) value = ((Number) v).doubleValue(); else if (v instanceof String) { String str = ((String) v).trim(); if (!str.isEmpty()) { try { value = Double.parseDouble(str); } catch (Exception ignore) { } } } if (value != null) { weight2Map.put(min, value); } } } // 合并weight1Map和weight2Map到weightMap,取最大值 Map weightMap = new LinkedHashMap<>(); for (Map.Entry entry : weight1Map.entrySet()) { weightMap.put(entry.getKey(), entry.getValue()); } for (Map.Entry entry : weight2Map.entrySet()) { weightMap.put(entry.getKey(), Math.max(weightMap.getOrDefault(entry.getKey(), 0d), entry.getValue())); } // 按key正序排序 weightMap = weightMap.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .collect(java.util.LinkedHashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), java.util.LinkedHashMap::putAll); List> arr = new ArrayList<>(); boolean inTappingCycle = false; java.math.BigDecimal cycleTotal = java.math.BigDecimal.ZERO; java.math.BigDecimal lastW = java.math.BigDecimal.ZERO; for (int i = 0; i < xAxis.size(); i++) { String time = xAxis.get(i); Integer tapping = tappingMap.getOrDefault(time, 0); Double orDefault = weightMap.get(time); java.math.BigDecimal w = new java.math.BigDecimal(weightMap.getOrDefault(time, 0d).toString()); if (tapping == 1) { if (!inTappingCycle) { inTappingCycle = true; //System.out.println("[出铁周期结束] 开始于: " + time); } if (w.compareTo(java.math.BigDecimal.ZERO) == 0) { w = lastW; weightMap.put(time, w.doubleValue()); } else { lastW = w; } if (i > 0) { java.math.BigDecimal prevW = new java.math.BigDecimal(weightMap.getOrDefault(xAxis.get(i - 1), 0d).toString()); //上一个减去当前的 if (prevW.subtract(w).compareTo(new java.math.BigDecimal("130")) > 0) { //System.out.println("[出铁周期满载情况] 时间: " + xAxis.get(i - 1) + ", 铁水满载值: " + prevW); cycleTotal = cycleTotal.add(prevW); } } arr.add(java.util.Arrays.asList(time, w.add(cycleTotal).setScale(scale, java.math.RoundingMode.HALF_UP).doubleValue())); } else { if (inTappingCycle) { double value = cycleTotal.setScale(scale, java.math.RoundingMode.HALF_UP).doubleValue(); //System.out.println("[出铁周期结束] 结束于: " + time + ", 本周期铁水总净重: " + value); arr.add(java.util.Arrays.asList(time, value)); inTappingCycle = false; cycleTotal = java.math.BigDecimal.ZERO; // for (List objects : arr) { // System.out.println(objects.get(0)+" >>> "+objects.get(1)); // } } else { arr.add(java.util.Arrays.asList(time, 0)); } } } return arr; } }