From dac47617b37ccfb834cd73ce0ee725e1101de214 Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期四, 14 八月 2025 17:25:51 +0800 Subject: [PATCH] 2025.8.14 1. 动态溯源模块添加滑动平均异常计算(调试中) --- src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedSummary.kt | 235 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 174 insertions(+), 61 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..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 @@ -1,16 +1,19 @@ 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.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.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.math.BigDecimal +import java.time.LocalDateTime +import java.util.Date +import java.util.Timer +import java.util.TimerTask + +// 寮傚父鏁版嵁鐢熸垚鍥炶皟绫� +typealias NewPolluteSummaryCallback = (ex: AnalysisResult) -> Unit /** * 姹℃煋鎯呭喌姹囨�� @@ -18,7 +21,7 @@ * @date 2025/5/27 * @author feiyu02 */ -class PollutedSummary { +class PollutedSummary(private val config: RTExcWindLevelConfig, private val callback: NewPolluteSummaryCallback) { /** @@ -26,75 +29,185 @@ * 姣忎竴鍒婚挓瀵瑰巻鍙茬嚎绱㈣繘琛岀粺璁★紝鎻愬嚭浼氬晢寤鸿锛堢姹℃煋婧愯緝杩溿�佹薄鏌撴簮鏁伴噺銆佸嚭鐜版鏁帮級銆佽蛋鑸矾绾胯皟鏁村缓璁紙绂绘薄鏌撴簮杈冭繎銆佽蛋鑸建杩规湭鎺ヨ繎婧簮鍦烘櫙锛� */ - 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 AnalysisStatistic { + // 鎸夌収琚壂鎻忔鏁伴檷搴忔帓鍒楃殑姹℃煋婧愬垪琛� + var sortedSceneList: List<Pair<SceneInfo?, Int>>? = null } - constructor(sceneInfoRep: SceneInfoRep) : this(sceneInfoRep, null) + // 鏈�鏂板疄鏃惰蛋鑸洃娴嬫暟鎹� + val realTimeDataList = mutableListOf<BaseRealTimeData>() - // 姹℃煋绾跨储 - var clueList = mutableListOf<PollutedClue>() + // 鏈垎鏋愮殑姹℃煋绾跨储 + val clueList = mutableListOf<PollutedClue>() - private val sceneInfoRep: SceneInfoRep + // 宸插垎鏋愮殑姹℃煋绾跨储 + private val historyClueList = mutableListOf<PollutedClue>() - private val config: RTExcWindLevelConfig + // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟鎺у埗 + private var analysisTimer: Timer? = null - private val taskList = mutableListOf<BaseExceptionAnalysis<RTExcWindLevelConfig, PollutedClue>>() + // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟 + private var lastAnalysisOnTimeTask: TimerTask? = 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 var analysisTaskIsRunning = false + + // 涓婁竴娆″畾鏃舵薄鏌撳垎鏋愪换鍔$粨鏉熸椂闂� + private lateinit var lastAnalysisTime: LocalDateTime + + init { + clear() + } + + // 鏂板涓�鏉℃薄鏌撶嚎绱� + fun addClue(pollutedClue: PollutedClue) { + // 褰撴函婧愭湭鎵惧埌椋庨櫓婧愭椂锛屾娆℃函婧愪俊鎭笉浣滀负绾跨储缁熻椤� + if (pollutedClue.pollutedSource?.sceneList?.isNotEmpty() == true) + clueList.add(pollutedClue) +// realTimeSummary() + analysisOnClueCount() + } + + // 鏂板涓�鏉℃薄鏌撶嚎绱� + fun addClueList(pollutedClues: List<PollutedClue>) { + pollutedClues.forEach { addClue(it) } + } + + // 鍒锋柊褰撳墠鏈�鏂扮殑璧拌埅鐩戞祴鏁版嵁 + 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() } } /** - * 璁$畻鏂扮殑涓�鏉″疄鏃惰蛋鑸暟鎹� + * 瀹炴椂绾跨储缁熻 */ - 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() { + 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) + } } - }, 60 * 1000) - timer.cancel() + } + 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() + + if (config.isSearchAddress) { + // 寤鸿鐨勮蛋鑸矾绾� + result.direction = AMapService.directionDriving(origin, destination) + } + } + // 绾跨储鍒嗘瀽瀹屾垚鍚庯紝绉诲姩鑷冲巻鍙茬嚎绱㈠垪琛� + 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)) + // 瀹氭椂姹℃煋鍒嗘瀽浠诲姟 + 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