Commit ca3377a8 authored by zhoushiguang's avatar zhoushiguang

删除、注释一些未用的类

parent 92c4bc00
package net.wanji.opt;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author
*/
@SpringBootApplication(scanBasePackages = {"net.wanji.opt", "net.wanji.databus", "net.wanji.common",
"net.wanji.opt.task.controller"})
@MapperScan(basePackages = {"net.wanji.opt.dao.mapper", "net.wanji.databus.dao.mapper"})
@EnableTransactionManagement
@EnableScheduling
@EnableAsync
public class SignalOptimizeApplication {
public static void main(String[] args) {
SpringApplication.run(SignalOptimizeApplication.class, args);
}
}
package net.wanji.opt.common;//package net.wanji.opt.common;
//package net.wanji.opt.common;
//
//import com.alibaba.fastjson.JSONObject;
//import com.fasterxml.jackson.core.JsonProcessingException;
......
package net.wanji.opt.config;//package net.wanji.opt.config;
//package net.wanji.opt.config;
//
//import org.apache.kafka.clients.consumer.ConsumerConfig;
//import org.apache.kafka.common.serialization.StringDeserializer;
......
package net.wanji.opt.config;///*
///*
// * Copyright (C) 2018 Zhejiang xiaominfo Technology CO.,LTD.
// * All rights reserved.
// * Official Web Site: http://www.xiaominfo.com.
......
package net.wanji.opt.config;//package net.wanji.opt.config;
//package net.wanji.opt.config;
//
//import com.google.common.base.Predicates;
//import org.springframework.context.annotation.Bean;
......
package net.wanji.opt.dao.mapper;
import net.wanji.opt.synthesis.pojo.*;
import net.wanji.opt.synthesis.pojo.vo.CrossOrGreenWaveTypeEntity;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 监测详情-路口事件详情
* </p>
* @author zhengyifan
* @date 2025/3/15
*/
public interface CrossMapper {
/**
* 监测详情-路口事件详情-路口状态分布趋势-优化时间
* @param crossID 路口ID
*/
List<CrossStatusDisOptTimeEntity> getOptTimes(String crossID);
/**
* 监测详情-路口事件详情-路口实时告警
* @param crossID 路口ID
* @param time 时间
*/
CrossRealTimeAlarmEntity getCrossRealTimeAlarms(String crossID, String time);
/**
* 监测详情-路口策略详情-路口实时告警
* @param crossID
* @param time
* @return
*/
CrossRealTimeAlarmEntity getCrossRealTimeAlarmsPlan(String crossID, String time,String eventSerialNumber);
/**
* 路口方向信息
*
* @param crossID 路口ID
*/
List<CrossDirectionInfoEntity> getCrossDirectionInfo(String crossID);
/**
* 路口转向信息
*
* @param crossID 路口ID
*/
List<CrossTurnInfoEntity> getCrossTurnInfo(String crossID);
/**
* 路口车道信息
*
* @param crossID 路口ID
*/
List<CrossLaneInfoEntity> getCrossLaneInfo(String crossID);
/**
* 路口类型信息
*
* @param crossID 路口ID
* @param date 日期 格式:yyyyMMdd
*/
List<CrossOrGreenWaveTypeEntity> getCrossTypeInfo(@Param("crossID") String crossID, @Param("dt") String date);
}
package net.wanji.opt.dao.mapper.comprehensivequery;
import net.wanji.opt.entity.comprehensivequery.GreenAndCrossEntity;
import net.wanji.opt.po.base.CrossLaneDataHistPoExtend;
import java.util.List;
import java.util.Map;
public interface ComprehensiveQueryMapper {
List<GreenAndCrossEntity> getGreenAndCross();
List<GreenAndCrossEntity> getCross();
List<CrossLaneDataHistPoExtend> findCrossObjectIndex(Map<String,Object> params);
}
package net.wanji.opt.dao.mapper.evaluation;
import net.wanji.common.framework.mapper.BaseInterfaceMapper;
import net.wanji.opt.entity.evaluation.EventInfo;
import net.wanji.opt.entity.eventoptimize.TEventOptimizeInfo;
import net.wanji.opt.entity.judgeanalysis.AnalysisProblemAndStrategyDay;
import net.wanji.opt.po.trend.EventInfoSimplePo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* <p>
* 交通事件信息
* </p>
*
* @Author wangtao
* @Date 2025-03-18
*/
public interface CrossProblemEvaluationMapper {
public List<AnalysisProblemAndStrategyDay> findOVerFlowInfo();
List<EventInfoSimplePo> getOverflow(@Param("evenType") String evenType, @Param("currentAlgo")String currentAlgo, @Param("crossId")String crossId, @Param("startTime")String startTime, @Param("endTime")String endTime);
List<EventInfoSimplePo> getContrastOverflow(@Param("evenType")String evenType,@Param("currentAlgo")String currentAlgo,@Param("crossId")String crossId,@Param("contrastStartTime") String contrastStartTime, @Param("constrastEndTime")String constrastEndTime);
}
package net.wanji.opt.dao.mapper.eventoptimize;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import net.wanji.opt.entity.eventoptimize.TEventOptimizeInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
@Mapper
public interface TEventOptimizeInfoMapper extends BaseMapper<TEventOptimizeInfo> {
Page<TEventOptimizeInfo> selectPageWithConditions(@Param("page") Page<TEventOptimizeInfo> page,
@Param("startTime") String startTime,
@Param("endTime") String endTime,
@Param("crossId") String crossId,
@Param("eventType") String eventType,
@Param("optStatus") Integer optStatus,
@Param("duration") Integer duration,
@Param("startOptDuration") Integer startOptDuration,
@Param("endOptDuration") Integer endOptDuration,
@Param("startDuration") Integer startDuration,
@Param("endDuration") Integer endDuration
);
Page<TEventOptimizeInfo> selectPageWithCrossIdAndGreenId(@Param("page") Page<TEventOptimizeInfo> page,
@Param("startTime") String startTime,
@Param("endTime") String endTime,
@Param("crossId") String crossId,
@Param("greenId") Integer greenId);
List<Map<String,String>> getCrossOptimizeDistribute(@Param("groupType") Integer groupType,
@Param("startTime") String startTime,
@Param("endTime") String endTime,
@Param("crossId") String crossId,
@Param("greenId") Integer greenId);
String getEventLabel(@Param("eventType") String eventType);
Page<TEventOptimizeInfo> pageWithLineConditions(@Param("page") Page<TEventOptimizeInfo> page,
@Param("startTime") String startTime,
@Param("endTime") String endTime,
@Param("greenId") Integer greenId,
@Param("eventType") String eventType,
@Param("optStatus") Integer optStatus,
@Param("duration") Integer duration,
@Param("startOptDuration") Integer startOptDuration,
@Param("endOptDuration") Integer endOptDuration,
@Param("startDuration") Integer startDuration,
@Param("endDuration") Integer endDuration
);
}
\ No newline at end of file
package net.wanji.opt.dao.mapper.syslog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import net.wanji.opt.entity.judgeanalysis.AnalysisProblemCrossDay;
import net.wanji.opt.entity.syslog.SysOptimizeLog;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 系统日志
* </p>
* @author huangwm
* @date 2025/3/26
*/
public interface SysLogMapper extends BaseMapper<SysOptimizeLog> {
List<SysOptimizeLog> findSysOptimizeLog(@Param("crossId") String crossId, @Param("startTime") String startTime,@Param("endTime") String endTime);
}
package net.wanji.opt.service;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.po.CrossDataRealtimePO;
import net.wanji.databus.po.CrossDirDataRealtimePO;
import net.wanji.databus.po.CrossDirStatusDataPO;
import net.wanji.databus.po.TBaseCrossInfo;
import net.wanji.opt.po.trend.HoloEventInfoPO;
import net.wanji.opt.vo.AIOptResultVO;
import net.wanji.opt.vo.CrossEventListPO;
import net.wanji.opt.vo.CrossOptResult;
import net.wanji.opt.vo.CrossStatusCountVO;
import java.util.List;
import java.util.Map;
/**
* @author duanruiming
* @date 2024/11/25 19:12
*/
public interface CrossIndexService {
Map<Integer, CrossDirDataRealtimePO> crossDirIndex(CrossIdBO crossIdBO);
CrossDataRealtimePO crossIndex(CrossIdBO crossIdBO);
List<TBaseCrossInfo> crossInfoList();
List<CrossOptResult> crossOptResultList(CrossIdBO crossIdBO) throws Exception;
List<AIOptResultVO> crossAIList() throws Exception;
List<CrossStatusCountVO> crossStatusCount(String crossId) throws Exception;
HoloEventInfoPO crossEventDirTurn(String crossId) throws Exception;
List<CrossEventListPO> selectCrossEventList() throws Exception;
/**
* @Description 查询据当前时间某小时的数据
* @Param crossId 路口编号
* @Param hour 小时数
* @return java.util.List<net.wanji.databus.po.CrossDirDataHistPO>
**/
CrossDirStatusDataPO selectByCrossIdAndHour(String crossId,int hour);
}
package net.wanji.opt.service;
/**
* @author hfx
* @date 2023/1/12 15:12
* @desc 路口基础信息接口服务
*/
public interface CrossInfoService {
/**
* 查询路口基础信息列表
* @return
*/
// List<CrossInfoDTO> listCrossInfo(CrossQuery query);
}
package net.wanji.opt.service;
import net.wanji.databus.po.CrossDataRealtimePO;
import java.util.List;
/**
* @author hfx
* @date 2023/1/10 11:12
* @desc 路口优化接口服务
*/
public interface CrossOptimizeService {
/**
* 路口实时优化
* @return
*/
String realtimeOptimize(List<CrossDataRealtimePO> abnormalCrossList, List<CrossDataRealtimePO> crossDataRealtimePOList);
/**
* 路口方案优化
*/
// String schemeOptimize();
}
package net.wanji.opt.service;
import net.wanji.databus.bo.CrossIdAndSchemeIdBO;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.opt.dto.CrossIdAndDirDTO;
import net.wanji.opt.dto.CrossIdAndSchemeIdDTO;
import net.wanji.opt.dto.SaveLaneInfoDTO;
import net.wanji.opt.dto.SendManualDTO;
import net.wanji.opt.dto.strategy.AddOrUpdateSceneDTO;
import net.wanji.opt.vo.CrossIdAndLocationVO;
import net.wanji.opt.vo.OptEffectVO;
import net.wanji.opt.vo.SchemeOptVO;
import java.util.List;
/**
* @author Kent HAN
* @date 2023/3/2 10:09
*/
public interface DiagnoService {
AddOrUpdateSceneDTO queryCrossScene(CrossIdBO crossIdBO);
List<CrossIdAndLocationVO> queryNeighborCross(CrossIdBO crossIdBO);
SchemeOptVO querySchemeOpt(CrossIdAndSchemeIdBO bo);
List<SchemeOptVO.PhaseOptTime> queryOptTime(CrossIdAndSchemeIdDTO crossIdAndSchemeIdDTO);
List<SchemeOptVO.PhaseOptTime> schemeComparison(CrossIdAndSchemeIdDTO crossIdAndSchemeIdDTO);
void sendManual(SendManualDTO sendManualDTO) throws Exception;
void restoreSend(CrossIdBO crossIdBO) throws Exception;
OptEffectVO optEffect(CrossIdAndDirDTO crossIdAndDirDTO);
SaveLaneInfoDTO listLaneInfo(CrossIdBO crossIdBO);
}
package net.wanji.opt.service;
import net.wanji.opt.dto.CrossIdAndMinutesDTO;
import net.wanji.opt.vo.EvaluateCrossDetailVO;
import net.wanji.opt.vo.EvaluateMetricsVO;
/**
* @author hanbing
* @date 2023/1/12 15:12
* @desc 信号评价接口服务
*/
public interface EvaluateService {
EvaluateCrossDetailVO evaluateCrossDetail(CrossIdAndMinutesDTO crossIdAndMinutesDTO);
EvaluateMetricsVO evaluateMetrics(CrossIdAndMinutesDTO crossIdAndMinutesDTO);
}
package net.wanji.opt.service;
import net.wanji.common.framework.exception.DubboProviderException;
import net.wanji.databus.dto.EventInfoTrafficStatusDTO;
import net.wanji.databus.vo.EventInfoTrafficStatusVO;
import net.wanji.opt.entity.EventAlarmInfo;
import net.wanji.opt.po.base.EventStatisticPo;
import java.util.List;
import java.util.Map;
/**
* 事件接口
*/
public interface EventService {
/**
* 查询路口事件统计数
* @param crossId
* @param type
* @param startTime
* @param endTime
* @return
*/
EventStatisticPo findCrossEventCount(String crossId, String type, String startTime, String endTime) throws DubboProviderException;
/**
* 场景分布
* @param crossId
* @param startTime
* @param endTime
* @return
*/
List<Map<String,Object>> findEventDistribute(String crossId, String startTime, String endTime) throws DubboProviderException;
/**
* 路口监测、干线监测-交通状态
* @param eventInfoTrafficStatusDTO
* @return
*/
EventInfoTrafficStatusVO trafficStatus(EventInfoTrafficStatusDTO eventInfoTrafficStatusDTO) throws DubboProviderException;
/**
* 当时事件报警数据监测
* @return
* @throws DubboProviderException
*/
List<EventAlarmInfo> findEventAlarmInfo(String realtimeType, String eventType, String name) throws DubboProviderException;
/**
* 查询当前未结束事件
* @return
* @throws DubboProviderException
*/
List<EventAlarmInfo> findNotFinishAlarmInfo() throws DubboProviderException;
}
package net.wanji.opt.service;
import net.wanji.databus.bo.GreenwaveStartEndDateBO;
import net.wanji.opt.bo.*;
import net.wanji.opt.vo.*;
import java.util.List;
public interface MainlineEvaluateService {
List<String> bottomMenu(BottomMenuBO bo);
List<MainlineEvaluateBottomCurveVO> bottomCurve(BottomCurveBO bo) throws Exception;
List<MainlineListVO> mainlineList();
MainlineSchemeAnalysisVO mainlineSchemeAnalysis(MainlineSchemeAnalysisBO bo) throws Exception;
MainlineSchemeEvaluateVO mainlineSchemeEvaluate(MainlineSchemeEvaluateBO bo);
List<MainlineCrossEvaluateVO> mainlineCrossEvaluate(MainlineCrossEvaluateBO bo);
List<MainlineRunningAnalyseVO> mainlineRunningAnalyse(GreenwaveStartEndDateBO bo);
}
package net.wanji.opt.service;
import net.wanji.common.framework.exception.DubboProviderException;
import net.wanji.databus.bo.CrossIdAndStartEndDateBO;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.bo.HeatMapBO;
import net.wanji.databus.vo.RunningEvaluateCrossListVO;
import net.wanji.opt.bo.CrossNameBO;
import net.wanji.opt.bo.MetricsDetailBO;
import net.wanji.opt.vo.*;
import java.util.List;
public interface RunningEvaluateService {
List<RunningEvaluateCrossListVO> crossList(CrossNameBO crossNameBO);
RunningEvaluateCrossEvaluateVO crossEvaluate(CrossIdAndStartEndDateBO bo) throws DubboProviderException;
RunningEvaluateStatusVO congestionStatus(CrossIdAndStartEndDateBO bo);
RunningEvaluateStatusVO unbalanceStatus(CrossIdAndStartEndDateBO bo);
RunningEvaluateStatusVO spilloverStatus(CrossIdAndStartEndDateBO bo);
List<RunningEvaluateSchemeProblemsVO> schemeProblems(CrossIdAndStartEndDateBO bo);
RunningEvaluateMetricsDetailVO metricsDetail(MetricsDetailBO bo);
RunningEvaluateScopeTreeVO scopeTree(CrossIdBO bo);
List<RunningEvaluateHeatMapVO> heatMap(HeatMapBO bo);
}
package net.wanji.opt.service;
import net.wanji.databus.bo.CrossIdAndStartEndDateBO;
import net.wanji.databus.bo.HeatMapBO;
import net.wanji.opt.bo.AbnormalDetailBO;
import net.wanji.opt.bo.MetricsTurnAndLaneBO;
import net.wanji.opt.bo.SceneMetricsDetailBO;
import net.wanji.opt.vo.*;
import net.wanji.opt.vo.SceneMetricsDetailVO;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.List;
public interface SceneEvaluateService {
SceneEvaluateAbnormalDistributeVO abnormalDistribute(CrossIdAndStartEndDateBO bo);
SceneEvaluateAbnormalDetailVO abnormalDetail(AbnormalDetailBO abnormalDetailBO) throws ParseException;
List<SceneMetricsDetailVO> metricsDetail(SceneMetricsDetailBO bo) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException;
SceneEvaluateMetricsTurnVO metricsTurn(MetricsTurnAndLaneBO bo) throws ParseException;
SceneEvaluateMetricsLaneVO metricsLane(MetricsTurnAndLaneBO bo) throws ParseException;
List<SceneEvaluateHeatMapVO> heatMap(HeatMapBO bo);
}
package net.wanji.opt.service;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.opt.bo.CrossSchemeListBO;
import net.wanji.opt.bo.CurveChartBO;
import net.wanji.opt.bo.ProblemSchemeBO;
import net.wanji.opt.bo.SchemeDetailOverallBO;
import net.wanji.opt.vo.*;
import java.text.ParseException;
import java.util.List;
public interface SchemeEvaluateService {
SchemeEvaluateProblemSchemeVO problemSchemeList(ProblemSchemeBO problemSchemeBO);
List<SchemeEvaluateStrategyMetricMenuVO> strategyMetricMenu(CrossIdBO crossIdBO);
List<SchemeEvaluateCrossSchemeListVO> crossSchemeList(CrossSchemeListBO crossSchemeListBO);
SchemeEvaluateSchemeDetailOverallVO schemeDetailOverall(SchemeDetailOverallBO schemeDetailOverallBO) throws Exception;
SchemeEvaluateSchemeDetailedProblemVO detailedProblem(SchemeDetailOverallBO schemeDetailOverallBO) throws Exception;
List<SchemeEvaluateCurveChartVO> curveChart(CurveChartBO curveChartBO) throws ParseException, NoSuchFieldException, IllegalAccessException;
}
package net.wanji.opt.service;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.vo.GreenwaveListVO;
import net.wanji.opt.bo.*;
import net.wanji.opt.dto.trend.AbnormalCrossListDTO;
import net.wanji.opt.dto.trend.GreenwaveListDTO;
import net.wanji.opt.po.trend.AnalysisRidTurnIndicators;
import net.wanji.opt.po.trend.HoloEventInfoPO;
import net.wanji.opt.vo.*;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
/**
* @date 2023/1/12 15:12
* @desc 态势监测接口服务
*/
public interface TrendService {
List<GreenwaveListVO> greenwaveList(GreenwaveListDTO greenwaveListDTO);
GreenwaveStats buildGreenwaveStats(List<GreenwaveListVO> greenwaveListVOList);
AbnormalCrossVO abnormalCrossList(AbnormalCrossListDTO abnormalCrossListDTO);
AbnormalCrossDetailVO abnormalCrossDetail(CrossIdBO crossIdBO);
List<EventAlarmVO> eventAlarm(Date todayTime) throws ParseException;
List<GreenWaveCrossMonitorVO> greenwaveCrossMonitor(GreenwaveIdBO greenwaveIdBO);
List<GreenwaveRunMonitorVO> greenwaveRunMonitor(GreenwaveIdBO greenwaveIdBO);
GreenwaveDetailVO greenwaveDetail(GreenwaveDetailBO greenwaveDetailBO) throws Exception;
List<GreenwaveCrossMetricsVO> greenwaveCrossMetrics(GreenwaveIdAndTimeStampBO greenwaveIdAndTimeStampBO) throws Exception;
void saveGreenwaveStrategy(SaveGreenwaveStrategyBO saveGreenwaveStrategyBO);
GreenwaveDetailVO currentGreenwaveDetail(GreenwaveIdBO bo) throws Exception;
CountRealTimeVO countRealTime(String crossId) throws Exception;
TableQueryVO tableQuery(CrossIdAndTimeSpanBO crossIdAndTimeSpanBO) throws Exception;
TableQueryVO tableRealTime(CrossIdAndIsFirstBO crossIdAndIsFirstBO) throws Exception;
OptTypeVO optType(CrossIdBO crossIdBO);
List<HotspotCrossVO> hotspotCross(CommonCrossIdVO commonCrossIdVO) throws Exception;
List<HotspotCrossTurnVO> crossTurnData(CommonCrossIdVO commonCrossIdVO) throws Exception;
List<HotspotCrossLaneVO> crossLaneData(CommonCrossIdVO commonCrossIdVO) throws Exception;
List<Top5IndexVO> top5Flow() throws Exception;
CrossStatusTimeRateVO crossStatusTimeRate(CommonCrossIdVO commonCrossIdVO) throws Exception;
GreenStatusTimeRateVO greenStatusTimeRate(Integer greenId) throws Exception;
List<TableQueryVO.CycleDataElement> laneTrafficIndex(CommonCrossIdDateTimeVO crossIdDateTimeVO) throws Exception;
List<TableQueryVO.RealTimeDataElement> laneSnapshotIndex(LaneSnapshotIndexVO laneSnapshotIndexVO) throws Exception;
List<OverflowEvent> overFlowEvent(LaneSnapshotIndexVO laneSnapshotIndexVO) throws Exception;
List<AnalysisRidTurnIndicators> lanePeriodTurnData(LanePeriodTurnVO lanePeriodTurnVO) throws Exception;
List<HoloEventInfoPO> holoEvenList(HoloEventVO holoEventVO) throws Exception;
List<LaneIdAliasNameVO> laneIdList(CommonCrossIdVO commonCrossIdVO) throws Exception;
void periodExcel(CommonCrossIdDateTimeVO crossIdDateTimeVO, HttpServletResponse response) throws Exception;
void periodTurnExcel(LanePeriodTurnVO lanePeriodTurnVO, HttpServletResponse response) throws Exception;
void laneSnapshotExcel(LaneSnapshotIndexVO laneSnapshotIndexVO, HttpServletResponse response) throws Exception;
}
package net.wanji.opt.service.es;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.constant.Constants;
import net.wanji.common.utils.tool.JacksonUtils;
import net.wanji.common.utils.tool.StringUtils;
import net.wanji.opt.dto.CrossLaneSnapshotDataDTO;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author duanruiming
* @date 2023/10/26 14:13
*/
@Service
@Slf4j
public class LaneSnapshotDataQueryService implements LaneSnapshotService {
@Resource
RestHighLevelClient client;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public List<CrossLaneSnapshotDataDTO> queryByCrossIdAndTimeSpan(
String crossId, int startTimeStamp, int endTimeStamp, int pageNum, String laneId, boolean overFlow)
throws Exception {
List<CrossLaneSnapshotDataDTO> result = new ArrayList<>();
try {
SearchRequest searchRequest = new SearchRequest(Constants.LANE_SNAPSHOT_DATA_ES_INDEX);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("crossId", crossId);
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("timeStamp")
.gte(startTimeStamp)
.lte(endTimeStamp);
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(matchQuery)
.must(rangeQuery);
// 是否是溢出事件
MatchQueryBuilder overFlowQuery = null;
if (overFlow) {
overFlowQuery = QueryBuilders.matchQuery("overflow", true);
boolQuery.must(overFlowQuery);
}
// 车道号筛选
String[] split = null;
if (StringUtils.isNotBlank(laneId)) {
split = laneId.split(",");
TermsQueryBuilder termsQuery = QueryBuilders.termsQuery("laneId.keyword", Arrays.asList(split));
boolQuery.must(termsQuery);
}
if (pageNum == -1) {
searchSourceBuilder
.query(boolQuery)
.size(50000);
} else {
searchSourceBuilder
.query(boolQuery)
.from(pageNum * 500)
.size((pageNum + 1) * 500);
}
searchRequest.source(searchSourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
CrossLaneSnapshotDataDTO crossLaneSnapshotDataDTO =
JacksonUtils.getInstance().readValue(sourceAsString, CrossLaneSnapshotDataDTO.class);
result.add(crossLaneSnapshotDataDTO);
}
} catch (Exception e) {
log.error("ES数据获取错误", e);
throw new Exception(e);
}
return result;
}
@Override
public int queryCountsByCrossIdAndTimeSpan(String crossId, int startTimeStamp, int endTimeStamp) throws Exception {
try {
CountRequest countRequest = new CountRequest(Constants.LANE_SNAPSHOT_DATA_ES_INDEX);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("crossId", crossId);
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("timeStamp")
.gte(startTimeStamp)
.lte(endTimeStamp);
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(matchQuery)
.must(rangeQuery);
searchSourceBuilder.query(boolQuery);
countRequest.source(searchSourceBuilder);
CountResponse countResponse = client.count(countRequest, RequestOptions.DEFAULT);
long count = countResponse.getCount();
return (int) count;
} catch (Exception e) {
log.error("ES数据获取错误", e);
throw new Exception(e);
}
}
}
package net.wanji.opt.service.es;
import net.wanji.opt.dto.CrossLaneSnapshotDataDTO;
import java.util.List;
/**
* @author duanruiming
* @date 2023/10/26 14:12
*/
public interface LaneSnapshotService {
List<CrossLaneSnapshotDataDTO> queryByCrossIdAndTimeSpan(String crossId, int startTimeStamp,
int endTimeStamp, int pageNum,
String laneId, boolean overFlow) throws Exception;
int queryCountsByCrossIdAndTimeSpan(String crossId, int startTimeStamp, int endTimeStamp) throws Exception;
}
package net.wanji.opt.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.utils.tool.LocalDateTimeUtil;
import net.wanji.common.utils.tool.StringUtils;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.dao.mapper.BaseCrossInfoMapper;
import net.wanji.databus.dao.mapper.CrossDataRealtimeMapper;
import net.wanji.databus.dao.mapper.CrossDirDataHistMapper;
import net.wanji.databus.dao.mapper.CrossDirDataRealtimeMapper;
import net.wanji.databus.po.*;
import net.wanji.opt.common.enums.CrossOptResultStrategyEnum;
import net.wanji.opt.common.enums.EventInfoTypeEnum;
import net.wanji.opt.common.enums.OptStatusEnum;
import net.wanji.opt.common.enums.StrategyControlEnum;
import net.wanji.opt.dao.mapper.HoloEventMapper;
import net.wanji.opt.dao.mapper.StrategyCrossResultMapper;
import net.wanji.opt.po.trend.HoloEventInfoPO;
import net.wanji.opt.service.CrossIndexService;
import net.wanji.opt.synthesis.pojo.StrategyCrossResultEntity;
import net.wanji.opt.vo.AIOptResultVO;
import net.wanji.opt.vo.CrossEventListPO;
import net.wanji.opt.vo.CrossOptResult;
import net.wanji.opt.vo.CrossStatusCountVO;
import org.apache.curator.drivers.EventTrace;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author duanruiming
* @date 2024/11/25 19:12
*/
@Service
@Slf4j
public class CrossIndexServiceImpl implements CrossIndexService {
@Resource
private CrossDirDataRealtimeMapper crossDirDataRealtimeMapper;
@Resource
private CrossDataRealtimeMapper crossDataRealtimeMapper;
@Resource
private BaseCrossInfoMapper baseCrossInfoMapper;
@Resource
private StrategyCrossResultMapper strategyCrossResultMapper;
@Resource
private HoloEventMapper holoEventMapper;
@Resource
private CrossDirDataHistMapper crossDirDataHistMapper;
@Override
public Map<Integer, CrossDirDataRealtimePO> crossDirIndex(CrossIdBO crossIdBO) {
List<CrossDirDataRealtimePO> crossDirDataRealtimePOS = crossDirDataRealtimeMapper.selectBycrossId(crossIdBO.getCrossId());
if (!CollectionUtils.isEmpty(crossDirDataRealtimePOS)) {
Map<Integer, CrossDirDataRealtimePO> dirDataMap = new HashMap<>(crossDirDataRealtimePOS.size());
for (CrossDirDataRealtimePO crossDirDataRealtimePO : crossDirDataRealtimePOS) {
dirDataMap.put(crossDirDataRealtimePO.getDirType(), crossDirDataRealtimePO);
}
return dirDataMap;
}
return null;
}
@Override
public CrossDataRealtimePO crossIndex(CrossIdBO crossIdBO) {
CrossDataRealtimePO crossDataRealtimePO = crossDataRealtimeMapper.selectByCrossId(crossIdBO.getCrossId());
return crossDataRealtimePO;
}
@Override
public List<TBaseCrossInfo> crossInfoList() {
LambdaQueryWrapper<TBaseCrossInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TBaseCrossInfo::getIsSignal, 1);
List<TBaseCrossInfo> baseCrossInfoPOS = baseCrossInfoMapper.selectList(queryWrapper);
return baseCrossInfoPOS;
}
@Override
public List<CrossOptResult> crossOptResultList(CrossIdBO crossIdBO) throws Exception {
LambdaQueryWrapper<StrategyCrossResultEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StrategyCrossResultEntity::getCrossId, crossIdBO.getCrossId());
LocalDate currentDate = LocalDate.now();
LocalTime startTime = LocalTime.MIDNIGHT;
LocalDateTime startOfDay = LocalDateTime.of(currentDate, startTime);
queryWrapper.eq(StrategyCrossResultEntity::getCrossId, crossIdBO.getCrossId());
queryWrapper.ge(StrategyCrossResultEntity::getIssueTime, startOfDay);
queryWrapper.eq(StrategyCrossResultEntity::getResponseCode, 200);
List<StrategyCrossResultEntity> list = strategyCrossResultMapper.selectList(queryWrapper);
List<CrossOptResult> crossOptResults = new ArrayList<>();
if (!CollectionUtils.isEmpty(list)) {
for (StrategyCrossResultEntity entity : list) {
CrossOptResult crossOptResult = new CrossOptResult();
Date date = entity.getIssueTime();
crossOptResult.setTimeStamp(date);
Integer countDown = entity.getCountDown();
if (entity.getCurrentAlgo() == 2) {
countDown = 5;
}
crossOptResult.setCountDown(countDown);
Integer currentAlgo = entity.getCurrentAlgo();
crossOptResult.setStrategy(currentAlgo);
crossOptResult.setStrategyName(CrossOptResultStrategyEnum.getDesc(currentAlgo));
crossOptResults.add(crossOptResult);
}
}
return crossOptResults;
}
@Override
public List<AIOptResultVO> crossAIList() {
List<AIOptResultVO> results = new ArrayList<>();
try {
LocalDate currentDate = LocalDate.now();
LocalTime startTime = LocalTime.MIDNIGHT;
LocalDateTime startOfDay = LocalDateTime.of(currentDate, startTime);
Date date = Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
List<StrategyCrossResultEntity> list = strategyCrossResultMapper.selectAICrossList(date);
if (!CollectionUtils.isEmpty(list)) {
for (StrategyCrossResultEntity resultEntity : list) {
AIOptResultVO aiOptResultVO = new AIOptResultVO();
aiOptResultVO.setId(resultEntity.getCrossId());
aiOptResultVO.setName(resultEntity.getCrossName());
Integer currentAlgo = resultEntity.getCurrentAlgo();
if (Objects.nonNull(currentAlgo)) {
aiOptResultVO.setStrategy(currentAlgo);
// 失衡 均衡调控,其他效率提升
aiOptResultVO.setOptMethod(Objects.equals(1, currentAlgo) ? StrategyControlEnum.ONE.getMethod() : StrategyControlEnum.TWO.getMethod());
// 失衡 优化中,15分钟内,优化中,其他,优化完
aiOptResultVO.setOptStatus(OptStatusEnum.ZERO.getCode());
Date issueTimeDate = resultEntity.getIssueTime();
Integer countDown = Objects.isNull(resultEntity.getCountDown()) ? 0 : resultEntity.getCountDown();
long optTime = issueTimeDate.getTime();
long currentTimeMillis = System.currentTimeMillis();
long offset = (currentTimeMillis - optTime) / 1000;
if (Objects.equals(1, currentAlgo)) {
if (offset <= 15 * 60 * 1000) {
aiOptResultVO.setOptStatus(OptStatusEnum.ONE.getCode());
}
} else {
if (offset <= countDown ) {
aiOptResultVO.setOptStatus(OptStatusEnum.ONE.getCode());
}
}
aiOptResultVO.setOptStatusName(OptStatusEnum.getDesc(aiOptResultVO.getOptStatus()));
} else {
aiOptResultVO.setOptStatus(OptStatusEnum.ZERO.getCode());
aiOptResultVO.setOptStatusName(OptStatusEnum.getDesc(aiOptResultVO.getOptStatus()));
}
results.add(aiOptResultVO);
}
}
} catch (Exception e) {
log.error("AI路口监测查询异常:", e);
throw new RuntimeException(e);
}
Collections.sort(results, Comparator.comparingInt(AIOptResultVO::getOptStatus).reversed());
return results;
}
@Override
public List<CrossStatusCountVO> crossStatusCount(String crossId) throws Exception {
List<CrossStatusCountVO> results = new ArrayList<>();
try {
LocalDate currentDate = LocalDate.now();
LocalTime startTime = LocalTime.MIDNIGHT;
LocalDateTime startOfDay = LocalDateTime.of(currentDate, startTime);
LambdaQueryWrapper<HoloEventInfoPO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(HoloEventInfoPO::getCrossId, crossId);
queryWrapper.ge(HoloEventInfoPO::getStartTime, startOfDay);
List<HoloEventInfoPO> holoEventInfoPOS = holoEventMapper.selectList(queryWrapper);
if (!CollectionUtils.isEmpty(holoEventInfoPOS)) {
Map<String, List<HoloEventInfoPO>> eventTypeMap = holoEventInfoPOS.stream().collect(Collectors.groupingBy(HoloEventInfoPO::getType));
for (Map.Entry<String, List<HoloEventInfoPO>> entry : eventTypeMap.entrySet()) {
String eventType = entry.getKey();
List<HoloEventInfoPO> value = entry.getValue();
// 过滤干线
if (StringUtils.equalsIgnoreCase(eventType, EventInfoTypeEnum.GREEN_SLOW.getEventType())
|| StringUtils.equalsIgnoreCase(eventType, EventInfoTypeEnum.GREEN_CONGEST.getEventType())) {
continue;
}
// 当前事件返回实体
CrossStatusCountVO crossStatusCountVO = new CrossStatusCountVO();
crossStatusCountVO.setType(EventInfoTypeEnum.getOptType(eventType));
crossStatusCountVO.setCount(value.size());
List<CrossStatusCountVO.DirTurn> dirTurns = new ArrayList<>();
if (!CollectionUtils.isEmpty(value)) {
for (HoloEventInfoPO holoEventInfoPO : value) {
CrossStatusCountVO.DirTurn dirTurn = new CrossStatusCountVO.DirTurn();
dirTurn.setDir(holoEventInfoPO.getDir());
dirTurn.setTurn(holoEventInfoPO.getTurn());
dirTurns.add(dirTurn);
}
}
crossStatusCountVO.setList(dirTurns);
results.add(crossStatusCountVO);
}
}
} catch (Exception e) {
log.error("优化监测-问题诊断查询异常:", e);
throw new RuntimeException(e);
}
return results;
}
@Override
public CrossDirStatusDataPO selectByCrossIdAndHour(String crossId, int hour) {
List<CrossDirDataHistPO> crossDirDataHistPOS = crossDirDataHistMapper.selectByCrossIdAndHour(crossId, hour);
CrossDirStatusDataPO crossDirStatusDataPO = new CrossDirStatusDataPO();
if (ObjectUtil.isNotEmpty(crossDirDataHistPOS)){
//LocalDateTimeUtil.formatTimeStamp(Long.valueOf(x.getBatchTime())*1000, "HH:mm")
//根据dirType升序,分组
LinkedHashMap<Integer, List<CrossDirDataHistPO>> stringListMap = crossDirDataHistPOS.stream().sorted(Comparator.comparing(CrossDirDataHistPO::getDirType)).collect(Collectors.groupingBy(x -> x.getDirType(), LinkedHashMap::new, Collectors.toList()));
Set<Integer> stringSet = stringListMap.keySet();
Map<Integer, List<Integer>> dirStatusListMap = new HashMap<>();
for (Integer dir : stringSet) {
List<Integer> list = stringListMap.get(dir).stream().sorted(Comparator.comparing(CrossDirDataHistPO::getBatchTime)).map(x -> x.getStatus()).collect(Collectors.toList());
dirStatusListMap.put(dir,list);
}
//获取第一个方向
Integer firstDir = stringSet.iterator().next();
List<String> timeList = stringListMap.get(firstDir).stream().sorted(Comparator.comparing(CrossDirDataHistPO::getBatchTime)).map(x -> LocalDateTimeUtil.formatTimeStamp(Long.valueOf(x.getBatchTime()) * 1000, "HH:mm")).collect(Collectors.toList());
crossDirStatusDataPO.setTimeList(timeList);
crossDirStatusDataPO.setDirStatusListMap(dirStatusListMap);
}
return crossDirStatusDataPO;
}
@Override
public HoloEventInfoPO crossEventDirTurn(String crossId) throws Exception {
try {
LambdaQueryWrapper<HoloEventInfoPO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(HoloEventInfoPO::getCrossId, crossId);
queryWrapper.orderByDesc(HoloEventInfoPO::getStartTime);
queryWrapper.last("limit 1");
HoloEventInfoPO holoEventInfoPO = holoEventMapper.selectOne(queryWrapper);
if (Objects.nonNull(holoEventInfoPO)) {
return holoEventInfoPO;
}
return null;
} catch (Exception e) {
log.error("交通体检-路口监测-事件方向转向 查询失败:", e);
throw new Exception(e);
}
}
@Override
public List<CrossEventListPO> selectCrossEventList() throws Exception {
List<CrossEventListPO> holoEventInfoPOS = holoEventMapper.selectCrossEventList();
return holoEventInfoPOS;
}
}
package net.wanji.opt.service.impl;
import net.wanji.opt.service.CrossInfoService;
import org.springframework.stereotype.Service;
/**
* @author hfx
* @date 2023/1/12 15:12
* @desc CrossInfoServiceImpl
*/
@Service
public class CrossInfoServiceImpl implements CrossInfoService {
// @Resource
// CrossInfoMapper crossInfoMapper;
//
// public List<CrossInfoDTO> listCrossInfo(CrossQuery query) {
//
// // 获取数据库数据
// List<CrossInfoPO> crossInfoPOList = crossInfoMapper.listCrossInfo(query);
// return BeanListUtils.populateList(crossInfoPOList, new ArrayList<>(), CrossInfoDTO.class);
// }
}
package net.wanji.opt.service.impl;//package net.wanji.opt.service.impl;
//package net.wanji.opt.service.impl;
//
//import lombok.extern.slf4j.Slf4j;
//import net.wanji.common.utils.tool.BeanListUtils;
......
package net.wanji.opt.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.CrossStatusEnum;
import net.wanji.common.framework.Constants;
import net.wanji.common.framework.rest.JsonViewObject;
import net.wanji.common.utils.tool.BeanListUtils;
import net.wanji.common.utils.tool.BeanMapUtils;
import net.wanji.databus.dao.entity.BaseCrossSchemePO;
import net.wanji.databus.dao.entity.CrossPhasePO;
import net.wanji.databus.dao.entity.RidInfoEntity;
import net.wanji.databus.dao.mapper.CrossDirDataRealtimeMapper;
import net.wanji.databus.dao.mapper.CrossTurnDataRealtimeMapper;
import net.wanji.databus.dto.CrossDirInfoDTO;
import net.wanji.databus.dto.CrossTurnInfoDTO;
import net.wanji.databus.entity.develop.servicedevelop.develop.StatusCodeEnum;
import net.wanji.databus.po.CrossDataRealtimePO;
import net.wanji.databus.po.CrossDirDataRealtimePO;
import net.wanji.databus.po.CrossTurnDataRealtimePO;
import net.wanji.databus.vo.SchemeSendVO;
import net.wanji.databus.vo.SignalStatusVO;
import net.wanji.feign.service.UtcFeignClients;
import net.wanji.opt.cache.*;
import net.wanji.opt.common.exception.OptServiceException;
import net.wanji.opt.dao.mapper.CrossSchemeOptLogMapper;
import net.wanji.opt.dto.CrossPhaseDTO;
import net.wanji.opt.dto.CrossTurnDataRealtimeDTO;
import net.wanji.opt.po.base.CrossSchemeOptLogPO;
import net.wanji.opt.po.strategy.SceneStrategyIdeaPO;
import net.wanji.opt.service.CrossOptimizeService;
import net.wanji.opt.service.strategy.SceneService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author hfx
* @date 2023/1/10 15:15
* @desc CrossOptimizeServiceImpl
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class CrossOptimizeServiceImpl implements CrossOptimizeService {
private final CrossSchemeOptLogMapper crossSchemeOptLogMapper;
private final UtcFeignClients utcFeignClients;
private final CrossDirTurnPhaseCache crossDirTurnPhaseCache;
private final CrossRidInfoCache crossRidInfoCache;
private final SceneService sceneService;
private final CrossTurnDataRealtimeMapper crossTurnDataRealtimeMapper;
private final CrossDirDataRealtimeMapper crossDirDataRealtimeMapper;
private final BaseCrossInfoCache crossInfoCache;
private final BaseCrossSchemeInfoCache baseCrossSchemeInfoCache;
private final BaseCrossPhaseInfoCache baseCrossPhaseInfoCache;
@Value("${crossOptParam.maxVehheadDist}")
private Double maxVehheadDist;
@Value("${crossOptParam.minVehheadDist}")
private Double minVehheadDist;
@Value("${crossOptParam.defaultVehheadDist}")
private Double defaultVehheadDist;
@Value("${crossOptParam.maxVehheadTime}")
private Double maxVehheadTime;
@Value("${crossOptParam.minVehheadTime}")
private Double minVehheadTime;
@Value("${crossOptParam.defaultVehheadTime}")
private Double defaultVehheadTime;
static Set<String> CROSS_OPT = new HashSet<>(); // 记录已优化的路口
@Override
@Transactional
public String realtimeOptimize(List<CrossDataRealtimePO> abnormalCrossList, List<CrossDataRealtimePO> crossDataRealtimePOList) {
try {
// todo 系统管理,路口管理,信控标志关闭,优化下发也要关闭
// 相位配时信息,key: 路口编号_方向类型_转向类型,value: 相位配时信息
crossDirTurnPhaseCache.refresh();
Map<String, CrossPhaseDTO> phaseMap = crossDirTurnPhaseCache.getPhaseDirTurnMap();
setTurnList(abnormalCrossList, phaseMap);
setTurnList(crossDataRealtimePOList, phaseMap);
// 获取所有信控路口转向实时数据,包括异常路口和正常路口
// Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtimeMap = listTurnDataRealtime(crossDataRealtimePOList);
List<CrossTurnDataRealtimePO> crossTurnDataRealtimePOS = crossTurnDataRealtimeMapper.selectList(new LambdaQueryWrapper<CrossTurnDataRealtimePO>());
ArrayList<CrossTurnDataRealtimeDTO> turnDataRealtimeList = new ArrayList<>();
BeanListUtils.populateList(crossTurnDataRealtimePOS, turnDataRealtimeList, CrossTurnDataRealtimeDTO.class);
Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtimeMap = turnDataRealtimeList.stream().collect(Collectors.groupingBy(CrossTurnDataRealtimeDTO::getCrossId));
// 恢复优化路口原始方案:上一批次优化后,路口正常需要恢复原始方案
// todo 方案运行时间,恢复时当前时间是否在远方案运行时间内,否则phaseMap数据不准确
restoreOptCrossOriSchema(abnormalCrossList, phaseMap);
Map<Integer, List<CrossDataRealtimePO>> crossDataMap = abnormalCrossList.stream().collect(Collectors.groupingBy(CrossDataRealtimePO::getStatus));
abnormalCrossList = crossDataMap.get(CrossStatusEnum.SPILLOVER.getCode()); // 溢出
if (abnormalCrossList != null && !abnormalCrossList.isEmpty()) {
spilloverOpt(abnormalCrossList, turnDataRealtimeMap, phaseMap);
}
abnormalCrossList = crossDataMap.get(CrossStatusEnum.CONGESTION.getCode()); // 拥堵
if (abnormalCrossList != null && !abnormalCrossList.isEmpty()) {
congestionOpt(abnormalCrossList, turnDataRealtimeMap, phaseMap);
}
abnormalCrossList = crossDataMap.get(CrossStatusEnum.UNBALANCE.getCode()); // 失衡
if (abnormalCrossList != null && !abnormalCrossList.isEmpty()) {
unbalanceOpt(abnormalCrossList, turnDataRealtimeMap, phaseMap);
}
} catch (Exception e) {
e.printStackTrace();
log.error("实时优化", e.getMessage());
}
return null;
}
/**
* 路口溢出优化
*
* @param abnormalCrossList
* @param turnDataRealtimeMap
* @param phaseMap
*/
private void spilloverOpt(List<CrossDataRealtimePO> abnormalCrossList, Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtimeMap,
Map<String, CrossPhaseDTO> phaseMap) throws Exception {
// todo 获取溢出场景当前执行的策略方法的指标数据,通过指标数据进行下发方案
SceneStrategyIdeaPO sceneStrategyIdeaPO = sceneService.selectIdBySceneNum(CrossStatusEnum.SPILLOVER.getCode());
// 溢出路口集合
Map<String, List<CrossDataRealtimePO>> congestCrossMap = abnormalCrossList.stream().collect(Collectors.groupingBy(CrossDataRealtimePO::getCrossId));
String crossId;
for (CrossDataRealtimePO cross : abnormalCrossList) {
crossId = cross.getCrossId();
// 不是信控路口跳过
if (!isSignalCross(crossId)) {
continue;
}
// 判断信号机是否在线 todo 是否某些故障也不需要优化
// 判断当前路口是否存在特殊控制操作
if (isOffLineOrSpecialControlMode(crossId)) {
continue;
}
// 判断当前路口是否已优化
if (CROSS_OPT.contains(crossId)) {
continue;
}
// 判断路口是否是绿波
// 路口拥堵进口方向,dir
List<Integer> optCrossDirList = getOptCrossInDirList(crossId);
// 溢出当前路口方向转向减少时间 10s
// 计算路口各转向所需的通行时长(秒)
List<CrossTurnDataRealtimeDTO> crossTurnDataRealtimeDTOS = turnDataRealtimeMap.get(crossId);
for (Integer dir : optCrossDirList) {
for (CrossTurnDataRealtimeDTO crossTurnDataRealtimeDTO : crossTurnDataRealtimeDTOS) {
Integer inDir = crossTurnDataRealtimeDTO.getInDir();
if (Objects.equals(dir, inDir)) {
crossTurnDataRealtimeDTO.setPassTime(-10.0);
}
}
}
// 溢出优化当前路口 直行
doExecuteCrossOpt(crossTurnDataRealtimeDTOS, phaseMap, crossId, "3");
// 下游路口通过可排队长度计算可加可减时间优化
// 获取下游路口
List<RidInfoEntity> ridInfoEntities = crossRidInfoCache.getRidInfoListByCrossId(crossId, Constants.SystemParam.NULL);
// 不存在下游路口,不做处理
if (CollectionUtils.isEmpty(ridInfoEntities)) {
continue;
}
for (Integer dir : optCrossDirList) {
for (RidInfoEntity ridInfoEntity : ridInfoEntities) {
Integer inDir = ridInfoEntity.getInDir();
if (!congestCrossMap.containsKey(ridInfoEntity.getEndCrossId()) && Objects.equals(inDir, dir)) {
String endCrossId = ridInfoEntity.getEndCrossId();
// 判断当前路口是否已优化
if (CROSS_OPT.contains(endCrossId)) {
continue;
}
List<CrossTurnDataRealtimeDTO> endcrossTurnDataRealtimeDTOS = turnDataRealtimeMap.get(endCrossId);
if (CollectionUtils.isEmpty(endcrossTurnDataRealtimeDTOS)) {
log.error("溢出路口:{},优化其下游路口:{}时,路口转向数据为空", crossId, ridInfoEntity.getEndCrossId());
throw new OptServiceException("实时监控->溢出路口方案优化异常,优化路口转向数据异常");
}
endcrossTurnDataRealtimeDTOS.forEach(item -> item.setPassTime(calPassTime(item)));
// 进行优化下发
doExecuteCrossOpt(crossTurnDataRealtimeDTOS, phaseMap, endCrossId, "3");
// 记录已优化的路口
CROSS_OPT.add(endCrossId);
}
}
}
}
}
/**
* 是否是信控路口
*
* @param crossId
* @return
*/
private boolean isSignalCross(String crossId) {
List<String> isSignalCrossIdList = crossInfoCache.getIsSignalCrossIdList();
if (isSignalCrossIdList.contains(crossId)) {
return true;
}
return false;
}
/**
* 路口拥堵优化
*
* @param abnormalCrossList
* @param turnDataRealtimeMap
* @param phaseMap
*/
private void congestionOpt(List<CrossDataRealtimePO> abnormalCrossList, Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtimeMap,
Map<String, CrossPhaseDTO> phaseMap) throws Exception {
// 获取拥堵场景当前执行的策略方法的指标数据,通过指标数据进行下发方案
SceneStrategyIdeaPO sceneStrategyIdeaPO = sceneService.selectIdBySceneNum(CrossStatusEnum.CONGESTION.getCode());
// 拥堵路口集合
Map<String, List<CrossDataRealtimePO>> congestCrossMap = abnormalCrossList.stream().collect(Collectors.groupingBy(CrossDataRealtimePO::getCrossId));
String crossId;
for (CrossDataRealtimePO cross : abnormalCrossList) {
crossId = cross.getCrossId();
// 不是信控路口跳过
if (!isSignalCross(crossId)) {
continue;
}
// 判断信号机是否在线 todo 是否某些故障也不需要优化
// 判断当前路口是否存在特殊控制操作
if (isOffLineOrSpecialControlMode(crossId)) {
continue;
}
// 路口拥堵方向转向,dir_turn
List<Integer> optCrossDirList = getOptCrossInDirList(crossId);
// 判断当前路口是否已优化
if (CROSS_OPT.contains(crossId)) {
continue;
}
// 判断路口是否是绿波
// 获取上游路口
List<RidInfoEntity> ridInfoEntities = crossRidInfoCache.getRidInfoListByCrossId(Constants.SystemParam.NULL, crossId);
// 不存在上游路口,不做处理
if (CollectionUtils.isEmpty(ridInfoEntities)) {
continue;
}
// 当前路口拥堵方向,优化当前路口方向的上游路口的直行和左转方向
for (Integer intCongestionDir : optCrossDirList) {
// 拥堵路口对上游路口进 行优化
for (RidInfoEntity ridInfoEntity : ridInfoEntities) {
String startCrossId = ridInfoEntity.getStartCrossId();
// 上游路口时拥堵路口时,不进行优化或者判断当前路口是否已优化
if (congestCrossMap.containsKey(startCrossId) || CROSS_OPT.contains(startCrossId)) {
continue;
}
Integer inDir = ridInfoEntity.getInDir();
// 优化当前开始路口的此方向直行,和逆时针方向左转
if (Objects.equals(inDir, intCongestionDir)) {
// 计算上游路口各转向所需的通行时长(秒) 此方向和逆时针左转可可减时间 10s
List<CrossTurnDataRealtimeDTO> crossTurnDataRealtimeDTOS = turnDataRealtimeMap.get(startCrossId);
if (!CollectionUtils.isEmpty(crossTurnDataRealtimeDTOS)) {
for (CrossTurnDataRealtimeDTO crossTurnDataRealtimeDTO : crossTurnDataRealtimeDTOS) {
Integer startInDir = crossTurnDataRealtimeDTO.getInDir();
String turnType = crossTurnDataRealtimeDTO.getTurnType();
if (Objects.equals(startInDir, intCongestionDir)) {
crossTurnDataRealtimeDTO.setPassTime(-10.0);
}
if (intCongestionDir > 7 && Objects.equals(startInDir, (intCongestionDir + 2) == 9 ? 1 : intCongestionDir + 2) && Objects.equals("l", turnType)) {
crossTurnDataRealtimeDTO.setPassTime(-10.0);
}
}
// 进行优化下发
doExecuteCrossOpt(crossTurnDataRealtimeDTOS, phaseMap, startCrossId, "2");
// 记录已优化的路口
CROSS_OPT.add(crossId);
} else {
log.error("当前拥堵路口: {}, 实时监控->优化上游路口: {}时,未获取到上游路口的实时转向数据!", crossId, startCrossId);
}
}
}
}
}
}
/**
* 路口失衡优化
*
* @param abnormalCrossList 失衡路口实时数据
* @param turnDataRealtimeMap 路口转向实时数据
* @param phaseMap 路口相位配时数据
*/
private void unbalanceOpt(List<CrossDataRealtimePO> abnormalCrossList, Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtimeMap,
Map<String, CrossPhaseDTO> phaseMap) throws Exception {
// 获取失衡场景当前执行的策略方法的指标数据,通过指标数据进行下发方案
SceneStrategyIdeaPO sceneStrategyIdeaPO = sceneService.selectIdBySceneNum(CrossStatusEnum.CONGESTION.getCode());
String crossId;
for (CrossDataRealtimePO cross : abnormalCrossList) {
crossId = cross.getCrossId();
// 不是信控路口跳过
if (!isSignalCross(crossId)) {
continue;
}
// 判断信号机是否在线 todo 是否某些故障也不需要优化
// 判断当前路口是否存在特殊控制操作
if (isOffLineOrSpecialControlMode(crossId)) {
continue;
}
// 判断当前路口是否已优化
if (CROSS_OPT.contains(crossId)) {
continue;
}
// 判断路口是否是绿波
// 计算路口各转向所需的通行时长(秒)
List<CrossTurnDataRealtimeDTO> crossTurnDataRealtimeDTOS = turnDataRealtimeMap.get(crossId);
crossTurnDataRealtimeDTOS.forEach(item -> item.setPassTime(calPassTime(item)));
// 执行路口优化
doExecuteCrossOpt(crossTurnDataRealtimeDTOS, phaseMap, crossId, "1");
// 记录已优化的路口
CROSS_OPT.add(crossId);
}
}
private List<Integer> getOptCrossInDirList(String crossId) {
LambdaQueryWrapper<CrossDirDataRealtimePO> dirWrapper = new LambdaQueryWrapper<>();
dirWrapper.eq(CrossDirDataRealtimePO::getCrossId, crossId);
dirWrapper.eq(CrossDirDataRealtimePO::getInOutType, 1);
List<CrossDirDataRealtimePO> crossDirDataRealtimePOS = crossDirDataRealtimeMapper.selectList(dirWrapper);
List<Integer> optCrossDirList = crossDirDataRealtimePOS.stream().map(CrossDirDataRealtimePO::getDirType).collect(Collectors.toList());
return optCrossDirList;
}
/**
* 设置异常数据转向数据
*
* @param abnormalCrossList
* @param phaseMap
*/
private static void setTurnList(List<CrossDataRealtimePO> abnormalCrossList, Map<String, CrossPhaseDTO> phaseMap) {
for (CrossDataRealtimePO crossDataRealtimeDTO : abnormalCrossList) {
List<CrossTurnInfoDTO> turnList = new ArrayList<>();
List<CrossDirInfoDTO> dirList = new ArrayList<>();
for (Map.Entry<String, CrossPhaseDTO> entry : phaseMap.entrySet()) {
String crossDirTurn = entry.getKey();
String[] split = crossDirTurn.split(Constants.SystemParam.SEPARATOR_UNDER_LINE);
String crossId = split[0];
String dir = split[1];
String turn = split[2];
CrossTurnInfoDTO crossTurnInfoDTO = new CrossTurnInfoDTO();
CrossDirInfoDTO crossDirInfoDTO = new CrossDirInfoDTO();
if (StringUtils.equals(crossId, crossDataRealtimeDTO.getCrossId())) {
crossDirInfoDTO.setCrossId(crossId);
crossDirInfoDTO.setInOutType(1);
crossDirInfoDTO.setDirType(Integer.valueOf(dir));
dirList.add(crossDirInfoDTO);
crossTurnInfoDTO.setTurnType(turn);
crossTurnInfoDTO.setInDir(Integer.valueOf(dir));
crossTurnInfoDTO.setCrossId(crossId);
turnList.add(crossTurnInfoDTO);
}
}
}
}
/**
* 通过第二批次列表,判断需要恢复的优化路口原始方案
*
* @param abnormalCrossList
*/
private void restoreOptCrossOriSchema(List<CrossDataRealtimePO> abnormalCrossList, Map<String, CrossPhaseDTO> phaseMap) throws Exception {
List<String> abnormalCrossIdList = abnormalCrossList.stream().map(CrossDataRealtimePO::getCrossId).collect(Collectors.toList());
for (String optCrossId : CROSS_OPT) {
if (!abnormalCrossIdList.contains(optCrossId)) {
// 下发原始方案
SchemeSendVO schemeSendVO = getSchemeSendVO(optCrossId, phaseMap, Collections.EMPTY_MAP);
JsonViewObject jsonViewObject = utcFeignClients.schemeSend(schemeSendVO);
if (Objects.isNull(jsonViewObject) || jsonViewObject.getCode() != 200) {
log.error("实时监控->路口优化方案下发远程调用异常!", jsonViewObject);
throw new OptServiceException("实时监控->恢复原始方案调用UTC服务异常");
}
CROSS_OPT.remove(optCrossId);
}
}
}
/**
* 执行路口优化逻辑
* 计算路口相位优化时长并下发方案
*
* @param crossTurnDataRealtimeDTOS
* @param phaseMap
* @param crossId
* @throws Exception
*/
private void doExecuteCrossOpt(List<CrossTurnDataRealtimeDTO> crossTurnDataRealtimeDTOS, Map<String, CrossPhaseDTO> phaseMap, String crossId, String optType) throws Exception {
// 计算路口各相位调整时长(秒)
Map<String, Integer> phaseTimeOptResultMap = new HashMap<>();
Map<String, Integer> phaseTimeOffset = getTimeOffsetPhaseMap(phaseMap, crossTurnDataRealtimeDTOS);
// 是否需要拆分相位
if (isSplitPhase(phaseTimeOffset)) {
} else {
phaseTimeOptResultMap = getPhaseTimeOptMap(phaseTimeOffset);
}
if (!phaseTimeOptResultMap.isEmpty()) {
// 修改原始方案绿灯时间为优化后时间,方案下发
SchemeSendVO schemeSendVO = getSchemeSendVO(crossId, phaseMap, phaseTimeOptResultMap);
JsonViewObject jsonViewObject = utcFeignClients.schemeSend(schemeSendVO);
//todo test下发成功
jsonViewObject.success();
if (Objects.isNull(jsonViewObject) || jsonViewObject.getCode() != 200) {
log.error("实时监控->路口优化方案下发远程调用异常!", jsonViewObject);
throw new OptServiceException("实时监控->下发优化方案调用UTC服务异常");
}
// 将优化记录插入方案优化记录表
insertCrossSchemeOptLog(phaseTimeOptResultMap, phaseMap, optType);
}
}
/**
* 将优化记录数据[按路口相位转向]插入到优化记录表这种
*
* @param phaseTimeOptResultMap
* @param phaseMap
*/
private void insertCrossSchemeOptLog(Map<String, Integer> phaseTimeOptResultMap, Map<String, CrossPhaseDTO> phaseMap, String optType) {
List<CrossSchemeOptLogPO> insertList = new ArrayList<>();
// 数据批次
long dataBatchTimeLong = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
for (Map.Entry<String, CrossPhaseDTO> item : phaseMap.entrySet()) {
CrossSchemeOptLogPO crossSchemeOptLogPO = new CrossSchemeOptLogPO();
CrossPhaseDTO crossPhaseDTO = item.getValue();
String phaseNo = crossPhaseDTO.getPhaseNo();
for (Map.Entry<String, Integer> entry : phaseTimeOptResultMap.entrySet()) {
if (Objects.equals(phaseNo, entry.getKey())) {
BeanUtils.copyProperties(crossPhaseDTO, crossSchemeOptLogPO);
crossSchemeOptLogPO.setSchemeId(crossPhaseDTO.getSchemeId());
crossSchemeOptLogPO.setPhaseOrderId(crossPhaseDTO.getSort());
crossSchemeOptLogPO.setStartTime(new Date());
crossSchemeOptLogPO.setOptType("1");// 自动优化
crossSchemeOptLogPO.setOptType(optType);
crossSchemeOptLogPO.setOptResult("1");
crossSchemeOptLogPO.setOptResultDesc(StatusCodeEnum.STATUS_00200.getDetail());
crossSchemeOptLogPO.setDataBatchTime((int) dataBatchTimeLong);
// todo 测试数据
crossSchemeOptLogPO.setDataExtend("{\"sceneName\": \"测试JSON\",\"strategyName\": \"测试JSON\",\"ideaName\": \"测试JSON\"}");// todo 需要通过场景策略方法
crossSchemeOptLogPO.setOptTime(entry.getValue());
crossSchemeOptLogPO.setOriGreenTime(crossPhaseDTO.getGreenTime());
insertList.add(crossSchemeOptLogPO);
}
}
}
crossSchemeOptLogMapper.insertBatch(insertList);
}
/**
* 构建下发的优化方案
* 如果phaseTimeOptResultMap=null,下发的原始方案
* 否则原始方案和相位优化时间参数phaseTimeOptResultMap构建下发参数
*
* @param crossId
* @param phaseMap
* @param phaseTimeOptResultMap
* @return
*/
public SchemeSendVO getSchemeSendVO(String crossId, Map<String, CrossPhaseDTO> phaseMap, Map<String, Integer> phaseTimeOptResultMap) throws Exception {
String key = String.join(Constants.SystemParam.SEPARATOR_UNDER_LINE, crossId, "1", "s");
CrossPhaseDTO crossPhaseDTO = phaseMap.get(key);
if (Objects.isNull(crossPhaseDTO)) {
log.error("当前路口:{}未获取到信号机方案信息,无法进行方案下发优化", crossId);
throw new OptServiceException("当前路口不能获取到运行方案相位信息!");
}
Integer schemeId = crossPhaseDTO.getSchemeId();
BaseCrossSchemePO baseCrossSchemePO = baseCrossSchemeInfoCache.getSchemePOCache(String.join(Constants.SystemParam.SEPARATOR_UNDER_LINE, crossId, String.valueOf(schemeId)));
// 当前路口方案号的相位参数
Map<Integer, List<CrossPhasePO>> ringNoPhasePOMap = baseCrossPhaseInfoCache.getCrossPhaseCacheByCrossId(crossId).stream().filter(po -> Objects.equals(schemeId, po.getPlanId())).collect(Collectors.groupingBy(CrossPhasePO::getRingNo));
SchemeSendVO schemeSendVO = new SchemeSendVO();
List<SchemeSendVO.Pattern> patternList = new ArrayList<>();
if (Objects.nonNull(baseCrossSchemePO)) {
SchemeSendVO.Pattern pattern = new SchemeSendVO.Pattern();
pattern.setPatternName("实时监测优化方案".concat(baseCrossSchemePO.getSchemeNo()));
pattern.setPatternNo(String.valueOf(baseCrossSchemePO.getId()));
pattern.setCycle(String.valueOf(baseCrossSchemePO.getCycle()));
pattern.setOffset(String.valueOf(baseCrossSchemePO.getOffset()));
pattern.setCoordPhase(String.valueOf(baseCrossSchemePO.getCoordPhase()));
List<SchemeSendVO.Pattern.Ring> rings = new ArrayList<>();
ringNoPhasePOMap.entrySet().forEach(entry -> {
SchemeSendVO.Pattern.Ring ring = new SchemeSendVO.Pattern.Ring();
List<SchemeSendVO.Pattern.Ring.Phase> phaseList = new ArrayList<>();
List<CrossPhasePO> value = entry.getValue();
value.forEach(crossPhasePO -> {
SchemeSendVO.Pattern.Ring.Phase phase = new SchemeSendVO.Pattern.Ring.Phase();
phase.setPhaseNo(crossPhasePO.getPhaseNo());
phase.setPhaseName(crossPhasePO.getName());
phase.setSort(String.valueOf(crossPhasePO.getSort()));
phase.setControlMode(String.valueOf(crossPhasePO.getControlMode()));
phase.setMinGreenTime(String.valueOf(crossPhasePO.getMinGreenTime()));
phase.setMaxGreenTime(String.valueOf(crossPhasePO.getMaxGreenTime()));
// 可优化时间
Integer currentPhaseOffset = getCurrentPhaseOptOffsetTime(phaseTimeOptResultMap, crossPhasePO.getPhaseNo());
phase.setPhaseTime(String.valueOf(crossPhasePO.getPhaseTime() + currentPhaseOffset));
phase.setGreenTime(String.valueOf(crossPhasePO.getGreenTime() + currentPhaseOffset));
phase.setGreenFlashTime(String.valueOf(crossPhasePO.getGreenFlashTime()));
phase.setPedFlashTime(String.valueOf(crossPhasePO.getPedFlashTime()));
phase.setYellowTime(String.valueOf(crossPhasePO.getYellowTime()));
phase.setRedTime(String.valueOf(crossPhasePO.getRedTime()));
phaseList.add(phase);
});
ring.setRingNo(String.valueOf(entry.getKey()));
ring.setPhaseList(phaseList);
rings.add(ring);
});
pattern.setRings(rings);
patternList.add(pattern);
}
schemeSendVO.setCrossCode(crossId);
schemeSendVO.setPatternList(patternList);
return schemeSendVO;
}
/**
* 获取当前相位的可优化时间,默认0
*
* @param phaseTimeOptResultMap
* @param phaseNo
* @return
*/
private static int getCurrentPhaseOptOffsetTime(Map<String, Integer> phaseTimeOptResultMap, String phaseNo) {
if (Objects.nonNull(phaseTimeOptResultMap) && !phaseTimeOptResultMap.isEmpty()) {
for (Map.Entry<String, Integer> phaseEntry : phaseTimeOptResultMap.entrySet()) {
if (StringUtils.equals(phaseNo, phaseEntry.getKey())) {
Integer optTime = phaseTimeOptResultMap.get(phaseNo);
return optTime;
}
}
}
return 0;
}
/**
* 在最大最小绿范围内,通过转向优化计算相位可优化时间
* key:相位号 value:offsetTime
*
* @param timeOffsetPhaseMap
* @return
*/
private static Map<String, Integer> getPhaseTimeOptMap(Map<String, Integer> timeOffsetPhaseMap) {
HashMap<String, Integer> phaseTimeOptResultMap = new HashMap<>();
// key:相位号 value:最大可加减时间
Map<String, Integer> phaseOffsetTimeSetMap = new HashMap<>();
for (Map.Entry<String, Integer> entry : timeOffsetPhaseMap.entrySet()) {
Integer offsetTime = entry.getValue() == null ? 0 : entry.getValue();
String phaseNo = entry.getKey();
if (phaseOffsetTimeSetMap.containsKey(phaseNo)) {
Integer currentOffsetTime = phaseOffsetTimeSetMap.get(phaseNo);
if (Math.abs(offsetTime) > Math.abs(currentOffsetTime)) {
phaseOffsetTimeSetMap.put(phaseNo, offsetTime);
} else {
phaseOffsetTimeSetMap.put(phaseNo, currentOffsetTime);
}
} else {
phaseOffsetTimeSetMap.put(phaseNo, offsetTime);
}
}
List<Integer> subTimeList = phaseOffsetTimeSetMap.entrySet().stream().map(entry -> entry.getValue()).collect(Collectors.toList()).stream().filter(i -> i < 0).collect(Collectors.toList());
List<Integer> addTimeList = phaseOffsetTimeSetMap.entrySet().stream().map(entry -> entry.getValue()).collect(Collectors.toList()).stream().filter(i -> i > 0).collect(Collectors.toList());
int subTimeSum = subTimeList.stream().mapToInt(Integer::intValue).sum();
int addTimeSum = addTimeList.stream().mapToInt(Integer::intValue).sum();
int countOffsetAdd = Math.abs(subTimeSum) >= addTimeSum ? addTimeSum : Math.abs(subTimeSum);
int countOffsetSub = -countOffsetAdd;
// 可加可减时间为0,不需要计算相位时间
if (countOffsetAdd == 0) {
return Collections.EMPTY_MAP;
}
for (Map.Entry<String, Integer> entry : phaseOffsetTimeSetMap.entrySet()) {
Integer offsetTime = entry.getValue();
String phaseNo = entry.getKey();
if (countOffsetAdd <= 0 && countOffsetSub >= 0) {
break;
}
// 可加时间有可减时间
if (offsetTime > 0 && countOffsetSub < 0) {
int currentSub = countOffsetSub;
countOffsetSub += offsetTime;
if (countOffsetSub <= 0) {
phaseTimeOptResultMap.put(phaseNo, offsetTime);
} else {
phaseTimeOptResultMap.put(phaseNo, -currentSub);
}
}
// 可减时间有可加时间
if (offsetTime < 0 && countOffsetAdd > 0) {
int cuttentAdd = countOffsetAdd;
countOffsetAdd += offsetTime;
if (countOffsetAdd >= 0) {
phaseTimeOptResultMap.put(phaseNo, offsetTime);
} else {
phaseTimeOptResultMap.put(phaseNo, cuttentAdd);
}
}
}
return phaseTimeOptResultMap;
}
/**
* 是否需要拆分相位灯组
* 同一相位内不同转向同时存在可加可减,需要拆分相位
*
* @param timeOffsetPhaseMap
* @return
*/
private boolean isSplitPhase(Map<String, Integer> timeOffsetPhaseMap) {
HashMap<String, Boolean> phaseOffsetMap = new HashMap<>();
for (Map.Entry<String, Integer> entry : timeOffsetPhaseMap.entrySet()) {
Boolean gtZore = entry.getValue() >= 0 ? Boolean.TRUE : Boolean.FALSE;
String phaseNo = entry.getKey();
if (phaseOffsetMap.containsKey(phaseNo) && !phaseOffsetMap.containsValue(gtZore)) {
return true;
}
}
return false;
}
/**
* 计算路口各相位调整时长(秒)
* 相位所需总放行时长 = sum(相位所需放行时长) - 总放行时长(周期)
* 相位可减时长 = 相位有效绿灯时长 - 相位所需时长,同时“相位剩余有效绿灯时长”必须介于最小绿时长与最大绿时长之间
* 相位可加时长 = 相位所需时长 - 有效绿灯时长
* 相位可用总时长 = sum(相位可减时长)
* 相位优化时长 = 原相位时长 + 相位调整时长(相位可减时长或相位可加时长)
*
* @param phaseMap
* @param crossTurnDataRealtimeDTOS
* @return key:相位编号 value:相位可加减时间
*/
private Map<String, Integer> getTimeOffsetPhaseMap(Map<String, CrossPhaseDTO> phaseMap, List<CrossTurnDataRealtimeDTO> crossTurnDataRealtimeDTOS) {
Map<String, Integer> timeOffsetPhaseMap = new HashMap<>();
crossTurnDataRealtimeDTOS.forEach(item -> {
String key = String.join(Constants.SystemParam.SEPARATOR_UNDER_LINE, item.getCrossId(), String.valueOf(item.getInDir()), String.valueOf(item.getTurnType()));
Double passTime = item.getPassTime();
phaseMap.entrySet().forEach(entry -> {
String crossIdDirTurn = entry.getKey();
CrossPhaseDTO crossPhaseDTO = entry.getValue();
String phaseNo = crossPhaseDTO.getPhaseNo();
if (StringUtils.equals(key, crossIdDirTurn)) {
Integer realOptGreenTime = getRealOptGreenTime(passTime, crossPhaseDTO);
Integer greenTimeOffset = realOptGreenTime - crossPhaseDTO.getGreenTime() - crossPhaseDTO.getGreenFlashTime();
Integer realGreenTimeOffset = 0;
if (!timeOffsetPhaseMap.isEmpty() && timeOffsetPhaseMap.get(phaseNo) != null) {
realGreenTimeOffset = timeOffsetPhaseMap.get(phaseNo);
timeOffsetPhaseMap.put(phaseNo, greenTimeOffset);
if (greenTimeOffset < 0 && realGreenTimeOffset > greenTimeOffset) {
timeOffsetPhaseMap.put(phaseNo, realGreenTimeOffset);
}
if (greenTimeOffset >= 0 && realGreenTimeOffset < greenTimeOffset) {
timeOffsetPhaseMap.put(phaseNo, realGreenTimeOffset);
}
} else {
timeOffsetPhaseMap.put(phaseNo, greenTimeOffset);
}
}
});
});
return timeOffsetPhaseMap;
}
private Integer getRealOptGreenTime(Double passTime, CrossPhaseDTO crossPhaseDTO) {
Integer passTimeInt = passTime == null ? 0 : passTime.intValue();
if (passTimeInt <= crossPhaseDTO.getMinGreenTime()) {
passTimeInt = crossPhaseDTO.getMinGreenTime();
}
if (passTimeInt >= crossPhaseDTO.getMaxGreenTime()) {
passTimeInt = crossPhaseDTO.getMaxGreenTime();
}
return passTimeInt;
}
private boolean isOffLineOrSpecialControlMode(String crossId) throws Exception {
JsonViewObject jsonViewObject = utcFeignClients.runningStatusAlarm();
if (Objects.isNull(jsonViewObject) || jsonViewObject.getCode() != 200) {
log.error("路口优化获取当前路口控制模式异常!");
throw new OptServiceException("路口优化获取当前路口控制模式异常!");
}
List<Map<String, Object>> source = (List<Map<String, Object>>) jsonViewObject.getContent();
List<SignalStatusVO> signalStatusVOS = BeanMapUtils.mapsToObjects(source, SignalStatusVO.class);
List<SignalStatusVO> resultList = signalStatusVOS.stream().filter(signalStatusVO -> Objects.equals(crossId, signalStatusVO.getCrossId())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(resultList)) {
SignalStatusVO signalStatusVO = resultList.get(0);
if (0 == signalStatusVO.getStatus() || 1 != signalStatusVO.getControlType()) {
return true;
}
}
return false;
}
/**
* 获取所有信控路口转向实时数据
* key 路口编号
* value 转向实时数据
*
* @return
*/
// public Map<String, List<CrossTurnDataRealtimeDTO>> listTurnDataRealtime(List<CrossDataRealtimePO> abnormalCrossList) {
// Map<String, List<CrossTurnDataRealtimeDTO>> turnDataRealtimeDTOList = new HashMap<>();
//
// abnormalCrossList.forEach(entry -> {
// List<CrossTurnDataRealtimeDTO> crossTurnDataRealtimeDTOS = new ArrayList<>();
// String crossId = entry.getCrossId();
// List<CrossTurnInfoDTO> turnList = entry.getTurnList();
// turnList.forEach(crossTurnInfoDTO -> {
// CrossTurnDataRealtimeDTO crossTurnDataRealtimeDTO = new CrossTurnDataRealtimeDTO();
// BeanUtils.copyProperties(entry, crossTurnDataRealtimeDTO);
// crossTurnDataRealtimeDTO.setTurnType(crossTurnInfoDTO.getTurnType());
// crossTurnDataRealtimeDTO.setInDir(crossTurnInfoDTO.getInDir());
// crossTurnDataRealtimeDTO.setOutDir(crossTurnInfoDTO.getOutDir());
// crossTurnDataRealtimeDTOS.add(crossTurnDataRealtimeDTO);
// });
// turnDataRealtimeDTOList.put(crossId, crossTurnDataRealtimeDTOS);
// });
//
// return turnDataRealtimeDTOList;
// }
/**
* 计算路口各转向所需的通行时长(秒)
* 相位的通行时长需大于等于最小绿灯时长,并且小于等于最大绿灯时长
* 车头间距(米):车间据如果不在20和7之间取9(默认9)
* 车头时距(秒):车时距如果不在2和5之间取2.8(默认2.8)
* 排队车辆 = 排队长度 / 车头间距
* 通行时长 = 排队车辆 * 车头时距
*/
public Double calPassTime(CrossTurnDataRealtimeDTO entity) {
// todo 优化参数,策略场景优化需要配置参数选择优化方法,读取不同配置优化信息
Double currentVehheadDist = entity.getVehheadDist();
if (Objects.isNull(currentVehheadDist) || currentVehheadDist > maxVehheadDist || currentVehheadDist < minVehheadDist) {
currentVehheadDist = defaultVehheadDist;
}
Double currentVehheadTime = entity.getVehheadTime();
if (Objects.isNull(currentVehheadTime) || currentVehheadTime > maxVehheadTime || currentVehheadTime < minVehheadTime) {
currentVehheadTime = defaultVehheadTime;
}
// 排队车辆
Double queuedVehicles = null;
if (Objects.nonNull(entity.getQueueLength())) {
queuedVehicles = entity.getQueueLength() / currentVehheadDist;
}
// 通行时长
Double calPassTime = queuedVehicles * currentVehheadTime;
return calPassTime;
}
}
package net.wanji.opt.service.impl;//package net.wanji.opt.service.impl;
//package net.wanji.opt.service.impl;
//
//import net.wanji.databus.dao.entity.CrossPhaseLightsPO;
//import net.wanji.databus.dao.entity.CrossPhasePO;
......
package net.wanji.opt.service.impl;//package net.wanji.opt.service.impl;
//package net.wanji.opt.service.impl;
//
//import lombok.extern.slf4j.Slf4j;
//import net.wanji.common.utils.tool.BeanListUtils;
......
package net.wanji.opt.service.impl;//package net.wanji.opt.service.impl;
//package net.wanji.opt.service.impl;
//
//import lombok.extern.slf4j.Slf4j;
//import net.wanji.common.utils.tool.BeanListUtils;
......
package net.wanji.opt.service.impl;//package net.wanji.opt.service.impl;
//package net.wanji.opt.service.impl;
//
//import lombok.extern.slf4j.Slf4j;
//import net.wanji.common.utils.tool.BeanListUtils;
......
package net.wanji.opt.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.LightsAddressEnum;
import net.wanji.common.framework.rest.JsonViewObject;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.common.utils.tool.JacksonUtils;
import net.wanji.databus.bo.CrossIdAndSchemeIdBO;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.dao.entity.*;
import net.wanji.databus.dao.mapper.*;
import net.wanji.databus.dto.CrossSchemeRingsDTO;
import net.wanji.databus.dto.QueryByCrossIdAndTimeDTO;
import net.wanji.databus.po.*;
import net.wanji.databus.vo.SchemeOptSendVO;
import net.wanji.databus.vo.SchemeSendVO;
import net.wanji.feign.service.UtcFeignClients;
import net.wanji.opt.dao.mapper.CrossSchemeOptLogMapper;
import net.wanji.opt.dao.mapper.strategy.SceneMapper;
import net.wanji.opt.dto.*;
import net.wanji.opt.dto.strategy.AddOrUpdateSceneDTO;
import net.wanji.opt.dto.strategy.QuerySceneDTO;
import net.wanji.opt.po.base.CrossSchemeOptLogPO;
import net.wanji.opt.po.strategy.ScenePO;
import net.wanji.opt.service.DiagnoService;
import net.wanji.opt.service.signalcontrol.FeignProxyService;
import net.wanji.opt.service.strategy.SceneService;
import net.wanji.opt.vo.CrossIdAndLocationVO;
import net.wanji.opt.vo.OptEffectVO;
import net.wanji.opt.vo.SchemeOptVO;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Kent HAN
* @date 2023/3/2 10:09
*/
@Service
@Slf4j
public class DiagnoServiceImpl implements DiagnoService {
private final BaseCrossInfoMapper baseCrossInfoMapper;
private final CrossDataRealtimeMapper crossDataRealtimeMapper;
private final SceneService sceneService;
private final SceneMapper sceneMapper;
private final BaseCrossDirInfoMapper baseCrossDirInfoMapper;
private final RidInfoMapper ridInfoMapper;
private final CrossSchemeOptLogMapper crossSchemeOptLogMapper;
private final BaseCrossSchemeMapper baseCrossSchemeMapper;
private final BaseCrossPhaseMapper baseCrossPhaseMapper;
private final FeignProxyService feignProxyService;
private final CrossDataHistMapper crossDataHistMapper;
private final CrossDirDataHistMapper crossDirDataHistMapper;
private final LaneInfoMapper laneInfoMapper;
private final CrossDirDataRealtimeMapper crossDirDataRealtimeMapper;
private final BaseCrossLaneLightsMapper baseCrossLaneLightsMapper;
private final BaseCrossLightsMapper baseCrossLightsMapper;
@Resource
private UtcFeignClients utcFeignClients;
private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
// 机动车灯数据库类型与前端类型对应关系
private static final Map<Integer, Integer> MOTOR_VEH_MAP = new HashMap<>(5);
static {
MOTOR_VEH_MAP.put(1, 1);
MOTOR_VEH_MAP.put(2, 3);
MOTOR_VEH_MAP.put(3, 4);
MOTOR_VEH_MAP.put(4, 5);
MOTOR_VEH_MAP.put(5, 6);
}
// 非机动车灯数据库类型与前端类型对应关系
private static final Map<Integer, Integer> NON_MOTOR_VEH_MAP = new HashMap<>(5);
static {
MOTOR_VEH_MAP.put(10, 2);
MOTOR_VEH_MAP.put(11, 3);
MOTOR_VEH_MAP.put(12, 4);
MOTOR_VEH_MAP.put(13, 5);
MOTOR_VEH_MAP.put(14, 6);
}
public DiagnoServiceImpl(BaseCrossInfoMapper baseCrossInfoMapper, CrossDataRealtimeMapper crossDataRealtimeMapper,
SceneService sceneService, SceneMapper sceneMapper, BaseCrossDirInfoMapper baseCrossDirInfoMapper,
RidInfoMapper ridInfoMapper, CrossSchemeOptLogMapper crossSchemeOptLogMapper,
BaseCrossSchemeMapper baseCrossSchemeMapper, BaseCrossPhaseMapper baseCrossPhaseMapper,
FeignProxyService feignProxyService, CrossDataHistMapper crossDataHistMapper,
CrossDirDataHistMapper crossDirDataHistMapper, LaneInfoMapper laneInfoMapper,
CrossDirDataRealtimeMapper crossDirDataRealtimeMapper,
BaseCrossLaneLightsMapper baseCrossLaneLightsMapper, BaseCrossLightsMapper baseCrossLightsMapper) {
this.baseCrossInfoMapper = baseCrossInfoMapper;
this.crossDataRealtimeMapper = crossDataRealtimeMapper;
this.sceneService = sceneService;
this.sceneMapper = sceneMapper;
this.baseCrossDirInfoMapper = baseCrossDirInfoMapper;
this.ridInfoMapper = ridInfoMapper;
this.crossSchemeOptLogMapper = crossSchemeOptLogMapper;
this.baseCrossSchemeMapper = baseCrossSchemeMapper;
this.baseCrossPhaseMapper = baseCrossPhaseMapper;
this.feignProxyService = feignProxyService;
this.crossDataHistMapper = crossDataHistMapper;
this.crossDirDataHistMapper = crossDirDataHistMapper;
this.laneInfoMapper = laneInfoMapper;
this.crossDirDataRealtimeMapper = crossDirDataRealtimeMapper;
this.baseCrossLaneLightsMapper = baseCrossLaneLightsMapper;
this.baseCrossLightsMapper = baseCrossLightsMapper;
}
@Override
public AddOrUpdateSceneDTO queryCrossScene(CrossIdBO crossIdBO) {
// 查询路口场景代码
String crossId = crossIdBO.getCrossId();
CrossDataRealtimePO crossDataRealtimePO = crossDataRealtimeMapper.selectByCrossId(crossId);
Integer status = crossDataRealtimePO.getStatus();
// 获取场景名称
ScenePO scenePO = sceneMapper.selectBySceneNum(status);
String sceneName = scenePO.getSceneName();
// 构造请求体
QuerySceneDTO querySceneDTO = new QuerySceneDTO();
querySceneDTO.setSceneName(sceneName);
querySceneDTO.setSceneTarget(1);
querySceneDTO.setPageNum(1);
querySceneDTO.setPageSize(999);
PageInfo<AddOrUpdateSceneDTO> pageInfo = sceneService.queryScene(querySceneDTO);
List<AddOrUpdateSceneDTO> list = pageInfo.getList();
return list.get(0);
}
@Override
public List<CrossIdAndLocationVO> queryNeighborCross(CrossIdBO crossIdBO) {
List<CrossIdAndLocationVO> crossIdAndLocationVOList = new ArrayList<>();
String crossId = crossIdBO.getCrossId();
List<Integer> inDirs = baseCrossDirInfoMapper.selectInDirsByCrossId(crossId);
for (Integer inDir : inDirs) {
RidInfoEntity ridInfo = ridInfoMapper.selectByEndInDir(crossId, inDir);
if (ridInfo != null) {
CrossIdAndLocationVO crossIdAndLocationVO = new CrossIdAndLocationVO();
// 关联路口坐标
String startCrossId = ridInfo.getStartCrossId();
crossIdAndLocationVO.setId(startCrossId);
TBaseCrossInfo crossInfoPO = baseCrossInfoMapper.selectByPrimaryKey(startCrossId);
if (crossInfoPO != null) {
crossIdAndLocationVO.setName(crossInfoPO.getName());
String startLocationStr = crossInfoPO.getLocation();
double[] startLonLat = CrossUtil.getLonLat(startLocationStr);
List<Double> startLocation = new ArrayList<>();
startLocation.add(startLonLat[0]);
startLocation.add(startLonLat[1]);
crossIdAndLocationVO.setLocation(startLocation);
}
// 关联路口wkt
String wkt = ridInfo.getWkt();
crossIdAndLocationVO.setWkt(wkt);
CrossDataRealtimePO crossDataRealtimePO = crossDataRealtimeMapper.selectByCrossId(startCrossId);
if (crossDataRealtimePO == null) {
throw new RuntimeException("没有该路口实时数据");
}
crossIdAndLocationVO.setRealtimeStatus(crossDataRealtimePO.getStatus());
crossIdAndLocationVOList.add(crossIdAndLocationVO);
}
}
return crossIdAndLocationVOList;
}
@Override
public SchemeOptVO querySchemeOpt(CrossIdAndSchemeIdBO bo) {
String crossId = bo.getCrossId();
Integer schemeId = bo.getSchemeId();
SchemeOptVO schemeOptVO = new SchemeOptVO();
schemeOptVO.setCrossId(crossId);
schemeOptVO.setSchemeId(schemeId);
// 选择数据批次时间最大的记录
List<CrossSchemeOptLogPO> maxList = crossSchemeOptLogMapper.selectMaxByCrossIdAndSchemeId(crossId, schemeId);
if (!CollectionUtils.isEmpty(maxList)) {
// 根据相位去重
TreeSet<CrossSchemeOptLogPO> collect = maxList.stream()
.collect(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(CrossSchemeOptLogPO::getPhaseNo))));
CrossSchemeOptLogPO crossSchemeOptLogPO = maxList.get(0);
String optType = crossSchemeOptLogPO.getOptType();
schemeOptVO.setOptType(Integer.parseInt(optType));
BaseCrossSchemePO baseCrossSchemePO = baseCrossSchemeMapper.selectByCrossIdAndSchemeId(crossId, schemeId);
if (baseCrossSchemePO != null) {
schemeOptVO.setCycle(baseCrossSchemePO.getCycle());
schemeOptVO.setOffset(crossSchemeOptLogPO.getOffset());
}
// 构造调整时间列表
List<SchemeOptVO.PhaseOptTime> phaseOptTimeList = buildPhaseOptTimeList(collect, schemeId, crossId);
schemeOptVO.setPhaseOptTimeList(phaseOptTimeList);
} else {
List<SchemeOptVO.PhaseOptTime> phaseOptTimeList = new ArrayList<>();
initPhaseOptTimeList(schemeId, phaseOptTimeList, crossId);
schemeOptVO.setPhaseOptTimeList(phaseOptTimeList);
}
return schemeOptVO;
}
@Override
public List<SchemeOptVO.PhaseOptTime> queryOptTime(CrossIdAndSchemeIdDTO crossIdAndSchemeIdDTO) {
String crossId = crossIdAndSchemeIdDTO.getCrossId();
Integer schemeId = crossIdAndSchemeIdDTO.getSchemeId();
List<SchemeOptVO.PhaseOptTime> phaseOptTimeList = new ArrayList<>();
// 选择数据批次时间最大的记录
List<CrossSchemeOptLogPO> maxList = crossSchemeOptLogMapper.selectMaxByCrossId(crossId);
for (CrossSchemeOptLogPO crossSchemeOptLogPO : maxList) {
SchemeOptVO.PhaseOptTime phaseOptTime = new SchemeOptVO.PhaseOptTime();
String phaseNo = crossSchemeOptLogPO.getPhaseNo();
phaseOptTime.setPhaseNo(phaseNo);
Integer oriGreenTime = crossSchemeOptLogPO.getOriGreenTime();
phaseOptTime.setOriGreenTime(oriGreenTime);
Integer optGreenTime = getNewGreenTime(crossId, schemeId, phaseNo);
phaseOptTime.setOptGreenTime(optGreenTime);
phaseOptTime.setOptTime(optGreenTime - oriGreenTime);
phaseOptTimeList.add(phaseOptTime);
}
return phaseOptTimeList;
}
@Override
public List<SchemeOptVO.PhaseOptTime> schemeComparison(CrossIdAndSchemeIdDTO crossIdAndSchemeIdDTO) {
String crossId = crossIdAndSchemeIdDTO.getCrossId();
List<SchemeOptVO.PhaseOptTime> phaseOptTimeList = new ArrayList<>();
QueryByCrossIdAndTimeDTO queryByCrossIdAndTimeDTO = new QueryByCrossIdAndTimeDTO();
queryByCrossIdAndTimeDTO.setCrossId(crossId);
queryByCrossIdAndTimeDTO.setDatetime(new Date());
//查询路口当前方案
JsonViewObject jsonViewObjectScheme = utcFeignClients.selectSchemeByParams(queryByCrossIdAndTimeDTO);
Integer jsonViewObjectSchemeCode = jsonViewObjectScheme.getCode();
if (jsonViewObjectSchemeCode != 200){
log.info("未查询到当前路口号,crossId:{}",crossId);
return phaseOptTimeList;
}
ObjectMapper mapper1 = JacksonUtils.getInstance();
BaseCrossSchemePO baseCrossSchemePO = mapper1.convertValue(jsonViewObjectScheme.getContent(), new TypeReference<BaseCrossSchemePO>() {
});
if (ObjectUtils.isEmpty(baseCrossSchemePO)){
return phaseOptTimeList;
}
Integer schemeNo = Integer.valueOf(baseCrossSchemePO.getSchemeNo());
if (ObjectUtil.isEmpty(schemeNo) || schemeNo == 85){
log.info("当前路口为黃闪,crossId:{}",crossId);
return phaseOptTimeList;
}
List<CrossPhasePO> phasePOList = baseCrossPhaseMapper.selectByCrossIdAndSchemeNo(crossId, schemeNo);
if (ObjectUtils.isEmpty(phasePOList) || ObjectUtils.isEmpty(schemeNo)) {
return phaseOptTimeList;
}
CrossSchemeRingsDTO crossSchemeRingsDTO = new CrossSchemeRingsDTO();
crossSchemeRingsDTO.setCrossId(crossId);
crossSchemeRingsDTO.setPattern(String.valueOf(schemeNo));
JsonViewObject jsonViewObject = utcFeignClients.schemeOptLog(crossSchemeRingsDTO);
Integer code = jsonViewObject.getCode();
ObjectMapper mapper = JacksonUtils.getInstance();
List<CrossSchemeStageOptLogPO> crossSchedulesPOList = mapper.convertValue(jsonViewObject.getContent(), new TypeReference<List<CrossSchemeStageOptLogPO>>() {
});
//
if (code != 200 || ObjectUtils.isEmpty(crossSchedulesPOList)) {
log.info("该路口方案暂未优化,{}", JSONObject.toJSONString(crossIdAndSchemeIdDTO));
//将优化后的方案都设置为0
for (CrossPhasePO crossPhasePO : phasePOList) {
SchemeOptVO.PhaseOptTime phaseOptTime = new SchemeOptVO.PhaseOptTime();
phaseOptTime.setPhaseNo(crossPhasePO.getPhaseNo());
phaseOptTime.setOriGreenTime(crossPhasePO.getPhaseTime());
phaseOptTime.setOptGreenTime(0);
phaseOptTime.setOptTime(0);
phaseOptTimeList.add(phaseOptTime);
}
} else {
for (CrossPhasePO crossPhasePO : phasePOList) {
SchemeOptVO.PhaseOptTime phaseOptTime = new SchemeOptVO.PhaseOptTime();
phaseOptTime.setPhaseNo(String.valueOf(crossPhasePO.getSort()));
Integer oriPhaseTime = crossPhasePO.getPhaseTime();
phaseOptTime.setOriGreenTime(oriPhaseTime);
List<CrossSchemeStageOptLogPO> list = crossSchedulesPOList.stream().filter(x -> x.getPhaseNo().equals(String.valueOf(crossPhasePO.getSort()))).collect(Collectors.toList());
if (ObjectUtils.isEmpty(list)) {
phaseOptTime.setOptGreenTime(0);
phaseOptTime.setOptTime(0-oriPhaseTime);
} else {
CrossSchemeStageOptLogPO optLogPO = list.get(0);
Integer optPhaseTime = optLogPO.getPhaseTime();
phaseOptTime.setOptGreenTime(optPhaseTime);
int optTime = optPhaseTime - oriPhaseTime;
phaseOptTime.setOptTime(optTime);
}
phaseOptTimeList.add(phaseOptTime);
}
}
return phaseOptTimeList;
}
@Override
public void sendManual(SendManualDTO sendManualDTO) throws Exception {
// 构造场景、策略、方法
String optDataExtend = buildOptDataExtend(sendManualDTO);
SchemeOptSendVO schemeOptSendVO = new SchemeOptSendVO();
schemeOptSendVO.setDataExtend(optDataExtend);
Integer optTypeInt = sendManualDTO.getOptType();
String optTypeStr = String.valueOf(optTypeInt);
schemeOptSendVO.setOptType(optTypeStr);
Integer crossStatus = sendManualDTO.getCrossStatus();
String crossStatusStr = String.valueOf(crossStatus);
schemeOptSendVO.setOptReason(crossStatusStr);
String currentCrossId = sendManualDTO.getCurrentCrossId();
String sendCrossId = sendManualDTO.getSendCrossId();
if (!Objects.equals(currentCrossId, sendCrossId)) {
schemeOptSendVO.setRelationFlag(String.valueOf(0)); // 是否被关联调整 1否 0是
schemeOptSendVO.setRelationCrossId(currentCrossId);
} else {
schemeOptSendVO.setRelationFlag(String.valueOf(1));
}
Map<String, Integer> phaseOffsetTimeMap = new HashMap<>();
List<SchemeOptVO.PhaseOptTime> phaseOptTimeList = sendManualDTO.getPhaseOptTimeList();
for (SchemeOptVO.PhaseOptTime phaseOptTime : phaseOptTimeList) {
phaseOffsetTimeMap.put(phaseOptTime.getPhaseNo(), phaseOptTime.getOptTime());
}
schemeOptSendVO.setPhaseOffsetTimeMap(phaseOffsetTimeMap);
schemeOptSendVO.setCrossCode(sendCrossId);
Integer schemeId = sendManualDTO.getSchemeId();
List<SchemeSendVO.Pattern> patternList = buildPatternList(sendCrossId, schemeId, phaseOffsetTimeMap);
schemeOptSendVO.setPatternList(patternList);
feignProxyService.schemeOptSend(schemeOptSendVO);
}
private String buildOptDataExtend(SendManualDTO sendManualDTO) {
String crossId = sendManualDTO.getSendCrossId();
// 选择数据批次时间最大的记录
List<CrossSchemeOptLogPO> maxList = crossSchemeOptLogMapper.selectMaxByCrossId(crossId);
if (!CollectionUtils.isEmpty(maxList)) {
CrossSchemeOptLogPO crossSchemeOptLogPO = maxList.get(0);
String dataExtend = crossSchemeOptLogPO.getDataExtend();
OptDataExtend optDataExtendOld = gson.fromJson(dataExtend, OptDataExtend.class);
OptDataExtend optDataExtendNew = new OptDataExtend();
optDataExtendNew.setSceneName(optDataExtendOld.getSceneName());
optDataExtendNew.setStrategyName(optDataExtendOld.getStrategyName());
// todo 改为枚举值
optDataExtendNew.setIdeaName("手动干预");
return gson.toJson(optDataExtendNew);
}
return null;
}
private List<SchemeSendVO.Pattern> buildPatternList(String sendCrossId, Integer schemeId,
Map<String, Integer> phaseOffsetTimeMap) {
List<SchemeSendVO.Pattern> patternList = new ArrayList<>();
BaseCrossSchemePO baseCrossSchemePO = baseCrossSchemeMapper.selectById(schemeId);
SchemeSendVO.Pattern pattern = new SchemeSendVO.Pattern();
pattern.setPatternNo(baseCrossSchemePO.getSchemeNo());
pattern.setPatternName(baseCrossSchemePO.getName());
pattern.setCycle(baseCrossSchemePO.getCycle().toString());
pattern.setCoordPhase(baseCrossSchemePO.getCoordPhase().toString());
pattern.setOffset(baseCrossSchemePO.getOffset().toString());
// 构造环列表
List<SchemeSendVO.Pattern.Ring> rings = buildRings(sendCrossId, schemeId, phaseOffsetTimeMap);
pattern.setRings(rings);
patternList.add(pattern);
return patternList;
}
private List<SchemeSendVO.Pattern.Ring> buildRings(String sendCrossId, Integer schemeId,
Map<String, Integer> phaseOffsetTimeMap) {
List<SchemeSendVO.Pattern.Ring> rings = new ArrayList<>();
// 根据路口ID和方案ID查询相位集合,根据ringNo分组,特殊控制ringNo为0
CrossPhasePO crossPhasePO = new CrossPhasePO();
crossPhasePO.setCrossId(sendCrossId);
crossPhasePO.setPlanId(schemeId);
List<CrossPhasePO> crossPhasePOList = baseCrossPhaseMapper.listCrossPhasePO(crossPhasePO);
Map<Integer, List<CrossPhasePO>> collectMap = crossPhasePOList.stream()
.collect(Collectors.groupingBy(CrossPhasePO::getRingNo));
for (Map.Entry<Integer, List<CrossPhasePO>> entry : collectMap.entrySet()) {
SchemeSendVO.Pattern.Ring ring = new SchemeSendVO.Pattern.Ring();
ring.setRingNo(entry.getKey().toString());
// 构造相位列表
List<CrossPhasePO> phases = entry.getValue();
List<SchemeSendVO.Pattern.Ring.Phase> phaseList = buildPhaseList(phases, phaseOffsetTimeMap);
ring.setPhaseList(phaseList);
rings.add(ring);
}
return rings;
}
private List<SchemeSendVO.Pattern.Ring.Phase> buildPhaseList(List<CrossPhasePO> phases,
Map<String, Integer> phaseOffsetTimeMap) {
List<SchemeSendVO.Pattern.Ring.Phase> phaseList = new ArrayList<>();
for (CrossPhasePO phasePO : phases) {
SchemeSendVO.Pattern.Ring.Phase phase = new SchemeSendVO.Pattern.Ring.Phase();
String phaseNo = phasePO.getPhaseNo();
phase.setPhaseNo(phaseNo);
phase.setPhaseName(phasePO.getName());
phase.setSort(phasePO.getSort().toString());
phase.setControlMode(phasePO.getControlMode().toString());
phase.setMinGreenTime(phasePO.getMinGreenTime().toString());
phase.setMaxGreenTime(phasePO.getMaxGreenTime().toString());
phase.setPhaseTime(phasePO.getPhaseTime().toString());
Integer oldGreenTime = phasePO.getGreenTime();
Integer optTime = phaseOffsetTimeMap.get(phaseNo);
if (optTime != null) {
Integer newGreenTime = oldGreenTime + optTime;
phase.setGreenTime(newGreenTime.toString());
} else {
phase.setGreenTime(oldGreenTime.toString());
}
phase.setGreenFlashTime(phasePO.getGreenFlashTime().toString());
phase.setPedFlashTime(phasePO.getPedFlashTime().toString());
phase.setYellowTime(phasePO.getYellowTime().toString());
phase.setRedTime(phasePO.getRedTime().toString());
phaseList.add(phase);
}
return phaseList;
}
@Override
public void restoreSend(CrossIdBO crossIdBO) throws Exception {
String crossId = crossIdBO.getCrossId();
feignProxyService.schemeOptRestore(crossId);
}
@Override
public OptEffectVO optEffect(CrossIdAndDirDTO crossIdAndDirDTO) {
String crossId = crossIdAndDirDTO.getCrossId();
OptEffectVO optEffectVO = new OptEffectVO();
TBaseCrossInfo crossInfoPO = baseCrossInfoMapper.selectByPrimaryKey(crossId);
optEffectVO.setCrossName(crossInfoPO.getName());
List<CrossSchemeOptLogPO> maxList = crossSchemeOptLogMapper.selectMaxByCrossId(crossId);
String optReason = null;
if (!CollectionUtils.isEmpty(maxList)) {
CrossSchemeOptLogPO crossSchemeOptLogPO = maxList.get(0);
optReason = crossSchemeOptLogPO.getOptReason();
Date endTime = crossSchemeOptLogPO.getEndTime();
if (ObjectUtil.isEmpty(endTime)) {
optEffectVO.setStatus(2);
} else {
optEffectVO.setStatus(1);
}
}
Integer dir = crossIdAndDirDTO.getDir();
// 获取当前时间之前45分钟的10位时间戳
long currentSeconds = DateUtil.currentSeconds();
long optStartTime = currentSeconds - 2 * 60 * 60;
//long optStartTime = 1689525900l;
// 优化开始时间,两个小时内最早时间
CrossSchemeOptLogPO optStartEntity = crossSchemeOptLogMapper.selectOptStartEntity(crossId, optReason, optStartTime);
if (Objects.nonNull(optStartEntity)) {
optEffectVO.setOptStartTime(optStartEntity.getStartTime());
}
long preSeconds = currentSeconds - 45 * 60;
if (ObjectUtil.isEmpty(dir) || dir == 0) {
// 获取路口历史数据
List<CrossDataHistPO> crossDataHistPOList =
crossDataHistMapper.selectByCrossIdAndTimestamp(crossId, preSeconds);
if (!CollectionUtils.isEmpty(crossDataHistPOList)) {
List<OptEffectVO.IndexDelay> indexDelayList = buildIndexDelayList(crossDataHistPOList);
optEffectVO.setIndexDelayList(indexDelayList);
List<OptEffectVO.QueueStop> queueStopList = buildQueueStopList(crossDataHistPOList);
optEffectVO.setQueueStopList(queueStopList);
}
} else {
// 获取路口方向历史数据
List<CrossDirDataHistPO> crossDirDataHistPOList =
crossDirDataHistMapper.selectByCrossIdDirAndTimestamp(crossId, dir, preSeconds);
if (!CollectionUtils.isEmpty(crossDirDataHistPOList)) {
List<OptEffectVO.IndexDelay> indexDelayList = buildIndexDelayListDir(crossDirDataHistPOList);
optEffectVO.setIndexDelayList(indexDelayList);
List<OptEffectVO.QueueStop> queueStopList = buildQueueStopListDir(crossDirDataHistPOList);
optEffectVO.setQueueStopList(queueStopList);
}
}
return optEffectVO;
}
@Override
public SaveLaneInfoDTO listLaneInfo(CrossIdBO crossIdBO) {
String crossId = crossIdBO.getCrossId();
SaveLaneInfoDTO saveLaneInfoDTO = new SaveLaneInfoDTO();
saveLaneInfoDTO.setCrossId(crossId);
// 路口拥堵指数
CrossDataRealtimePO crossDataRealtimePO = crossDataRealtimeMapper.selectByCrossId(crossId);
Double trafficIndex = crossDataRealtimePO.getTrafficIndex();
saveLaneInfoDTO.setCrossIndex(Double.valueOf(String.format("%.2f", trafficIndex)));
// 构造dirList
buildDirList(crossId, saveLaneInfoDTO);
// 构造ledConfigList
buildLedConfigList(crossId, saveLaneInfoDTO);
return saveLaneInfoDTO;
}
private void buildLedConfigList(String crossId, SaveLaneInfoDTO saveLaneInfoDTO) {
saveLaneInfoDTO.setLedConfigList(new ArrayList<>());
List<LedConfigListElement> ledConfigList = saveLaneInfoDTO.getLedConfigList();
// 获取灯组数据
List<BaseCrossLightsPO> crossLightsPOList = baseCrossLightsMapper.selectByCrossId(crossId);
// 赋值给ledConfigList
for (BaseCrossLightsPO crossLightsPO : crossLightsPOList) {
LedConfigListElement ledConfigListElement = new LedConfigListElement();
ledConfigListElement.setId(crossLightsPO.getId());
ledConfigListElement.setOrder(crossLightsPO.getSort());
ledConfigListElement.setCode(crossLightsPO.getLightsNo());
// 处理type
Integer type = crossLightsPO.getType();
if (type > 0 && type < 10) { // 机动车灯
ledConfigListElement.setType(1);
Integer signalType = MOTOR_VEH_MAP.get(type);
ledConfigListElement.setSignalType(signalType);
} else if (type >= 10 && type < 20) { // 非机动车灯
ledConfigListElement.setType(2);
Integer signalType = NON_MOTOR_VEH_MAP.get(type);
ledConfigListElement.setSignalType(signalType);
} else if (type >= 20 && type < 30) { // 行人灯
ledConfigListElement.setType(4);
ledConfigListElement.setSignalType(8);
} else if (type == 30) { // 公交专用灯
ledConfigListElement.setType(3);
ledConfigListElement.setSignalType(7);
}
// 灯组放行方向
Integer dir = crossLightsPO.getDir();
if (type < 20 || type >= 30) { // 非行人灯
String address = LightsAddressEnum.getMsgByCode(dir);
ledConfigListElement.setAddress(address);
} else if (type == 20) { // 一次过街
String s = "" + dir + 1;
setLightAddress(ledConfigListElement, s);
} else if (type == 22) { // 二次过街-出口
String s = "" + dir + 21;
setLightAddress(ledConfigListElement, s);
} else if (type == 21) { // 二次过街-进口
String s = "" + dir + 22;
setLightAddress(ledConfigListElement, s);
}
ledConfigList.add(ledConfigListElement);
}
Collections.sort(ledConfigList, Comparator.comparingInt(led -> Integer.valueOf(led.getCode())));
}
private void setLightAddress(LedConfigListElement ledConfigListElement, String s) {
int i = Integer.parseInt(s);
String address = LightsAddressEnum.getMsgByCode(i);
ledConfigListElement.setAddress(address);
}
private void buildDirList(String crossId, SaveLaneInfoDTO saveLaneInfoDTO) {
saveLaneInfoDTO.setDirList(new ArrayList<>());
List<LaneInfoPO> laneInfoPOList = laneInfoMapper.selectBycrossId(crossId);
Map<Integer, List<LaneInfoPO>> collect = laneInfoPOList.stream()
.collect(Collectors.groupingBy(LaneInfoPO::getDir));
for (Map.Entry<Integer, List<LaneInfoPO>> entry : collect.entrySet()) {
Integer key = entry.getKey();
DirListElement dirListElement = new DirListElement();
dirListElement.setDir(key);
// 查询拥堵状态、排队长度和指数
CrossDirDataRealtimePO crossDirDataRealtimePO =
crossDirDataRealtimeMapper.selectByCrossIdAndDirType(crossId, key);
if (crossDirDataRealtimePO != null) {
dirListElement.setStatus(crossDirDataRealtimePO.getStatus());
dirListElement.setTraffic_index(crossDirDataRealtimePO.getTrafficIndex());
dirListElement.setLength(crossDirDataRealtimePO.getLength());
dirListElement.setDuration(crossDirDataRealtimePO.getDuration());
}
// 获取是否有行人道
BaseCrossDirInfoPO baseCrossDirInfoPO = baseCrossDirInfoMapper.selectByCrossIdAndDirType(crossId, key);
Integer isPedestrian = baseCrossDirInfoPO.getIsPedestrian();
dirListElement.setIsPersonCross(isPedestrian);
// 构造laneList
List<LaneInfoPO> value = entry.getValue();
List<LaneInfoPO> sortedValue = value.stream().
sorted(Comparator.comparing(LaneInfoPO::getSort)).
collect(Collectors.toList());
List<LaneListElement> laneListElementList = new ArrayList<>();
for (LaneInfoPO laneInfoPO : sortedValue) {
LaneListElement laneListElement = new LaneListElement();
String laneId = laneInfoPO.getId();
laneListElement.setId(laneId);
Integer turn = laneInfoPO.getTurn();
laneListElement.setDirection(turn);
laneListElement.setLaneType(laneInfoPO.getCategory());
laneListElement.setName(laneInfoPO.getCode());
// 根据laneId获取灯组代码
String lightsCode = baseCrossLaneLightsMapper.selectLightsCodeByLaneId(laneId);
if (lightsCode != null) {
laneListElement.setLedNum(lightsCode);
}
laneListElementList.add(laneListElement);
}
dirListElement.setLaneList(laneListElementList);
// 构造行人过街数据
List<BaseCrossLightsPO> crossLightsPOList = baseCrossLightsMapper.selectByCrossIdAndDir(crossId, key);
for (BaseCrossLightsPO crossLightsPO : crossLightsPOList) {
Integer type = crossLightsPO.getType();
String lightsNo = crossLightsPO.getLightsNo();
if (type == 20) { // 一次过街
dirListElement.setPersonCrossType("oneCross");
dirListElement.setOneCross(lightsNo);
} else if (type == 22) { // 二次过街出口灯
dirListElement.setPersonCrossType("twiceCross");
dirListElement.setTwiceCrossOut(lightsNo);
} else if (type == 21) { // 二次过街进口灯
dirListElement.setPersonCrossType("twiceCross");
dirListElement.setTwiceCrossIn(lightsNo);
}
}
List<DirListElement> dirList = saveLaneInfoDTO.getDirList();
dirList.add(dirListElement);
}
// 返回没有车道的方向
List<BaseCrossDirInfoPO> baseCrossDirInfoPOList = baseCrossDirInfoMapper.selectByCrossId(crossId);
for (BaseCrossDirInfoPO baseCrossDirInfoPO : baseCrossDirInfoPOList) {
List<DirListElement> dirList = saveLaneInfoDTO.getDirList();
Integer dirType = baseCrossDirInfoPO.getDirType();
List<LaneInfoPO> laneInfoPOList1 = laneInfoMapper.selectInDirByCrossIdAndDir(crossId, dirType);
if (CollectionUtils.isEmpty(laneInfoPOList1)) {
DirListElement dirListElement = new DirListElement();
dirListElement.setDir(baseCrossDirInfoPO.getDirType());
dirListElement.setIsPersonCross(baseCrossDirInfoPO.getIsPedestrian());
dirList.add(dirListElement);
}
}
}
private List<OptEffectVO.QueueStop> buildQueueStopListDir(List<CrossDirDataHistPO> crossDirDataHistPOList) {
List<OptEffectVO.QueueStop> queueStopList = new ArrayList<>();
for (CrossDirDataHistPO crossDirDataHistPO : crossDirDataHistPOList) {
OptEffectVO.QueueStop queueStop = new OptEffectVO.QueueStop();
// 获取采集时间
long batchTimeLong = crossDirDataHistPO.getBatchTime();
batchTimeLong *= 1000;
Date date = DateUtil.date(batchTimeLong);
queueStop.setTime(date);
queueStop.setQueue(crossDirDataHistPO.getQueueLength());
queueStop.setStop(crossDirDataHistPO.getStopTimes());
queueStopList.add(queueStop);
}
return queueStopList;
}
private List<OptEffectVO.IndexDelay> buildIndexDelayListDir(List<CrossDirDataHistPO> crossDirDataHistPOList) {
List<OptEffectVO.IndexDelay> indexDelayList = new ArrayList<>();
for (CrossDirDataHistPO crossDirDataHistPO : crossDirDataHistPOList) {
OptEffectVO.IndexDelay indexDelay = new OptEffectVO.IndexDelay();
// 获取采集时间
long batchTimeLong = crossDirDataHistPO.getBatchTime();
batchTimeLong *= 1000;
Date date = DateUtil.date(batchTimeLong);
indexDelay.setTime(date);
indexDelay.setIndex(crossDirDataHistPO.getTrafficIndex());
indexDelay.setDelay(crossDirDataHistPO.getDelayTime());
indexDelayList.add(indexDelay);
}
return indexDelayList;
}
private List<OptEffectVO.QueueStop> buildQueueStopList(List<CrossDataHistPO> crossDataHistPOList) {
List<OptEffectVO.QueueStop> queueStopList = new ArrayList<>();
for (CrossDataHistPO crossDataHistPO : crossDataHistPOList) {
OptEffectVO.QueueStop queueStop = new OptEffectVO.QueueStop();
// 获取采集时间
Integer batchTime = crossDataHistPO.getBatchTime();
Date date = DateUtil.date(batchTime * 1000);
queueStop.setTime(date);
queueStop.setQueue(crossDataHistPO.getQueueLength());
queueStop.setStop(crossDataHistPO.getStopTimes());
queueStopList.add(queueStop);
}
return queueStopList;
}
private List<OptEffectVO.IndexDelay> buildIndexDelayList(List<CrossDataHistPO> crossDataHistPOList) {
List<OptEffectVO.IndexDelay> indexDelayList = new ArrayList<>();
for (CrossDataHistPO crossDataHistPO : crossDataHistPOList) {
OptEffectVO.IndexDelay indexDelay = new OptEffectVO.IndexDelay();
// 获取采集时间
Integer batchTime = crossDataHistPO.getBatchTime();
Date date = DateUtil.date(batchTime * 1000);
indexDelay.setTime(date);
indexDelay.setIndex(crossDataHistPO.getTrafficIndex());
indexDelay.setDelay(crossDataHistPO.getDelayTime());
indexDelayList.add(indexDelay);
}
return indexDelayList;
}
private Integer getNewGreenTime(String crossId, Integer schemeId, String phaseNo) {
CrossPhasePO entity = new CrossPhasePO();
entity.setCrossId(crossId);
entity.setPlanId(schemeId);
List<CrossPhasePO> crossPhasePOList = baseCrossPhaseMapper.listCrossPhasePO(entity);
for (CrossPhasePO crossPhasePO : crossPhasePOList) {
String newPhaseNo = crossPhasePO.getPhaseNo();
if (Objects.equals(phaseNo, newPhaseNo)) {
return crossPhasePO.getGreenTime();
}
}
return 0;
}
private List<SchemeOptVO.PhaseOptTime> buildPhaseOptTimeList(
Collection<CrossSchemeOptLogPO> crossSchemeOptLogPOList, Integer schemeId, String crossId) {
// 初始化列表
List<SchemeOptVO.PhaseOptTime> phaseOptTimeList = new ArrayList<>();
initPhaseOptTimeList(schemeId, phaseOptTimeList, crossId);
for (CrossSchemeOptLogPO crossSchemeOptLogPO : crossSchemeOptLogPOList) {
for (SchemeOptVO.PhaseOptTime phaseOptTime : phaseOptTimeList) {
String phaseNo1 = crossSchemeOptLogPO.getPhaseNo();
String phaseNo2 = phaseOptTime.getPhaseNo();
if (Objects.equals(phaseNo1, phaseNo2)) {
int optTime = crossSchemeOptLogPO.getOptTime();
int oriGreenTime = crossSchemeOptLogPO.getOriGreenTime();
phaseOptTime.setOriGreenTime(oriGreenTime);
phaseOptTime.setOptGreenTime(oriGreenTime + optTime);
phaseOptTime.setOptTime(optTime);
}
}
}
return phaseOptTimeList;
}
private void initPhaseOptTimeList(Integer schemeId, List<SchemeOptVO.PhaseOptTime> phaseOptTimeList, String crossId) {
CrossPhasePO phasePO = new CrossPhasePO();
phasePO.setCrossId(crossId);
phasePO.setPlanId(schemeId);
List<CrossPhasePO> crossPhasePOList = baseCrossPhaseMapper.listCrossPhasePO(phasePO);
for (CrossPhasePO crossPhasePO : crossPhasePOList) {
SchemeOptVO.PhaseOptTime phaseOptTime = new SchemeOptVO.PhaseOptTime();
phaseOptTime.setPhaseNo(crossPhasePO.getPhaseNo());
phaseOptTime.setOriGreenTime(crossPhasePO.getGreenTime());
phaseOptTime.setOptGreenTime(crossPhasePO.getGreenTime());
phaseOptTime.setOptTime(0);
phaseOptTimeList.add(phaseOptTime);
}
}
}
package net.wanji.opt.service.impl;
import cn.hutool.core.date.DateUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.CrossInOutEnum;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.databus.bo.CrossDirDataHistAvgBO;
import net.wanji.databus.dao.mapper.*;
import net.wanji.databus.po.CrossDataHistPO;
import net.wanji.databus.po.CrossDataRealtimePO;
import net.wanji.databus.po.CrossDirDataRealtimePO;
import net.wanji.databus.po.TBaseCrossInfo;
import net.wanji.opt.dao.mapper.CrossSchemeOptLogMapper;
import net.wanji.opt.dto.CrossIdAndMinutesDTO;
import net.wanji.opt.service.EvaluateService;
import net.wanji.opt.vo.EvaluateCrossDetailVO;
import net.wanji.opt.vo.EvaluateMetricsVO;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
/**
* @author Kent HAN
* @date 2023/3/10 10:47
*/
@Service
@Slf4j
public class EvaluateServiceImpl implements EvaluateService {
private final BaseCrossInfoMapper baseCrossInfoMapper;
private final CrossSchemeOptLogMapper crossSchemeOptLogMapper;
private final CrossDataRealtimeMapper crossDataRealtimeMapper;
private final CrossDirDataRealtimeMapper crossDirDataRealtimeMapper;
private final CrossDirDataHistMapper crossDirDataHistMapper;
private final CrossDataHistMapper crossDataHistMapper;
private Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
public EvaluateServiceImpl(BaseCrossInfoMapper baseCrossInfoMapper, CrossSchemeOptLogMapper crossSchemeOptLogMapper,
CrossDataRealtimeMapper crossDataRealtimeMapper,
CrossDirDataRealtimeMapper crossDirDataRealtimeMapper,
CrossDirDataHistMapper crossDirDataHistMapper, CrossDataHistMapper crossDataHistMapper) {
this.baseCrossInfoMapper = baseCrossInfoMapper;
this.crossSchemeOptLogMapper = crossSchemeOptLogMapper;
this.crossDataRealtimeMapper = crossDataRealtimeMapper;
this.crossDirDataRealtimeMapper = crossDirDataRealtimeMapper;
this.crossDirDataHistMapper = crossDirDataHistMapper;
this.crossDataHistMapper = crossDataHistMapper;
}
@Override
public EvaluateCrossDetailVO evaluateCrossDetail(CrossIdAndMinutesDTO crossIdAndMinutesDTO) {
EvaluateCrossDetailVO evaluateCrossDetailVO = new EvaluateCrossDetailVO();
String crossId = crossIdAndMinutesDTO.getCrossId();
TBaseCrossInfo crossInfoPO = baseCrossInfoMapper.selectByPrimaryKey(crossId);
String crossName = crossInfoPO.getName();
evaluateCrossDetailVO.setCrossName(crossName);
Integer minutes = crossIdAndMinutesDTO.getMinutes();
fillRealtimeData(evaluateCrossDetailVO, crossId, minutes);
// 计算轨迹时间
fillWindowTime(evaluateCrossDetailVO, minutes);
return evaluateCrossDetailVO;
}
private void fillWindowTime(EvaluateCrossDetailVO evaluateCrossDetailVO, Integer minutes) {
// 获取当前时间的整分钟Date
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date nowDate = calendar.getTime();
// 当前时间之前的第一个整5分钟
int leftMinute = DateUtil.minute(nowDate) % 5;
Date windowEndTime = DateUtil.offsetMinute(nowDate, -leftMinute);
// 再向前推 时间间隔加5分钟 作为开始时间
Date windowStartTime = DateUtil.offsetMinute(windowEndTime, -minutes - 5);
evaluateCrossDetailVO.setWindowStartTime(windowStartTime);
evaluateCrossDetailVO.setWindowEndTime(windowEndTime);
}
@Override
public EvaluateMetricsVO evaluateMetrics(CrossIdAndMinutesDTO crossIdAndMinutesDTO) {
String crossId = crossIdAndMinutesDTO.getCrossId();
Integer minutes = crossIdAndMinutesDTO.getMinutes();
EvaluateMetricsVO evaluateMetricsVO = new EvaluateMetricsVO();
// 路口流量
List<EvaluateMetricsVO.CrossFlowElement> crossFlow = buildCrossFlow(crossId, minutes);
evaluateMetricsVO.setCrossFlow(crossFlow);
// 路口排队长度
List<EvaluateMetricsVO.QueueLengthElement> queueLength = buildQueueLength(crossId, minutes);
evaluateMetricsVO.setQueueLength(queueLength);
// 拥堵指数
List<EvaluateMetricsVO.TrafficIndexElement> trafficIndex = buildTrafficIndex(crossId, minutes);
evaluateMetricsVO.setTrafficIndex(trafficIndex);
// 溢流率
List<EvaluateMetricsVO.EffusionRateElement> effusionRate = buildEffusionRate(crossId, minutes);
evaluateMetricsVO.setEffusionRate(effusionRate);
return evaluateMetricsVO;
}
private List<EvaluateMetricsVO.EffusionRateElement> buildEffusionRate(String crossId, Integer minutes) {
List<EvaluateMetricsVO.EffusionRateElement> res = new ArrayList<>();
// 实时数据
Map<Integer, List<CrossDirDataRealtimePO>> dirObjMapRealtime = getRealTimeData(crossId);
// 历史数据
Map<Integer, List<CrossDirDataHistAvgBO>> dirObjMapHist = getHistData(crossId, minutes);
for (Integer dir : dirObjMapRealtime.keySet()) {
EvaluateMetricsVO.EffusionRateElement effusionRateElement = new EvaluateMetricsVO.EffusionRateElement();
effusionRateElement.setDir(dir);
List<CrossDirDataRealtimePO> realtimeObj = dirObjMapRealtime.get(dir);
if (isNotEmpty(realtimeObj)) {
CrossDirDataRealtimePO crossDirDataRealtimePO = realtimeObj.get(0);
Double effusionRate = crossDirDataRealtimePO.getEffusionRate();
effusionRateElement.setCurrentRate(effusionRate);
}
List<CrossDirDataHistAvgBO> histObj = dirObjMapHist.get(dir);
if (isNotEmpty(histObj)) {
CrossDirDataHistAvgBO crossDirDataHistAvgBO = histObj.get(0);
Double avgEffusionRate = crossDirDataHistAvgBO.getAvgEffusionRate();
effusionRateElement.setCompareRate(avgEffusionRate);
}
res.add(effusionRateElement);
}
return res;
}
private List<EvaluateMetricsVO.TrafficIndexElement> buildTrafficIndex(String crossId, Integer minutes) {
List<EvaluateMetricsVO.TrafficIndexElement> res = new ArrayList<>();
// 实时数据
Map<Integer, List<CrossDirDataRealtimePO>> dirObjMapRealtime = getRealTimeData(crossId);
// 历史数据
Map<Integer, List<CrossDirDataHistAvgBO>> dirObjMapHist = getHistData(crossId, minutes);
for (Integer dir : dirObjMapRealtime.keySet()) {
EvaluateMetricsVO.TrafficIndexElement trafficIndexElement = new EvaluateMetricsVO.TrafficIndexElement();
trafficIndexElement.setDir(dir);
List<CrossDirDataRealtimePO> realtimeObj = dirObjMapRealtime.get(dir);
if (isNotEmpty(realtimeObj)) {
CrossDirDataRealtimePO crossDirDataRealtimePO = realtimeObj.get(0);
trafficIndexElement.setCurrentIndex(crossDirDataRealtimePO.getTrafficIndex());
}
List<CrossDirDataHistAvgBO> histObj = dirObjMapHist.get(dir);
if (isNotEmpty(histObj)) {
CrossDirDataHistAvgBO crossDirDataHistAvgBO = histObj.get(0);
trafficIndexElement.setCompareIndex(crossDirDataHistAvgBO.getAvgIndex());
}
res.add(trafficIndexElement);
}
return res;
}
private List<EvaluateMetricsVO.QueueLengthElement> buildQueueLength(String crossId, Integer minutes) {
List<EvaluateMetricsVO.QueueLengthElement> res = new ArrayList<>();
// 实时数据
Map<Integer, List<CrossDirDataRealtimePO>> dirObjMapRealtime = getRealTimeData(crossId);
// 历史数据
Map<Integer, List<CrossDirDataHistAvgBO>> dirObjMapHist = getHistData(crossId, minutes);
for (Integer dir : dirObjMapRealtime.keySet()) {
EvaluateMetricsVO.QueueLengthElement queueLengthElement = new EvaluateMetricsVO.QueueLengthElement();
queueLengthElement.setDir(dir);
List<CrossDirDataRealtimePO> realtimeObj = dirObjMapRealtime.get(dir);
if (isNotEmpty(realtimeObj)) {
CrossDirDataRealtimePO crossDirDataRealtimePO = realtimeObj.get(0);
queueLengthElement.setCurrentLength(crossDirDataRealtimePO.getLength());
}
List<CrossDirDataHistAvgBO> histObj = dirObjMapHist.get(dir);
if (isNotEmpty(histObj)) {
CrossDirDataHistAvgBO crossDirDataHistAvgBO = histObj.get(0);
queueLengthElement.setCompareLength(crossDirDataHistAvgBO.getAvgQueueLength());
}
res.add(queueLengthElement);
}
return res;
}
private List<EvaluateMetricsVO.CrossFlowElement> buildCrossFlow(String crossId, Integer minutes) {
List<EvaluateMetricsVO.CrossFlowElement> res = new ArrayList<>();
// 实时数据
Map<Integer, List<CrossDirDataRealtimePO>> dirObjMapRealtime = getRealTimeData(crossId);
// 历史数据
Map<Integer, List<CrossDirDataHistAvgBO>> dirObjMapHist = getHistData(crossId, minutes);
for (Integer dir : dirObjMapRealtime.keySet()) {
EvaluateMetricsVO.CrossFlowElement crossFlowElement = new EvaluateMetricsVO.CrossFlowElement();
crossFlowElement.setDir(dir);
List<CrossDirDataRealtimePO> realtimeObj = dirObjMapRealtime.get(dir);
if (isNotEmpty(realtimeObj)) {
CrossDirDataRealtimePO crossDirDataRealtimePO = realtimeObj.get(0);
crossFlowElement.setCurrentCapacity(crossDirDataRealtimePO.getCapacity());
crossFlowElement.setCurrentFlow(crossDirDataRealtimePO.getFlow());
}
List<CrossDirDataHistAvgBO> histObj = dirObjMapHist.get(dir);
if (isNotEmpty(histObj)) {
CrossDirDataHistAvgBO crossDirDataHistAvgBO = histObj.get(0);
crossFlowElement.setCompareCapacity(crossDirDataHistAvgBO.getAvgCapacity());
crossFlowElement.setCompareFlow(crossDirDataHistAvgBO.getAvgFlow());
}
res.add(crossFlowElement);
}
return res;
}
@NotNull
private Map<Integer, List<CrossDirDataHistAvgBO>> getHistData(String crossId, Integer minutes) {
// 获取当前时间之前 minutes 分钟的10位时间戳
long currentSeconds = DateUtil.currentSeconds();
long preSeconds = currentSeconds - minutes * 60 - 10 * 60; // 再向前10分钟数据才能形成对比
long endSeconds = DateUtil.currentSeconds() - 10 * 60;
List<CrossDirDataHistAvgBO> crossDirDataHistAvgBOList = crossDirDataHistMapper.selectByCrossIdInOutTimestamp(
crossId, CrossInOutEnum.IN.getCode(), preSeconds, endSeconds);
Map<Integer, List<CrossDirDataHistAvgBO>> dirObjMapHist = crossDirDataHistAvgBOList.stream()
.collect(Collectors.groupingBy(CrossDirDataHistAvgBO::getDirType));
return dirObjMapHist;
}
@NotNull
private Map<Integer, List<CrossDirDataRealtimePO>> getRealTimeData(String crossId) {
List<CrossDirDataRealtimePO> crossDirDataRealtimePOList =
crossDirDataRealtimeMapper.selectByCrossIdAndInOutType(crossId, CrossInOutEnum.IN.getCode());
Map<Integer, List<CrossDirDataRealtimePO>> dirObjMapRealtime = crossDirDataRealtimePOList.stream()
.collect(Collectors.groupingBy(CrossDirDataRealtimePO::getDirType));
return dirObjMapRealtime;
}
private void fillRealtimeData(EvaluateCrossDetailVO evaluateCrossDetailVO, String crossId, Integer minutes) {
CrossDataRealtimePO crossDataRealtimePO = crossDataRealtimeMapper.selectByCrossId(crossId);
// 服务水平
Double sturation = crossDataRealtimePO.getSturation();
String serviceLevel = CrossUtil.getServiceLevel(sturation);
evaluateCrossDetailVO.setServiceLevel(serviceLevel);
// 路口流量
// 获取当前时间前 minutes 分钟的10位时间戳
long currentSeconds = DateUtil.currentSeconds();
long preSeconds = currentSeconds - (minutes + 5) * 60L;
List<CrossDataHistPO> crossDataHistPOS = crossDataHistMapper.selectByCrossIdAndTimestamp(crossId, preSeconds);
if (isNotEmpty(crossDataHistPOS)) {
// 路口流量
double avg = crossDataHistPOS.stream()
.mapToInt(CrossDataHistPO::getFlow)
.average().orElse(0.0);
evaluateCrossDetailVO.setFlow((int) Math.round(avg));
// 最大排队长度
double maxQueue = crossDataHistPOS.stream()
.mapToDouble(CrossDataHistPO::getQueueLength)
.max().orElse(0.0);
evaluateCrossDetailVO.setLength((int) Math.round(maxQueue));
// 路口平均延误
double avgDelay = crossDataHistPOS.stream()
.mapToInt(CrossDataHistPO::getDelayTime)
.average().orElse(0.0);
evaluateCrossDetailVO.setDelayTime((int) Math.round(avgDelay));
// 路口平均速度
double avgSpeed = crossDataHistPOS.stream()
.mapToDouble(CrossDataHistPO::getSpeed)
.average().orElse(0.0);
evaluateCrossDetailVO.setSpeed((int) Math.round(avgSpeed));
}
}
}
package net.wanji.opt.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.BaseEnum;
import net.wanji.common.framework.exception.DubboProviderException;
import net.wanji.common.utils.tool.DateUtil;
import net.wanji.common.utils.tool.LocalDateTimeUtil;
import net.wanji.databus.dao.entity.GreenwaveHistPO;
import net.wanji.databus.dao.mapper.BaseCrossInfoMapper;
import net.wanji.databus.dao.mapper.GreenwaveHistMapper;
import net.wanji.databus.dto.EventInfoTrafficStatusDTO;
import net.wanji.databus.po.EventInfoTrafficStatusPO;
import net.wanji.databus.po.TBaseCrossInfo;
import net.wanji.databus.vo.EventInfoTrafficStatusVO;
import net.wanji.opt.common.EsDateIndexUtil;
import net.wanji.opt.common.enums.EventInfoTypeEnum;
import net.wanji.opt.dao.mapper.HoloEventMapper;
import net.wanji.opt.dao.mapper.base.BaseRidInfoMapper;
import net.wanji.opt.entity.EventAlarmInfo;
import net.wanji.opt.po.base.BaseRidInfo;
import net.wanji.opt.po.base.EventStatisticPo;
import net.wanji.opt.po.trend.EventInfoSimplePo;
import net.wanji.opt.service.EventService;
import org.joda.time.DateTime;
import org.joda.time.Minutes;
import org.joda.time.Seconds;
import org.joda.time.format.DateTimeFormat;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
/**
*
*/
@Slf4j
@Service
public class EventServiceImpl implements EventService {
@Resource
HoloEventMapper holoEventMapper;
@Resource
BaseRidInfoMapper baseRidInfoMapper;
@Resource
BaseCrossInfoMapper baseCrossInfoMapper;
@Resource
GreenwaveHistMapper greenwaveHistMapper;
@Override
public EventStatisticPo findCrossEventCount(String crossId, String type, String startTime, String endTime) throws DubboProviderException {
Map<String, Object> params = new HashMap<>();
params.put("crossId", crossId);
params.put("startDate", startTime);
params.put("endDate", endTime);
params.put("eventType", type);
EventStatisticPo po = holoEventMapper.findCrossEventCount(params);
if (po != null) {
String dirs = po.getDirs();
Map<String, Long> countMap = null;
List<Map<String, Object>> list = new ArrayList<>();
if (Objects.nonNull(dirs)) {
String[] dirList = dirs.split("@");
List<String> allDirList = new ArrayList<>();
for (String dirArr : dirList) {
if (!dirArr.startsWith("[") || !dirArr.endsWith("]")){
//过滤不合规格式数据
continue;
}
List<String> jsonArray = JSONArray.parseArray(dirArr, String.class);
if (jsonArray.size()>0) {
allDirList.addAll(jsonArray.stream().map(o -> (Integer.valueOf(o).toString())).distinct().collect(Collectors.toList()));
}
}
//统计每个方向发生的次数
countMap = allDirList.stream().collect(Collectors.groupingBy(String::valueOf, Collectors.counting()));
countMap.entrySet().forEach(o -> {
Map<String, Object> map = new HashMap<>();
map.put("dir", o.getKey());
map.put("count", o.getValue());
list.add(map);
});
}
po.setDirEventCount(countMap);
po.setDirEventCountList(list);
QueryWrapper<BaseRidInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("end_cross_id", crossId);
List<BaseRidInfo> ridList = baseRidInfoMapper.selectList(queryWrapper);
Map<String, List<String>> group = ridList.stream().collect(Collectors.groupingBy(o -> o.getInDir().toString(), Collectors.mapping(BaseRidInfo::getWkt, Collectors.toList())));
//进口道方向wkt
Map<String, String> dirWkt = new HashMap<>();
group.forEach((k, v) -> {
dirWkt.put(k, v.get(0));
});
po.setDirs(null);
po.setDirWkt(dirWkt);
}
return po;
}
@Override
public List<Map<String, Object>> findEventDistribute(String crossId, String startTime, String endTime) {
Map<String, Object> params = new HashMap<>();
params.put("crossId", crossId);
params.put("startDate", startTime);
params.put("endDate", endTime);
List<Map<String, Object>> retList = new ArrayList<>();
DateTime start = DateTime.parse(startTime, DateTimeFormat.forPattern(EsDateIndexUtil.YMD_HM_FORMATTER));
DateTime end = DateTime.parse(endTime, DateTimeFormat.forPattern(EsDateIndexUtil.YMD_HM_FORMATTER));
//存放时段
Set<String> sortedSet = getTimeScopeList(start, end, EsDateIndexUtil.YMD_HM_FORMATTER);
List<EventInfoSimplePo> list = holoEventMapper.findEventDistribute(params);
//每5分组分组
Map<String, List<EventInfoSimplePo>> group = list.stream().collect(Collectors.groupingBy(o -> o.getTimeAxisStart()));
List<EventInfoSimplePo> tmpList = new ArrayList<>();
List<String> dataserList = new ArrayList<>();
group.forEach((time, valList1) -> {
//5分组内数据按类型分组
Map<String, List<EventInfoSimplePo>> groupByType = valList1.stream().collect(Collectors.groupingBy(o -> o.getEventType()));
//List<EventInfoSimplePo> tmpList = new ArrayList<>();
groupByType.forEach((type, valList2) -> {
EventInfoSimplePo tmp = null;
for (EventInfoSimplePo po : valList2) {
po.setDate(net.wanji.common.utils.tool.DateUtil.formatDate(po.getStartTime(), "M/d"));
//合并时间重叠事件
if (tmp != null) {
Date agoStartTime = tmp.getStartTime();
Date agoEndTime = tmp.getEndTime();
Date currentStartTime = po.getStartTime();
Date currentEndTime = po.getEndTime();
if (currentStartTime.before(agoEndTime)) {
int duration = Seconds.secondsBetween(new DateTime(agoStartTime.getTime()), new DateTime(currentEndTime.getTime())).getSeconds();
po.setDuration(duration);
po.setStartTime(agoStartTime);
po.setEndTime(currentEndTime);
po.setTimeAxisStart(tmp.getTimeAxisStart());
po.setCount(po.getCount() + 1);
//清理合并前的记录
tmpList.remove(tmp);
}
}
//==============周期数据时间范围============================================//
DateTime startAxis = new DateTime(DateTime.parse(po.getTimeAxisStart(), DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")));
DateTime endAxis = new DateTime(po.getEndTime());
int diffNum = Minutes.minutesBetween(startAxis, endAxis).getMinutes();
List<String> dataTimeList = po.getDataTimeList();
for (int i = 0; i <= diffNum; i++) {
DateTime axisDateTime = startAxis.plusMinutes(i * 1);
int m = axisDateTime.getMinuteOfHour();
if (m % 5 == 0 && axisDateTime.isBefore(endAxis)) {
dataTimeList.add(axisDateTime.toString("yyyy-MM-dd HH:mm:ss"));
}
}
po.setTimeAxisEnd(endAxis.toString("yyyy-MM-dd HH:mm:ss"));
po.setDataTimeList(dataTimeList);
//======================================================================//
tmpList.add(po);
tmp = po;
}
});
});
List<EventInfoSimplePo> sortList = tmpList.stream().sorted(Comparator.comparing(o -> o.getStartTime())).collect(Collectors.toList());
sortList.forEach(po -> {
String axis = DateUtil.formatDate(po.getStartTime(), "M/d") + "," + DateUtil.formatDate(po.getStartTime(), "HH:mm:ss") + "," + po.getEventType();
dataserList.add(axis);
});
Map<String, Object> map = new HashMap<>();
map.put("statusByDateList", sortList);
map.put("dataser", dataserList);
retList.add(map);
// Set<String> timeList = group.keySet();
//补充缺少时段数据,保留时段字段默认值
// for (String timeSec : sortedSet) {
// if (!timeList.contains(timeSec)) {
// Map<String, Object> map = new HashMap<>();
// map.put("timeAxis", timeSec);
// map.put("statusByDateList", new ArrayList<>());
// retList.add(map);
// }
// }
// List<Map<String, Object>> sortList = retList.stream().sorted(Comparator.comparing(o -> o.get("timeAxis").toString())).collect(Collectors.toList());
return retList;
}
@Override
public EventInfoTrafficStatusVO trafficStatus(EventInfoTrafficStatusDTO eventInfoTrafficStatusDTO) throws DubboProviderException {
EventInfoTrafficStatusVO eventInfoTrafficStatusVO = new EventInfoTrafficStatusVO();
String eventType = eventInfoTrafficStatusDTO.getEventType();
Integer queryType = eventInfoTrafficStatusDTO.getQueryType();
String timeType = eventInfoTrafficStatusDTO.getTimeType();
List<EventInfoTrafficStatusPO> eventInfoTrafficStatusPOS = null;
if (ObjectUtil.equals(1, queryType)) {
//路口
//获取type
String type = EventInfoTypeEnum.getEventInfoTypeEnum(Integer.valueOf(eventType)).getEventType();
eventInfoTrafficStatusDTO.setEventType(type);
eventInfoTrafficStatusPOS = holoEventMapper.trafficStatus(eventInfoTrafficStatusDTO);
} else {
//干线
List<Integer> statusList = new ArrayList<>();
if (ObjectUtil.equals("6", eventType)) {
//干线缓行
statusList.add(2);
} else {
//干线拥堵
statusList.add(3);
statusList.add(4);
}
List<GreenwaveHistPO> greenwaveHistPOS = greenwaveHistMapper.selectByIdAndType(Integer.valueOf(eventInfoTrafficStatusDTO.getId()), statusList);
if (ObjectUtil.isNotEmpty(greenwaveHistPOS)) {
eventInfoTrafficStatusPOS = greenwaveHistHandler(timeType,greenwaveHistPOS);
/*eventInfoTrafficStatusPOS = new ArrayList<EventInfoTrafficStatusPO>();
if (ObjectUtil.equals(timeType,3)) {
//按小时统计,还按照之前逻辑处理
Map<Integer, List<GreenwaveHistPO>> collect = greenwaveHistPOS.stream().collect(Collectors.groupingBy(x -> x.getStartTime().getHours()));
for (Map.Entry<Integer, List<GreenwaveHistPO>> entry : collect.entrySet()) {
eventInfoTrafficStatusPOS.add(handerEntry(entry));
}
}else {
//其它十分钟,15分钟,30分钟数据有一次算一次
Map<String, List<GreenwaveHistPO>> groupedEvents = greenwaveHistPOS.stream()
.collect(Collectors.groupingBy(event -> {
GreenwaveHistPO greenwaveHistPO = (GreenwaveHistPO)event;
Date date = greenwaveHistPO.getStartTime();
LocalDateTime startTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
// 将时间向下取整到最近的15分钟(按时间聚合)
LocalDateTime roundedTime = null;
if (ObjectUtil.equals(timeType,"5")){
//十分钟
roundedTime = startTime.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(10 * (startTime.getMinute() / 10));
}else if (ObjectUtil.equals(timeType,"1")){
//15分钟
roundedTime = startTime.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(15 * (startTime.getMinute() / 15));
}else if (ObjectUtil.equals(timeType,"2")){
//30分钟
roundedTime = startTime.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(30 * (startTime.getMinute() / 30));
}
// 格式化为"小时:分钟"字符串
return roundedTime.format(DateTimeFormatter.ofPattern("HH:mm"));
}));
Set<String> strings = groupedEvents.keySet();
for (String string : strings) {
List<GreenwaveHistPO> value = groupedEvents.get(string);
EventInfoTrafficStatusPO eventInfoTrafficStatusPO = new EventInfoTrafficStatusPO();
int size = value.size();
int sum = value.stream().mapToInt(GreenwaveHistPO::getStrategyDuration).sum();
eventInfoTrafficStatusPO.setDuration(sum);
eventInfoTrafficStatusPO.setCount(size);
eventInfoTrafficStatusPO.setTimeAxisStart(string);
eventInfoTrafficStatusPOS.add(eventInfoTrafficStatusPO);
}
}*/
}
}
//获取当前时间的时间轴
LocalDateTime localDateTime = LocalDateTimeUtil.convertDateToLDT(new Date());
LocalDateTime dayStart = LocalDateTimeUtil.getDayStart(localDateTime);
String now = LocalDateTimeUtil.formatTime(localDateTime, LocalDateTimeUtil.TIMEFORMATTER);
String startTime = LocalDateTimeUtil.formatTime(dayStart, LocalDateTimeUtil.TIMEFORMATTER);
Set<String> timeScopeList = EsDateIndexUtil.getTimeGranularityAxis(eventInfoTrafficStatusDTO.getTimeType(), startTime, now);
if (ObjectUtil.isNotEmpty(timeScopeList)) {
ArrayList<String> arrayList = timeScopeList.stream().collect(Collectors.toCollection(ArrayList::new));
List<String> collect = arrayList.stream().sorted(Comparator.comparing(time -> Integer.valueOf(time.split(":")[0]))).collect(Collectors.toList());
eventInfoTrafficStatusVO.setTimeList(collect);
//补充全部数据
if (ObjectUtil.isEmpty(eventInfoTrafficStatusPOS)) {
int size = timeScopeList.size();
List<Integer> list = getDefaultList(size);
eventInfoTrafficStatusVO.setEventCount(list);
eventInfoTrafficStatusVO.setDurationTime(list);
} else {
List<String> timeList = eventInfoTrafficStatusPOS.stream().map(EventInfoTrafficStatusPO::getTimeAxisStart).collect(Collectors.toList());
//补充缺少时段数据
for (String s : timeScopeList) {
if (!timeList.contains(s)) {
EventInfoTrafficStatusPO eventInfoTrafficStatusPO = new EventInfoTrafficStatusPO();
eventInfoTrafficStatusPO.setDuration(0);
eventInfoTrafficStatusPO.setCount(0);
eventInfoTrafficStatusPO.setTimeAxisStart(s);
eventInfoTrafficStatusPOS.add(eventInfoTrafficStatusPO);
}
}
List<EventInfoTrafficStatusPO> trafficStatusPOS = eventInfoTrafficStatusPOS.stream().sorted(Comparator.comparing(time -> {
try {
return DateUtil.parse(time.getTimeAxisStart(),LocalDateTimeUtil.HOURMINITFORMATTER);
} catch (ParseException e) {
throw new RuntimeException(e);
}
})).collect(Collectors.toList());
List<Integer> durationList = trafficStatusPOS.stream().map(x -> x.getDuration()).collect(Collectors.toList());
List<Integer> countList = trafficStatusPOS.stream().map(x -> x.getCount()).collect(Collectors.toList());
eventInfoTrafficStatusVO.setEventCount(countList);
eventInfoTrafficStatusVO.setDurationTime(durationList);
}
}
return eventInfoTrafficStatusVO;
}
/**
* @Description 干线数据处理
* @Param [greenwaveHistPOS]
* @return void
**/
private List<EventInfoTrafficStatusPO> greenwaveHistHandler(String timeType ,List<GreenwaveHistPO> greenwaveHistPOS){
List<EventInfoTrafficStatusPO> eventInfoTrafficStatusPOS = new ArrayList<>();
//其它十分钟,15分钟,30分钟数据有一次算一次
Map<String, List<GreenwaveHistPO>> groupedEvents = greenwaveHistPOS.stream()
.collect(Collectors.groupingBy(event -> {
GreenwaveHistPO greenwaveHistPO = (GreenwaveHistPO)event;
Date date = greenwaveHistPO.getStartTime();
LocalDateTime startTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
// 将时间向下取整到最近的15分钟(按时间聚合)
LocalDateTime roundedTime = null;
if (ObjectUtil.equals(timeType,"5")){
//十分钟
roundedTime = startTime.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(10 * (startTime.getMinute() / 10));
}else if (ObjectUtil.equals(timeType,"1")){
//15分钟
roundedTime = startTime.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(15 * (startTime.getMinute() / 15));
}else if (ObjectUtil.equals(timeType,"2")){
//30分钟
roundedTime = startTime.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(30 * (startTime.getMinute() / 30));
}else if (ObjectUtil.equals(timeType,"3")){
//1小时
roundedTime = startTime.truncatedTo(ChronoUnit.HOURS)
.plusMinutes(60 * (startTime.getMinute() / 60));
}
// 格式化为"小时:分钟"字符串
return roundedTime.format(DateTimeFormatter.ofPattern("HH:mm"));
}));
Set<String> strings = groupedEvents.keySet();
for (String string : strings) {
EventInfoTrafficStatusPO eventInfoTrafficStatusPO = new EventInfoTrafficStatusPO();
List<GreenwaveHistPO> value = groupedEvents.get(string);
int count = 0;
int duration = 0;
for (int i = 0; i < value.size(); i++) {
if (i == 0){
count++;
//五分钟数据,则一次拥堵为300秒
duration+=300;
}else {
if (value.get(i).getStartTime().getTime() - value.get(i - 1).getStartTime().getTime() <= 305) {
//视为连续拥堵,则不加次数,拥堵时长加300秒
//五分钟数据,则一次拥堵为300秒
duration+=300;
}else {
count++;
//五分钟数据,则一次拥堵为300秒
duration+=300;
}
}
}
eventInfoTrafficStatusPO.setDuration(duration);
eventInfoTrafficStatusPO.setCount(count);
eventInfoTrafficStatusPO.setTimeAxisStart(string);
eventInfoTrafficStatusPOS.add(eventInfoTrafficStatusPO);
}
return eventInfoTrafficStatusPOS;
}
/**
* @return net.wanji.databus.po.EventInfoTrafficStatusPO
* @Description 干线数据处理
* @Param [entry]
**/
private EventInfoTrafficStatusPO handerEntry(Map.Entry<Integer, List<GreenwaveHistPO>> entry) {
EventInfoTrafficStatusPO eventInfoTrafficStatusPO = new EventInfoTrafficStatusPO();
Integer hour = entry.getKey();
String timeAxisStart = null;
if (hour <= 9) {
timeAxisStart = "0" + entry.getKey() + ":00";
} else {
timeAxisStart = entry.getKey() + ":00";
}
int count = 0;
List<GreenwaveHistPO> value = entry.getValue();
for (int i = 0; i < value.size(); i++) {
if (i == 0) {
count++;
} else {
if (value.get(i).getStartTime().getTime() - value.get(i - 1).getStartTime().getTime() >= 300) {
count++;
}
}
}
int duration = value.size() * 300;
eventInfoTrafficStatusPO.setDuration(duration);
eventInfoTrafficStatusPO.setCount(count);
eventInfoTrafficStatusPO.setTimeAxisStart(timeAxisStart);
return eventInfoTrafficStatusPO;
}
/**
* @return java.util.List<java.lang.Integer>
* @Description 根据集合长度,获取默认0补充的list
* @Param [size] 长度
**/
private List<Integer> getDefaultList(int size) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(0);
}
return list;
}
@Override
public List<EventAlarmInfo> findEventAlarmInfo(String realtimeType, String eventType, String name) throws DubboProviderException {
//获取数据库数据
List<EventAlarmInfo> eventAlarmInfo = holoEventMapper.findEventAlarmInfo(realtimeType, eventType, name);
return eventAlarmInfo;
}
@Override
public List<EventAlarmInfo> findNotFinishAlarmInfo() throws DubboProviderException {
Map<String,Object> param = new HashMap<>();
param.put("is_signal",1);
List<TBaseCrossInfo> crossList = baseCrossInfoMapper.selectByMap(param);
List<EventAlarmInfo> list = holoEventMapper.findNotFinishAlarmInfo();
List<String> cidList = new ArrayList<>();
for (EventAlarmInfo info : list) {
String dir = info.getDir();
String turn = info.getTurn();
cidList.add(info.getCrossId());
if (Objects.nonNull(dir)) {
List<Integer> dirJsonArray = JSONArray.parseArray(dir, Integer.class);
//dirJsonArray = dirJsonArray.stream().distinct().collect(Collectors.toList());
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(info.getCurrentAlgo() + "发生方向:");
if (Objects.nonNull(turn)) {
//有方向、有转向
List<Integer> turnJsonArray = JSONArray.parseArray(turn, Integer.class);
//turnJsonArray = turnJsonArray.stream().distinct().collect(Collectors.toList());
for (int i = 0; i < dirJsonArray.size(); i++) {
String dirName = BaseEnum.SignalDirectionEnum.getNameByCode(Integer.valueOf(dirJsonArray.get(i))) + "进口";
if (Objects.equals(3,info.getStatus())){
dirName = BaseEnum.SignalDirectionEnum.getNameByCode(Integer.valueOf(dirJsonArray.get(i))) + "出口";
}
String turnName = BaseEnum.TurnTypeEnum.getNameByCode(turnJsonArray.get(i));
String desc = dirName + turnName;
// if (stringBuilder.indexOf(desc)>0){
// continue;
// }
if (i != dirJsonArray.size() - 1) {
stringBuilder.append(desc);
stringBuilder.append(";");
} else {
stringBuilder.append(desc);
}
}
} else {
//只有方向
for (int i = 0; i < dirJsonArray.size(); i++) {
String dirName = BaseEnum.SignalDirectionEnum.getNameByCode(Integer.valueOf(dirJsonArray.get(i))) + "进口";
if (Objects.equals(3,info.getStatus())){
dirName = BaseEnum.SignalDirectionEnum.getNameByCode(Integer.valueOf(dirJsonArray.get(i))) + "出口";
}
// if (stringBuilder.indexOf(dirName)>0){
// continue;
// }
if (i != dirJsonArray.size() - 1) {
stringBuilder.append(dirName);
stringBuilder.append(";");
} else {
stringBuilder.append(dirName);
}
}
}
info.setDirDesc(stringBuilder.toString());
}
}
for (TBaseCrossInfo info : crossList) {
String crossId = info.getId();
if (cidList.contains(crossId)) {
continue;
}
EventAlarmInfo emptyAlarm = new EventAlarmInfo();
emptyAlarm.setStatus(0);
emptyAlarm.setCrossId(crossId);
emptyAlarm.setCrossName(info.getName());
String wkt = info.getLocation();//.replaceAll(" ",",");
wkt = wkt.replaceAll("POINT\\(","");
wkt = wkt.replaceAll("\\)","");
emptyAlarm.setWkt(wkt);
list.add(emptyAlarm);
}
return list;
}
public static Set<String> getTimeScopeList(DateTime start, DateTime end, String dateFormat) {
Set<String> indexList = new HashSet<>();
int diffNum = Minutes.minutesBetween(start, end).getMinutes();
int unitTime = 5;
for (int i = 0; i <= diffNum; i = i + unitTime) {
String format = start.plusMinutes(i).toString(dateFormat);
indexList.add(format);
}
return indexList;
}
}
\ No newline at end of file
package net.wanji.opt.service.impl;//package net.wanji.opt.service.impl;
//package net.wanji.opt.service.impl;
//
//import lombok.extern.slf4j.Slf4j;
//import net.wanji.common.utils.tool.BeanListUtils;
......
package net.wanji.opt.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.CrossStatusEnum;
import net.wanji.common.enums.TurnConvertEnum;
import net.wanji.common.framework.exception.DubboProviderException;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.common.utils.tool.StringUtils;
import net.wanji.common.utils.tool.TimeArrayUtil;
import net.wanji.databus.bo.CrossIdAndStartEndDateBO;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.bo.HeatMapBO;
import net.wanji.databus.dao.entity.*;
import net.wanji.databus.dao.mapper.*;
import net.wanji.databus.dto.MetricHistDTO;
import net.wanji.databus.dto.RunningPlanDTO;
import net.wanji.databus.po.BaseCrossInfoPO;
import net.wanji.databus.po.CrossDataHistPO;
import net.wanji.databus.po.CrossTurnInfoPO;
import net.wanji.databus.po.LaneInfoPO;
import net.wanji.databus.po.TBaseCrossInfo;
import net.wanji.databus.vo.RunningEvaluateCrossListVO;
import net.wanji.opt.bo.CrossNameBO;
import net.wanji.opt.bo.MetricsDetailBO;
import net.wanji.opt.common.KafkaConsumerUtil;
import net.wanji.opt.constant.EventAbnormalEnum;
import net.wanji.opt.constant.ServiceLevelEnum;
import net.wanji.opt.dto.PhaseEmptyResult;
import net.wanji.opt.service.GreenwaveHistProvider;
import net.wanji.opt.service.RunningEvaluateService;
import net.wanji.opt.vo.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author Kent HAN
* @date 2023/8/21 9:53
*/
@Slf4j
@Service
public class RunningEvaluateServiceImpl implements RunningEvaluateService {
@Value("${spring.kafka.bootstrap-servers}")
private String bootstrapServers;
@Value("${spring.kafka.empty-phase-topic}")
private String emptyPhaseTopic;
private final CrossDataRealtimeMapper crossDataRealtimeMapper;
private final CrossDataHistMapper crossDataHistMapper;
private final BaseCrossSectionMapper baseCrossSectionMapper;
private final BaseCrossSchemeMapper baseCrossSchemeMapper;
private final BaseCrossDirInfoMapper baseCrossDirInfoMapper;
private final BaseCrossTurnInfoMapper baseCrossTurnInfoMapper;
private final LaneInfoMapper laneInfoMapper;
private final BaseCrossInfoMapper baseCrossInfoMapper;
private final BaseCrossPlanMapper baseCrossPlanMapper;
private final BaseCrossSchedulesMapper baseCrossSchedulesMapper;
private final BaseCrossSchedulesPlanMapper baseCrossSchedulesPlanMapper;
private final CrossDirDataHistMapper crossDirDataHistMapper;
private final CrossTurnDataHistMapper crossTurnDataHistMapper;
private final CrossLaneDataHistMapper crossLaneDataHistMapper;
@Resource
private GreenwaveHistProvider greenwaveHistProvider;
SimpleDateFormat HOUR_SDF = new SimpleDateFormat("HH:mm");
SimpleDateFormat DAY_SDF = new SimpleDateFormat("yyyy-MM-dd");
ObjectMapper objectMapper = new ObjectMapper();
public RunningEvaluateServiceImpl(CrossDataRealtimeMapper crossDataRealtimeMapper,
CrossDataHistMapper crossDataHistMapper,
@Qualifier("baseCrossSectionMapper") BaseCrossSectionMapper baseCrossSectionMapper,
@Qualifier("baseCrossSchemeMapper") BaseCrossSchemeMapper baseCrossSchemeMapper,
@Qualifier("baseCrossDirInfoMapper") BaseCrossDirInfoMapper baseCrossDirInfoMapper,
@Qualifier("baseCrossTurnInfoMapper") BaseCrossTurnInfoMapper baseCrossTurnInfoMapper,
@Qualifier("laneInfoMapper") LaneInfoMapper laneInfoMapper,
@Qualifier("baseCrossInfoMapper") BaseCrossInfoMapper baseCrossInfoMapper,
@Qualifier("baseCrossPlanMapper") BaseCrossPlanMapper baseCrossPlanMapper,
@Qualifier("baseCrossSchedulesMapper") BaseCrossSchedulesMapper baseCrossSchedulesMapper,
@Qualifier("baseCrossSchedulesPlanMapper") BaseCrossSchedulesPlanMapper baseCrossSchedulesPlanMapper,
CrossDirDataHistMapper crossDirDataHistMapper,
CrossTurnDataHistMapper crossTurnDataHistMapper,
CrossLaneDataHistMapper crossLaneDataHistMapper) {
this.crossDataRealtimeMapper = crossDataRealtimeMapper;
this.crossDataHistMapper = crossDataHistMapper;
this.baseCrossSectionMapper = baseCrossSectionMapper;
this.baseCrossSchemeMapper = baseCrossSchemeMapper;
this.baseCrossDirInfoMapper = baseCrossDirInfoMapper;
this.baseCrossTurnInfoMapper = baseCrossTurnInfoMapper;
this.laneInfoMapper = laneInfoMapper;
this.baseCrossInfoMapper = baseCrossInfoMapper;
this.baseCrossPlanMapper = baseCrossPlanMapper;
this.baseCrossSchedulesMapper = baseCrossSchedulesMapper;
this.baseCrossSchedulesPlanMapper = baseCrossSchedulesPlanMapper;
this.crossDirDataHistMapper = crossDirDataHistMapper;
this.crossTurnDataHistMapper = crossTurnDataHistMapper;
this.crossLaneDataHistMapper = crossLaneDataHistMapper;
}
@Override
public List<RunningEvaluateCrossListVO> crossList(CrossNameBO crossNameBO) {
String crossName = crossNameBO.getCrossName();
List<RunningEvaluateCrossListVO> voList = crossDataRealtimeMapper.selectByCrossName(crossName);
for (RunningEvaluateCrossListVO vo : voList) {
Double sturation = vo.getSturation();
vo.setServiceLevel(CrossUtil.getServiceLevel(sturation));
// 路口经纬度
String crossId = vo.getCrossId();
BaseCrossInfoPO baseCrossInfoPO = baseCrossInfoMapper.selectById(crossId);
String location = baseCrossInfoPO.getLocation();
double[] lonLat = CrossUtil.getLonLat(location);
vo.setLongitude(lonLat[0]);
vo.setLatitude(lonLat[1]);
// 浮点精度
BigDecimal congestionIndex = vo.getCongestionIndex();
BigDecimal roundedCongestionIndex = congestionIndex.setScale(2, RoundingMode.HALF_UP);
vo.setCongestionIndex(roundedCongestionIndex);
}
// 按服务水平降序排序
List<RunningEvaluateCrossListVO> res = voList.stream()
.sorted(Comparator.comparing(RunningEvaluateCrossListVO::getSturation).reversed())
.collect(Collectors.toList());
return res;
}
@Override
public RunningEvaluateCrossEvaluateVO crossEvaluate(CrossIdAndStartEndDateBO bo) throws DubboProviderException {
RunningEvaluateCrossEvaluateVO vo = new RunningEvaluateCrossEvaluateVO();
String crossId = bo.getCrossId();
List<CrossDataHistPO> crossDataHistPOList = buildCrossDataHistPOList(bo, crossId);
for (CrossDataHistPO po : crossDataHistPOList) {
//历史未存服务水平字段数据置为A,否则分组报异常
po.setServiceLevel(po.getServiceLevel()==null?"A":po.getServiceLevel());
}
String startTime = net.wanji.common.utils.tool.DateUtil.formatDate(bo.getStartDate(), "yyyy-MM-dd HH:mm:ss");
String endTime = net.wanji.common.utils.tool.DateUtil.formatDate(bo.getEndDate(), "yyyy-MM-dd HH:mm:ss");
//按服务水平分组
Map<String, List<CrossDataHistPO>> groupByServerLevel = crossDataHistPOList.stream().collect(Collectors.groupingBy(o -> o.getServiceLevel()));
double total = 0;
for (Map.Entry<String, List<CrossDataHistPO>> entry1 : groupByServerLevel.entrySet()) {
String key = entry1.getKey();
total += ServiceLevelEnum.getByType(key).getVal() * entry1.getValue().size();
}
//服务水平加权平均计算:给服务水平(等级得分*该等级的数量)累加/总数量
int avgService = (int) Math.round(total/crossDataHistPOList.size());
String serviceLevel = ServiceLevelEnum.getByVal(avgService)==null?"A":ServiceLevelEnum.getByVal(avgService).getType();
vo.setServiceLevel(serviceLevel);
// *******************************************************************************************************//
List<GreenWaveRunStateVO> runStateList = null;
//greenwaveHistProvider.findGreenWaveRunState(null, bo.getCrossId(), startTime, endTime, "701,702,703");
Map<Integer, GreenWaveRunStateVO> groupList = runStateList.stream().collect(Collectors.toMap(o -> o.getState(), o -> o));
vo.setUnbalanceTimes(groupList.get(EventAbnormalEnum.CROSS_UNBALANCE.getType()) == null ? 0 : groupList.get(EventAbnormalEnum.CROSS_UNBALANCE.getType()).getCount());
int unbalanceSum = groupList.get(EventAbnormalEnum.CROSS_UNBALANCE.getType()) == null ? 0 : groupList.get(EventAbnormalEnum.CROSS_UNBALANCE.getType()).getDuration();
vo.setUnbalanceSum(Math.round(unbalanceSum));
vo.setSpilloverTimes(groupList.get(EventAbnormalEnum.CROSS_OVERFLOW.getType()) == null ? 0 : groupList.get(EventAbnormalEnum.CROSS_OVERFLOW.getType()).getCount());
int spilloverSum = groupList.get(EventAbnormalEnum.CROSS_OVERFLOW.getType()) == null ? 0 : groupList.get(EventAbnormalEnum.CROSS_OVERFLOW.getType()).getDuration();
vo.setSpilloverSum(Math.round(spilloverSum));
int emptyPhaseCount = groupList.get(EventAbnormalEnum.CROSS_PHASE_EMPTY.getType()) == null ? 0 : groupList.get(EventAbnormalEnum.CROSS_PHASE_EMPTY.getType()).getCount();
int emptyPhaseSum = groupList.get(EventAbnormalEnum.CROSS_PHASE_EMPTY.getType()) == null ? 0 : groupList.get(EventAbnormalEnum.CROSS_PHASE_EMPTY.getType()).getDuration();
vo.setEmptyPhaseTimes(emptyPhaseCount);
vo.setEmptyPhaseSum(Math.round(emptyPhaseSum));
// *******************************************************************************************************//
return vo;
}
private boolean isInTimeRange(Integer batchTime) {
// 早晚高峰及平峰时段
int hour = (batchTime % 86400) / 3600;
int minute = (batchTime % 3600) / 60;
return (hour >= 7 && hour < 9) ||
(hour >= 16 && (hour < 18 || (hour == 18 && minute < 30))) ||
(hour >= 11 && hour < 13);
}
private List<CrossDataHistPO> buildCrossDataHistPOList(CrossIdAndStartEndDateBO bo, String crossId) {
Date startDate = bo.getStartDate();
Date endDate = bo.getEndDate();
if (isZeros(endDate)) {
endDate = DateUtil.offsetDay(endDate, 1); // 包含最后一天
}
int startStamp = (int) (startDate.getTime() / 1000); // 10位时间戳
int endStamp = (int) (endDate.getTime() / 1000);
List<CrossDataHistPO> crossDataHistPOList = crossDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startStamp, endStamp);
return crossDataHistPOList;
}
private boolean isZeros(Date endDate) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(endDate);
return calendar.get(Calendar.HOUR_OF_DAY) == 0 &&
calendar.get(Calendar.MINUTE) == 0 &&
calendar.get(Calendar.SECOND) == 0 &&
calendar.get(Calendar.MILLISECOND) == 0;
}
@Override
public RunningEvaluateStatusVO congestionStatus(CrossIdAndStartEndDateBO bo) {
return evaluateStatus(bo, CrossStatusEnum.CONGESTION);
}
@Override
public RunningEvaluateStatusVO unbalanceStatus(CrossIdAndStartEndDateBO bo) {
return evaluateStatus(bo, CrossStatusEnum.UNBALANCE);
}
@Override
public RunningEvaluateStatusVO spilloverStatus(CrossIdAndStartEndDateBO bo) {
return evaluateStatus(bo, CrossStatusEnum.SPILLOVER);
}
public RunningEvaluateStatusVO evaluateStatus(CrossIdAndStartEndDateBO bo, CrossStatusEnum statusEnum) {
RunningEvaluateStatusVO runningEvaluateStatusVO = new RunningEvaluateStatusVO();
String crossId = bo.getCrossId();
int status = statusEnum.getCode();
// 构造入参开始和结束时间戳
Date startDate = bo.getStartDate();
Date endDate = bo.getEndDate();
endDate = DateUtil.offsetDay(endDate, 1); // 包含最后一天
int startStamp = (int) (startDate.getTime() / 1000); // 10位时间戳
int endStamp = (int) (endDate.getTime() / 1000);
runningEvaluateStatusVO.setRunningEvaluateIndexStatusVOList(buildRes(bo, crossId, status));
// 获取问题列表
// 路口级别全量数据
List<MetricHistDTO> crossDTOList = crossDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
// 过滤有问题的记录
List<MetricHistDTO> filteredList = crossDTOList.stream()
.filter(metricHistDTO -> metricHistDTO.getStatus() != null && metricHistDTO.getStatus().equals(status))
.collect(Collectors.toList());
runningEvaluateStatusVO.setProblemStatusList(buildProblemStatusList(filteredList));
runningEvaluateStatusVO.setTimeList(TimeArrayUtil.getMinuteSectionArray(5));
return runningEvaluateStatusVO;
}
@Override
public List<RunningEvaluateSchemeProblemsVO> schemeProblems(CrossIdAndStartEndDateBO bo) {
String crossId = bo.getCrossId();
List<RunningEvaluateSchemeProblemsVO> res = new ArrayList<>();
List<String> timeArray = TimeArrayUtil.getHourArray();
for (String time : timeArray) {
RunningEvaluateSchemeProblemsVO vo = new RunningEvaluateSchemeProblemsVO();
vo.setTime(time);
List<CrossDataHistPO> crossDataHistPOList = buildCrossDataHistPOList(bo, crossId);
// 找出有问题的记录
List<CrossDataHistPO> collect = crossDataHistPOList.stream()
.filter(po -> !Objects.equals(po.getStatus(), CrossStatusEnum.NORMAL.getCode()))
.collect(Collectors.toList());
// 按采集时间小时进行聚合
Map<String, List<CrossDataHistPO>> timePOMap = buildTimePOMap(collect);
;
// 找出当前小时的记录
List<CrossDataHistPO> currentHourList = timePOMap.get(time.substring(0, 2)); // 保留小时字符串
if (currentHourList != null) {
// 按相同开始时间去重,保留持续时间最长的一个
List<CrossDataHistPO> uniqueList = currentHourList.stream()
.collect(Collectors.groupingBy(
CrossDataHistPO::getStartTime, // 按startTime分组
Collectors.collectingAndThen(
// 在每个组中找到duration最大的元素
Collectors.maxBy(Comparator.comparingLong(CrossDataHistPO::getDuration)),
Optional::get // 从Optional中获取元素
)
))
.values().stream().collect(Collectors.toList()); // 从Map中获取值并收集到新的列表中
// 统计数量
vo.setCounts(uniqueList.size());
// 找出出现问题的日期和方案
List<RunningEvaluateSchemeProblemsVO.DateAndScheme> dateAndSchemeList = new ArrayList<>();
dateAndSchemeList = buildDateAndSchemeList(uniqueList, crossId);
vo.setDateAndSchemeList(dateAndSchemeList);
}
res.add(vo);
}
return res;
}
private Map<String, List<CrossDataHistPO>> buildTimePOMap(List<CrossDataHistPO> crossDataHistPOList) {
SimpleDateFormat sdf = new SimpleDateFormat("HH");
Map<String, List<CrossDataHistPO>> timePOMap = crossDataHistPOList.stream()
.collect(Collectors.groupingBy(po -> {
Date date = new Date((long) po.getBatchTime() * 1000); // 将10位时间戳转换为Date对象
return sdf.format(date); // 将Date对象转换为"HH"格式的字符串
}));
return timePOMap;
}
@Override
public RunningEvaluateMetricsDetailVO metricsDetail(MetricsDetailBO bo) {
String crossId = bo.getCrossId();
Integer dir = bo.getDir();
String turn = bo.getTurn();
Integer laneSort = bo.getLaneSort();
// 构造某一天开始和结束时间戳
Date date = bo.getDate();
Date startDate = date;
Date endDate = DateUtil.offsetDay(date, 1); // 包含最后一天
int startStamp = (int) (startDate.getTime() / 1000); // 10位时间戳
int endStamp = (int) (endDate.getTime() / 1000);
Integer minutes = bo.getMinutes();
List<MetricHistDTO> metricHistDTOList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(laneSort)) {
Integer turnInt = TurnConvertEnum.getKeyByCode(turn);
String laneId = laneInfoMapper.selectIdByCrossIdDirTurn2(crossId, dir, turnInt);
metricHistDTOList = crossLaneDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp, laneId);
} else if (ObjectUtil.isNotEmpty(turn)) {
metricHistDTOList = crossTurnDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp, dir, turn);
} else if (ObjectUtil.isNotEmpty(dir)) {
metricHistDTOList = crossDirDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp, dir);
} else { // 路口级别
metricHistDTOList = crossDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
// 相位空放指标
long startTime = startDate.getTime();
long endTime = endDate.getTime();
KafkaConsumerUtil kafkaConsumerUtil = new KafkaConsumerUtil(bootstrapServers, "empty-phase-comsumer");
List<PhaseEmptyResult> phaseEmptyResults =
kafkaConsumerUtil.consumeEmptyPhaseForTimeRange(emptyPhaseTopic, 0, startTime, endTime);
fillPhaseEmpty(metricHistDTOList, crossId, phaseEmptyResults);
}
RunningEvaluateMetricsDetailVO res = new RunningEvaluateMetricsDetailVO();
// 路口级别全量数据
List<MetricHistDTO> crossDTOList = crossDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
// 过滤有问题的记录
List<MetricHistDTO> filteredList = crossDTOList.stream()
.filter(metricHistDTO -> metricHistDTO.getStatus() != null && metricHistDTO.getStatus() != 0)
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(filteredList)) {
res.setProblemStatusList(buildProblemStatusList(filteredList));
res.setSchemeList(buildSchemeList(filteredList, crossId));
}
if (CollectionUtil.isEmpty(metricHistDTOList)) {
return res;
}
// 使用全量数据按时间粒度聚合指标
List<RunningEvaluateMetricsDetailVO.CrossMetrics> crossMetrics = buildMetricsList(metricHistDTOList, minutes);
res.setMetricsList(crossMetrics);
return res;
}
private void fillPhaseEmpty(List<MetricHistDTO> metricHistDTOList, String crossId,
List<PhaseEmptyResult> phaseEmptyResults) {
List<PhaseEmptyResult> crossResults = phaseEmptyResults.stream()
.filter(result -> crossId.equals(result.getCrossId()))
.collect(Collectors.toList());
for (MetricHistDTO metricHistDTO : metricHistDTOList) {
// 计算结束时间
Date endTime = new Date(metricHistDTO.getStartTime().getTime() + 5 * 60 * 1000); // 增加5分钟
// 遍历每个 PhaseEmptyResult 来查找和累加 duration
for (PhaseEmptyResult phaseEmptyResult : crossResults) {
if (phaseEmptyResult.getDetectTime() * 1000 >= metricHistDTO.getStartTime().getTime()
&& phaseEmptyResult.getDetectTime() * 1000 <= endTime.getTime()) {
// 累加 duration
metricHistDTO.setEmptyPhase(metricHistDTO.getEmptyPhase() + phaseEmptyResult.getDuration());
}
}
}
}
public static List<RunningEvaluateMetricsDetailVO.CrossMetrics> buildMetricsList(
List<MetricHistDTO> metricHistDTOList, Integer minutes) {
// 按时间段分组
Map<String, List<MetricHistDTO>> groupedByTime = metricHistDTOList.stream()
.collect(Collectors.groupingBy(metricHistDTO -> {
long timestampInMillSeconds = metricHistDTO.getBatchTime() * 1000L - 300000;
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);
// 计算指标
List<RunningEvaluateMetricsDetailVO.CrossMetrics> res = new ArrayList<>();
for (String section : minuteSectionArray) {
RunningEvaluateMetricsDetailVO.CrossMetrics crossMetrics = new RunningEvaluateMetricsDetailVO.CrossMetrics();
List<MetricHistDTO> dtoList = groupedByTime.get(section);
if (CollectionUtil.isNotEmpty(dtoList)) {
int flowSum = 0;
double speedSum = 0.0;
int capacitySum = 0;
double sturationSum = 0.0;
double stopTimesSum = 0.0;
int delayTimeSum = 0;
double effusionRateSum = 0.0;
int emptyPhaseSum = 0;
for (MetricHistDTO metricHistDTO : dtoList) {
Integer flow = metricHistDTO.getFlow();
Double speed = metricHistDTO.getSpeed();
Integer capacity = metricHistDTO.getCapacity();
Double sturation = metricHistDTO.getSturation();
Double stopTimes = metricHistDTO.getStopTimes();
Integer delayTime = metricHistDTO.getDelayTime();
Double effusionRate = metricHistDTO.getEffusionRate();
Integer emptyPhase = metricHistDTO.getEmptyPhase();
if (flow != null) flowSum += flow;
if (speed != null) speedSum += speed;
if (capacity != null) capacitySum += capacity;
if (sturation != null) sturationSum += sturation;
if (stopTimes != null) stopTimesSum += stopTimes;
if (delayTime != null) delayTimeSum += delayTime;
if (effusionRate != null) effusionRateSum += effusionRate;
if (emptyPhase != null) emptyPhaseSum += emptyPhase;
}
int size = dtoList.size();
crossMetrics.setFlow(flowSum);
crossMetrics.setSpeed(speedSum / size);
crossMetrics.setCapacity(capacitySum / size);
crossMetrics.setSturation(sturationSum / size);
crossMetrics.setStopTimes(stopTimesSum / size);
crossMetrics.setDelayTime(delayTimeSum / size);
crossMetrics.setEffusionRate(effusionRateSum / size);
crossMetrics.setEmptyPhase(emptyPhaseSum);
Date currentDate = dtoList.get(dtoList.size() - 1).getStartTime();
Calendar instance = Calendar.getInstance();
instance.setTime(currentDate);
instance.set(Calendar.HOUR_OF_DAY, Integer.parseInt(section.substring(0, 2)));
instance.set(Calendar.MINUTE, 0);
crossMetrics.setTimeStamp(instance.getTime());
crossMetrics.setMetricTime(section);
}
if (StringUtils.isNotBlank(crossMetrics.getMetricTime())) {
res.add(crossMetrics);
}
}
return res;
}
private List<RunningEvaluateMetricsDetailVO.ProblemScheme> buildSchemeList(
List<MetricHistDTO> metricHistDTOList, String crossId) {
List<BaseCrossSchemePO> baseCrossSchemePOList = baseCrossSchemeMapper.selectAll();
List<RunningEvaluateMetricsDetailVO.ProblemScheme> res = new ArrayList<>();
// 验证数据是否正确
if (!isDataValid(metricHistDTOList)) {
return res;
}
// 根据持续时长去重
List<MetricHistDTO> uniqueList = metricHistDTOList.stream()
.collect(Collectors.groupingBy(
MetricHistDTO::getStartTime, // 按startTime分组
Collectors.collectingAndThen(
// 在每个组中找到duration最大的元素
Collectors.maxBy(Comparator.comparingLong(MetricHistDTO::getDuration)),
Optional::get // 从Optional中获取元素
)
))
.values().stream().collect(Collectors.toList()); // 从Map中获取值并收集到新的列表中
for (MetricHistDTO dto : uniqueList) {
Date abnormalEventStartTime = dto.getStartTime();
Integer duration = dto.getDuration();
Date abnormalEventEndTime = DateUtil.offsetMinute(abnormalEventStartTime, duration);
String eventStartTime = HOUR_SDF.format(abnormalEventStartTime);
String eventEndTime = HOUR_SDF.format(abnormalEventEndTime);
Date datetime = new Date();
String dateStr = DAY_SDF.format(datetime);
// 获取当前计划ID
Integer planId = findPlanId(datetime, dateStr, crossId);
List<CrossSectionPO> crossSectionPOList = baseCrossSectionMapper.selectByCrossAndPlan(crossId, planId);
for (CrossSectionPO crossSectionPO : crossSectionPOList) {
String sectionStartTime = crossSectionPO.getStartTime();
String sectionEndTime = crossSectionPO.getEndTime();
// 比较两组时间段是否相交
boolean isIntersecting = isTimeIntersecting(
eventStartTime, eventEndTime, sectionStartTime, sectionEndTime);
buildResIfIntersecting(res, crossSectionPO, sectionStartTime, sectionEndTime, isIntersecting,
baseCrossSchemePOList);
}
}
// 去除相同方案
List<RunningEvaluateMetricsDetailVO.ProblemScheme> uniqueRes = res.stream()
.distinct()
.collect(Collectors.toList());
return uniqueRes;
}
void buildResIfIntersecting(List<RunningEvaluateMetricsDetailVO.ProblemScheme> res, CrossSectionPO crossSectionPO,
String sectionStartTime, String sectionEndTime, boolean isIntersecting,
List<BaseCrossSchemePO> crossSchemePOList) {
if (isIntersecting) {
Integer schemeId = crossSectionPO.getSchemeId();
Optional<BaseCrossSchemePO> result = crossSchemePOList.stream()
.filter(crossScheme -> schemeId.equals(crossScheme.getId()))
.findFirst();
BaseCrossSchemePO baseCrossSchemePO = result.get();
String schemeName = baseCrossSchemePO.getName();
RunningEvaluateMetricsDetailVO.ProblemScheme problemScheme =
new RunningEvaluateMetricsDetailVO.ProblemScheme();
problemScheme.setSchemeName(schemeName);
problemScheme.setSchemeId(schemeId);
problemScheme.setStartTime(sectionStartTime);
problemScheme.setEndTime(sectionEndTime);
res.add(problemScheme);
}
}
List<RunningEvaluateMetricsDetailVO.ProblemStatus> buildProblemStatusList(
List<MetricHistDTO> metricHistDTOList) {
List<RunningEvaluateMetricsDetailVO.ProblemStatus> res = new ArrayList<>();
// 验证数据是否正确
if (!isDataValid(metricHistDTOList)) {
return res;
}
// 根据持续时长去重
List<MetricHistDTO> uniqueList = metricHistDTOList.stream()
.collect(Collectors.groupingBy(
MetricHistDTO::getStartTime, // 按startTime分组
Collectors.collectingAndThen(
// 在每个组中找到duration最大的元素
Collectors.maxBy(Comparator.comparingLong(MetricHistDTO::getDuration)),
Optional::get // 从Optional中获取元素
)
))
.values().stream().collect(Collectors.toList()); // 从Map中获取值并收集到新的列表中
for (MetricHistDTO metricHistDTO : uniqueList) {
RunningEvaluateMetricsDetailVO.ProblemStatus problemStatus =
new RunningEvaluateMetricsDetailVO.ProblemStatus();
Integer status1 = metricHistDTO.getStatus();
problemStatus.setStatus(status1);
Date startTime1 = metricHistDTO.getStartTime();
problemStatus.setStartTime(startTime1);
Integer duration1 = metricHistDTO.getDuration();
DateTime endTime = DateUtil.offsetMinute(startTime1, duration1);
problemStatus.setEndTime(endTime);
problemStatus.setDurationMinutes(duration1);
res.add(problemStatus);
}
// 合并时间区间
// 先按 status 排序,status 相同再按 startTime 排序
List<RunningEvaluateMetricsDetailVO.ProblemStatus> sortedList = res.stream()
.sorted(Comparator.comparingInt(RunningEvaluateMetricsDetailVO.ProblemStatus::getStatus)
.thenComparing(RunningEvaluateMetricsDetailVO.ProblemStatus::getStartTime))
.collect(Collectors.toList());
List<RunningEvaluateMetricsDetailVO.ProblemStatus> mergedList = new ArrayList<>();
RunningEvaluateMetricsDetailVO.ProblemStatus current = sortedList.get(0);
for (int i = 1; i < sortedList.size(); i++) {
RunningEvaluateMetricsDetailVO.ProblemStatus next = sortedList.get(i);
if (Objects.equals(current.getStatus(), next.getStatus())
&& !current.getEndTime().before(next.getStartTime())) {
// 如果有交叉,则合并记录
current.setEndTime(new Date(Math.max(current.getEndTime().getTime(), next.getEndTime().getTime())));
current.setDurationMinutes(
(int) ((current.getEndTime().getTime() - current.getStartTime().getTime()) / (60 * 1000)));
} else {
// 否则,将当前记录添加到结果列表中,并更新当前记录
mergedList.add(current);
current = next;
}
}
mergedList.add(current); // 添加最后一个记录
return mergedList;
}
private boolean isDataValid(List<MetricHistDTO> metricHistDTOList) {
if (CollectionUtil.isEmpty(metricHistDTOList)) {
return false;
}
MetricHistDTO dto = metricHistDTOList.get(0);
Integer status = dto.getStatus();
Date startTime = dto.getStartTime();
Integer duration = dto.getDuration();
if (ObjectUtil.isEmpty(startTime) || ObjectUtil.isEmpty(duration) || ObjectUtil.isEmpty(status)) {
return false;
}
return true;
}
@Override
public RunningEvaluateScopeTreeVO scopeTree(CrossIdBO bo) {
String crossId = bo.getCrossId();
RunningEvaluateScopeTreeVO runningEvaluateScopeTreeVO = new RunningEvaluateScopeTreeVO();
runningEvaluateScopeTreeVO.setCrossId(crossId);
List<RunningEvaluateScopeTreeVO.DirVO> dirVOList = buildDirVOList(crossId);
runningEvaluateScopeTreeVO.setChild(dirVOList);
return runningEvaluateScopeTreeVO;
}
@Override
public List<RunningEvaluateHeatMapVO> heatMap(HeatMapBO bo) {
String crossId = bo.getCrossId();
Date startDate = bo.getStartDate();
Date endDate = bo.getEndDate();
endDate = DateUtil.offsetDay(endDate, 1); // 包含最后一天
int startStamp = (int) (startDate.getTime() / 1000); // 10位时间戳
int endStamp = (int) (endDate.getTime() / 1000);
Integer status = bo.getStatus();
List<RunningEvaluateHeatMapVO> res = new ArrayList<>();
List<CrossDataHistPO> crossDataHistPOList = crossDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startStamp, endStamp);
// 根据 status 值选择分组字段
Function<CrossDataHistPO, String> groupByField;
switch (status) {
case 1:
groupByField = CrossDataHistPO::getUnbalanceDirs;
break;
case 2:
groupByField = CrossDataHistPO::getCongestionDirs;
break;
case 3:
groupByField = CrossDataHistPO::getSpilloverDirs;
break;
default:
throw new IllegalArgumentException("状态值非法");
}
// 过滤 status 字段值为 status 变量的对象,并按照方向分组
Map<String, List<CrossDataHistPO>> grouped = crossDataHistPOList.stream()
.flatMap(po -> {
String dirs = "";
if (status == 1) {
dirs = po.getUnbalanceDirs();
} else if (status == 2) {
dirs = po.getCongestionDirs();
} else if (status == 3) {
dirs = po.getSpilloverDirs();
}
return Arrays.stream(dirs.split(","))
.map(dir -> new AbstractMap.SimpleEntry<>(dir, po));
})
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())
));
// 对每个组进行处理,仅保留 start_time 相同的记录中 duration 最大的一条
Map<String, List<CrossDataHistPO>> filteredGrouped = grouped.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
.collect(Collectors.groupingBy(CrossDataHistPO::getStartTime))
.values().stream()
.map(list -> list.stream().max(Comparator.comparingInt(CrossDataHistPO::getDuration))
.orElse(null))
.collect(Collectors.toList())
));
// 遍历 filteredGrouped,提取每个 key 和与该 key 关联的列表的元素个数
filteredGrouped.forEach((key, list) -> {
RunningEvaluateHeatMapVO runningEvaluateHeatMapVO = new RunningEvaluateHeatMapVO();
if (ObjectUtil.isNotEmpty(key)) {
runningEvaluateHeatMapVO.setDir(Integer.parseInt(key));
runningEvaluateHeatMapVO.setCounts(list.size());
res.add(runningEvaluateHeatMapVO);
}
});
return res;
}
private List<RunningEvaluateScopeTreeVO.DirVO> buildDirVOList(String crossId) {
List<RunningEvaluateScopeTreeVO.DirVO> res = new ArrayList<>();
Integer type = 1; // 进口
List<BaseCrossDirInfoPO> baseCrossDirInfoPOList =
baseCrossDirInfoMapper.selectByCrossIdAndInOutType(crossId, type);
for (BaseCrossDirInfoPO baseCrossDirInfoPO : baseCrossDirInfoPOList) {
RunningEvaluateScopeTreeVO.DirVO dirVO = new RunningEvaluateScopeTreeVO.DirVO();
Integer dir = baseCrossDirInfoPO.getDirType();
dirVO.setDir(dir);
List<RunningEvaluateScopeTreeVO.TurnVO> turnVOList = buildTurnVOList(crossId, dir);
dirVO.setChild(turnVOList);
res.add(dirVO);
}
return res;
}
private List<RunningEvaluateScopeTreeVO.TurnVO> buildTurnVOList(String crossId, Integer dir) {
List<RunningEvaluateScopeTreeVO.TurnVO> res = new ArrayList<>();
List<CrossTurnInfoPO> crossTurnInfoPOList = baseCrossTurnInfoMapper.selectByCrossIdAndDir(crossId, dir);
for (CrossTurnInfoPO crossTurnInfoPO : crossTurnInfoPOList) {
RunningEvaluateScopeTreeVO.TurnVO turnVO = new RunningEvaluateScopeTreeVO.TurnVO();
String turnType = crossTurnInfoPO.getTurnType();
turnVO.setTurn(turnType);
List<RunningEvaluateScopeTreeVO.LaneVO> laneVOList = buildLaneVOList(crossId, dir, turnType);
turnVO.setChild(laneVOList);
res.add(turnVO);
}
return res;
}
private List<RunningEvaluateScopeTreeVO.LaneVO> buildLaneVOList(String crossId, Integer dir, String turnType) {
List<RunningEvaluateScopeTreeVO.LaneVO> res = new ArrayList<>();
List<Integer> keyList = TurnConvertEnum.getKeyListBySingleCode(turnType);
Integer type = 2; // 进口
if (ObjectUtil.isNotEmpty(keyList)) {
List<LaneInfoPO> laneInfoPOList = laneInfoMapper.selectByTurnType(crossId, type, dir, keyList);
for (LaneInfoPO laneInfoPO : laneInfoPOList) {
RunningEvaluateScopeTreeVO.LaneVO laneVO = new RunningEvaluateScopeTreeVO.LaneVO();
Integer sort = laneInfoPO.getSort();
laneVO.setLaneSort(sort);
res.add(laneVO);
}
}
return res;
}
private List<RunningEvaluateSchemeProblemsVO.DateAndScheme> buildDateAndSchemeList(
List<CrossDataHistPO> uniqueList, String crossId) {
List<RunningEvaluateSchemeProblemsVO.DateAndScheme> res = new ArrayList<>();
// 将问题按日期分组
Map<LocalDate, List<CrossDataHistPO>> groupedByDate = uniqueList.stream()
.collect(Collectors.groupingBy(
// 将10位时间戳转换为Instant
crossDataHistPO -> Instant.ofEpochSecond(crossDataHistPO.getBatchTime())
.atZone(ZoneId.systemDefault()) // 将Instant转换为系统默认时区的ZonedDateTime
.toLocalDate() // 获取LocalDate
));
for (Map.Entry<LocalDate, List<CrossDataHistPO>> entry : groupedByDate.entrySet()) {
LocalDate localDate = entry.getKey(); // 获取日期
List<CrossDataHistPO> crossDataHistPOs = entry.getValue(); // 获取该日期下的CrossDataHistPO对象列表
RunningEvaluateSchemeProblemsVO.DateAndScheme dateAndScheme =
new RunningEvaluateSchemeProblemsVO.DateAndScheme();
Date date = Date.from(localDate.atStartOfDay()
.atZone(ZoneId.systemDefault())
.toInstant());
dateAndScheme.setProblemDate(date);
Set<String> schemeNameSet = new HashSet<>();
for (CrossDataHistPO abnormalEvent : crossDataHistPOs) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
Date abnormalEventStartTime = abnormalEvent.getStartTime();
Integer duration = abnormalEvent.getDuration();
Date abnormalEventEndTime = DateUtil.offsetMinute(abnormalEventStartTime, duration);
String eventStartTime = sdf.format(abnormalEventStartTime);
String eventEndTime = sdf.format(abnormalEventEndTime);
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
Date datetime = new Date();
String dateStr = sdf2.format(datetime);
// 获取当前计划ID
Integer planId = findPlanId(datetime, dateStr, crossId);
List<CrossSectionPO> crossSectionPOList = baseCrossSectionMapper.selectByCrossAndPlan(crossId, planId);
for (CrossSectionPO crossSectionPO : crossSectionPOList) {
String sectionStartTime = crossSectionPO.getStartTime();
String sectionEndTime = crossSectionPO.getEndTime();
// 比较两组时间段是否相交
boolean isIntersecting = isTimeIntersecting(
eventStartTime, eventEndTime, sectionStartTime, sectionEndTime);
if (isIntersecting) {
Integer schemeId = crossSectionPO.getSchemeId();
BaseCrossSchemePO baseCrossSchemePO = baseCrossSchemeMapper.selectById(schemeId);
schemeNameSet.add(baseCrossSchemePO.getName());
dateAndScheme.setSchemeNameSet(schemeNameSet);
}
}
}
res.add(dateAndScheme);
}
return res;
}
@NotNull
private List<RunningEvaluateIndexStatusVO> buildRes(CrossIdAndStartEndDateBO bo, String crossId, int status) {
List<CrossDataHistPO> crossDataHistPOList = buildCrossDataHistPOList(bo, crossId);
List<RunningEvaluateIndexStatusVO> res = buildRunningEvaluateIndexStatusVOList(crossDataHistPOList, status);
return res;
}
@NotNull
private List<RunningEvaluateIndexStatusVO> buildRunningEvaluateIndexStatusVOList(
List<CrossDataHistPO> crossDataHistPOList, int status) {
Map<String, List<CrossDataHistPO>> timePOMap = buildTimePOMap(crossDataHistPOList);
// 构造结果集
List<RunningEvaluateIndexStatusVO> res = new ArrayList<>();
List<String> timeArray = TimeArrayUtil.getHourArray();
for (String time : timeArray) {
RunningEvaluateIndexStatusVO vo = new RunningEvaluateIndexStatusVO();
vo.setTime(time);
List<CrossDataHistPO> subList = timePOMap.get(time.substring(0, 2)); // 保留小时字符串
if (subList != null) {
Double avgCongestionIndex = calcAvgIndex(subList, status);
vo.setIndex(avgCongestionIndex);
}
res.add(vo);
}
return res;
}
private Double calcAvgIndex(List<CrossDataHistPO> subList, int status) {
Double average = 0.0;
if (status == CrossStatusEnum.CONGESTION.getCode()) {
average = subList.stream()
.mapToDouble(CrossDataHistPO::getCongestionIndex)
.average()
.orElse(0.0);
} else if (status == CrossStatusEnum.UNBALANCE.getCode()) {
average = subList.stream()
.mapToDouble(CrossDataHistPO::getUnbalanceIndex)
.average()
.orElse(0.0);
} else if (status == CrossStatusEnum.SPILLOVER.getCode()) {
average = subList.stream()
.mapToDouble(CrossDataHistPO::getSpilloverIndex)
.average()
.orElse(0.0);
}
DecimalFormat df = new DecimalFormat("#.00");
String formattedAverage = df.format(average);
return Double.parseDouble(formattedAverage);
}
private Integer calcSchemeProblems(List<CrossDataHistPO> congestionEventList,
List<CrossDataHistPO> unbalanceEventList,
List<CrossDataHistPO> spilloverEventList,
String crossId) {
Set<Integer> schemeIdSet = new HashSet<>(); // 用于方案ID去重
List<CrossDataHistPO> allList = Stream.of(congestionEventList, unbalanceEventList, spilloverEventList)
.flatMap(List::stream)
.collect(Collectors.toList());
for (CrossDataHistPO abnormalEvent : allList) {
Date abnormalEventStartTime = abnormalEvent.getStartTime();
Integer duration = abnormalEvent.getDuration();
Date abnormalEventEndTime = DateUtil.offsetMinute(abnormalEventStartTime, duration);
String eventStartTime = HOUR_SDF.format(abnormalEventStartTime);
String eventEndTime = HOUR_SDF.format(abnormalEventEndTime);
Date datetime = new Date();
String dateStr = DAY_SDF.format(datetime);
// 获取当前计划ID
Integer planId = findPlanId(datetime, dateStr, crossId);
List<CrossSectionPO> crossSectionPOList = baseCrossSectionMapper.selectByCrossAndPlan(crossId, planId);
for (CrossSectionPO crossSectionPO : crossSectionPOList) {
String sectionStartTime = crossSectionPO.getStartTime();
String sectionEndTime = crossSectionPO.getEndTime();
// 比较两组时间段是否相交
boolean isIntersecting = isTimeIntersecting(
eventStartTime, eventEndTime, sectionStartTime, sectionEndTime);
if (isIntersecting) {
Integer schemeId = crossSectionPO.getSchemeId();
schemeIdSet.add(schemeId);
}
}
}
return schemeIdSet.size();
}
Integer findPlanId(Date datetime, String dateStr, String crossId) {
CrossIdBO crossIdBO = new CrossIdBO();
crossIdBO.setCrossId(crossId);
RunningPlanDTO runningPlanDTO = listRunningPlan(crossIdBO);
List<RunningPlanDTO.SchedulesPlanListElement> schedulesPlanList = runningPlanDTO.getSchedulesPlanList();
for (RunningPlanDTO.SchedulesPlanListElement schedulesPlan : schedulesPlanList) {
List<RunningPlanDTO.ExecListElement> execList = schedulesPlan.getExecList();
for (RunningPlanDTO.ExecListElement execListElement : execList) {
// 先查询特殊日期,再查询星期
List<String> specialDateList = execListElement.getSpecialDateList();
List<Integer> week = execListElement.getWeek();
if (CollectionUtil.isNotEmpty(specialDateList)) {
for (String specialDate : specialDateList) {
String substring = specialDate.substring(0, 10);
if (Objects.equals(dateStr, substring)) {
Integer planId = execListElement.getPlanId();
return planId;
}
}
}
if (CollectionUtil.isNotEmpty(week)) {
for (Integer day : week) {
// 1表示周日,2表示周一
int today = DateUtil.dayOfWeek(datetime);
today -= 1;
if (today == 0) {
today = 7;
}
if (day == today) {
Integer planId = execListElement.getPlanId();
return planId;
}
}
}
}
}
return null;
}
public RunningPlanDTO listRunningPlan(CrossIdBO crossIdBO) {
RunningPlanDTO runningPlanDTO = new RunningPlanDTO();
String crossId = crossIdBO.getCrossId();
runningPlanDTO.setCrossId(crossId);
// 构造dailyPlanList
List<RunningPlanDTO.DailyPlanListElement> dailyPlanList = buildDailyPlanList(crossId);
runningPlanDTO.setDailyPlanList(dailyPlanList);
// 构造schedulesPlanList
List<RunningPlanDTO.SchedulesPlanListElement> schedulesPlanList = buildSchedulesPlanList(crossId);
runningPlanDTO.setSchedulesPlanList(schedulesPlanList);
return runningPlanDTO;
}
private List<RunningPlanDTO.DailyPlanListElement> buildDailyPlanList(String crossId) {
List<RunningPlanDTO.DailyPlanListElement> dailyPlanList = new ArrayList<>();
dailyPlanList = baseCrossPlanMapper.selectDailyPlanList(crossId);
if (CollectionUtil.isEmpty(dailyPlanList)) {
List<BaseCrossPlanPO> crossPlanPOList = baseCrossPlanMapper.selectByCrossId(crossId);
if (CollectionUtil.isNotEmpty(crossPlanPOList)) {
for (BaseCrossPlanPO baseCrossPlanPO : crossPlanPOList) {
RunningPlanDTO.DailyPlanListElement dailyPlan = new RunningPlanDTO.DailyPlanListElement();
dailyPlan.setPlanNo(baseCrossPlanPO.getPlanNo());
dailyPlan.setName(baseCrossPlanPO.getName());
dailyPlan.setTimeList(new ArrayList<>());
dailyPlanList.add(dailyPlan);
}
}
} else {
for (RunningPlanDTO.DailyPlanListElement dailyPlan : dailyPlanList) {
List<RunningPlanDTO.TimeListElement> timeList = dailyPlan.getTimeList();
for (RunningPlanDTO.TimeListElement timeListElement : timeList) {
String[] startEndTime = new String[2];
String startTime = timeListElement.getStartTime();
String endTime = timeListElement.getEndTime();
startEndTime[0] = startTime;
startEndTime[1] = endTime;
timeListElement.setStartEndTime(startEndTime);
}
}
}
return dailyPlanList;
}
private List<RunningPlanDTO.SchedulesPlanListElement> buildSchedulesPlanList(String crossId) {
List<RunningPlanDTO.SchedulesPlanListElement> schedulesPlanList = new ArrayList<>();
List<BaseCrossSchedulesPO> baseCrossSchedulesPOList = baseCrossSchedulesMapper.selectByCrossId(crossId);
for (BaseCrossSchedulesPO baseCrossSchedulesPO : baseCrossSchedulesPOList) {
String scheduleNo = baseCrossSchedulesPO.getScheduleNo();
String name = baseCrossSchedulesPO.getName();
Integer crossSchedulesPOId = baseCrossSchedulesPO.getId();
RunningPlanDTO.SchedulesPlanListElement schedulesPlan = new RunningPlanDTO.SchedulesPlanListElement();
schedulesPlan.setScheduleNo(scheduleNo);
schedulesPlan.setName(name);
schedulesPlan.setId(crossSchedulesPOId);
schedulesPlan.setStatus(baseCrossSchedulesPO.getStatus());
// 构造execList
List<RunningPlanDTO.ExecListElement> execList = buildExecList(crossId, scheduleNo);
schedulesPlan.setExecList(execList);
schedulesPlanList.add(schedulesPlan);
}
return schedulesPlanList;
}
private List<RunningPlanDTO.ExecListElement> buildExecList(String crossId, String scheduleNo) {
List<RunningPlanDTO.ExecListElement> execList = new ArrayList<>();
// 获取调度ID
BaseCrossSchedulesPO schedulesPO = baseCrossSchedulesMapper.selectByCrossIdAndScheduleNo(crossId, scheduleNo);
Integer schedulesId = schedulesPO.getId();
// 根据路口ID、调度ID和计划ID查询调度计划关系
List<BaseCrossSchedulesPlanPO> baseCrossSchedulesPlanPOList =
baseCrossSchedulesPlanMapper.selectByCrossIdAndSchedulesId(crossId, schedulesId);
Map<Integer, List<BaseCrossSchedulesPlanPO>> collectMap = baseCrossSchedulesPlanPOList.stream()
.collect(Collectors.groupingBy(BaseCrossSchedulesPlanPO::getPlanId));
for (Map.Entry<Integer, List<BaseCrossSchedulesPlanPO>> entry : collectMap.entrySet()) {
RunningPlanDTO.ExecListElement execListElement = new RunningPlanDTO.ExecListElement();
List<Integer> week = new ArrayList<>();
List<String> specialDateList = new ArrayList<>();
Integer planId = entry.getKey();
List<BaseCrossSchedulesPlanPO> secondList = entry.getValue();
for (BaseCrossSchedulesPlanPO baseCrossSchedulesPlanPO : secondList) {
Integer day = baseCrossSchedulesPlanPO.getWeek();
if (day == 0) { // 特殊日期
Date specialDate = baseCrossSchedulesPlanPO.getSpecialDate();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
specialDateList.add(sdf.format(specialDate));
} else {
week.add(day);
}
}
execListElement.setWeek(week);
execListElement.setSpecialDateList(specialDateList);
BaseCrossPlanPO baseCrossPlanPO = baseCrossPlanMapper.selectById(planId);
execListElement.setPlanName(baseCrossPlanPO.getName());
execListElement.setPlanId(baseCrossPlanPO.getId());
execList.add(execListElement);
}
return execList;
}
boolean isTimeIntersecting(String startTime1, String endTime1, String startTime2, String endTime2) {
return !(endTime1.compareTo(startTime2) <= 0 || startTime1.compareTo(endTime2) >= 0);
}
private List<CrossDataHistPO> buildSpilloverEvents(List<CrossDataHistPO> crossDataHistPOList) {
return buildEvents(crossDataHistPOList, CrossStatusEnum.SPILLOVER.getCode());
}
private List<CrossDataHistPO> buildUnbalanceEvents(List<CrossDataHistPO> crossDataHistPOList) {
return buildEvents(crossDataHistPOList, CrossStatusEnum.UNBALANCE.getCode());
}
private List<CrossDataHistPO> buildCongestionEvents(List<CrossDataHistPO> crossDataHistPOList) {
return buildEvents(crossDataHistPOList, CrossStatusEnum.CONGESTION.getCode());
}
private List<CrossDataHistPO> buildEvents(List<CrossDataHistPO> crossDataHistPOList, int status) {
List<CrossDataHistPO> collect = crossDataHistPOList.stream()
.filter(po -> po.getStatus() == status)
.collect(Collectors.groupingBy(
CrossDataHistPO::getStartTime,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingInt(CrossDataHistPO::getDuration)),
Optional::get
)
))
.values()
.stream()
.collect(Collectors.toList());
return collect;
}
}
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 lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.CrossStatusEnum;
import net.wanji.common.enums.StrategyAndMetricsEnum;
import net.wanji.common.enums.TurnConvertEnum;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.common.utils.tool.TimeArrayUtil;
import net.wanji.databus.bo.CrossIdAndStartEndDateBO;
import net.wanji.databus.bo.HeatMapBO;
import net.wanji.databus.dao.entity.BaseCrossSchemePO;
import net.wanji.databus.dao.entity.CrossSectionPO;
import net.wanji.databus.dao.mapper.*;
import net.wanji.databus.dto.MetricHistDTO;
import net.wanji.databus.po.*;
import net.wanji.feign.service.ControlFeignClients;
import net.wanji.opt.bo.AbnormalDetailBO;
import net.wanji.opt.bo.MetricsTurnAndLaneBO;
import net.wanji.opt.bo.SceneMetricsDetailBO;
import net.wanji.opt.service.SceneEvaluateService;
import net.wanji.opt.vo.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author Kent HAN
* @date 2023/8/28 16:38
*/
@Slf4j
@Service
public class SceneEvaluateServiceImpl implements SceneEvaluateService {
private final CrossDataHistMapper crossDataHistMapper;
private final RunningEvaluateServiceImpl runningEvaluateService;
private final BaseCrossSchemeMapper baseCrossSchemeMapper;
private final BaseCrossSchedulesMapper baseCrossSchedulesMapper;
private final BaseCrossSchedulesPlanMapper baseCrossSchedulesPlanMapper;
private final ControlFeignClients controlFeignClients;
private final BaseCrossSectionMapper baseCrossSectionMapper;
private final CrossDirDataHistMapper crossDirDataHistMapper;
private final CrossLaneDataHistMapper crossLaneDataHistMapper;
private final CrossTurnDataHistMapper crossTurnDataHistMapper;
private final LaneInfoMapper laneInfoMapper;
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, CrossLaneDataHistMapper crossLaneDataHistMapper, CrossTurnDataHistMapper crossTurnDataHistMapper, @Qualifier("laneInfoMapper") LaneInfoMapper laneInfoMapper) {
this.crossDataHistMapper = crossDataHistMapper;
this.runningEvaluateService = runningEvaluateService;
this.baseCrossSchemeMapper = baseCrossSchemeMapper;
this.baseCrossSchedulesMapper = baseCrossSchedulesMapper;
this.baseCrossSchedulesPlanMapper = baseCrossSchedulesPlanMapper;
this.controlFeignClients = controlFeignClients;
this.baseCrossSectionMapper = baseCrossSectionMapper;
this.crossDirDataHistMapper = crossDirDataHistMapper;
this.crossLaneDataHistMapper = crossLaneDataHistMapper;
this.crossTurnDataHistMapper = crossTurnDataHistMapper;
this.laneInfoMapper = laneInfoMapper;
}
@Override
public SceneEvaluateAbnormalDistributeVO abnormalDistribute(CrossIdAndStartEndDateBO bo) {
String crossId = bo.getCrossId();
Date startDate = bo.getStartDate();
Date endDate = bo.getEndDate();
SceneEvaluateAbnormalDistributeVO vo = new SceneEvaluateAbnormalDistributeVO();
List<SceneEvaluateAbnormalDistributeVO.TimeDistribution> timeDistributionList =
buildTimeDistributionList(crossId, startDate, endDate);
vo.setTimeDateDistributionList(buildTimeDateDistributionList(timeDistributionList));
setCounts(timeDistributionList, vo);
return vo;
}
@Override
public SceneEvaluateAbnormalDetailVO abnormalDetail(AbnormalDetailBO abnormalDetailBO) throws ParseException {
String crossId = abnormalDetailBO.getCrossId();
String hourMinute = abnormalDetailBO.getHourMinute();
Date problemDate = abnormalDetailBO.getProblemDate();
Integer status = abnormalDetailBO.getStatus();
// 获取当前年份
Calendar calendar = Calendar.getInstance();
int currentYear = calendar.get(Calendar.YEAR);
// 设置 problemDate 的年份为当前年份
calendar.setTime(problemDate);
calendar.set(Calendar.YEAR, currentYear);
Date newDate = calendar.getTime();
calendar.setTime(newDate);
// 设置时间为当天开始时间(00:00:00)
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
int startOfDayTimestamp = (int) (calendar.getTimeInMillis() / 1000);
// 设置时间为当天结束时间(23:59:59)
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
int endOfDayTimestamp = (int) (calendar.getTimeInMillis() / 1000);
// 查询当天所有场景
List<CrossDataHistPO> crossDataHistPOList =
crossDataHistMapper.selectByCrossIdAndStartEnd(crossId, startOfDayTimestamp, endOfDayTimestamp);
// 按照startTime分组并选择duration最长的一个。
List<CrossDataHistPO> filteredList = crossDataHistPOList.stream()
.filter(po -> Objects.equals(po.getStatus(), status))
.collect(Collectors.groupingBy(CrossDataHistPO::getStartTime))
.values().stream()
.map(list -> list.stream().max(Comparator.comparingInt(CrossDataHistPO::getDuration)).get())
.collect(Collectors.toList());
// 进行startTime和endTime的格式化和分组。
Map<String, List<CrossDataHistPO>> groupedData = filteredList.stream()
.collect(Collectors.groupingBy(po -> {
// 计算startTime和endTime
Date startTime = po.getStartTime();
Date endTime = new Date(startTime.getTime() + po.getDuration() * 60 * 1000L);
// startTime向前取整至5分钟
calendar.setTime(startTime);
int minute = calendar.get(Calendar.MINUTE);
calendar.add(Calendar.MINUTE, -(minute % 5));
String startTimeStr = HOUR_SDF.format(calendar.getTime());
// endTime向后取整至5分钟
calendar.setTime(endTime);
minute = calendar.get(Calendar.MINUTE);
calendar.add(Calendar.MINUTE, 5 - (minute % 5));
String endTimeStr = HOUR_SDF.format(calendar.getTime());
return startTimeStr + "-" + endTimeStr;
}));
Date targetDate = HOUR_SDF.parse(hourMinute);
// 获取当前年份,并设置targetDate的年份
Calendar cal = Calendar.getInstance();
cal.setTime(newDate);
String[] split = hourMinute.split(":");
cal.set(Calendar.HOUR, Integer.parseInt(split[0]));
cal.set(Calendar.MINUTE, Integer.parseInt(split[1]));
targetDate = cal.getTime();
// 从groupedData中筛选与hourMinute相交的记录
List<CrossDataHistPO> intersectingRecords = new ArrayList<>();
for (Map.Entry<String, List<CrossDataHistPO>> entry : groupedData.entrySet()) {
String key = entry.getKey();
String[] times = key.split("-");
Calendar startCal = Calendar.getInstance();
Calendar endCal = Calendar.getInstance();
startCal.setTime(newDate);
endCal.setTime(newDate);
String[] start = times[0].split(":");
startCal.set(Calendar.HOUR, Integer.parseInt(start[0]));
startCal.set(Calendar.MINUTE, Integer.parseInt(start[1]));
String[] end = times[1].split(":");
endCal.set(Calendar.HOUR, Integer.parseInt(end[0]));
endCal.set(Calendar.MINUTE, Integer.parseInt(end[1]));
Date startTime = startCal.getTime();
Date endTime = endCal.getTime();
// 检查相交条件
if (!(targetDate.before(startTime) || targetDate.after(endTime))) {
intersectingRecords.addAll(entry.getValue());
}
}
if (ObjectUtil.isEmpty(intersectingRecords)) {
throw new RuntimeException("该时段无异常事件");
}
CrossDataHistPO crossDataHistPO = intersectingRecords.get(0);
SceneEvaluateAbnormalDetailVO vo = new SceneEvaluateAbnormalDetailVO();
vo.setStatus(status);
Date startTime = crossDataHistPO.getStartTime();
Integer duration = crossDataHistPO.getDuration();
// 计算startTime加上duration后的时间
cal.setTime(startTime);
Integer timeSpan = duration - 1;
cal.add(Calendar.MINUTE, timeSpan);
Date newEndTime = cal.getTime();
List<CrossDataHistPO> sceneCrossDataHistPOList = getCrossDataHistPOList(startTime, newEndTime, crossId);
vo.setStartTime(startTime);
vo.setTimeline(getTimeline(startTime, newEndTime));
// 只有拥堵显示
if (Objects.equals(status, CrossStatusEnum.CONGESTION.getCode())) {
Integer delayTime = calcCrossDelayTime(sceneCrossDataHistPOList);
Integer level = calcCongestionLevel(delayTime);
vo.setLevel(level);
}
vo.setDuration(duration);
if (Objects.equals(status, CrossStatusEnum.CONGESTION.getCode())) {
String congestionDirs = crossDataHistPO.getCongestionDirs();
vo.setDirs(buildDirs(congestionDirs));
} else if (Objects.equals(status, CrossStatusEnum.UNBALANCE.getCode())) {
String unbalanceDirs = crossDataHistPO.getUnbalanceDirs();
vo.setDirs(buildDirs(unbalanceDirs));
} else if (Objects.equals(status, CrossStatusEnum.SPILLOVER.getCode())) {
String spilloverDirs = crossDataHistPO.getSpilloverDirs();
vo.setDirs(buildDirs(spilloverDirs));
}
// 查找当前路口全部方案
List<BaseCrossSchemePO> baseCrossSchemePOList = baseCrossSchemeMapper.selectByCrossId(crossId);
// 找出当前计划
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String startDay = sdf.format(startTime);
Integer planId = controlFeignClients.findPlanId(startTime, startDay, crossId);
if (ObjectUtil.isEmpty(planId)) {
throw new RuntimeException("当前时段无正在运行的计划");
}
// 获取时段信息
List<CrossSectionPO> crossSectionPOList = baseCrossSectionMapper.selectByCrossAndPlan(crossId, planId);
// 根据 startTime 和 duration 查找相交的方案
// 将Date转换为"HH:mm"字符串
String newStartTimeStr = HOUR_SDF.format(startTime);
String newEndTimeStr = HOUR_SDF.format(newEndTime);
List<CrossSectionPO> intersectingSections = crossSectionPOList.stream()
.filter(po -> !(po.getEndTime().compareTo(newStartTimeStr) < 0
|| po.getStartTime().compareTo(newEndTimeStr) > 0))
.collect(Collectors.toList());
// 筛选baseCrossSchemePOList,找出id与intersectingSections中的schemeId相等的记录
List<BaseCrossSchemePO> matchedSchemes = baseCrossSchemePOList.stream()
.filter(baseScheme -> intersectingSections.stream()
.anyMatch(section -> section.getSchemeId().equals(baseScheme.getId())))
.collect(Collectors.toList());
vo.setPatternNames(buildPatternNames(matchedSchemes));
Double sturation = calcCrossSaturation(sceneCrossDataHistPOList);
String serviceLevel = CrossUtil.getServiceLevel(sturation);
vo.setServiceLevel(serviceLevel);
vo.setFlow(calcCrossFlow(sceneCrossDataHistPOList));
if (Objects.equals(status, CrossStatusEnum.CONGESTION.getCode())) {
vo.setOverallMetricsList(buildCrossCongestionMetrics(
crossId, startTime, newEndTime, sceneCrossDataHistPOList));
} else if (Objects.equals(status, CrossStatusEnum.UNBALANCE.getCode())) {
vo.setOverallMetricsList(buildCrossUnbalanceMetrics(crossId, startTime, newEndTime, sceneCrossDataHistPOList));
} else if (Objects.equals(status, CrossStatusEnum.SPILLOVER.getCode())) {
vo.setOverallMetricsList(buildCrossSpilloverMetrics(sceneCrossDataHistPOList));
}
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)) {
// 获取车道ID
Integer turnInt = TurnConvertEnum.getKeyByCode(turn);
String laneId = laneInfoMapper.selectIdByCrossIdDirTurn2(crossId, dir, turnInt);
metricHistDTOList = crossLaneDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp, laneId);
} else if (ObjectUtil.isNotEmpty(turn)) {
metricHistDTOList = crossTurnDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp, dir, turn);
} else if (ObjectUtil.isNotEmpty(dir)) {
metricHistDTOList = crossDirDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp, dir);
} else { // 路口级别
metricHistDTOList = crossDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
}
// 更新空放次数
metricHistDTOList.forEach(metricHistDTO -> {
if (metricHistDTO.getGreenLightEfficiency() != null && metricHistDTO.getGreenLightEfficiency() >0 && 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;
}
@Override
public SceneEvaluateMetricsTurnVO metricsTurn(MetricsTurnAndLaneBO bo) throws ParseException {
Integer status = bo.getStatus();
String crossId = bo.getCrossId();
Integer dir = bo.getDir();
Date day = bo.getDay();
String hourMinute = bo.getHourMinute();
// 构造开始时间结束时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String todayDateString = sdf.format(day); // Get today's date
String startTimeString = todayDateString + " " + hourMinute + ":00";
Date startTime = dateTimeFormatter.parse(startTimeString);
Calendar cal = Calendar.getInstance();
cal.setTime(startTime);
cal.add(Calendar.MINUTE, 4);
cal.add(Calendar.SECOND, 59);
Date endTime = cal.getTime();
int startTimeStamp = (int) (startTime.getTime() / 1000);
int endTimeStamp = (int) (endTime.getTime() / 1000);
// 查询该时段内转向级别数据
List<CrossTurnDataHistPO> crossTurnDataHistPOList =
crossTurnDataHistMapper.selectByCrossIdAndDir(crossId, dir, endTimeStamp, startTimeStamp);
Map<String, List<CrossTurnDataHistPO>> groupedByTurn = crossTurnDataHistPOList.stream()
.collect(Collectors.groupingBy(CrossTurnDataHistPO::getTurnType));
SceneEvaluateMetricsTurnVO res = new SceneEvaluateMetricsTurnVO();
// 获取延误
double v = crossTurnDataHistPOList.stream()
.mapToInt(CrossTurnDataHistPO::getDelayTime)
.average()
.orElse(0);
Integer delayTime = (int)v;
Integer level = calcCongestionLevel(delayTime);
res.setLevel(level);
List<SceneEvaluateMetricsTurnVO.TurnListElement> elementList = new ArrayList<>();
for (Map.Entry<String, List<CrossTurnDataHistPO>> entry : groupedByTurn.entrySet()) {
SceneEvaluateMetricsTurnVO.TurnListElement element = buildTurnListElement(entry, status);
elementList.add(element);
}
res.setTurnList(elementList);
return res;
}
@Override
public SceneEvaluateMetricsLaneVO metricsLane(MetricsTurnAndLaneBO bo) throws ParseException {
Integer status = bo.getStatus();
String crossId = bo.getCrossId();
Integer dir = bo.getDir();
Date day = bo.getDay();
String hourMinute = bo.getHourMinute();
// 构造开始时间结束时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat dateTimeFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String todayDateString = sdf.format(day); // Get today's date
String startTimeString = todayDateString + " " + hourMinute + ":00";
Date startTime = dateTimeFormatter.parse(startTimeString);
Calendar cal = Calendar.getInstance();
cal.setTime(startTime);
cal.add(Calendar.MINUTE, 4);
cal.add(Calendar.SECOND, 59);
Date endTime = cal.getTime();
int startTimeStamp = (int) (startTime.getTime() / 1000);
int endTimeStamp = (int) (endTime.getTime() / 1000);
// 查询该时段内车道级别数据
List<CrossLaneDataHistPOExt> poExtList =
crossLaneDataHistMapper.selectByCrossIdAndDir(crossId, dir, endTimeStamp, startTimeStamp);
//poExtList.forEach(o->o.setGreenLightEfficiency(o.getGreenLightEfficiency()<0.0?0.0:o.getGreenLightEfficiency()));
Map<Integer, List<CrossLaneDataHistPOExt>> groupedBySort = poExtList.stream()
.collect(Collectors.groupingBy(CrossLaneDataHistPOExt::getSort));
SceneEvaluateMetricsLaneVO res = new SceneEvaluateMetricsLaneVO();
// 获取延误
double v = poExtList.stream()
.mapToInt(CrossLaneDataHistPOExt::getDelayTime)
.average()
.orElse(0);
Integer delayTime = (int)v;
Integer level = calcCongestionLevel(delayTime);
res.setLevel(level);
List<SceneEvaluateMetricsLaneVO.LaneListElement> elementList = new ArrayList<>();
for (Map.Entry<Integer, List<CrossLaneDataHistPOExt>> entry : groupedBySort.entrySet()) {
SceneEvaluateMetricsLaneVO.LaneListElement element = buildLaneListElement(entry, status);
elementList.add(element);
}
res.setLaneList(elementList);
return res;
}
@Override
public List<SceneEvaluateHeatMapVO> heatMap(HeatMapBO bo) {
String crossId = bo.getCrossId();
Date startDate = bo.getStartDate();
String hourMinute = bo.getHourMinute();
Integer status = bo.getStatus();
String[] parts = hourMinute.split(":");
int hour = Integer.parseInt(parts[0]);
int minute = Integer.parseInt(parts[1]);
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
int startStamp = (int)(calendar.getTimeInMillis() / 1000);
calendar.add(Calendar.MINUTE, 4);
int endStamp = (int)(calendar.getTimeInMillis() / 1000);
List<SceneEvaluateHeatMapVO> res = new ArrayList<>();
List<CrossDataHistPO> crossDataHistPOList = crossDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startStamp, endStamp);
// 根据 status 值选择分组字段
Function<CrossDataHistPO, String> groupByField;
switch (status) {
case 1:
groupByField = CrossDataHistPO::getUnbalanceDirs;
break;
case 2:
groupByField = CrossDataHistPO::getCongestionDirs;
break;
case 3:
groupByField = CrossDataHistPO::getSpilloverDirs;
break;
default:
throw new IllegalArgumentException("状态值非法");
}
// 过滤 status 字段值为 status 变量的对象,并按照方向分组
Map<String, List<CrossDataHistPO>> grouped = crossDataHistPOList.stream()
.flatMap(po -> {
String dirs = "";
if (status == 1) {
dirs = po.getUnbalanceDirs();
} else if (status == 2) {
dirs = po.getCongestionDirs();
} else if (status == 3) {
dirs = po.getSpilloverDirs();
}
return Arrays.stream(dirs.split(","))
.map(dir -> new AbstractMap.SimpleEntry<>(dir, po));
})
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())
));
// 对每个组进行处理,仅保留 start_time 相同的记录中 duration 最大的一条
Map<String, List<CrossDataHistPO>> filteredGrouped = grouped.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
.collect(Collectors.groupingBy(CrossDataHistPO::getStartTime))
.values().stream()
.map(list -> list.stream().max(Comparator.comparingInt(CrossDataHistPO::getDuration))
.orElse(null))
.collect(Collectors.toList())
));
// 遍历 filteredGrouped,提取每个 key 和与该 key 关联的列表的元素个数
filteredGrouped.forEach((key, list) -> {
SceneEvaluateHeatMapVO sceneEvaluateHeatMapVO = new SceneEvaluateHeatMapVO();
if (ObjectUtil.isNotEmpty(key)) {
sceneEvaluateHeatMapVO.setDir(Integer.parseInt(key));
if (!status.equals(CrossStatusEnum.CONGESTION.getCode())) {
if (list.isEmpty()) {
sceneEvaluateHeatMapVO.setIsUnbalanceOrSpillOver(0);
} else {
sceneEvaluateHeatMapVO.setIsUnbalanceOrSpillOver(1);
}
} else {
Integer delayTime = calcCrossDelayTime(list);
Integer level = calcCongestionLevel(delayTime);
sceneEvaluateHeatMapVO.setLevel(level);
}
sceneEvaluateHeatMapVO.setStatus(status);
res.add(sceneEvaluateHeatMapVO);
}
});
return res;
}
private SceneEvaluateMetricsLaneVO.LaneListElement buildLaneListElement(
Map.Entry<Integer, List<CrossLaneDataHistPOExt>> entry, Integer status) {
SceneEvaluateMetricsLaneVO.LaneListElement element = new SceneEvaluateMetricsLaneVO.LaneListElement();
Integer sort = entry.getKey();
element.setSort(sort);
List<CrossLaneDataHistPOExt> poExtList = entry.getValue();
// 获取流量
int totalFlow = poExtList.stream()
.filter(Objects::nonNull)
.mapToInt(CrossLaneDataHistPOExt::getFlow)
.sum();
int averageFlow = 0;
element.setFlow(totalFlow);
// 动态指标
element.setMetricsMap(buildLaneMetricMap(poExtList, status));
return element;
}
private Map<String, Integer> buildLaneMetricMap(List<CrossLaneDataHistPOExt> poExtList, Integer status) {
Map<String, Integer> res = new HashMap<>();
if (Objects.equals(status, CrossStatusEnum.CONGESTION.getCode())) {
buildLaneCongestionRes(res, poExtList);
} else if (Objects.equals(status, CrossStatusEnum.UNBALANCE.getCode())) {
buildLaneUnbalanceRes(res, poExtList);
} else if (Objects.equals(status, CrossStatusEnum.SPILLOVER.getCode())) {
buildLaneSpilloverRes(res, poExtList);
}
return res;
}
private void buildLaneSpilloverRes(Map<String, Integer> res, List<CrossLaneDataHistPOExt> poExtList) {
// 最大排队长度
double maxQueueLength = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getQueueLength)
.max()
.orElse(0.0);
int maxQueueLengthInt = (int) (Math.round(maxQueueLength));
res.put(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getCode(), maxQueueLengthInt);
// 平均延误
double maxDelayTime = poExtList.stream()
.mapToInt(CrossLaneDataHistPOExt::getDelayTime)
.average()
.orElse(0.0);
int maxDelayTimeInt = (int) (Math.round(maxDelayTime));
res.put(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getCode(), maxDelayTimeInt);
// 停车次数
double maxStopTimes = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getStopTimes)
.average()
.orElse(0.0);
int maxStopTimesInt = (int) (Math.round(maxStopTimes));
res.put(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getCode(), maxStopTimesInt);
// 溢流率
double maxEffusionRate = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getEffusionRate)
.average()
.orElse(0.0);
int maxEffusionRateInt = (int) (Math.round(maxEffusionRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getCode(), maxEffusionRateInt);
}
private void buildLaneUnbalanceRes(Map<String, Integer> res, List<CrossLaneDataHistPOExt> poExtList) {
// 不停车通过率
double maxNoStopRate = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getNoStopRate)
.average()
.orElse(0.0);
int maxNoStopRateInt = (int) (Math.round(maxNoStopRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getCode(), maxNoStopRateInt);
// N次停车通过率
double maxOneStopRate = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getOneStopRate)
.average()
.orElse(0.0);
int maxOneStopRateInt = (int) (Math.round(maxOneStopRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.STOP_RATE.getCode(), maxOneStopRateInt);
// 空放次数-绿灯有效利用率小于80%
long emptyDischarges = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getGreenLightEfficiency)
.filter(efficiency -> efficiency < 0.8)
.count();
res.put(StrategyAndMetricsEnum.Metrics.EMPTY_DISCHARGES.getCode(), (int)emptyDischarges);
// 绿灯有效利用率
double maxGreenLightEfficiency = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getGreenLightEfficiency)
.average()
.orElse(0.0);
int maxGreenLightEfficiencyInt = (int) (Math.round(maxGreenLightEfficiency * 100));
res.put(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getCode(), maxGreenLightEfficiencyInt);
}
private void buildLaneCongestionRes(Map<String, Integer> res, List<CrossLaneDataHistPOExt> poExtList) {
// N次停车通过率
double maxOneStopRate = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getOneStopRate)
.average()
.orElse(0.0);
int maxOneStopRateInt = (int) (Math.round(maxOneStopRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.STOP_RATE.getCode(), maxOneStopRateInt);
// 平均速度
double maxSpeed = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getSpeed)
.average()
.orElse(0.0);
int maxSpeedInt = (int) (Math.round(maxSpeed));
res.put(StrategyAndMetricsEnum.Metrics.AVERAGE_SPEED.getCode(), maxSpeedInt);
// 平均延误
double maxDelayTime = poExtList.stream()
.mapToInt(CrossLaneDataHistPOExt::getDelayTime)
.average()
.orElse(0.0);
int maxDelayTimeInt = (int) (Math.round(maxDelayTime));
res.put(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getCode(), maxDelayTimeInt);
// 停车次数
double maxStopTimes = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getStopTimes)
.average()
.orElse(0.0);
int maxStopTimesInt = (int) (Math.round(maxStopTimes));
res.put(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getCode(), maxStopTimesInt);
// 最大排队长度
double maxQueueLength = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getQueueLength)
.max()
.orElse(0.0);
int maxQueueLengthInt = (int) (Math.round(maxQueueLength));
res.put(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getCode(), maxQueueLengthInt);
// 溢流率
double maxEffusionRate = poExtList.stream()
.mapToDouble(CrossLaneDataHistPOExt::getEffusionRate)
.average()
.orElse(0.0);
int maxEffusionRateInt = (int) (Math.round(maxEffusionRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getCode(), maxEffusionRateInt);
}
private SceneEvaluateMetricsTurnVO.TurnListElement buildTurnListElement(
Map.Entry<String, List<CrossTurnDataHistPO>> entry, Integer status) {
SceneEvaluateMetricsTurnVO.TurnListElement element = new SceneEvaluateMetricsTurnVO.TurnListElement();
String turn = entry.getKey();
element.setTurn(turn);
List<CrossTurnDataHistPO> poList = entry.getValue();
//poList.forEach(o->o.setGreenLightEfficiency(o.getGreenLightEfficiency()<0.0?0.0:o.getGreenLightEfficiency()));
// 获取流量
OptionalDouble optionalAverageFlow = poList.stream()
.filter(Objects::nonNull)
.mapToInt(CrossTurnDataHistPO::getFlow)
.average();
int averageFlow = 0;
if (optionalAverageFlow.isPresent()) {
averageFlow = (int) Math.round(optionalAverageFlow.getAsDouble());
}
element.setFlow(averageFlow);
// 动态指标
element.setMetricsMap(buildTurnMetricMap(poList, status));
return element;
}
private Map<String, Integer> buildTurnMetricMap(List<CrossTurnDataHistPO> poList, Integer status) {
Map<String, Integer> res = new HashMap<>();
if (Objects.equals(status, CrossStatusEnum.CONGESTION.getCode())) {
buildTurnCongestionRes(res, poList);
} else if (Objects.equals(status, CrossStatusEnum.UNBALANCE.getCode())) {
buildTurnUnbalanceRes(res, poList);
} else if (Objects.equals(status, CrossStatusEnum.SPILLOVER.getCode())) {
buildTurnSpilloverRes(res, poList);
}
return res;
}
private void buildTurnSpilloverRes(Map<String, Integer> res, List<CrossTurnDataHistPO> poList) {
// 最大排队长度
double maxQueueLength = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getQueueLength)
.max()
.orElse(0.0);
int maxQueueLengthInt = (int) (Math.round(maxQueueLength));
res.put(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getCode(), maxQueueLengthInt);
// 平均延误
double maxDelayTime = poList.stream()
.mapToInt(CrossTurnDataHistPO::getDelayTime)
.average()
.orElse(0.0);
int maxDelayTimeInt = (int) (Math.round(maxDelayTime));
res.put(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getCode(), maxDelayTimeInt);
// 停车次数
double maxStopTimes = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getStopTimes)
.average()
.orElse(0.0);
int maxStopTimesInt = (int) (Math.round(maxStopTimes));
res.put(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getCode(), maxStopTimesInt);
// 溢流率
double maxEffusionRate = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getEffusionRate)
.average()
.orElse(0.0);
int maxEffusionRateInt = (int) (Math.round(maxEffusionRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getCode(), maxEffusionRateInt);
}
private void buildTurnUnbalanceRes(Map<String, Integer> res, List<CrossTurnDataHistPO> poList) {
// 不停车通过率
double maxNoStopRate = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getNoStopRate)
.average()
.orElse(0.0);
int maxNoStopRateInt = (int) (Math.round(maxNoStopRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getCode(), maxNoStopRateInt);
// N次停车通过率
double maxOneStopRate = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getOneStopRate)
.average()
.orElse(0.0);
int maxOneStopRateInt = (int) (Math.round(maxOneStopRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.STOP_RATE.getCode(), maxOneStopRateInt);
// 空放次数-绿灯有效利用率小于80%
long emptyDischarges = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getGreenLightEfficiency)
.filter(efficiency -> efficiency < 0.8)
.count();
res.put(StrategyAndMetricsEnum.Metrics.EMPTY_DISCHARGES.getCode(), (int)emptyDischarges);
// 绿灯有效利用率
double maxGreenLightEfficiency = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getGreenLightEfficiency)
.average()
.orElse(0.0);
int maxGreenLightEfficiencyInt = (int) (Math.round(maxGreenLightEfficiency * 100));
res.put(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getCode(), maxGreenLightEfficiencyInt);
}
private void buildTurnCongestionRes(Map<String, Integer> res, List<CrossTurnDataHistPO> poList) {
// N次停车通过率
double maxOneStopRate = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getOneStopRate)
.average()
.orElse(0.0);
int maxOneStopRateInt = (int) (Math.round(maxOneStopRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.STOP_RATE.getCode(), maxOneStopRateInt);
// 平均速度
double maxSpeed = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getSpeed)
.average()
.orElse(0.0);
int maxSpeedInt = (int) (Math.round(maxSpeed));
res.put(StrategyAndMetricsEnum.Metrics.AVERAGE_SPEED.getCode(), maxSpeedInt);
// 平均延误
double maxDelayTime = poList.stream()
.mapToInt(CrossTurnDataHistPO::getDelayTime)
.average()
.orElse(0.0);
int maxDelayTimeInt = (int) (Math.round(maxDelayTime));
res.put(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getCode(), maxDelayTimeInt);
// 停车次数
double maxStopTimes = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getStopTimes)
.average()
.orElse(0.0);
int maxStopTimesInt = (int) (Math.round(maxStopTimes));
res.put(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getCode(), maxStopTimesInt);
// 最大排队长度
double maxQueueLength = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getQueueLength)
.max()
.orElse(0.0);
int maxQueueLengthInt = (int) (Math.round(maxQueueLength));
res.put(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getCode(), maxQueueLengthInt);
// 溢流率
double maxEffusionRate = poList.stream()
.mapToDouble(CrossTurnDataHistPO::getEffusionRate)
.average()
.orElse(0.0);
int maxEffusionRateInt = (int) (Math.round(maxEffusionRate * 100));
res.put(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getCode(), maxEffusionRateInt);
}
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 = ((Number) value).doubleValue();;
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) {
List<String> res = new ArrayList<>();
Calendar startCal = Calendar.getInstance();
startCal.setTime(startTime);
int minute = startCal.get(Calendar.MINUTE);
int remainder = minute % 5;
startCal.add(Calendar.MINUTE, -remainder);
Calendar endCal = Calendar.getInstance();
endCal.setTime(newEndTime);
minute = endCal.get(Calendar.MINUTE);
remainder = (5 - (minute % 5)) % 5;
endCal.add(Calendar.MINUTE, remainder);
for (Calendar cal = (Calendar) startCal.clone();
cal.before(endCal) || cal.equals(endCal);
cal.add(Calendar.MINUTE, 5)) {
res.add(HOUR_SDF.format(cal.getTime()));
}
res.remove(res.size() - 1); // 去除最后一个时间
return res;
}
private List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> buildCrossSpilloverMetrics(
List<CrossDataHistPO> sceneCrossDataHistPOList) {
List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> res = new ArrayList<>();
// 最大排队长度
double maxQueueLength = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getQueueLength)
.max()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH, maxQueueLength));
// 平均延误
double avgDelayTime = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getDelayTime)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY, avgDelayTime));
// 平均停车次数
double avgStopTimes = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getStopTimes)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.STOP_TIMES, avgStopTimes));
// 溢流率
double avgEffusionRate = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getEffusionRate)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE, avgEffusionRate * 100));
return res;
}
private List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> buildCrossUnbalanceMetrics(
String crossId, Date startTime, Date newEndTime, List<CrossDataHistPO> sceneCrossDataHistPOList) {
List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> res = new ArrayList<>();
List<CrossDirDataHistPO> crossDirDataHistPOList = getCrossDirDataHistPOList(startTime, newEndTime, crossId);
// 用方向数据计算不停车通过率
double avgNoStopRate = crossDirDataHistPOList.stream()
.mapToDouble(CrossDirDataHistPO::getNoStopRate)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE, avgNoStopRate * 100));
// 用方向数据计算N次停车通过率
double maxOneStopRate = crossDirDataHistPOList.stream()
.mapToDouble(CrossDirDataHistPO::getOneStopRate)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.STOP_RATE, maxOneStopRate * 100));
// 空放次数-绿灯有效利用率小于80%
long emptyDischarges = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getGreenLightEfficiency)
.filter(efficiency -> efficiency < 0.8)
.count();
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.EMPTY_DISCHARGES, emptyDischarges));
// 绿灯有效利用率
double avgGreenLightEfficiency = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getGreenLightEfficiency)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY,
avgGreenLightEfficiency * 100));
// 负载均衡度
double avgLoadBalance = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getLoadBalance)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.LOAD_BALANCE, avgLoadBalance));
return res;
}
private List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> buildCrossCongestionMetrics(
String crossId, Date startTime, Date newEndTime, List<CrossDataHistPO> sceneCrossDataHistPOList) {
List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> res = new ArrayList<>();
// 从方向数据计算N次停车通过率
List<CrossDirDataHistPO> crossDirDataHistPOList = getCrossDirDataHistPOList(startTime, newEndTime, crossId);
double maxOneStopRate = crossDirDataHistPOList.stream()
.mapToDouble(CrossDirDataHistPO::getOneStopRate)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.STOP_RATE, maxOneStopRate * 100));
double avgSpeed = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getSpeed)
.average()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.AVERAGE_SPEED, avgSpeed));
int maxDelayTime = sceneCrossDataHistPOList.stream()
.mapToInt(CrossDataHistPO::getDelayTime)
.max()
.orElse(0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY, maxDelayTime));
double maxStopTimes = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getStopTimes)
.max()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.STOP_TIMES, maxStopTimes));
double maxQueueLength = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getQueueLength)
.max()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH, maxQueueLength));
double maxEffusionRate = sceneCrossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getEffusionRate)
.max()
.orElse(0.0);
res.add(buildMetrics(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE, maxEffusionRate * 100));
return res;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildMetrics(
StrategyAndMetricsEnum.Metrics metricEnum, double value) {
int roundedValue = (int) Math.round(value);
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics metric = new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
metric.setMetricCode(metricEnum.getCode());
metric.setMetricUnit(metricEnum.getUnit());
metric.setMetricName(metricEnum.getDescription());
metric.setMetricValue(roundedValue);
return metric;
}
private List<CrossDirDataHistPO> getCrossDirDataHistPOList(Date startTime, Date newEndTime, String crossId) {
int startTimeStamp = (int) (startTime.getTime() / 1000);
int endTimeStamp = (int) (newEndTime.getTime() / 1000);
List<CrossDirDataHistPO> res = crossDirDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startTimeStamp, endTimeStamp);
return res;
}
private Integer calcCrossFlow(List<CrossDataHistPO> crossDataHistPOList) {
int max = crossDataHistPOList.stream()
.mapToInt(CrossDataHistPO::getFlow)
.max()
.orElse(0);
return max;
}
private Double calcCrossSaturation(List<CrossDataHistPO> crossDataHistPOList) {
double max = crossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getSturation)
.max()
.orElse(0.0);
return max;
}
private List<CrossDataHistPO> getCrossDataHistPOList(Date startTime, Date newEndTime, String crossId) {
int startTimeStamp = (int) (startTime.getTime() / 1000);
int endTimeStamp = (int) (newEndTime.getTime() / 1000);
List<CrossDataHistPO> crossDataHistPOList = crossDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startTimeStamp, endTimeStamp);
return crossDataHistPOList;
}
private Integer calcCrossDelayTime(List<CrossDataHistPO> crossDataHistPOList) {
int max = crossDataHistPOList.stream()
.mapToInt(CrossDataHistPO::getDelayTime)
.max()
.orElse(0);
return max;
}
private List<String> buildPatternNames(List<BaseCrossSchemePO> matchedSchemes) {
List<String> res = new ArrayList<>();
for (BaseCrossSchemePO matchedScheme : matchedSchemes) {
res.add(matchedScheme.getName());
}
return res;
}
private List<Integer> buildDirs(String congestionDirs) {
List<Integer> res = new ArrayList<>();
String[] split = congestionDirs.split(",");
for (String s : split) {
res.add(Integer.parseInt(s));
}
return res;
}
private Integer calcCongestionLevel(Integer delayTime) {
Integer res = null;
if (delayTime >= 110) {
res = 3;
} else if (delayTime >= 65) {
res = 2;
} else if (delayTime >= 20) {
res = 1;
} else {
res = 0;
}
return res;
}
public List<SceneEvaluateAbnormalDistributeVO.TimeDateDistribution> buildTimeDateDistributionList(
List<SceneEvaluateAbnormalDistributeVO.TimeDistribution> timeDistributionList) {
List<SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution> finalTimeDistributionList = new ArrayList<>();
for (SceneEvaluateAbnormalDistributeVO.TimeDistribution timeDistribution : timeDistributionList) {
Date problemDate = timeDistribution.getProblemDate();
for (RunningEvaluateMetricsDetailVO.ProblemStatus problemStatus : timeDistribution.getProblemStatusList()) {
Integer status = problemStatus.getStatus();
Date startTime = problemStatus.getStartTime();
Date endTime = problemStatus.getEndTime();
// 生成 FinalTimeDistribution 对象
for (Date time = getStartTimeOfDay(); time.before(getEndTimeOfDay()); time = addFiveMinutes(time)) {
if (isTimeIntersecting(time, addFiveMinutes(time), startTime, endTime)) {
SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution finalTimeDistribution =
new SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution();
finalTimeDistribution.setProblemDate(problemDate);
finalTimeDistribution.setStatus(status);
// 将 time 中的年、月、日设置为 problemDate 中的年、月、日
Calendar calTime = Calendar.getInstance();
Calendar calProblemDate = Calendar.getInstance();
calTime.setTime(time);
calProblemDate.setTime(problemDate);
calTime.set(Calendar.YEAR, calProblemDate.get(Calendar.YEAR));
calTime.set(Calendar.MONTH, calProblemDate.get(Calendar.MONTH));
calTime.set(Calendar.DAY_OF_MONTH, calProblemDate.get(Calendar.DAY_OF_MONTH));
Date newTime = calTime.getTime();
finalTimeDistribution.setDistributionTime(newTime);
finalTimeDistributionList.add(finalTimeDistribution);
}
}
}
// 填满 finalTimeDistributionList
// 生成时间列表
List<Date> timeList = new ArrayList<>();
Calendar cal = Calendar.getInstance();
cal.setTime(problemDate);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
for (int i = 0; i < 24 * 60; i += 5) {
timeList.add(cal.getTime());
cal.add(Calendar.MINUTE, 5);
}
for (Date time : timeList) {
boolean exists = finalTimeDistributionList.stream()
.anyMatch(item -> item.getDistributionTime().equals(time)
&& isSameDay(item.getProblemDate(), problemDate));
if (!exists) {
SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution newItem =
new SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution();
newItem.setProblemDate(problemDate);
newItem.setDistributionTime(time);
newItem.setStatus(null);
finalTimeDistributionList.add(newItem);
}
}
}
// 重新排序
finalTimeDistributionList
.sort(Comparator.comparing(SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution::getProblemDate)
.thenComparing(SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution::getDistributionTime));
// 生成时间日期分布
List<SceneEvaluateAbnormalDistributeVO.TimeDateDistribution> timeDateDistributionList = new ArrayList<>();
List<String> minuteSectionArray = TimeArrayUtil.getMinuteSectionArray(5);
for (String timeStr : minuteSectionArray) {
SceneEvaluateAbnormalDistributeVO.TimeDateDistribution timeDateDistribution =
new SceneEvaluateAbnormalDistributeVO.TimeDateDistribution();
timeDateDistribution.setHourMinute(timeStr);
timeDateDistribution.setStatusByDateList(buildStatusByDateList(timeStr, finalTimeDistributionList));
timeDateDistributionList.add(timeDateDistribution);
}
return timeDateDistributionList;
}
private List<SceneEvaluateAbnormalDistributeVO.StatusByDate> buildStatusByDateList(
String timeStr, List<SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution> finalTimeDistributionList) {
List<SceneEvaluateAbnormalDistributeVO.StatusByDate> res = new ArrayList<>();
for (SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution ftd : finalTimeDistributionList) {
Date problemDate = ftd.getProblemDate();
Date distributionTime = ftd.getDistributionTime();
String format = HOUR_SDF.format(distributionTime);
if (Objects.equals(timeStr, format)) {
SceneEvaluateAbnormalDistributeVO.StatusByDate inRes = getRecordInRes(res, problemDate);
// 如果 res 中没有记录
if (ObjectUtil.isEmpty(inRes)) {
SceneEvaluateAbnormalDistributeVO.StatusByDate statusByDate = buildStatusByDate(ftd, problemDate);
res.add(statusByDate);
} else {
modifyRecordInRes(ftd, inRes);
}
}
}
return res;
}
private void modifyRecordInRes(
SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution ftd,
SceneEvaluateAbnormalDistributeVO.StatusByDate inRes) {
Integer status = ftd.getStatus();
if (Objects.equals(status, CrossStatusEnum.UNBALANCE.getCode())) {
inRes.setIsUnbalance(1);
} else if (Objects.equals(status, CrossStatusEnum.CONGESTION.getCode())) {
inRes.setIsCongestion(1);
} else if (Objects.equals(status, CrossStatusEnum.SPILLOVER.getCode())) {
inRes.setIsSpillover(1);
}
}
@NotNull
private SceneEvaluateAbnormalDistributeVO.StatusByDate buildStatusByDate(
SceneEvaluateAbnormalDistributeVO.FinalTimeDistribution ftd, Date problemDate) {
SceneEvaluateAbnormalDistributeVO.StatusByDate statusByDate =
new SceneEvaluateAbnormalDistributeVO.StatusByDate();
statusByDate.setProblemDate(problemDate);
modifyRecordInRes(ftd, statusByDate);
return statusByDate;
}
private SceneEvaluateAbnormalDistributeVO.StatusByDate getRecordInRes(
List<SceneEvaluateAbnormalDistributeVO.StatusByDate> res, Date problemDate) {
for (SceneEvaluateAbnormalDistributeVO.StatusByDate statusByDate : res) {
Date problemDateInRes = statusByDate.getProblemDate();
// 创建Calendar实例
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
// 设置Calendar实例的时间
cal1.setTime(problemDate);
cal2.setTime(problemDateInRes);
// 比较两个日期是否相等(忽略时间部分)
boolean isSameDay = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
if (isSameDay) {
return statusByDate;
}
}
return null;
}
private boolean isSameDay(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTime(date1);
cal2.setTime(date2);
return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
}
// 辅助方法:判断两个时间段是否相交
public boolean isTimeIntersecting(Date eventStartTime, Date eventEndTime,
Date sectionStartTime, Date sectionEndTime) {
Calendar cal = java.util.Calendar.getInstance();
cal.setTime(eventStartTime);
int eventStartHour = cal.get(java.util.Calendar.HOUR_OF_DAY);
int eventStartMinute = cal.get(java.util.Calendar.MINUTE);
cal.setTime(eventEndTime);
int eventEndHour = cal.get(java.util.Calendar.HOUR_OF_DAY);
int eventEndMinute = cal.get(java.util.Calendar.MINUTE);
cal.setTime(sectionStartTime);
int sectionStartHour = cal.get(Calendar.HOUR_OF_DAY);
int sectionStartMinute = cal.get(Calendar.MINUTE);
cal.setTime(sectionEndTime);
int sectionEndHour = cal.get(Calendar.HOUR_OF_DAY);
int sectionEndMinute = cal.get(Calendar.MINUTE);
// 将小时和分钟转换为分钟数以便比较
int eventStartInMinutes = eventStartHour * 60 + eventStartMinute;
int eventEndInMinutes = eventEndHour * 60 + eventEndMinute;
int sectionStartInMinutes = sectionStartHour * 60 + sectionStartMinute;
int sectionEndInMinutes = sectionEndHour * 60 + sectionEndMinute;
// 判断两个时间段是否相交
return (eventStartInMinutes < sectionEndInMinutes && eventEndInMinutes > sectionStartInMinutes) ||
(sectionStartInMinutes < eventEndInMinutes && sectionEndInMinutes > eventStartInMinutes);
}
// 辅助方法:获取当天的开始时间(00:00)
private static Date getStartTimeOfDay() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
// 辅助方法:获取当天的结束时间(23:59)
private static Date getEndTimeOfDay() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
return calendar.getTime();
}
// 辅助方法:给时间加上5分钟
private static Date addFiveMinutes(Date time) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(time);
calendar.add(Calendar.MINUTE, 5);
return calendar.getTime();
}
private static void setCounts(List<SceneEvaluateAbnormalDistributeVO.TimeDistribution> timeDistributionList,
SceneEvaluateAbnormalDistributeVO vo) {
int congestionDuration = 0;
int congestionTimes = 0;
int unbalanceDuration = 0;
int unbalanceTimes = 0;
int spilloverDuration = 0;
int spilloverTimes = 0;
for (SceneEvaluateAbnormalDistributeVO.TimeDistribution timeDistribution : timeDistributionList) {
List<RunningEvaluateMetricsDetailVO.ProblemStatus> problemStatusList =
timeDistribution.getProblemStatusList();
for (RunningEvaluateMetricsDetailVO.ProblemStatus problemStatus : problemStatusList) {
Integer status = problemStatus.getStatus();
Integer durationMinutes = problemStatus.getDurationMinutes();
if (status != null && status.equals(CrossStatusEnum.CONGESTION.getCode())) {
congestionTimes++;
congestionDuration += durationMinutes;
} else if (status != null && status.equals(CrossStatusEnum.UNBALANCE.getCode())) {
unbalanceTimes++;
unbalanceDuration += durationMinutes;
} else if (status != null && status.equals(CrossStatusEnum.SPILLOVER.getCode())) {
spilloverTimes++;
spilloverDuration += durationMinutes;
}
}
}
vo.setCongestionTimes(congestionTimes);
vo.setUnbalanceTimes(unbalanceTimes);
vo.setSpilloverTimes(spilloverTimes);
vo.setCongestionDuration(congestionDuration);
vo.setUnbalanceDuration(unbalanceDuration);
vo.setSpilloverDuration(spilloverDuration);
}
private List<SceneEvaluateAbnormalDistributeVO.TimeDistribution> buildTimeDistributionList(
String crossId, Date startDate, Date endDate) {
List<SceneEvaluateAbnormalDistributeVO.TimeDistribution> res = new ArrayList<>();
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
start.setTime(startDate);
end.setTime(endDate);
// 使 endDate 包含在内
end.add(Calendar.DATE, 1);
for (Date date = start.getTime(); start.before(end); start.add(Calendar.DATE, 1), date = start.getTime()) {
SceneEvaluateAbnormalDistributeVO.TimeDistribution timeDistribution =
new SceneEvaluateAbnormalDistributeVO.TimeDistribution();
timeDistribution.setProblemDate(date);
// 获取问题列表
// 路口级别全量数据
Calendar partEnd = (Calendar) start.clone();
partEnd.add(Calendar.DAY_OF_MONTH, 1);
int startStamp = (int)(start.getTimeInMillis() / 1000);
int endStamp = (int)(partEnd.getTimeInMillis() / 1000);
//按开始、截止时间查询事件列表
List<MetricHistDTO> crossDTOList = crossDataHistMapper.selectMetricHistDTO(
crossId, startStamp, endStamp);
// 过滤有问题的记录
List<MetricHistDTO> filteredList = crossDTOList.stream()
.filter(metricHistDTO -> metricHistDTO.getStatus() != null && !metricHistDTO.getStatus().equals(0))
.collect(Collectors.toList());
timeDistribution.setProblemStatusList(runningEvaluateService.buildProblemStatusList(filteredList));
res.add(timeDistribution);
}
return res;
}
}
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 lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.BaseEnum;
import net.wanji.common.enums.CrossInOutEnum;
import net.wanji.common.enums.StrategyAndMetricsEnum;
import net.wanji.common.enums.TurnConvertEnum;
import net.wanji.common.utils.tool.CrossUtil;
import net.wanji.common.utils.tool.TimeArrayUtil;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.dao.entity.BaseCrossSchedulesPO;
import net.wanji.databus.dao.entity.BaseCrossSchedulesPlanPO;
import net.wanji.databus.dao.entity.BaseCrossSchemePO;
import net.wanji.databus.dao.entity.CrossSectionPO;
import net.wanji.databus.dao.mapper.*;
import net.wanji.databus.po.*;
import net.wanji.opt.bo.CrossSchemeListBO;
import net.wanji.opt.bo.CurveChartBO;
import net.wanji.opt.bo.CurveChartBO.DirTurn;
import net.wanji.opt.bo.ProblemSchemeBO;
import net.wanji.opt.bo.SchemeDetailOverallBO;
import net.wanji.opt.dao.mapper.HoloEventMapper;
import net.wanji.opt.dao.mapper.strategy.SceneMapper;
import net.wanji.opt.dao.mapper.strategy.SceneStrategyMapper;
import net.wanji.opt.dao.mapper.strategy.StrategyMapper;
import net.wanji.opt.po.strategy.ScenePO;
import net.wanji.opt.po.strategy.SceneStrategyPO;
import net.wanji.opt.po.strategy.StrategyPO;
import net.wanji.opt.service.SchemeEvaluateService;
import net.wanji.opt.vo.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author Kent HAN
* @date 2023/8/25 16:09
*/
@Slf4j
@Service
public class SchemeEvaluateServiceImpl implements SchemeEvaluateService {
private final CrossDataHistMapper crossDataHistMapper;
private final RunningEvaluateServiceImpl runningEvaluateService;
private final BaseCrossSectionMapper baseCrossSectionMapper;
private final BaseCrossSchemeMapper baseCrossSchemeMapper;
private final SceneMapper sceneMapper;
private final SceneStrategyMapper sceneStrategyMapper;
private final StrategyMapper strategyMapper;
private final BaseCrossSchedulesMapper baseCrossSchedulesMapper;
private final BaseCrossSchedulesPlanMapper baseCrossSchedulesPlanMapper;
private final CrossDataRealtimeMapper crossDataRealtimeMapper;
private final CrossDirDataHistMapper crossDirDataHistMapper;
private final BaseCrossDirInfoMapper baseCrossDirInfoMapper;
private final CrossTurnDataHistMapper crossTurnDataHistMapper;
private final BaseCrossTurnInfoMapper baseCrossTurnInfoMapper;
private final HoloEventMapper holoEventMapper;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public SchemeEvaluateServiceImpl(CrossDataHistMapper crossDataHistMapper,
RunningEvaluateServiceImpl runningEvaluateService,
@Qualifier("baseCrossSectionMapper") BaseCrossSectionMapper baseCrossSectionMapper,
@Qualifier("baseCrossSchemeMapper") BaseCrossSchemeMapper baseCrossSchemeMapper,
@Qualifier("sceneMapper") SceneMapper sceneMapper,
@Qualifier("sceneStrategyMapper") SceneStrategyMapper sceneStrategyMapper,
@Qualifier("strategyMapper") StrategyMapper strategyMapper,
@Qualifier("baseCrossSchedulesMapper") BaseCrossSchedulesMapper baseCrossSchedulesMapper,
@Qualifier("baseCrossSchedulesPlanMapper") BaseCrossSchedulesPlanMapper baseCrossSchedulesPlanMapper,
CrossDataRealtimeMapper crossDataRealtimeMapper, CrossDirDataHistMapper crossDirDataHistMapper,
@Qualifier("baseCrossDirInfoMapper") BaseCrossDirInfoMapper baseCrossDirInfoMapper,
CrossTurnDataHistMapper crossTurnDataHistMapper,
@Qualifier("baseCrossTurnInfoMapper") BaseCrossTurnInfoMapper baseCrossTurnInfoMapper, @Qualifier("holoEventMapper") HoloEventMapper holoEventMapper) {
this.crossDataHistMapper = crossDataHistMapper;
this.runningEvaluateService = runningEvaluateService;
this.baseCrossSectionMapper = baseCrossSectionMapper;
this.baseCrossSchemeMapper = baseCrossSchemeMapper;
this.sceneMapper = sceneMapper;
this.sceneStrategyMapper = sceneStrategyMapper;
this.strategyMapper = strategyMapper;
this.baseCrossSchedulesMapper = baseCrossSchedulesMapper;
this.baseCrossSchedulesPlanMapper = baseCrossSchedulesPlanMapper;
this.crossDataRealtimeMapper = crossDataRealtimeMapper;
this.crossDirDataHistMapper = crossDirDataHistMapper;
this.baseCrossDirInfoMapper = baseCrossDirInfoMapper;
this.crossTurnDataHistMapper = crossTurnDataHistMapper;
this.baseCrossTurnInfoMapper = baseCrossTurnInfoMapper;
this.holoEventMapper = holoEventMapper;
}
@Override
public SchemeEvaluateProblemSchemeVO problemSchemeList(ProblemSchemeBO problemSchemeBO) {
SchemeEvaluateProblemSchemeVO res = new SchemeEvaluateProblemSchemeVO();
String crossId = problemSchemeBO.getCrossId();
Date startDate = problemSchemeBO.getStartDate();
Date endDate = problemSchemeBO.getEndDate();
endDate = DateUtil.offsetDay(endDate, 1); // 包含最后一天
int startDateStamp = (int) (startDate.getTime() / 1000); // 10位时间戳
int endDateStamp = (int) (endDate.getTime() / 1000);
String startTime = problemSchemeBO.getStartTime();
String endTime = problemSchemeBO.getEndTime();
List<CrossDataHistPO> crossDataHistPOList =
crossDataHistMapper.selectByCrossIdAndStartEnd(crossId, startDateStamp, endDateStamp);
// 构造时间-问题结果集
Map<String, List<CrossDataHistPO>> timeProblemMap = getTimeProblemMap(
crossDataHistPOList, endTime, startTime);
// 构造结果
int problemCounts = 0; // 问题次数
if (CollectionUtil.isNotEmpty(timeProblemMap)) {
for (List<CrossDataHistPO> list : timeProblemMap.values()) {
problemCounts += list.size();
}
}
res.setProblemCounts(problemCounts); // 问题方案数量
// 构造问题方案列表(根据日期)
Map<Date, List<CrossDataHistPO>> dateProblemsMap = buildDateProblemsMap(timeProblemMap); // 构造日期-问题结果集
List<CrossSectionPO> crossSectionPOList = baseCrossSectionMapper.selectAll();
List<BaseCrossSchemePO> crossSchemePOList = baseCrossSchemeMapper.selectAll();
Map<Date, List<RunningEvaluateMetricsDetailVO.ProblemScheme>> dateSchemesMap =
buildDateSchemesMap(dateProblemsMap, crossId, crossSectionPOList, crossSchemePOList); // 构造日期-问题方案结果集
List<ScenePO> scenePOList = sceneMapper.selectAll();
List<SchemeEvaluateProblemSchemeVO.ByDateVO> byDateVOList = buildProblemSchemeListByDate(
dateProblemsMap, dateSchemesMap, scenePOList);
res.setProblemSchemeListByDate(byDateVOList);
// 构造计数
int schemeCounts = calcSchemeCounts(dateSchemesMap);
res.setSchemeCounts(schemeCounts);
res.setEfficiencyProblemCounts(calcProblemCounts(
byDateVOList, SchemeEvaluateProblemSchemeVO.ByDateVO::getEfficiencyProblemCounts));
res.setBalanceProblemCounts(calcProblemCounts(
byDateVOList, SchemeEvaluateProblemSchemeVO.ByDateVO::getBalanceProblemCounts));
res.setSecurityProblemCounts(calcProblemCounts(
byDateVOList, SchemeEvaluateProblemSchemeVO.ByDateVO::getSecurityProblemCounts));
// 构造问题方案列表(根据方案)
res.setProblemSchemeListByScheme(buildProblemSchemeListByScheme(dateSchemesMap));
return res;
}
@Override
public List<SchemeEvaluateStrategyMetricMenuVO> strategyMetricMenu(CrossIdBO crossIdBO) {
List<SchemeEvaluateStrategyMetricMenuVO> voList = new ArrayList<>();
for (Map.Entry<StrategyAndMetricsEnum.Strategy, List<StrategyAndMetricsEnum.Metrics>> entry
: StrategyAndMetricsEnum.STRATEGY_METRICS_MAP.entrySet()) {
SchemeEvaluateStrategyMetricMenuVO vo = new SchemeEvaluateStrategyMetricMenuVO();
vo.setStrategyCode(entry.getKey().getCode());
vo.setStrategyName(entry.getKey().getMsg());
List<SchemeEvaluateStrategyMetricMenuVO.EvaluateMetric> metricInfoList = buildEvaluateMetrics(entry);
vo.setMetricList(metricInfoList);
voList.add(vo);
}
return voList;
}
private List<SchemeEvaluateStrategyMetricMenuVO.EvaluateMetric> buildEvaluateMetrics(
Map.Entry<StrategyAndMetricsEnum.Strategy, List<StrategyAndMetricsEnum.Metrics>> entry) {
List<SchemeEvaluateStrategyMetricMenuVO.EvaluateMetric> metricInfoList = new ArrayList<>();
for (StrategyAndMetricsEnum.Metrics metric : entry.getValue()) {
SchemeEvaluateStrategyMetricMenuVO.EvaluateMetric evaluateMetric =
new SchemeEvaluateStrategyMetricMenuVO.EvaluateMetric();
String metricCode = metric.getCode();
evaluateMetric.setMetricCode(metricCode);
evaluateMetric.setMetricName(metric.getDescription());
if (Objects.equals(metricCode, StrategyAndMetricsEnum.Metrics.LOAD_BALANCE.getCode())
|| Objects.equals(metricCode, StrategyAndMetricsEnum.Metrics.CLEAR_RATE.getCode())) {
evaluateMetric.setIsShownInDetail(0);
}
metricInfoList.add(evaluateMetric);
}
return metricInfoList;
}
@Override
public List<SchemeEvaluateCrossSchemeListVO> crossSchemeList(CrossSchemeListBO crossSchemeListBO) {
String crossId = crossSchemeListBO.getCrossId();
String schemeNoOrName = crossSchemeListBO.getSchemeNoOrName();
String strategyCode = crossSchemeListBO.getStrategyCode();
// 查找方案
List<BaseCrossSchemePO> baseCrossSchemePOList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(schemeNoOrName)) {
if (isNumeric(schemeNoOrName)) { // 方案号
String schemeNo = schemeNoOrName;
BaseCrossSchemePO baseCrossSchemePO = baseCrossSchemeMapper.selectByCrossIdAndSchemeNo(
crossId, Integer.parseInt(schemeNo));
baseCrossSchemePOList.add(baseCrossSchemePO);
} else { // 方案名模糊搜索
String schemeName = schemeNoOrName;
baseCrossSchemePOList = baseCrossSchemeMapper.selectByCrossIdAndPartialSchemeName(
crossId, schemeName);
}
} else { // 全部方案
baseCrossSchemePOList = baseCrossSchemeMapper.selectByCrossId(crossId);
}
Integer weekDay = crossSchemeListBO.getWeekDay();
// 找出当前路口已执行的调度,在某天对应的计划
BaseCrossSchedulesPO baseCrossSchedulesPO = baseCrossSchedulesMapper.selectExecByCrossId(crossId);
if (ObjectUtil.isEmpty(baseCrossSchedulesPO)) {
throw new RuntimeException("该路口没有正在执行的调度");
}
Integer scheduleId = baseCrossSchedulesPO.getId();
List<BaseCrossSchedulesPlanPO> baseCrossSchedulesPlanPOList =
baseCrossSchedulesPlanMapper.selectByCrossIdAndSchedulesId(crossId, scheduleId);
List<BaseCrossSchedulesPlanPO> filteredList = baseCrossSchedulesPlanPOList.stream()
.filter(po -> po.getWeek().equals(weekDay))
.collect(Collectors.toList());
List<SchemeEvaluateCrossSchemeListVO> res = new ArrayList<>();
// 根据计划 ID 和方案 ID,获取时段信息
for (BaseCrossSchedulesPlanPO baseCrossSchedulesPlanPO : filteredList) {
Integer planId = baseCrossSchedulesPlanPO.getPlanId();
for (BaseCrossSchemePO baseCrossSchemePO : baseCrossSchemePOList) {
Integer schemeId = baseCrossSchemePO.getId();
List<CrossSectionPO> crossSectionPOList = baseCrossSectionMapper.selectByCrossIdPlanIdAndSchemeId(
crossId, planId, schemeId);
// todo 按控制模式和策略入参筛选结果
for (CrossSectionPO crossSectionPO : crossSectionPOList) {
SchemeEvaluateCrossSchemeListVO vo =
buildSchemeEvaluateCrossSchemeListVO(baseCrossSchemePO, crossSectionPO);
res.add(vo);
}
}
}
// 特殊日期根据方案 ID 筛选重复方案
if (weekDay == 0) {
List<SchemeEvaluateCrossSchemeListVO> sortedUniqueList = res.stream()
.collect(Collectors.toMap(
SchemeEvaluateCrossSchemeListVO::getSchemeId,
vo -> vo,
(existing, replacement) -> existing))
.values()
.stream()
.sorted(Comparator.comparing(SchemeEvaluateCrossSchemeListVO::getStartTime))
.collect(Collectors.toList());
return sortedUniqueList;
}
// 按照 startTime 排序
List<SchemeEvaluateCrossSchemeListVO> sortedList = res.stream()
.sorted(Comparator.comparing(SchemeEvaluateCrossSchemeListVO::getStartTime))
.collect(Collectors.toList());
return sortedList;
}
@Override
public SchemeEvaluateSchemeDetailOverallVO schemeDetailOverall(SchemeDetailOverallBO schemeDetailOverallBO)
throws ParseException {
String crossId = schemeDetailOverallBO.getCrossId();
String strategyCode = schemeDetailOverallBO.getStrategyCode();
Date problemDate = schemeDetailOverallBO.getProblemDate();
String startTime = schemeDetailOverallBO.getStartTime();
String endTime = schemeDetailOverallBO.getEndTime();
SchemeEvaluateSchemeDetailOverallVO vo = new SchemeEvaluateSchemeDetailOverallVO();
// 查询起止时间内历史数据
String dateStr = dateFormat.format(problemDate);
String concatenatedStartTime = dateStr + " " + startTime;
String concatenatedEndTime = dateStr + " " + endTime;
int startTimeStamp = (int) (timeFormat.parse(concatenatedStartTime).getTime() / 1000);
int endTimeStamp = (int) (timeFormat.parse(concatenatedEndTime).getTime() / 1000);
List<CrossDataHistPO> crossDataHistPOList = crossDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startTimeStamp, endTimeStamp);
List<CrossDirDataHistPO> crossDirDataHistPOList = crossDirDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startTimeStamp, endTimeStamp);
// 服务水平
double sumA = crossDataHistPOList.stream()
.filter(item -> item.getBatchTime() >= startTimeStamp && item.getBatchTime() <= endTimeStamp)
.mapToDouble(item -> item.getFlow() * item.getSturation())
.sum();
double sumB = crossDataHistPOList.stream()
.filter(item -> item.getBatchTime() >= startTimeStamp && item.getBatchTime() <= endTimeStamp)
.mapToDouble(CrossDataHistPO::getFlow)
.sum();
double saturation = sumA / sumB;
String serviceLevel = CrossUtil.getServiceLevel(saturation);
vo.setServiceLevel(serviceLevel);
if (Objects.equals(strategyCode, StrategyAndMetricsEnum.Strategy.EFFICIENCY.getCode())) {
buildEfficiencyVO(crossDataHistPOList, crossDirDataHistPOList, vo, crossId, startTimeStamp, endTimeStamp);
} else if (Objects.equals(strategyCode, StrategyAndMetricsEnum.Strategy.BALANCE.getCode())) {
buildBalanceVO(crossDataHistPOList, crossDirDataHistPOList, vo, crossId, startTimeStamp, endTimeStamp);
} else if (Objects.equals(strategyCode, StrategyAndMetricsEnum.Strategy.SECURITY.getCode())) {
buildSecurityVO(crossDataHistPOList, crossDirDataHistPOList, vo, crossId, startTimeStamp, endTimeStamp);
}
return vo;
}
@Override
public SchemeEvaluateSchemeDetailedProblemVO detailedProblem(SchemeDetailOverallBO schemeDetailOverallBO)
throws ParseException {
String crossId = schemeDetailOverallBO.getCrossId();
Date problemDate = schemeDetailOverallBO.getProblemDate();
String startTime = schemeDetailOverallBO.getStartTime();
String endTime = schemeDetailOverallBO.getEndTime();
String strategyCode = schemeDetailOverallBO.getStrategyCode();
// 查询起止时间内历史数据
String dateStr = dateFormat.format(problemDate);
String concatenatedStartTime = dateStr + " " + startTime;
String concatenatedEndTime = dateStr + " " + endTime;
int startTimeStamp = (int) (timeFormat.parse(concatenatedStartTime).getTime() / 1000);
int endTimeStamp = (int) (timeFormat.parse(concatenatedEndTime).getTime() / 1000);
List<CrossDirDataHistPO> crossDirDataHistPOList = crossDirDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startTimeStamp, endTimeStamp);
List<CrossTurnDataHistPO> crossTurnDataHistPOList =
crossTurnDataHistMapper.selectByCrossId(crossId, endTimeStamp, startTimeStamp);
SchemeEvaluateSchemeDetailedProblemVO vo = new SchemeEvaluateSchemeDetailedProblemVO();
if (Objects.equals(strategyCode, StrategyAndMetricsEnum.Strategy.EFFICIENCY.getCode())) {
buildEfficiencyDetailVO(
crossDirDataHistPOList, crossTurnDataHistPOList, vo, crossId);
} else if (Objects.equals(strategyCode, StrategyAndMetricsEnum.Strategy.BALANCE.getCode())) {
buildBalanceDetailVO(
crossDirDataHistPOList, crossTurnDataHistPOList, vo, crossId);
} else if (Objects.equals(strategyCode, StrategyAndMetricsEnum.Strategy.SECURITY.getCode())) {
buildSecurityDetailVO(
crossDirDataHistPOList, crossTurnDataHistPOList, vo, crossId, startTimeStamp, endTimeStamp);
}
return vo;
}
@Override
public List<SchemeEvaluateCurveChartVO> curveChart(CurveChartBO curveChartBO)
throws ParseException, NoSuchFieldException, IllegalAccessException {
String crossId = curveChartBO.getCrossId();
Integer minutes = curveChartBO.getMinutes();
Date problemDate = curveChartBO.getProblemDate();
String startTime = curveChartBO.getStartTime();
String endTime = curveChartBO.getEndTime();
String dateStr = dateFormat.format(problemDate);
String concatenatedStartTime = dateStr + " " + startTime;
String concatenatedEndTime = dateStr + " " + endTime;
int startTimeStamp = (int) (timeFormat.parse(concatenatedStartTime).getTime() / 1000);
int endTimeStamp = (int) (timeFormat.parse(concatenatedEndTime).getTime() / 1000);
String metricCode = curveChartBO.getMetricCode();
List<DirTurn> dirTurnList = curveChartBO.getDirTurnList();
List<SchemeEvaluateCurveChartVO> res = new ArrayList<>();
List<String> minuteSectionArray = TimeArrayUtil.getCustomTimeIntervals(startTime, endTime, minutes);
for (DirTurn dirTurn : dirTurnList) {
String turnType = dirTurn.getTurn();
String dirCode = dirTurn.getDir();
int dirInt = Integer.parseInt(dirCode);
if (ObjectUtil.isEmpty(turnType)) {
// 查询该方向所有的车道ID
List<String> laneIds = baseCrossDirInfoMapper.selectLaneIds(crossId, dirInt);
// 查询该方向,该时段内全量数据
List<CrossDirDataHistPOExt> crossDirDataHistPOList = crossDirDataHistMapper.selectByMetrics(
crossId, dirInt, startTimeStamp, endTimeStamp);
Integer emergencyCount = holoEventMapper.selectEmergencyCountWithLaneIds(
crossId, startTimeStamp, endTimeStamp, laneIds);
for (CrossDirDataHistPOExt po : crossDirDataHistPOList) {
po.setEmergencyCount(emergencyCount);
}
// 按时间段分组
Map<String, List<CrossDirDataHistPOExt>> groupedByTime = crossDirDataHistPOList.stream()
.collect(Collectors.groupingBy(po -> {
long timestampInMillSeconds = po.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);
}));
// 按照时间粒度聚合
for (String section : minuteSectionArray) {
SchemeEvaluateCurveChartVO vo = new SchemeEvaluateCurveChartVO();
vo.setMetricTime(section);
vo.setDir(dirCode);
vo.setTurn(turnType);
List<CrossDirDataHistPOExt> poList = groupedByTime.get(section);
String metricField = StrategyAndMetricsEnum.Metrics.getFieldByCode(metricCode);
Field declaredField = CrossDirDataHistPOExt.class.getField(metricField);
declaredField.setAccessible(true);
if (CollectionUtil.isNotEmpty(poList)) {
double metricSum = 0;
for (CrossDirDataHistPOExt crossDirDataHistPOExt : poList) {
Double doubleValue = getDirDouble(crossDirDataHistPOExt, declaredField);
metricSum += doubleValue;
}
int size = poList.size();
double v = metricSum / size;
BigDecimal bd = new BigDecimal(v);
bd = bd.setScale(2, RoundingMode.HALF_UP);
double roundedValue = bd.doubleValue();
vo.setMetricValue(roundedValue);
}
res.add(vo);
}
} else {
// 查询该转向所有的车道ID
Integer intTurnCode = BaseEnum.TurnTypeEnum.getIntCodeByStrCode(turnType);
List<String> laneIds = baseCrossTurnInfoMapper.selectLaneIds(crossId, dirInt, intTurnCode);
// 查询该方向,该转向,该时段内全量数据
List<CrossTurnDataHistPOExt> crossTurnDataHistPOList = crossTurnDataHistMapper.selectByMetrics(
crossId, dirInt, turnType, startTimeStamp, endTimeStamp);
Integer emergencyCount = holoEventMapper.selectEmergencyCountWithLaneIds(
crossId, startTimeStamp, endTimeStamp, laneIds);
for (CrossTurnDataHistPOExt crossTurnDataHistPOExt : crossTurnDataHistPOList) {
crossTurnDataHistPOExt.setEmergencyCount(emergencyCount);
}
// 按时间段分组
Map<String, List<CrossTurnDataHistPOExt>> groupedByTime = crossTurnDataHistPOList.stream()
.collect(Collectors.groupingBy(po -> {
long timestampInMillSeconds = po.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);
}));
// 按照时间粒度聚合
for (String section : minuteSectionArray) {
SchemeEvaluateCurveChartVO vo = new SchemeEvaluateCurveChartVO();
vo.setMetricTime(section);
vo.setDir(dirCode);
vo.setTurn(turnType);
List<CrossTurnDataHistPOExt> poList = groupedByTime.get(section);
String metricField = StrategyAndMetricsEnum.Metrics.getFieldByCode(metricCode);
Field declaredField = CrossTurnDataHistPOExt.class.getField(metricField);
declaredField.setAccessible(true);
if (CollectionUtil.isNotEmpty(poList)) {
double metricSum = 0;
for (CrossTurnDataHistPOExt crossTurnDataHistPOExt : poList) {
Double doubleValue = getTurnDouble(crossTurnDataHistPOExt, declaredField);
metricSum += doubleValue;
}
int size = poList.size();
double v = metricSum / size;
BigDecimal bd = new BigDecimal(v);
bd = bd.setScale(2, RoundingMode.HALF_UP);
double roundedValue = bd.doubleValue();
vo.setMetricValue(roundedValue);
}
res.add(vo);
}
}
}
return res;
}
private static final Set<String> SPECIAL_METRICS = new HashSet<>();
static {
SPECIAL_METRICS.add(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getField());
SPECIAL_METRICS.add(StrategyAndMetricsEnum.Metrics.STOP_RATE.getField());
SPECIAL_METRICS.add(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getField());
SPECIAL_METRICS.add(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getField());
SPECIAL_METRICS.add(StrategyAndMetricsEnum.Metrics.CLEAR_RATE.getField());
}
private Double getDoubleFromObject(Object object, Field declaredField) throws IllegalAccessException {
Object objValue = declaredField.get(object);
if (ObjectUtil.isEmpty(objValue)) {
objValue = 0;
}
String fieldName = declaredField.getName();
if (SPECIAL_METRICS.contains(fieldName) && objValue instanceof Double) {
objValue = (double) Math.round((Double) objValue * 100);
}
if (objValue instanceof Integer) {
return (double) objValue;
} else if (objValue instanceof Double) {
BigDecimal bd = BigDecimal.valueOf((double) objValue);
bd = bd.setScale(2, RoundingMode.HALF_UP);
return bd.doubleValue();
} else {
throw new IllegalArgumentException("字段值不是 int 或 double");
}
}
private Double getTurnDouble(CrossTurnDataHistPOExt crossTurnDataHistPO, Field declaredField)
throws IllegalAccessException {
return getDoubleFromObject(crossTurnDataHistPO, declaredField);
}
private Double getDirDouble(CrossDirDataHistPOExt crossDirDataHistPO, Field declaredField)
throws IllegalAccessException {
return getDoubleFromObject(crossDirDataHistPO, declaredField);
}
private void buildSecurityDetailVO(List<CrossDirDataHistPO> crossDirDataHistPOList,
List<CrossTurnDataHistPO> crossTurnDataHistPOList,
SchemeEvaluateSchemeDetailedProblemVO vo, String crossId,
int startTimeStamp, int endTimeStamp) {
List<String> problemList = new ArrayList<>();
List<SchemeEvaluateSchemeDetailedProblemVO.TableContent> tableContentList = new ArrayList<>();
// 获取路口方向
List<Integer> dirCodes = baseCrossDirInfoMapper.selectInDirsByCrossId(crossId);
for (Integer dirCode : dirCodes) {
Map<String, String> metricsMap = new HashMap<>();
SchemeEvaluateSchemeDetailedProblemVO.TableContent tableContent =
new SchemeEvaluateSchemeDetailedProblemVO.TableContent();
tableContent.setPosition(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口");
tableContent.setPositionCode(dirCode.toString());
// 流量加总
int flow = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToInt(CrossDirDataHistPO::getFlow)
.sum();
tableContent.setFlow(flow);
// 溢流率取最大
double effusionRateMax = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getEffusionRate)
.max()
.orElse(0.0);
metricsMap.put(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getCode(),
effusionRateMax * 100 + StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getUnit());
// 方向级别三急一速数量
// 查询该方向所有的车道ID
List<String> laneIds = baseCrossDirInfoMapper.selectLaneIds(crossId, dirCode);
// 加总该方向的三急一速
Integer emergencyCount = holoEventMapper.selectEmergencyCountWithLaneIds(
crossId, startTimeStamp, endTimeStamp, laneIds);
metricsMap.put(StrategyAndMetricsEnum.Metrics.EMERGENCY_COUNT.getCode(),
emergencyCount + StrategyAndMetricsEnum.Metrics.EMERGENCY_COUNT.getUnit());
// 筛选当前方向的转向数据
List<CrossTurnDataHistPO> dirTurnPOList = crossTurnDataHistPOList.stream()
.filter(item -> Objects.equals(item.getInDir(), dirCode))
.collect(Collectors.toList());
tableContent.setSubList(buildSecuritySublist(dirTurnPOList, dirCode, crossId,
startTimeStamp, endTimeStamp));
tableContent.setMetricsMap(metricsMap);
for (SchemeEvaluateSchemeDetailedProblemVO.SubTableContent content : tableContent.getSubList()) {
if (content.getHasProblem() == 1) {
tableContent.setHasProblem(1);
}
}
tableContentList.add(tableContent);
}
vo.setTableContentList(tableContentList);
// 计算指标是否合格
List<CrossDataHistPO> crossDataHistPOList = crossDataHistMapper.selectByCrossIdAndStartEnd(
crossId, startTimeStamp, endTimeStamp);
Double maxCrossSaturation = crossDataHistMapper.selectMaxSaturation(crossId, startTimeStamp, endTimeStamp);
// 绿灯间隔清空率取最大
OptionalDouble clearRateMax = crossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getClearRate)
.max();
boolean isQualified = calcSecurity(maxCrossSaturation, clearRateMax);
if (!isQualified) {
problemList.add("路口存在安全隐患");
} else {
problemList.add("路口满足安全保障需求");
}
vo.setProblems(problemList);
}
private List<SchemeEvaluateSchemeDetailedProblemVO.SubTableContent> buildSecuritySublist(
List<CrossTurnDataHistPO> currentDirTurnPOList, Integer dirCode, String crossId,
int startTimeStamp, int endTimeStamp) {
List<SchemeEvaluateSchemeDetailedProblemVO.SubTableContent> tableContentList = new ArrayList<>();
// 获取该方向的每个转向
List<String> turnTypes = currentDirTurnPOList.stream()
.map(CrossTurnDataHistPO::getTurnType)
.distinct()
.collect(Collectors.toList());
for (String turnType : turnTypes) {
SchemeEvaluateSchemeDetailedProblemVO.SubTableContent tableContent =
new SchemeEvaluateSchemeDetailedProblemVO.SubTableContent();
tableContent.setPosition(TurnConvertEnum.getDescByCode(turnType));
tableContent.setPositionCode(turnType);
tableContent.setDirCode(dirCode.toString());
Map<String, String> metricsMap = new HashMap<>();
// 流量加总
int flow = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToInt(CrossTurnDataHistPO::getFlow)
.sum();
tableContent.setFlow(flow);
// 溢流率取最大
double effusionRateMax = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getEffusionRate)
.max()
.orElse(0.0);
metricsMap.put(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getCode(),
effusionRateMax * 100 + StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getUnit());
// 转向级别三急一速数量
// 查询该转向所有的车道ID
Integer intTurnCode = BaseEnum.TurnTypeEnum.getIntCodeByStrCode(turnType);
List<String> laneIds = baseCrossTurnInfoMapper.selectLaneIds(crossId, dirCode, intTurnCode);
// 加总该转向的三急一速
Integer emergencyCount = holoEventMapper.selectEmergencyCountWithLaneIds(
crossId, startTimeStamp, endTimeStamp, laneIds);
metricsMap.put(StrategyAndMetricsEnum.Metrics.EMERGENCY_COUNT.getCode(),
emergencyCount + StrategyAndMetricsEnum.Metrics.EMERGENCY_COUNT.getUnit());
tableContent.setMetricsMap(metricsMap);
tableContentList.add(tableContent);
}
return tableContentList;
}
private void buildBalanceDetailVO(List<CrossDirDataHistPO> crossDirDataHistPOList,
List<CrossTurnDataHistPO> crossTurnDataHistPOList,
SchemeEvaluateSchemeDetailedProblemVO vo, String crossId) {
List<String> problemList = new ArrayList<>();
List<SchemeEvaluateSchemeDetailedProblemVO.TableContent> tableContentList = new ArrayList<>();
// 获取路口方向
List<Integer> dirCodes = baseCrossDirInfoMapper.selectInDirsByCrossId(crossId);
for (Integer dirCode : dirCodes) {
Map<String, String> metricsMap = new HashMap<>();
SchemeEvaluateSchemeDetailedProblemVO.TableContent tableContent =
new SchemeEvaluateSchemeDetailedProblemVO.TableContent();
tableContent.setPosition(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口");
tableContent.setPositionCode(dirCode.toString());
// 流量加总
int flow = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToInt(CrossDirDataHistPO::getFlow)
.sum();
tableContent.setFlow(flow);
// 绿灯有效利用率取最大
double greenLightEfficiencyMax = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getGreenLightEfficiency)
.max()
.orElse(0.0);
long greenLightEfficiencyMaxLong = Math.round(greenLightEfficiencyMax * 100);
metricsMap.put(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getCode(),
greenLightEfficiencyMaxLong + StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getUnit());
// 饱和度取最大
double maxSaturation = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getSturation)
.max()
.orElse(0.0);
metricsMap.put(StrategyAndMetricsEnum.Metrics.SATURATION.getCode(),
maxSaturation + StrategyAndMetricsEnum.Metrics.SATURATION.getUnit());
// 筛选当前方向的转向数据
List<CrossTurnDataHistPO> dirTurnPOList = crossTurnDataHistPOList.stream()
.filter(item -> Objects.equals(item.getInDir(), dirCode))
.collect(Collectors.toList());
tableContent.setSubList(buildBalanceSublist(problemList, dirTurnPOList, dirCode));
tableContent.setMetricsMap(metricsMap);
for (SchemeEvaluateSchemeDetailedProblemVO.SubTableContent content : tableContent.getSubList()) {
if (content.getHasProblem() == 1) {
tableContent.setHasProblem(1);
}
}
tableContentList.add(tableContent);
}
vo.setTableContentList(tableContentList);
if (CollectionUtil.isNotEmpty(problemList)) {
problemList.add("其他方向均衡状况良好");
} else {
problemList.add("各方向均衡状况良好");
}
vo.setProblems(problemList);
}
private List<SchemeEvaluateSchemeDetailedProblemVO.SubTableContent> buildBalanceSublist(
List<String> problemList, List<CrossTurnDataHistPO> currentDirTurnPOList, Integer dirCode) {
List<SchemeEvaluateSchemeDetailedProblemVO.SubTableContent> tableContentList = new ArrayList<>();
// 获取该方向的每个转向
List<String> turnTypes = currentDirTurnPOList.stream()
.map(CrossTurnDataHistPO::getTurnType)
.distinct()
.collect(Collectors.toList());
for (String turnType : turnTypes) {
SchemeEvaluateSchemeDetailedProblemVO.SubTableContent tableContent =
new SchemeEvaluateSchemeDetailedProblemVO.SubTableContent();
tableContent.setPosition(TurnConvertEnum.getDescByCode(turnType));
tableContent.setPositionCode(turnType);
tableContent.setDirCode(dirCode.toString());
Map<String, String> metricsMap = new HashMap<>();
// 流量加总
int flow = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToInt(CrossTurnDataHistPO::getFlow)
.sum();
tableContent.setFlow(flow);
// 绿灯有效利用率取最大
double greenLightEfficiencyMax = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getGreenLightEfficiency)
.max()
.orElse(0.0);
long greenLightEfficiencyMaxLong = Math.round(greenLightEfficiencyMax * 100);
metricsMap.put(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getCode(),
greenLightEfficiencyMaxLong + StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getUnit());
// 饱和度取最大
double maxSaturation = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getSturation)
.max()
.orElse(0);
metricsMap.put(StrategyAndMetricsEnum.Metrics.SATURATION.getCode(),
maxSaturation + StrategyAndMetricsEnum.Metrics.SATURATION.getUnit());
// 计算指标是否合格
boolean isQualified = calcBalance(maxSaturation, greenLightEfficiencyMax);
if (!isQualified) {
tableContent.setHasProblem(1);
problemList.add(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口"
+ TurnConvertEnum.getDescByCode(turnType) + "失衡");
}
tableContent.setMetricsMap(metricsMap);
tableContentList.add(tableContent);
}
return tableContentList;
}
private void buildEfficiencyDetailVO(List<CrossDirDataHistPO> crossDirDataHistPOList,
List<CrossTurnDataHistPO> crossTurnDataHistPOList,
SchemeEvaluateSchemeDetailedProblemVO vo, String crossId) {
List<String> problemList = new ArrayList<>();
List<SchemeEvaluateSchemeDetailedProblemVO.TableContent> tableContentList = new ArrayList<>();
// 获取路口方向
List<Integer> dirCodes = baseCrossDirInfoMapper.selectInDirsByCrossId(crossId);
for (Integer dirCode : dirCodes) {
Map<String, String> metricsMap = new HashMap<>();
SchemeEvaluateSchemeDetailedProblemVO.TableContent tableContent =
new SchemeEvaluateSchemeDetailedProblemVO.TableContent();
tableContent.setPosition(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口");
tableContent.setPositionCode(dirCode.toString());
// 流量加总
int flow = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToInt(CrossDirDataHistPO::getFlow)
.sum();
tableContent.setFlow(flow);
// 速度取平均
double speed = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getSpeed)
.average()
.orElse(0.0);
long speedLong = Math.round(speed);
metricsMap.put(StrategyAndMetricsEnum.Metrics.AVERAGE_SPEED.getCode(),
speedLong + StrategyAndMetricsEnum.Metrics.AVERAGE_SPEED.getUnit());
// 延误取最大
int maxDelayTime = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToInt(CrossDirDataHistPO::getDelayTime)
.max()
.orElse(0);
metricsMap.put(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getCode(),
maxDelayTime + StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getUnit());
// 排队长度取最大
double maxQueueLength = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getQueueLength)
.max()
.orElse(0.0);
long queueLengthLong = Math.round(maxQueueLength);
metricsMap.put(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getCode(),
queueLengthLong + StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getUnit());
// 不停车通过率取平均
double noStopRate = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getNoStopRate)
.average()
.orElse(0.0);
long noStopRateLong = Math.round(noStopRate * 100);
metricsMap.put(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getCode(),
noStopRateLong + StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getUnit());
// 一/二/三次及以上停车通过率取最大
double stopRate = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getOneStopRate)
.max()
.orElse(0.0);
long stopRateLong = Math.round(stopRate * 100);
metricsMap.put(StrategyAndMetricsEnum.Metrics.STOP_RATE.getCode(),
stopRateLong + StrategyAndMetricsEnum.Metrics.STOP_RATE.getUnit());
// 停车次数取最大
double stopTimes = crossDirDataHistPOList.stream()
.filter(item -> Objects.equals(item.getDirType(), dirCode)
&& Objects.equals(item.getInOutType(), CrossInOutEnum.IN.getCode()))
.mapToDouble(CrossDirDataHistPO::getStopTimes)
.max()
.orElse(0.0);
long stopTimesLong = Math.round(stopTimes);
metricsMap.put(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getCode(),
stopTimesLong + StrategyAndMetricsEnum.Metrics.STOP_TIMES.getUnit());
// 筛选当前方向的转向数据
List<CrossTurnDataHistPO> dirTurnPOList = crossTurnDataHistPOList.stream()
.filter(item -> Objects.equals(item.getInDir(), dirCode))
.collect(Collectors.toList());
tableContent.setSubList(buildEfficiencySublist(problemList, dirTurnPOList, dirCode));
tableContent.setMetricsMap(metricsMap);
for (SchemeEvaluateSchemeDetailedProblemVO.SubTableContent content : tableContent.getSubList()) {
if (content.getHasProblem() == 1) {
tableContent.setHasProblem(1);
}
}
tableContentList.add(tableContent);
}
vo.setTableContentList(tableContentList);
if (CollectionUtil.isNotEmpty(problemList)) {
problemList.add("其他方向运行效率良好");
} else {
problemList.add("各方向运行效率良好");
}
vo.setProblems(problemList);
}
private List<SchemeEvaluateSchemeDetailedProblemVO.SubTableContent> buildEfficiencySublist(
List<String> problemList, List<CrossTurnDataHistPO> currentDirTurnPOList, Integer dirCode) {
List<SchemeEvaluateSchemeDetailedProblemVO.SubTableContent> tableContentList = new ArrayList<>();
// 获取该方向的每个转向
List<String> turnTypes = currentDirTurnPOList.stream()
.map(CrossTurnDataHistPO::getTurnType)
.distinct()
.collect(Collectors.toList());
for (String turnType : turnTypes) {
SchemeEvaluateSchemeDetailedProblemVO.SubTableContent tableContent =
new SchemeEvaluateSchemeDetailedProblemVO.SubTableContent();
tableContent.setPosition(TurnConvertEnum.getDescByCode(turnType));
tableContent.setPositionCode(turnType);
tableContent.setDirCode(dirCode.toString());
Map<String, String> metricsMap = new HashMap<>();
// 流量加总
int flow = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToInt(CrossTurnDataHistPO::getFlow)
.sum();
tableContent.setFlow(flow);
// 速度取平均
double speed = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getSpeed)
.average()
.orElse(0.0);
long speedLong = Math.round(speed);
metricsMap.put(StrategyAndMetricsEnum.Metrics.AVERAGE_SPEED.getCode(),
speedLong + StrategyAndMetricsEnum.Metrics.AVERAGE_SPEED.getUnit());
// 延误取最大
int maxDelayTime = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToInt(CrossTurnDataHistPO::getDelayTime)
.max()
.orElse(0);
metricsMap.put(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getCode(),
maxDelayTime + StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getUnit());
// 排队长度取最大
double maxQueueLength = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getQueueLength)
.max()
.orElse(0.0);
long queueLengthLong = Math.round(maxQueueLength);
metricsMap.put(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getCode(),
queueLengthLong + StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getUnit());
// 不停车通过率取平均
double noStopRate = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getNoStopRate)
.average()
.orElse(0.0);
long noStopRateLong = Math.round(noStopRate * 100);
metricsMap.put(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getCode(),
noStopRateLong + StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getUnit());
// 一/二/三次及以上停车通过率取最大
double stopRate = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getOneStopRate)
.max()
.orElse(0.0);
long stopRateLong = Math.round(stopRate * 100);
metricsMap.put(StrategyAndMetricsEnum.Metrics.STOP_RATE.getCode(),
stopRateLong + StrategyAndMetricsEnum.Metrics.STOP_RATE.getUnit());
// 停车次数取最大
double stopTimes = currentDirTurnPOList.stream()
.filter(item -> Objects.equals(item.getTurnType(), turnType))
.mapToDouble(CrossTurnDataHistPO::getStopTimes)
.max()
.orElse(0.0);
long stopTimesLong = Math.round(stopTimes);
metricsMap.put(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getCode(),
stopTimesLong + StrategyAndMetricsEnum.Metrics.STOP_TIMES.getUnit());
// 计算指标是否合格
int level = CrossUtil.calcEfficiencyLevel(maxDelayTime, maxQueueLength);
if (level == 3) {
tableContent.setHasProblem(1);
problemList.add(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口"
+ TurnConvertEnum.getDescByCode(turnType) + "延误较高效率较低");
} else if (level == 4) {
tableContent.setHasProblem(1);
problemList.add(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口"
+ TurnConvertEnum.getDescByCode(turnType) + "延误高效率低");
}
tableContent.setMetricsMap(metricsMap);
tableContentList.add(tableContent);
}
return tableContentList;
}
private void buildSecurityVO(List<CrossDataHistPO> crossDataHistPOList,
List<CrossDirDataHistPO> crossDirDataHistPOList,
SchemeEvaluateSchemeDetailOverallVO vo, String crossId,
int startTimeStamp, int endTimeStamp) {
List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> overallMetricsList = new ArrayList<>();
// 溢流率取最大
OptionalDouble effusionMax = crossDirDataHistPOList.stream()
.mapToDouble(CrossDirDataHistPO::getEffusionRate)
.max();
if (effusionMax.isPresent()) {
int intMax = (int) Math.round(effusionMax.getAsDouble() * 100);
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildEffusionOverallMetrics(intMax);
overallMetricsList.add(overallMetrics);
} else {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildEffusionOverallMetrics(0);
overallMetricsList.add(overallMetrics);
// throw new RuntimeException("该时段无溢流率数据");
}
// 绿灯间隔清空率取最大
OptionalDouble clearRateMax = crossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getClearRate)
.max();
if (clearRateMax.isPresent()) {
int intMax = (int) Math.round(clearRateMax.getAsDouble());
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildClearRateOverallMetrics(intMax);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无绿灯间隔清空率数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildClearRateOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
// 路口级别三急一速数量
Integer emergencyCount = holoEventMapper.selectCrossEmergencyCount(crossId, startTimeStamp, endTimeStamp);
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildEmergencyCountOverallMetrics(emergencyCount);
overallMetricsList.add(overallMetrics);
vo.setOverallMetricsList(overallMetricsList);
// 查询路口指标数值(都取最大),并与评价标准比较:如果饱和度<0.8,则需绿灯间隔清空率大于70%;如果饱和度>0.8,则需绿灯间隔清空率大于60%
// 达到指标要求,显示路口满足安全保障策略需求;未达到指标,显示路口存在安全隐患
List<String> strategyEvaluateList = new ArrayList<>();
boolean isQualified = false;
Double maxSaturation = crossDataHistMapper.selectMaxSaturation(crossId, startTimeStamp, endTimeStamp);
if (clearRateMax.isPresent()) {
isQualified = calcSecurity(maxSaturation, clearRateMax);
}
if (!isQualified) {
strategyEvaluateList.add("路口存在安全隐患");
}
if (CollectionUtil.isEmpty(strategyEvaluateList)) {
strategyEvaluateList.add("路口满足安全保障策略需求");
}
vo.setStrategyEvaluateList(strategyEvaluateList);
}
private boolean calcSecurity(Double maxSaturation, OptionalDouble clearRateMax) {
double clearRateMaxDouble = clearRateMax.getAsDouble();
// 如果饱和度<0.8,则需绿灯间隔清空率大于70%;如果饱和度>0.8,则需绿灯间隔清空率大于60%
if (maxSaturation < 0.8 && clearRateMaxDouble > 0.7) {
return true;
} else if (maxSaturation >= 0.8 && clearRateMaxDouble > 0.6) {
return true;
}
return false;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildEmergencyCountOverallMetrics(
Integer emergencyCount) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.EMERGENCY_COUNT.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.EMERGENCY_COUNT.getDescription());
overallMetrics.setMetricValue(emergencyCount);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.EMERGENCY_COUNT.getUnit());
return overallMetrics;
}
private void buildBalanceVO(List<CrossDataHistPO> crossDataHistPOList,
List<CrossDirDataHistPO> crossDirDataHistPOList,
SchemeEvaluateSchemeDetailOverallVO vo, String crossId,
int startTimeStamp, int endTimeStamp) {
List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> overallMetricsList = new ArrayList<>();
// 绿灯有效利用率取最大
OptionalDouble greenLightEfficiencyMax = crossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getGreenLightEfficiency)
.filter(Objects::nonNull)
.max();
if (greenLightEfficiencyMax.isPresent()) {
int intGreenLightEfficiencyMax = (int) Math.round(greenLightEfficiencyMax.getAsDouble() * 100);
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildGreenLightUseOverallMetrics(intGreenLightEfficiencyMax);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无绿灯有效利用率数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildGreenLightUseOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
// 饱和度取最大
OptionalDouble saturationMax = crossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getSturation)
.filter(Objects::nonNull)
.max();
if (saturationMax.isPresent()) {
int intMax = (int) Math.round(saturationMax.getAsDouble());
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildSaturationMaxOverallMetrics(intMax);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无饱和度数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildSaturationMaxOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
// 负载均衡度取最大
OptionalDouble loadBalanceMax = crossDataHistPOList.stream()
.map(CrossDataHistPO::getLoadBalance)
.filter(Objects::nonNull)
.mapToDouble(Double::doubleValue) // 将Double转换为double
.max();
if (loadBalanceMax.isPresent()) {
int intMax = (int) Math.round(loadBalanceMax.getAsDouble());
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildLoadBalanceOverallMetrics(intMax);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无负载均衡度数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildLoadBalanceOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
vo.setOverallMetricsList(overallMetricsList);
// 查询方向指标数值(都取最大),并与评价标准比较:如果饱和度<0.8,则需绿灯利用率大于50%;如果饱和度>0.8,则需绿灯利用率大于80%
// 未达到指标,显示xx方向失衡;达到指标要求,显示路口满足均衡调控策略需求
// 获取路口方向
List<Integer> dirCodes = baseCrossDirInfoMapper.selectInDirsByCrossId(crossId);
List<String> strategyEvaluateList = new ArrayList<>();
for (Integer dirCode : dirCodes) {
Double maxSaturation = crossDirDataHistMapper.selectMaxSaturation(
crossId, dirCode, CrossInOutEnum.IN.getCode(), startTimeStamp, endTimeStamp);
Double maxGreenLightUse = crossDirDataHistMapper.selectMaxGreenLightEfficiency(
crossId, dirCode, CrossInOutEnum.IN.getCode(), startTimeStamp, endTimeStamp);
boolean isQualified = calcBalance(maxSaturation, maxGreenLightUse);
if (!isQualified) {
strategyEvaluateList.add(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口方向失衡");
}
}
if (CollectionUtil.isEmpty(strategyEvaluateList)) {
strategyEvaluateList.add("路口满足均衡调控策略需求");
}
vo.setStrategyEvaluateList(strategyEvaluateList);
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildClearRateOverallMetrics(int intMax) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.CLEAR_RATE.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.CLEAR_RATE.getDescription());
overallMetrics.setMetricValue(intMax);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.CLEAR_RATE.getUnit());
return overallMetrics;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildEffusionOverallMetrics(int intMax) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getDescription());
overallMetrics.setMetricValue(intMax);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.EFFUSION_RATE.getUnit());
return overallMetrics;
}
private boolean calcBalance(Double maxSaturation, Double greenLightEfficiencyMax) {
// 如果饱和度<0.8,则需绿灯利用率大于50%;如果饱和度>0.8,则需绿灯利用率大于80%
if (Objects.nonNull(maxSaturation) && Objects.nonNull(greenLightEfficiencyMax)) {
if (maxSaturation < 0.8 && greenLightEfficiencyMax > 0.5) {
return true;
} else if (maxSaturation >= 0.8 && greenLightEfficiencyMax > 0.8) {
return true;
}
}
return false;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildLoadBalanceOverallMetrics(
int intMax) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.LOAD_BALANCE.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.LOAD_BALANCE.getDescription());
overallMetrics.setMetricValue(intMax);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.LOAD_BALANCE.getUnit());
return overallMetrics;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildSaturationMaxOverallMetrics(
int intMax) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.SATURATION.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.SATURATION.getDescription());
overallMetrics.setMetricValue(intMax);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.SATURATION.getUnit());
return overallMetrics;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildGreenLightUseOverallMetrics(
int intGreenLightEfficiencyMax) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getDescription());
overallMetrics.setMetricValue(intGreenLightEfficiencyMax);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.GREEN_LIGHT_EFFICIENCY.getUnit());
return overallMetrics;
}
private void buildEfficiencyVO(List<CrossDataHistPO> crossDataHistPOList,
List<CrossDirDataHistPO> crossDirDataHistPOList,
SchemeEvaluateSchemeDetailOverallVO vo, String crossId,
int startTimeStamp, int endTimeStamp) {
List<SchemeEvaluateSchemeDetailOverallVO.OverallMetrics> overallMetricsList = new ArrayList<>();
// 排队长度取最大
OptionalDouble queueLengthMax = crossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getQueueLength)
.max();
if (queueLengthMax.isPresent()) {
// 四舍五入并转换为 int 类型
int intQueueLengthAverage = (int) Math.round(queueLengthMax.getAsDouble());
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildQueueLengthOverallMetrics(intQueueLengthAverage);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无最大排队数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildQueueLengthOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
// 延误取最大
OptionalInt delayTimeMax = crossDataHistPOList.stream()
.mapToInt(CrossDataHistPO::getDelayTime)
.max();
if (delayTimeMax.isPresent()) {
int intDelayTimeAverage = delayTimeMax.getAsInt();
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildDelayTimeOverallMetrics(intDelayTimeAverage);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无延误数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildDelayTimeOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
// 停车次数取最大
OptionalDouble stopTimesMax = crossDataHistPOList.stream()
.mapToDouble(CrossDataHistPO::getStopTimes)
.max();
if (stopTimesMax.isPresent()) {
// 四舍五入并转换为 int 类型
int intStopTimesAverage = (int) Math.round(stopTimesMax.getAsDouble());
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildStopTimesOverallMetrics(intStopTimesAverage);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无停车次数数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildStopTimesOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
// 不停车通过率取最大
OptionalDouble noStopRateMax = crossDirDataHistPOList.stream()
.mapToDouble(CrossDirDataHistPO::getNoStopRate)
.max();
if (noStopRateMax.isPresent()) {
// 先乘以100,再四舍五入并转换为 int 类型
int intStopTimesAverage = (int) Math.round(noStopRateMax.getAsDouble() * 100);
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildNoStopRateOverallMetrics(intStopTimesAverage);
overallMetricsList.add(overallMetrics);
} else {
// throw new RuntimeException("该时段无不停车通过率数据");
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
buildNoStopRateOverallMetrics(0);
overallMetricsList.add(overallMetrics);
}
vo.setOverallMetricsList(overallMetricsList);
// 查询方向指标数值(都取最大),并与评价标准比较
// 获取路口方向
List<Integer> dirCodes = baseCrossDirInfoMapper.selectInDirsByCrossId(crossId);
List<String> strategyEvaluateList = new ArrayList<>();
for (Integer dirCode : dirCodes) {
Integer maxDelayTime = crossDirDataHistMapper.selectMaxDelayTime(
crossId, dirCode, CrossInOutEnum.IN.getCode(), startTimeStamp, endTimeStamp);
Double maxQueueLength = crossDirDataHistMapper.selectMaxQueueLength(
crossId, dirCode, CrossInOutEnum.IN.getCode(), startTimeStamp, endTimeStamp);
int level = CrossUtil.calcEfficiencyLevel(maxDelayTime, maxQueueLength);
if (level == 3) {
strategyEvaluateList.add(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口延误较高效率较低");
} else if (level == 4) {
strategyEvaluateList.add(BaseEnum.SignalDirectionEnum.getNameByCode(dirCode) + "进口延误高效率低");
}
}
if (CollectionUtil.isEmpty(strategyEvaluateList)) {
strategyEvaluateList.add("路口满足效率提升策略需求");
}
vo.setStrategyEvaluateList(strategyEvaluateList);
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildNoStopRateOverallMetrics(
int intStopTimesAverage) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getDescription());
overallMetrics.setMetricValue(intStopTimesAverage);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.NO_STOP_RATE.getUnit());
return overallMetrics;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildStopTimesOverallMetrics(
int intStopTimesAverage) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getDescription());
overallMetrics.setMetricValue(intStopTimesAverage);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.STOP_TIMES.getUnit());
return overallMetrics;
}
private SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildDelayTimeOverallMetrics(
int intDelayTimeAverage) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getDescription());
overallMetrics.setMetricValue(intDelayTimeAverage);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.AVERAGE_DELAY.getUnit());
return overallMetrics;
}
@NotNull
private static SchemeEvaluateSchemeDetailOverallVO.OverallMetrics buildQueueLengthOverallMetrics(
int intQueueLengthAverage) {
SchemeEvaluateSchemeDetailOverallVO.OverallMetrics overallMetrics =
new SchemeEvaluateSchemeDetailOverallVO.OverallMetrics();
overallMetrics.setMetricCode(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getCode());
overallMetrics.setMetricName(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getDescription());
overallMetrics.setMetricValue(intQueueLengthAverage);
overallMetrics.setMetricUnit(StrategyAndMetricsEnum.Metrics.MAX_QUEUE_LENGTH.getUnit());
return overallMetrics;
}
@NotNull
private static SchemeEvaluateCrossSchemeListVO buildSchemeEvaluateCrossSchemeListVO
(BaseCrossSchemePO baseCrossSchemePO, CrossSectionPO crossSectionPO) {
SchemeEvaluateCrossSchemeListVO vo = new SchemeEvaluateCrossSchemeListVO();
vo.setSchemeName(baseCrossSchemePO.getName());
vo.setSchemeId(baseCrossSchemePO.getId());
vo.setStartTime(crossSectionPO.getStartTime());
vo.setEndTime(crossSectionPO.getEndTime());
vo.setSectionId(crossSectionPO.getId());
vo.setSchemeNo(baseCrossSchemePO.getSchemeNo());
vo.setCycle(baseCrossSchemePO.getCycle());
vo.setNote("");
return vo;
}
private boolean isNumeric(String str) {
return str != null && str.matches("[0-9]+");
}
private List<SchemeEvaluateProblemSchemeVO.BySchemeVO> buildProblemSchemeListByScheme(
Map<Date, List<RunningEvaluateMetricsDetailVO.ProblemScheme>> dateSchemesMap) {
// 使用一个Map来临时存储按方案名称分组的数据
Map<String, List<SchemeEvaluateProblemSchemeVO.SchemeDatetime>> tempMap = new HashMap<>();
for (Map.Entry<Date, List<RunningEvaluateMetricsDetailVO.ProblemScheme>> entry : dateSchemesMap.entrySet()) {
Date date = entry.getKey();
List<RunningEvaluateMetricsDetailVO.ProblemScheme> problemSchemes = entry.getValue();
for (RunningEvaluateMetricsDetailVO.ProblemScheme problemScheme : problemSchemes) {
Integer schemeId = problemScheme.getSchemeId();
String schemeName = problemScheme.getSchemeName();
String schemeIdName = schemeId + "_" + schemeName;
SchemeEvaluateProblemSchemeVO.SchemeDatetime schemeDatetime =
new SchemeEvaluateProblemSchemeVO.SchemeDatetime();
schemeDatetime.setYear(date);
schemeDatetime.setWeek(DateUtil.dayOfWeek(date));
schemeDatetime.setProblemDate(date);
schemeDatetime.setStartTime(problemScheme.getStartTime());
schemeDatetime.setEndTime(problemScheme.getEndTime());
tempMap.computeIfAbsent(schemeIdName, k -> new ArrayList<>()).add(schemeDatetime);
}
}
// 构建最终的 List<BySchemeVO>
List<SchemeEvaluateProblemSchemeVO.BySchemeVO> bySchemeVOList = tempMap.entrySet().stream()
.map(entry -> {
SchemeEvaluateProblemSchemeVO.BySchemeVO bySchemeVO = new SchemeEvaluateProblemSchemeVO.BySchemeVO();
String schemeIdName = entry.getKey();
String[] s = schemeIdName.split("_");
bySchemeVO.setSchemeId(Integer.parseInt(s[0]));
bySchemeVO.setSchemeName(s[1]);
bySchemeVO.setSchemeDatetimeList(entry.getValue());
return bySchemeVO;
})
.collect(Collectors.toList());
return bySchemeVOList;
}
private int calcProblemCounts(List<SchemeEvaluateProblemSchemeVO.ByDateVO> byDateVOList,
Function<SchemeEvaluateProblemSchemeVO.ByDateVO, Integer> getCount) {
return byDateVOList.stream().mapToInt(getCount::apply).sum();
}
private int calcSchemeCounts(Map<Date, List<RunningEvaluateMetricsDetailVO.ProblemScheme>> dateSchemesMap) {
Set<Integer> problemIdSet = new HashSet<>();
Collection<List<RunningEvaluateMetricsDetailVO.ProblemScheme>> values = dateSchemesMap.values();
for (List<RunningEvaluateMetricsDetailVO.ProblemScheme> list : values) {
for (RunningEvaluateMetricsDetailVO.ProblemScheme problemScheme : list) {
Integer schemeId = problemScheme.getSchemeId();
problemIdSet.add(schemeId);
}
}
return problemIdSet.size();
}
@NotNull
private List<SchemeEvaluateProblemSchemeVO.ByDateVO> buildProblemSchemeListByDate(
Map<Date, List<CrossDataHistPO>> dateProblemsMap,
Map<Date, List<RunningEvaluateMetricsDetailVO.ProblemScheme>> dateSchemesMap, List<ScenePO> scenePOList) {
List<SchemeEvaluateProblemSchemeVO.ByDateVO> byDateVOList = new ArrayList<>();
List<SceneStrategyPO> sceneStrategyPOList = sceneStrategyMapper.selectAll();
List<StrategyPO> strategyPOList = strategyMapper.selectAll();
for (Map.Entry<Date, List<CrossDataHistPO>> entry : dateProblemsMap.entrySet()) {
Date key = entry.getKey();
SchemeEvaluateProblemSchemeVO.ByDateVO byDateVO = new SchemeEvaluateProblemSchemeVO.ByDateVO();
byDateVO.setProblemDate(key);
List<RunningEvaluateMetricsDetailVO.ProblemScheme> problemSchemeList = dateSchemesMap.get(key);
byDateVO.setSectionSechemeList(problemSchemeList);
List<CrossDataHistPO> value = entry.getValue();
int efficiencyProblemCounts = 0;
int balanceProblemCounts = 0;
int securityProblemCounts = 0;
for (CrossDataHistPO crossDataHistPO : value) {
Integer status = crossDataHistPO.getStatus();
// 根据场景查询策略
Optional<ScenePO> first = scenePOList.stream()
.filter(po -> status.equals(po.getSceneNum()))
.findFirst();
ScenePO scenePO = first.get();
Integer sceneId = scenePO.getId();
List<SceneStrategyPO> sceneStrategyList = sceneStrategyPOList.stream()
.filter(po -> sceneId.equals(po.getSceneId()))
.collect(Collectors.toList());
for (SceneStrategyPO sceneStrategyPO : sceneStrategyList) {
Integer strategyId = sceneStrategyPO.getStrategyId();
Optional<StrategyPO> first1 = strategyPOList.stream()
.filter(po -> strategyId.equals(po.getId()))
.findFirst();
StrategyPO strategyPO = first1.get();
String strategyCode = strategyPO.getStrategyCode();
if (strategyCode.equals(StrategyAndMetricsEnum.Strategy.EFFICIENCY.getCode())) {
efficiencyProblemCounts += 1;
} else if (strategyCode.equals(StrategyAndMetricsEnum.Strategy.BALANCE.getCode())) {
balanceProblemCounts += 1;
} else if (strategyCode.equals(StrategyAndMetricsEnum.Strategy.SECURITY.getCode())) {
securityProblemCounts += 1;
}
}
}
byDateVO.setEfficiencyProblemCounts(efficiencyProblemCounts);
byDateVO.setBalanceProblemCounts(balanceProblemCounts);
byDateVO.setSecurityProblemCounts(securityProblemCounts);
byDateVOList.add(byDateVO);
}
return byDateVOList;
}
private Map<Date, List<RunningEvaluateMetricsDetailVO.ProblemScheme>> buildDateSchemesMap(
Map<Date, List<CrossDataHistPO>> dateProblemsMap, String crossId, List<CrossSectionPO> crossSectionPOList,
List<BaseCrossSchemePO> crossSchemePOList) {
Map<Date, List<RunningEvaluateMetricsDetailVO.ProblemScheme>> dateSchemesMap = new HashMap<>();
// 获取当前计划ID
for (Map.Entry<Date, List<CrossDataHistPO>> dateListEntry : dateProblemsMap.entrySet()) {
List<RunningEvaluateMetricsDetailVO.ProblemScheme> problemSchemeList = new ArrayList<>();
Date datetime = dateListEntry.getKey();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateStr = sdf.format(datetime);
Integer planId = runningEvaluateService.findPlanId(datetime, dateStr, crossId);
List<CrossSectionPO> filteredList = crossSectionPOList.stream()
.filter(crossSection -> crossId.equals(crossSection.getCrossId()) &&
planId.equals(crossSection.getPlanId()))
.collect(Collectors.toList());
for (CrossSectionPO crossSectionPO : filteredList) {
String sectionStartTime = crossSectionPO.getStartTime();
String sectionEndTime = crossSectionPO.getEndTime();
List<CrossDataHistPO> value = dateListEntry.getValue();
for (CrossDataHistPO crossDataHistPO : value) {
SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm");
Date abnormalEventStartTime = crossDataHistPO.getStartTime();
Integer duration = crossDataHistPO.getDuration();
Date abnormalEventEndTime = DateUtil.offsetMinute(abnormalEventStartTime, duration);
String eventStartTime = sdf2.format(abnormalEventStartTime);
String eventEndTime = sdf2.format(abnormalEventEndTime);
// 比较两组时间段是否相交
boolean isIntersecting = runningEvaluateService.isTimeIntersecting(
eventStartTime, eventEndTime, sectionStartTime, sectionEndTime);
runningEvaluateService.buildResIfIntersecting(problemSchemeList, crossSectionPO, sectionStartTime,
sectionEndTime, isIntersecting, crossSchemePOList);
}
}
// 去除相同方案
List<RunningEvaluateMetricsDetailVO.ProblemScheme> uniqueRes = problemSchemeList.stream()
.distinct()
.collect(Collectors.toList());
dateSchemesMap.put(datetime, uniqueRes);
}
return dateSchemesMap;
}
private Map<Date, List<CrossDataHistPO>> buildDateProblemsMap(Map<String, List<CrossDataHistPO>> timeProblemMap) {
// 创建一个新的Map,用于存储以Date为Key,List<CrossDataHistPO>为Value的数据
Map<Date, List<CrossDataHistPO>> dateMap = new HashMap<>();
// 创建一个SimpleDateFormat对象,用于将10位时间戳转换为Date对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 遍历timeProblemMap的所有entries
for (List<CrossDataHistPO> list : timeProblemMap.values()) {
for (CrossDataHistPO po : list) {
long timestamp = po.getBatchTime() * 1000L; // 将10位时间戳转换为13位
Date date = new Date(timestamp);
String formattedDate = sdf.format(date); // 格式化日期为"yyyy-MM-dd"
try {
Date keyDate = sdf.parse(formattedDate); // 将格式化后的日期字符串转回为Date对象
// 将CrossDataHistPO对象添加到相应日期的List中
dateMap.computeIfAbsent(keyDate, k -> new ArrayList<>()).add(po);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return dateMap;
}
@NotNull
private static Map<String, List<CrossDataHistPO>> getTimeProblemMap(
List<CrossDataHistPO> crossDataHistPOList, String endTime, String startTime) {
// 过滤有问题的记录
List<CrossDataHistPO> filteredList = crossDataHistPOList.stream()
.filter(po -> po.getStatus() != null && po.getStatus() != 0)
.collect(Collectors.toList());
// 保留 duration 最大的一条
List<CrossDataHistPO> result = filteredList.stream()
.collect(Collectors.groupingBy(CrossDataHistPO::getStartTime))
.values().stream()
.map(list -> list.stream().max(Comparator.comparingInt(CrossDataHistPO::getDuration)).orElse(null))
.collect(Collectors.toList());
// 按照 startTime 和 endTime 的 "HH:mm" 的时间区间分组
Map<String, List<CrossDataHistPO>> groupedByTimeInterval = result.stream()
.collect(Collectors.groupingBy(po -> {
Date startTime1 = po.getStartTime();
Date endTime1 = new Date(startTime1.getTime() + po.getDuration() * 60 * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
return sdf.format(startTime1) + " - " + sdf.format(endTime1);
}));
// 过滤 groupedByTimeInterval,保留与 startTime 和 endTime 有交叉的条目
Map<String, List<CrossDataHistPO>> filteredGroupedByTimeInterval = groupedByTimeInterval.entrySet().stream()
.filter(entry -> {
String[] times = entry.getKey().split(" - ");
String groupStartTime = times[0];
String groupEndTime = times[1];
return (groupStartTime.compareTo(endTime) < 0 || groupStartTime.equals(endTime))
&& (groupEndTime.compareTo(startTime) > 0 || groupEndTime.equals(startTime));
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return filteredGroupedByTimeInterval;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
package net.wanji.opt.service.signalcontrol;
import net.wanji.common.framework.rest.JsonViewObject;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.dto.CrossIdDateTimeDTO;
import net.wanji.databus.vo.ControlCommandVO;
import net.wanji.databus.vo.SchemeOptSendVO;
/**
* @author duanruiming
* @date 2023/03/01 20:59
*/
public interface FeignProxyService {
JsonViewObject schemeOptSend(SchemeOptSendVO schemeOptSendVO) throws Exception;
JsonViewObject schemeOptRestore(String crossId) throws Exception;
/** 增加路口红闪,黄闪,步进,相位锁定服务 20250315 /
*
* @param vo
* @return
* @throws Exception
*/
JsonViewObject allRedControl(ControlCommandVO vo) throws Exception;
JsonViewObject yellowLightControl(ControlCommandVO vo) throws Exception;
JsonViewObject stepControl(String crossId, Integer command, Integer stepNum) throws Exception;
JsonViewObject lockControl(ControlCommandVO vo) throws Exception;
JsonViewObject recoverSchedule(CrossIdBO crossIdBO) throws Exception;
JsonViewObject lightStatusOneHist(CrossIdDateTimeDTO crossIdDateTimeDTO) throws Exception;
}
package net.wanji.opt.service.signalcontrol.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.framework.exception.FeignServiceException;
import net.wanji.common.framework.rest.JsonViewObject;
import net.wanji.databus.bo.CrossIdBO;
import net.wanji.databus.dto.CrossIdDateTimeDTO;
import net.wanji.databus.entity.develop.servicedevelop.develop.StatusCodeEnum;
import net.wanji.databus.vo.ControlCommandVO;
import net.wanji.databus.vo.LockControlVO;
import net.wanji.databus.vo.SchemeSendVO;
import net.wanji.feign.service.UtcFeignClients;
import net.wanji.opt.cache.CrossDirTurnPhaseCache;
import net.wanji.opt.dao.mapper.CrossSchemeOptLogMapper;
import net.wanji.opt.dto.CrossPhaseDTO;
import net.wanji.opt.po.base.CrossSchemeOptLogPO;
import net.wanji.opt.service.impl.CrossOptimizeServiceImpl;
import net.wanji.opt.service.signalcontrol.FeignProxyService;
import net.wanji.databus.vo.SchemeOptSendVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
/**
* @author duanruiming
* @date 2023/03/02 9:11
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class FeignProxyServiceImpl implements FeignProxyService {
private final UtcFeignClients utcFeignClients;
private final CrossSchemeOptLogMapper crossSchemeOptLogMapper;
private final CrossDirTurnPhaseCache crossDirTurnPhaseCache;
private final CrossOptimizeServiceImpl crossOptimizeService;
@Override
public JsonViewObject schemeOptSend(SchemeOptSendVO schemeOptSendVO) throws Exception {
SchemeSendVO schemeSendVO = new SchemeSendVO();
BeanUtils.copyProperties(schemeOptSendVO, schemeSendVO);
JsonViewObject jsonViewObject = utcFeignClients.tempScheme(schemeOptSendVO);
if (Objects.isNull(jsonViewObject) || jsonViewObject.getCode() != 200) {
log.error("诊断优化手动下发优化方案,UTC服务调用异常", jsonViewObject);
throw new FeignServiceException("诊断优化手动下发优化方案,UTC服务调用异常");
}
// 将优化记录插入方案优化记录表
List<CrossSchemeOptLogPO> crossSchemeOptLogPOS = getCrossSchemeOptLogPOList(schemeOptSendVO);
crossSchemeOptLogMapper.insertBatch(crossSchemeOptLogPOS);
return jsonViewObject.success("手动下发优化方案成功");
}
@Override
public JsonViewObject schemeOptRestore(String crossId) throws Exception {
// 下发原始方案
Map<String, CrossPhaseDTO> phaseMap = crossDirTurnPhaseCache.getPhaseDirTurnMap();
SchemeSendVO schemeSendVO = crossOptimizeService.getSchemeSendVO(crossId, phaseMap, Collections.EMPTY_MAP);
JsonViewObject jsonViewObject = utcFeignClients.schemeSend(schemeSendVO);
if (Objects.isNull(jsonViewObject) || jsonViewObject.getCode() != 200) {
log.error("诊断优化手动恢复优化方案,UTC服务调用异常!", jsonViewObject);
throw new FeignServiceException("手动恢复优化方案,UTC服务调用异常");
}
return jsonViewObject.success("手动恢复优化方案成功");
}
/**
* 获取方案优化数据,插入到数据库
*
* @param schemeOptSendVO
* @return
*/
private List<CrossSchemeOptLogPO> getCrossSchemeOptLogPOList(SchemeOptSendVO schemeOptSendVO) {
List<CrossSchemeOptLogPO> crossSchemeOptLogPOS = new ArrayList<>();
Map<String, CrossPhaseDTO> phaseDirTurnMap = crossDirTurnPhaseCache.getPhaseDirTurnMap();
long dataBatchTimeLong = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
Map<String, Integer> phaseOffsetTimeMap = schemeOptSendVO.getPhaseOffsetTimeMap();
String crossId = schemeOptSendVO.getCrossCode();
List<SchemeSendVO.Pattern> patternList = schemeOptSendVO.getPatternList();
for (SchemeSendVO.Pattern pattern : patternList) {
String patternNo = pattern.getPatternNo();
String offset = pattern.getOffset();
List<SchemeSendVO.Pattern.Ring> rings = pattern.getRings();
for (SchemeSendVO.Pattern.Ring ring : rings) {
String ringNo = ring.getRingNo();
List<SchemeSendVO.Pattern.Ring.Phase> phaseList = ring.getPhaseList();
for (SchemeSendVO.Pattern.Ring.Phase phase : phaseList) {
String phaseNo = phase.getPhaseNo();
String greenTime = phase.getGreenTime();
Integer greenTimeOffset = phaseOffsetTimeMap.get(phaseNo);
for (Map.Entry<String, CrossPhaseDTO> entry : phaseDirTurnMap.entrySet()) {
CrossPhaseDTO crossPhaseDTO = entry.getValue();
if (StringUtils.equals(crossId, crossPhaseDTO.getCrossId()) && StringUtils.equals(phaseNo, crossPhaseDTO.getPhaseNo())) {
Integer dirType = crossPhaseDTO.getDirType();
String turnType = crossPhaseDTO.getTurnType();
CrossSchemeOptLogPO crossSchemeOptLogPO = new CrossSchemeOptLogPO();
crossSchemeOptLogPO.setCrossId(crossId);
crossSchemeOptLogPO.setSchemeId(Integer.valueOf(patternNo));
crossSchemeOptLogPO.setDirType(dirType);
crossSchemeOptLogPO.setTurnType(turnType);
crossSchemeOptLogPO.setOffset(Integer.valueOf(offset));
crossSchemeOptLogPO.setRingNo(Integer.valueOf(ringNo));
crossSchemeOptLogPO.setPhaseNo(phaseNo);
crossSchemeOptLogPO.setPhaseOrderId(Integer.valueOf(phase.getSort()));
crossSchemeOptLogPO.setOriGreenTime(Integer.valueOf(greenTime) - greenTimeOffset);
crossSchemeOptLogPO.setOptGreenTime(Integer.valueOf(greenTime));
crossSchemeOptLogPO.setOptTime(greenTimeOffset);
crossSchemeOptLogPO.setOptType(schemeOptSendVO.getOptType());
crossSchemeOptLogPO.setOptReason(schemeOptSendVO.getOptReason());
crossSchemeOptLogPO.setStartTime(new Date());
crossSchemeOptLogPO.setRelationFlag(schemeOptSendVO.getRelationFlag());
crossSchemeOptLogPO.setRelationCrossId(schemeOptSendVO.getRelationCrossId());
crossSchemeOptLogPO.setOptResult("1");
crossSchemeOptLogPO.setOptResultDesc(StatusCodeEnum.STATUS_00200.getDetail());
crossSchemeOptLogPO.setDataBatchTime((int) dataBatchTimeLong);
}
}
}
}
}
return crossSchemeOptLogPOS;
}
@Override
public JsonViewObject allRedControl(ControlCommandVO vo) throws Exception {
return utcFeignClients.allRedControl(vo);
}
@Override
public JsonViewObject yellowLightControl(ControlCommandVO vo) throws Exception {
return utcFeignClients.yellowLightControl(vo);
}
@Override
public JsonViewObject stepControl(String crossId, Integer command, Integer stepNum) throws Exception {
return utcFeignClients.stepControl(crossId, command, stepNum);
}
@Override
public JsonViewObject lockControl(ControlCommandVO vo) throws Exception {
LockControlVO lockControlVO = new LockControlVO();
lockControlVO.setCrossCode(vo.getCrossCode());
lockControlVO.setCommand(vo.getCommand());
lockControlVO.setDuration(vo.getDuration());
lockControlVO.setPhaseList(vo.getPhaseList());
return utcFeignClients.lockControl(lockControlVO);
}
@Override
public JsonViewObject recoverSchedule(CrossIdBO crossIdBO) throws Exception {
return utcFeignClients.recoverSchedule(crossIdBO.getCrossId());
}
@Override
public JsonViewObject lightStatusOneHist(CrossIdDateTimeDTO crossIdDateTimeDTO) throws Exception {
return utcFeignClients.selectLightStatusHist(crossIdDateTimeDTO);
}
}
package net.wanji.opt.service.signalopt;
import net.wanji.opt.vo.GreenBeltCrossDetailVO;
import net.wanji.opt.vo.GreenBeltFlowStopTimeVO;
import net.wanji.opt.vo.GreenBeltKeyCrossFlowTimeVO;
import net.wanji.opt.vo.GreenBeltSpeedWidthVO;
import java.util.List;
/**
* @author duanruiming
* @date 2024/11/19 18:07
*/
public interface GreenBeltInfoService {
List<GreenBeltFlowStopTimeVO> greenBeltCrossDetailHist(Integer greenId) throws Exception;
List<GreenBeltSpeedWidthVO> greenBeltSpeedWidth(Integer greenId) throws Exception;
List<GreenBeltKeyCrossFlowTimeVO> greenBeltKeyCrossFlowTime(Integer greenId) throws Exception;
GreenBeltCrossDetailVO greenBeltCrossDetailList(Integer greenId) throws Exception;
}
package net.wanji.opt.service.signalopt.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.framework.Constants;
import net.wanji.common.utils.tool.DateUtil;
import net.wanji.common.utils.tool.JacksonUtils;
import net.wanji.common.utils.tool.StringUtils;
import net.wanji.databus.dao.entity.GreenwaveCrossPO;
import net.wanji.databus.dao.entity.GreenwaveHistPO;
import net.wanji.databus.dao.entity.GreenwaveInfoPO;
import net.wanji.databus.dao.entity.GreenwaveRealtimePO;
import net.wanji.databus.dao.mapper.*;
import net.wanji.databus.po.CrossDataRealtimePO;
import net.wanji.databus.po.CrossDirDataHistPO;
import net.wanji.opt.cache.BaseCrossInfoCache;
import net.wanji.opt.cache.GreenWaveInfoCache;
import net.wanji.opt.common.enums.GreenBeltDirEnum;
import net.wanji.opt.common.enums.GreenWaveInDirEnum;
import net.wanji.opt.dao.mapper.StrategyGreenOptHistMapper;
import net.wanji.opt.po.StrategyGreenOptHistEntity;
import net.wanji.opt.service.signalopt.GreenBeltInfoService;
import net.wanji.opt.vo.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author duanruiming
* @date 2024/12/02 13:42
*/
@Service
@Slf4j
public class GreenBeltServiceImpl implements GreenBeltInfoService {
@Resource
private GreenwaveInfoMapper greenwaveInfoMapper;
@Resource
private CrossDataHistMapper crossDataHistMapper;
@Resource
private StrategyGreenOptHistMapper strategyGreenOptHistMapper;
@Resource
private GreenwaveRealtimeMapper greenwaveRealtimeMapper;
@Resource
private GreenwaveHistMapper greenwaveHistMapper;
@Resource
private GreenwaveCrossMapper greenwaveCrossMapper;
@Resource
private CrossDataRealtimeMapper crossDataRealtimeMapper;
@Resource
private BaseCrossInfoCache baseCrossInfoCache;
@Resource
private CrossDirDataHistMapper crossDirDataHistMapper;
@Override
public GreenBeltCrossDetailVO greenBeltCrossDetailList(Integer greenId) throws Exception {
List<GreenwaveCrossPO> crossPOS = greenwaveCrossMapper.selectByGreenwaveId(greenId);
List<CrossDataRealtimePO> realtimePOS = crossDataRealtimeMapper.selectAll();
GreenBeltCrossDetailVO greenBeltCrossDetailVO = new GreenBeltCrossDetailVO();
LambdaQueryWrapper<GreenwaveRealtimePO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(GreenwaveRealtimePO::getGreenId, greenId);
if (!CollectionUtils.isEmpty(crossPOS) && !CollectionUtils.isEmpty(realtimePOS)) {
List<GreenBeltCrossDetailVO.CrossDetail> detailList = new ArrayList<>();
for (GreenwaveCrossPO crossPO : crossPOS) {
String crossId = crossPO.getCrossId();
GreenBeltCrossDetailVO.CrossDetail crossDetail = new GreenBeltCrossDetailVO.CrossDetail();
for (CrossDataRealtimePO realtimePO : realtimePOS) {
if (StringUtils.equalsIgnoreCase(crossPO.getCrossId(), realtimePO.getCrossId())) {
String crossName = baseCrossInfoCache.getCrossName(crossId);
crossDetail.setCrossName(crossName);
crossDetail.setCrossIndex(realtimePO.getTrafficIndex());
detailList.add(crossDetail);
}
}
}
List<GreenwaveRealtimePO> greenRealTimes = greenwaveRealtimeMapper.selectList(queryWrapper);
if (!CollectionUtils.isEmpty(greenRealTimes)) {
double asDouble = greenRealTimes.stream().mapToDouble(GreenwaveRealtimePO::getTrafficIndex).average().getAsDouble();
greenBeltCrossDetailVO.setGreenIndex(asDouble);
}
greenBeltCrossDetailVO.setDetailList(detailList);
Map<Integer, GreenwaveInfoPO> greenWaveMap = GreenWaveInfoCache.greenWaveMap;
GreenwaveInfoPO greenwaveInfoPO = greenWaveMap.get(greenId);
greenBeltCrossDetailVO.setGreenName(greenwaveInfoPO.getName());
greenBeltCrossDetailVO.setCrossNum(detailList.size());
}
return greenBeltCrossDetailVO;
}
@Override
public List<GreenBeltKeyCrossFlowTimeVO> greenBeltKeyCrossFlowTime(Integer greenId) throws Exception {
try {
List<GreenBeltKeyCrossFlowTimeVO> results = new ArrayList<>();
LocalDate currentDate = LocalDate.now();
LocalTime startTime = LocalTime.MIDNIGHT;
LocalDateTime startOfDay = LocalDateTime.of(currentDate, startTime);
// 最少有一条数据
List<GreenBeltKeyCrossFlowTimeVO.Detail> optResults = getGreenOptList(greenId, startOfDay);
GreenBeltKeyCrossFlowTimeVO.Detail optDetail = optResults.get(0);
String crossId = optDetail.getCrossId();
GreenwaveInfoPO greenwaveInfoPO = GreenWaveInfoCache.greenWaveMap.get(greenId);
String greenDir = greenwaveInfoPO.getGreenDir();
String[] split = greenDir.split(",");
List<Integer> dirList = new ArrayList<>();
for (String s : split) {
dirList.add(Integer.valueOf(s));
}
Instant instant = startOfDay.atZone(ZoneId.systemDefault()).toInstant();
int start = (int) (instant.toEpochMilli() / 1000) + 300;
int end = (int) (System.currentTimeMillis() / 1000) + 300;
List<CrossDirDataHistPO> dirDataHistPOS = crossDirDataHistMapper.selectDirDataList(crossId, dirList, start, end);
if (!CollectionUtils.isEmpty(dirDataHistPOS)) {
Map<Integer, List<CrossDirDataHistPO>> dirHistMap = dirDataHistPOS.stream().collect(Collectors.groupingBy(CrossDirDataHistPO::getDirType));
Integer dir = null;
for (Map.Entry<Integer, List<CrossDirDataHistPO>> entry : dirHistMap.entrySet()) {
dir = entry.getKey();
List<CrossDirDataHistPO> value = entry.getValue();
Double greenTimeRatio = 0.0;
List<GreenBeltKeyCrossFlowTimeVO.Detail> details = new ArrayList<>();
for (CrossDirDataHistPO dirDataHistPO : value) {
GreenBeltKeyCrossFlowTimeVO.Detail detail = new GreenBeltKeyCrossFlowTimeVO.Detail();
detail.setCrossId(crossId);
String crossName = baseCrossInfoCache.getCrossName(crossId);
detail.setCrossName(crossName);
Integer dirType = dirDataHistPO.getDirType();
detail.setDir(String.valueOf(dirType));
detail.setFlow(dirDataHistPO.getFlow());
detail.setStartTime(dirDataHistPO.getStartTime());
detail.setGreenTimeRatio(greenTimeRatio);
for (GreenBeltKeyCrossFlowTimeVO.Detail optResult : optResults) {
if (StringUtils.equalsIgnoreCase("cancel", optResult.getDir())
&& dirDataHistPO.getStartTime().getTime() == optResult.getStartTime().getTime()) {
greenTimeRatio = 0.0;
}
Integer curDir = GreenBeltDirEnum.getInDir(optResult.getDir());
if (StringUtils.equalsIgnoreCase(crossId, optResult.getCrossId()) && Objects.equals(curDir, dirType)
&& dirDataHistPO.getStartTime().getTime() == optResult.getStartTime().getTime()) {
detail.setGreenTimeRatio(optResult.getGreenTimeRatio() * 100);
greenTimeRatio = optResult.getGreenTimeRatio() * 100;
}
}
details.add(detail);
}
if (!CollectionUtils.isEmpty(details)) {
GreenBeltKeyCrossFlowTimeVO greenBeltKeyCrossFlowTimeVO = new GreenBeltKeyCrossFlowTimeVO();
String crossName = "";
if (!CollectionUtils.isEmpty(value)) {
GreenBeltKeyCrossFlowTimeVO.Detail detail = details.get(0);
crossName = detail.getCrossName();
}
greenBeltKeyCrossFlowTimeVO.setCrossName(crossName);
greenBeltKeyCrossFlowTimeVO.setDirName(GreenBeltDirEnum.getInDirName(Integer.valueOf(dir)));
List<GreenBeltKeyCrossFlowTimeVO.Detail> collect = details.stream().sorted(Comparator.comparing(GreenBeltKeyCrossFlowTimeVO.Detail::getStartTime)).collect(Collectors.toList());
greenBeltKeyCrossFlowTimeVO.setDetailList(collect);
results.add(greenBeltKeyCrossFlowTimeVO);
}
}
}
return results;
} catch (Exception e) {
log.error("绿波关键路口流量绿信比查询异常:", e);
throw new RuntimeException(e);
}
}
/**
* 获取绿波优化列表
*
* @param greenId
* @param startOfDay
* @return
* @throws JsonProcessingException
*/
private List<GreenBeltKeyCrossFlowTimeVO.Detail> getGreenOptList(Integer greenId, LocalDateTime startOfDay) throws Exception {
List<GreenBeltKeyCrossFlowTimeVO.Detail> optResults = null;
try {
optResults = new ArrayList<>();
// 绿波优化数据
List<StrategyGreenOptHistEntity> entities = new ArrayList<>();
LambdaQueryWrapper<StrategyGreenOptHistEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StrategyGreenOptHistEntity::getGreenId, greenId);
queryWrapper.ge(StrategyGreenOptHistEntity::getControlTime, startOfDay);
entities = strategyGreenOptHistMapper.selectList(queryWrapper);
if (CollectionUtils.isEmpty(entities)) {
// 如果路口没有绿波,获取当前绿波最大的一条数据
LambdaQueryWrapper<StrategyGreenOptHistEntity> queryWrapperMaxId = new LambdaQueryWrapper<>();
queryWrapperMaxId.eq(StrategyGreenOptHistEntity::getGreenId, greenId);
queryWrapperMaxId.eq(StrategyGreenOptHistEntity::getControlMethod, 1);
// 查询最近三天内的优化记录
queryWrapperMaxId.ge(StrategyGreenOptHistEntity::getControlTime, startOfDay.minusDays(3));
queryWrapperMaxId.orderByDesc(StrategyGreenOptHistEntity::getControlTime);
queryWrapperMaxId.last("limit 1");
entities = strategyGreenOptHistMapper.selectList(queryWrapperMaxId);
}
// 一个绿波只有一个关键路口
if (!CollectionUtils.isEmpty(entities)) {
for (StrategyGreenOptHistEntity entity : entities) {
GreenBeltKeyCrossFlowTimeVO.Detail detail = new GreenBeltKeyCrossFlowTimeVO.Detail();
String keyCross = entity.getKeyCross();
detail.setCrossId(keyCross);
detail.setDir(entity.getDir());
Date controlTime = get5MinuteDate(entity.getControlTime());
detail.setStartTime(controlTime);
String crossGreenDetail = entity.getCrossGreenDetail();
Integer cycle = entity.getCycle();
ObjectMapper mapper = JacksonUtils.getInstance();
List<GreenBeltInfoVO.CrossGreenDetail> crossGreenDetails = mapper.readValue(crossGreenDetail, new TypeReference<List<GreenBeltInfoVO.CrossGreenDetail>>() {
});
if (!CollectionUtils.isEmpty(crossGreenDetails)) {
List<GreenBeltInfoVO.CrossGreenDetail> keyCrossDetail = crossGreenDetails.stream().filter(details -> StringUtils.equalsIgnoreCase(keyCross, details.getCrossId())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(keyCrossDetail)) {
for (GreenBeltInfoVO.CrossGreenDetail curKeyCross : keyCrossDetail) {
String currentCrossId = curKeyCross.getCrossId();
if (StringUtils.equalsIgnoreCase(keyCross, currentCrossId)) {
Double phaseStartTime = curKeyCross.getPhaseStartTime();
Double phaseEndTime = curKeyCross.getPhaseEndTime();
Double greenTimeRatio = (phaseEndTime - phaseStartTime) / cycle;
detail.setGreenTimeRatio(greenTimeRatio);
}
}
}
}
// 设置中间变量 优化结束
if (entity.getControlMethod() <= 0) {
detail.setDir("cancel");
}
optResults.add(detail);
}
}
} catch (Exception e) {
log.error("绿波优化列表数据异常;", e);
throw new Exception(e);
}
return optResults;
}
@Override
public List<GreenBeltSpeedWidthVO> greenBeltSpeedWidth(Integer greenId) throws Exception {
try {
List<GreenBeltSpeedWidthVO> results = new ArrayList<>();
LocalDate currentDate = LocalDate.now();
LocalTime startTime = LocalTime.MIDNIGHT;
LocalDateTime startOfDay = LocalDateTime.of(currentDate, startTime);
// 绿波历史数据
LambdaQueryWrapper<GreenwaveHistPO> greenWrapper = new LambdaQueryWrapper<>();
greenWrapper.eq(GreenwaveHistPO::getGreenId, greenId);
greenWrapper.ge(GreenwaveHistPO::getStartTime, startOfDay);
List<GreenwaveHistPO> greenwaveHistPOS = greenwaveHistMapper.selectList(greenWrapper);
// 绿波优化数据
LambdaQueryWrapper<StrategyGreenOptHistEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StrategyGreenOptHistEntity::getGreenId, greenId);
queryWrapper.ge(StrategyGreenOptHistEntity::getControlTime, startOfDay);
List<StrategyGreenOptHistEntity> entities = strategyGreenOptHistMapper.selectList(queryWrapper);
if (!CollectionUtils.isEmpty(greenwaveHistPOS)) {
Map<String, List<GreenwaveHistPO>> greenDirMap = greenwaveHistPOS.stream().collect(Collectors.groupingBy(GreenwaveHistPO::getRoadDirection));
for (Map.Entry<String, List<GreenwaveHistPO>> entry : greenDirMap.entrySet()) {
String dir = entry.getKey();
GreenBeltSpeedWidthVO greenBeltSpeedWidthVO = new GreenBeltSpeedWidthVO();
greenBeltSpeedWidthVO.setDirName(GreenBeltDirEnum.getDesc(dir));
List<GreenBeltSpeedWidthVO.Detail> details = new ArrayList<>();
List<GreenwaveHistPO> value = entry.getValue();
double greenWidthTime = 0.0;
for (GreenwaveHistPO histPO : value) {
Integer curGreenId = histPO.getGreenId();
Date curStartTime = histPO.getStartTime();
String curStartTimeStr = DateUtil.format(curStartTime, Constants.DATE_FORMAT.E_DATE_FORMAT_SECOND);
Date startTimeminuteDate = get5MinuteDate(curStartTimeStr);
Double speed = histPO.getSpeed();
GreenBeltSpeedWidthVO.Detail detail = new GreenBeltSpeedWidthVO.Detail();
for (StrategyGreenOptHistEntity entity : entities) {
Integer optGreenId = entity.getGreenId();
String controlTime = entity.getControlTime();
String optDir = entity.getDir();
Date minuteDate = get5MinuteDate(controlTime);
if (Objects.equals(curGreenId, optGreenId) && StringUtils.equalsIgnoreCase(optDir, dir)
&& minuteDate.getTime() == startTimeminuteDate.getTime()) {
greenWidthTime = entity.getGreenWidthTime();
}
if (entity.getControlMethod() < 0 && minuteDate.getTime() == startTimeminuteDate.getTime()) {
greenWidthTime = 0.0;
}
}
detail.setStartTime(curStartTime);
detail.setSpeed(speed);
detail.setWidth(greenWidthTime);
detail.setDir(dir);
details.add(detail);
}
greenBeltSpeedWidthVO.setDetailList(details);
results.add(greenBeltSpeedWidthVO);
}
}
return results;
} catch (Exception e) {
log.error("绿波带宽曲线异常:", e);
throw new RuntimeException(e);
}
}
/**
* 将下发时间按五分钟取整
*
* @param controlTime
* @return
*/
public static Date get5MinuteDate(String controlTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(controlTime, formatter);
// 获取当前分钟
int minute = dateTime.getMinute();
// 计算需要补充的分钟数(如果 minute % 5 != 0)
int minutesToAdd = (5 - minute % 5) % 5;
// 添加这些分钟并返回新的时间
LocalDateTime localDateTime = dateTime.plusMinutes(minutesToAdd).withSecond(0).withNano(0);
ZoneId zoneId = ZoneId.systemDefault();
Date minuteDate = Date.from(localDateTime.atZone(zoneId).toInstant());
return minuteDate;
}
@Override
public List<GreenBeltFlowStopTimeVO> greenBeltCrossDetailHist(Integer greenId) throws Exception {
try {
List<String> crossIds = greenwaveInfoMapper.selectCrossIdsById(greenId);
GreenwaveInfoPO greenwaveInfoPO = greenwaveInfoMapper.selectById(greenId);
long currentTimeMillis = System.currentTimeMillis();
int startSecond = ((int) (currentTimeMillis / 1000)) - 3600;
int endSecond = (int) (currentTimeMillis / 1000);
List<GreenBeltFlowStopTimeVO> results = new ArrayList<>();
if (Objects.nonNull(greenwaveInfoPO)) {
String greenDir = greenwaveInfoPO.getGreenDir();
String[] split = greenDir.split(",");
List<Integer> dirList = new ArrayList<>(split.length);
for (String s : split) {
dirList.add(Integer.valueOf(s));
}
List<CrossDirDataHistPO> dirDataHistPOS = crossDirDataHistMapper.selectByCrossIdsDirsAndTimestamp(crossIds, dirList, startSecond, endSecond);
if (!CollectionUtils.isEmpty(dirDataHistPOS)) {
Map<Date, List<CrossDirDataHistPO>> dateMap = dirDataHistPOS.stream().collect(Collectors.groupingBy(CrossDirDataHistPO::getStartTime));
for (Map.Entry<Date, List<CrossDirDataHistPO>> entry : dateMap.entrySet()) {
Date date = entry.getKey();
List<CrossDirDataHistPO> value = entry.getValue();
GreenBeltFlowStopTimeVO greenBeltFlowStopTimeVO = new GreenBeltFlowStopTimeVO();
greenBeltFlowStopTimeVO.setStartTime(date);
List<GreenBeltFlowStopTimeVO.FlowStopTimeDetail> detailList = new ArrayList<>();
if (!CollectionUtils.isEmpty(value)) {
for (CrossDirDataHistPO crossDirDataHistPO : value) {
GreenBeltFlowStopTimeVO.FlowStopTimeDetail detail = new GreenBeltFlowStopTimeVO.FlowStopTimeDetail();
Integer dirType = crossDirDataHistPO.getDirType();
detail.setGreenDir(GreenWaveInDirEnum.getDesc(dirType));
detail.setCrossId(crossDirDataHistPO.getCrossId());
detail.setFlow(crossDirDataHistPO.getFlow());
detail.setStopTimes(crossDirDataHistPO.getStopTimes());
detail.setSpeed(crossDirDataHistPO.getSpeed());
detailList.add(detail);
}
}
greenBeltFlowStopTimeVO.setDetailList(detailList);
results.add(greenBeltFlowStopTimeVO);
}
}
Collections.sort(results, Comparator.comparing(GreenBeltFlowStopTimeVO::getStartTime));
return results;
}
return Collections.EMPTY_LIST;
} catch (Exception e) {
log.error("绿波协调方向路口流量停车次数查询异常:", e);
throw new RuntimeException(e);
}
}
}
package net.wanji.opt.service.strategy;
import com.github.pagehelper.PageInfo;
import net.wanji.opt.dto.IntegerIdsDTO;
import net.wanji.opt.dto.strategy.AddOrUpdateIdeaDTO;
import net.wanji.opt.dto.strategy.QueryIdeaDTO;
import net.wanji.opt.po.strategy.IdeaPO;
/**
* @author hanbing
* @date 2023/1/12 15:12
* @desc 策略管理-方法库接口服务
*/
public interface IdeaService {
void addOrUpdateIdea(AddOrUpdateIdeaDTO addOrUpdateIdeaDTO);
void deleteIdea(IntegerIdsDTO integerIdsDTO);
PageInfo<IdeaPO> queryIdea(QueryIdeaDTO queryIdeaDTO);
}
package net.wanji.opt.service.strategy;
import com.github.pagehelper.PageInfo;
import net.wanji.opt.dto.IntegerIdsDTO;
import net.wanji.opt.dto.strategy.AddOrUpdateSceneDTO;
import net.wanji.opt.dto.strategy.QuerySceneDTO;
import net.wanji.opt.po.strategy.SceneStrategyIdeaPO;
/**
* @author hanbing
* @date 2023/1/12 15:12
* @desc 策略管理-场景库接口服务
*/
public interface SceneService {
void addOrUpdateScene(AddOrUpdateSceneDTO addOrUpdateSceneDTO);
void deleteScene(IntegerIdsDTO integerIdsDTO);
PageInfo<AddOrUpdateSceneDTO> queryScene(QuerySceneDTO querySceneDTO);
/**
* 通过场景编号获取当前执行的场景-策略-方法的id
*
* @param sceneNum
* @return
*/
SceneStrategyIdeaPO selectIdBySceneNum(Integer sceneNum);
}
package net.wanji.opt.service.strategy;
import com.github.pagehelper.PageInfo;
import net.wanji.opt.dto.IntegerIdsDTO;
import net.wanji.opt.dto.strategy.AddOrUpdateStrategyDTO;
import net.wanji.opt.dto.strategy.QueryStrategyDTO;
import net.wanji.opt.po.strategy.StrategyPO;
/**
* @author hanbing
* @date 2023/1/12 15:12
* @desc 策略管理-策略库接口服务
*/
public interface StrategyService {
void addOrUpdateStrategy(AddOrUpdateStrategyDTO addOrUpdateStrategyDTO);
void deleteStrategy(IntegerIdsDTO integerIdsDTO);
PageInfo<StrategyPO> queryStrategy(QueryStrategyDTO queryStrategyDTO);
}
package net.wanji.opt.service.strategy.impl;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import net.wanji.opt.dao.mapper.strategy.IdeaMapper;
import net.wanji.opt.dao.mapper.strategy.SceneStrategyIdeaMapper;
import net.wanji.opt.dto.IntegerIdsDTO;
import net.wanji.opt.dto.strategy.AddOrUpdateIdeaDTO;
import net.wanji.opt.dto.strategy.QueryIdeaDTO;
import net.wanji.opt.po.strategy.IdeaPO;
import net.wanji.opt.service.strategy.IdeaService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author Kent HAN
* @date 2023/2/27 9:43
*/
@Service
public class IdeaServiceImpl implements IdeaService {
private final IdeaMapper ideaMapper;
private final SceneStrategyIdeaMapper sceneStrategyIdeaMapper;
public IdeaServiceImpl(IdeaMapper ideaMapper, SceneStrategyIdeaMapper sceneStrategyIdeaMapper) {
this.ideaMapper = ideaMapper;
this.sceneStrategyIdeaMapper = sceneStrategyIdeaMapper;
}
@Override
@Transactional
public void addOrUpdateIdea(AddOrUpdateIdeaDTO addOrUpdateIdeaDTO) {
Integer id = addOrUpdateIdeaDTO.getId();
if (ObjectUtil.isEmpty(id) || id == 0) {
// 不传ID为新增
IdeaPO ideaPO = new IdeaPO();
fillData(addOrUpdateIdeaDTO, ideaPO);
ideaMapper.insertOne(ideaPO);
} else {
// 传ID为修改
IdeaPO ideaPO = new IdeaPO();
ideaPO.setId(id);
fillData(addOrUpdateIdeaDTO, ideaPO);
ideaMapper.updateOne(ideaPO);
}
}
private void fillData(AddOrUpdateIdeaDTO addOrUpdateIdeaDTO, IdeaPO ideaPO) {
ideaPO.setIdeaCode(addOrUpdateIdeaDTO.getIdeaCode());
ideaPO.setIdeaName(addOrUpdateIdeaDTO.getIdeaName());
ideaPO.setIdeaTarget(addOrUpdateIdeaDTO.getIdeaTarget());
ideaPO.setIdeaDetail(addOrUpdateIdeaDTO.getIdeaDetail());
}
@Override
public void deleteIdea(IntegerIdsDTO integerIdsDTO) {
List<Integer> ids = integerIdsDTO.getIds();
ideaMapper.deleteByIds(ids);
// 删除关系表数据
sceneStrategyIdeaMapper.deleteByIdeaIds(ids);
}
@Override
public PageInfo<IdeaPO> queryIdea(QueryIdeaDTO queryIdeaDTO) {
Integer pageNum = queryIdeaDTO.getPageNum();
Integer pageSize = queryIdeaDTO.getPageSize();
PageHelper.startPage(pageNum, pageSize);
List<IdeaPO> ideaPOList = ideaMapper.selectByIdeaNameAndIdeaTarget(queryIdeaDTO);
PageInfo<IdeaPO> ideaPOPageInfo = new PageInfo<>(ideaPOList);
return ideaPOPageInfo;
}
}
package net.wanji.opt.service.strategy.impl;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import net.wanji.opt.common.exception.UniqueException;
import net.wanji.opt.dao.mapper.strategy.IdeaMapper;
import net.wanji.opt.dao.mapper.strategy.SceneMapper;
import net.wanji.opt.dao.mapper.strategy.SceneStrategyIdeaMapper;
import net.wanji.opt.dao.mapper.strategy.SceneStrategyMapper;
import net.wanji.opt.dao.mapper.strategy.StrategyMapper;
import net.wanji.opt.dto.IntegerIdsDTO;
import net.wanji.opt.dto.strategy.AddOrUpdateSceneDTO;
import net.wanji.opt.dto.strategy.QuerySceneDTO;
import net.wanji.opt.po.strategy.IdeaPO;
import net.wanji.opt.po.strategy.ScenePO;
import net.wanji.opt.po.strategy.SceneStrategyIdeaPO;
import net.wanji.opt.po.strategy.SceneStrategyPO;
import net.wanji.opt.po.strategy.StrategyPO;
import net.wanji.opt.service.strategy.SceneService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Kent HAN
* @date 2023/2/27 11:42
*/
@Service
public class SceneServiceImpl implements SceneService {
private final SceneMapper sceneMapper;
private final SceneStrategyMapper sceneStrategyMapper;
private final SceneStrategyIdeaMapper sceneStrategyIdeaMapper;
private final StrategyMapper strategyMapper;
private final IdeaMapper ideaMapper;
public SceneServiceImpl(SceneMapper sceneMapper, SceneStrategyMapper sceneStrategyMapper,
SceneStrategyIdeaMapper sceneStrategyIdeaMapper, StrategyMapper strategyMapper, IdeaMapper ideaMapper) {
this.sceneMapper = sceneMapper;
this.sceneStrategyMapper = sceneStrategyMapper;
this.sceneStrategyIdeaMapper = sceneStrategyIdeaMapper;
this.strategyMapper = strategyMapper;
this.ideaMapper = ideaMapper;
}
@Override
public SceneStrategyIdeaPO selectIdBySceneNum(Integer sceneNum) {
return sceneStrategyIdeaMapper.selectIdBySceneNum(sceneNum);
}
@Override
@Transactional
public void addOrUpdateScene(AddOrUpdateSceneDTO addOrUpdateSceneDTO) {
checkUnique(addOrUpdateSceneDTO);
Integer id = addOrUpdateSceneDTO.getId();
if (ObjectUtil.isEmpty(id) || id == 0) {
// 不传ID为新增
// 插入场景表获取场景ID
ScenePO scenePO = new ScenePO();
fillData(addOrUpdateSceneDTO, scenePO);
sceneMapper.insertOne(scenePO);
// 插入关系表
Integer sceneId = scenePO.getId();
updateRelationship(addOrUpdateSceneDTO, sceneId);
} else {
// 传ID为修改
// 修改场景表
ScenePO scenePO = new ScenePO();
scenePO.setId(id);
fillData(addOrUpdateSceneDTO, scenePO);
sceneMapper.updateOne(scenePO);
// 删除关系表并重新插入
List<Integer> sceneIdList = new ArrayList<>();
sceneIdList.add(id);
sceneStrategyMapper.deleteBySceneIds(sceneIdList);
sceneStrategyIdeaMapper.deleteBySceneIds(sceneIdList);
updateRelationship(addOrUpdateSceneDTO, id);
}
}
private void checkUnique(AddOrUpdateSceneDTO addOrUpdateSceneDTO) {
Set<String> strategyNameSet = new HashSet<>();
Set<Integer> strategyPrioritySet = new HashSet<>();
List<AddOrUpdateSceneDTO.StrategyListElement> strategyList = addOrUpdateSceneDTO.getStrategyList();
for (AddOrUpdateSceneDTO.StrategyListElement strategyListElement : strategyList) {
String strategyName = strategyListElement.getStrategyName();
boolean addStrategy = strategyNameSet.add(strategyName);
Integer priority = strategyListElement.getPriority();
boolean addPriority = strategyPrioritySet.add(priority);
if (!addStrategy || !addPriority) {
throw new UniqueException();
}
Set<String> ideaNameSet = new HashSet<>();
List<AddOrUpdateSceneDTO.IdeaListElement> ideaList = strategyListElement.getIdeaList();
for (AddOrUpdateSceneDTO.IdeaListElement ideaListElement : ideaList) {
String ideaName = ideaListElement.getIdeaName();
boolean addIdea = ideaNameSet.add(ideaName);
if (!addIdea) {
throw new UniqueException();
}
}
}
}
private void updateRelationship(AddOrUpdateSceneDTO addOrUpdateSceneDTO, Integer id) {
List<AddOrUpdateSceneDTO.StrategyListElement> strategyList = addOrUpdateSceneDTO.getStrategyList();
for (AddOrUpdateSceneDTO.StrategyListElement strategy : strategyList) {
SceneStrategyPO sceneStrategyPO = new SceneStrategyPO();
sceneStrategyPO.setSceneId(id);
Integer strategyId = strategy.getId();
sceneStrategyPO.setStrategyId(strategyId);
Integer priority = strategy.getPriority();
sceneStrategyPO.setSceneStrategyPriority(priority);
sceneStrategyMapper.insertOne(sceneStrategyPO);
// 插入场景-策略-方法关系表
List<AddOrUpdateSceneDTO.IdeaListElement> ideaList = strategy.getIdeaList();
for (AddOrUpdateSceneDTO.IdeaListElement idea : ideaList) {
SceneStrategyIdeaPO sceneStrategyIdeaPO = new SceneStrategyIdeaPO();
sceneStrategyIdeaPO.setSceneId(id);
sceneStrategyIdeaPO.setStrategyId(strategyId);
Integer ideaId = idea.getId();
sceneStrategyIdeaPO.setIdeaId(ideaId);
sceneStrategyIdeaPO.setIdeaOrder(idea.getOrder());
sceneStrategyIdeaMapper.insertOne(sceneStrategyIdeaPO);
}
}
}
private static void fillData(AddOrUpdateSceneDTO addOrUpdateSceneDTO, ScenePO scenePO) {
String sceneCode = addOrUpdateSceneDTO.getSceneCode();
scenePO.setSceneCode(sceneCode);
String sceneName = addOrUpdateSceneDTO.getSceneName();
scenePO.setSceneName(sceneName);
if (sceneName.startsWith("失衡")) {
scenePO.setSceneNum(1);
} else if (sceneName.startsWith("拥堵")) {
scenePO.setSceneNum(2);
} else if (sceneName.startsWith("溢出")) {
scenePO.setSceneNum(3);
} else {
scenePO.setSceneNum(0);
}
Integer secneTarget = addOrUpdateSceneDTO.getSecneTarget();
scenePO.setSceneTarget(secneTarget);
}
@Override
@Transactional
public void deleteScene(IntegerIdsDTO integerIdsDTO) {
List<Integer> ids = integerIdsDTO.getIds();
sceneMapper.deleteByIds(ids);
sceneStrategyMapper.deleteBySceneIds(ids);
sceneStrategyIdeaMapper.deleteBySceneIds(ids);
}
@Override
public PageInfo<AddOrUpdateSceneDTO> queryScene(QuerySceneDTO querySceneDTO) {
List<AddOrUpdateSceneDTO> res = new ArrayList<>();
String sceneName = querySceneDTO.getSceneName();
Integer sceneTarget = querySceneDTO.getSceneTarget();
Integer pageNum = querySceneDTO.getPageNum();
Integer pageSize = querySceneDTO.getPageSize();
PageHelper.startPage(pageNum, pageSize);
List<ScenePO> scenePOList = sceneMapper.selectByNameAndTarget(sceneName, sceneTarget);
PageInfo<ScenePO> scenePOPageInfo = new PageInfo<>(scenePOList);
for (ScenePO scenePO : scenePOList) {
AddOrUpdateSceneDTO addOrUpdateSceneDTO = new AddOrUpdateSceneDTO();
Integer id = scenePO.getId();
addOrUpdateSceneDTO.setId(id);
String sceneCode = scenePO.getSceneCode();
addOrUpdateSceneDTO.setSceneCode(sceneCode);
Integer sceneNum = scenePO.getSceneNum();
addOrUpdateSceneDTO.setSceneNum(sceneNum);
String sceneNameFromDb = scenePO.getSceneName();
addOrUpdateSceneDTO.setSceneName(sceneNameFromDb);
Integer sceneTargetFromDb = scenePO.getSceneTarget();
addOrUpdateSceneDTO.setSecneTarget(sceneTargetFromDb);
// 构造策略列表
List<AddOrUpdateSceneDTO.StrategyListElement> strategyList = buildStrategyList(id);
addOrUpdateSceneDTO.setStrategyList(strategyList);
res.add(addOrUpdateSceneDTO);
}
PageInfo<AddOrUpdateSceneDTO> resPageInfo = new PageInfo<>();
BeanUtils.copyProperties(scenePOPageInfo, resPageInfo);
resPageInfo.setList(res);
return resPageInfo;
}
private List<AddOrUpdateSceneDTO.StrategyListElement> buildStrategyList(Integer sceneId) {
List<AddOrUpdateSceneDTO.StrategyListElement> strategyList = new ArrayList<>();
List<SceneStrategyPO> sceneStrategyPOList = sceneStrategyMapper.selectBySceneId(sceneId);
for (SceneStrategyPO sceneStrategyPO : sceneStrategyPOList) {
AddOrUpdateSceneDTO.StrategyListElement strategyListElement = new AddOrUpdateSceneDTO.StrategyListElement();
Integer strategyId = sceneStrategyPO.getStrategyId();
strategyListElement.setId(strategyId);
StrategyPO strategyPO = strategyMapper.selectById(strategyId);
strategyListElement.setStrategyName(strategyPO.getStrategyName());
strategyListElement.setPriority(sceneStrategyPO.getSceneStrategyPriority());
// 构造方法列表
List<AddOrUpdateSceneDTO.IdeaListElement> ideaList = buildIdeaList(sceneId, strategyId);
strategyListElement.setIdeaList(ideaList);
strategyList.add(strategyListElement);
}
List<AddOrUpdateSceneDTO.StrategyListElement> collect = strategyList.stream()
.sorted(Comparator.comparing(AddOrUpdateSceneDTO.StrategyListElement::getPriority))
.collect(Collectors.toList());
return collect;
}
private List<AddOrUpdateSceneDTO.IdeaListElement> buildIdeaList(Integer sceneId, Integer strategyId) {
List<AddOrUpdateSceneDTO.IdeaListElement> ideaList = new ArrayList<>();
List<SceneStrategyIdeaPO> sceneStrategyIdeaPOList = sceneStrategyIdeaMapper
.selectBySceneIdAndStrategyId(sceneId, strategyId);
for (SceneStrategyIdeaPO sceneStrategyIdeaPO : sceneStrategyIdeaPOList) {
AddOrUpdateSceneDTO.IdeaListElement ideaListElement = new AddOrUpdateSceneDTO.IdeaListElement();
Integer ideaId = sceneStrategyIdeaPO.getIdeaId();
IdeaPO ideaPO = ideaMapper.selectById(ideaId);
ideaListElement.setId(ideaId);
ideaListElement.setIdeaName(ideaPO.getIdeaName());
Integer order = sceneStrategyIdeaPO.getIdeaOrder();
ideaListElement.setOrder(order);
ideaList.add(ideaListElement);
}
ideaList.sort(Comparator.comparing(AddOrUpdateSceneDTO.IdeaListElement::getOrder));
return ideaList;
}
}
package net.wanji.opt.service.strategy.impl;
import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import net.wanji.opt.dao.mapper.strategy.SceneStrategyIdeaMapper;
import net.wanji.opt.dao.mapper.strategy.SceneStrategyMapper;
import net.wanji.opt.dao.mapper.strategy.StrategyMapper;
import net.wanji.opt.dto.IntegerIdsDTO;
import net.wanji.opt.dto.strategy.AddOrUpdateStrategyDTO;
import net.wanji.opt.dto.strategy.QueryStrategyDTO;
import net.wanji.opt.po.strategy.StrategyPO;
import net.wanji.opt.service.strategy.StrategyService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author Kent HAN
* @date 2023/2/27 9:43
*/
@Service
public class StrategyServiceImpl implements StrategyService {
private final StrategyMapper strategyMapper;
private final SceneStrategyMapper sceneStrategyMapper;
private final SceneStrategyIdeaMapper sceneStrategyIdeaMapper;
public StrategyServiceImpl(StrategyMapper strategyMapper, SceneStrategyMapper sceneStrategyMapper, SceneStrategyIdeaMapper sceneStrategyIdeaMapper) {
this.strategyMapper = strategyMapper;
this.sceneStrategyMapper = sceneStrategyMapper;
this.sceneStrategyIdeaMapper = sceneStrategyIdeaMapper;
}
@Override
@Transactional
public void addOrUpdateStrategy(AddOrUpdateStrategyDTO addOrUpdateStrategyDTO) {
Integer id = addOrUpdateStrategyDTO.getId();
if (ObjectUtil.isEmpty(id) || id == 0) {
// 不传ID为新增
StrategyPO strategyPO = new StrategyPO();
strategyPO.setStrategyCode(addOrUpdateStrategyDTO.getStrategyCode());
strategyPO.setStrategyName(addOrUpdateStrategyDTO.getStrategyName());
strategyPO.setStrategyTarget(addOrUpdateStrategyDTO.getStrategyTarget());
strategyPO.setStrategyDetail(addOrUpdateStrategyDTO.getStrategyDetail());
strategyMapper.insertOne(strategyPO);
} else {
// 传ID为修改
StrategyPO strategyPO = new StrategyPO();
strategyPO.setId(id);
strategyPO.setStrategyCode(addOrUpdateStrategyDTO.getStrategyCode());
strategyPO.setStrategyName(addOrUpdateStrategyDTO.getStrategyName());
strategyPO.setStrategyTarget(addOrUpdateStrategyDTO.getStrategyTarget());
strategyPO.setStrategyDetail(addOrUpdateStrategyDTO.getStrategyDetail());
strategyMapper.updateOne(strategyPO);
}
}
@Override
public void deleteStrategy(IntegerIdsDTO integerIdsDTO) {
List<Integer> ids = integerIdsDTO.getIds();
strategyMapper.deleteByIds(ids);
// 删除关系表数据
sceneStrategyMapper.deleteByStrategyIds(ids);
sceneStrategyIdeaMapper.deleteByStrategyIds(ids);
}
@Override
public PageInfo<StrategyPO> queryStrategy(QueryStrategyDTO queryStrategyDTO) {
Integer pageNum = queryStrategyDTO.getPageNum();
Integer pageSize = queryStrategyDTO.getPageSize();
PageHelper.startPage(pageNum, pageSize);
List<StrategyPO> strategyPOList = strategyMapper.selectByStrategyNameAndTarget(queryStrategyDTO);
PageInfo<StrategyPO> strategyPOPageInfo = new PageInfo<>(strategyPOList);
return strategyPOPageInfo;
}
}
package net.wanji.opt.servicev2.comprehensivequery;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import net.wanji.opt.entity.comprehensivequery.CrossLaneDataHistPoExtendName;
import net.wanji.opt.entity.comprehensivequery.GreenTreeEntity;
import java.util.List;
import java.util.Map;
public interface ComprehensiveQueryService {
List<GreenTreeEntity> getGreenAndCross();
JSONObject getCrossStatusDistribution(String crossId , String startTime , String endTime , String objectType , String groupType, Integer pageNum, Integer pageSize);
}
package net.wanji.opt.servicev2.comprehensivequery.impl;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import net.wanji.common.enums.BaseEnum;
import net.wanji.opt.dao.mapper.comprehensivequery.ComprehensiveQueryMapper;
import net.wanji.opt.entity.comprehensivequery.CrossEntity;
import net.wanji.opt.entity.comprehensivequery.CrossLaneDataHistPoExtendName;
import net.wanji.opt.entity.comprehensivequery.GreenAndCrossEntity;
import net.wanji.opt.entity.comprehensivequery.GreenTreeEntity;
import net.wanji.opt.po.base.CrossLaneDataHistPoExtend;
import net.wanji.opt.po.strategy.StrategyPO;
import net.wanji.opt.servicev2.comprehensivequery.ComprehensiveQueryService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.constraints.Future;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 综合查询
* </p>
*
* @author huangwm
* @since 2025-03-26
*/
@Service
public class ComprehensiveQueryServiceImpl implements ComprehensiveQueryService {
@Resource
private ComprehensiveQueryMapper comprehensiveQueryMapper;
@Override
public List<GreenTreeEntity> getGreenAndCross() {
List<GreenAndCrossEntity> list = comprehensiveQueryMapper.getGreenAndCross();
String greenNameTemp = "";
List<CrossEntity> crossList = new ArrayList<>();
List<GreenTreeEntity> greenList = new ArrayList<>();
GreenTreeEntity greenTreeEntity = new GreenTreeEntity();
CrossEntity crossEntity = new CrossEntity();
int a = 0;
for(GreenAndCrossEntity temp : list){
// 判断干线名称是否一致
if(!greenNameTemp.equals(temp.getGreenName())){
greenNameTemp = temp.getGreenName();
//判断是否是空数组,第一次进入的时候是空数组,后续是有数据的数组需要把数据添加进去
if(greenTreeEntity.getGreenId() != null){
greenTreeEntity.setChildren(crossList);
greenList.add(greenTreeEntity);
greenTreeEntity = new GreenTreeEntity();
greenTreeEntity.setGreenId(temp.getGreenId());
greenTreeEntity.setGreenName(temp.getGreenName());
crossEntity = new CrossEntity();
crossList = new ArrayList<>();
crossEntity.setCrossName(temp.getCrossName());
crossEntity.setCrossId(temp.getCrossId());
crossList.add(crossEntity);
}else {
greenTreeEntity.setGreenId(temp.getGreenId());
greenTreeEntity.setGreenName(temp.getGreenName());
crossEntity = new CrossEntity();
crossList = new ArrayList<>();
crossEntity.setCrossName(temp.getCrossName());
crossEntity.setCrossId(temp.getCrossId());
crossList.add(crossEntity);
}
}else {
crossEntity = new CrossEntity();
crossEntity.setCrossName(temp.getCrossName());
crossEntity.setCrossId(temp.getCrossId());
crossList.add(crossEntity);
if (a == list.size() - 1) {
greenTreeEntity.setChildren(crossList);
greenList.add(greenTreeEntity);
}
}
a++;
}
return greenList;
}
@Override
public JSONObject getCrossStatusDistribution(String crossId , String startTime ,String endTime ,String objectType ,String groupType,Integer pageNum,Integer pageSize) {
List<CrossLaneDataHistPoExtendName> resultList = new ArrayList<>();
List<GreenAndCrossEntity> CrossList = comprehensiveQueryMapper.getCross();
String[] crossIdArray = crossId.split(",");
for (String id : crossIdArray) {
String crossName = "";
for(GreenAndCrossEntity temp : CrossList){
if(id.equals(temp.getCrossId())){
crossName = temp.getCrossName();
}
}
Map<String, Object> params = new HashMap<>();
params.put("crossId", id);
params.put("startDate", startTime);
params.put("endDate", endTime);
params.put("groupType", groupType);
params.put("objectType", objectType);
List<CrossLaneDataHistPoExtend> list = comprehensiveQueryMapper.findCrossObjectIndex(params);
for (CrossLaneDataHistPoExtend c : list) {
CrossLaneDataHistPoExtendName temp = new CrossLaneDataHistPoExtendName();
temp.setCrossId(c.getCrossId());
temp.setStartTime(c.getStartTime());
temp.setDirType(c.getDirType());
temp.setTurnType(c.getTurnType());
temp.setFlow(c.getFlow());
temp.setSpeed(c.getSpeed());
temp.setMaxQueueLength(c.getMaxQueueLength());
temp.setMinQueueLength(c.getMinQueueLength());
temp.setAvgQueueLength(c.getAvgQueueLength());
temp.setStopTimes(c.getStopTimes());
temp.setDelayTime(c.getDelayTime());
temp.setTrafficIndex(c.getTrafficIndex());
temp.setCrossName(crossName);
temp.setEndTime(c.getEndTime());
if(c.getDirType() != null && c.getDirType() > 0 ){
temp.setDirTypeName(BaseEnum.SignalDirectionEnum.getNameByCode(c.getDirType()));
}
if(c.getTurnType() != null && c.getTurnType() > 0){
temp.setTurnTypeName(BaseEnum.TurnTypeEnum.getNameByCode(c.getTurnType()));
}
resultList.add(temp);
}
}
List<CrossLaneDataHistPoExtendName> collect = new ArrayList<>();
if(CollectionUtils.isNotEmpty(resultList)){
collect = resultList.stream().skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
}
JSONObject result = new JSONObject();
result.put("fullDataList",resultList);
result.put("pageList",collect);
result.put("totalPage",Math.ceil((double) resultList.size() / pageSize));
result.put("totalSize",resultList.size());
return result;
}
}
package net.wanji.opt.servicev2.evaluation;
import com.baomidou.mybatisplus.extension.service.IService;
import net.wanji.databus.po.CrossDataHistPO;
import java.util.List;
import java.util.Map;
public interface EvaluationInfoService extends IService<CrossDataHistPO> {
Map<String,Object> getListEvaluationSummarize(String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime);
Map<String, Object> summaryEvaluation(String evenType,String currentAlgo,String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime);
Map<String, Object> unbalanceEvaluation(String evenType,String currentAlgo,String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime);
Map<String, Object> idleEvaluation(String evenType,String currentAlgo,String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime);
}
package net.wanji.opt.servicev2.evaluation.impl;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import net.wanji.databus.dao.mapper.CrossDataHistMapper;
import net.wanji.databus.po.CrossDataHistPO;
import net.wanji.opt.constant.ServiceLevelEnum;
import net.wanji.opt.entity.eventoptimize.TEventOptimizeInfo;
import net.wanji.opt.entity.judgeanalysis.AnalysisProblemAndStrategyDay;
import net.wanji.opt.dao.mapper.evaluation.CrossProblemEvaluationMapper;
import net.wanji.opt.po.trend.EventInfoSimplePo;
import net.wanji.opt.servicev2.evaluation.EvaluationInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Service
@Slf4j
public class EvaluationInfoServiceImpl extends ServiceImpl<CrossDataHistMapper, CrossDataHistPO> implements EvaluationInfoService {
@Autowired
CrossDataHistMapper crossDataHistMapper;
@Autowired
CrossProblemEvaluationMapper crossProblemEvaluationMapper;
@Override
public Map<String,Object> getListEvaluationSummarize(String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime) {
try {
//分析时间的数据
List<CrossDataHistPO> analyseList = crossDataHistMapper.getListEvaluationanalyse(crossId, startTime, endTime);
//比较时间的数据
List<CrossDataHistPO> contrastList = crossDataHistMapper.getListEvaluationcontrast(crossId, contrastStartTime, constrastEndTime);
//分析时间服务水平
// List<CrossDataHistPO> ServiceLevelanalyseList = crossDataHistMapper.getEvaluationanalyseServiceLevel(crossId, startTime, endTime);
//比较时间的服务水平
// List<CrossDataHistPO> contrastServiceLevelList = crossDataHistMapper.getServiceLevelEvaluationcontrast(crossId, contrastStartTime, constrastEndTime);
//取出分析时间 的速度 延误 排队长度
Double speed = 0.00;
Integer delayTime = 0;
Double queueLength = 0.00;
//分析的交通流量
int analyseFlow = 0;
for (CrossDataHistPO analyselist : analyseList) {
if (analyselist == null) {
continue; // 跳过空元素
}
speed = analyselist.getSpeed();
delayTime = analyselist.getDelayTime();
queueLength = analyselist.getQueueLength();
analyseFlow = analyselist.getFlow();
}
//取出对比时间 的速度 延误 排队长度
Double speedCompare = 0.00;
Integer delayTimeCompare = 0;
Double queueLengthCompare = 0.00;
//对比的交通流量
int contrastFlow = 0;
for (CrossDataHistPO contrastlist : contrastList) {
if (contrastlist == null) {
continue; // 跳过空元素
}
speedCompare = contrastlist.getSpeed();
delayTimeCompare = contrastlist.getDelayTime();
queueLengthCompare = contrastlist.getQueueLength();
contrastFlow = contrastlist.getFlow();
}
// 计算速度变化百分比
double speedChangePercent = calculatePercentage(speed, speedCompare);
// 计算延误变化百分比
double delayTimeChangePercent = calculatePercentage(delayTime, delayTimeCompare);
// 计算排队长度变化百分比
double queueLengthChangePercent = calculatePercentage(queueLength, queueLengthCompare);
// 计算交通流量百分比
double flow = calculatePercentage(analyseFlow, contrastFlow);
//取出分析时间的服务水平
// String analyseserviceLevel = getServiceLevel(ServiceLevelanalyseList);
//取出对比时间的服务水平
// String compareServiceLevel = getServiceLevel(contrastServiceLevelList);
JSONObject jsonObject = new JSONObject();
//平均速度
jsonObject.put("speed", speedChangePercent + "%");
//平均延误
jsonObject.put("delay", delayTimeChangePercent + "%");
//平均排队时长
jsonObject.put("queueLength", queueLengthChangePercent + "%");
// 计算交通流量百分比
jsonObject.put("flow", flow + "%");
// jsonObject.put("analyseserviceLevel", analyseserviceLevel);
// jsonObject.put("compareServiceLevel", compareServiceLevel);
return jsonObject;
}catch (Exception e){
log.error("{} getListEvaluationSummarize error", this.getClass().getSimpleName(), e);
throw e;
}
}
/**
* 计算变化百分比
*
* @param analyseValue 分析值
* @param contrastValue 对比值
* @return 变化百分比(保留两位小数)
*/
private static double calculatePercentage(double analyseValue, double contrastValue) {
// 防止除零错误
if (contrastValue == 0) {
return (int)analyseValue*100;
}
// 计算变化值(分析值 - 对比值)
double difference = analyseValue - contrastValue;
// 计算变化百分比,并保留两位小数(差值/对比值)
return Math.round((difference / contrastValue) * 100 * 100.0) / 100.0;
}
/*获取服务水平*/
public String getServiceLevel(List<CrossDataHistPO> list){
//按服务水平分组
Map<String, List<CrossDataHistPO>> groupByServerLevel = list.stream().collect(Collectors.groupingBy(o -> o.getServiceLevel()));
double total = 0;
for (Map.Entry<String, List<CrossDataHistPO>> entry1 : groupByServerLevel.entrySet()) {
String key = entry1.getKey();
total += ServiceLevelEnum.getByType(key).getVal() * entry1.getValue().size();
}
//服务水平加权平均计算:给服务水平(等级得分*该等级的数量)累加/总数量
int avgService = (int) Math.round(total/list.size());
String serviceLevel = ServiceLevelEnum.getByVal(avgService)==null?"A":ServiceLevelEnum.getByVal(avgService).getType();
return serviceLevel;
}
/*
* 溢出
* */
@Override
public Map<String, Object> summaryEvaluation(String evenType,String currentAlgo,String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime) {
try {
//分析时间
List<EventInfoSimplePo> overFlowList = crossProblemEvaluationMapper.getOverflow(evenType,currentAlgo,crossId, startTime, endTime);
//对比时间
List<EventInfoSimplePo> contrastoverFlowList = crossProblemEvaluationMapper.getContrastOverflow(evenType,currentAlgo,crossId, contrastStartTime, constrastEndTime);
//分析时间的查询数据集
//分析溢出次数
long overFlowcount=0;
//分析溢出优化次数
long overFlowTime =0;
//分析溢出时长
int fenxioverflowTime=0;
for (EventInfoSimplePo fxList:overFlowList){
//分析溢出次数
overFlowcount = fxList.getEventCount();
//分析溢出优化次数
overFlowTime = fxList.getOptimizecount();
fenxioverflowTime=fxList.getDuration();
}
//对比时间的查询数据集
//对比溢出次数
long ontrastoverFlowcount=0;
//对比溢出优化次数
long contrastoverFlowTime=0;
//对比溢出时长
int duibioverflowTime=0;
for (EventInfoSimplePo fxList:contrastoverFlowList){
//对比溢出次数
ontrastoverFlowcount = fxList.getEventCount();
//对比溢出优化次数
contrastoverFlowTime = fxList.getOptimizecount();
duibioverflowTime=fxList.getDuration();
}
//计算溢出次数百分比
double overFlowCishujisuan = calculatePercentage(overFlowcount, ontrastoverFlowcount);
//计算溢时长百分比
double overFlowtimejisuan = calculatePercentage(fenxioverflowTime, duibioverflowTime);
//分析时间的数据t_cross_data_hist
List<CrossDataHistPO> analyseList = crossDataHistMapper.getListEvaluationanalyse(crossId, startTime, endTime);
//比较时间的数据t_cross_data_hist
List<CrossDataHistPO> contrastList = crossDataHistMapper.getListEvaluationcontrast(crossId, contrastStartTime, constrastEndTime);
//溢出分析的延时时间
Integer overFlowdelayTime = 0;
for (CrossDataHistPO analyselist : analyseList) {
if (analyselist == null) {
continue; // 跳过空元素
}
overFlowdelayTime = analyselist.getDelayTime();
}
//溢出对比的延时时间
Integer conTrastoverFlowdelayTime = 0;
for (CrossDataHistPO contrastlist : contrastList) {
if (contrastlist == null) {
continue; // 跳过空元素
}
conTrastoverFlowdelayTime = contrastlist.getDelayTime();
}
//溢出的平均延误时间计算
double overFlowDelayjisuan = calculatePercentage(overFlowdelayTime, conTrastoverFlowdelayTime);
JSONObject jsonObject = new JSONObject();
//溢出次数
jsonObject.put("analyOverFlowTime", overFlowcount);
//溢出优化次数
jsonObject.put("analyOverFlowOptimize", overFlowTime);
//对比溢出次数
jsonObject.put("contrastOverFlowTime", ontrastoverFlowcount);
//对比的溢出优化次数
jsonObject.put("contrastOverFlowOptimize", contrastoverFlowTime);
//溢出次数分析对比计算
jsonObject.put("OverFlowTimeCalculate", overFlowCishujisuan + "%");
//溢出时长分析对比计算
jsonObject.put("OverFlowHourCalculate", overFlowtimejisuan + "%");
//溢出平均延误
jsonObject.put("OverFlowavgdelay", overFlowDelayjisuan + "%");
return jsonObject;
}
catch (Exception e){
log.error("{} summaryEvaluation error", this.getClass().getSimpleName(), e);
throw e;
}
}
/*失衡702
*
* */
@Override
public Map<String, Object> unbalanceEvaluation(String evenType,String currentAlgo,String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime) {
try {
//分析时间
List<EventInfoSimplePo> overFlowList = crossProblemEvaluationMapper.getOverflow(evenType,currentAlgo,crossId, startTime, endTime);
//对比时间
List<EventInfoSimplePo> contrastoverFlowList = crossProblemEvaluationMapper.getContrastOverflow(evenType,currentAlgo,crossId, contrastStartTime, constrastEndTime);
//分析时间结果集
//分析失衡次数
long unbalancecount=0;
//分析失衡优化次数
long unbalanceTime=0;
//分析失衡时长
int fenxiunbalanceTime=0;
for (EventInfoSimplePo fxList:overFlowList){
//分析次数
unbalancecount = fxList.getEventCount();
//分析优化次数
unbalanceTime = fxList.getOptimizecount();
fenxiunbalanceTime=fxList.getDuration();
}
//对比时间结果集
//对比失衡次数
long contrastunbalancecount=0;
//对比失衡优化次数
long contrastunbalanceTime=0;
//对比失衡时长
int duibiunbalanceTime=0;
for (EventInfoSimplePo fxList:contrastoverFlowList){
//对比次数
contrastunbalancecount = fxList.getEventCount();
//对比优化次数
contrastunbalanceTime = fxList.getOptimizecount();
duibiunbalanceTime=fxList.getDuration();
}
//计算失衡次数百分比
double unbalanceCishujisuan = calculatePercentage(unbalancecount, contrastunbalancecount);
//计算失衡时长百分比
double unbalancetimejisuan = calculatePercentage(fenxiunbalanceTime, duibiunbalanceTime);
//分析时间路口平均停车次数t_cross_data_hist
List<CrossDataHistPO> analyseList = crossDataHistMapper.getListEvaluationanalyse(crossId, startTime, endTime);
//比较时间的数据路口平均停车次数t_cross_data_hist
List<CrossDataHistPO> contrastList = crossDataHistMapper.getListEvaluationcontrast(crossId, contrastStartTime, constrastEndTime);
//失衡分析时间的stop_times路口平均停车次数
Double unbalanceStopTimes = 0.0;
for (CrossDataHistPO analyselist : analyseList) {
if (analyselist == null) {
continue; // 跳过空元素
}
unbalanceStopTimes = analyselist.getStopTimes();
}
//失衡对比的时间stop_times路口平均停车次数
Double conTrastUnbalanceStopTimes = 0.0;
for (CrossDataHistPO contrastlist : contrastList) {
if (contrastlist == null) {
continue; // 跳过空元素
}
conTrastUnbalanceStopTimes = contrastlist.getStopTimes();
}
//失衡的平均停车次数计算
double unbalanceStopTimesjisuan = calculatePercentage(unbalanceStopTimes, conTrastUnbalanceStopTimes);
JSONObject jsonObject = new JSONObject();
//分析失衡次数
jsonObject.put("unbalancecount", unbalancecount);
//分析失衡优化次数
jsonObject.put("unbalanceTime", unbalanceTime);
//对比失衡次数
jsonObject.put("ontrastunbalancecount", contrastunbalancecount);
//对比的失衡的优化次数
jsonObject.put("contrastunbalanceTime", contrastunbalanceTime);
//失衡次数分析对比计算
jsonObject.put("unbalanceCishucalculate", unbalanceCishujisuan + "%");
//失衡时长分析对比计算
jsonObject.put("unbalancetimecalculate", unbalancetimejisuan + "%");
//失衡平均停车次数
jsonObject.put("unbalanceStopTimescalculate", unbalanceStopTimesjisuan + "%");
return jsonObject;
}catch (Exception e){
log.error("{} unbalanceEvaluation error", this.getClass().getSimpleName(), e);
throw e;
}
}
/*
* 空放701
* */
@Override
public Map<String, Object> idleEvaluation(String evenType,String currentAlgo,String crossId, String startTime, String endTime, String contrastStartTime, String constrastEndTime) {
try {
//分析时间
List<EventInfoSimplePo> overFlowList = crossProblemEvaluationMapper.getOverflow(evenType,currentAlgo,crossId, startTime, endTime);
//对比时间
List<EventInfoSimplePo> contrastoverFlowList = crossProblemEvaluationMapper.getContrastOverflow(evenType,currentAlgo,crossId, contrastStartTime, constrastEndTime);
//分析时间结果集
//分析时间空放次数
long dileCount=0;
//分析时间空放优化次数
long dileTime=0;
//分析空放时长
int fenxiDileTime=0;
for (EventInfoSimplePo fxList:overFlowList){
//分析次数
dileCount = fxList.getEventCount();
//分析优化次数
dileTime = fxList.getOptimizecount();
fenxiDileTime=fxList.getDuration();
}
//对比时间结果集
//对比时间空放次数
long contrastDileCount=0;
//对比时间空放优化次数
long contrastDileTime=0;
//对比空放时长
int duibiDileTime=0;
for (EventInfoSimplePo fxList:contrastoverFlowList){
//对比次数
contrastDileCount = fxList.getEventCount();
//对比优化次数
contrastDileTime = fxList.getOptimizecount();
duibiDileTime=fxList.getDuration();
}
//计算空放次数百分比
double dileCishujisuan = calculatePercentage(dileCount, contrastDileCount);
//计算空放时长百分比
double dileTimejisuan = calculatePercentage(fenxiDileTime, duibiDileTime);
//分析时间路口平均速度t_cross_data_hist
List<CrossDataHistPO> analyseList = crossDataHistMapper.getListEvaluationanalyse(crossId, startTime, endTime);
//比较时间的数据路口平均速度t_cross_data_hist
List<CrossDataHistPO> contrastList = crossDataHistMapper.getListEvaluationcontrast(crossId, contrastStartTime, constrastEndTime);
//空放分析时间的Speed路口平均速度
Double dileSpeed = 0.0;
for (CrossDataHistPO analyselist : analyseList) {
if (analyselist == null) {
continue; // 跳过空元素
}
dileSpeed = analyselist.getSpeed();
}
//空放对比的时间平均速度
Double conTrastDileSpeed = 0.0;
for (CrossDataHistPO contrastlist : contrastList) {
if (contrastlist == null) {
continue; // 跳过空元素
}
conTrastDileSpeed = contrastlist.getSpeed();
}
//空放的平均速度
double dileSpeedjisuan = calculatePercentage(dileSpeed, conTrastDileSpeed);
JSONObject jsonObject = new JSONObject();
//分析时间空放次数
jsonObject.put("dileCount", dileCount);
//分析时间空放优化次数
jsonObject.put("dileTime", dileTime);
//对比时间空放的次数
jsonObject.put("contrastDileCount", contrastDileCount);
//对比的空放的优化次数
jsonObject.put("contrastDileTime", contrastDileTime);
//空放次数分析对比计算
jsonObject.put("dileCishucalculate", dileCishujisuan + "%");
//空放时长分析对比计算
jsonObject.put("dileTimecalculate", dileTimejisuan + "%");
//空放评价速度对比计算
jsonObject.put("dileSpeedcalculate", dileSpeedjisuan + "%");
return jsonObject;
}catch (Exception e){
log.error("{} idleEvaluation error", this.getClass().getSimpleName(), e);
throw e;
}
}
}
package net.wanji.opt.servicev2.eventoptimize;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import net.wanji.opt.entity.eventoptimize.TEventOptimizeInfo;
import net.wanji.opt.entity.eventoptimize.TEventOptimizeInfoVO;
public interface TEventOptimizeInfoService extends IService<TEventOptimizeInfo> {
Page<TEventOptimizeInfo> queryPageWithConditions(int currentPage, int pageSize, String startTime, String endTime, String crossId,String eventType,Integer optStatus,Integer duration,Integer startOptDuration, Integer endOptDuration,Integer startDuration,Integer endDuration);
Page<TEventOptimizeInfoVO> selectPageWithCrossIdAndGreenId(int currentPage, int pageSize, String startTime, String endTime, String crossId, Integer greenId);
JSONObject getCrossOptimizeDistribute(Integer greenId, String crossId, String startTime, String endTime, Integer groupType);
Page<TEventOptimizeInfo> pageWithLineConditions(int currentPage, int pageSize, String startTime, String endTime, Integer greenId,String eventType, Integer optStatus, Integer duration,Integer startOptDuration,Integer endOptDuration,Integer startDuration, Integer endDuration);
}
\ No newline at end of file
package net.wanji.opt.servicev2.eventoptimize.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.wanji.databus.po.EventOptimizeCountPo;
import net.wanji.opt.common.EsDateIndexUtil;
import net.wanji.opt.dao.mapper.eventoptimize.TEventOptimizeInfoMapper;
import net.wanji.opt.entity.eventoptimize.TEventOptimizeInfo;
import net.wanji.opt.entity.eventoptimize.TEventOptimizeInfoVO;
import net.wanji.opt.servicev2.eventoptimize.TEventOptimizeInfoService;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class TEventOptimizeInfoServiceImpl extends ServiceImpl<TEventOptimizeInfoMapper, TEventOptimizeInfo> implements TEventOptimizeInfoService {
@Autowired
private TEventOptimizeInfoMapper tEventOptimizeInfoMapper;
// 新增接口用于带有条件的分页查询
@Override
public Page<TEventOptimizeInfo> queryPageWithConditions(int currentPage, int pageSize, String startTime, String endTime, String crossId,String eventType,Integer optStatus,Integer duration,Integer startOptDuration, Integer endOptDuration,Integer startDuration,Integer endDuration) {
Page<TEventOptimizeInfo> page = new Page<>(currentPage, pageSize);
Page<TEventOptimizeInfo> tEventOptimizeInfoPage = tEventOptimizeInfoMapper.selectPageWithConditions(page, startTime, endTime, crossId, eventType,optStatus,duration, startOptDuration, endOptDuration, startDuration ,endDuration);
tEventOptimizeInfoPage.getRecords().forEach(x->{
x.setEventLabal(getEventLabel(x.getEventType()));
});
return tEventOptimizeInfoPage;
}
@Override
public Page<TEventOptimizeInfoVO> selectPageWithCrossIdAndGreenId(int currentPage, int pageSize, String startTime, String endTime, String crossId, Integer greenId) {
Page<TEventOptimizeInfo> page = new Page<>(currentPage, pageSize);
Page<TEventOptimizeInfo> tEventOptimizeInfoPage = baseMapper.selectPageWithCrossIdAndGreenId(page, startTime, endTime, crossId, greenId);
List<TEventOptimizeInfoVO> collect = tEventOptimizeInfoPage.getRecords().stream().map(x -> {
TEventOptimizeInfoVO tEventOptimizeInfoVO = new TEventOptimizeInfoVO();
BeanUtils.copyProperties(x, tEventOptimizeInfoVO);
tEventOptimizeInfoVO.setEventLabal(getEventLabel(x.getEventType()));
return tEventOptimizeInfoVO;
}).collect(Collectors.toList());
Page<TEventOptimizeInfoVO> pageVO = new Page<>(currentPage, pageSize);
pageVO.setTotal(page.getTotal());
pageVO.setRecords(collect);
return pageVO;
}
@Override
public JSONObject getCrossOptimizeDistribute(Integer greenId, String crossId, String startTime, String endTime, Integer groupType) {
List<Map<String, String>> crossOptimizeDistribute = tEventOptimizeInfoMapper.getCrossOptimizeDistribute(groupType, startTime, endTime, crossId,greenId);
List<String> sortedSet = EsDateIndexUtil.getTimeGranularityAxisAll(String.valueOf(groupType), startTime, endTime);// 按事件类型分组
Map<String, EventOptimizeCountPo> eventTypeMap = new HashMap<>();
for (Map<String, String> data : crossOptimizeDistribute) {
String eventType = data.get("event_type");
EventOptimizeCountPo optimizeCountPo = eventTypeMap.computeIfAbsent(eventType, k -> {
EventOptimizeCountPo item = new EventOptimizeCountPo();
item.setEventLabel(getEventLabel(eventType)); // 设置事件名称
item.setEventType(eventType);
item.setNoOptimizeNumberList(new ArrayList<>(Collections.nCopies(sortedSet.size(), 0)));
item.setTotalNumberList(new ArrayList<>(Collections.nCopies(sortedSet.size(), 0)));
return item;
});
// 更新对应时间的统计数据
int timeIndex = sortedSet.indexOf(data.get("time_label"));
String totalCount = String.valueOf(data.get("total_count")) ;
String unoptimizedCount = String.valueOf(data.get("unoptimized_count")) ;
optimizeCountPo.getTotalNumberList().set(timeIndex, Integer.valueOf(totalCount));
optimizeCountPo.getNoOptimizeNumberList().set(timeIndex, Integer.valueOf(unoptimizedCount));
}
ArrayList<String> timeLabelList = new ArrayList<>(Collections.nCopies(sortedSet.size(), ""));
sortedSet.forEach(x->{
String timeFormat = getTimeFormat(groupType,x);
int index = sortedSet.indexOf(x);
timeLabelList.set(index,timeFormat);
});
JSONObject jsonObject = new JSONObject();
jsonObject.put("timeList", timeLabelList);
jsonObject.put("timeListAll", sortedSet);
jsonObject.put("dataList", eventTypeMap.values());
return jsonObject;
}
private String getTimeFormat(Integer groupType, String time) {
DateTime dateTime = DateTime.parse(time, DateTimeFormat.forPattern(EsDateIndexUtil.YMD_HM_FORMATTER));
String format = "";
if(!ObjectUtils.isEmpty(groupType) && groupType == 4 ){
format = dateTime.toString("yyyy-MM-dd");
}else {
format = dateTime.toString("HH:mm");
}
return format;
}
// 获取事件名称(可以根据实际需求扩展)
private String getEventLabel(String eventType) {
String eventLabel = tEventOptimizeInfoMapper.getEventLabel(eventType);
if(ObjectUtils.isEmpty(eventLabel)){
return "未知事件";
}else {
return eventLabel;
}
}
// 新增干线接口用于带有条件的分页查询
@Override
public Page<TEventOptimizeInfo> pageWithLineConditions(int currentPage, int pageSize, String startTime, String endTime, Integer greenId, String eventType, Integer optStatus, Integer duration,Integer startOptDuration,Integer endOptDuration,Integer startDuration, Integer endDuration) {
Page<TEventOptimizeInfo> page = new Page<>(currentPage, pageSize);
return tEventOptimizeInfoMapper.pageWithLineConditions(page,startTime,endTime,greenId, eventType, optStatus ,duration,startOptDuration,endOptDuration,startDuration,endDuration);
}
}
\ No newline at end of file
package net.wanji.opt.servicev2.implv2;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.BaseEnum;
import net.wanji.opt.dao.mapper.CrossMapper;
import net.wanji.opt.dao.mapper.GreenwaveHistoryMapper;
import net.wanji.opt.po.base.CrossLaneDataHistPoExtend;
import net.wanji.opt.servicev2.CrossService;
import net.wanji.opt.synthesis.pojo.*;
import net.wanji.opt.synthesis.pojo.vo.CrossOrGreenWaveTypeEntity;
import net.wanji.opt.vo2.CrossBaseInfoVO;
import net.wanji.opt.vo2.CrossStatusDistributionVO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* 监测详情-路口事件详情
*
* @author zhengyifan
* @date 2025/3/15
*/
@Service
@Slf4j
public class CrossServiceImpl implements CrossService {
@Resource
private CrossMapper crossMapper;
@Resource
private GreenwaveHistoryMapper greenwaveHistoryMapper;
@Override
public Map<String, Object> getCrossStatusDistribution(String crossID, String date, String groupType, Integer objectType, String condition) {
Map<String, Object> resultMap = new HashMap<>();
if (objectType == 1) {
// 方向级
// condition是方向--1 3 5 7
String[] conditions = condition.split(";");
for (String c : conditions) {
List<CrossStatusDistributionVO> list = getCrossStatusDistribution_SingleCondition(crossID, date, groupType, objectType, c);
resultMap.put(c + "List", list);
}
} else if (objectType == 2) {
// 转向级
// condition是转向--dir:l;dir:r;dir:n;dir:u-dir1,dir2,dir3
String[] dir = condition.split("-");
List<CrossStatusDistributionVO> list = getCrossStatusDistribution_AllCondition(crossID, date, groupType, objectType, dir[1]);
String[] conditions = dir[0].split(";");
for (String c : conditions) {
String[] cs = c.split(":");
String turnDir = BaseEnum.TurnTypeEnum.getIntCodeByStrCode(cs[1]).toString();
List<CrossStatusDistributionVO> temp = list.stream().filter(p -> cs[0].equals(p.getDirType().toString())).collect(Collectors.toList());
List<CrossStatusDistributionVO> temp1 = temp.stream().filter(p -> turnDir.equals(p.getTurnType().toString())).collect(Collectors.toList());
String namePart1 = BaseEnum.SignalDirectionEnum.getNameByCode(Integer.parseInt(cs[0]));
String namePart2 = BaseEnum.TurnTypeEnum.getNameByCode(BaseEnum.TurnTypeEnum.getIntCodeByStrCode(cs[1]));
String name = namePart1 + namePart2;
resultMap.put(name, temp1);
}
} else if (objectType == 3) {
// 车道级
// condition是dir:turn(int):laneNum-dir1,dir2,dir3
String[] dir = condition.split("-");
List<CrossStatusDistributionVO> list = getCrossStatusDistribution_AllCondition(crossID, date, groupType, objectType, dir[1]);
String[] conditions = dir[0].split(";");
for (String c : conditions) {
String[] cs = c.split(":");
String turnDir = cs[1].toString();
List<CrossStatusDistributionVO> temp = list.stream().filter(p -> cs[0].equals(p.getDirType().toString())).collect(Collectors.toList());
List<CrossStatusDistributionVO> temp1 = temp.stream().filter(p -> turnDir.equals(p.getTurnType().toString())).collect(Collectors.toList());
List<CrossStatusDistributionVO> temp2 = temp1.stream().filter(p -> cs[2].equals(p.getLaneNo().toString())).collect(Collectors.toList());
String namePart1 = BaseEnum.SignalDirectionEnum.getNameByCode(Integer.parseInt(cs[0]));
String namePart2 = BaseEnum.TurnTypeEnum.getNameByCode(Integer.parseInt(cs[1]) );
String namePart3 = cs[2];
String name = namePart1 + namePart2 + namePart3;
resultMap.put(name, temp2);
}
} else if (objectType == 4) {
// 路口级
// 无condition
List<CrossStatusDistributionVO> list = getCrossStatusDistribution_SingleCondition(crossID, date, groupType, objectType, "");
resultMap.put("cross_list", list);
}
return resultMap;
}
/**
* 路口状态分布_单条件
*
* @param crossID 路口ID
* @param date 日期
* @param groupType 时间粒度 参数要求:0--5分钟 1--15分钟 2--30分钟 3--60分钟
* @param objectType 范围 参数要求:1--方向级 2--转向级 3--车道级 4--路口级
* @param condition 条件
*/
@Override
public List<CrossStatusDistributionVO> getCrossStatusDistribution_SingleCondition(String crossID, String date, String groupType, Integer objectType, String condition) {
Map<String, Object> params = new HashMap<>();
params.put("crossId", crossID);
params.put("startDate", date + " 00:00:00");
params.put("endDate", date + " 23:59:59");
params.put("groupType", groupType);
params.put("objectType", objectType);
if (objectType == 1) params.put("dir", condition);
if (objectType == 2) params.put("dir", condition.split(":")[0]);
if (objectType == 3) params.put("dir", condition.split(":")[0]);
List<CrossLaneDataHistPoExtend> firstList = greenwaveHistoryMapper.findCrossObjectIndexByDay(params);
List<CrossStatusDistributionVO> results = new ArrayList<>();
for (CrossLaneDataHistPoExtend c: firstList) {
CrossStatusDistributionVO cd = new CrossStatusDistributionVO();
cd.setSpeed(c.getSpeed());
cd.setStartTime(c.getStartTime().toString().substring(11, 16));
cd.setDelayTime(c.getDelayTime());
cd.setTurnType(c.getTurnType());
cd.setTurnTypeName(BaseEnum.TurnTypeEnum.getNameByCode(c.getTurnType()));
cd.setDirType(c.getDirType());
cd.setDirTypeName(BaseEnum.SignalDirectionEnum.getNameByCode(c.getDirType()));
cd.setStopTimes(c.getStopTimes());
cd.setQueueLength(c.getAvgQueueLength());
cd.setLaneNo(c.getLaneNo());
cd.setFlow(c.getFlow());
results.add(cd);
}
// 根据筛选条件筛选一次结果
if (objectType == 2) {
// 转向级
String[] con = condition.split(":");
results.removeIf(c -> !Objects.equals(c.getTurnType(), BaseEnum.TurnTypeEnum.getIntCodeByStrCode(con[1])));
} else if (objectType == 3) {
// 车道级
String[] con = condition.split(":");
results.removeIf(c -> c.getTurnType() != Integer.parseInt(con[1]));
results.removeIf(c -> c.getLaneNo() != Integer.parseInt(con[2]));
}
return results;
}
/**
* 路口状态分布_单条件
*
* @param crossID 路口ID
* @param date 日期
* @param groupType 时间粒度 参数要求:0--5分钟 1--15分钟 2--30分钟 3--60分钟
* @param objectType 范围 参数要求:1--方向级 2--转向级 3--车道级 4--路口级
* @param condition 条件
*/
public List<CrossStatusDistributionVO> getCrossStatusDistribution_AllCondition(String crossID, String date, String groupType, Integer objectType, String condition) {
Map<String, Object> params = new HashMap<>();
params.put("crossId", crossID);
params.put("startDate", date + " 00:00:00");
params.put("endDate", date + " 23:59:59");
params.put("groupType", groupType);
params.put("objectType", objectType);
params.put("dir", condition);
List<CrossLaneDataHistPoExtend> firstList = greenwaveHistoryMapper.findCrossObjectIndexByDay(params);
List<CrossStatusDistributionVO> results = new ArrayList<>();
for (CrossLaneDataHistPoExtend c: firstList) {
CrossStatusDistributionVO cd = new CrossStatusDistributionVO();
cd.setSpeed(c.getSpeed());
cd.setStartTime(c.getStartTime().toString().substring(11, 16));
cd.setDelayTime(c.getDelayTime());
cd.setTurnType(c.getTurnType());
cd.setTurnTypeName(BaseEnum.TurnTypeEnum.getNameByCode(c.getTurnType()));
cd.setDirType(c.getDirType());
cd.setDirTypeName(BaseEnum.SignalDirectionEnum.getNameByCode(c.getDirType()));
cd.setStopTimes(c.getStopTimes());
cd.setQueueLength(c.getAvgQueueLength());
cd.setLaneNo(c.getLaneNo());
cd.setFlow(c.getFlow());
results.add(cd);
}
return results;
}
/**
* 路口实时告警
*
* @param crossID 路口ID
* @param time 可选参数
*/
@Override
public List<CrossRealTimeAlarmEntity> getCrossRealTimeAlarm(String crossID, String time) {
List<CrossRealTimeAlarmEntity> list = new ArrayList<>();
CrossRealTimeAlarmEntity temp1 = new CrossRealTimeAlarmEntity();
CrossRealTimeAlarmEntity temp = crossMapper.getCrossRealTimeAlarms(crossID, time);
if(temp != null)
{
list.add(temp);
temp1 = crossMapper.getCrossRealTimeAlarmsPlan(crossID,temp.getStartTime() , temp.getEventSerialNumber() );
if(temp1 != null){
list.add(temp1);
}
}
return list;
}
@Override
public List<CrossStatusDisOptTimeEntity> getOptTimeList(String crossID) {
return crossMapper.getOptTimes(crossID);
}
/**
* 路口基础信息————方向、转向、车道信息
*
* @param crossID 路口ID
*/
@Override
public CrossBaseInfoVO getCrossBaseInfos(String crossID) {
List<CrossBaseInfoVO> crossBaseInfoVOS = new ArrayList<>();
List<CrossDirectionInfoEntity> directionInfoEntities = crossMapper.getCrossDirectionInfo(crossID);
List<CrossTurnInfoEntity> turnInfoEntities = crossMapper.getCrossTurnInfo(crossID);
List<CrossLaneInfoEntity> laneInfoEntities = crossMapper.getCrossLaneInfo(crossID);
CrossBaseInfoVO crossBaseInfoVO = new CrossBaseInfoVO();
crossBaseInfoVO.setCrossID(crossID);
crossBaseInfoVO.setDirectionInfo(directionInfoEntities);
crossBaseInfoVO.setTurnInfo(turnInfoEntities);
crossBaseInfoVO.setLaneInfo(laneInfoEntities);
return crossBaseInfoVO;
}
@Override
public List<CrossOrGreenWaveTypeEntity> getCrossTypeList(String crossID, String date) {
return crossMapper.getCrossTypeInfo(crossID, date.replace("-", ""));
}
}
package net.wanji.opt.servicev2.implv2;//package net.wanji.opt.servicev2.implv2;
//package net.wanji.opt.servicev2.implv2;
//
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
//import com.fasterxml.jackson.core.type.TypeReference;
......
......@@ -576,13 +576,13 @@ public class AnalysisGreenCongestionPeriodServiceImpl implements AnalysisGreenCo
if(temp.getGreenId().equals(greenId)){
if(queue.size() == 2){
//判断流量是否大于阀值
if(trafficThreshold < temp.getTrafficIndex() && StringUtil.isEmpty(startTime)){
if(trafficThreshold < temp.getTrafficIndex() && com.github.pagehelper.util.StringUtil.isEmpty(startTime)){
startTime = temp.getStartTime();
list.add(temp);
} else if( temp.getTrafficIndex() < trafficThreshold &&
queue.getFirst().getTrafficIndex() < trafficThreshold &&
queue.getLast().getTrafficIndex() < trafficThreshold &&
!StringUtil.isEmpty(startTime) ){
!com.github.pagehelper.util.StringUtil.isEmpty(startTime) ){
if(list.size() < 10){
startTime = "";
list.clear();
......@@ -966,13 +966,13 @@ public class AnalysisGreenCongestionPeriodServiceImpl implements AnalysisGreenCo
if(temp.getCrossId().equals(crossId)){
if(queue.size() == 2){
//判断流量是否大于阀值
if(trafficThreshold < temp.getTrafficIndex() && StringUtil.isEmpty(startTime)){
if(trafficThreshold < temp.getTrafficIndex() && com.github.pagehelper.util.StringUtil.isEmpty(startTime)){
startTime = temp.getStartTime();
list.add(temp);
} else if( temp.getTrafficIndex() < trafficThreshold &&
queue.getFirst().getTrafficIndex() < trafficThreshold &&
queue.getLast().getTrafficIndex() < trafficThreshold &&
!StringUtil.isEmpty(startTime) ){
!com.github.pagehelper.util.StringUtil.isEmpty(startTime) ){
if(list.size() < 10){
startTime = "";
list.clear();
......@@ -1436,13 +1436,13 @@ public class AnalysisGreenCongestionPeriodServiceImpl implements AnalysisGreenCo
if(temp.getCrossId().equals(crossId)){
if(queue.size() == 2){
//判断流量是否大于阀值
if(trafficThreshold < temp.getTrafficIndex() && StringUtil.isEmpty(startTime)){
if(trafficThreshold < temp.getTrafficIndex() && com.github.pagehelper.util.StringUtil.isEmpty(startTime)){
startTime = temp.getStartTime();
list.add(temp);
} else if( temp.getTrafficIndex() < trafficThreshold &&
queue.getFirst().getTrafficIndex() < trafficThreshold &&
queue.getLast().getTrafficIndex() < trafficThreshold &&
!StringUtil.isEmpty(startTime) ){
!com.github.pagehelper.util.StringUtil.isEmpty(startTime) ){
if(list.size() < 10){
startTime = "";
list.clear();
......
package net.wanji.opt.servicev2.syslog;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService;
import net.wanji.opt.entity.syslog.SysOptimizeLog;
import java.util.List;
/**
* <p>
* 系统日志 服务类
* </p>
*
* @author huangwm
* @since 2025-03-26
*/
public interface SysLogServer extends IService<SysOptimizeLog> {
JSONObject findSysOptimizeLog(String crossId, String startTime, String endTime, Integer pageNum, Integer pageSize);
}
package net.wanji.opt.servicev2.syslog.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.wanji.opt.dao.mapper.syslog.SysLogMapper;
import net.wanji.opt.entity.syslog.SysOptimizeLog;
import net.wanji.opt.servicev2.syslog.SysLogServer;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 系统日志
* </p>
*
* @author huangwm
* @since 2025-03-26
*/
@Service
public class SysLogServerImpl extends ServiceImpl<SysLogMapper, SysOptimizeLog> implements SysLogServer {
@Resource
private SysLogMapper sysLogMapper;
@Override
public JSONObject findSysOptimizeLog(String crossId, String startTime, String endTime, Integer pageNum, Integer pageSize) {
List<SysOptimizeLog> list = sysLogMapper.findSysOptimizeLog(crossId, startTime, endTime);
List<SysOptimizeLog> results = new ArrayList<>();
for (SysOptimizeLog temp : list) {
switch (temp.getCommandType()) {
case "1":
JSONObject temp1 = JSONObject.parseObject(temp.getDataInfo());
if (temp1.get("command").equals(1)) {
temp.setCommandType("步进控制");
} else if (temp1.get("command").equals(0)) {
temp.setCommandType("解除步进");
}
break;
case "2":
temp.setCommandType("恢复时间表");
break;
case "3":
JSONObject temp2 = JSONObject.parseObject(temp.getDataInfo());
if (temp2.get("command").equals(1)) {
temp.setCommandType("相位锁定");
} else if (temp2.get("command").equals(0)) {
temp.setCommandType("相位解锁");
}
break;
case "4":
temp.setCommandType("临时方案下发");
break;
case "5":
JSONObject temp3 = JSONObject.parseObject(temp.getDataInfo());
Integer commandType = temp3.getInteger("commandType");
switch (commandType) {
//1-步进控制/恢复(公用);2-恢复时间表(公用);3-相位锁定/解锁(公用);4-临时方案下发(公用);5-定时任务恢复失败;10-查询环图失败记录',
case 1:
temp.setCommandType("定时任务 - 解除步进控制");
break;
case 2:
temp.setCommandType("定时任务 - 恢复时间表");
break;
case 3:
temp.setCommandType("定时任务 - 解除相位锁定");
break;
case 4:
temp.setCommandType("定时任务 - 解除临时方案下发");
break;
default:
temp.setCommandType("定时任务 - 解除控制指令");
break;
}
default:
temp.setCommandType("其它操作");
break;
}
results.add(temp);
}
List<SysOptimizeLog> collect = new ArrayList<>();
if (CollectionUtils.isNotEmpty(results)) {
collect = results.stream().skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
}
JSONObject result = new JSONObject();
result.put("fullDataList", results);
result.put("pageList", collect);
result.put("totalPage", Math.ceil((double) results.size() / pageSize));
result.put("totalSize", results.size());
return result;
}
}
package net.wanji.opt.synthesis.service.impl;//package net.wanji.opt.synthesis.service.impl;
//package net.wanji.opt.synthesis.service.impl;
//
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
......
package net.wanji.opt.task;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.enums.CrossStatusEnum;
import net.wanji.common.framework.Constants;
import net.wanji.databus.dao.mapper.CrossDataRealtimeMapper;
import net.wanji.databus.po.CrossDataRealtimePO;
import net.wanji.opt.kafka.ConsumerHandler;
import net.wanji.opt.service.CrossOptimizeService;
import net.wanji.opt.service.impl.LaneInfoServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author hfx
* @date 2023/1/16 16:39
* @desc RealtimeOptimizeTask
*/
@RequiredArgsConstructor
@Component
@Slf4j
public class CrossMonitorTask {
private final CrossOptimizeService crossOptimizeService;
private final ConsumerHandler consumerHandler;
private final CrossDataRealtimeMapper crossDataRealtimeMapper;
private final LaneInfoServiceImpl laneInfoService;
/**
* 路口实时监测
*
*/
//@Scheduled(fixedRate = 1 * 60 * 1000)
//public void realtimeMonitor() {
// log.info("路口实时监测任务...");
// 获取路口实时监测数据
//List<CrossDataRealtimePO> crossDataRealtimePOList = listCrossDataRealtime();
//log.info("路口实时数据:{}条", crossDataRealtimePOList.size());
// 测试时无数据暂时注释
// if(crossDataRealtimePOList.isEmpty()) {
// return ;
// }
// 获取所有信控路口异常数据(失衡/拥堵/溢出/死锁)
//List<CrossDataRealtimePO> abnormalCrossList = listAbnormalCross(crossDataRealtimePOList);
//log.info("加载异常路口:{}条", abnormalCrossList.size());
// if(abnormalCrossList.isEmpty()) {
// return ;
// }
// 调用路口实时优化
//crossOptimizeService.realtimeOptimize(abnormalCrossList, crossDataRealtimePOList);
//}
/**
* 获取异常路口数据
*
* @return
*/
public List<CrossDataRealtimePO> listAbnormalCross(List<CrossDataRealtimePO> crossDataRealtimePOList) {
List<CrossDataRealtimePO> dtoList = new ArrayList<>();
CrossDataRealtimePO dto = null;
int status = 0;
for (CrossDataRealtimePO po : crossDataRealtimePOList) {
// 获取失衡、拥堵、溢出路口数据
if (Constants.SystemParam.NO.equals(po.getIsSpillover()) && Constants.SystemParam.NO.equals(po.getIsCongestion()) && Constants.SystemParam.NO.equals(po.getIsUnbalance())) {
continue;
}
if (Constants.SystemParam.YES.equals(po.getIsSpillover())) { // 溢出
status = CrossStatusEnum.SPILLOVER.getCode();
} else if (Constants.SystemParam.YES.equals(po.getIsCongestion())) { // 拥堵
status = CrossStatusEnum.CONGESTION.getCode();
} else if (Constants.SystemParam.YES.equals(po.getIsUnbalance())) { // 失衡
status = CrossStatusEnum.UNBALANCE.getCode();
}
dto = new CrossDataRealtimePO();
BeanUtils.copyProperties(po, dto);
dto.setCrossId(po.getCrossId());
dto.setStatus(status);
dtoList.add(dto);
}
return dtoList;
}
/**
* 获取路口实时监测数据,获取数据中心存入到数据库中的数据
* (暂定从数据中心kafka获取)
*
* @return
*/
public List<CrossDataRealtimePO> listCrossDataRealtime() {
// todo 测试数据
LambdaQueryWrapper<CrossDataRealtimePO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(CrossDataRealtimePO::getCrossId, "14Q0S09IQB0")
.or().eq(CrossDataRealtimePO::getCrossId, "14Q1409IRF0")
.or().eq(CrossDataRealtimePO::getCrossId, "14PU609IQA0")
.or().eq(CrossDataRealtimePO::getCrossId, "14Q1509ISH0")
.or().eq(CrossDataRealtimePO::getCrossId, "14Q1S09IR70")
.or().eq(CrossDataRealtimePO::getCrossId, "14Q0O09INT0");
List<CrossDataRealtimePO> crossDataRealtimePOS = crossDataRealtimeMapper.selectList(queryWrapper);
return crossDataRealtimePOS;
}
}
\ No newline at end of file
......@@ -32,7 +32,7 @@ public class TablePartitionManagerTask {
public void createTablePartition() {
String[] tableList = partitionTableList.split(",");
DateTime tomorrow = DateTime.now().offset(DateField.HOUR,24);
DateTime tomorrow = DateTime.now().offset(DateField.HOUR,1);
Integer dt = Integer.parseInt(DateUtil.format(tomorrow.toJdkDate(), "yyyyMMdd"));
......
package net.wanji.opt.task;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.ResponseHeader;
import lombok.extern.slf4j.Slf4j;
import net.wanji.common.framework.rest.JsonViewObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* </p>
*
* @author fengyi
* @version 1.0
* @Date 2023-04-08
*/
@RestController
@Slf4j
@RequestMapping("/taskTest")
@Api(value = "TaskControllerTest", description = "", tags = "定时任务测试")
public class TaskControllerTest {
@Resource
AnalysisGreenCongestionPeriodWeekTask analysisGreenCongestionPeriodWeekTask;
@Resource
AnalysisProblemAndStrategyDayTask analysisProblemAndStrategyDayTask;
@Resource
AnalysisProblemCrossDayTask analysisProblemCrossDayTask;
@Resource
AnalysisProblemCrossDirHourTask analysisProblemCrossDirHourTask;
@Resource
AnalysisProblemDayTask analysisProblemDayTask;
@Resource
AnalysisProblemHourTask analysisProblemHourTask;
@Resource
GreenWaveWeekDataTask greenWaveWeekDataTask;
@Resource
ReportGreenAndCrossOptimizeStatisticTask reportGreenAndCrossOptimizeStatisticTask;
@GetMapping("/request")
public JsonViewObject list(int type) {
try {
JsonViewObject jsonViewObject = JsonViewObject.newInstance();
if (type == 1) {
//TODO 待验证
analysisGreenCongestionPeriodWeekTask.task();
}
if (type == 2) {
analysisGreenCongestionPeriodWeekTask.taskDay();
}
if (type == 3) {
analysisGreenCongestionPeriodWeekTask.insertCrossSlowRunEventData();
}
//============================================================//
if (type == 5) {
analysisProblemAndStrategyDayTask.taskCross();
}
if (type == 6) {
analysisProblemAndStrategyDayTask.taskGreen();;
}
//================================================//
if (type == 7) {
analysisProblemCrossDayTask.executeGreenCrossHourTask();;
}
if (type == 8) {
analysisProblemCrossDayTask.executeWeeklyTask();
}
//=================================================
if (type == 9) {
//TODO 异常
analysisProblemCrossDirHourTask.executeCrossOverFlowTask();
}
if (type == 10) {
analysisProblemDayTask.task();
}
if (type == 11) {
analysisProblemHourTask.task();
}
if (type == 12) {
greenWaveWeekDataTask.executeWeeklyTask();
}
if (type == 13) {
reportGreenAndCrossOptimizeStatisticTask.optimizeDurationCal();
}
if (type == 14) {
reportGreenAndCrossOptimizeStatisticTask.optimizeGreenWaveDurationCal();
}
return jsonViewObject.success();
} catch (Exception e) {
log.error("", e);
return JsonViewObject.newInstance().fail("请求失败");
}
}
}
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