Commit b9bdb7bd79182205a53c82eb4a6a1fccade0490a

Authored by 杨鸣坤
1 parent b064769e

feat: 新增设备能耗明细与OEE时序查询接口

@@ -143,4 +143,18 @@ public class HealthController { @@ -143,4 +143,18 @@ public class HealthController {
143 public Map<String, Object> energyStats() { 143 public Map<String, Object> energyStats() {
144 return energySearchService.queryEnergyStats(); 144 return energySearchService.queryEnergyStats();
145 } 145 }
  146 +
  147 + /**
  148 + * 根据dtuSn查询指定日期的设备时用电量和OEE时序
  149 + * 返回时用电量数组、总用电量、OEE时序、总时长、各状态运行时长和占比
  150 + *
  151 + * @param dtuSn 设备序列号
  152 + * @param date 查询日期 yyyy-MM-dd
  153 + */
  154 + @GetMapping("/energy/detail")
  155 + public Map<String, Object> energyDetail(
  156 + @RequestParam String dtuSn,
  157 + @RequestParam String date) {
  158 + return energySearchService.queryEnergyDetailByDate(dtuSn, date);
  159 + }
146 } 160 }
1 package com.iot.scheduler.service; 1 package com.iot.scheduler.service;
2 2
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONArray;
  5 +import com.alibaba.fastjson.JSONObject;
3 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
4 import org.springframework.beans.factory.annotation.Value; 7 import org.springframework.beans.factory.annotation.Value;
5 import org.springframework.jdbc.core.JdbcTemplate; 8 import org.springframework.jdbc.core.JdbcTemplate;
@@ -8,6 +11,8 @@ import org.springframework.util.StringUtils; @@ -8,6 +11,8 @@ import org.springframework.util.StringUtils;
8 11
9 import jakarta.annotation.Resource; 12 import jakarta.annotation.Resource;
10 13
  14 +import java.math.BigDecimal;
  15 +import java.math.RoundingMode;
