|
1
|
1
|
package com.iot.scheduler.service;
|
|
2
|
2
|
|
|
|
3
|
+import com.alibaba.fastjson.JSON;
|
|
3
|
4
|
import com.alibaba.fastjson.JSONArray;
|
|
4
|
5
|
import com.alibaba.fastjson.JSONObject;
|
|
5
|
6
|
import lombok.extern.slf4j.Slf4j;
|
|
...
|
...
|
@@ -550,4 +551,381 @@ public class DeviceSearchService { |
|
550
|
551
|
|
|
551
|
552
|
return jdbcTemplate.queryForList(sql.toString(), params.toArray());
|
|
552
|
553
|
}
|
|
|
554
|
+
|
|
|
555
|
+ // ==================== OEE 时序图分页查询(含稼动率计算) ====================
|
|
|
556
|
+
|
|
|
557
|
+ /**
|
|
|
558
|
+ * 按设备分页查询所有设备的OEE时序数据,并计算稼动率
|
|
|
559
|
+ *
|
|
|
560
|
+ * @param startDate 开始日期 yyyy-MM-dd
|
|
|
561
|
+ * @param endDate 结束日期 yyyy-MM-dd
|
|
|
562
|
+ * @param pageNo 页码,从1开始
|
|
|
563
|
+ * @param pageSize 每页设备数,最大20
|
|
|
564
|
+ */
|
|
|
565
|
+ public Map<String, Object> queryOeeTimeline(String startDate, String endDate, Integer pageNo, Integer pageSize) {
|
|
|
566
|
+ log.info("========== [OEE时序图查询-按设备分页] startDate={}, endDate={}, pageNo={}, pageSize={} ==========",
|
|
|
567
|
+ startDate, endDate, pageNo, pageSize);
|
|
|
568
|
+
|
|
|
569
|
+ // 参数校验与默认值
|
|
|
570
|
+ if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) {
|
|
|
571
|
+ return Map.of("total", 0, "pageNo", pageNo, "pageSize", pageSize, "list", List.of());
|
|
|
572
|
+ }
|
|
|
573
|
+ int ps = Math.min(pageSize != null ? pageSize : 20, 20);
|
|
|
574
|
+ int pn = pageNo != null && pageNo > 0 ? pageNo : 1;
|
|
|
575
|
+
|
|
|
576
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
577
|
+ String todayStr = sdf.format(new Date());
|
|
|
578
|
+ boolean includeToday = isDateInRange(todayStr, startDate, endDate);
|
|
|
579
|
+ log.info("包含今日({}): {}", todayStr, includeToday);
|
|
|
580
|
+
|
|
|
581
|
+ // 1. 从设备表查询所有 dtuSn 及设备名称
|
|
|
582
|
+ Map<String, String> deviceNameMap = queryAllDtuSnWithName();
|
|
|
583
|
+ List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet());
|
|
|
584
|
+ int deviceTotal = allDtuSns.size();
|
|
|
585
|
+ log.info("设备总数: {}", deviceTotal);
|
|
|
586
|
+
|
|
|
587
|
+ if (allDtuSns.isEmpty()) {
|
|
|
588
|
+ return buildPageResult(0, pn, ps, List.of());
|
|
|
589
|
+ }
|
|
|
590
|
+
|
|
|
591
|
+ // 2. 构建日期范围列表
|
|
|
592
|
+ List<String> dateList = buildDayList(startDate, endDate);
|
|
|
593
|
+ log.info("日期范围共 {} 天: {} ~ {}", dateList.size(), dateList.get(0), dateList.get(dateList.size() - 1));
|
|
|
594
|
+
|
|
|
595
|
+ // 3. 批量从数据库查询全部设备的 OEE 数据
|
|
|
596
|
+ List<OeeRecord> allRecords = queryOeeBatch(allDtuSns, dateList, includeToday ? todayStr : null);
|
|
|
597
|
+
|
|
|
598
|
+ // 4. 如果包含今天,补充调用接口获取今天的实时数据
|
|
|
599
|
+ if (includeToday) {
|
|
|
600
|
+ supplementTodayData(allDtuSns, todayStr, allRecords);
|
|
|
601
|
+ }
|
|
|
602
|
+
|
|
|
603
|
+ // 5. 按 dtuSn 分组,每个设备包含该日期范围内所有天的数据
|
|
|
604
|
+ Map<String, List<OeeRecord>> deviceMap = new LinkedHashMap<>();
|
|
|
605
|
+ for (OeeRecord r : allRecords) {
|
|
|
606
|
+ deviceMap.computeIfAbsent(r.dtuSn, k -> new ArrayList<>()).add(r);
|
|
|
607
|
+ }
|
|
|
608
|
+ // 确保没有数据的设备也有空列表(保持顺序一致)
|
|
|
609
|
+ for (String sn : allDtuSns) {
|
|
|
610
|
+ if (!deviceMap.containsKey(sn)) {
|
|
|
611
|
+ deviceMap.put(sn, new ArrayList<>());
|
|
|
612
|
+ }
|
|
|
613
|
+ }
|
|
|
614
|
+
|
|
|
615
|
+ // 6. 设备维度分页
|
|
|
616
|
+ List<Map<String, Object>> pageList;
|
|
|
617
|
+ int offset = (pn - 1) * ps;
|
|
|
618
|
+ List<String> pagedDevices = new ArrayList<>(deviceMap.keySet()).subList(
|
|
|
619
|
+ Math.min(offset, deviceTotal), Math.min(offset + ps, deviceTotal));
|
|
|
620
|
+ pageList = convertDeviceGroupToResponse(pagedDevices, deviceMap, dateList, deviceNameMap);
|
|
|
621
|
+
|
|
|
622
|
+ return buildPageResult(deviceTotal, pn, ps, pageList);
|
|
|
623
|
+ }
|
|
|
624
|
+
|
|
|
625
|
+ /** 查询设备表所有dtuSn及对应设备名称 */
|
|
|
626
|
+ private Map<String, String> queryAllDtuSnWithName() {
|
|
|
627
|
+ String sql = "SELECT dtuSn, deviceName FROM " + deviceTableName + " WHERE corp_code = ? ORDER BY dtuSn";
|
|
|
628
|
+ List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, deviceCorpCode);
|
|
|
629
|
+ Map<String, String> result = new LinkedHashMap<>(rows.size());
|
|
|
630
|
+ for (Map<String, Object> row : rows) {
|
|
|
631
|
+ result.put((String) row.get("dtuSn"), (String) row.get("deviceName"));
|
|
|
632
|
+ }
|
|
|
633
|
+ return result;
|
|
|
634
|
+ }
|
|
|
635
|
+
|
|
|
636
|
+ /** 判断某日期是否在范围内 */
|
|
|
637
|
+ private boolean isDateInRange(String dateStr, String start, String end) {
|
|
|
638
|
+ try {
|
|
|
639
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
640
|
+ Date target = sdf.parse(dateStr);
|
|
|
641
|
+ Date s = sdf.parse(start);
|
|
|
642
|
+ Date e = sdf.parse(end);
|
|
|
643
|
+ return !target.before(s) && !target.after(e);
|
|
|
644
|
+ } catch (Exception e) {
|
|
|
645
|
+ return false;
|
|
|
646
|
+ }
|
|
|
647
|
+ }
|
|
|
648
|
+
|
|
|
649
|
+ /** 构建连续日期列表 */
|
|
|
650
|
+ private List<String> buildDayList(String startDate, String endDate) {
|
|
|
651
|
+ List<String> result = new ArrayList<>();
|
|
|
652
|
+ try {
|
|
|
653
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
654
|
+ Calendar cur = Calendar.getInstance();
|
|
|
655
|
+ cur.setTime(sdf.parse(startDate));
|
|
|
656
|
+ Calendar endCal = Calendar.getInstance();
|
|
|
657
|
+ endCal.setTime(sdf.parse(endDate));
|
|
|
658
|
+ while (!cur.after(endCal)) {
|
|
|
659
|
+ result.add(sdf.format(cur.getTime()));
|
|
|
660
|
+ cur.add(Calendar.DAY_OF_MONTH, 1);
|
|
|
661
|
+ }
|
|
|
662
|
+ } catch (Exception e) {
|
|
|
663
|
+ log.error("日期解析失败: {} ~ {}", startDate, endDate, e);
|
|
|
664
|
+ }
|
|
|
665
|
+ return result;
|
|
|
666
|
+ }
|
|
|
667
|
+
|
|
|
668
|
+ /** OEE内部记录结构 */
|
|
|
669
|
+ private static class OeeRecord {
|
|
|
670
|
+ String dtuSn;
|
|
|
671
|
+ String oeeDate;
|
|
|
672
|
+ JSONArray lampData; // 该日lampData数组
|
|
|
673
|
+ double availabilityRate; // 稼动率 (%)
|
|
|
674
|
+
|
|
|
675
|
+ OeeRecord(String dtuSn, String oeeDate) {
|
|
|
676
|
+ this.dtuSn = dtuSn;
|
|
|
677
|
+ this.oeeDate = oeeDate;
|
|
|
678
|
+ this.availabilityRate = 0.0;
|
|
|
679
|
+ }
|
|
|
680
|
+ }
|
|
|
681
|
+
|
|
|
682
|
+ /** 批量从数据库查询OEE数据 */
|
|
|
683
|
+ private List<OeeRecord> queryOeeBatch(List<String> dtuSns, List<String> dateList, String excludeToday) {
|
|
|
684
|
+ List<OeeRecord> records = new ArrayList<>();
|
|
|
685
|
+
|
|
|
686
|
+ if (dateList.isEmpty()) return records;
|
|
|
687
|
+
|
|
|
688
|
+ StringBuilder sql = new StringBuilder(
|
|
|
689
|
+ "SELECT dtuSn, oee_date, triColorLamp1, triColorLamp2 FROM " + oeeTableName +
|
|
|
690
|
+ " WHERE corp_code = ? AND dtuSn IN (");
|
|
|
691
|
+ List<Object> params = new ArrayList<>();
|
|
|
692
|
+ params.add(deviceCorpCode);
|
|
|
693
|
+
|
|
|
694
|
+ // dtuSn IN 条件
|
|
|
695
|
+ for (String sn : dtuSns) { sql.append("?,"); params.add(sn); }
|
|
|
696
|
+ sql.deleteCharAt(sql.length() - 1).append(")");
|
|
|
697
|
+
|
|
|
698
|
+ // 日期条件(排除今天)
|
|
|
699
|
+ sql.append(" AND oee_date IN (");
|
|
|
700
|
+ List<Object> dateParams = new ArrayList<>();
|
|
|
701
|
+ for (String d : dateList) {
|
|
|
702
|
+ if (d.equals(excludeToday)) continue;
|
|
|
703
|
+ sql.append("?,"); dateParams.add(d);
|
|
|
704
|
+ }
|
|
|
705
|
+ if (dateParams.isEmpty()) return records; // 全是今天
|
|
|
706
|
+ sql.deleteCharAt(sql.length() - 1).append(")");
|
|
|
707
|
+ params.addAll(dateParams);
|
|
|
708
|
+
|
|
|
709
|
+ List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray());
|
|
|
710
|
+ log.info("DB批量查询返回 {} 行OEE数据", rows.size());
|
|
|
711
|
+
|
|
|
712
|
+ for (Map<String, Object> row : rows) {
|
|
|
713
|
+ String sn = (String) row.get("dtuSn");
|
|
|
714
|
+ String oeeDate = String.valueOf(row.get("oee_date"));
|
|
|
715
|
+ if (oeeDate.length() > 10) oeeDate = oeeDate.substring(0, 10);
|
|
|
716
|
+ String lamp1 = (String) row.get("triColorLamp1");
|
|
|
717
|
+ String lamp2 = (String) row.get("triColorLamp2");
|
|
|
718
|
+
|
|
|
719
|
+ OeeRecord record = new OeeRecord(sn, oeeDate);
|
|
|
720
|
+ try {
|
|
|
721
|
+ String fullJson = (lamp1 != null ? lamp1 : "") + (lamp2 != null ? lamp2 : "");
|
|
|
722
|
+ if (!fullJson.isEmpty()) {
|
|
|
723
|
+ record.lampData = JSONArray.parseArray(fullJson);
|
|
|
724
|
+ } else {
|
|
|
725
|
+ record.lampData = new JSONArray();
|
|
|
726
|
+ }
|
|
|
727
|
+ } catch (Exception e) {
|
|
|
728
|
+ log.warn("解析OEE JSON异常 - dtuSn:{}, date:{}", sn, oeeDate, e);
|
|
|
729
|
+ record.lampData = new JSONArray();
|
|
|
730
|
+ }
|
|
|
731
|
+
|
|
|
732
|
+ record.availabilityRate = calcAvailabilityRate(record.lampData);
|
|
|
733
|
+ records.add(record);
|
|
|
734
|
+ }
|
|
|
735
|
+
|
|
|
736
|
+ return records;
|
|
|
737
|
+ }
|
|
|
738
|
+
|
|
|
739
|
+ /** 补充今天的实时接口数据 */
|
|
|
740
|
+ private void supplementTodayData(List<String> dtuSns, String todayStr, List<OeeRecord> records) {
|
|
|
741
|
+ log.info("开始补充今日({})实时OEE数据...", todayStr);
|
|
|
742
|
+ int apiCount = 0;
|
|
|
743
|
+ for (String dtuSn : dtuSns) {
|
|
|
744
|
+ // 先检查是否已有该设备今天的数据
|
|
|
745
|
+ boolean exists = false;
|
|
|
746
|
+ for (OeeRecord r : records) {
|
|
|
747
|
+ if (r.dtuSn.equals(dtuSn) && r.oeeDate.equals(todayStr)) {
|
|
|
748
|
+ exists = true; break;
|
|
|
749
|
+ }
|
|
|
750
|
+ }
|
|
|
751
|
+ if (exists) continue;
|
|
|
752
|
+
|
|
|
753
|
+ try {
|
|
|
754
|
+ String apiResult = devicePullService.getLampData(dtuSn, todayStr);
|
|
|
755
|
+ if (!StringUtils.hasText(apiResult)) continue;
|
|
|
756
|
+
|
|
|
757
|
+ Map<String, Object> res = JSON.parseObject(apiResult, new com.alibaba.fastjson.TypeReference<>() {});
|
|
|
758
|
+ Integer code = (Integer) res.get("code");
|
|
|
759
|
+ if (code == null || code != 200) continue;
|
|
|
760
|
+
|
|
|
761
|
+ JSONArray dataList = (JSONArray) res.get("data");
|
|
|
762
|
+ if (dataList == null || dataList.isEmpty()) continue;
|
|
|
763
|
+
|
|
|
764
|
+ JSONObject dataObj = (JSONObject) dataList.get(0);
|
|
|
765
|
+ OeeRecord record = new OeeRecord(dtuSn, todayStr);
|
|
|
766
|
+ record.lampData = dataObj.getJSONArray("lampData");
|
|
|
767
|
+ if (record.lampData == null) record.lampData = new JSONArray();
|
|
|
768
|
+ record.availabilityRate = calcAvailabilityRate(record.lampData);
|
|
|
769
|
+ records.add(record);
|
|
|
770
|
+ apiCount++;
|
|
|
771
|
+ } catch (Exception e) {
|
|
|
772
|
+ log.error("获取今日OEE数据异常 - dtuSn:{}", dtuSn, e);
|
|
|
773
|
+ }
|
|
|
774
|
+ }
|
|
|
775
|
+ log.info("今日实时数据补充完成, 新增 {} 条", apiCount);
|
|
|
776
|
+ }
|
|
|
777
|
+
|
|
|
778
|
+ /**
|
|
|
779
|
+ * 计算稼动率
|
|
|
780
|
+ * 稼动率 = 绿灯(state=3)时长 / 总时长 * 100%
|
|
|
781
|
+ */
|
|
|
782
|
+ private double calcAvailabilityRate(JSONArray lampData) {
|
|
|
783
|
+ if (lampData == null || lampData.isEmpty()) return 0.0;
|
|
|
784
|
+
|
|
|
785
|
+ long totalDuration = 0;
|
|
|
786
|
+ long greenDuration = 0;
|
|
|
787
|
+
|
|
|
788
|
+ for (int i = 0; i < lampData.size(); i++) {
|
|
|
789
|
+ JSONObject item = lampData.getJSONObject(i);
|
|
|
790
|
+ if (item == null) continue;
|
|
|
791
|
+ int state = item.getIntValue("lampState");
|
|
|
792
|
+ long dur = item.getLongValue("duration");
|
|
|
793
|
+ totalDuration += dur;
|
|
|
794
|
+ if (state == 3) greenDuration += dur;
|
|
|
795
|
+ }
|
|
|
796
|
+
|
|
|
797
|
+ if (totalDuration == 0) return 0.0;
|
|
|
798
|
+ return Math.round(greenDuration * 10000.0 / totalDuration) / 100.0; // 保留2位小数
|
|
|
799
|
+ }
|
|
|
800
|
+
|
|
|
801
|
+ /** 按设备分组转换为响应格式:每个设备一条记录,包含lampData和设备名称 */
|
|
|
802
|
+ private List<Map<String, Object>> convertDeviceGroupToResponse(List<String> pagedDevices,
|
|
|
803
|
+ Map<String, List<OeeRecord>> deviceMap,
|
|
|
804
|
+ List<String> dateList,
|
|
|
805
|
+ Map<String, String> deviceNameMap) {
|
|
|
806
|
+ List<Map<String, Object>> list = new ArrayList<>(pagedDevices.size());
|
|
|
807
|
+
|
|
|
808
|
+ for (String dtuSn : pagedDevices) {
|
|
|
809
|
+ Map<String, Object> item = new LinkedHashMap<>();
|
|
|
810
|
+ item.put("dtuSn", dtuSn);
|
|
|
811
|
+ item.put("deviceName", deviceNameMap.getOrDefault(dtuSn, ""));
|
|
|
812
|
+
|
|
|
813
|
+ List<OeeRecord> dayRecords = deviceMap.getOrDefault(dtuSn, Collections.emptyList());
|
|
|
814
|
+ // 构建日期→record的快速查找map
|
|
|
815
|
+ Map<String, OeeRecord> recordByDate = new LinkedHashMap<>();
|
|
|
816
|
+ for (OeeRecord r : dayRecords) {
|
|
|
817
|
+ recordByDate.put(r.oeeDate, r);
|
|
|
818
|
+ }
|
|
|
819
|
+
|
|
|
820
|
+ // 汇总计算综合稼动率
|
|
|
821
|
+ long totalDur = 0, greenDur = 0;
|
|
|
822
|
+ long offD = 0, redD = 0, yellowD = 0, greenD = 0, blueD = 0;
|
|
|
823
|
+ int offC = 0, redC = 0, yellowC = 0, greenC = 0, blueC = 0;
|
|
|
824
|
+
|
|
|
825
|
+ // 拼接所有天的 lampData 为一个数组(按日期排序)
|
|
|
826
|
+ JSONArray allLampData = new JSONArray();
|
|
|
827
|
+ List<Map<String, Object>> dailyDetails = new ArrayList<>();
|
|
|
828
|
+
|
|
|
829
|
+ for (String d : dateList) {
|
|
|
830
|
+ OeeRecord rec = recordByDate.get(d);
|
|
|
831
|
+ if (rec != null && rec.lampData != null) {
|
|
|
832
|
+ for (int i = 0; i < rec.lampData.size(); i++) {
|
|
|
833
|
+ JSONObject lamp = rec.lampData.getJSONObject(i);
|
|
|
834
|
+ if (lamp == null) continue;
|
|
|
835
|
+ int state = lamp.getIntValue("lampState");
|
|
|
836
|
+ long dur = lamp.getLongValue("duration");
|
|
|
837
|
+ switch (state) {
|
|
|
838
|
+ case 0 -> { offD += dur; offC++; }
|
|
|
839
|
+ case 1 -> { redD += dur; redC++; }
|
|
|
840
|
+ case 2 -> { yellowD += dur; yellowC++; }
|
|
|
841
|
+ case 3 -> { greenD += dur; greenC++; }
|
|
|
842
|
+ case 4 -> { blueD += dur; blueC++; }
|
|
|
843
|
+ }
|
|
|
844
|
+ totalDur += dur;
|
|
|
845
|
+ if (state == 3) greenDur += dur;
|
|
|
846
|
+ }
|
|
|
847
|
+ allLampData.addAll(rec.lampData);
|
|
|
848
|
+ }
|
|
|
849
|
+ double dayRate = (rec != null) ? rec.availabilityRate : 0.0;
|
|
|
850
|
+ dailyDetails.add(Map.of(
|
|
|
851
|
+ "oeeDate", d,
|
|
|
852
|
+ "availabilityRate", dayRate,
|
|
|
853
|
+ "hasData", rec != null
|
|
|
854
|
+ ));
|
|
|
855
|
+ }
|
|
|
856
|
+
|
|
|
857
|
+ double overallRate = (totalDur > 0) ? Math.round(greenDur * 10000.0 / totalDur) / 100.0 : 0.0;
|
|
|
858
|
+
|
|
|
859
|
+ // 扁平化字段,对齐截图格式
|
|
|
860
|
+ item.put("availabilityRatio", String.format("%.2f%%", overallRate));
|
|
|
861
|
+ item.put("offDuration", formatDuration(offD));
|
|
|
862
|
+ item.put("redDuration", formatDuration(redD));
|
|
|
863
|
+ item.put("yellowDuration", formatDuration(yellowD));
|
|
|
864
|
+ item.put("greenDuration", formatDuration(greenD));
|
|
|
865
|
+ item.put("blueDuration", formatDuration(blueD));
|
|
|
866
|
+ item.put("dataDays", recordByDate.size());
|
|
|
867
|
+ item.put("totalDays", dateList.size());
|
|
|
868
|
+ item.put("lampData", allLampData);
|
|
|
869
|
+ item.put("dailyDetails", dailyDetails);
|
|
|
870
|
+
|
|
|
871
|
+ list.add(item);
|
|
|
872
|
+ }
|
|
|
873
|
+
|
|
|
874
|
+ return list;
|
|
|
875
|
+ }
|
|
|
876
|
+
|
|
|
877
|
+ /** 转换为响应格式 */
|
|
|
878
|
+ private List<Map<String, Object>> convertToResponse(List<OeeRecord> records) {
|
|
|
879
|
+ List<Map<String, Object>> list = new ArrayList<>(records.size());
|
|
|
880
|
+
|
|
|
881
|
+ for (OeeRecord r : records) {
|
|
|
882
|
+ Map<String, Object> item = new LinkedHashMap<>();
|
|
|
883
|
+ item.put("dtuSn", r.dtuSn);
|
|
|
884
|
+ item.put("oeeDate", r.oeeDate);
|
|
|
885
|
+ item.put("availabilityRate", r.availabilityRate); // 稼动率
|
|
|
886
|
+ item.put("availabilityRateStr", r.availabilityRate + "%");
|
|
|
887
|
+
|
|
|
888
|
+ // 各状态时长统计
|
|
|
889
|
+ long offDur = 0, redDur = 0, yellowDur = 0, greenDur = 0, blueDur = 0;
|
|
|
890
|
+ int offCnt = 0, redCnt = 0, yellowCnt = 0, greenCnt = 0, blueCnt = 0;
|
|
|
891
|
+
|
|
|
892
|
+ if (r.lampData != null) {
|
|
|
893
|
+ for (int i = 0; i < r.lampData.size(); i++) {
|
|
|
894
|
+ JSONObject lamp = r.lampData.getJSONObject(i);
|
|
|
895
|
+ if (lamp == null) continue;
|
|
|
896
|
+ int state = lamp.getIntValue("lampState");
|
|
|
897
|
+ long dur = lamp.getLongValue("duration");
|
|
|
898
|
+ switch (state) {
|
|
|
899
|
+ case 0 -> { offDur += dur; offCnt++; }
|
|
|
900
|
+ case 1 -> { redDur += dur; redCnt++; }
|
|
|
901
|
+ case 2 -> { yellowDur += dur; yellowCnt++; }
|
|
|
902
|
+ case 3 -> { greenDur += dur; greenCnt++; }
|
|
|
903
|
+ case 4 -> { blueDur += dur; blueCnt++; }
|
|
|
904
|
+ }
|
|
|
905
|
+ }
|
|
|
906
|
+ }
|
|
|
907
|
+
|
|
|
908
|
+ item.put("off", Map.of("duration", formatDuration(offDur), "seconds", offDur, "count", offCnt));
|
|
|
909
|
+ item.put("red", Map.of("duration", formatDuration(redDur), "seconds", redDur, "count", redCnt));
|
|
|
910
|
+ item.put("yellow", Map.of("duration", formatDuration(yellowDur), "seconds", yellowDur, "count", yellowCnt));
|
|
|
911
|
+ item.put("green", Map.of("duration", formatDuration(greenDur), "seconds", greenDur, "count", greenCnt));
|
|
|
912
|
+ item.put("blue", Map.of("duration", formatDuration(blueDur), "seconds", blueDur, "count", blueCnt));
|
|
|
913
|
+ item.put("lampData", r.lampData != null ? r.lampData : new JSONArray());
|
|
|
914
|
+
|
|
|
915
|
+ list.add(item);
|
|
|
916
|
+ }
|
|
|
917
|
+ return list;
|
|
|
918
|
+ }
|
|
|
919
|
+
|
|
|
920
|
+ /** 构建分页结果(标准分页格式) */
|
|
|
921
|
+ private Map<String, Object> buildPageResult(long total, int pageNo, int pageSize, List<Map<String, Object>> list) {
|
|
|
922
|
+ return Map.of(
|
|
|
923
|
+ "data", Map.of(
|
|
|
924
|
+ "total", total,
|
|
|
925
|
+ "size", pageSize,
|
|
|
926
|
+ "current", pageNo,
|
|
|
927
|
+ "records", list
|
|
|
928
|
+ )
|
|
|
929
|
+ );
|
|
|
930
|
+ }
|
|
553
|
931
|
} |
...
|
...
|
|