Browse Source

图表按半小时一条数据显示

master
review512jwy@163.com 1 month ago
parent
commit
316243a512
  1. 3
      dongjian-dashboard-back-controller/src/main/java/com/dongjian/dashboard/back/controller/DeviceDataAccumulateController.java
  2. 2
      dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/DeviceDataAccumulateService.java
  3. 42
      dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/common/CommonOpt.java
  4. 126
      dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/common/LineDataHourAggregator.java
  5. 15
      dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/impl/DeviceDataAccumulateServiceImpl.java
  6. 5
      dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/impl/DeviceDataMeasureServiceImpl.java

3
dongjian-dashboard-back-controller/src/main/java/com/dongjian/dashboard/back/controller/DeviceDataAccumulateController.java

@ -116,6 +116,7 @@ public class DeviceDataAccumulateController {
@Operation(summary = "获取7日趋势数据") @Operation(summary = "获取7日趋势数据")
@RequestMapping(value = "/getLineData",method = RequestMethod.POST) @RequestMapping(value = "/getLineData",method = RequestMethod.POST)
public SimpleDataResponse<List<LineData>> getLineData( public SimpleDataResponse<List<LineData>> getLineData(
@Parameter(name = "searchType", description = "1-按小时,2-全部数据", required = true) Integer searchType,
@Parameter(name = "LoginName", description = "Login name", required = true, schema = @Schema(defaultValue = "admin")) @RequestHeader(required=true) String LoginName, @Parameter(name = "LoginName", description = "Login name", required = true, schema = @Schema(defaultValue = "admin")) @RequestHeader(required=true) String LoginName,
@Parameter(name = "AccessToken", description = "Authentication token", required = true) @RequestHeader(required=true) String AccessToken, @Parameter(name = "AccessToken", description = "Authentication token", required = true) @RequestHeader(required=true) String AccessToken,
@Parameter(name = "UserId", description = "User ID", required = true, schema = @Schema(defaultValue = "1")) @RequestHeader(required=true) Long UserId, @Parameter(name = "UserId", description = "User ID", required = true, schema = @Schema(defaultValue = "1")) @RequestHeader(required=true) Long UserId,
@ -123,7 +124,7 @@ public class DeviceDataAccumulateController {
@Parameter(name = "LanguageType", description = "Language type (0: Chinese, 1: English, 2: Japanese)", required = true, schema = @Schema(defaultValue = "2")) @RequestHeader(required=true) Integer LanguageType, @Parameter(name = "LanguageType", description = "Language type (0: Chinese, 1: English, 2: Japanese)", required = true, schema = @Schema(defaultValue = "2")) @RequestHeader(required=true) Integer LanguageType,
@RequestBody LineDataSearchParams lineDataSearchParams @RequestBody LineDataSearchParams lineDataSearchParams
) throws BusinessException { ) throws BusinessException {
return deviceDataAccumulateService.getLineData(lineDataSearchParams, CompanyId, UserId, LanguageType); return deviceDataAccumulateService.getLineData(searchType, lineDataSearchParams, CompanyId, UserId, LanguageType);
} }
} }

2
dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/DeviceDataAccumulateService.java

@ -18,5 +18,5 @@ public interface DeviceDataAccumulateService {
List<DeviceAccumulateData> handleDeviceAccumulateData(AccumulateDataSearchParam pageSearchParam); List<DeviceAccumulateData> handleDeviceAccumulateData(AccumulateDataSearchParam pageSearchParam);
SimpleDataResponse<List<LineData>> getLineData(LineDataSearchParams lineDataSearchParams, Long companyId, Long userId, Integer languageType); SimpleDataResponse<List<LineData>> getLineData(Integer searchType, LineDataSearchParams lineDataSearchParams, Long companyId, Long userId, Integer languageType);
} }

42
dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/common/CommonOpt.java

