增加计算单位可选方法.
优化图形分析根据可选时间补0逻辑,完成度70%。 优化业务自定义95值计算功能修改相关数据方法。
This commit is contained in:
+236
@@ -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;
|
||||
}
|
||||
}
|
||||
+19
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user