|
@ -8,8 +8,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
|
|
import com.ruoyi.common.exception.ServiceException; |
|
|
import com.ruoyi.common.exception.ServiceException; |
|
|
import com.zc.business.domain.DcGantryMetricsStatisticsData; |
|
|
import com.zc.business.domain.DcGantryMetricsStatisticsData; |
|
|
import com.zc.business.domain.DcGantryStatisticsData; |
|
|
|
|
|
import com.zc.business.enums.ChannelCongestionLevelEnum; |
|
|
import com.zc.business.enums.ChannelCongestionLevelEnum; |
|
|
|
|
|
import com.zc.business.enums.StakeMarkRange; |
|
|
import com.zc.business.enums.TrafficCompositionRateEnum; |
|
|
import com.zc.business.enums.TrafficCompositionRateEnum; |
|
|
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|
|
import com.zc.business.enums.TrafficDataPeriodTypeEnum; |
|
|
import com.zc.business.mapper.DcGantryMetricsStatisticsDataMapper; |
|
|
import com.zc.business.mapper.DcGantryMetricsStatisticsDataMapper; |
|
@ -28,9 +28,11 @@ import org.springframework.stereotype.Service; |
|
|
import javax.annotation.PostConstruct; |
|
|
import javax.annotation.PostConstruct; |
|
|
import javax.annotation.Resource; |
|
|
import javax.annotation.Resource; |
|
|
import java.io.IOException; |
|
|
import java.io.IOException; |
|
|
import java.util.ArrayList; |
|
|
import java.time.LocalDateTime; |
|
|
import java.util.Date; |
|
|
import java.util.*; |
|
|
import java.util.List; |
|
|
import java.util.regex.Matcher; |
|
|
|
|
|
import java.util.regex.Pattern; |
|
|
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 门架指标统计服务实现类,负责处理实时设备消息、缓存数据、定时任务以及数据保存等功能。 |
|
|
* 门架指标统计服务实现类,负责处理实时设备消息、缓存数据、定时任务以及数据保存等功能。 |
|
@ -162,6 +164,226 @@ public class IDcGantryMetricsStatisticsDataServiceImpl |
|
|
return list(queryWrapper); |
|
|
return list(queryWrapper); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 路段交通指标分析 |
|
|
|
|
|
* |
|
|
|
|
|
* @param startDate |
|
|
|
|
|
* @param direction |
|
|
|
|
|
* @param periodType |
|
|
|
|
|
* @return |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
public List<Map<String, Object>> sectionTrafficIndexAnalysis(String startDate, String direction, String periodType, int ranking) { |
|
|
|
|
|
List<Map<String, Object>> mapListOne = gantryMetricsStatisticsDataMapper.sectionTrafficIndexAnalysis(startDate, direction, periodType); |
|
|
|
|
|
List<Map<String, Object>> mapList = new ArrayList<>(); |
|
|
|
|
|
Map<Integer, List<Map<String, Object>>> result = mapListOne.stream() |
|
|
|
|
|
.collect(Collectors.groupingBy(map -> { |
|
|
|
|
|
String stakeMark = map.get("stakeMark").toString(); |
|
|
|
|
|
int extractedNumber = Integer.parseInt(extract(stakeMark)); |
|
|
|
|
|
return Arrays.stream(StakeMarkRange.values()) |
|
|
|
|
|
.filter(smRange -> extractedNumber >= smRange.getStakeMark() && extractedNumber <= smRange.getEndMark()) |
|
|
|
|
|
.mapToInt(StakeMarkRange::getIdentification) |
|
|
|
|
|
.findFirst() |
|
|
|
|
|
.orElse(0); |
|
|
|
|
|
})); |
|
|
|
|
|
// 处理每个组
|
|
|
|
|
|
for (Map.Entry<Integer, List<Map<String, Object>>> entry : result.entrySet()) { |
|
|
|
|
|
Integer groupId = entry.getKey(); |
|
|
|
|
|
List<Map<String, Object>> groupData = entry.getValue(); |
|
|
|
|
|
|
|
|
|
|
|
// 计算crowdingRate和trafficCompositionRate的众数,以及saturationRate的平均值
|
|
|
|
|
|
int[] rates = {0, 0}; // 用于存储众数,第一个元素为crowdingRate众数,第二个为trafficCompositionRate众数
|
|
|
|
|
|
float sumSaturationRate = 0; |
|
|
|
|
|
int count = groupData.size(); |
|
|
|
|
|
String id = ""; |
|
|
|
|
|
Map<Integer, Integer> crowdingRateCounts = new HashMap<>(); |
|
|
|
|
|
Map<Integer, Integer> trafficCompositionRateCounts = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
|
|
for (Map<String, Object> item : groupData) { |
|
|
|
|
|
Integer crowdingRate = (Integer) item.get("crowdingRate"); |
|
|
|
|
|
Integer trafficCompositionRate = (Integer) item.get("trafficCompositionRate"); |
|
|
|
|
|
Float saturationRate = (Float) item.get("saturationRate"); |
|
|
|
|
|
id = (String) item.get("id"); |
|
|
|
|
|
|
|
|
|
|
|
// Double saturationRate = (Double) item.get("saturationRate");
|
|
|
|
|
|
|
|
|
|
|
|
sumSaturationRate += saturationRate; |
|
|
|
|
|
|
|
|
|
|
|
crowdingRateCounts.put(crowdingRate, crowdingRateCounts.getOrDefault(crowdingRate, 0) + 1); |
|
|
|
|
|
trafficCompositionRateCounts.put(trafficCompositionRate, trafficCompositionRateCounts.getOrDefault(trafficCompositionRate, 0) + 1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 找到众数
|
|
|
|
|
|
rates[0] = findMaxCountKey(crowdingRateCounts); |
|
|
|
|
|
rates[1] = findMaxCountKey(trafficCompositionRateCounts); |
|
|
|
|
|
|
|
|
|
|
|
// 计算平均saturationRate
|
|
|
|
|
|
double avgSaturationRate = count > 0 ? sumSaturationRate / count : 0; |
|
|
|
|
|
|
|
|
|
|
|
// 格式化保留4位小数
|
|
|
|
|
|
String formattedAvgSaturationRate = String.format("%.4f", avgSaturationRate); |
|
|
|
|
|
Map<String, Object> map = new HashMap<>(); |
|
|
|
|
|
String description = getDescriptionByIdentification(groupId); |
|
|
|
|
|
|
|
|
|
|
|
map.put("groupId", groupId); |
|
|
|
|
|
map.put("Id", id); |
|
|
|
|
|
map.put("groupName", description); |
|
|
|
|
|
map.put("crowdingRate", rates[0]); |
|
|
|
|
|
map.put("trafficCompositionRate", rates[1]); |
|
|
|
|
|
map.put("saturationRate", formattedAvgSaturationRate); |
|
|
|
|
|
mapList.add(map); |
|
|
|
|
|
// System.out.println("集团: " + groupId);
|
|
|
|
|
|
// System.out.println("拥堵度" + rates[0]);
|
|
|
|
|
|
// System.out.println("交通组成特征指数" + rates[1]);
|
|
|
|
|
|
// System.out.println("平均饱和度:" + formattedAvgSaturationRate);
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
if (ranking == 1) { |
|
|
|
|
|
mapList.sort(Comparator.comparingInt(map -> (Integer) ((Map<String, Object>) map).get("saturationRate")).reversed()); |
|
|
|
|
|
} |
|
|
|
|
|
if (ranking == 2) { |
|
|
|
|
|
mapList.sort(Comparator.comparingInt(map -> (Integer) ((Map<String, Object>) map).get("crowdingRate")).reversed()); |
|
|
|
|
|
} |
|
|
|
|
|
if (ranking == 3) { |
|
|
|
|
|
mapList.sort(Comparator.comparingInt(map -> (Integer) ((Map<String, Object>) map).get("trafficCompositionRate")).reversed()); |
|
|
|
|
|
} |
|
|
|
|
|
return mapList; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 交通指标时间分布 |
|
|
|
|
|
* |
|
|
|
|
|
* @param startDate |
|
|
|
|
|
* @param direction |
|
|
|
|
|
* @param periodType |
|
|
|
|
|
* @return |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
public List<Map<String, Object>> passIndicatorTimeDistribution(String startDate, String direction, String periodType) { |
|
|
|
|
|
List<Map<String, Object>> mapList = gantryMetricsStatisticsDataMapper.sectionTrafficIndexAnalysis(startDate, direction, periodType); |
|
|
|
|
|
List<Map<String, Object>> mapTime = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
|
|
// 使用 Java流按照相同时间分组
|
|
|
|
|
|
Map<LocalDateTime, List<Map<String, Object>>> result = mapList.stream() |
|
|
|
|
|
.collect(Collectors.groupingBy( |
|
|
|
|
|
map -> (LocalDateTime) map.get("statisticalDate"), |
|
|
|
|
|
Collectors.toList() |
|
|
|
|
|
)); |
|
|
|
|
|
// 处理每个组
|
|
|
|
|
|
for (Map.Entry<LocalDateTime, List<Map<String, Object>>> entry : result.entrySet()) { |
|
|
|
|
|
LocalDateTime groupId = entry.getKey(); |
|
|
|
|
|
List<Map<String, Object>> groupData = entry.getValue(); |
|
|
|
|
|
|
|
|
|
|
|
// 计算crowdingRate和trafficCompositionRate的众数,以及saturationRate的平均值
|
|
|
|
|
|
int[] rates = {0, 0}; // 用于存储众数,第一个元素为crowdingRate众数,第二个为trafficCompositionRate众数
|
|
|
|
|
|
float sumSaturationRate = 0; |
|
|
|
|
|
int count = groupData.size(); |
|
|
|
|
|
String id = ""; |
|
|
|
|
|
Map<Integer, Integer> crowdingRateCounts = new HashMap<>(); |
|
|
|
|
|
Map<Integer, Integer> trafficCompositionRateCounts = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
|
|
for (Map<String, Object> item : groupData) { |
|
|
|
|
|
Integer crowdingRate = (Integer) item.get("crowdingRate"); |
|
|
|
|
|
Integer trafficCompositionRate = (Integer) item.get("trafficCompositionRate"); |
|
|
|
|
|
Float saturationRate = (Float) item.get("saturationRate"); |
|
|
|
|
|
id = (String) item.get("id"); |
|
|
|
|
|
|
|
|
|
|
|
// Double saturationRate = (Double) item.get("saturationRate");
|
|
|
|
|
|
|
|
|
|
|
|
sumSaturationRate += saturationRate; |
|
|
|
|
|
|
|
|
|
|
|
crowdingRateCounts.put(crowdingRate, crowdingRateCounts.getOrDefault(crowdingRate, 0) + 1); |
|
|
|
|
|
trafficCompositionRateCounts.put(trafficCompositionRate, trafficCompositionRateCounts.getOrDefault(trafficCompositionRate, 0) + 1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 找到众数
|
|
|
|
|
|
rates[0] = findMaxCountKey(crowdingRateCounts); |
|
|
|
|
|
rates[1] = findMaxCountKey(trafficCompositionRateCounts); |
|
|
|
|
|
|
|
|
|
|
|
// 计算平均saturationRate
|
|
|
|
|
|
double avgSaturationRate = count > 0 ? sumSaturationRate / count : 0; |
|
|
|
|
|
|
|
|
|
|
|
// 格式化保留4位小数
|
|
|
|
|
|
String formattedAvgSaturationRate = String.format("%.4f", avgSaturationRate); |
|
|
|
|
|
Map<String, Object> map = new HashMap<>(); |
|
|
|
|
|
map.put("groupTime", groupId); |
|
|
|
|
|
map.put("Id", id); |
|
|
|
|
|
map.put("crowdingRate", rates[0]); |
|
|
|
|
|
map.put("trafficCompositionRate", rates[1]); |
|
|
|
|
|
map.put("saturationRate", formattedAvgSaturationRate); |
|
|
|
|
|
mapTime.add(map); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 输出结果
|
|
|
|
|
|
result.forEach((date, data) -> { |
|
|
|
|
|
System.out.println("统计日期:" + date); |
|
|
|
|
|
data.forEach(entry -> { |
|
|
|
|
|
entry.forEach((key, value) -> { |
|
|
|
|
|
System.out.println(key + ": " + value); |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
return mapTime; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 交通指标雷达图 |
|
|
|
|
|
* @param startDate |
|
|
|
|
|
* @param direction |
|
|
|
|
|
* @param periodType |
|
|
|
|
|
* @return |
|
|
|
|
|
*/ |
|
|
|
|
|
@Override |
|
|
|
|
|
public Map<String, Object> radarMapOfTrafficIndicators(String startDate, String direction, String periodType) { |
|
|
|
|
|
List<Map<String, Object>> mapOne = gantryMetricsStatisticsDataMapper.sectionTrafficIndexAnalysis(startDate, direction, periodType); |
|
|
|
|
|
// 计算crowdingRate和trafficCompositionRate的众数,以及saturationRate的平均值
|
|
|
|
|
|
int[] rates = {0, 0}; // 用于存储众数,第一个元素为crowdingRate众数,第二个为trafficCompositionRate众数
|
|
|
|
|
|
float sumSaturationRate = 0; |
|
|
|
|
|
int count = mapOne.size(); |
|
|
|
|
|
Map<Integer, Integer> crowdingRateCounts = new HashMap<>(); |
|
|
|
|
|
Map<Integer, Integer> trafficCompositionRateCounts = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
|
|
for (Map<String, Object> item : mapOne) { |
|
|
|
|
|
Integer crowdingRate = (Integer) item.get("crowdingRate"); |
|
|
|
|
|
Integer trafficCompositionRate = (Integer) item.get("trafficCompositionRate"); |
|
|
|
|
|
Float saturationRate = (Float) item.get("saturationRate"); |
|
|
|
|
|
// Double saturationRate = (Double) item.get("saturationRate");
|
|
|
|
|
|
sumSaturationRate += saturationRate; |
|
|
|
|
|
|
|
|
|
|
|
crowdingRateCounts.put(crowdingRate, crowdingRateCounts.getOrDefault(crowdingRate, 0) + 1); |
|
|
|
|
|
trafficCompositionRateCounts.put(trafficCompositionRate, trafficCompositionRateCounts.getOrDefault(trafficCompositionRate, 0) + 1); |
|
|
|
|
|
} |
|
|
|
|
|
// 找到众数
|
|
|
|
|
|
rates[0] = findMaxCountKey(crowdingRateCounts); |
|
|
|
|
|
rates[1] = findMaxCountKey(trafficCompositionRateCounts); |
|
|
|
|
|
// 计算平均saturationRate
|
|
|
|
|
|
double avgSaturationRate = count > 0 ? sumSaturationRate / count : 0; |
|
|
|
|
|
|
|
|
|
|
|
// 格式化保留4位小数
|
|
|
|
|
|
String formattedAvgSaturationRate = String.format("%.4f", avgSaturationRate); |
|
|
|
|
|
Map<String, Object> map = new HashMap<>(); |
|
|
|
|
|
map.put("crowdingRate", rates[0]); |
|
|
|
|
|
map.put("trafficCompositionRate", rates[1]); |
|
|
|
|
|
map.put("saturationRate", formattedAvgSaturationRate); |
|
|
|
|
|
return map; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static int findMaxCountKey(Map<Integer, Integer> counts) { |
|
|
|
|
|
// 初始化一个 Pair 类型来存储当前的最大计数及对应的键
|
|
|
|
|
|
Pair<Integer, Integer> maxPair = null; |
|
|
|
|
|
|
|
|
|
|
|
for (Map.Entry<Integer, Integer> entry : counts.entrySet()) { |
|
|
|
|
|
if (maxPair == null || entry.getValue() > maxPair.getValue() || |
|
|
|
|
|
(entry.getValue().equals(maxPair.getValue()) && entry.getKey() > maxPair.getKey())) { |
|
|
|
|
|
maxPair = new Pair<>(entry.getKey(), entry.getValue()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 确保maxPair不为null,这里假设输入的counts非空且至少有一个元素
|
|
|
|
|
|
return maxPair.getKey(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 恢复小时缓存数据的方法 |
|
|
* 恢复小时缓存数据的方法 |
|
|
* 该方法首先会获取当前月份的门架入口数据, |
|
|
* 该方法首先会获取当前月份的门架入口数据, |
|
@ -272,4 +494,44 @@ public class IDcGantryMetricsStatisticsDataServiceImpl |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static String extract(String input) { |
|
|
|
|
|
Pattern pattern = Pattern.compile("K(\\d{3})\\+(\\d{3})"); |
|
|
|
|
|
Matcher matcher = pattern.matcher(input); |
|
|
|
|
|
|
|
|
|
|
|
if (matcher.find()) { |
|
|
|
|
|
String part1 = matcher.group(1); |
|
|
|
|
|
String part2 = matcher.group(2); |
|
|
|
|
|
// 直接拼接两部分数字,无需格式化,这样得到的字符串自然没有前导零
|
|
|
|
|
|
return part1 + part2; |
|
|
|
|
|
} else { |
|
|
|
|
|
return "N/A"; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static String getDescriptionByIdentification(int identification) { |
|
|
|
|
|
for (StakeMarkRange range : StakeMarkRange.values()) { |
|
|
|
|
|
if (range.getIdentification() == identification) { |
|
|
|
|
|
return range.getDescription(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return ""; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static class Pair<K, V> { |
|
|
|
|
|
private K key; |
|
|
|
|
|
private V value; |
|
|
|
|
|
|
|
|
|
|
|
public Pair(K key, V value) { |
|
|
|
|
|
this.key = key; |
|
|
|
|
|
this.value = value; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public K getKey() { |
|
|
|
|
|
return key; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public V getValue() { |
|
|
|
|
|
return value; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|