Commit b0f95639 authored by hanbing's avatar hanbing

[add] 新信号评价-运行评价-详细指标查询

parent 6b57a7ff
package net.wanji.opt.bo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* @author Kent HAN
* @date 2023/6/9 13:52
*/
@Data
@ApiModel(value = "SceneMetricsDetailBO", description = "场景评价-详细指标查询输入参数")
public class SceneMetricsDetailBO {
@ApiModelProperty(value = "路口ID", required = true)
private String crossId;
@ApiModelProperty(value = "进口方向:1北;2东北;3东;4东南;5南;6西南;7西;8西北")
private Integer dir;
@ApiModelProperty(value = "转向:u掉头;l左转;s直行;r右转")
private String turn;
@ApiModelProperty(value = "车道序号,从左车道开始编号11、12、13...")
private Integer laneSort;
@ApiModelProperty(value = "日期 yyyy-MM-dd", required = true)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date date;
@ApiModelProperty(value = "时间粒度(分钟)", required = true)
private Integer minutes;
@ApiModelProperty(value = "指标编号列表", required = true)
List<String> metricCodes;
}
...@@ -7,16 +7,20 @@ import io.swagger.annotations.ApiResponses; ...@@ -7,16 +7,20 @@ import io.swagger.annotations.ApiResponses;
import net.wanji.common.framework.rest.JsonViewObject; import net.wanji.common.framework.rest.JsonViewObject;
import net.wanji.databus.bo.CrossIdAndStartEndDateBO; import net.wanji.databus.bo.CrossIdAndStartEndDateBO;
import net.wanji.opt.bo.AbnormalDetailBO; import net.wanji.opt.bo.AbnormalDetailBO;
import net.wanji.opt.bo.SceneMetricsDetailBO;
import net.wanji.opt.service.impl.SceneEvaluateServiceImpl; import net.wanji.opt.service.impl.SceneEvaluateServiceImpl;
import net.wanji.opt.vo.SceneEvaluateAbnormalDetailVO; import net.wanji.opt.vo.SceneEvaluateAbnormalDetailVO;
import net.wanji.opt.vo.SceneEvaluateAbnormalDistributeVO; import net.wanji.opt.vo.SceneEvaluateAbnormalDistributeVO;
import net.wanji.opt.vo.SceneMetricsDetailVO;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException; import java.text.ParseException;
import java.util.List;
/** /**
* 场景评价 * 场景评价
...@@ -57,4 +61,17 @@ public class SceneEvaluateController { ...@@ -57,4 +61,17 @@ public class SceneEvaluateController {
SceneEvaluateAbnormalDetailVO res = sceneEvaluateService.abnormalDetail(abnormalDetailBO); SceneEvaluateAbnormalDetailVO res = sceneEvaluateService.abnormalDetail(abnormalDetailBO);
return JsonViewObject.newInstance().success(res); return JsonViewObject.newInstance().success(res);
} }
@ApiOperation(value = "详细指标查询", notes = "详细指标查询", response = JsonViewObject.class,
produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
@PostMapping(value = "/metricsDetail",
produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
@ApiResponses({
@ApiResponse(code = 200, message = "OK", response = SceneMetricsDetailVO.class),
})
public JsonViewObject schemeProblems(@RequestBody SceneMetricsDetailBO bo)
throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
List<SceneMetricsDetailVO> res = sceneEvaluateService.metricsDetail(bo);
return JsonViewObject.newInstance().success(res);
}
} }
\ No newline at end of file
...@@ -2,14 +2,20 @@ package net.wanji.opt.service; ...@@ -2,14 +2,20 @@ package net.wanji.opt.service;
import net.wanji.databus.bo.CrossIdAndStartEndDateBO; import net.wanji.databus.bo.CrossIdAndStartEndDateBO;
import net.wanji.opt.bo.AbnormalDetailBO; import net.wanji.opt.bo.AbnormalDetailBO;
import net.wanji.opt.bo.SceneMetricsDetailBO;
import net.wanji.opt.vo.SceneEvaluateAbnormalDetailVO; import net.wanji.opt.vo.SceneEvaluateAbnormalDetailVO;
import net.wanji.opt.vo.SceneEvaluateAbnormalDistributeVO; import net.wanji.opt.vo.SceneEvaluateAbnormalDistributeVO;
import net.wanji.opt.vo.SceneMetricsDetailVO;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException; import java.text.ParseException;
import java.util.List;
public interface SceneEvaluateService { public interface SceneEvaluateService {
SceneEvaluateAbnormalDistributeVO abnormalDistribute(CrossIdAndStartEndDateBO bo); SceneEvaluateAbnormalDistributeVO abnormalDistribute(CrossIdAndStartEndDateBO bo);
SceneEvaluateAbnormalDetailVO abnormalDetail(AbnormalDetailBO abnormalDetailBO) throws ParseException; SceneEvaluateAbnormalDetailVO abnormalDetail(AbnormalDetailBO abnormalDetailBO) throws ParseException;
List<SceneMetricsDetailVO> metricsDetail(SceneMetricsDetailBO bo) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException;
} }
package net.wanji.opt.service.impl; package net.wanji.opt.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.CrossStatusEnum; import net.wanji.common.enums.CrossStatusEnum;
...@@ -15,15 +17,15 @@ import net.wanji.databus.po.CrossDataHistPO; ...@@ -15,15 +17,15 @@ import net.wanji.databus.po.CrossDataHistPO;
import net.wanji.databus.po.CrossDirDataHistPO; import net.wanji.databus.po.CrossDirDataHistPO;
import net.wanji.feign.service.ControlFeignClients; import net.wanji.feign.service.ControlFeignClients;
import net.wanji.opt.bo.AbnormalDetailBO; import net.wanji.opt.bo.AbnormalDetailBO;
import net.wanji.opt.bo.SceneMetricsDetailBO;
import net.wanji.opt.service.SceneEvaluateService; import net.wanji.opt.service.SceneEvaluateService;
import net.wanji.opt.vo.RunningEvaluateMetricsDetailVO; import net.wanji.opt.vo.*;
import net.wanji.opt.vo.SceneEvaluateAbnormalDetailVO;
import net.wanji.opt.vo.SceneEvaluateAbnormalDistributeVO;
import net.wanji.opt.vo.SchemeEvaluateSchemeDetailOverallVO;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
...@@ -44,9 +46,11 @@ public class SceneEvaluateServiceImpl implements SceneEvaluateService { ...@@ -44,9 +46,11 @@ public class SceneEvaluateServiceImpl implements SceneEvaluateService {
private final ControlFeignClients controlFeignClients; private final ControlFeignClients controlFeignClients;
private final BaseCrossSectionMapper baseCrossSectionMapper; private final BaseCrossSectionMapper baseCrossSectionMapper;
private final CrossDirDataHistMapper crossDirDataHistMapper; private final CrossDirDataHistMapper crossDirDataHistMapper;
private final CrossLaneDataHistMapper crossLaneDataHistMapper;
private final CrossTurnDataHistMapper crossTurnDataHistMapper;
SimpleDateFormat HOUR_SDF = new SimpleDateFormat("HH:mm"); SimpleDateFormat HOUR_SDF = new SimpleDateFormat("HH:mm");
public SceneEvaluateServiceImpl(CrossDataHistMapper crossDataHistMapper, RunningEvaluateServiceImpl runningEvaluateService, @Qualifier("baseCrossSchemeMapper") BaseCrossSchemeMapper baseCrossSchemeMapper, @Qualifier("baseCrossSchedulesMapper") BaseCrossSchedulesMapper baseCrossSchedulesMapper, @Qualifier("baseCrossSchedulesPlanMapper") BaseCrossSchedulesPlanMapper baseCrossSchedulesPlanMapper, @Qualifier("net.wanji.feign.service.ControlFeignClients") ControlFeignClients controlFeignClients, @Qualifier("baseCrossSectionMapper") BaseCrossSectionMapper baseCrossSectionMapper, CrossDirDataHistMapper crossDirDataHistMapper) { public SceneEvaluateServiceImpl(CrossDataHistMapper crossDataHistMapper, RunningEvaluateServiceImpl runningEvaluateService, @Qualifier("baseCrossSchemeMapper") BaseCrossSchemeMapper baseCrossSchemeMapper, @Qualifier("baseCrossSchedulesMapper") BaseCrossSchedulesMapper baseCrossSchedulesMapper, @Qualifier("baseCrossSchedulesPlanMapper") BaseCrossSchedulesPlanMapper baseCrossSchedulesPlanMapper, @Qualifier("net.wanji.feign.service.ControlFeignClients") ControlFeignClients controlFeignClients, @Qualifier("baseCrossSectionMapper") BaseCrossSectionMapper baseCrossSectionMapper, CrossDirDataHistMapper crossDirDataHistMapper, CrossLaneDataHistMapper crossLaneDataHistMapper, CrossTurnDataHistMapper crossTurnDataHistMapper) {
this.crossDataHistMapper = crossDataHistMapper; this.crossDataHistMapper = crossDataHistMapper;
this.runningEvaluateService = runningEvaluateService; this.runningEvaluateService = runningEvaluateService;
this.baseCrossSchemeMapper = baseCrossSchemeMapper; this.baseCrossSchemeMapper = baseCrossSchemeMapper;
...@@ -55,6 +59,8 @@ public class SceneEvaluateServiceImpl implements SceneEvaluateService { ...@@ -55,6 +59,8 @@ public class SceneEvaluateServiceImpl implements SceneEvaluateService {
this.controlFeignClients = controlFeignClients; this.controlFeignClients = controlFeignClients;
this.baseCrossSectionMapper = baseCrossSectionMapper; this.baseCrossSectionMapper = baseCrossSectionMapper;
this.crossDirDataHistMapper = crossDirDataHistMapper; this.crossDirDataHistMapper = crossDirDataHistMapper;
this.crossLaneDataHistMapper = crossLaneDataHistMapper;
this.crossTurnDataHistMapper = crossTurnDataHistMapper;
} }
@Override @Override
...@@ -243,6 +249,114 @@ public class SceneEvaluateServiceImpl implements SceneEvaluateService { ...@@ -243,6 +249,114 @@ public class SceneEvaluateServiceImpl implements SceneEvaluateService {
return vo; return vo;
} }
@Override
public List<SceneMetricsDetailVO> metricsDetail(SceneMetricsDetailBO bo)
throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
String crossId = bo.getCrossId();
Integer dir = bo.getDir();
String turn = bo.getTurn();
Integer laneSort = bo.getLaneSort();
Date date = bo.getDate();
Integer minutes = bo.getMinutes();
List<String> metricCodes = bo.getMetricCodes();
// 构造某一天开始和结束时间戳
Date startDate = date;
Date endDate = DateUtil.offsetDay(date, 1); // 包含最后一天
int startStamp = (int) (startDate.getTime() / 1000); // 10位时间戳
int endStamp = (int) (endDate.getTime() / 1000);
// 查询全部指标
List<MetricHistDTO> metricHistDTOList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(laneSort)) {
metricHistDTOList = crossLaneDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
} else if (ObjectUtil.isNotEmpty(turn)) {
metricHistDTOList = crossTurnDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
} else if (ObjectUtil.isNotEmpty(dir)) {
metricHistDTOList = crossDirDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
} else { // 路口级别
metricHistDTOList = crossDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
}
// 更新空放次数
metricHistDTOList.forEach(metricHistDTO -> {
if (metricHistDTO.getGreenLightEfficiency() != null && metricHistDTO.getGreenLightEfficiency() < 0.8) {
metricHistDTO.setEmptyDischarges(1);
}
});
List<SceneMetricsDetailVO> res = new ArrayList<>();
if (CollectionUtil.isEmpty(metricHistDTOList)) {
return res;
}
res = buildMetricsList(metricHistDTOList, minutes, metricCodes);
return res;
}
private List<SceneMetricsDetailVO> buildMetricsList(
List<MetricHistDTO> metricHistDTOList, Integer minutes, List<String> metricCodes) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<SceneMetricsDetailVO> res = new ArrayList<>();
// 按时间段分组
Map<String, List<MetricHistDTO>> groupedByTime = metricHistDTOList.stream()
.collect(Collectors.groupingBy(metricHistDTO -> {
long timestampInMillSeconds = metricHistDTO.getBatchTime() * 1000L;
Date date = new Date(timestampInMillSeconds);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
int minuteOfDay = date.getMinutes() + date.getHours() * 60;
int roundedMinute = (minuteOfDay / minutes) * minutes;
date.setHours(roundedMinute / 60);
date.setMinutes(roundedMinute % 60);
return sdf.format(date);
}));
// 获取时间段数组
List<String> minuteSectionArray = TimeArrayUtil.getMinuteSectionArray(minutes);
// 计算指标
for (String section : minuteSectionArray) {
List<MetricHistDTO> dtoList = groupedByTime.get(section);
for (String metricCode : metricCodes) {
SceneMetricsDetailVO crossMetrics = new SceneMetricsDetailVO();
crossMetrics.setMetricTime(section);
crossMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.getNameByCode(metricCode));
if (CollectionUtil.isNotEmpty(dtoList)) {
int metricValue = 0;
for (MetricHistDTO metricHistDTO : dtoList) {
// 获取field名称
String fieldName = StrategyAndMetricsEnum.Metrics.getFieldByCode(metricCode);
// 首字母大写,以匹配JavaBean规范中的get方法名称
String capitalizedFieldName = fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
// 获取get方法
Method method = MetricHistDTO.class.getMethod("get" + capitalizedFieldName);
// 调用方法并获取返回值
Object value = method.invoke(metricHistDTO);
double valDouble = (double) value;
if (fieldName.equals(StrategyAndMetricsEnum.Metrics.STOP_RATE.getField())
|| fieldName.equals(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getField())
|| fieldName.equals(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getField())
|| fieldName.equals(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getField())) {
valDouble *= 100;
}
int valInt = (int)valDouble;
metricValue += valInt;
}
int size = dtoList.size();
if (!Objects.equals(metricCode, StrategyAndMetricsEnum.Metrics.EMPTY_DISCHARGES.getCode())) {
crossMetrics.setMetricValue(metricValue / size);
} else {
crossMetrics.setMetricValue(metricValue);
}
}
res.add(crossMetrics);
}
}
return res;
}
private List<String> getTimeline(Date startTime, Date newEndTime) { private List<String> getTimeline(Date startTime, Date newEndTime) {
List<String> res = new ArrayList<>(); List<String> res = new ArrayList<>();
......
package net.wanji.opt.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Kent HAN
* @date 2023/2/9 8:38
*/
@Data
@NoArgsConstructor
@ApiModel(value = "SchemeEvaluateCurveChartVO", description = "详细指标查询")
public class SceneMetricsDetailVO {
@ApiModelProperty(value = "指标名称")
private String metricName;
@ApiModelProperty(value = "时间")
private String metricTime;
@ApiModelProperty(value = "指标数值")
private Integer metricValue;
}
...@@ -67,6 +67,15 @@ public class StrategyAndMetricsEnum { ...@@ -67,6 +67,15 @@ public class StrategyAndMetricsEnum {
} }
return null; return null;
} }
public static String getNameByCode(String code) {
for (Metrics value : Metrics.values()) {
if (value.code.equals(code)) {
return value.description;
}
}
return null;
}
} }
public static final Map<Strategy, List<Metrics>> STRATEGY_METRICS_MAP; public static final Map<Strategy, List<Metrics>> STRATEGY_METRICS_MAP;
......
...@@ -12,31 +12,38 @@ public class MetricHistDTO { ...@@ -12,31 +12,38 @@ public class MetricHistDTO {
@ApiModelProperty(value = "状态:0正常;1失衡;2拥堵;3溢出;4死锁", notes = "") @ApiModelProperty(value = "状态:0正常;1失衡;2拥堵;3溢出;4死锁", notes = "")
private Integer status; private Integer status;
@ApiModelProperty(value = "开始时间:yyyy-MM-dd HH:mm:ss", notes = "") @ApiModelProperty(value = "开始时间:yyyy-MM-dd HH:mm:ss", notes = "")
private Date startTime; private Date startTime;
@ApiModelProperty(value = "持续时间(单位:分钟)", notes = "") @ApiModelProperty(value = "持续时间(单位:分钟)", notes = "")
private Integer duration; private Integer duration;
@ApiModelProperty(value = "交通流量(辆)", notes = "") @ApiModelProperty(value = "交通流量(辆)", notes = "")
private Integer flow; private Integer flow = 0;
@ApiModelProperty(value = "采集时间(10位时间戳)", notes = "")
@ApiModelProperty(value = "平均速度(km/h)", notes = "") private Integer batchTime;
private Double speed;
@ApiModelProperty(value = "通行能力") @ApiModelProperty(value = "通行能力")
private Integer capacity; private Integer capacity = 0;
@ApiModelProperty(value = "饱和度", notes = "") @ApiModelProperty(value = "饱和度", notes = "")
private Double sturation; private Double sturation = 0.0;
@ApiModelProperty(value = "N次停车通过率")
public Double oneStopRate = 0.0;
@ApiModelProperty(value = "平均速度(km/h)", notes = "")
private Double speed = 0.0;
@ApiModelProperty(value = "停车次数(次)", notes = "") @ApiModelProperty(value = "停车次数(次)", notes = "")
private Double stopTimes; private Double stopTimes = 0.0;
@ApiModelProperty(value = "延误时间(秒)", notes = "") @ApiModelProperty(value = "延误时间(秒)", notes = "")
private Integer delayTime; private Integer delayTime = 0;
@ApiModelProperty(value = "最大排队(米)")
private Double queueLength = 0.0;
@ApiModelProperty(value = "溢流率", notes = "")
private Double effusionRate = 0.0;
@ApiModelProperty(value = "不停车率")
public Double noStopRate = 0.0;
@ApiModelProperty(value = "空放次数")
public Integer emptyDischarges = 0;
@ApiModelProperty(value = "绿灯有效利用率", notes = "")
private Double greenLightEfficiency = 0.0;
@ApiModelProperty(value = "负载均衡度", notes = "")
private Double loadBalance = 0.0;
@ApiModelProperty(value = "采集时间(10位时间戳)", notes = "")
private Integer batchTime;
} }
...@@ -86,7 +86,7 @@ ...@@ -86,7 +86,7 @@
</select> </select>
<select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO"> <select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO">
select status, start_time, duration, flow, speed, sturation, stop_times, delay_time, batch_time select status, start_time, duration, flow, speed, sturation, stop_times, delay_time, batch_time, one_stop_rate, queue_length, effusion_rate, no_stop_rate, green_light_efficiency, load_balance
from t_cross_data_hist from t_cross_data_hist
where cross_id = #{crossId} where cross_id = #{crossId}
and batch_time <![CDATA[ >= ]]> #{startStamp} and batch_time <![CDATA[ >= ]]> #{startStamp}
......
...@@ -113,7 +113,7 @@ ...@@ -113,7 +113,7 @@
</select> </select>
<select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO"> <select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO">
select status, start_time, duration, flow, speed, sturation, capacity, stop_times, delay_time, batch_time select status, start_time, duration, flow, speed, sturation, capacity, stop_times, delay_time, batch_time, one_stop_rate, queue_length, effusion_rate, no_stop_rate, green_light_efficiency
from t_cross_dir_data_hist from t_cross_dir_data_hist
where cross_id = #{crossId} where cross_id = #{crossId}
and batch_time <![CDATA[ >= ]]> #{startStamp} and batch_time <![CDATA[ >= ]]> #{startStamp}
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
</delete> </delete>
<select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO"> <select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO">
select flow, speed, sturation, capacity, stop_times, delay_time, batch_time select flow, speed, sturation, capacity, stop_times, delay_time, batch_time, one_stop_rate, queue_length, effusion_rate, no_stop_rate, green_light_efficiency
from t_lane_data_hist from t_lane_data_hist
where cross_id = #{crossId} where cross_id = #{crossId}
and batch_time <![CDATA[ >= ]]> #{startStamp} and batch_time <![CDATA[ >= ]]> #{startStamp}
......
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
</select> </select>
<select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO"> <select id="selectMetricHistDTO" resultType="net.wanji.databus.dto.MetricHistDTO">
select status, flow, speed, sturation, stop_times, delay_time, batch_time select status, flow, speed, sturation, stop_times, delay_time, batch_time, one_stop_rate, queue_length, effusion_rate, no_stop_rate, green_light_efficiency
from t_cross_turn_data_hist from t_cross_turn_data_hist
where cross_id = #{crossId} where cross_id = #{crossId}
and batch_time <![CDATA[ >= ]]> #{startStamp} and batch_time <![CDATA[ >= ]]> #{startStamp}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment