From e731486b50c4ea6e2d28f302df449b4bd0b2be57 Mon Sep 17 00:00:00 2001
From: Riku <risaku@163.com>
Date: 星期一, 02 六月 2025 23:02:59 +0800
Subject: [PATCH] 1. 新增走航动态溯源功能

---
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt |  199 ++++++++++++++++++++++++++++++++++---------------
 1 files changed, 137 insertions(+), 62 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 3070bcf..6ec9d46 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,16 +1,14 @@
 package com.flightfeather.uav.biz.sourcetrace.model
 
-import com.flightfeather.uav.biz.FactorFilter
-import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis
-import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig
 import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
-import com.flightfeather.uav.biz.sourcetrace.exceptiontype.*
-import com.flightfeather.uav.common.utils.GsonUtils
 import com.flightfeather.uav.domain.entity.BaseRealTimeData
-import com.flightfeather.uav.domain.repository.SceneInfoRep
-import com.flightfeather.uav.socket.eunm.FactorType
-import com.flightfeather.uav.socket.sender.UnderwayWebSocketSender
-import java.util.*
+import com.flightfeather.uav.domain.entity.SceneInfo
+import java.time.LocalDateTime
+import java.util.Timer
+import java.util.TimerTask
+
+// 寮傚父鏁版嵁鐢熸垚鍥炶皟绫�
+typealias NewPolluteSummaryCallback = (ex: PollutedSummary.AnalysisResult) -> Unit
 
 /**
  * 姹℃煋鎯呭喌姹囨��
@@ -18,7 +16,7 @@
  * @date 2025/5/27
  * @author feiyu02
  */
-class PollutedSummary {
+class PollutedSummary(private val config: RTExcWindLevelConfig, private val callback: NewPolluteSummaryCallback) {
 
 
     /**
@@ -26,75 +24,152 @@
      * 姣忎竴鍒婚挓瀵瑰巻鍙茬嚎绱㈣繘琛岀粺璁★紝鎻愬嚭浼氬晢寤鸿锛堢姹℃煋婧愯緝杩溿�佹薄鏌撴簮鏁伴噺銆佸嚭鐜版鏁帮級銆佽蛋鑸矾绾胯皟鏁村缓璁紙绂绘薄鏌撴簮杈冭繎銆佽蛋鑸建杩规湭鎺ヨ繎婧簮鍦烘櫙锛�
      */
 
-    constructor(sceneInfoRep: SceneInfoRep, factorFilter: FactorFilter?) {
-        this.sceneInfoRep = sceneInfoRep
-        this.config = if (factorFilter != null)
-            RTExcWindLevelConfig(factorFilter)
-        else
-            RTExcWindLevelConfig(
-                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()
-            )
-        initTask()
+    /**
+     * 鍒嗘瀽缁撴灉
+     */
+    inner class AnalysisResult{
+        // 鎸夌収琚壂鎻忔鏁伴檷搴忔帓鍒楃殑姹℃煋婧愬垪琛�
+        var sortedSceneList: List<Pair<SceneInfo?, Int>>? = null
     }
 
-    constructor(sceneInfoRep: SceneInfoRep) : this(sceneInfoRep, null)
+    /**
+     * 瀹炴椂缁熻
+     */
+    inner class AnalysisStatistic {
+        // 鎸夌収琚壂鎻忔鏁伴檷搴忔帓鍒楃殑姹℃煋婧愬垪琛�
+        var sortedSceneList: List<Pair<SceneInfo?, Int>>? = null
+    }
 
-    // 姹℃煋绾跨储
-    var clueList = mutableListOf<PollutedClue>()
+    // 鏈�鏂板疄鏃惰蛋鑸洃娴嬫暟鎹�
+    val realTimeDataList = mutableListOf<BaseRealTimeData>()
 
-    private val sceneInfoRep: SceneInfoRep
+    // 鏈垎鏋愮殑姹℃煋绾跨储
+    val clueList = mutableListOf<PollutedClue>()
 
-    private val config: RTExcWindLevelConfig
+    // 宸插垎鏋愮殑姹℃煋绾跨储
+    private val historyClueList = mutableListOf<PollutedClue>()
 
-    private val taskList = mutableListOf<BaseExceptionAnalysis<RTExcWindLevelConfig, PollutedClue>>()
+    // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟鎺у埗
+    private var analysisTimer: Timer? = null
 
-    fun initTask() {
-        taskList.clear()
-        taskList.apply {
-            add(RTExcWindLevel1(config) { exceptionCallback(it) }.also { it.init() })
-            add(RTExcWindLevel1_1(config) { exceptionCallback(it) }.also { it.init() })
-            add(RTExcWindLevel4(config) { exceptionCallback(it) }.also { it.init() })
-            add(RTExcWindLevel6(config) { exceptionCallback(it) }.also { it.init() })
+    // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟
+    private val analysisOnTimeTask = object : TimerTask() {
+        override fun run() {
+            // 璁板綍浠诲姟杩愯鐘舵��
+            analysisTaskIsRunning = true
+            analysis()
+            // 璁板綍涓婁竴娆$殑浠诲姟缁撴潫鏃堕棿
+            lastAnalysisTime = LocalDateTime.now()
+            analysisTaskIsRunning = false
+        }
+    }
+
+    // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟杩愯鐘舵��
+    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()
+        // 浠ュ綋鍓嶆椂闂翠负璧风偣锛岄噸鏂板紑濮嬫柊鐨勪竴杞瓑寰呰鏃�
+        analysisTimer = Timer()
+        val period = config.analysisPeriod * 60 * 1000L
+        analysisTimer?.schedule(analysisOnTimeTask, period, period)
+    }
+
+    /**
+     * 鍦ㄥ畾鏃舵薄鏌撶嚎绱㈠垎鏋愪换鍔$瓑寰呭懆鏈熸椂闂村唴锛岃嫢姹℃煋绾跨储閲忚秴杩囪瀹氬�硷紝鐩存帴瑙﹀彂鍒嗘瀽绾跨储浠诲姟
+     * 骞堕噸缃畾鏃跺垎鏋愪换鍔�
+     */
+    private fun analysisOnClueCount() {
+        if (clueList.size >= config.analysisCount && !analysisTaskIsRunning) {
+            analysisOnTimeTask.run()
+            resetAnalysisOnTime()
         }
     }
 
     /**
-     * 璁$畻鏂扮殑涓�鏉″疄鏃惰蛋鑸暟鎹�
+     * 瀹炴椂绾跨储缁熻
      */
-    fun addOneData(data: BaseRealTimeData) {
-        // 璁$畻寮傚父
-        taskList.forEach { it.onNextData(data) }
-        // 闄愬畾鏃堕棿鍐呮病鏈夋柊鏁版嵁浼犲叆锛屽垯缁撴潫褰撳墠鐨勮绠�
+    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 dealOnTimeout() {
-        val timer = Timer(true)
-        timer.schedule(object : TimerTask() {
-            override fun run() {
-                TODO("Not yet implemented")
+    private fun analysis() {
+        val result = AnalysisResult()
+        // 鍏辨湁澶氬皯鐩稿叧姹℃煋婧愶紝鍝簺姹℃煋婧愯鎵弿娆℃暟杈冨
+        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)
+                }
             }
-        }, 60 * 1000)
-        timer.cancel()
+        }
+        val res = sceneMap.entries.sortedBy { it.value.second }
+        result.sortedSceneList = res.map { it.value }
+
+        // 褰撳墠鐨勮蛋鑸暟鎹殑瀹氫綅鍜屾薄鏌撴簮璺濈鏄惁鏄�愭笎鎺ヨ繎锛岃嫢璧拌埅杩滅浜嗕富瑕佹薄鏌撴簮锛屾彁绀虹敤鎴疯皟鏁磋蛋鑸矾绾�
+
+
+        // 绾跨储鍒嗘瀽瀹屾垚鍚庯紝绉诲姩鑷冲巻鍙茬嚎绱㈠垪琛�
+        historyClueList.addAll(clueList)
+        clueList.clear()
+        realTimeDataList.clear()
+
+        callback(result)
+//        TODO()
     }
 
-    // 鏁版嵁绐佸彉寮傚父鍥炶皟
-    private fun exceptionCallback(ex: PollutedClue) {
-        // 婧簮姹℃煋婧愪俊鎭�
-        ex.searchScenes(sceneInfoRep)
-        clueList
-        // 骞挎挱姹℃煋婧簮寮傚父缁撴灉
-        UnderwayWebSocketSender.broadcast(GsonUtils.gson.toJson(ex))
-    }
 }
\ No newline at end of file

--
Gitblit v1.9.3