From b10c22af595bd995e56946bff63b8f2f984b13e8 Mon Sep 17 00:00:00 2001
From: feiyu02 <risaku@163.com>
Date: 星期四, 14 八月 2025 17:25:05 +0800
Subject: [PATCH] 2025.8.14 1. 动态溯源模块添加滑动平均异常计算(调试中)

---
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt               |    1 
 src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceControllerTest.kt           |   16 +
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt                |   85 ++++----
 src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionResult.kt                |    3 
 src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt            |   26 +
 src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/model/ExceptionTag.kt                 |    4 
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt         |   25 +
 src/main/resources/mapper/SourceTraceMsgMapper.xml                                           |   12 -
 src/main/kotlin/com/flightfeather/uav/domain/repository/SourceTraceRep.kt                    |   48 +++-
 src/main/resources/generator/generatorConfig.xml                                             |   17 
 src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImplTest.kt |    5 
 src/main/kotlin/com/flightfeather/uav/domain/entity/SourceTraceMsg.java                      |   17 -
 src/main/kotlin/com/flightfeather/uav/lightshare/bean/SourceTraceMsgVo.kt                    |   15 +
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt     |  194 +++++++++++++++++++
 src/main/kotlin/com/flightfeather/uav/domain/mapper/SourceTraceMsgMapper.kt                  |   10 
 src/test/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuousTest.kt        |   85 +++++--
 src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt               |   10 
 17 files changed, 426 insertions(+), 147 deletions(-)

diff --git a/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt b/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt
index 3866509..0388a35 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt
@@ -154,8 +154,8 @@
         lastData = data
 
         removeSingleFactor(data)
-        checkDelayedExceptions(data)
-        mergeExceptionResult(data)
+        val fittedComb = checkDelayedExceptions(data)
+        mergeExceptionResult(data, fittedComb)
         onNewResult(result)
         clearExceptions(data)
     }
