From 94fee0b511279679b43e210878d3d36e5a14384b Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期二, 30 九月 2025 09:14:10 +0800 Subject: [PATCH] 2025.9.30 1. 新增走航任务统计功能 --- src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 152 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt index beb76d5..ff1ab18 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/report/MissionSummary.kt @@ -1,16 +1,31 @@ package com.flightfeather.uav.biz.report -import org.springframework.stereotype.Component +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 */ -@Component -class MissionSummary { +class MissionSummary() { - inner class Summary( + companion object { + private const val FOCUS_AREA_COUNT = 2 + } + + data class Summary( + // 姹囨�诲懆鏈熷紑濮嬫椂闂� + val startTime: Date, + // 姹囨�诲懆鏈熺粨鏉熸椂闂� + val endTime: Date, + // 璧拌埅鍖哄煙淇℃伅 + val area: AreaVo, // 璧拌埅娆℃暟 val count: Int, // 鎬婚噷绋嬫暟锛堝叕閲岋級 @@ -20,14 +35,143 @@ // 鍚勭瓑绾х┖姘旇川閲忚儗鏅蛋鑸鏁�,<绌烘皵璐ㄩ噺绛夌骇锛屾鏁帮紝鍗犳瘮> val countByDegree: List<Triple<String, Int, Double>>, // 闂鎬绘暟 - val probCount:Int, + val probCount: Int, // 楂橀闄╁満鏅�绘暟 - val highRiskSceneCount:Int, + val highRiskSceneCount: Int, // 闂鎸夌洃娴嬪洜瀛愮被鍨嬪垎甯冩儏鍐�, <鍥犲瓙绫诲瀷锛屾鏁帮紝鍗犳瘮> - val probByFactor:List<Triple<String, Int, Double>> + val probByFactor: List<Triple<String, Int, Double>>, + // 鑱氱劍鍖哄煙鎴栧満鏅� + val focusRegion: List<String>, ) - 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(), + 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) } } \ No newline at end of file -- Gitblit v1.9.3