From c66ed91b47929f1fbb79afbf07db1f3387f92612 Mon Sep 17 00:00:00 2001
From: zmc <zmc_li@foxmail.com>
Date: 星期一, 13 十一月 2023 16:21:34 +0800
Subject: [PATCH] 新增查询风险值的接口

---
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt   |   10 +
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt           |   41 +++++
 src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskAnalysis.kt          |  133 +++++++++++++++++++
 src/test/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisControllerTest.kt     |   35 +++++
 src/main/java/com/flightfeather/monitor/MonitorApplication.java                         |    8 +
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt |   10 +
 src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskMonthAnalysis.kt     |   74 ++++++++++
 src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt         |  109 +++++++++++++++
 8 files changed, 417 insertions(+), 3 deletions(-)

diff --git a/src/main/java/com/flightfeather/monitor/MonitorApplication.java b/src/main/java/com/flightfeather/monitor/MonitorApplication.java
index 73d4a78..1360808 100644
--- a/src/main/java/com/flightfeather/monitor/MonitorApplication.java
+++ b/src/main/java/com/flightfeather/monitor/MonitorApplication.java
@@ -2,6 +2,7 @@
 
 import com.flightfeather.monitor.scheduledtasks.TaskController;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
 import org.springframework.boot.ApplicationRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -14,7 +15,12 @@
 
     @Bean
     public ApplicationRunner runner() {
-         return args -> taskController.run();
+        return new ApplicationRunner() {
+            @Override
+            public void run(ApplicationArguments args) throws Exception {
+//                taskController.run();
+            }
+        };
     }
 
     public static void main(String[] args) {
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt
new file mode 100644
index 0000000..afc6bc1
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt
@@ -0,0 +1,109 @@
+package com.flightfeather.monitor.analysis.dust
+
+import com.flightfeather.monitor.analysis.dust.risk.*
+import com.flightfeather.monitor.domain.ds1.repository.*
+import com.flightfeather.monitor.enumration.dust.DeviceStatus
+import com.flightfeather.monitor.utils.DateUtil
+import org.springframework.stereotype.Component
+import java.time.LocalDate
+import java.time.LocalDateTime
+import java.time.ZoneId
+
+/**
+ * 鏁版嵁椋庨櫓鍒嗘瀽鎺у埗鍣�
+ */
+@Component
+class RiskAnalysisController(
+    private val dustExceptionSettingRep: DustExceptionSettingRep,
+    private val riskValueRep: RiskValueRep,
+    private val dustSiteStatusRep: DustSiteStatusRep,
+    private val dustSiteDataRep: DustSiteDataRep,
+    private val dustExceptionDataRep: DustExceptionDataRep,
+    private val dustStatisticValueRep: DustStatisticsValueRep,
+) {
+
+    private var running1 = false
+    private var running2 = false
+
+    private var taskDaily: DustRiskAnalysis? = null
+    private var taskMonthly: DustRiskMonthAnalysis? = null
+
+    fun init() {
+        dustExceptionSettingRep.findLatestSetting("閲戝北鍖�")?.let {
+            taskDaily = DustRiskAnalysis(it)
+            taskMonthly = DustRiskMonthAnalysis(it)
+        }
+    }
+
+    fun autoRunDaily() {
+        val data = riskValueRep.findLatestData("day")
+        val yesterday = LocalDate.now().minusDays(1)
+        if (data == null) {
+            runDaily(yesterday)
+        } else {
+            val date = LocalDateTime.ofInstant(data.lst.toInstant(), ZoneId.systemDefault())
+            val sT = if (date.hour == 0 && date.minute == 0 && date.second == 0) {
+                date.toLocalDate()
+            } else {
+                date.plusDays(1).toLocalDate()
+            }
+            val du = DateUtil.findDurationDate(sT, yesterday)
+            du.forEach {
+                runDaily(it)
+            }
+        }
+    }
+
+    fun autoRunMonthly() {
+        val data = riskValueRep.findLatestData("month")
+        val lastMonth = LocalDate.now().minusMonths(1).withDayOfMonth(1)
+        if (data == null) {
+            runMonthly(lastMonth)
+        } else {
+            val date = LocalDateTime.ofInstant(data.lst.toInstant(), ZoneId.systemDefault())
+            val sT = date.plusMonths(1).toLocalDate()
+            val du = DateUtil.findDurationMonth(sT, lastMonth)
+            du.forEach {
+                runMonthly(it)
+            }
+        }
+    }
+
+    fun runDaily(date: LocalDate) {
+        running1 = true
+        taskDaily?.init()
+        // 鑾峰彇鎵�鏈夊綋鍓嶄笂绾垮拰鍋滆繍鐨勮澶�
+        dustSiteStatusRep.select(listOf(DeviceStatus.ONLINE, DeviceStatus.STOP)).forEach { s ->
+            s?.let {
+                taskDaily?.roundInit()
+                val dustSiteDataList = dustSiteDataRep.select(s.mnCode, date)
+                val dustExceptionDataList = dustExceptionDataRep.select(s.mnCode, date)
+                val dustStatisticValueList = dustStatisticValueRep.select(s.mnCode, date)
+                if (dustStatisticValueList.isEmpty()) return@forEach
+                taskDaily?.roundCal(dustStatisticValueList[0]!!, dustSiteDataList, dustExceptionDataList)
+            }
+        }
+        // 鎵�鏈夊垎鏋愮粨鏋滃叆搴�
+        if (taskDaily?.resultList?.isNotEmpty() == true) {
+            riskValueRep.insert(taskDaily?.resultList!!)
+        }
+        running1 = false
+    }
+
+    fun runMonthly(date: LocalDate) {
+        running2 = true
+        taskMonthly?.init()
+        dustSiteStatusRep.select(listOf(DeviceStatus.ONLINE, DeviceStatus.STOP)).forEach { s ->
+            s?.let {
+                taskMonthly?.roundInit()
+                val riskValueList = riskValueRep.select(s.mnCode, date)
+                taskMonthly?.roundCal(riskValueList)
+            }
+        }
+        // 鎵�鏈夊垎鏋愮粨鏋滃叆搴�
+        if (taskMonthly?.resultList?.isNotEmpty() == true) {
+            riskValueRep.insert(taskMonthly?.resultList!!)
+        }
+        running2 = false
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskAnalysis.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskAnalysis.kt
new file mode 100644
index 0000000..df364e2
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskAnalysis.kt
@@ -0,0 +1,133 @@
+package com.flightfeather.monitor.analysis.dust.risk
+
+import com.flightfeather.monitor.domain.ds1.entity.*
+import com.flightfeather.monitor.enumration.dust.ExceptionType
+
+/**
+ * 鎵皹鐩戞祴鏁版嵁椋庨櫓鍒嗘瀽鍩虹被
+ */
+class DustRiskAnalysis(val config: DustExceptionSetting) {
+
+    //鍒嗘瀽缁撴灉
+    val resultList = mutableListOf<RiskValue>()
+
+    /**
+     * 鍒濆鍖�
+     */
+    fun init() {
+        resultList.clear()
+    }
+
+    /**
+     * 姣忚疆娆$殑鍒濆鍖�
+     */
+    fun roundInit() {
+        resultList.add(RiskValue())
+    }
+
+    /**
+     * 姣忚疆娆$殑椋庨櫓鍊艰绠�
+     */
+    fun roundCal(data: DustStatisticsValue, list: List<DustSiteData?>, dList: List<DustExceptionData?>) {
+        if (resultList.isEmpty()) throw IllegalStateException("缁撴灉闆唕esultList涓嶈兘涓虹┖锛�")
+
+        val res = resultList.last()
+        riskOnlineRate(res, data)
+        riskValidRate(res, data)
+        riskExceedRate(res, list)
+        riskExceptionRepetitionRate(res, dList)
+        riskExceptionType(res, dList)
+        onDone(res)
+    }
+
+    /**
+     * 鍦ㄧ嚎鐜囬闄╁��
+     */
+    fun riskOnlineRate(riskValue: RiskValue, data: DustStatisticsValue) {
+        val dayOnline = data.dayOnline.substring(0, data.dayOnline.lastIndex).toDouble() / 100
+        riskValue.onlineRisk = 1 - dayOnline
+    }
+
+    /**
+     * 鏈夋晥鐜囬闄╁��
+     */
+    fun riskValidRate(riskValue: RiskValue, data: DustStatisticsValue) {
+        val dayValid = data.dayValid.substring(0, data.dayValid.lastIndex).toDouble() / 100
+        riskValue.validRisk = 1 - dayValid
+    }
+
+    /**
+     * 瓒呮爣椋庨櫓鍊�
+     */
+    fun riskExceedRate(riskValue: RiskValue, list: List<DustSiteData?>) {
+        // 鏃ヨ秴鏍囨鏁�/7锛堝ぇ浜�1mg/m鲁锛屽皬浜�2mg/m鲁锛�
+        var v1 = 0
+        // 鏃ヨ秴鏍囨鏁�/2锛堝ぇ浜�2mg/m鲁锛�
+        var v2 = 0
+        // 鏃ヤ复杩戣秴鏍囨鏁�/7
+        var v3 = 0
+        list.forEach {d ->
+            if (d == null) return@forEach
+            when {
+                d.dustValue >= 2.0 -> v2++
+                d.dustValue >= 1.0 && d.dustValue < 2.0 -> v1++
+                d.dustValue >= config.nearExceedLowValue && d.dustValue < config.nearExceedHighValue -> v3++
+            }
+        }
+        // 鍜岀殑鏈�澶у�间负3鏈�灏忓�间负0锛屼笂杩颁箣鍜岄櫎浠�3锛岀粨鏋滄渶澶у�间负1鏈�灏忓�间负0锛屽嵆涓烘棩瓒呮爣椋庨櫓鍊�
+        val r = (v1 + v2 + v3) / 3.0
+        riskValue.exceedRisk = if (r > 1) 1.0 else r
+    }
+
+    /**
+     * 鍏稿瀷寮傚父澶嶇幇鐜�
+     */
+    fun riskExceptionRepetitionRate(riskValue: RiskValue, list: List<DustExceptionData?>) {
+        //1銆侀拡瀵归噺绾х獊鍙樺紓甯搞�佷复杩戣秴鏍囧紓甯搞�佸崟鏃ヨ秴鏍囨鏁颁复鐣屽紓甯哥殑鎸囧畾鏃舵锛堝24灏忔椂鍐咃級閲嶅鍑虹幇姒傜巼鏉ョ患鍚堝垽瀹氬吀鍨嬪紓甯稿鐜扮巼锛�
+        //2銆佹棩閲忕骇绐佸彉寮傚父澶嶇幇鐜囷紙E4锛夛細锛圢4-1锛�/4锛� 鏈�澶т负1锛屾渶灏忎负0
+        //3銆佹棩涓磋繎瓒呮爣寮傚父澶嶇幇鐜囷紙E5锛夛細锛圢5-1锛�/3锛� 鏈�澶т负1锛屾渶灏忎负0
+        //4銆佹棩瓒呮爣娆℃暟涓寸晫寮傚父澶嶇幇鐜囷紙E6锛夛細锛圢6-1锛�/2锛� 鏈�澶т负1锛屾渶灏忎负0
+        //5銆佹棩鍏稿瀷寮傚父澶嶇幇鐜�: 鍙朎4銆丒5銆丒6鐨勫拰锛屾渶澶т负1锛屾渶灏忎负0
+        //6銆佹湀鍏稿瀷寮傚父澶嶇幇鐜囷細褰撴湀鍐呭悇鏃ュ吀鍨嬪紓甯稿鐜扮巼鐨勫拰/褰撴湀澶╂暟锛屾渶澶т负1锛屾渶灏忎负0
+        var v1 = 0
+        var v2 = 0
+        var v3 = 0
+        list.forEach { d->
+            if (d == null) return@forEach
+            when (d.exceptionType) {
+                ExceptionType.TYPE4.value -> v1++
+                ExceptionType.TYPE5.value -> v2++
+                ExceptionType.TYPE6.value -> v3++
+            }
+        }
+        val e1 = upperLimit((v1 - 1) / 4.0)
+        val e2 = upperLimit((v2 - 1) / 3.0)
+        val e3 = upperLimit((v3 - 1) / 2.0)
+        riskValue.typicalExceptionRepetitionRate = upperLimit(e1 + e2 + e3)
+    }
+
+    /**
+     * 寮傚父绫诲瀷鑱氶泦鐜�
+     */
+    fun riskExceptionType(riskValue: RiskValue, list: List<DustExceptionData?>) {
+        // 鏃ュ紓甯哥被鍨嬭仛闆嗙巼锛氬綋鏃ュ嚭鐜扮殑涓嶅悓寮傚父绫诲瀷涓暟/6锛屾渶澶т负1锛屾渶灏忎负0
+        //2銆佹湀寮傚父绫诲瀷鑱氶泦鐜囷細褰撴湀鍐呭悇鏃ュ紓甯哥被鍨嬭仛闆嗙巼鐨勫拰/褰撴湀澶╂暟锛屾渶澶т负1锛屾渶灏忎负0
+        // 鍏朵粬鏃舵浠ユ绫绘帹锛屾暟鎹秴浣庛�侀暱鏃堕棿鏃犳尝鍔ㄧ瓑涓ょ被寮傚父鏆備笉绾冲叆鍒嗘瀽锛岃嫢绾冲叆鍒嗘瀽鍒欏垎姣嶄负8
+        val exceptionTypes = mutableListOf<Int>()
+        list.forEach { d ->
+            if (d == null) return@forEach
+            if (!exceptionTypes.contains(d.exceptionType)) {
+                if (d.exceptionType != ExceptionType.TYPE1.value && d.exceptionType != ExceptionType.TYPE3.value) {
+                    exceptionTypes.add(d.exceptionType)
+                }
+            }
+        }
+        riskValue.exceptionTypeAggregation = exceptionTypes.size / 6.0
+    }
+
+    fun onDone(riskValue: RiskValue) {
+        riskValue.type = "day"
+    }
+
+    private fun upperLimit(d:Double):Double = if (d > 1) 1.0  else d
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskMonthAnalysis.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskMonthAnalysis.kt
new file mode 100644
index 0000000..4ba6551
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/risk/DustRiskMonthAnalysis.kt
@@ -0,0 +1,74 @@
+package com.flightfeather.monitor.analysis.dust.risk
+
+import com.flightfeather.monitor.domain.ds1.entity.*
+
+class DustRiskMonthAnalysis(val config: DustExceptionSetting) {
+
+    //鍒嗘瀽缁撴灉
+    val resultList = mutableListOf<RiskValue>()
+
+    /**
+     * 鍒濆鍖�
+     */
+    fun init() {
+        resultList.clear()
+    }
+
+    /**
+     * 姣忚疆娆$殑鍒濆鍖�
+     */
+    fun roundInit() {
+        resultList.add(RiskValue())
+    }
+
+    /**
+     * 姣忚疆娆$殑椋庨櫓鍊艰绠�
+     */
+    fun roundCal(list: List<RiskValue?>) {
+        if (resultList.isEmpty()) throw IllegalStateException("缁撴灉闆唕esultList涓嶈兘涓虹┖锛�")
+
+        val res = resultList.last()
+
+        riskOnlineRate(res, list)
+        riskValidRate(res, list)
+        riskExceedRate(res, list)
+        riskExceptionRepetitionRate(res, list)
+        riskExceptionType(res, list)
+        onDone(res)
+    }
+
+    fun riskOnlineRate(riskValue: RiskValue, list: List<RiskValue?>) {
+        riskValue.onlineRisk = avg(list) { it.onlineRisk }
+    }
+
+    fun riskValidRate(riskValue: RiskValue, list: List<RiskValue?>) {
+        riskValue.validRisk = avg(list) { it.validRisk }
+    }
+
+    fun riskExceedRate(riskValue: RiskValue, list: List<RiskValue?>) {
+        riskValue.exceedRisk = avg(list) { it.exceedRisk }
+    }
+
+    fun riskExceptionRepetitionRate(riskValue: RiskValue, list: List<RiskValue?>) {
+        riskValue.typicalExceptionRepetitionRate = avg(list) { it.typicalExceptionRepetitionRate }
+    }
+
+    fun riskExceptionType(riskValue: RiskValue, list: List<RiskValue?>) {
+        riskValue.exceptionTypeAggregation = avg(list) { it.exceptionTypeAggregation }
+    }
+
+    fun onDone(riskValue: RiskValue) {
+        riskValue.type = "month"
+    }
+
+    private fun avg(list: List<RiskValue?>, onNext: (value: RiskValue) -> Double): Double {
+        var total = .0
+        var count = 0
+        list.forEach {
+            if (it == null) return@forEach
+            total += onNext(it)
+            count++
+        }
+        return if (count == 0) .0 else total / count
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt
index 3bf25c9..a6d60c0 100644
--- a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt
@@ -43,4 +43,14 @@
     fun insert(list: List<DustExceptionData>): Int {
         return dustExceptionDataMapper.insertList(list)
     }
+
+    fun select(mnCode: String, date: LocalDate): List<DustExceptionData?> {
+        val s = date.atStartOfDay()
+        val e = s.plusDays(1).minusSeconds(1)
+        return dustExceptionDataMapper.selectByExample(Example(DustExceptionData::class.java).apply {
+            createCriteria().andBetween("beginTime", s, e)
+                .andEqualTo("mnCode", mnCode)
+            orderBy("beginTime")
+        })
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt
index fbd89ea..8721324 100644
--- a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt
@@ -1,5 +1,6 @@
 package com.flightfeather.monitor.domain.ds1.repository
 
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionData
 import com.flightfeather.monitor.domain.ds1.entity.DustStatisticsValue
 import com.flightfeather.monitor.domain.ds1.mapper.DustStatisticsValueMapper
 import com.github.pagehelper.PageHelper
@@ -45,12 +46,17 @@
     }
 
     fun monthlyStatics(date: LocalDate) {
-        val s = date.atStartOfDay()
+        val s = date.withDayOfMonth(1).atStartOfDay()
         val e = s.plusMonths(1).minusSeconds(1)
         val d = Duration.between(s, e).toDays() + 1
         val dataCount = d * 96
         dustStatisticsValueMapper.monthlyStatics(s, e, dataCount.toInt())
     }
 
-
+    fun select(mnCode: String, date: LocalDate): List<DustStatisticsValue?> {
+        return dustStatisticsValueMapper.selectByExample(Example(DustStatisticsValue::class.java).apply {
+            createCriteria().andEqualTo("lst", date)
+                .andEqualTo("mnCode", mnCode)
+        })
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt
new file mode 100644
index 0000000..dc3e5d6
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt
@@ -0,0 +1,41 @@
+package com.flightfeather.monitor.domain.ds1.repository
+
+import com.flightfeather.monitor.domain.ds1.entity.RiskValue
+import com.flightfeather.monitor.domain.ds1.mapper.RiskValueMapper
+import com.github.pagehelper.PageHelper
+import org.springframework.stereotype.Repository
+import tk.mybatis.mapper.entity.Example
+import java.time.LocalDate
+
+@Repository
+class RiskValueRep(private val riskValueMapper: RiskValueMapper) {
+
+    /**
+     * 鑾峰彇鏈�鏂颁竴鏉¤褰�
+     */
+    fun findLatestData(type: String): RiskValue? {
+        val p = PageHelper.startPage<RiskValue>(1, 1)
+        riskValueMapper.selectByExample(Example(RiskValue::class.java).apply {
+            createCriteria().andEqualTo("type", type)
+            orderBy("lst").desc()
+        })
+        return if (p.isNotEmpty()) {
+            p[0]
+        } else {
+            null
+        }
+    }
+
+    fun insert(list: List<RiskValue>): Int {
+        return riskValueMapper.insertList(list)
+    }
+
+    fun select(mnCode: String, date: LocalDate): List<RiskValue?> {
+        val s = date.withDayOfMonth(1).atStartOfDay()
+        val e = s.plusMonths(1).minusSeconds(1)
+        return riskValueMapper.selectByExample(Example(RiskValue::class.java).apply {
+            createCriteria().andEqualTo("mnCode", mnCode)
+                .andBetween("lst", s, e)
+        })
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisControllerTest.kt b/src/test/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisControllerTest.kt
new file mode 100644
index 0000000..27e3781
--- /dev/null
+++ b/src/test/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisControllerTest.kt
@@ -0,0 +1,35 @@
+package com.flightfeather.monitor.analysis.dust
+
+import com.flightfeather.monitor.utils.DateUtil
+import org.junit.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import org.junit.runner.RunWith
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.junit.jupiter.SpringExtension
+import org.springframework.test.context.junit4.SpringRunner
+import java.time.LocalDate
+
+@RunWith(SpringRunner::class)
+@ExtendWith(SpringExtension::class)
+@SpringBootTest
+class RiskAnalysisControllerTest {
+
+    @Autowired
+    lateinit var riskAnalysisController: RiskAnalysisController
+
+    @Test
+    fun autoRunDaily() {
+        val s = LocalDate.of(2023, 10, 1)
+        val e = LocalDate.of(2023, 10, 31)
+        val du = DateUtil.findDurationDate(s, e)
+        du.forEach {
+            riskAnalysisController.runDaily(it)
+        }
+    }
+
+    @Test
+    fun autoRunMonthly() {
+        riskAnalysisController.autoRunMonthly()
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3