From 9c797fa0d704ef8ffb65cd1716b8eb694b4c46c3 Mon Sep 17 00:00:00 2001
From: feiyu02 <risaku@163.com>
Date: 星期五, 04 七月 2025 17:28:00 +0800
Subject: [PATCH] 2025.7.4 1. 新增动态污染溯源新的判定逻辑

---
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt |  190 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 187 insertions(+), 3 deletions(-)

diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt
index 91983a8..cbd6721 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt
@@ -1,12 +1,27 @@
 package com.flightfeather.uav.biz.sourcetrace.model
 
+import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
+import com.flightfeather.uav.common.net.AMapService
+import com.flightfeather.uav.common.utils.DateUtil
+import com.flightfeather.uav.common.utils.MapUtil
+import com.flightfeather.uav.domain.entity.BaseRealTimeData
+import com.flightfeather.uav.domain.entity.SceneInfo
+import java.math.BigDecimal
+import java.time.LocalDateTime
+import java.util.Date
+import java.util.Timer
+import java.util.TimerTask
+
+// 寮傚父鏁版嵁鐢熸垚鍥炶皟绫�
+typealias NewPolluteSummaryCallback = (ex: AnalysisResult) -> Unit
+
 /**
  * 姹℃煋鎯呭喌姹囨��
  * 閽堝鍗曟璧拌埅锛屽畾鏃剁粺璁″凡鏈夋薄鏌撶嚎绱PollutedClue]锛屾寜鐓х瓥鐣ョ粰鍑鸿蛋鑸缓璁�
  * @date 2025/5/27
  * @author feiyu02
  */
