| | |
| | | package com.flightfeather.uav.biz.report |
| | | |
| | | import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue |
| | | import com.flightfeather.uav.domain.entity.Mission |
| | | import com.flightfeather.uav.domain.repository.MissionRep |
| | | import com.flightfeather.uav.lightshare.bean.AreaVo |
| | | import com.flightfeather.uav.socket.eunm.FactorType |
| | | import com.flightfeather.uav.socket.sender.MsgType |
| | | import org.springframework.stereotype.Component |
| | | import java.util.* |
| | | import kotlin.math.round |
| | | |
| | | /** |
| | | * 走航任务汇总 |
| | | * @date 2025/8/22 |
| | | * @author feiyu02 |
| | | */ |
| | | @Component |
| | | class MissionSummary { |
| | | class MissionSummary() { |
| | | |
| | | inner class Summary( |
| | | data class Summary( |
| | | // 汇总周期开始时间 |
| | | val startTime: Date, |
| | | // 汇总周期结束时间 |
| | | val endTime: Date, |
| | | // 走航区域信息 |
| | | val area: AreaVo, |
| | | // 走航次数 |
| | | val count: Int, |
| | | // 总里程数(公里) |
| | |
| | | val probByFactor:List<Triple<String, Int, Double>> |
| | | ) |
| | | |
| | | fun execute() { |
| | | /** |
| | | * 根据时间范围查询走航任务并生成统计结果 |
| | | * @param startTime 统计开始时间 |
| | | * @param endTime 统计结束时间 |
| | | * @param missions 走航任务列表(外部传入,避免重复查询) |
| | | * @param clues 污染线索列表(用于问题统计) |
| | | * @return 走航任务统计结果Summary |
| | | */ |
| | | fun execute(startTime: Date, endTime: Date, missions: List<Mission?>, clues: List<PollutedClue?>): Summary { |
| | | // 1. 查询指定时间范围内的走航任务 |
| | | if (missions.isEmpty()) { |
| | | return Summary( |
| | | startTime = startTime, |
| | | endTime = endTime, |
| | | area = AreaVo(), // 空任务时返回默认区域信息 |
| | | count = 0, |
| | | kilometres = 0.0, |
| | | regionList = emptyList(), |
| | | countByDegree = emptyList(), |
| | | probCount = 0, |
| | | highRiskSceneCount = 0, |
| | | probByFactor = emptyList() |
| | | ) |
| | | } |
| | | |
| | | // 2. 基础统计:总任务数、总里程 |
| | | val totalCount = missions.size |
| | | val totalKilometres = missions.sumOf { it?.kilometres?.toDouble() ?: 0.0 } |
| | | |
| | | // 3. 区域信息:取首个任务的行政区划信息(如存在多区域可扩展为合并逻辑) |
| | | val firstMission = missions.first() |
| | | val area = AreaVo().apply { |
| | | provinceCode = firstMission?.provinceCode |
| | | provinceName = firstMission?.provinceName |
| | | cityCode = firstMission?.cityCode |
| | | cityName = firstMission?.cityName |
| | | districtCode = firstMission?.districtCode |
| | | districtName = firstMission?.districtName |
| | | townCode = firstMission?.townCode |
| | | townName = firstMission?.townName |
| | | } |
| | | |
| | | // 4. 涉及区域列表:去重收集所有任务的region字段 |
| | | val regionList = missions.mapNotNull { it?.region }.distinct() |
| | | |
| | | // 5. 空气质量等级分布:按pollutionDegree分组统计次数及占比 |
| | | val degreeGroups = missions |
| | | .filter { it?.pollutionDegree != null } // 过滤无效等级 |
| | | .groupBy { it?.pollutionDegree!! } |
| | | .mapValues { it.value.size } |
| | | val countByDegree = degreeGroups.map { (degree, count) -> |
| | | Triple(degree, count, count.toDouble() / totalCount) |
| | | } |
| | | |
| | | // 6. 问题相关统计 |
| | | val clueRes = calClue(clues) |
| | | val probCount = clueRes.first // 需关联问题表统计 |
| | | val highRiskSceneCount = clueRes.second // 需关联场景表统计 |
| | | val probByFactor = clueRes.third |
| | | |
| | | // 7. 构建并返回统计结果 |
| | | return Summary( |
| | | startTime = startTime, |
| | | endTime = endTime, |
| | | area = area, |
| | | count = totalCount, |
| | | kilometres = totalKilometres, |
| | | regionList = regionList, |
| | | countByDegree = countByDegree, |
| | | probCount = probCount, |
| | | highRiskSceneCount = highRiskSceneCount, |
| | | probByFactor = probByFactor |
| | | ) |
| | | } |
| | | |
| | | private fun calClue(clues: List<PollutedClue?>): Triple<Int, Int, List<Triple<String, Int, Double>>> { |
| | | var probCount = 0 |
| | | var highRiskSceneCount = 0 |
| | | val probByFactorMap = mutableMapOf<FactorType, Int>() |
| | | clues.forEach { c -> |
| | | if (c?.msgType == MsgType.PolClue.value) { |
| | | c.pollutedSource?.sceneList?.size?.let { s -> highRiskSceneCount += s } |
| | | c.pollutedData?.statisticMap?.keys?.forEach { k -> |
| | | probCount++ |
| | | if (!probByFactorMap.containsKey(k)) { |
| | | probByFactorMap[k] = 0 |
| | | } |
| | | probByFactorMap[k] = probByFactorMap[k]!! + 1 |
| | | } |
| | | } |
| | | } |
| | | val probByFactor = probByFactorMap.entries.map { |
| | | val per = if(probCount == 0) .0 else round(it.value.toDouble() / probCount * 100) / 100 |
| | | Triple(it.key.des, it.value, per) |
| | | } |
| | | return Triple(probCount, highRiskSceneCount, probByFactor) |
| | | } |
| | | } |