From 176d7d8283e66ccf63878c9ab823e900df94b748 Mon Sep 17 00:00:00 2001 From: feiyu02 <risaku@163.com> Date: 星期二, 05 八月 2025 17:20:58 +0800 Subject: [PATCH] 2025.8.5 1. 动态溯源模块添加延迟数据周期异常合并功能 --- src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt | 409 +++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 334 insertions(+), 75 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 bf4f1d1..3866509 100644 --- a/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt +++ b/src/main/kotlin/com/flightfeather/uav/biz/dataanalysis/BaseExceptionContinuous.kt @@ -2,6 +2,7 @@ import com.flightfeather.uav.biz.FactorFilter import com.flightfeather.uav.biz.dataanalysis.model.ExceptionTag +import com.flightfeather.uav.biz.sourcetrace.model.RemainException import com.flightfeather.uav.domain.entity.BaseRealTimeData import com.flightfeather.uav.lightshare.eunm.ExceptionStatusType import com.flightfeather.uav.socket.eunm.FactorType @@ -11,48 +12,17 @@ * 杩炵画绫诲瀷鐨勫紓甯稿垎鏋愬熀绫�,閫傜敤浜庡綋鍓嶆暟鎹笌鐩搁偦鏁版嵁涔嬮棿鏈夊叧鑱斿叧绯荤殑鎯呭喌 */ abstract class BaseExceptionContinuous<T : ExceptionTag, V : BaseAnalysisConfig, Y : BaseExceptionResult>( - config: V, private val tagClz: Class<T> + config: V, private val tagClz: Class<T>, ) : BaseExceptionAnalysis<V, Y>(config) { + + enum class JudgeMethod(val des: String) { + M1("鍦ㄤ竴瀹氱殑绌洪棿鍜屾椂闂磋寖鍥村唴锛屾暟鎹疮璁″嚭鐜癗娆″紓甯稿悗锛岃涓鸿寮傚父鎴愮珛"), + M2("瑕佹眰鏁版嵁涓嶉棿鏂繛缁嚭鐜癗娆″紓甯稿悗锛岃涓鸿寮傚父鎴愮珛"), + } companion object { // 璁板綍寮傚父鏁版嵁娈垫椂锛屽垎鍒悜璧峰鍓嶅拰鏈熬鍚庨澶栬褰曠殑鏁版嵁涓暟鍋忕Щ閲� private const val OFFSET = 10 - } - - inner class Tag { - // 璧峰鏁版嵁涓嬫爣 - var sIndex = 0 - - // 璧峰鏁版嵁瀵硅薄 - var startData: BaseRealTimeData? = null - - // 鏈熬鏁版嵁涓嬫爣 - var eIndex = -1 - - // 鏈熬鏁版嵁瀵硅薄 - var endData: BaseRealTimeData? = null - - // 寮傚父鏁版嵁娈� - var exceptionData = mutableListOf<BaseRealTimeData>() - - // 鏄惁瀛樺湪寮傚父 - var exceptionExisted = false - - // 寮傚父缁撴灉鏄惁鍒涘缓 - var exceptionCreated = false - - fun addExceptionData(data: BaseRealTimeData) { - exceptionExisted = true - exceptionData.add(data) - } - - fun refreshWithNextException(data: BaseRealTimeData) { - sIndex = eIndex - startData = data - exceptionData.clear() - exceptionExisted = false - exceptionCreated = false - } } protected val tagMap = mutableMapOf<FactorType, T>() @@ -62,6 +32,36 @@ // 鏈熬鏁版嵁瀵硅薄 protected var lastData: BaseRealTimeData? = null + + // 鏈�鏂扮殑涓�缁勫紓甯革紝璁板綍鍗曞洜瀛愬紓甯� + val latestExceptions = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>() + + /** + * 鏈�鏂扮殑涓�缁勫悎骞跺紓甯革紝鏍规嵁閰嶇疆鍙傛暟浠嶽latestExceptions]鍗曞洜瀛愬紓甯镐腑锛屽悎骞跺紓甯� + */ + protected val latestCombinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>() + + // 璁板綍闇�瑕佸欢杩熸暟鎹懆鏈熻繘琛屽悎骞剁殑寮傚父 + val remainingExceptions = mutableListOf<RemainException<T>>() + + /** + * 寮傚父缁撴灉 + */ + val result = mutableListOf<Y>() + + /** + * 涓嶉�傜敤浜庢寮傚父绫诲瀷鐨勭洃娴嬪洜瀛� + */ + open var excludedFactor: List<FactorType> = emptyList() + + abstract var judgeMethod: JudgeMethod + + /** + * 绔嬪嵆鍒ゆ柇锛氬綋鍑虹幇寮傚父鏃讹紝缂撳瓨寮傚父鏁版嵁鐨勫悓鏃讹紝绔嬪嵆瀵瑰凡鏈夊紓甯歌繘琛屽垽鏂槸鍚︽弧瓒冲紓甯哥粨鏋滆姹� + */ + open fun immeExcCheck(tag: T, factorType: FactorType): Boolean { + return false + } /** * 鍒ゆ柇鐩搁偦鏁版嵁鏄惁杩炵画 @@ -75,7 +75,17 @@ } /** - * 鍒ゆ柇鏄惁婊¤冻寮傚父鏉′欢 + * 鍒ゆ柇鏁版嵁閲忕骇鍦ㄥ紓甯稿垽鏂殑鑼冨洿鍐� + * 榛樿鎵�鏈夐噺绾ч兘鍦ㄥ紓甯稿垽鏂殑鑼冨洿鍐� + */ + open fun judgeDataScale(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> { + val res = mutableMapOf<FactorType, Boolean>() + config.factorFilter.mainList().forEach { f -> res[f] = true } + return res + } + + /** + * 鍒ゆ柇鍓嶅悗鏁版嵁鏄惁婊¤冻寮傚父鏉′欢 */ abstract fun judgeException(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> @@ -83,15 +93,28 @@ * 鍒ゆ柇寮傚父鍑虹幇鐨勮繛缁釜鏁版槸鍚︽弧瓒虫潯浠� * @param tag 寮傚父鏁版嵁瀵硅薄 */ - abstract fun judgeExceptionCount(tag: T): Boolean + abstract fun judgeExceptionCount(tag: T, factorType: FactorType?): Boolean + + /** + * 鍒ゆ柇鐩戞祴鍥犲瓙鏄惁鍑虹幇寮傚父 + */ + open fun judge(p: BaseRealTimeData?, n: BaseRealTimeData): MutableMap<FactorType, Boolean> { + val jds = judgeDataScale(p, n) + val jex = judgeException(p, n) + val res = mutableMapOf<FactorType, Boolean>() + jds.forEach { (t, u) -> + res[t] = u && jex[t] ?: false + } + return res + } /** * 寮傚父鏁版嵁鐨勬埅鍙栧垽鏂� - * 鏄惁闇�瑕侀檺鍒朵竴缁勫紓甯告暟鎹殑闀垮害 - * @return 榛樿涓嶉渶瑕佹埅鍙� + * @return */ - open fun needCut(tag: T): Boolean { - return false + open fun needCut(tag: T, hasException: Boolean?, data: BaseRealTimeData): Boolean { + // 榛樿鍒ゆ柇鏉′欢涓� 褰撳紓甯镐笉鍐嶉噸澶嶅嚭鐜版椂 + return tag.exceptionExisted && hasException == false } override fun init() { @@ -105,9 +128,12 @@ override fun onNextData(data: BaseRealTimeData) { val isContinue = isContinuous(lastData, data) - val hasException = judgeException(lastData, data) + val hasException = judge(lastData, data) config.factorFilter.selectedList.forEach { s -> val f = s.main + // 鎺掗櫎姝ゅ紓甯哥被鍨嬩笉閫傜敤鐨勭洃娴嬪洜瀛� + if (excludedFactor.contains(f)) return@forEach + tagMap[f]?.let { it.eIndex++ // 璧峰鏁版嵁 @@ -115,21 +141,23 @@ if (it.startData == null) { it.refreshWithNextException(data) } - // 鍒ゆ柇鐩搁偦鏁版嵁鏄惁杩炵画骞朵笖鏄惁婊¤冻寮傚父鍒ゆ柇 - if (!isContinue || needCut(it)) { - // 鏁版嵁涓嶈繛缁椂锛岃褰曞紓甯告儏鍐� - recordException(s, it, data) - } else { - if (hasException[f] == true) { - it.addExceptionData(data) - } else { - // 寮傚父涓嶅啀閲嶅鍑虹幇鏃讹紝璁板綍寮傚父鎯呭喌 - recordException(s, it, data) - } + + // 鎸夌収涓嶅悓鐨勬柟寮忚繘琛屽紓甯稿垽鏂� + when (judgeMethod) { + JudgeMethod.M1 -> judgeMethod1(hasException, f, it, data, s) + JudgeMethod.M2 -> judgeMethod2(isContinue, hasException, f, it, data, s) } + + it.addHistoryData(data) } } lastData = data + + removeSingleFactor(data) + checkDelayedExceptions(data) + mergeExceptionResult(data) + onNewResult(result) + clearExceptions(data) } override fun onDone() { @@ -137,13 +165,73 @@ } /** + * 鏁版嵁寮傚父鍒ゆ柇鏂瑰紡涓� + * 鍦ㄤ竴瀹氱殑绌洪棿鍜屾椂闂磋寖鍥村唴锛屾暟鎹疮璁″嚭鐜癗娆″紓甯稿悗锛岃涓鸿寮傚父鎴愮珛 + */ + private fun judgeMethod1( + hasException: MutableMap<FactorType, Boolean>, + f: FactorType, + tag: T, + data: BaseRealTimeData, + s: FactorFilter.SelectedFactor, + ) { + // 鍑虹幇寮傚父 + if (hasException[f] == true) { + // 鍒ゆ柇鏁版嵁鍦ㄧ┖闂村拰鏃堕棿鍙樺寲涓婃槸鍚﹁秴鍑洪檺瀹氳寖鍥达紝鑻ヨ秴鍑哄垯鍒犻櫎閬楃暀鐨勫紓甯歌褰曪紝鍒锋柊璧峰鐐规暟鎹� + if (needCut(tag, hasException[f], data)) { + tag.refreshWithNextException(data) + } + // 璁板綍寮傚父鏁版嵁 + tag.addExceptionData(data) + // 褰撶珛鍗冲垽鏂�氳繃鏃讹紝褰㈡垚寮傚父缁撴灉 + if (immeExcCheck(tag, f)) { + recordException(s, tag, data) + } + } + // 鏁版嵁姝e父锛屽苟涓旀病鏈夊巻鍙插紓甯告暟鎹椂锛屽埛鏂拌捣濮嬬偣鏁版嵁 + else if (!tag.exceptionExisted) { + tag.refreshWithNextException(data) + } + } + + /** + * 鏁版嵁寮傚父鍒ゆ柇鏂瑰紡浜� + * 瑕佹眰鏁版嵁涓嶉棿鏂繛缁嚭鐜癗娆″紓甯稿悗锛岃涓鸿寮傚父鎴愮珛 + */ + private fun judgeMethod2( + isContinue: Boolean, + hasException: MutableMap<FactorType, Boolean>, + f: FactorType, + tag: T, + data: BaseRealTimeData, + s: FactorFilter.SelectedFactor, + ) { + // 褰撶浉閭绘暟鎹椂闂翠笉杩炵画鏃讹紝鍒锋柊璧峰鐐规暟鎹紝绉婚櫎鍘嗗彶寮傚父璁板綍 + if (!isContinue) { + tag.refreshWithNextException(data) + } + // 鍑虹幇寮傚父 + else if (hasException[f] == true) { + // 鏈夊紓甯稿嚭鐜版椂锛岃褰曞紓甯告暟鎹� + tag.addExceptionData(data) + // 褰撶珛鍗冲垽鏂�氳繃鏃讹紝褰㈡垚寮傚父缁撴灉 + if (immeExcCheck(tag, f)) { + recordException(s, tag, data) + } + } + // 鏁版嵁姝e父锛屽埛鏂拌捣濮嬬偣鏁版嵁锛岀Щ闄ゅ巻鍙插紓甯歌褰� + else { + tag.refreshWithNextException(data) + } + } + + /** * 寮傚父缁撴潫锛岃褰曞紓甯� + * 鍒ゆ柇宸叉湁鐨勫紓甯告暟鎹槸鍚︽弧瓒冲紓甯告潯浠讹紝婊¤冻鍒欒褰曪紝涓嶆弧瓒冲垯鐣ヨ繃 */ fun recordException(factor: FactorFilter.SelectedFactor, tag: T, data: BaseRealTimeData) { checkResult(factor, ExceptionStatusType.Ended) -// if (tag.eIndex - tag.sIndex >= durationCount) { - tag.refreshWithNextException(data) -// } +// tag.refreshWithNextException(data) } /** @@ -151,17 +239,17 @@ */ open fun checkResult( factor: FactorFilter.SelectedFactor? = null, - exceptionStatus: ExceptionStatusType = ExceptionStatusType.InProgress + exceptionStatus: ExceptionStatusType = ExceptionStatusType.InProgress, ) { val tag = tagMap[factor?.main] if (factor != null && tag != null) { - if (tag.exceptionExisted && judgeExceptionCount(tag)) { + if (tag.exceptionExisted && judgeExceptionCount(tag, factor.main)) { onNewException(tag, factor, exceptionStatus) } } else { config.factorFilter.selectedList.forEach { f -> val tag1 = tagMap[f.main] ?: return@forEach - if (tag1.exceptionExisted && judgeExceptionCount(tag1)) { + if (tag1.exceptionExisted && judgeExceptionCount(tag1, f.main)) { onNewException(tag1, f, exceptionStatus) } } @@ -173,22 +261,193 @@ */ open fun onNewException(tag: T, factor: FactorFilter.SelectedFactor, exceptionStatus: ExceptionStatusType) { if (tag.startData == null) return - val ex = newResult(tag.startData!!, lastData, factor, tag.exceptionData) - .apply { status = exceptionStatus.value } - // 寮傚父宸插垱寤烘椂锛屾洿鏂板紓甯镐俊鎭� - if (tag.exceptionCreated) { - // 灏嗘渶鏂扮殑寮傚父鐨刧uid璧嬪�肩粰ex - val lastEx = tag.exceptionResult.last() - ex.guid = lastEx.guid - tag.exceptionResult.removeLast() - tag.exceptionResult.add(ex) +// val ex = newResult(tag.startData!!, tag.endData, factor, tag.exceptionData) +// val ex = newResult(tag, factor) +// .apply { status = exceptionStatus.value } +// // 寮傚父宸插垱寤烘椂锛屾洿鏂板紓甯镐俊鎭� +// if (tag.exceptionCreated) { +// // 灏嗘渶鏂扮殑寮傚父鐨刧uid璧嬪�肩粰ex +// val lastEx = tag.exceptionResult.last() +// ex.guid = lastEx.guid +// tag.exceptionResult.removeLast() +// tag.exceptionResult.add(ex) +// } +// // 寮傚父鏈垱寤烘椂锛屾柊寤哄紓甯镐俊鎭� +// else { +// tag.exceptionResult.add(ex) +// tag.exceptionCreated = true +// } +// val tagClone = tagClz.newInstance() +// BeanUtils.copyProperties(tag, tagClone) + latestExceptions.add(factor to tag) + } + + /** + * 灏嗕笉鍦ㄥ叧鑱斿叧绯讳腑鐨勭洃娴嬪洜瀛愬紓甯稿瓨鍌紝骞跺墧闄� + */ + fun removeSingleFactor(data: BaseRealTimeData) { + // 鏌ユ壘涓嶅湪鍥犲瓙鍏宠仈缁勫悎涓殑寮傚父鍥犲瓙 + val sfList = latestExceptions.filter { + config.factorFilter.combination.find { c -> c.find { f -> f == it.first.main } != null } == null } - // 寮傚父鏈垱寤烘椂锛屾柊寤哄紓甯镐俊鎭� - else { - tag.exceptionResult.add(ex) -// resultList.add(ex) - tag.exceptionCreated = true + // 鐢熸垚瀵瑰簲鐨勫紓甯哥粨鏋滐紝骞跺垵濮嬪寲璇ュ紓甯� + sfList.forEach { + result.add(newResult(listOf(it))) + it.second.refreshWithNextException(data) + } + // 鍓旈櫎 + latestExceptions.removeAll(sfList) + } + + /** + * 妫�鏌ュ欢杩熺殑寰呭悎骞跺紓甯镐笌褰撳墠寮傚父鏄惁鑳藉尮閰� + * 1. 灏嗛仐鐣欑殑瓒呰繃绛夊緟鏁版嵁鍛ㄦ湡鐨勫紓甯稿瓨鍌� + * 2. 灏嗗尮閰嶆垚鍔熺殑鍚堝苟寮傚父瀛樺偍 + * 3. 淇濈暀渚濇棫鏈悎骞舵垚鍔熷苟涓斿彲缁х画绛夊緟鐨勫紓甯� + * @return 琚尮閰嶆垚鍔熺殑鍏宠仈鍏崇郴 + */ + fun checkDelayedExceptions(data: BaseRealTimeData): List<List<FactorType>> { + // 琚尮閰嶆垚鍔熺殑鐩戞祴鍥犲瓙鍏宠仈鍏崇郴 + val fittedComb = mutableListOf<List<FactorType>>() + // 閬楃暀鐨勮繘鍏ヤ笅涓�涓暟鎹懆鏈熷仛鍒ゆ柇鐨勫緟鍚堝苟寮傚父闆嗗悎 + val leftExc = mutableListOf<RemainException<T>>() + // 鎴愬姛鍖归厤鐨勫悎骞跺紓甯搁泦鍚� + val combinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>() + // 鏈鏁版嵁鍛ㄦ湡涓紝琚尮閰嶆垚鍔熺殑寮傚父闆嗗悎 + 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) { + fittedComb.add(it.combination) + // 灏嗘煡鎵剧粨鏋滄坊鍔犺嚦宸叉湁寮傚父闆嗗悎涓� + it.addExceptions(res) +// // 璁板綍琚尮閰嶆垚鍔熺殑寮傚父 +// res.forEach { r-> +// if (exceps.find { e -> e.second == r.second } == null) { +// exceps.add(r) +// } +// } + // 灏嗗悎骞跺紓甯稿瓨鍌� + combinedExc.add(it.exceptions) + + } + // 鍚﹀垯鐣欎綔涓嬫鏁版嵁鍛ㄦ湡鍐嶅垽瀹氬瓨鍏ュ緟鍚堝苟寮傚父闆嗗悎 + else { + it.period++ + // 褰撳緟鍚堝苟鐨勫紓甯哥瓑寰呮暟鎹懆鏈熷ぇ浜庤瀹氬�兼椂锛屼笉鍐嶇瓑寰咃紝鐩存帴杈撳嚭寮傚父 + if (it.period > config.maxDelayPeriod) { + result.add(newResult(it.exceptions)) + return@forEach + } else { + fittedComb.add(it.combination) + // 灏嗘煡鎵剧粨鏋滄坊鍔犺嚦宸叉湁寮傚父闆嗗悎涓� + it.addExceptions(res) +// // 璁板綍琚尮閰嶆垚鍔熺殑寮傚父 +// res.forEach { r-> +// if (exceps.find { e -> e.second == r.second } == null) { +// exceps.add(r) +// } +// } + leftExc.add(it) + } + } + } + // 瀛樺偍鍚堝苟寮傚父 + combinedExc.forEach { + result.add(newResult(it)) + } +// // 灏嗚鍖归厤鎴愬姛鐨勫紓甯稿埛鏂帮紝骞朵粠鏈鏁版嵁鍛ㄦ湡鐨勫紓甯搁泦鍚堜腑绉婚櫎 +// exceps.forEach { r-> r.second.refreshWithNextException(data) } +// latestExceptions.removeAll(exceps) + // 淇濈暀鏈尮閰嶇殑缁勫悎 + remainingExceptions.clear() + remainingExceptions.addAll(leftExc) + + return fittedComb + } + + /** + * 鍚堝苟寮傚父 + */ + open fun mergeExceptionResult(data: BaseRealTimeData) { + val combinedExc = mutableListOf<List<Pair<FactorFilter.SelectedFactor, T>>>() + // 閬嶅巻鎵�鏈夌殑鍥犲瓙缁勫悎 + config.factorFilter.combination.forEach { c -> + val combRes = matchCombFactor(c, latestExceptions) + val res = combRes.second + val exist = combRes.first + // 濡傛灉缁勫悎鍐呯殑鎵�鏈夊洜瀛愰兘瀛樺湪寮傚父锛屽垯瀛樺偍涓哄悎骞跺紓甯� + if (exist) { + // 灏嗗悎骞跺紓甯稿瓨鍌� + combinedExc.add(res) + } + // 鍚﹀垯灏嗗紓甯哥殑娣辨嫹璐濈増鏈瓨鍏ュ緟鍚堝苟寮傚父闆嗗悎 + // TODO 2025.8.4: 鍚庣画娣诲姞褰撳叧鑱旂殑鐩戞祴鍥犲瓙绱寮傚父璁℃暟鎺ヨ繎闃堝�兼椂锛屾墠瀛樺叆闆嗗悎鐨勯�昏緫 + else { + remainingExceptions.add(RemainException(res, c)) + } + } + + // 瀛樺偍鍚堝苟寮傚父 + combinedExc.forEach { + result.add(newResult(it)) } } + /** + * 鍖归厤鍏宠仈寮傚父鍥犲瓙 + * @param comb 鍏宠仈鍥犲瓙鍏崇郴 + * @param exceptions 鍚勭洃娴嬪洜瀛愬紓甯搁泦鍚� + * @return exist琛ㄧず鏄惁鎵惧埌鍏宠仈鍏崇郴[comb]涓墍鏈夌殑鍥犲瓙锛宺es琛ㄧず鎵惧埌鐨勭粨鏋� + */ + private fun matchCombFactor( + comb: List<FactorType>, + exceptions: List<Pair<FactorFilter.SelectedFactor, T>>, + ): Pair<Boolean, MutableList<Pair<FactorFilter.SelectedFactor, T>>> { + val res = mutableListOf<Pair<FactorFilter.SelectedFactor, T>>() + var exist = true + // 鏌ョ湅缁勫悎鍐呯殑鎵�鏈夊洜瀛愭槸鍚﹂兘鍚屾椂鍑虹幇寮傚父 + comb.forEach { f -> + val r = exceptions.find { e -> + e.first.main == f + } + if (r != null) { + res.add(r) + } else { + exist = false + } + } + return exist to res + } + + abstract fun onNewResult(result: List<Y>) + + /** + * 鍦ㄥ紓甯哥敓鎴愮粨鏋滃悗锛岃繘琛屽垵濮嬪寲 + */ + private fun clearExceptions(data: BaseRealTimeData) { + // 姝ゆ椂latestExceptions涓簲璇ュ寘鍚殑渚濇棫鏄湰娆℃暟鎹懆鏈熷唴鐨勬墍鏈夊紓甯� + latestExceptions.forEach { + it.second.refreshWithNextException(data) + } + latestExceptions.clear() + result.clear() + } + + /** + * 鐢熸垚涓�鏉″紓甯稿垎鏋愮粨鏋� + */ + abstract fun newResult(tag: T, factor: FactorFilter.SelectedFactor): Y + + abstract fun newResult(exceptions: List<Pair<FactorFilter.SelectedFactor, ExceptionTag>>): Y + } \ No newline at end of file -- Gitblit v1.9.3