-class PollutedSummary {
+class PollutedSummary(private val config: RTExcWindLevelConfig, private val callback: NewPolluteSummaryCallback) {
 
 
     /**
@@ -14,6 +29,175 @@
      * 姣忎竴鍒婚挓瀵瑰巻鍙茬嚎绱㈣繘琛岀粺璁★紝鎻愬嚭浼氬晢寤鸿锛堢姹℃煋婧愯緝杩溿�佹薄鏌撴簮鏁伴噺銆佸嚭鐜版鏁帮級銆佽蛋鑸矾绾胯皟鏁村缓璁紙绂绘薄鏌撴簮杈冭繎銆佽蛋鑸建杩规湭鎺ヨ繎婧簮鍦烘櫙锛�
      */
 
-    // 姹℃煋绾跨储
-    var clueList = mutableListOf<PollutedClue>()
+    /**
+     * 瀹炴椂缁熻
+     */
+    inner class AnalysisStatistic {
+        // 鎸夌収琚壂鎻忔鏁伴檷搴忔帓鍒楃殑姹℃煋婧愬垪琛�
+        var sortedSceneList: List<Pair<SceneInfo?, Int>>? = null
+    }
+
+    // 鏈�鏂板疄鏃惰蛋鑸洃娴嬫暟鎹�
+    val realTimeDataList = mutableListOf<BaseRealTimeData>()
+
+    // 鏈垎鏋愮殑姹℃煋绾跨储
+    val clueList = mutableListOf<PollutedClue>()
+
+    // 宸插垎鏋愮殑姹℃煋绾跨储
+    private val historyClueList = mutableListOf<PollutedClue>()
+
+    // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟鎺у埗
+    private var analysisTimer: Timer? = null
+
+    // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟
+    private var lastAnalysisOnTimeTask: TimerTask? = null
+
+    // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟杩愯鐘舵��
+    private var analysisTaskIsRunning = false
+
+    // 涓婁竴娆″畾鏃舵薄鏌撳垎鏋愪换鍔$粨鏉熸椂闂�
+    private lateinit var lastAnalysisTime: LocalDateTime
+
+    init {
+        clear()
+    }
+
+    // 鏂板涓�鏉℃薄鏌撶嚎绱�
+    fun addClue(pollutedClue: PollutedClue) {
+        clueList.add(pollutedClue)
+//        realTimeSummary()
+        analysisOnClueCount()
+    }
+
+    // 鍒锋柊褰撳墠鏈�鏂扮殑璧拌埅鐩戞祴鏁版嵁
+    fun refreshLatestMonitorData(data: BaseRealTimeData) {
+//        realTimeDataList.clear()
+        realTimeDataList.add(data)
+    }
+
+    fun clear() {
+        realTimeDataList.clear()
+        clueList.clear()
+        historyClueList.clear()
+        analysisTimer?.cancel()
+        analysisTimer = null
+        analysisTaskIsRunning = false
+        lastAnalysisTime = LocalDateTime.now()
+        resetAnalysisOnTime()
+    }
+
+    /**
+     * 閲嶇疆瀹氭椂鍒嗘瀽绾跨储浠诲姟
+     */
+    private fun resetAnalysisOnTime() {
+        // 鍙栨秷鍘熸湁鐨勫垎鏋愪换鍔¤鏃�
+        analysisTimer?.cancel()
+        lastAnalysisOnTimeTask?.cancel()
+        // 浠ュ綋鍓嶆椂闂翠负璧风偣锛岄噸鏂板紑濮嬫柊鐨勪竴杞瓑寰呰鏃�
+        analysisTimer = Timer()
+        val period = config.analysisPeriod * 60 * 1000L
+        lastAnalysisOnTimeTask = newAnalysisTask()
+        analysisTimer?.schedule(lastAnalysisOnTimeTask, period, period)
+    }
+
+    /**
+     * 鍦ㄥ畾鏃舵薄鏌撶嚎绱㈠垎鏋愪换鍔$瓑寰呭懆鏈熸椂闂村唴锛岃嫢姹℃煋绾跨储閲忚秴杩囪瀹氬�硷紝鐩存帴瑙﹀彂鍒嗘瀽绾跨储浠诲姟
+     * 骞堕噸缃畾鏃跺垎鏋愪换鍔�
+     */
+    private fun analysisOnClueCount() {
+        if (clueList.size >= config.analysisCount && !analysisTaskIsRunning) {
+            newAnalysisTask().run()
+            resetAnalysisOnTime()
+        }
+    }
+
+    /**
+     * 瀹炴椂绾跨储缁熻
+     */
+    private fun realTimeSummary() {
+        val statistic = AnalysisStatistic()
+        // 鍏辨湁澶氬皯鐩稿叧姹℃煋婧愶紝鍝簺姹℃煋婧愯鎵弿娆℃暟杈冨
+        val sceneMap = mutableMapOf<String?, Pair<SceneInfo?, Int>>()
+        clueList.forEach { c ->
+            c.pollutedSource?.sceneList?.forEach { s ->
+                if (!sceneMap.containsKey(s?.guid)) {
+                    sceneMap[s?.guid] = s to 1
+                } else {
+                    sceneMap[s?.guid] = s to (sceneMap[s?.guid]?.second!! + 1)
+                }
+            }
+        }
+        val res = sceneMap.entries.sortedBy { it.value.second }
+        statistic.sortedSceneList = res.map { it.value }
+    }
+
+    /**
+     * 绾跨储鍒嗘瀽
+     */
+    private fun analysis() {
+        if (clueList.isEmpty()) return
+        val result = AnalysisResult().apply { deviceCode = clueList.first().deviceCode }
+        // 鍏辨湁澶氬皯鐩稿叧姹℃煋婧愶紝鍝簺姹℃煋婧愯鎵弿娆℃暟杈冨
+        val sceneMap = mutableMapOf<String?, Pair<SceneInfo?, Int>>()
+        clueList.forEach { c ->
+            c.pollutedSource?.sceneList?.forEach { s ->
+                if (!sceneMap.containsKey(s?.guid)) {
+                    sceneMap[s?.guid] = s to 1
+                } else {
+                    sceneMap[s?.guid] = s to (sceneMap[s?.guid]?.second!! + 1)
+                }
+            }
+        }
+        val res = sceneMap.entries.sortedByDescending { it.value.second }
+        result.sortedSceneList = res.map { it.value }
+
+        // 褰撳墠鐨勮蛋鑸暟鎹殑瀹氫綅鍜屾薄鏌撴簮璺濈鏄惁鏄�愭笎鎺ヨ繎锛岃嫢璧拌埅杩滅浜嗕富瑕佹薄鏌撴簮锛屾彁绀虹敤鎴疯皟鏁磋蛋鑸矾绾�
+        if (!result.sortedSceneList.isNullOrEmpty()) {
+            val sT = DateUtil.instance.dateToString(clueList.first().pollutedData?.startTime, DateUtil.DateStyle.HH_MM_SS)
+            val eT = DateUtil.instance.dateToString(clueList.last().pollutedData?.endTime, DateUtil.DateStyle.HH_MM_SS)
+            val closetScene = result.sortedSceneList?.first()
+            // 璧拌埅璺嚎璋冩暣寤鸿
+            result.advice =
+                "鏍规嵁${sT}鑷�${eT}鐨�${clueList.size}鏉℃函婧愬垏鐗囷紝椋庨櫓婧愩��" +
+                        "${closetScene?.first?.name}銆戣澶氭婧簮锛屽叿鏈夎緝楂樻薄鏌撻闄╋紝鐜版彁渚涙柊鐨勮蛋鑸帹鑽愯矾绾匡紝鍙粡杩囪姹℃煋婧愩��"
+
+            val lastP = realTimeDataList.last()
+            // 寤鸿瀵瑰簲鐨勬暟鎹噰鏍锋椂闂�
+            result.time = lastP.dataTime
+            if (lastP.longitude != null && lastP.latitude != null &&
+                lastP.longitude!! > BigDecimal.ZERO && lastP.latitude!! > BigDecimal.ZERO
+                && closetScene?.first?.longitude != null && closetScene.first?.latitude != null &&
+                closetScene.first?.longitude!! > BigDecimal.ZERO && closetScene.first?.latitude!! > BigDecimal.ZERO
+            ) {
+
+                val origin = MapUtil.wgs84ToGcj02(lastP.longitude!!.toDouble() to lastP.latitude!!.toDouble())
+                val destination = closetScene.first!!.longitude.toDouble() to closetScene.first!!.latitude.toDouble()
+
+                // 寤鸿鐨勮蛋鑸矾绾�
+                result.direction = AMapService.directionDriving(origin, destination)
+            }
+            // 绾跨储鍒嗘瀽瀹屾垚鍚庯紝绉诲姩鑷冲巻鍙茬嚎绱㈠垪琛�
+            historyClueList.addAll(clueList)
+            clueList.clear()
+            realTimeDataList.clear()
+
+            callback(result)
+        }
+//        TODO()
+    }
+
+    // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟
+    private fun newAnalysisTask(): TimerTask {
+        return object : TimerTask() {
+            override fun run() {
+                // 璁板綍浠诲姟杩愯鐘舵��
+                analysisTaskIsRunning = true
+                analysis()
+                // 璁板綍涓婁竴娆$殑浠诲姟缁撴潫鏃堕棿
+                lastAnalysisTime = LocalDateTime.now()
+                analysisTaskIsRunning = false
+            }
+        }
+    }
+
 }
\ No newline at end of file

--
Gitblit v1.9.3