package com.flightfeather.uav.lightshare.service.impl
|
|
import com.flightfeather.uav.biz.FactorFilter
|
import com.flightfeather.uav.biz.dataanalysis.ExceptionAnalysisController
|
import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult
|
import com.flightfeather.uav.biz.report.MissionGridFusion
|
import com.flightfeather.uav.biz.report.MissionInventory
|
import com.flightfeather.uav.biz.report.MissionRiskArea
|
import com.flightfeather.uav.biz.report.MissionSummary
|
import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue
|
import com.flightfeather.uav.common.exception.BizException
|
import com.flightfeather.uav.common.location.LocationRoadNearby
|
import com.flightfeather.uav.common.utils.GsonUtils
|
import com.flightfeather.uav.domain.entity.*
|
import com.flightfeather.uav.domain.mapper.MissionMapper
|
import com.flightfeather.uav.domain.repository.*
|
import com.flightfeather.uav.lightshare.bean.AreaVo
|
import com.flightfeather.uav.lightshare.bean.GridDataDetailMixVo
|
import com.flightfeather.uav.lightshare.eunm.PollutionDegree
|
import com.flightfeather.uav.lightshare.eunm.SceneType
|
import com.flightfeather.uav.lightshare.service.DataAnalysisService
|
import com.flightfeather.uav.lightshare.service.SatelliteDataCalculateService
|
import com.flightfeather.uav.socket.eunm.FactorType
|
import com.flightfeather.uav.socket.sender.MsgType
|
import org.springframework.stereotype.Service
|
import tk.mybatis.mapper.entity.Example
|
import java.util.*
|
|
/**
|
* 数据分析服务接口实现类
|
* 提供走航任务数据的统计分析、污染溯源、任务清单及详情生成等核心业务功能
|
* 整合多数据源完成数据聚合与分析,为前端提供标准化的统计结果
|
* @date 2025/5/8
|
* @author feiyu02
|
*/
|
@Service
|
class DataAnalysisServiceImpl(
|
private val missionRep: MissionRep,
|
private val missionMapper: MissionMapper,
|
private val realTimeDataRep: RealTimeDataRep,
|
private val locationRoadNearby: LocationRoadNearby,
|
private val segmentInfoRep: SegmentInfoRep,
|
private val sourceTraceRep: SourceTraceRep,
|
private val sceneInfoRep: SceneInfoRep,
|
private val satelliteGridRep: SatelliteGridRep,
|
private val satelliteDataCalculateService: SatelliteDataCalculateService
|
) : DataAnalysisService {
|
|
/**
|
* 污染溯源分析
|
* 对指定走航任务进行多因子污染数据分析,识别异常数据点和潜在污染源
|
* @param missionCode 走航任务编码(主键)
|
* @return 异常结果列表,包含异常类型、位置、浓度值等详细信息
|
* @throws BizException 当走航任务不存在时抛出
|
* @see ExceptionAnalysisController 异常分析控制器,处理具体的数据分析逻辑
|
*/
|
override fun pollutionTrace(missionCode: String): List<ExceptionResult> {
|
val mission = missionRep.findOne(missionCode) ?: throw BizException("走航任务不存在")
|
|
val exceptionAnalysisController =
|
ExceptionAnalysisController(realTimeDataRep, locationRoadNearby, segmentInfoRep)
|
|
return exceptionAnalysisController.execute(
|
mission, FactorFilter.builder()
|
// .withMain(FactorType.NO2)
|
.withMain(FactorType.CO)
|
// .withMain(FactorType.H2S)
|
// .withMain(FactorType.SO2)
|
// .withMain(FactorType.O3)
|
.withMain(FactorType.PM25)
|
.withMain(FactorType.PM10)
|
.withMain(FactorType.VOC)
|
.create()
|
)
|
}
|
|
/**
|
* 获取历史污染溯源结果
|
* 查询指定任务的历史污染溯源结果并序列化为JSON字符串
|
* @param missionCode 走航任务编码
|
* @return 历史污染溯源结果的JSON字符串,具体格式由sourceTraceRep实现决定
|
* @throws BizException 当走航任务不存在时抛出
|
*/
|
override fun fetchHistory(missionCode: String): String {
|
val mission = missionRep.findOne(missionCode) ?: throw BizException("走航任务不存在")
|
|
val res = sourceTraceRep.fetchList(mission.deviceCode, mission.startTime, mission.endTime)
|
return GsonUtils.gson.toJson(res)
|
}
|
|
/**
|
* 生成走航任务汇总统计
|
* 按时间范围和行政区划统计走航任务的关键指标(任务数量、异常率、平均里程等)
|
* @param startTime 统计起始时间(包含)
|
* @param endTime 统计结束时间(包含)
|
* @param areaVo 区域参数,包含省、市、区三级行政区划编码
|
* @return 汇总统计对象,包含任务总数、异常点数量、平均里程等核心指标
|
* @see MissionSummary 汇总统计处理器,封装具体的统计逻辑实现
|
*/
|
override fun generateMissionSummary(startTime: Date, endTime: Date, areaVo: AreaVo): MissionSummary.Summary {
|
val clues = mutableListOf<PollutedClue?>()
|
val missions = missionRep.findByAreaAndTime(areaVo, startTime, endTime).onEach {
|
it ?: return@onEach
|
val clue = sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?>
|
clues.addAll(clue)
|
}
|
val summary = MissionSummary().execute(startTime, endTime, missions, clues)
|
return summary
|
}
|
|
/**
|
* 生成走航任务清单(按时间和区域筛选)
|
* 根据时间范围和行政区划查询走航任务,并关联污染线索数据生成任务列表
|
* @param startTime 查询起始时间(包含)
|
* @param endTime 查询结束时间(包含)
|
* @param areaVo 区域参数,包含省、市、区编码
|
* @return 走航任务信息列表,每个元素包含任务基本信息和关联的污染线索
|
* @see MissionRep.findByAreaAndTime 区域时间筛选数据源
|
* @see generateMissionList 重载方法,处理已关联的数据对
|
*/
|
override fun generateMissionList(startTime: Date, endTime: Date, areaVo: AreaVo): List<MissionInventory.MissionInfo> {
|
val missionClues = missionRep.findByAreaAndTime(areaVo, startTime, endTime).filterNotNull().map {
|
it to sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?>
|
}
|
return generateMissionList(missionClues)
|
}
|
|
/**
|
* 生成走航任务清单(直接处理任务数据)
|
* 接收已关联的任务-污染线索数据对,生成格式化的任务列表
|
* @param missionClues 任务-污染线索数据对列表,Pair.first为任务对象,Pair.second为对应污染线索
|
* @return 标准化的走航任务信息列表,包含任务基本属性和污染统计信息
|
* @see MissionInventory 任务清单生成器,封装具体格式化逻辑
|
*/
|
override fun generateMissionList(missionClues: List<Pair<Mission, List<PollutedClue?>>>): List<MissionInventory.MissionInfo> {
|
return MissionInventory().generateMissionList(missionClues)
|
}
|
|
/**
|
* 生成走航任务详情(按时间和区域筛选)
|
* 根据时间范围和行政区划查询任务,整合实时监测数据生成详细任务报告
|
* @param startTime 查询起始时间(包含)
|
* @param endTime 查询结束时间(包含)
|
* @param areaVo 区域参数,包含省、市、区编码
|
* @return 任务详情列表,每个元素包含任务完整信息、污染线索及实时监测数据
|
* @see MissionRep.findByAreaAndTime 区域时间筛选数据源
|
* @see realTimeDataRep.fetchData 实时数据获取接口
|
*/
|
override fun generateMissionDetail(startTime: Date, endTime: Date, areaVo: AreaVo): List<MissionInventory.MissionDetail> {
|
val missionCluesData = missionRep.findByAreaAndTime(areaVo, startTime, endTime).filterNotNull().map {
|
Triple(
|
it,
|
sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?>,
|
realTimeDataRep.fetchData(it)
|
)
|
}
|
val keyScenes = sceneInfoRep.findBySceneTypes(
|
listOf(
|
SceneType.TYPE19.value,
|
SceneType.TYPE20.value,
|
SceneType.TYPE21.value
|
)
|
)
|
return generateMissionDetail(keyScenes, missionCluesData)
|
}
|
|
/**
|
* 生成走航任务详情(直接处理任务数据)
|
* 接收已关联的任务-污染线索-实时数据三元组,生成详细任务报告
|
* @param keyScenes 关键场景列表,用于分析走航是否经过该区域
|
* @param missionCluesData 任务数据三元组列表,Triple分别为任务对象、污染线索列表、实时数据列表
|
* @return 标准化的任务详情列表,包含完整的任务属性、污染分析和监测数据统计
|
* @see MissionInventory.generateMissionDetail 详情生成核心逻辑
|
*/
|
override fun generateMissionDetail(
|
keyScenes: List<SceneInfo?>,
|
missionCluesData: List<Triple<Mission, List<PollutedClue?>, List<BaseRealTimeData>>>,
|
): List<MissionInventory.MissionDetail> {
|
return missionCluesData.map {
|
MissionInventory().generateMissionDetail(keyScenes, it.first, it.second, it.third)
|
}
|
}
|
|
override fun generateClueByRiskArea(
|
startTime: Date,
|
endTime: Date,
|
areaVo: AreaVo,
|
): List<MissionRiskArea.ClueByArea> {
|
val clues = mutableListOf<PollutedClue?>()
|
missionRep.findByAreaAndTime(areaVo, startTime, endTime).onEach {
|
it ?: return@onEach
|
val clue = sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?>
|
clues.addAll(clue)
|
}
|
val keyScenes = sceneInfoRep.findBySceneTypes(
|
listOf(
|
SceneType.TYPE19.value,
|
SceneType.TYPE20.value,
|
SceneType.TYPE21.value
|
)
|
)
|
return generateClueByRiskArea(keyScenes, clues)
|
}
|
|
override fun generateClueByRiskArea(
|
keyScenes: List<SceneInfo?>,
|
pollutedClues: List<PollutedClue?>,
|
): List<MissionRiskArea.ClueByArea> {
|
return MissionRiskArea().generateClueByRiskArea(keyScenes, pollutedClues)
|
}
|
|
override fun generateGridFusion(
|
factorTypes: List<FactorType>,
|
startTime: Date,
|
endTime: Date,
|
areaVo: AreaVo,
|
): List<MissionGridFusion.GridFusionByAQI> {
|
val gridLen = 100
|
// 查询100米网格的具体网格数据
|
val gridGroup = satelliteGridRep.fetchGridGroup(GridGroup().apply {
|
type = "sub"
|
length = gridLen.toDouble()
|
provinceCode = areaVo.provinceCode
|
cityCode = areaVo.cityCode
|
districtCode = areaVo.districtCode
|
}).firstOrNull() ?: throw BizException("未查询到100米网格")
|
val gridCells = satelliteGridRep.fetchGridCell(gridGroup.id).filterNotNull()
|
// 查询范围内的所有走航任务
|
val missions = missionRep.findByAreaAndTime(areaVo, startTime, endTime)
|
// 根据空气质量等级分类
|
val missionGroups = missions.groupBy { PollutionDegree.getByDes(it?.pollutionDegree ?: "") }
|
// 查询每个等级下的走航任务对应的网格数据(如果没有数据则剔除该任务)
|
val gridDataDetailList = missionGroups.mapNotNull { (degree, missionList) ->
|
// 筛选出有网格融合数据的走航任务(同时获取对应的融合数据id列表)
|
val gridDataIds = mutableListOf<Int>()
|
val validMissions = missionList.filter {mission ->
|
val gridData = satelliteGridRep.fetchGridData(GridData().apply { missionCode = mission?.missionCode }).firstOrNull()
|
val res = gridData != null
|
if (res) gridDataIds.add(gridData?.id ?: 0)
|
res
|
}
|
// 合并每个等级下的网格数据
|
val gridDataDetailMixVos = satelliteDataCalculateService.mixUnderwayGridData(gridGroup.id, gridDataIds)
|
// 统计每个走航任务的走航详情信息
|
val missionCluesData = validMissions.filterNotNull().map {
|
Triple(
|
it,
|
sourceTraceRep.fetchList(it.deviceCode, it.startTime, it.endTime, MsgType.PolClue) as List<PollutedClue?>,
|
realTimeDataRep.fetchData(it)
|
)
|
}
|
val keyScenes = sceneInfoRep.findBySceneTypes(
|
listOf(
|
SceneType.TYPE19.value,
|
SceneType.TYPE20.value,
|
SceneType.TYPE21.value
|
)
|
)
|
val missionDetails = generateMissionDetail(keyScenes, missionCluesData)
|
|
return@mapNotNull Triple(degree, missionDetails, gridDataDetailMixVos)
|
}.filter { it.second.isNotEmpty() }
|
|
return generateGridFusion(factorTypes, gridLen, gridCells, gridDataDetailList)
|
}
|
|
override fun generateGridFusion(
|
factorTypes: List<FactorType>,
|
gridLen: Int,
|
gridCells: List<GridCell>,
|
dataList: List<Triple<PollutionDegree, List<MissionInventory.MissionDetail>, List<GridDataDetailMixVo>>>,
|
): List<MissionGridFusion.GridFusionByAQI> {
|
return MissionGridFusion(sceneInfoRep).generateGridFusion(factorTypes, gridLen, gridCells, dataList)
|
}
|
}
|