增加计算单位可选方法.

优化图形分析根据可选时间补0逻辑,完成度70%。
优化业务自定义95值计算功能修改相关数据方法。
This commit is contained in:
gaoyutao
2025-11-04 19:11:07 +08:00
parent fe1763386a
commit 84e003893d
18 changed files with 438 additions and 53 deletions
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -42,10 +44,244 @@ public class EchartsDataUtils {
return result;
}
/**
* 微秒转秒
*/
public static double convertMicrosecondsToSeconds(long microseconds) {
return microseconds / 1_000_000.0;
}
/**
* 构建ECharts图表数据(带时间补全和0值填充)
* @param list 原始数据列表
* @param timeExtractor 时间字段提取函数
* @param dataExtractors 数据提取器Map
* @param startTime 开始时间字符串(格式:yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间字符串(格式:yyyy-MM-dd HH:mm:ss
* @param <T> 数据类型泛型
* @return 包含xData和yData的Map
*/
public static <T> Map<String, Object> buildEchartsDataAutoPadding(
List<T> list,
Function<T, Date> timeExtractor,
Map<String, Function<T, ?>> dataExtractors,
String startTime,
String endTime) {
try {
// 解析时间字符串
Date startDate = parseStringToDate(startTime);
Date endDate = parseStringToDate(endTime);
if (startDate == null || endDate == null) {
throw new IllegalArgumentException("开始时间或结束时间格式错误");
}
if (startDate.after(endDate)) {
throw new IllegalArgumentException("开始时间不能晚于结束时间");
}
if (list == null || list.isEmpty()) {
return createEmptyResult(dataExtractors.keySet(), startTime, endTime);
}
// 按时间排序
List<T> sortedList = list.stream()
.sorted(Comparator.comparing(timeExtractor))
.collect(Collectors.toList());
// 自动检测时间间隔
long timeInterval = detectTimeInterval(sortedList, timeExtractor);
// 生成完整的时间序列
List<Date> fullTimeSeries = generateTimeSeries(startDate, endDate, timeInterval);
// 创建时间到数据的映射(考虑时间精度)
Map<Long, T> timeDataMap = sortedList.stream()
.collect(Collectors.toMap(
item -> normalizeTime(timeExtractor.apply(item), timeInterval),
Function.identity(),
(a, b) -> a
));
// 准备X轴和Y轴数据
List<String> xAxisData = new ArrayList<>();
Map<String, Object> yData = new LinkedHashMap<>();
// 初始化Y轴数据结构
dataExtractors.keySet().forEach(name ->
yData.put(name, new ArrayList<Object>()));
for (Date time : fullTimeSeries) {
// X轴数据
xAxisData.add(parseDateToStr(time));
// Y轴数据
Long normalizedTime = normalizeTime(time, timeInterval);
T item = timeDataMap.get(normalizedTime);
for (Map.Entry<String, Function<T, ?>> entry : dataExtractors.entrySet()) {
String name = entry.getKey();
Function<T, ?> extractor = entry.getValue();
@SuppressWarnings("unchecked")
List<Object> seriesData = (List<Object>) yData.get(name);
if (item != null) {
Object value = extractor.apply(item);
seriesData.add(value != null ? value : 0);
} else {
seriesData.add(0); // 补0
}
}
}
Map<String, Object> result = new HashMap<>();
result.put("xData", xAxisData);
result.put("yData", yData);
return result;
} catch (Exception e) {
// 记录日志
System.err.println("构建图表数据失败: " + e.getMessage());
return createEmptyResult(dataExtractors.keySet(), startTime, endTime);
}
}
/**
* 字符串转日期
*/
private static Date parseStringToDate(String dateStr) {
if (dateStr == null || dateStr.trim().isEmpty()) {
return null;
}
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setLenient(false); // 严格模式
return sdf.parse(dateStr);
} catch (ParseException e) {
System.err.println("日期解析失败: " + dateStr);
return null;
}
}
/**
* 日期转字符串
*/
private static String parseDateToStr(Date date) {
if (date == null) {
return "";
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
/**
* 生成完整的时间序列
*/
private static List<Date> generateTimeSeries(Date start, Date end, long interval) {
List<Date> timeSeries = new ArrayList<>();
Calendar calendar = Calendar.getInstance();
calendar.setTime(start);
// 确保开始时间对齐到时间间隔
long startMillis = normalizeTime(start, interval);
calendar.setTimeInMillis(startMillis);
while (!calendar.getTime().after(end)) {
timeSeries.add(calendar.getTime());
calendar.setTimeInMillis(calendar.getTimeInMillis() + interval);
}
return timeSeries;
}
/**
* 自动检测时间间隔
*/
private static <T> long detectTimeInterval(List<T> list, Function<T, Date> timeExtractor) {
if (list.size() < 2) {
return 300000; // 默认5分钟
}
// 计算时间间隔的众数
Map<Long, Integer> intervalCount = new HashMap<>();
for (int i = 1; i < list.size(); i++) {
long interval = timeExtractor.apply(list.get(i)).getTime() -
timeExtractor.apply(list.get(i - 1)).getTime();
if (interval > 0) {
intervalCount.merge(interval, 1, Integer::sum);
}
}
// 如果没有有效间隔,使用默认值
if (intervalCount.isEmpty()) {
return 300000L;
}
return intervalCount.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(300000L);
}
/**
* 时间标准化(对齐到时间间隔)
*/
private static long normalizeTime(Date time, long interval) {
long timeMillis = time.getTime();
return (timeMillis / interval) * interval;
}
/**
* 创建空结果(包含完整的时间序列)
*/
private static Map<String, Object> createEmptyResult(Set<String> dataNames, String startTime, String endTime) {
Map<String, Object> result = new HashMap<>();
try {
// 解析时间范围
Date startDate = parseStringToDate(startTime);
Date endDate = parseStringToDate(endTime);
if (startDate != null && endDate != null && !startDate.after(endDate)) {
// 使用默认时间间隔生成完整时间序列
long defaultInterval = 300000L; // 5分钟
List<Date> fullTimeSeries = generateTimeSeries(startDate, endDate, defaultInterval);
// 构建x轴数据
List<String> xAxisData = new ArrayList<>();
for (Date date : fullTimeSeries) {
xAxisData.add(parseDateToStr(date));
}
result.put("xData", xAxisData);
// 构建y轴数据(全部补0
Map<String, Object> yData = new LinkedHashMap<>();
int dataSize = xAxisData.size();
dataNames.forEach(name -> {
List<Object> zeroData = new ArrayList<>();
for (int i = 0; i < dataSize; i++) {
zeroData.add(0);
}
yData.put(name, zeroData);
});
result.put("yData", yData);
} else {
// 时间解析失败时返回空数据
result.put("xData", new ArrayList<>());
Map<String, Object> yData = new LinkedHashMap<>();
dataNames.forEach(name -> yData.put(name, new ArrayList<>()));
result.put("yData", yData);
}
} catch (Exception e) {
// 异常时返回空数据
result.put("xData", new ArrayList<>());
Map<String, Object> yData = new LinkedHashMap<>();
dataNames.forEach(name -> yData.put(name, new ArrayList<>()));
result.put("yData", yData);
}
return result;
}
}
@@ -0,0 +1,19 @@
package com.ruoyi.common.core.utils;
public class UnitChangeUtil {
private static final double GB = 1024.0 * 1024.0 * 1024.0;
public static double bytesToGb(long bytes) {
return bytes / GB;
}
public static double convertKbToGb(String kbValue) {
if (kbValue == null || kbValue.trim().isEmpty()) {
throw new IllegalArgumentException("KB值不能为空");
}
double kb = Double.parseDouble(kbValue.trim());
return kb / (1024.0 * 1024.0);
}
}