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.lightshare.bean.AreaVo
|
import com.flightfeather.uav.socket.eunm.FactorType
|
import com.flightfeather.uav.socket.sender.MsgType
|
import java.util.*
|
import kotlin.math.round
|
|
/**
|
* 走航任务汇总
|
* @date 2025/8/22
|
* @author feiyu02
|
*/
|
class MissionSummary() {
|
|
companion object {
|
private const val FOCUS_AREA_COUNT = 2
|
}
|
|
data class Summary(
|
// 汇总周期开始时间
|
val startTime: Date,
|
// 汇总周期结束时间
|
val endTime: Date,
|
// 走航区域信息
|
val area: AreaVo,
|
// 走航次数
|
val count: Int,
|
// 总里程数(公里)
|
val kilometres: Double,
|
// 涉及区域
|
val regionList: List<String>,
|
// 各等级空气质量背景走航次数,<空气质量等级,次数,占比>
|
val countByDegree: List<Triple<String, Int, Double>>,
|
// 问题总数
|
val probCount: Int,
|
// 高风险场景总数
|
val highRiskSceneCount: Int,
|
// 问题按监测因子类型分布情况, <因子类型,次数,占比>
|
val probByFactor: List<Triple<String, Int, Double>>,
|
// 聚焦区域或场景
|
val focusRegion: List<String>,
|
)
|
|
/**
|
* 根据时间范围查询走航任务并生成统计结果
|
* @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(),
|
focusRegion = 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. 从异常所在地区和溯源的场景中统计聚焦区域
|
val focusRegion = calFocusRegion(clues)
|
|
// 8. 构建并返回统计结果
|
return Summary(
|
startTime = startTime,
|
endTime = endTime,
|
area = area,
|
count = totalCount,
|
kilometres = totalKilometres,
|
regionList = regionList,
|
countByDegree = countByDegree,
|
probCount = probCount,
|
highRiskSceneCount = highRiskSceneCount,
|
probByFactor = probByFactor,
|
focusRegion = focusRegion
|
)
|
}
|
|
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)
|
}
|
|
private fun calFocusRegion(clues: List<PollutedClue?>): List<String> {
|
// 统计每个区域或场景出现的次数
|
val focusArea = mutableMapOf<String, Int>()
|
val focusScene = mutableMapOf<String, Int>()
|
clues.forEach { c->
|
if (c?.msgType == MsgType.PolClue.value) {
|
if (!c.pollutedArea?.address.isNullOrBlank()) {
|
if (focusArea.containsKey(c.pollutedArea?.address)) {
|
focusArea[c.pollutedArea?.address!!] = focusArea[c.pollutedArea?.address]!! + 1
|
} else {
|
focusArea[c.pollutedArea?.address!!] = 1
|
}
|
}
|
c.pollutedSource?.sceneList?.forEach { s->
|
if (s.name != null) {
|
if (focusScene.containsKey(s.name!!)) {
|
focusScene[s.name!!] = focusScene[s.name!!]!! + 1
|
} else {
|
focusScene[s.name!!] = 1
|
}
|
}
|
}
|
}
|
}
|
return focusArea.entries.sortedByDescending { it.value }.map { it.key }.take(FOCUS_AREA_COUNT) +
|
focusScene.entries.sortedByDescending { it.value }.map { it.key }.take(FOCUS_AREA_COUNT)
|
}
|
}
|