@@ -286,6 +286,8 @@
      * 灏嗕笉鍦ㄥ叧鑱斿叧绯讳腑鐨勭洃娴嬪洜瀛愬紓甯稿瓨鍌紝骞跺墧闄�
      */
     fun removeSingleFactor(data: BaseRealTimeData) {
+        if (latestExceptions.isEmpty()) return
+
         // 鏌ユ壘涓嶅湪鍥犲瓙鍏宠仈缁勫悎涓殑寮傚父鍥犲瓙
         val sfList = latestExceptions.filter {
             config.factorFilter.combination.find { c -> c.find { f -> f == it.first.main } != null } == null
@@ -302,11 +304,13 @@
     /**
      * 妫�鏌ュ欢杩熺殑寰呭悎骞跺紓甯镐笌褰撳墠寮傚父鏄惁鑳藉尮閰�
      * 1. 灏嗛仐鐣欑殑瓒呰繃绛夊緟鏁版嵁鍛ㄦ湡鐨勫紓甯稿瓨鍌�
-     * 2. 灏嗗尮閰嶆垚鍔熺殑鍚堝苟寮傚父瀛樺偍
+     * 2. 灏嗗尮閰嶆垚鍔熺殑鍚堝苟寮傚父瀛樺偍锛屽悓鏃跺皢鍏宠仈鍏崇郴鏍囪涓哄凡鍖归厤
      * 3. 淇濈暀渚濇棫鏈悎骞舵垚鍔熷苟涓斿彲缁х画绛夊緟鐨勫紓甯�
      * @return 琚尮閰嶆垚鍔熺殑鍏宠仈鍏崇郴
      */
     fun checkDelayedExceptions(data: BaseRealTimeData): List<List<FactorType>> {
+        if (latestExceptions.isEmpty()) return emptyList()
+
         // 琚尮閰嶆垚鍔熺殑鐩戞祴鍥犲瓙鍏宠仈鍏崇郴
         val fittedComb = mutableListOf<List<FactorType>>()
         // 閬楃暀鐨勮繘鍏ヤ笅涓�涓暟鎹懆鏈熷仛鍒ゆ柇鐨勫緟鍚堝苟寮傚父闆嗗悎
@@ -316,14 +320,13 @@
         // 鏈鏁版嵁鍛ㄦ湡涓紝琚尮閰嶆垚鍔熺殑寮傚父闆嗗悎
         val exceps = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>()
         remainingExceptions.forEach {
-            // 妫�鏌ュ綋鍓嶆柊寮傚父涓紝鏄惁鍖呭惈鍥犲瓙鍏宠仈鍏崇郴涓殑寮傚父
+            // 妫�鏌ユ湰娆℃暟鎹懆鏈熺殑寮傚父涓紝鏄惁鍖呭惈鍥犲瓙鍏宠仈鍏崇郴涓殑寮傚父
             val combRes = matchCombFactor(it.combination, latestExceptions)
             val res = combRes.second
             // 鍒ゆ柇鏈鏁版嵁鍛ㄦ湡涓壘鍒扮殑鍥犲瓙鍜屽凡鏈夌殑鍥犲瓙鏄惁婊¤冻鍏宠仈鍏崇郴
             val findFactors = mutableListOf<FactorType>()
             res.forEach {r -> findFactors.add(r.first.main) }
             it.exceptions.forEach {r -> findFactors.add(r.first.main) }
-            // 鍒ゆ柇鏄惁杩樻湁缂哄け寮傚父
             val isFitAll = findFactors.distinct() == it.combination
             // 濡傛灉宸茬粡娌℃湁缂哄け鐨勫紓甯稿洜瀛愶紝鍒欏彲鍚堝苟涓虹粍鍚堝紓甯�
             if (isFitAll) {
@@ -377,11 +380,20 @@
 
     /**
      * 鍚堝苟寮傚父
+     * @param data 褰撳墠鐩戞祴鏁版嵁
+     * @param fittedComb 鍦ㄩ仐鐣欑殑寮傚父[remainingExceptions]鍒ゆ柇涓紝宸茬粡杩涜鍖归厤鍒ゆ柇鐨勫叧鑱斿叧绯伙紝灏嗕笉鍐嶈繘琛屽尮閰�
      */
-    open fun mergeExceptionResult(data: BaseRealTimeData) {
+    open fun mergeExceptionResult(data: BaseRealTimeData, fittedComb: List<List<FactorType>>) {
+        if (latestExceptions.isEmpty()) return
+
         val combinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>()
         // 閬嶅巻鎵�鏈夌殑鍥犲瓙缁勫悎
         config.factorFilter.combination.forEach { c ->
+            /**
+             * 璺宠繃宸茬粡鍦╗checkDelayedExceptions]涓垽鏂繃鐨勫叧鑱斿叧绯�
+             */
+            if (fittedComb.indexOf(c) >= 0) return@forEach
+
             val combRes = matchCombFactor(c, latestExceptions)
             val res = combRes.second
             val exist = combRes.first
@@ -392,7 +404,7 @@
             }
             // 鍚﹀垯灏嗗紓甯哥殑娣辨嫹璐濈増鏈瓨鍏ュ緟鍚堝苟寮傚父闆嗗悎
             // TODO 2025.8.4: 鍚庣画娣诲姞褰撳叧鑱旂殑鐩戞祴鍥犲瓙绱寮傚父璁℃暟鎺ヨ繎闃堝�兼椂锛屾墠瀛樺叆闆嗗悎鐨勯�昏緫
-            else {
+            else if (res.isNotEmpty()) {
                 remainingExceptions.add(RemainException(res, c))
             }
         }
diff --git a/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionResult.kt b/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionResult.kt
index f8c3f84..2b2c188 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionResult.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionResult.kt
@@ -1,6 +1,7 @@
 package com.flightfeather.uav.biz.dataanalysis
 
 import com.flightfeather.uav.lightshare.eunm.ExceptionStatusType
+import java.io.Serializable
 import java.util.*
 
 /**
@@ -8,7 +9,7 @@
  * @date 2025/5/13
  * @author feiyu02
  */
-abstract class BaseExceptionResult {
+abstract class BaseExceptionResult : Serializable {
     // 寮傚父缂栧彿
     var guid: String? = null
 
diff --git a/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/model/ExceptionTag.kt b/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/model/ExceptionTag.kt
index 65507b3..474881b 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/model/ExceptionTag.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/model/ExceptionTag.kt
@@ -48,11 +48,11 @@
             // 淇濊瘉鍘嗗彶鏁版嵁鍖呭惈鎵�鏈夊紓甯告暟鎹紙寮傚父鏁版嵁鍙兘涓嶈繛缁級锛屽苟涓斿湪棣栦釜寮傚父鏁版嵁涔嬪墠鏈�澶氬啀淇濆瓨10涓暟鎹�
             val i = historyData.indexOf(exceptionData.first())
             if (i > MAX_HISTORY) {
-                historyData = historyData.subList(i - MAX_HISTORY, historyData.size)
+                historyData = historyData.subList(i - MAX_HISTORY, historyData.size).toMutableList()
             }
         } else {
             if (historyData.size > MAX_HISTORY) {
-                historyData = historyData.subList(historyData.size - MAX_HISTORY, historyData.size)
+                historyData = historyData.subList(historyData.size - MAX_HISTORY, historyData.size).toMutableList()
             }
         }
     }
diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt
index 7a910ee..d2b696f 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceController.kt
@@ -84,6 +84,7 @@
 
     private fun newTask() {
         taskList.apply {
+//            add(RTExcSlideAverage(config) { dataChangeCallback(it) }.also { it.init() })
             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() })
diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt
index b56fb48..9d69ca6 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/config/RTExcWindLevelConfig.kt
@@ -57,7 +57,7 @@
         1.6 to 7.9,
         0.2 to Double.MAX_VALUE,
         DistanceType.TYPE3,
-        3
+        2
 //        1
     )
 
@@ -66,7 +66,7 @@
         8.0 to 13.8,
         0.1 to Double.MAX_VALUE,
         DistanceType.TYPE4,
-        3
+        2
     )
 
     /****鏁版嵁蹇�熶笂鍗�*****************************************************************************/
@@ -103,14 +103,14 @@
             1.6 to 7.9,
             4.0 to Double.MAX_VALUE,
             DistanceType.TYPE3,
-            3
+            2
         ),
         // PM10鍦ㄤ竴涓洃娴嬪懆鏈燂紙4绉掞級涓婂崌閲忕骇澶т簬绛変簬4渭g/m鲁锛岃繛缁彂鐢�3娆�
         FactorType.PM10 to WindLevelCondition(
             1.6 to 7.9,
             4.0 to Double.MAX_VALUE,
             DistanceType.TYPE3,
-            3
+            2
         ),
         // VOC鍦ㄤ竴涓洃娴嬪懆鏈燂紙4绉掞級涓婂崌閲忕骇澶т簬绛変簬6渭g/m鲁锛岃繛缁彂鐢�1娆�
         FactorType.VOC to WindLevelCondition(
@@ -127,14 +127,14 @@
             8.0 to 13.8,
             4.0 to Double.MAX_VALUE,
             DistanceType.TYPE4,
-            3
+            2
         ),
         // PM10鍦ㄤ竴涓洃娴嬪懆鏈燂紙4绉掞級涓婂崌閲忕骇澶т簬绛変簬4渭g/m鲁锛岃繛缁彂鐢�3娆�
         FactorType.PM10 to WindLevelCondition(
             8.0 to 13.8,
             4.0 to Double.MAX_VALUE,
             DistanceType.TYPE4,
-            3
+            2
         ),
         // VOC鍦ㄤ竴涓洃娴嬪懆鏈燂紙4绉掞級涓婂崌閲忕骇澶т簬绛変簬6渭g/m鲁锛岃繛缁彂鐢�1娆�
         FactorType.VOC to WindLevelCondition(
@@ -177,14 +177,14 @@
             .0 to Double.MAX_VALUE,
             2.0 to 4.0,
             DistanceType.TYPE1,
-            3
+            2
         ),
         // PM10鍦ㄤ竴涓洃娴嬪懆鏈燂紙4绉掞級涓婂崌閲忕骇鍦�2 - 4渭g/m鲁涔嬮棿锛岃繛缁彂鐢�3娆�
         FactorType.PM10 to WindLevelCondition(
             .0 to Double.MAX_VALUE,
             2.0 to 4.0,
             DistanceType.TYPE1,
-            3
+            2
         ),
         // VOC鍦ㄤ竴涓洃娴嬪懆鏈燂紙4绉掞級涓婂崌閲忕骇鍦�3 - 6渭g/m鲁涔嬮棿锛岃繛缁彂鐢�2娆�
         FactorType.VOC to WindLevelCondition(
@@ -194,4 +194,13 @@
             2
         ),
     )
+
+    /****婊戝姩骞冲潎鍊煎紓甯�*****************************************************************************/
+    // 姹傛粦鍔ㄥ钩鍧囧�肩殑鏁版嵁缁勪釜鏁�
+    var changeTrendGroup = 12
+    // 婊戝姩骞冲潎鍊艰繛缁�
+    var changeTrendInterval = 12
+    var changeTrendRate = .2
+    // 婊戝姩骞冲潎鍊煎彉鍖栫巼寮傚父杩炵画娆℃暟
+    var changeTrendTimes = 3
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt
new file mode 100644
index 0000000..fb74b06
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/exceptiontype/RTExcSlideAverage.kt
@@ -0,0 +1,194 @@
+package com.flightfeather.uav.biz.sourcetrace.exceptiontype
+
+import com.flightfeather.uav.biz.FactorFilter
+import com.flightfeather.uav.biz.dataanalysis.BaseExceptionAnalysis
+import com.flightfeather.uav.biz.dataanalysis.exceptiontype.ExceptionSlideAverage.Tag
+import com.flightfeather.uav.biz.dataanalysis.model.ExceptionResult
+import com.flightfeather.uav.biz.dataanalysis.model.ExceptionSlideAverageTag
+import com.flightfeather.uav.biz.dataanalysis.model.ExceptionTag
+import com.flightfeather.uav.biz.dataanalysis.model.ExceptionType
+import com.flightfeather.uav.biz.sourcetrace.RealTimeAnalysisConfig
+import com.flightfeather.uav.biz.sourcetrace.config.RTExcWindLevelConfig
+import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue
+import com.flightfeather.uav.biz.sourcetrace.model.RealTimeExceptionResult
+import com.flightfeather.uav.domain.entity.BaseRealTimeData
+import com.flightfeather.uav.lightshare.eunm.ExceptionStatusType
+import com.flightfeather.uav.socket.eunm.FactorType
+import kotlin.math.abs
+
+/**
+ * 婊戝姩骞冲潎鍊肩獊鍙樺紓甯�
+ * @date 2025/5/13
+ * @author feiyu02
+ */
+class RTExcSlideAverage : BaseExceptionAnalysis<RTExcWindLevelConfig, PollutedClue> {
+
+    constructor(config: RTExcWindLevelConfig) : super(config)
+
+    constructor(config: RTExcWindLevelConfig, callback: NewPolluteClueCallback) : super(config){
+        this.callback = callback
+    }
+
+    private var callback: NewPolluteClueCallback? = null
+
+    private val historyDataList = mutableListOf<BaseRealTimeData>()
+    private val tempDataList = mutableListOf<BaseRealTimeData>()
+    private var lastData: BaseRealTimeData? = null
+
+    protected val tagMap = mutableMapOf<FactorType, ExceptionSlideAverageTag>()
+
+    override fun init() {
+        super.init()
+        historyDataList.clear()
+        tempDataList.clear()
+        lastData = null
+
+        tagMap.clear()
+        config.factorFilter.mainList().forEach { f ->
+            tagMap[f] = ExceptionSlideAverageTag()
+        }
+    }
+
+    override fun getExceptionType(): ExceptionType {
+        return ExceptionType.TYPE7
+    }
+
+    override fun onNextData(data: BaseRealTimeData) {
+        historyDataList.add(data)
+        // 鏁版嵁鍔犲叆涓存椂鏁扮粍
+        tempDataList.add(data)
+        // 鏁版嵁閲忚秴鍑鸿缃暟閲忔椂锛屽幓闄ゅ綋鍓嶆暟鎹粍棣栦釜鏁版嵁
+        if (tempDataList.size > config.changeTrendGroup) {
+            tempDataList.removeAt(0)
+        }
+        config.factorFilter.selectedList.forEach { s ->
+            val f = s.main
+            tagMap[f]?.let {
+                it.eIndex++
+                it.endData = lastData
+                if (it.startData == null) {
+                    it.startData = data
+                }
+                // 鏁版嵁閲忕瓑浜庤缃暟閲忔椂锛岃绠楀綋鍓嶆暟鎹粍鍧囧��
+                if (tempDataList.size == config.changeTrendGroup) {
+                    calAvg(f, tempDataList)
+                    if (checkSlideAvg(f)) {
+                        it.addExceptionData(data)
+                        checkResult(s)
+                    } else {
+                        recordException(s, it, data)
+                    }
+                }
+            }
+        }
+        lastData = data
+    }
+
+    override fun onDone() {
+        checkResult(exceptionStatus = ExceptionStatusType.Ended)
+    }
+
+    /**
+     * 寮傚父缁撴潫锛岃褰曞紓甯�
+     */
+    fun recordException(factor: FactorFilter.SelectedFactor, tag: ExceptionSlideAverageTag, data: BaseRealTimeData) {
+        checkResult(factor, ExceptionStatusType.Ended)
+        tag.refreshAfterCheckResult(historyDataList, config.changeTrendGroup)
+    }
+
+    /**
+     * 褰撳墠鏁版嵁鏈嚭鐜板紓甯告椂锛屾垨鏁版嵁寰幆缁撴潫鏃讹紝鍒ゆ柇鍚庣画姝ラ
+     */
+    private fun checkResult(
+        factor: FactorFilter.SelectedFactor? = null,
+        exceptionStatus: ExceptionStatusType = ExceptionStatusType.InProgress
+    ) {
+        val tag = tagMap[factor?.main]
+        if (factor != null && tag != null) {
+            if (tag.exceptionExisted) {
+                onNewException(tag, factor, exceptionStatus)
+            }
+        } else {
+            config.factorFilter.selectedList.forEach { f ->
+                val tag1 = tagMap[f.main] ?: return@forEach
+                if (tag1.exceptionExisted) {
+                    onNewException(tag1, f, exceptionStatus)
+                }
+            }
+        }
+
+    }
+
+    /**
+     * 鏂板鎴栨洿鏂颁竴鏉″紓甯�
+     */
+    open fun onNewException(tag: ExceptionSlideAverageTag, factor: FactorFilter.SelectedFactor, exceptionStatus: ExceptionStatusType) {
+        if (tag.startData == null) return
+        val ex = newResult(listOf(factor to tag))
+
+        callback?.invoke(ex)
+    }
+
+    fun newResult(exceptions: List<Pair<FactorFilter.SelectedFactor, ExceptionTag>>): PollutedClue {
+        return PollutedClue(exceptions, getExceptionType(), config, null)
+    }
+
+    /**
+     * 璁$畻涓�缁勬暟鎹殑鍧囧��
+     */
+    private fun calAvg(type: FactorType, list: List<BaseRealTimeData>) {
+        var total = .0
+        var valid = true
+        val count = list.size
+        if (count == 0) return
+        list.forEach {
+            val v = it.getByFactorType(type)
+            if (v == null) {
+                valid = false
+            } else {
+                total += v
+            }
+        }
+        val avg = total / count
+        tagMap[type]?.avgListReverse?.add(0, Pair(avg, valid))
+    }
+
+    /**
+     * 璁$畻鏁版嵁缁勪箣闂寸殑鍧囧�煎樊寮傛槸鍚﹁繛缁秴杩囬檺瀹氭瘮鐜�
+     */
+    private fun checkSlideAvg(type: FactorType): Boolean {
+        val tag = tagMap[type] ?: return false
+        // 璁$畻婊戝姩鍧囧�兼渶浣庤姹備釜鏁�
+        val minSize = config.changeTrendTimes + config.changeTrendInterval
+        if (tag.avgListReverse.size < minSize) {
+            return false
+        } else {
+            // 婊戝姩鍧囧�兼弧瓒虫暟閲忔椂锛岃绠楀潎鍊间箣闂存槸鍚﹁繛缁秴杩囬檺瀹氭瘮鐜�
+            val rateList = mutableListOf<Pair<Double, Boolean>>()
+            for (i in tag.avgListReverse.indices) {
+                if (i >= config.changeTrendTimes) break
+                val r = calAvgChangeRate(tag.avgListReverse[i], tag.avgListReverse[i + config.changeTrendInterval])
+                rateList.add(r)
+            }
+            for (y in rateList) {
+                if (!y.second || y.first < config.changeTrendRate) {
+                    return false
+                }
+            }
+            return true
+        }
+    }
+
+    /**
+     * 璁$畻婊戝姩鍧囧�煎彉鍖栫巼
+     * 姹俛1鐩稿浜巃2鐨勫彉鍖栫巼
+     */
+    private fun calAvgChangeRate(a1: Pair<Double, Boolean>, a2: Pair<Double, Boolean>): Pair<Double, Boolean> {
+        val valid = a1.second && a2.second
+        return if (a2.first == .0) {
+            Pair(1.0, valid)
+        } else {
+            Pair(abs(a1.first - a2.first) / a2.first, valid)
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
index 6d7b8f0..d25f252 100644
--- a/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
+++ b/src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSource.kt
@@ -45,41 +45,44 @@
         // 鎸夌収鍖哄煙妫�绱㈠唴閮ㄦ薄鏌撴簮淇℃伅
         var result = mutableListOf<SceneInfo>()
         // 1. 棣栧厛鎸夌収鍥涜嚦鑼冨洿浠庢暟鎹簱鍒濇绛涢�夋薄鏌撴簮锛屾澶勭殑鍖哄煙鍧愭爣宸茶浆鎹负鐏槦鍧愭爣绯�
-        val polygonTmp = pollutedArea.polygon!!
-        val fb = MapUtil.calFourBoundaries(polygonTmp)
-        val sceneList = sceneInfoRep.findByCoordinateRange(fb)
-        // 2. 鍐嶇簿纭垽鏂槸鍚﹀湪鍙嶅悜婧簮鍖哄煙澶氳竟褰㈠唴閮�
-        sceneList.forEach {
-            val point = it!!.longitude.toDouble() to it.latitude.toDouble()
-            if (MapUtil.isPointInPolygon(point, polygonTmp)) {
-                result.add(it)
-            }
-        }
+        val polygonTmp = pollutedArea.polygon
+        this.sceneList = emptyList()
 
-        val closePolygonTmp = pollutedArea.closePolygon!!
-        val closeFb = MapUtil.calFourBoundaries(closePolygonTmp)
-        val closeSceneList = sceneInfoRep.findByCoordinateRange(closeFb)
-        // 2. 鍐嶇簿纭垽鏂槸鍚﹀湪鍙嶅悜婧簮鍖哄煙澶氳竟褰㈠唴閮�
-        closeSceneList.forEach {
-            val point = it!!.longitude.toDouble() to it.latitude.toDouble()
-            if (MapUtil.isPointInPolygon(point, closePolygonTmp)) {
-                result.add(it)
-            }
-        }
-
-        // 鏍规嵁姹℃煋鍥犲瓙鐨勯噺绾э紝璁$畻涓昏鐨勬薄鏌撳満鏅被鍨嬶紝绛涢�夌粨鏋�
-        val mainSceneType = calSceneType(pollutedData)
-        if (mainSceneType != null) {
-//            this.conclusion = mainSceneType.first
-            result = result.filter {
-                val r = mainSceneType.second.find { s->
-                    s.value == it.typeId.toInt()
+        if (polygonTmp != null) {
+            val fb = MapUtil.calFourBoundaries(polygonTmp)
+            val sceneList = sceneInfoRep.findByCoordinateRange(fb)
+            // 2. 鍐嶇簿纭垽鏂槸鍚﹀湪鍙嶅悜婧簮鍖哄煙澶氳竟褰㈠唴閮�
+            sceneList.forEach {
+                val point = it!!.longitude.toDouble() to it.latitude.toDouble()
+                if (MapUtil.isPointInPolygon(point, polygonTmp)) {
+                    result.add(it)
                 }
-                r != null
-            }.toMutableList()
-        }
+            }
 
-        this.sceneList = findClosestStation(sceneInfoRep, result)
+            val closePolygonTmp = pollutedArea.closePolygon!!
+            val closeFb = MapUtil.calFourBoundaries(closePolygonTmp)
+            val closeSceneList = sceneInfoRep.findByCoordinateRange(closeFb)
+            // 2. 鍐嶇簿纭垽鏂槸鍚﹀湪鍙嶅悜婧簮鍖哄煙澶氳竟褰㈠唴閮�
+            closeSceneList.forEach {
+                val point = it!!.longitude.toDouble() to it.latitude.toDouble()
+                if (MapUtil.isPointInPolygon(point, closePolygonTmp)) {
+                    result.add(it)
+                }
+            }
+
+            // 鏍规嵁姹℃煋鍥犲瓙鐨勯噺绾э紝璁$畻涓昏鐨勬薄鏌撳満鏅被鍨嬶紝绛涢�夌粨鏋�
+            val mainSceneType = calSceneType(pollutedData)
+            if (mainSceneType != null) {
+//            this.conclusion = mainSceneType.first
+                result = result.filter {
+                    val r = mainSceneType.second.find { s ->
+                        s.value == it.typeId.toInt()
+                    }
+                    r != null
+                }.toMutableList()
+            }
+            this.sceneList = findClosestStation(sceneInfoRep, result)
+        }
 
         val txt = summaryTxt(pollutedData, this.sceneList!!)
         this.conclusion = txt
@@ -97,17 +100,17 @@
                 // 姘哀鍖栧悎鐗╋紝涓�鑸敱浜庢満鍔ㄨ溅灏炬皵锛屽悓姝ヨ绠桟O
                 FactorType.NO2 -> {
                     val coAvg = round(pollutedData.dataList.map { it.co!! }.average()) / 1000
-                     "姘哀鍖栧悎鐗╁亸楂橈紝CO鐨勯噺绾т负${coAvg}mg/m鲁锛屼竴鑸敱浜庢満鍔ㄨ溅灏炬皵閫犳垚锛屾薄鏌撴簮浠ユ苯淇�佸姞娌圭珯涓轰富" to
+                    "姘哀鍖栧悎鐗╁亸楂橈紝CO鐨勯噺绾т负${coAvg}mg/m鲁锛屼竴鑸敱浜庢満鍔ㄨ溅灏炬皵閫犳垚锛屾薄鏌撴簮浠ユ苯淇�佸姞娌圭珯涓轰富" to
                             listOf(SceneType.TYPE6, SceneType.TYPE10, SceneType.TYPE17)
                 }
 
-                FactorType.CO ->  null
+                FactorType.CO -> null
 
-                FactorType.H2S ->  null
+                FactorType.H2S -> null
 
-                FactorType.SO2 ->  null
+                FactorType.SO2 -> null
 
-                FactorType.O3 ->  null
+                FactorType.O3 -> null
                 // a) pm2.5銆乸m10鐗瑰埆楂橈紝涓よ�呭湪鍚勬儏鍐典笅鍚屾灞曠ず锛宲m2.5鍗爌m10鐨勬瘮閲嶅彉鍖栵紝姣旈噸瓒婇珮锛岃秺鏈夊彲鑳芥槸椁愰ギ
                 // b) pm10鐗瑰埆楂樸�乸m2.5杈冮珮锛屽ぇ棰楃矑鎵皹姹℃煋锛屽彧灞曠ずpm10锛宲m2.5鍗爌m10鐨勬瘮閲嶅彉鍖栵紝宸ュ湴涓轰富
                 FactorType.PM25,
@@ -121,7 +124,7 @@
                     }.average()
                     val str =
                         "PM2.5閲忕骇涓�${pm25Avg}渭g/m鲁锛孭M10閲忕骇涓�${pm10Avg}渭g/m鲁锛孭M2.5鍗燩M10鐨勬瘮閲嶄负${round(percentageAvg * 100)}%"
-                     if (percentageAvg > 0.666) {
+                    if (percentageAvg > 0.666) {
                         "${str}锛屾瘮閲嶈緝澶э紝姹℃煋婧愪互椁愰ギ涓轰富锛屽伐鍦版涔�" to
                                 listOf(
                                     SceneType.TYPE1,
@@ -156,11 +159,11 @@
                     val pm25Avg = round(pollutedData.dataList.map { it.pm25!! }.average() * 10) / 10
                     val coAvg = round(pollutedData.dataList.map { it.co!! }.average()) / 1000
                     val o3Avg = round(pollutedData.dataList.map { it.o3!! }.average() * 10) / 10
-                     "VOC鍋忛珮锛屽悓鏃禤M2.5閲忕骇涓�${pm25Avg}渭g/m鲁锛孋O閲忕骇涓�${coAvg}mg/m鲁锛孫3閲忕骇涓�${o3Avg}渭g/m鲁锛屾薄鏌撴簮浠ユ苯淇�佸姞娌圭珯涓轰富" to
+                    "VOC鍋忛珮锛屽悓鏃禤M2.5閲忕骇涓�${pm25Avg}渭g/m鲁锛孋O閲忕骇涓�${coAvg}mg/m鲁锛孫3閲忕骇涓�${o3Avg}渭g/m鲁锛屾薄鏌撴簮浠ユ苯淇�佸姞娌圭珯涓轰富" to
                             listOf(SceneType.TYPE6, SceneType.TYPE17, SceneType.TYPE12)
                 }
 
-                else ->  null
+                else -> null
             }
             des = res?.first
             res?.second?.let { sceneTypes.addAll(it) }
@@ -212,7 +215,7 @@
         val et = DateUtil.instance.getTime(pollutedData.endTime)
         var txt =
             "鍦�${st}鑷�${et}涔嬮棿锛屽嚭鐜�${pollutedData.exception}"
-        pollutedData.statisticMap.entries.forEach {s ->
+        pollutedData.statisticMap.entries.forEach { s ->
             txt += "锛�${s.key.des}鏈�浣庡�间负${s.value.min}渭g/m鲁锛屾渶楂樺�间负${s.value.max}渭g/m鲁锛屽潎鍊间负${s.value.avg}渭g/m鲁"
         }
         if (sceneList.isEmpty()) {
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 7baf746..0ea4343 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
@@ -160,7 +160,8 @@
 
         // 褰撳墠鐨勮蛋鑸暟鎹殑瀹氫綅鍜屾薄鏌撴簮璺濈鏄惁鏄�愭笎鎺ヨ繎锛岃嫢璧拌埅杩滅浜嗕富瑕佹薄鏌撴簮锛屾彁绀虹敤鎴疯皟鏁磋蛋鑸矾绾�
         if (!result.sortedSceneList.isNullOrEmpty()) {
-            val sT = DateUtil.instance.dateToString(clueList.first().pollutedData?.startTime, DateUtil.DateStyle.HH_MM_SS)
+            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()
             // 璧拌埅璺嚎璋冩暣寤鸿
@@ -180,9 +181,10 @@
                 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)
-//                Thread.sleep(200)
+                if (config.isSearchAddress) {
+                    // 寤鸿鐨勮蛋鑸矾绾�
+                    result.direction = AMapService.directionDriving(origin, destination)
+                }
             }
             // 绾跨储鍒嗘瀽瀹屾垚鍚庯紝绉诲姩鑷冲巻鍙茬嚎绱㈠垪琛�
             historyClueList.addAll(clueList)
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/entity/SourceTraceMsg.java b/src/main/kotlin/com/flightfeather/uav/domain/entity/SourceTraceMsg.java
index 1d364c5..2f48641 100644
--- a/src/main/kotlin/com/flightfeather/uav/domain/entity/SourceTraceMsg.java
+++ b/src/main/kotlin/com/flightfeather/uav/domain/entity/SourceTraceMsg.java
@@ -6,6 +6,7 @@
 @Table(name = "source_trace_msg")
 public class SourceTraceMsg {
     @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
     @Column(name = "device_code")
@@ -28,8 +29,6 @@
 
     @Column(name = "create_time")
     private Date createTime;
-
-    private String content;
 
     /**
      * @return id
@@ -141,19 +140,5 @@
      */
     public void setCreateTime(Date createTime) {
         this.createTime = createTime;
-    }
-
-    /**
-     * @return content
-     */
-    public String getContent() {
-        return content;
-    }
-
-    /**
-     * @param content
-     */
-    public void setContent(String content) {
-        this.content = content == null ? null : content.trim();
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/mapper/SourceTraceMsgMapper.kt b/src/main/kotlin/com/flightfeather/uav/domain/mapper/SourceTraceMsgMapper.kt
index 0916cf9..8a5968c 100644
--- a/src/main/kotlin/com/flightfeather/uav/domain/mapper/SourceTraceMsgMapper.kt
+++ b/src/main/kotlin/com/flightfeather/uav/domain/mapper/SourceTraceMsgMapper.kt
@@ -3,6 +3,14 @@
 import com.flightfeather.uav.domain.MyMapper
 import com.flightfeather.uav.domain.entity.SourceTraceMsg
 import org.apache.ibatis.annotations.Mapper
+import org.apache.ibatis.annotations.Select
 
 @Mapper
-interface SourceTraceMsgMapper : MyMapper<SourceTraceMsg?>
\ No newline at end of file
+interface SourceTraceMsgMapper : MyMapper<SourceTraceMsg?> {
+
+    /**
+     * 閲嶇疆鑷id
+     */
+    @Select("alter table source_trace_msg auto_increment = #{param1}")
+    fun resetAutoIncrement(id: Int)
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/repository/SourceTraceRep.kt b/src/main/kotlin/com/flightfeather/uav/domain/repository/SourceTraceRep.kt
index 17a9a7e..b8c4c4c 100644
--- a/src/main/kotlin/com/flightfeather/uav/domain/repository/SourceTraceRep.kt
+++ b/src/main/kotlin/com/flightfeather/uav/domain/repository/SourceTraceRep.kt
@@ -8,9 +8,12 @@
 import com.flightfeather.uav.common.utils.GsonUtils
 import com.flightfeather.uav.domain.entity.Mission
 import com.flightfeather.uav.domain.entity.SourceTraceMsg
+import com.flightfeather.uav.domain.entity.SourceTraceMsgBlob
+import com.flightfeather.uav.domain.mapper.SourceTraceMsgBlobMapper
 import com.flightfeather.uav.domain.mapper.SourceTraceMsgMapper
 import com.flightfeather.uav.socket.sender.MsgType
 import org.springframework.stereotype.Repository
+import org.springframework.transaction.annotation.Transactional
 import tk.mybatis.mapper.entity.Example
 import java.util.*
 
@@ -20,11 +23,22 @@
  * @author feiyu02
  */
 @Repository
-class SourceTraceRep(private val sourceTraceMsgMapper: SourceTraceMsgMapper) {
+class SourceTraceRep(
+    private val sourceTraceMsgMapper: SourceTraceMsgMapper,
+    private val sourceTraceMsgBlobMapper: SourceTraceMsgBlobMapper,
+) {
+
+    private fun insertBlob(stm: SourceTraceMsg, json: String) {
+        sourceTraceMsgBlobMapper.insert(SourceTraceMsgBlob().apply {
+            msgId = stm.id
+            content = json
+        })
+    }
 
     /**
      * 鎻掑叆婧簮淇℃伅鍜屾彁閱掍俊鎭�
      */
+    @Transactional
     fun insert(msgType: MsgType, obj: PollutedClue): Int {
         val stm = SourceTraceMsg().apply {
             deviceCode = obj.deviceCode
@@ -33,11 +47,12 @@
             startTime = obj.pollutedData?.startTime
             endTime = obj.pollutedData?.endTime
             this.msgType = msgType.value
-            content = GsonUtils.gson.toJson(obj)
             createTime = Date()
         }
         return if (fetchOneExist(stm) == null) {
-            sourceTraceMsgMapper.insert(stm)
+            val c = sourceTraceMsgMapper.insert(stm)
+            insertBlob(stm, GsonUtils.gson.toJson(obj))
+            c
         } else {
             0
         }
@@ -54,17 +69,19 @@
     /**
      * 鎻掑叆绾跨储淇℃伅
      */
+    @Transactional
     fun insert(res: AnalysisResult): Int {
         val stm = SourceTraceMsg().apply {
             deviceCode = res.deviceCode
             startTime = res.time
             endTime = res.time
             this.msgType = MsgType.AnaResult.value
-            content = GsonUtils.gson.toJson(res)
             createTime = Date()
         }
         return if (fetchOneExist(stm) == null) {
-            sourceTraceMsgMapper.insert(stm)
+            val c = sourceTraceMsgMapper.insert(stm)
+            insertBlob(stm, GsonUtils.gson.toJson(res))
+            c
         } else {
             0
         }
@@ -83,21 +100,17 @@
     }
 
     fun fetchList(deviceCode: String, startTime: Date, endTime: Date): List<BaseExceptionResult?> {
-        return sourceTraceMsgMapper.selectByExample(Example(SourceTraceMsg::class.java).apply {
-            createCriteria().andEqualTo("deviceCode", deviceCode)
-                .andGreaterThanOrEqualTo("startTime", startTime)
-                .andLessThanOrEqualTo("endTime", endTime)
-            orderBy("id").desc()
-        }).map { stm ->
+        return sourceTraceMsgBlobMapper.selectWithBlob(deviceCode, startTime, endTime)
+            .map { stm ->
             when (stm?.msgType) {
                 MsgType.PolClue.value,
                 MsgType.DataChange.value,
                     -> {
-                    GsonUtils.gson.fromJson(stm.content, PollutedClue::class.java)
+                    GsonUtils.gson.fromJson(stm.blobContent, PollutedClue::class.java)
                 }
 
                 MsgType.AnaResult.value -> {
-                    GsonUtils.gson.fromJson(stm.content, AnalysisResult::class.java)
+                    GsonUtils.gson.fromJson(stm.blobContent, AnalysisResult::class.java)
                 }
 
                 else -> null
@@ -105,11 +118,18 @@
         }
     }
 
+    @Transactional
     fun delete(mission: Mission): Int {
-        return sourceTraceMsgMapper.deleteByExample(Example(SourceTraceMsg::class.java).apply {
+        val idList = sourceTraceMsgMapper.selectByExample(Example(SourceTraceMsg::class.java).apply {
             createCriteria().andEqualTo("deviceCode", mission.deviceCode)
                 .andGreaterThanOrEqualTo("startTime", mission.startTime)
                 .andLessThanOrEqualTo("endTime", mission.endTime)
+        }).map { it?.id }
+        sourceTraceMsgMapper.deleteByExample(Example(SourceTraceMsg::class.java).apply {
+            createCriteria().andIn("id", idList)
+        })
+        return sourceTraceMsgBlobMapper.deleteByExample(Example(SourceTraceMsgBlob::class.java).apply {
+            createCriteria().andIn("msgId", idList)
         })
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/bean/SourceTraceMsgVo.kt b/src/main/kotlin/com/flightfeather/uav/lightshare/bean/SourceTraceMsgVo.kt
new file mode 100644
index 0000000..5ffc1de
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/bean/SourceTraceMsgVo.kt
@@ -0,0 +1,15 @@
+package com.flightfeather.uav.lightshare.bean
+
+import com.flightfeather.uav.domain.entity.SourceTraceMsg
+
+/**
+ *
+ * @date 2025/8/6
+ * @author feiyu02
+ */
+class SourceTraceMsgVo : SourceTraceMsg() {
+
+    var blobId: Int? = null
+    var blobMsgId: Int? = null
+    var blobContent: String? = null
+}
\ No newline at end of file
diff --git a/src/main/resources/generator/generatorConfig.xml b/src/main/resources/generator/generatorConfig.xml
index f6279e6..fdf25e1 100644
--- a/src/main/resources/generator/generatorConfig.xml
+++ b/src/main/resources/generator/generatorConfig.xml
@@ -25,15 +25,15 @@
             <property name="suppressAllComments" value="true"/>
         </commentGenerator>
         <!--鏁版嵁搴撻摼鎺RL锛岀敤鎴峰悕銆佸瘑鐮� -->
-<!--        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://47.100.191.150:3306/dronemonitor?serverTimezone=Asia/Shanghai"-->
-<!--						userId="remoteU1"-->
-<!--						password="eSoF8DnzfGTlhAjE">-->
-<!--        </jdbcConnection>-->
-        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
-                        connectionURL="jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai"
-                        userId="root"
-                        password="123456">
+        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://47.100.191.150:3306/dronemonitor?serverTimezone=Asia/Shanghai"
+						userId="remoteU1"
+						password="eSoF8DnzfGTlhAjE">
         </jdbcConnection>
+<!--        <jdbcConnection driverClass="com.mysql.jdbc.Driver"-->
+<!--                        connectionURL="jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai"-->
+<!--                        userId="root"-->
+<!--                        password="123456">-->
+<!--        </jdbcConnection>-->
         <javaTypeResolver>
             <property name="forceBigDecimals" value="false"/>
         </javaTypeResolver>
@@ -71,5 +71,6 @@
 <!--        <table tableName="grid_data" domainObjectName="GridData" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
 <!--        <table tableName="grid_data_detail" domainObjectName="GridDataDetail" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
         <table tableName="source_trace_msg" domainObjectName="SourceTraceMsg" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
+        <table tableName="source_trace_msg_blob" domainObjectName="SourceTraceMsgBlob" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
     </context>
 </generatorConfiguration>
\ No newline at end of file
diff --git a/src/main/resources/mapper/SourceTraceMsgMapper.xml b/src/main/resources/mapper/SourceTraceMsgMapper.xml
index 5ac4d84..0f7a596 100644
--- a/src/main/resources/mapper/SourceTraceMsgMapper.xml
+++ b/src/main/resources/mapper/SourceTraceMsgMapper.xml
@@ -14,22 +14,10 @@
     <result column="msg_type" jdbcType="INTEGER" property="msgType" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
-  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.flightfeather.uav.domain.entity.SourceTraceMsg">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    <result column="content" jdbcType="LONGVARCHAR" property="content" />
-  </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
     id, device_code, factor_name, exception_type, start_time, end_time, msg_type, create_time
-  </sql>
-  <sql id="Blob_Column_List">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    content
   </sql>
 </mapper>
\ No newline at end of file
diff --git a/src/test/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuousTest.kt b/src/test/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuousTest.kt
index 450871f..dff3477 100644
--- a/src/test/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuousTest.kt
+++ b/src/test/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuousTest.kt
@@ -26,7 +26,7 @@
             BaseRealTimeData().apply { id = 3 },
             endData!!
         )
-        historyData = mutableListOf()
+//        historyData = mutableListOf()
         exceptionExisted = true
         exceptionCreated = false
 //        exceptionResult =
@@ -103,33 +103,38 @@
 
     @Test
     fun checkDelayedExceptions() {
-        taskList().forEach { exc ->
-            val e = exceptions()
-            exc.remainingExceptions.add(RemainException(listOf(e[3], e[5]), listOf(FactorType.VOC, FactorType.PM25, FactorType.CO)))
-            exc.remainingExceptions.add(RemainException(listOf(e[1]), listOf(FactorType.VOC, FactorType.CO)))
-            exc.remainingExceptions.add(RemainException(listOf(e[3]), listOf(FactorType.PM10, FactorType.PM25)))
+        val res = listOf(FactorFilter.SelectedFactor(FactorType.PM25) to exceptionTag)
+        val c = listOf(FactorType.PM25, FactorType.PM10, FactorType.VOC)
+        val r = RemainException(res, c)
+        println(r)
+//        taskList().forEach { exc ->
+//            val e = exceptions()
+//            exc.remainingExceptions.add(RemainException(listOf(e[3], e[5]), listOf(FactorType.VOC, FactorType.PM25, FactorType.CO)))
+//            exc.remainingExceptions.add(RemainException(listOf(e[1]), listOf(FactorType.VOC, FactorType.CO)))
+//            exc.remainingExceptions.add(RemainException(listOf(e[3]), listOf(FactorType.PM10, FactorType.PM25)))
+//
+//            exc.latestExceptions.clear()
+//            exc.latestExceptions.addAll(exceptions())
+//
+//            exc.removeSingleFactor(BaseRealTimeData())
+//
+//            val resList = exc.result.map {
+//                it.pollutedData?.statisticMap?.entries?.map { e -> e.key }
+//            }
+//            assertContentEquals(
+//                listOf(listOf(FactorType.NO2), listOf(FactorType.O3)),
+//                resList,
+//                "寮傚父缁撴灉搴旇閮芥槸涓嶅湪缁勫悎涓殑寮傚父"
+//            )
+//
+//            val resList2 = exc.latestExceptions.map { it.first.main }
+//            assertContentEquals(
+//                listOf(FactorType.CO, FactorType.PM25, FactorType.PM10, FactorType.VOC),
+//                resList2,
+//                "鍓╀綑鐨勫簲璇ユ槸涓嶅湪缁勫悎涓殑寮傚父"
+//            )
+//        }
 
-            exc.latestExceptions.clear()
-            exc.latestExceptions.addAll(exceptions())
-
-            exc.removeSingleFactor(BaseRealTimeData())
-
-            val resList = exc.result.map {
-                it.pollutedData?.statisticMap?.entries?.map { e -> e.key }
-            }
-            assertContentEquals(
-                listOf(listOf(FactorType.NO2), listOf(FactorType.O3)),
-                resList,
-                "寮傚父缁撴灉搴旇閮芥槸涓嶅湪缁勫悎涓殑寮傚父"
-            )
-
-            val resList2 = exc.latestExceptions.map { it.first.main }
-            assertContentEquals(
-                listOf(FactorType.CO, FactorType.PM25, FactorType.PM10, FactorType.VOC),
-                resList2,
-                "鍓╀綑鐨勫簲璇ユ槸涓嶅湪缁勫悎涓殑寮傚父"
-            )
-        }
     }
 
     @Test
@@ -140,11 +145,33 @@
             FactorFilter.SelectedFactor(FactorType.CO),
         )
         val factorList2 = listOf(
-            FactorFilter.SelectedFactor(FactorType.CO),
             FactorFilter.SelectedFactor(FactorType.PM25),
             FactorFilter.SelectedFactor(FactorType.PM10),
         )
-        println(factorList == factorList2)
+
+        val factorList3 = listOf(
+            FactorFilter.SelectedFactor(FactorType.PM25),
+            FactorFilter.SelectedFactor(FactorType.VOC),
+        )
+
+        val comb = listOf(
+            listOf(
+                FactorFilter.SelectedFactor(FactorType.PM10),
+                FactorFilter.SelectedFactor(FactorType.PM25),
+                FactorFilter.SelectedFactor(FactorType.CO),
+            ),
+            listOf(
+                FactorFilter.SelectedFactor(FactorType.PM25),
+                FactorFilter.SelectedFactor(FactorType.PM10),
+            ),
+            listOf(
+                FactorFilter.SelectedFactor(FactorType.VOC),
+                FactorFilter.SelectedFactor(FactorType.PM25),
+            )
+        )
+
+        val i = comb.indexOf(factorList)
+        println(i)
     }
 
     @Test
diff --git a/src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceControllerTest.kt b/src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceControllerTest.kt
index 0961852..5988849 100644
--- a/src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceControllerTest.kt
+++ b/src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceControllerTest.kt
@@ -37,8 +37,12 @@
     @Test
     fun autoSourceTrace() {
         val sourceTraceController = SourceTraceController(sceneInfoRep, sourceTraceRep, false)
-        val mCode = listOf("SH-CN-20241227", "SH-CN-20241127", "SH-CN-20240906", "SH-CN-20240830(05)",
-            "SH-CN-20240830(04)", "SH-CN-20240823", "SH-CN-20240723(02)", "SH-CN-20250723(01)")
+        val mCode = listOf(
+            "SH-CN-20241227", "SH-CN-20241127", "SH-CN-20240906", "SH-CN-20240830(05)",
+            "SH-CN-20240830(04)", "SH-CN-20240823",
+            "SH-CN-20240723(02)",
+//            "SH-CN-20250723(01)"
+        )
         mCode.forEach { c->
             missionRep.findOne(c)?.let {m ->
                 val rtData = realTimeDataService.getSecondData(
@@ -99,8 +103,12 @@
 
     @Test
     fun deleteSourceTrace() {
-        val mCode = listOf("SH-CN-20241227", "SH-CN-20241127", "SH-CN-20240906", "SH-CN-20240830(05)",
-            "SH-CN-20240830(04)", "SH-CN-20240823", "SH-CN-20240723(02)", "SH-CN-20250723(01)")
+        val mCode = listOf(
+            "SH-CN-20241227", "SH-CN-20241127", "SH-CN-20240906", "SH-CN-20240830(05)",
+            "SH-CN-20240830(04)", "SH-CN-20240823",
+            "SH-CN-20240723(02)",
+//            "SH-CN-20250723(01)"
+        )
         mCode.forEach {c ->
             missionRep.findOne(c)?.let {
                 sourceTraceRep.delete(it)
diff --git a/src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImplTest.kt b/src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImplTest.kt
index 13faf0b..c9c3b1a 100644
--- a/src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImplTest.kt
+++ b/src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImplTest.kt
@@ -19,4 +19,9 @@
     fun testPollutionTrace() {
         dataAnalysisService.pollutionTrace("SH-CN-20250116")
     }
+
+    @Test
+    fun fetchHistory() {
+        dataAnalysisService.fetchHistory("SH-CN-20250723(01)")
+    }
 }
\ No newline at end of file

--
Gitblit v1.9.3