设备运行概览接口

main
liutao 2 weeks ago
parent 5c1055b821
commit b85e6e7360

@ -127,6 +127,13 @@ public class DeviceOperationRecordController {
return success(deviceTotalTimeRecordRespVOList); return success(deviceTotalTimeRecordRespVOList);
} }
@GetMapping("/runOverview")
@Operation(summary = "设备运行总览")
@PreAuthorize("@ss.hasPermission('iot:device-operation-record:query')")
public CommonResult<DeviceOperationOverviewRespVO> runOverview(@Valid DeviceTotalTimeRecordReqVO pageReqVO) {
return success(deviceOperationRecordService.runOverview(pageReqVO));
}
@GetMapping("/export-device-operation-report") @GetMapping("/export-device-operation-report")
@Operation(summary = "导出设备运行报表记录 Excel") @Operation(summary = "导出设备运行报表记录 Excel")

@ -2742,6 +2742,50 @@ public class TDengineService {
} }
} }
@DS("tdengine")
public List<Map<String, Object>> queryDeviceHourTrend(List<Long> deviceIds, String startTime, String endTime) {
StringBuilder sql = new StringBuilder();
List<Object> params = new ArrayList<>();
sql.append("SELECT ")
.append("HOUR(_wstart) AS hourValue, ")
.append("SUM(CASE WHEN rule = '0' THEN 1 ELSE 0 END) * 60 AS totalOfflineTime, ")
.append("SUM(CASE WHEN rule = '1' THEN 1 ELSE 0 END) * 60 AS totalRunningTime, ")
.append("SUM(CASE WHEN rule = '2' THEN 1 ELSE 0 END) * 60 AS totalStandbyTime, ")
.append("SUM(CASE WHEN rule = '3' THEN 1 ELSE 0 END) * 60 AS totalFaultTime ")
.append("FROM besure_server.iot_device_operation_record ")
.append("WHERE deleted = 0 ");
if (startTime != null && !startTime.trim().isEmpty()) {
sql.append("AND create_time >= ? ");
params.add(startTime);
}
if (endTime != null && !endTime.trim().isEmpty()) {
sql.append("AND create_time <= ? ");
params.add(endTime);
}
if (deviceIds != null && !deviceIds.isEmpty()) {
sql.append("AND device_id IN (");
for (int i = 0; i < deviceIds.size(); i++) {
if (i > 0) {
sql.append(", ");
}
sql.append("?");
params.add(deviceIds.get(i));
}
sql.append(") ");
}
sql.append("INTERVAL(1h) ORDER BY _wstart ASC");
try {
return jdbcTemplate.queryForList(sql.toString(), params.toArray());
} catch (Exception e) {
log.error("TDengine 查询设备小时趋势失败sql={}, params={}", sql, params, e);
return Collections.emptyList();
}
}

@ -59,4 +59,6 @@ public interface DeviceOperationRecordService {
List<DeviceOperationRateTrendRespVO> getDeviceRateTrendByDeviceId(Long deviceId, String period); List<DeviceOperationRateTrendRespVO> getDeviceRateTrendByDeviceId(Long deviceId, String period);
List<DeviceTotalTimeRecordRespVO> deviceOperationList(@Valid DeviceTotalTimeRecordReqVO pageReqVO); List<DeviceTotalTimeRecordRespVO> deviceOperationList(@Valid DeviceTotalTimeRecordReqVO pageReqVO);
DeviceOperationOverviewRespVO runOverview(@Valid DeviceTotalTimeRecordReqVO pageReqVO);
} }

