|
...
|
...
|
@@ -928,4 +928,197 @@ public class DeviceSearchService { |
|
928
|
928
|
)
|
|
929
|
929
|
);
|
|
930
|
930
|
}
|
|
|
931
|
+
|
|
|
932
|
+ // ==================== 智能灯统计稼动率查询(仪表盘) ====================
|
|
|
933
|
+
|
|
|
934
|
+ /**
|
|
|
935
|
+ * 智能灯统计稼动率综合查询(仪表盘数据)
|
|
|
936
|
+ * 返回:总时长、稼动率、当前机台运行状态、异常排行榜、每设备状态时长
|
|
|
937
|
+ *
|
|
|
938
|
+ * @param startDate 开始日期 yyyy-MM-dd
|
|
|
939
|
+ * @param endDate 结束日期 yyyy-MM-dd
|
|
|
940
|
+ */
|
|
|
941
|
+ public Map<String, Object> queryLampStatistics(String startDate, String endDate) {
|
|
|
942
|
+ log.info("========== [智能灯统计查询] startDate={}, endDate={} ==========", startDate, endDate);
|
|
|
943
|
+
|
|
|
944
|
+ // 1. 根据前端传入的起止日期构建日期范围
|
|
|
945
|
+ List<String> dateList = buildDayList(startDate, endDate);
|
|
|
946
|
+ if (dateList.isEmpty()) {
|
|
|
947
|
+ return buildEmptyLampStats();
|
|
|
948
|
+ }
|
|
|
949
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
950
|
+ String todayStr = sdf.format(new Date());
|
|
|
951
|
+ boolean includeToday = dateList.contains(todayStr);
|
|
|
952
|
+ log.info("日期范围共 {} 天, 包含今日({}): {}", dateList.size(), todayStr, includeToday);
|
|
|
953
|
+
|
|
|
954
|
+ // 2. 获取所有设备及名称
|
|
|
955
|
+ Map<String, String> deviceNameMap = queryAllDtuSnWithName();
|
|
|
956
|
+ List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet());
|
|
|
957
|
+ if (allDtuSns.isEmpty()) {
|
|
|
958
|
+ return buildEmptyLampStats();
|
|
|
959
|
+ }
|
|
|
960
|
+
|
|
|
961
|
+ // 3. 批量从OEE表查询数据
|
|
|
962
|
+ List<OeeRecord> allRecords = queryOeeBatch(allDtuSns, dateList, includeToday ? todayStr : null);
|
|
|
963
|
+
|
|
|
964
|
+ // 4. 补充今天的实时数据
|
|
|
965
|
+ if (includeToday) {
|
|
|
966
|
+ supplementTodayData(allDtuSns, todayStr, allRecords);
|
|
|
967
|
+ }
|
|
|
968
|
+
|
|
|
969
|
+ // 5. 按 dtuSn 分组
|
|
|
970
|
+ Map<String, List<OeeRecord>> deviceMap = new LinkedHashMap<>();
|
|
|
971
|
+ for (OeeRecord r : allRecords) {
|
|
|
972
|
+ deviceMap.computeIfAbsent(r.dtuSn, k -> new ArrayList<>()).add(r);
|
|
|
973
|
+ }
|
|
|
974
|
+ for (String sn : allDtuSns) {
|
|
|
975
|
+ if (!deviceMap.containsKey(sn)) {
|
|
|
976
|
+ deviceMap.put(sn, new ArrayList<>());
|
|
|
977
|
+ }
|
|
|
978
|
+ }
|
|
|
979
|
+
|
|
|
980
|
+ // 6. 计算各项统计数据
|
|
|
981
|
+ return buildLampStatisticsResult(allDtuSns, deviceMap, deviceNameMap, dateList);
|
|
|
982
|
+ }
|
|
|
983
|
+
|
|
|
984
|
+ /** 构建空结果 */
|
|
|
985
|
+ private Map<String, Object> buildEmptyLampStats() {
|
|
|
986
|
+ return Map.of(
|
|
|
987
|
+ "totalDuration", Map.of(
|
|
|
988
|
+ "off", Map.of("duration", "0时0分0秒", "seconds", 0),
|
|
|
989
|
+ "red", Map.of("duration", "0时0分0秒", "seconds", 0),
|
|
|
990
|
+ "yellow", Map.of("duration", "0时0分0秒", "seconds", 0),
|
|
|
991
|
+ "green", Map.of("duration", "0时0分0秒", "seconds", 0),
|
|
|
992
|
+ "blue", Map.of("duration", "0时0分0秒", "seconds", 0)
|
|
|
993
|
+ ),
|
|
|
994
|
+ "availabilityRate", "0.00%",
|
|
|
995
|
+ "currentStatus", Map.of(
|
|
|
996
|
+ "off", 0, "red", 0, "yellow", 0, "green", 0, "blue", 0
|
|
|
997
|
+ ),
|
|
|
998
|
+ "abnormalRanking", List.of(),
|
|
|
999
|
+ "deviceList", List.of()
|
|
|
1000
|
+ );
|
|
|
1001
|
+ }
|
|
|
1002
|
+
|
|
|
1003
|
+ /** 构建智能灯统计结果 */
|
|
|
1004
|
+ private Map<String, Object> buildLampStatisticsResult(List<String> allDtuSns,
|
|
|
1005
|
+ Map<String, List<OeeRecord>> deviceMap,
|
|
|
1006
|
+ Map<String, String> deviceNameMap,
|
|
|
1007
|
+ List<String> dateList) {
|
|
|
1008
|
+ // ---- ① 总时长:汇总所有设备各状态时长 ----
|
|
|
1009
|
+ long totalOff = 0, totalRed = 0, totalYellow = 0, totalGreen = 0, totalBlue = 0;
|
|
|
1010
|
+
|
|
|
1011
|
+ // ---- ② 设备维度统计:用于异常排名和每设备详情 ----
|
|
|
1012
|
+ List<Map<String, Object>> deviceStatList = new ArrayList<>();
|
|
|
1013
|
+
|
|
|
1014
|
+ for (String dtuSn : allDtuSns) {
|
|
|
1015
|
+ List<OeeRecord> dayRecords = deviceMap.getOrDefault(dtuSn, Collections.emptyList());
|
|
|
1016
|
+
|
|
|
1017
|
+ long devOff = 0, devRed = 0, devYellow = 0, devGreen = 0, devBlue = 0;
|
|
|
1018
|
+ long devTotalDur = 0, devGreenDur = 0;
|
|
|
1019
|
+
|
|
|
1020
|
+ for (OeeRecord rec : dayRecords) {
|
|
|
1021
|
+ if (rec.lampData != null) {
|
|
|
1022
|
+ for (int i = 0; i < rec.lampData.size(); i++) {
|
|
|
1023
|
+ JSONObject lamp = rec.lampData.getJSONObject(i);
|
|
|
1024
|
+ if (lamp == null) continue;
|
|
|
1025
|
+ int state = lamp.getIntValue("lampState");
|
|
|
1026
|
+ long dur = lamp.getLongValue("duration");
|
|
|
1027
|
+ switch (state) {
|
|
|
1028
|
+ case 0 -> devOff += dur;
|
|
|
1029
|
+ case 1 -> devRed += dur;
|
|
|
1030
|
+ case 2 -> devYellow += dur;
|
|
|
1031
|
+ case 3 -> { devGreen += dur; devGreenDur += dur; }
|
|
|
1032
|
+ case 4 -> devBlue += dur;
|
|
|
1033
|
+ }
|
|
|
1034
|
+ devTotalDur += dur;
|
|
|
1035
|
+ }
|
|
|
1036
|
+ }
|
|
|
1037
|
+ }
|
|
|
1038
|
+
|
|
|
1039
|
+ // 稼动率 = 绿 / (红 + 黄 + 绿) * 100%
|
|
|
1040
|
+ long devRygDur = devRed + devYellow + devGreen;
|
|
|
1041
|
+ double rate = (devRygDur > 0) ? Math.round(devGreenDur * 10000.0 / devRygDur) / 100.0 : 0.0;
|
|
|
1042
|
+ long abnormalDur = devRed + devYellow; // 异常时长 = 红+黄
|
|
|
1043
|
+
|
|
|
1044
|
+ Map<String, Object> devStat = new LinkedHashMap<>();
|
|
|
1045
|
+ devStat.put("dtuSn", dtuSn);
|
|
|
1046
|
+ devStat.put("deviceName", deviceNameMap.getOrDefault(dtuSn, ""));
|
|
|
1047
|
+ devStat.put("offDuration", formatDuration(devOff));
|
|
|
1048
|
+ devStat.put("offSeconds", devOff);
|
|
|
1049
|
+ devStat.put("redDuration", formatDuration(devRed));
|
|
|
1050
|
+ devStat.put("redSeconds", devRed);
|
|
|
1051
|
+ devStat.put("yellowDuration", formatDuration(devYellow));
|
|
|
1052
|
+ devStat.put("yellowSeconds", devYellow);
|
|
|
1053
|
+ devStat.put("greenDuration", formatDuration(devGreen));
|
|
|
1054
|
+ devStat.put("greenSeconds", devGreen);
|
|
|
1055
|
+ devStat.put("blueDuration", formatDuration(devBlue));
|
|
|
1056
|
+ devStat.put("blueSeconds", devBlue);
|
|
|
1057
|
+ devStat.put("availabilityRatio", String.format("%.2f%%", rate));
|
|
|
1058
|
+ devStat.put("rygTotalDuration", formatDuration(devRygDur)); // 红+黄+绿 总时长
|
|
|
1059
|
+ devStat.put("abnormalDuration", abnormalDur); // 用于排序
|
|
|
1060
|
+
|
|
|
1061
|
+ deviceStatList.add(devStat);
|
|
|
1062
|
+
|
|
|
1063
|
+ // 累加到全局总计
|
|
|
1064
|
+ totalOff += devOff;
|
|
|
1065
|
+ totalRed += devRed;
|
|
|
1066
|
+ totalYellow += devYellow;
|
|
|
1067
|
+ totalGreen += devGreen;
|
|
|
1068
|
+ totalBlue += devBlue;
|
|
|
1069
|
+ }
|
|
|
1070
|
+
|
|
|
1071
|
+ // ---- ③ 稼动率 = 绿 / (红 + 黄 + 绿) ----
|
|
|
1072
|
+ long totalRygDur = totalRed + totalYellow + totalGreen;
|
|
|
1073
|
+ double overallRate = (totalRygDur > 0) ? Math.round(totalGreen * 10000.0 / totalRygDur) / 100.0 : 0.0;
|
|
|
1074
|
+
|
|
|
1075
|
+ // ---- ④ 当前机台运行状态(从设备表实时查) ----
|
|
|
1076
|
+ Map<String, Integer> currentStatus = queryCurrentDeviceStatus();
|
|
|
1077
|
+
|
|
|
1078
|
+ // ---- ⑤ 异常排行榜(按红+黄时长降序) ----
|
|
|
1079
|
+ deviceStatList.sort((a, b) -> Long.compare(
|
|
|
1080
|
+ ((Number) b.get("abnormalDuration")).longValue(),
|
|
|
1081
|
+ ((Number) a.get("abnormalDuration")).longValue()
|
|
|
1082
|
+ ));
|
|
|
1083
|
+ // 排序后移除辅助字段
|
|
|
1084
|
+ for (Map<String, Object> d : deviceStatList) {
|
|
|
1085
|
+ d.remove("abnormalDuration");
|
|
|
1086
|
+ }
|
|
|
1087
|
+
|
|
|
1088
|
+ return Map.of(
|
|
|
1089
|
+ "totalDuration", Map.of(
|
|
|
1090
|
+ "off", Map.of("duration", formatDuration(totalOff), "seconds", totalOff),
|
|
|
1091
|
+ "red", Map.of("duration", formatDuration(totalRed), "seconds", totalRed),
|
|
|
1092
|
+ "yellow", Map.of("duration", formatDuration(totalYellow), "seconds", totalYellow),
|
|
|
1093
|
+ "green", Map.of("duration", formatDuration(totalGreen), "seconds", totalGreen),
|
|
|
1094
|
+ "blue", Map.of("duration", formatDuration(totalBlue), "seconds", totalBlue)
|
|
|
1095
|
+ ),
|
|
|
1096
|
+ "availabilityRate", String.format("%.2f%%", overallRate),
|
|
|
1097
|
+ "rygTotalDuration", formatDuration(totalRygDur), // 红黄绿总时长
|
|
|
1098
|
+ "currentStatus", currentStatus,
|
|
|
1099
|
+ "abnormalRanking", deviceStatList,
|
|
|
1100
|
+ "deviceList", deviceStatList
|
|
|
1101
|
+ );
|
|
|
1102
|
+ }
|
|
|
1103
|
+
|
|
|
1104
|
+ /** 查询当前设备的运行状态分布(从设备表) */
|
|
|
1105
|
+ private Map<String, Integer> queryCurrentDeviceStatus() {
|
|
|
1106
|
+ String sql = "SELECT lampState, COUNT(*) as cnt FROM " + deviceTableName +
|
|
|
1107
|
+ " WHERE corp_code = ? GROUP BY lampState";
|
|
|
1108
|
+ List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, deviceCorpCode);
|
|
|
1109
|
+
|
|
|
1110
|
+ int off = 0, red = 0, yellow = 0, green = 0, blue = 0;
|
|
|
1111
|
+ for (Map<String, Object> row : rows) {
|
|
|
1112
|
+ String state = String.valueOf(row.get("lampState"));
|
|
|
1113
|
+ int cnt = ((Number) row.get("cnt")).intValue();
|
|
|
1114
|
+ switch (state) {
|
|
|
1115
|
+ case "0" -> off = cnt;
|
|
|
1116
|
+ case "1" -> red = cnt;
|
|
|
1117
|
+ case "2" -> yellow = cnt;
|
|
|
1118
|
+ case "3" -> green = cnt;
|
|
|
1119
|
+ case "4" -> blue = cnt;
|
|
|
1120
|
+ }
|
|
|
1121
|
+ }
|
|
|
1122
|
+ return Map.of("off", off, "red", red, "yellow", yellow, "green", green, "blue", blue);
|
|
|
1123
|
+ }
|
|
931
|
1124
|
} |
...
|
...
|
|