@ -445,56 +445,44 @@ public class CommonOpt {
private void processResult(ResultSet result, LineData lineData, DeviceInfo deviceInfo, Double lastDayValue) { private void processResult(ResultSet result, LineData lineData, DeviceInfo deviceInfo, Double lastDayValue) {
try { try {
// 用于存储 xData 和 yData
List<Object> xDataList = new ArrayList<>(); List<Object> xDataList = new ArrayList<>();
List<Object> yDataList = new ArrayList<>(); List<Object> yDataList = new ArrayList<>();
// 使用 DateTimeFormatter 来格式化时间 DateTimeFormatter formatter =
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
ObjectMapper mapper = new ObjectMapper();
// 用于存储每个小时最后一条数据(仅在 deviceType = 2 时使用) ZoneId JST = ZoneId.of("Asia/Tokyo");
Map<String, Double> lastHourData = new LinkedHashMap<>(); // 按插入顺序保存数据
// 遍历查询结果
do { do {
// 获取 receive_ts 和 rawData
long receiveTs = result.getLong("upload_at"); long receiveTs = result.getLong("upload_at");
String value = result.getString("upload_value"); String value = result.getString("upload_value");
// 如果 receiveTs 为 0(表示无效时间戳),跳过当前行
if (receiveTs == 0) { if (receiveTs == 0) {
continue; // 跳过当前循环的剩余部分,继续处理下一行 continue;
} }
// 将 long 时间戳转换为 LocalDateTime(日本时区) // 日本时区时间
Instant instant = Instant.ofEpochMilli(receiveTs); Instant instant = Instant.ofEpochMilli(receiveTs);
String formattedDate = instant.atZone(ZoneId.of("Asia/Tokyo")) String formattedDate = instant
.atZone(JST)
.toLocalDateTime() .toLocalDateTime()
.format(formatter); .format(formatter);
// 将 rawData解析 添加到 yData
// String value = extractFirstValue(mapper, rawData);
double todayValue = StringUtils.isBlank(value) ? 0.0 : new BigDecimal(value).doubleValue(); double todayValue = StringUtils.isBlank(value) ? 0.0 : new BigDecimal(value).doubleValue();
//计算差值 // 默认今天值
double yValue = todayValue;//默认今天值 double yValue = todayValue;
if (null != lastDayValue && yValue >= lastDayValue){
// 计算差值
if (lastDayValue != null && todayValue >= lastDayValue) {
yValue = todayValue - lastDayValue; yValue = todayValue - lastDayValue;
} }
// 按小时分组,每个小时只保存最后一条数据
String hourKey = formattedDate.substring(0, 13) + ":00:00";
lastHourData.put(hourKey, yValue);
} while (result.next()); xDataList.add(formattedDate);
yDataList.add(CommonUtil.formatDecimal(yValue, deviceInfo.getDashboardDecimalPlaces()));
//只取每小时的最后一条数据 } while (result.next());
for (Map.Entry<String, Double> entry : lastHourData.entrySet()) {
xDataList.add(entry.getKey()); // 添加每小时的时间
yDataList.add(CommonUtil.formatDecimal(entry.getValue(), deviceInfo.getDashboardDecimalPlaces())); // 添加每小时最后一条数据的值
}
// 将处理后的数据加入到 lineData 中
lineData.getXData().addAll(xDataList); lineData.getXData().addAll(xDataList);
lineData.getYData().addAll(yDataList); lineData.getYData().addAll(yDataList);

126
dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/common/LineDataHourAggregator.java

@ -2,12 +2,11 @@ package com.dongjian.dashboard.back.service.common;
import com.dongjian.dashboard.back.vo.device.LineData; import com.dongjian.dashboard.back.vo.device.LineData;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/** /**
* 给计测设备按小时聚合数据求平均值 * 给计测设备按小时聚合数据求平均值
@ -65,5 +64,124 @@ public class LineDataHourAggregator {
lineData.setXData(newX); lineData.setXData(newX);
lineData.setYData(newY); lineData.setYData(newY);
} }
/**
* 给计测设备按半小时聚合数据求平均值
* 00~29 HH:00:00
* 30~59 HH:30:00
*/
public static void aggregateAverageByHalfHour(LineData lineData) {
List<Object> xData = lineData.getXData();
List<Object> yData = lineData.getYData();
if (xData == null || yData == null || xData.size() != yData.size()) {
return;
}
// halfHour -> List<Double>
Map<String, List<Double>> halfHourMap = new TreeMap<>();
for (int i = 0; i < xData.size(); i++) {
String timeStr = String.valueOf(xData.get(i));
Object yVal = yData.get(i);
if (yVal == null) {
continue;
}
LocalDateTime time = LocalDateTime.parse(timeStr, INPUT_FMT);
int minute = time.getMinute();
int halfHourMinute = minute < 30 ? 0 : 30;
LocalDateTime halfHourTime = time
.withMinute(halfHourMinute)
.withSecond(0)
.withNano(0);
String halfHourKey = halfHourTime.format(INPUT_FMT);
halfHourMap
.computeIfAbsent(halfHourKey, k -> new ArrayList<>())
.add(Double.parseDouble(String.valueOf(yVal)));
}
// 重新构建 xData / yData
List<Object> newX = new ArrayList<>();
List<Object> newY = new ArrayList<>();
for (Map.Entry<String, List<Double>> entry : halfHourMap.entrySet()) {
newX.add(entry.getKey());
double avg = entry.getValue()
.stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(0);
newY.add(avg);
}
lineData.setXData(newX);
lineData.setYData(newY);
}
/**
* 按半小时聚合只保留每个半小时内的最后一条数据
*/
public static void aggregateLastByHalfHour(LineData lineData) {
List<Object> xData = lineData.getXData();
List<Object> yData = lineData.getYData();
if (xData == null || yData == null || xData.size() != yData.size()) {
return;
}
// halfHour -> lastValue
Map<String, Double> halfHourLastMap = new TreeMap<>();
for (int i = 0; i < xData.size(); i++) {
String timeStr = String.valueOf(xData.get(i));
Object yVal = yData.get(i);
if (yVal == null) {
continue;
}
LocalDateTime time = LocalDateTime.parse(timeStr, INPUT_FMT);
int minute = time.getMinute();
int halfHourMinute = minute < 30 ? 0 : 30;
LocalDateTime halfHourTime = time
.withMinute(halfHourMinute)
.withSecond(0)
.withNano(0);
String halfHourKey = halfHourTime.format(INPUT_FMT);
// 同一个半小时,后面的会覆盖前面的 → 自然就是“最后一条”
halfHourLastMap.put(
halfHourKey,
Double.parseDouble(String.valueOf(yVal))
);
}
// 重新构建 xData / yData
List<Object> newX = new ArrayList<>();
List<Object> newY = new ArrayList<>();
for (Map.Entry<String, Double> entry : halfHourLastMap.entrySet()) {
newX.add(entry.getKey());
newY.add(entry.getValue());
}
lineData.setXData(newX);
lineData.setYData(newY);
}
} }

15
dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/impl/DeviceDataAccumulateServiceImpl.java

@ -22,6 +22,7 @@ import com.dongjian.dashboard.back.dto.device.LineDataSearchParams;
import com.dongjian.dashboard.back.model.DeviceRawdataRealtime; import com.dongjian.dashboard.back.model.DeviceRawdataRealtime;
import com.dongjian.dashboard.back.service.DeviceDataAccumulateService; import com.dongjian.dashboard.back.service.DeviceDataAccumulateService;
import com.dongjian.dashboard.back.service.common.CommonOpt; import com.dongjian.dashboard.back.service.common.CommonOpt;
import com.dongjian.dashboard.back.service.common.LineDataHourAggregator;
import com.dongjian.dashboard.back.util.CommonUtil; import com.dongjian.dashboard.back.util.CommonUtil;
import com.dongjian.dashboard.back.util.DateUtil; import com.dongjian.dashboard.back.util.DateUtil;
import com.dongjian.dashboard.back.vo.data.DeviceAccumulateData; import com.dongjian.dashboard.back.vo.data.DeviceAccumulateData;
@ -183,9 +184,19 @@ public class DeviceDataAccumulateServiceImpl implements DeviceDataAccumulateServ
} }
@Override @Override
public SimpleDataResponse<List<LineData>> getLineData(LineDataSearchParams lineDataSearchParams, public SimpleDataResponse<List<LineData>> getLineData(Integer searchType, LineDataSearchParams lineDataSearchParams,
Long companyId, Long userId, Integer languageType) { Long companyId, Long userId, Integer languageType) {
return SimpleDataResponse.success(commonOpt.getLineData(companyId, lineDataSearchParams, 2)); if (null == searchType) {
searchType = 2;//默认全部数据
}
List<LineData> lineDataList = commonOpt.getLineData(companyId, lineDataSearchParams, 2);
if (1 == searchType && CollectionUtils.isNotEmpty(lineDataList)) {
lineDataList.forEach(lineData -> {
//按半小时聚合
LineDataHourAggregator.aggregateLastByHalfHour(lineData);
});
}
return SimpleDataResponse.success(lineDataList);
} }

5
dongjian-dashboard-back-service/src/main/java/com/dongjian/dashboard/back/service/impl/DeviceDataMeasureServiceImpl.java

@ -238,7 +238,10 @@ public class DeviceDataMeasureServiceImpl implements DeviceDataMeasureService {
} }
List<LineData> lineDataList = commonOpt.getLineData(companyId, lineDataSearchParams, 3); List<LineData> lineDataList = commonOpt.getLineData(companyId, lineDataSearchParams, 3);
if (1 == searchType && CollectionUtils.isNotEmpty(lineDataList)) { if (1 == searchType && CollectionUtils.isNotEmpty(lineDataList)) {
lineDataList.forEach(LineDataHourAggregator::aggregateByHour); lineDataList.forEach(lineData -> {
//按半小时聚合
LineDataHourAggregator.aggregateAverageByHalfHour(lineData);
});
} }
return SimpleDataResponse.success(lineDataList); return SimpleDataResponse.success(lineDataList);
} }

Loading…
Cancel
Save