@ -16,7 +16,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.*; import java.time.*;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -451,6 +450,46 @@ public class DeviceOperationRecordServiceImpl implements DeviceOperationRecordSe
return lineList; return lineList;
} }
@Override
public DeviceOperationOverviewRespVO runOverview(DeviceTotalTimeRecordReqVO pageReqVO) {
applyPeriodIfNecessary(pageReqVO);
List<DeviceTotalTimeRecordRespVO> records = deviceOperationPageList(pageReqVO);
DeviceOperationOverviewRespVO respVO = new DeviceOperationOverviewRespVO();
double totalRunningHours = records.stream().mapToDouble(DeviceTotalTimeRecordRespVO::getTotalRunningTime).sum();
double totalStandbyHours = records.stream().mapToDouble(DeviceTotalTimeRecordRespVO::getTotalStandbyTime).sum();
double totalFaultHours = records.stream().mapToDouble(DeviceTotalTimeRecordRespVO::getTotalFaultTime).sum();
double totalOfflineHours = records.stream().mapToDouble(DeviceTotalTimeRecordRespVO::getTotalOfflineTime).sum();
double onlineHours = totalRunningHours + totalStandbyHours + totalFaultHours;
double totalHours = onlineHours + totalOfflineHours;
double utilizationRate = onlineHours > 0 ? totalRunningHours / onlineHours * 100 : 0D;
double powerOnRate = totalHours > 0 ? onlineHours / totalHours * 100 : 0D;
double faultRate = onlineHours > 0 ? totalFaultHours / onlineHours * 100 : 0D;
double standbyRate = onlineHours > 0 ? totalStandbyHours / onlineHours * 100 : 0D;
respVO.setMetrics(Arrays.asList(
DeviceOperationOverviewRespVO.MetricItem.builder().key("utilizationRate").icon("ep:pie-chart").value(round2(utilizationRate)).unit("%").change(0D).build(),
DeviceOperationOverviewRespVO.MetricItem.builder().key("powerOnRate").icon("ep:video-play").value(round2(powerOnRate)).unit("%").change(0D).build(),
DeviceOperationOverviewRespVO.MetricItem.builder().key("faultRate").icon("ep:warning").value(round2(faultRate)).unit("%").change(0D).build(),
DeviceOperationOverviewRespVO.MetricItem.builder().key("standbyRate").icon("ep:timer").value(round2(standbyRate)).unit("%").change(0D).build()
));
respVO.setSummary(Arrays.asList(
DeviceOperationOverviewRespVO.SummaryItem.builder().status("running").percent(toPercent(totalRunningHours, totalHours)).hours(round2(totalRunningHours)).build(),
DeviceOperationOverviewRespVO.SummaryItem.builder().status("standby").percent(toPercent(totalStandbyHours, totalHours)).hours(round2(totalStandbyHours)).build(),
DeviceOperationOverviewRespVO.SummaryItem.builder().status("fault").percent(toPercent(totalFaultHours, totalHours)).hours(round2(totalFaultHours)).build(),
DeviceOperationOverviewRespVO.SummaryItem.builder().status("offline").percent(toPercent(totalOfflineHours, totalHours)).hours(round2(totalOfflineHours)).build()
));
respVO.setSummaryTotalHours(round2(totalHours));
List<Long> deviceIds = parseIds(pageReqVO.getIds());
List<Map<String, Object>> hourlyRows = tDengineService.queryDeviceHourTrend(deviceIds, pageReqVO.getStartTime(), pageReqVO.getEndTime());
respVO.setHourlyStatus(buildHourlyStatus(hourlyRows));
return respVO;
}
private double parsePercentValue(DeviceTotalTimeRecordRespVO record) { private double parsePercentValue(DeviceTotalTimeRecordRespVO record) {
if (record == null || StringUtils.isBlank(record.getUtilizationRate())) { if (record == null || StringUtils.isBlank(record.getUtilizationRate())) {
return 0D; return 0D;
@ -458,6 +497,88 @@ public class DeviceOperationRecordServiceImpl implements DeviceOperationRecordSe
return Double.parseDouble(record.getUtilizationRate().replace("%", "").trim()); return Double.parseDouble(record.getUtilizationRate().replace("%", "").trim());
} }
private List<Long> parseIds(String ids) {
if (StringUtils.isBlank(ids)) {
return Collections.emptyList();
}
return Arrays.stream(ids.split(","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.map(Long::valueOf)
.distinct()
.collect(Collectors.toList());
}
private List<DeviceOperationOverviewRespVO.HourlyStatusItem> buildHourlyStatus(List<Map<String, Object>> hourlyRows) {
Map<String, HourBucket> bucketMap = new LinkedHashMap<>();
for (int i = 0; i < 24; i++) {
String hour = String.format("%02d:00", i);
bucketMap.put(hour, new HourBucket(hour));
}
for (Map<String, Object> row : hourlyRows) {
Integer hourValue = getIntValue(row, "hourValue");
if (hourValue == null || hourValue < 0 || hourValue > 23) {
continue;
}
String hour = String.format("%02d:00", hourValue);
HourBucket bucket = bucketMap.get(hour);
if (bucket == null) {
continue;
}
bucket.offline += getDoubleValue(row, "totalofflinetime");
bucket.running += getDoubleValue(row, "totalrunningtime");
bucket.standby += getDoubleValue(row, "totalstandbytime");
bucket.fault += getDoubleValue(row, "totalfaulttime");
}
return bucketMap.values().stream().map(bucket -> {
double total = bucket.running + bucket.standby + bucket.fault + bucket.offline;
return DeviceOperationOverviewRespVO.HourlyStatusItem.builder()
.hour(bucket.hour)
.running(total > 0 ? round2(bucket.running / total * 100) : 0D)
.standby(total > 0 ? round2(bucket.standby / total * 100) : 0D)
.fault(total > 0 ? round2(bucket.fault / total * 100) : 0D)
.offline(total > 0 ? round2(bucket.offline / total * 100) : 0D)
.build();
}).collect(Collectors.toList());
}
private double toPercent(double numerator, double denominator) {
return denominator > 0 ? round2(numerator / denominator * 100) : 0D;
}
private double round2(double value) {
return Math.round(value * 100D) / 100D;
}
private double getDoubleValue(Map<String, Object> map, String key) {
Object value = map.get(key);
if (value == null) {
return 0D;
}
if (value instanceof Number) {
return ((Number) value).doubleValue() / 3600D;
}
try {
return Double.parseDouble(String.valueOf(value)) / 3600D;
} catch (Exception e) {
return 0D;
}
}
private static class HourBucket {
private final String hour;
private double running;
private double standby;
private double fault;
private double offline;
private HourBucket(String hour) {
this.hour = hour;
}
}
private void calculateAndSetConvertedValues( private void calculateAndSetConvertedValues(
List<DeviceTotalTimeRecordRespVO> records, List<DeviceTotalTimeRecordRespVO> records,
DeviceTotalTimeRecordReqVO reqVO) { DeviceTotalTimeRecordReqVO reqVO) {

Loading…
Cancel
Save