11 import java.util.*; 16 import java.util.*;
12 17
13 @Slf4j 18 @Slf4j
@@ -18,6 +23,10 @@ public class EnergySearchService { @@ -18,6 +23,10 @@ public class EnergySearchService {
18 private String energyCorpCode; 23 private String energyCorpCode;
19 @Value("${energy.db.tableName}") 24 @Value("${energy.db.tableName}")
20 private String energyTableName; 25 private String energyTableName;
  26 + @Value("${energy.db.eqKwhTableName}")
  27 + private String eqKwhTableName;
  28 + @Value("${energy.db.eRunDtlTableName}")
  29 + private String eRunDtlTableName;
21 30
22 @Resource 31 @Resource
23 private JdbcTemplate jdbcTemplate; 32 private JdbcTemplate jdbcTemplate;
@@ -120,4 +129,124 @@ public class EnergySearchService { @@ -120,4 +129,124 @@ public class EnergySearchService {
120 "3", statusMap.get("3") 129 "3", statusMap.get("3")
121 ); 130 );
122 } 131 }
  132 +
  133 + /**
  134 + * 根据dtuSn查询指定日期的设备时用电量和OEE时序
  135 + * 1. 时用电量:从t_auto_ymk_iot_eq_kwh表获取,并计算当日总用电量
  136 + * 2. OEE时序:从t_auto_ymk_iot_e_run_dtl表获取,统计总时长、各状态运行时长和占比
  137 + *
  138 + * @param dtuSn 设备序列号
  139 + * @param date 查询日期 yyyy-MM-dd
  140 + */
  141 + public Map<String, Object> queryEnergyDetailByDate(String dtuSn, String date) {
  142 + // 1. 查询时用电量数据 - 原始数据直接返回
  143 + Object kwhRawData = Collections.emptyList();
  144 + BigDecimal totalKwh = BigDecimal.ZERO;
  145 + try {
  146 + String kwhSql = "SELECT description FROM " + eqKwhTableName
  147 + + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";
  148 + Map<String, Object> kwhRow = jdbcTemplate.queryForMap(kwhSql, energyCorpCode, dtuSn, date + " 00:00:00");
  149 + if (kwhRow != null && kwhRow.get("description") != null) {
  150 + String description = String.valueOf(kwhRow.get("description"));
  151 + kwhRawData = JSON.parseArray(description);
  152 + // 计算总用电量
  153 + JSONArray dataArray = JSON.parseArray(description);
  154 + for (int i = 0; i < dataArray.size(); i++) {
  155 + JSONObject item = dataArray.getJSONObject(i);
  156 + Double value = item.getDouble("value");
  157 + if (value != null) {
  158 + totalKwh = totalKwh.add(BigDecimal.valueOf(value));
  159 + }
  160 + }
  161 + }
  162 + } catch (Exception e) {
  163 + log.warn("【能耗明细】查询时用电量数据为空或异常 - dtuSn:{}, date:{}", dtuSn, date);
  164 + }
  165 +
  166 + // 2. 查询OEE时序数据 - 原始数据直接返回
  167 + Object oeeRawData = Collections.emptyList();
  168 + long totalDuration = 0;
  169 + // runStatus状态: 0-离线, 1-停机, 2-待机, 3-运行
  170 + Map<Integer, Long> statusDurationMap = new LinkedHashMap<>();
  171 + statusDurationMap.put(0, 0L); // 离线
  172 + statusDurationMap.put(1, 0L); // 停机
  173 + statusDurationMap.put(2, 0L); // 待机
  174 + statusDurationMap.put(3, 0L); // 运行
  175 +
  176 + try {
  177 + String oeeSql = "SELECT runStatus1, runStatus2 FROM " + eRunDtlTableName
  178 + + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";
  179 + Map<String, Object> oeeRow = jdbcTemplate.queryForMap(oeeSql, energyCorpCode, dtuSn, date + " 00:00:00");
  180 + if (oeeRow != null) {
  181 + String rs1 = oeeRow.get("runStatus1") != null ? String.valueOf(oeeRow.get("runStatus1")) : "";
  182 + String rs2 = oeeRow.get("runStatus2") != null ? String.valueOf(oeeRow.get("runStatus2")) : "";
  183 + String jsonStr = rs1 + rs2;
  184 + oeeRawData = JSON.parseArray(jsonStr);
  185 +
  186 + // 统计各状态时长
  187 + JSONArray dataArray = JSON.parseArray(jsonStr);
  188 + for (int i = 0; i < dataArray.size(); i++) {
  189 + JSONObject item = dataArray.getJSONObject(i);
  190 + Long duration = item.getLong("duration");
  191 + Integer runStatus = item.getInteger("runStatus");
  192 +
  193 + if (duration != null && duration > 0) {
  194 + totalDuration += duration;
  195 + int statusKey = runStatus != null ? runStatus : 0;
  196 + statusDurationMap.merge(statusKey, duration, Long::sum);
  197 + }
  198 + }
  199 + }
  200 + } catch (Exception e) {
  201 + log.warn("【能耗明细】查询OEE时序数据为空或异常 - dtuSn:{}, date:{}", dtuSn, date);
  202 + }
  203 +
  204 + // 3. 构建OEE统计结果(含格式化时长和占比)
  205 + List<Map<String, Object>> statusStats = new ArrayList<>();
  206 + for (Map.Entry<Integer, Long> entry : statusDurationMap.entrySet()) {
  207 + long dur = entry.getValue();
  208 + double percent = totalDuration > 0 ? BigDecimal.valueOf(dur * 100.0 / totalDuration)
  209 + .setScale(2, RoundingMode.HALF_UP).doubleValue() : 0.0;
  210 +
  211 + Map<String, Object> stat = new LinkedHashMap<>();
  212 + stat.put("status", entry.getKey());
  213 + stat.put("durationSeconds", dur);
  214 + stat.put("durationFormatted", formatDuration(dur));
  215 + stat.put("percent", percent);
  216 + statusStats.add(stat);
  217 + }
  218 +
  219 + return Map.of(
  220 + "code", 200,
  221 + "msg", "请求成功",
  222 + "dtuSn", dtuSn,
  223 + "date", date,
  224 + "kwhData", Map.of(
  225 + "list", kwhRawData,
  226 + "totalKwh", totalKwh.setScale(2, RoundingMode.HALF_UP)
  227 + ),
  228 + "oeeData", Map.of(
  229 + "list", oeeRawData,
  230 + "totalDurationFormatted", formatDuration(totalDuration),
  231 + "totalDurationSeconds", totalDuration,
  232 + "statusStats", statusStats
  233 + )
  234 + );
  235 + }
  236 +
  237 + /**
  238 + * 格式化时长为 xx时xx分xx秒 格式
  239 + * 时不为0则展示xx时xx分xx秒
  240 + * 时和分都为0则只展示xx秒
  241 + */
  242 + private static String formatDuration(long totalSeconds) {
  243 + long h = totalSeconds / 3600;
  244 + long m = (totalSeconds % 3600) / 60;
  245 + long s = totalSeconds % 60;
  246 + StringBuilder sb = new StringBuilder();
  247 + if (h > 0) sb.append(h).append("时");
  248 + if (h > 0 || m > 0) sb.append(m).append("分");
  249 + sb.append(s).append("秒");
  250 + return sb.toString();
  251 + }
123 } 252 }