From 70a7d1ec98064e1acb3130e56e16c45af52ade6c Mon Sep 17 00:00:00 2001
From: feiyu02 <risaku@163.com>
Date: 星期二, 24 十月 2023 12:03:49 +0800
Subject: [PATCH] 新增数据分析模块完成

---
 src/test/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisControllerTest.kt   |   33 +
 src/main/java/com/flightfeather/monitor/enumration/dust/DeviceStatus.kt                    |    7 
 src/main/java/com/flightfeather/monitor/scheduledtasks/DustExceptionAnalysisTask.kt        |   26 +
 src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataMissing.kt              |    5 
 pom.xml                                                                                    |    5 
 src/main/java/com/flightfeather/monitor/ServletInitializer.java                            |    2 
 src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustStatisticsValueMapper.kt     |    8 
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt      |   39 ++
 src/main/java/com/flightfeather/monitor/scheduledtasks/TaskController.kt                   |   29 -
 src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustSiteStatusMapper.kt          |    8 
 src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionExceedingTimes.kt           |   18 
 src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustExceptionSetting.java        |   24 +
 src/main/resources/mapper/ds1/DustSiteStatusMapper.xml                                     |    4 
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteStatusRep.kt         |   25 +
 src/main/java/com/flightfeather/monitor/enumration/dust/ExceptionType.kt                   |    2 
 src/main/java/com/flightfeather/monitor/scheduledtasks/DustDailyStatisticAnalysisTask.kt   |   26 +
 src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionSlideAverage.kt             |  128 +++++++
 src/main/java/com/flightfeather/monitor/utils/DateUtil.kt                                  |   24 +
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionSettingRep.kt   |   21 +
 src/main/java/com/flightfeather/monitor/MonitorApplication.java                            |    5 
 src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionValueMutation.kt            |    2 
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt    |   49 ++
 src/main/java/com/flightfeather/monitor/analysis/dust/BaseExceptionContinuous.kt           |   37 +
 src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisController.kt       |  113 ++++++
 /dev/null                                                                                  |   13 
 src/main/resources/mapper/ds1/DustStatisticsValueMapper.xml                                |   38 ++
 src/main/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisController.kt       |   70 ++++
 src/main/java/com/flightfeather/monitor/scheduledtasks/BaseTimingTask.kt                   |   10 
 src/test/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisControllerTest.kt   |   40 ++
 src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteDataRep.kt           |   36 ++
 src/main/resources/mapper/ds1/DustExceptionSettingMapper.xml                               |    3 
 src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataLowValue.kt             |   34 ++
 src/main/java/com/flightfeather/monitor/scheduledtasks/DustMonthlyStatisticAnalysisTask.kt |   25 +
 src/main/java/com/flightfeather/monitor/analysis/dust/BaseDustExceptionAnalysis.kt         |    8 
 src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustSiteStatus.java              |    2 
 src/test/java/com/flightfeather/monitor/MonitorApplicationTests.java                       |    2 
 src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataExceed.kt               |   21 +
 src/main/resources/generator/generatorConfig4ds1.xml                                       |   16 
 src/main/resources/application.yml                                                         |   12 
 39 files changed, 899 insertions(+), 71 deletions(-)

diff --git a/pom.xml b/pom.xml
index 52e0cd2..caa30d5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,6 +91,11 @@
             <artifactId>commons-codec</artifactId>
             <version>1.14</version>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/src/main/java/com/flightfeather/monitor/QianduanApplication.java b/src/main/java/com/flightfeather/monitor/MonitorApplication.java
similarity index 86%
rename from src/main/java/com/flightfeather/monitor/QianduanApplication.java
rename to src/main/java/com/flightfeather/monitor/MonitorApplication.java
index 2528537..73d4a78 100644
--- a/src/main/java/com/flightfeather/monitor/QianduanApplication.java
+++ b/src/main/java/com/flightfeather/monitor/MonitorApplication.java
@@ -8,7 +8,7 @@
 import org.springframework.context.annotation.Bean;
 
 @SpringBootApplication
-public class QianduanApplication {
+public class MonitorApplication {
     @Autowired
     private TaskController taskController;
 
@@ -16,8 +16,9 @@
     public ApplicationRunner runner() {
          return args -> taskController.run();
     }
+
     public static void main(String[] args) {
-        SpringApplication.run(QianduanApplication.class, args);
+        SpringApplication.run(MonitorApplication.class, args);
 
     }
 
diff --git a/src/main/java/com/flightfeather/monitor/ServletInitializer.java b/src/main/java/com/flightfeather/monitor/ServletInitializer.java
index 8ed4aca..48e38d4 100644
--- a/src/main/java/com/flightfeather/monitor/ServletInitializer.java
+++ b/src/main/java/com/flightfeather/monitor/ServletInitializer.java
@@ -7,6 +7,6 @@
 
     @Override
     protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
-        return builder.sources(QianduanApplication.class);
+        return builder.sources(MonitorApplication.class);
     }
 }
diff --git a/src/main/java/com/flightfeather/monitor/analysis/AnalysisController.kt b/src/main/java/com/flightfeather/monitor/analysis/AnalysisController.kt
deleted file mode 100644
index d17c522..0000000
--- a/src/main/java/com/flightfeather/monitor/analysis/AnalysisController.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.flightfeather.monitor.analysis
-
-/**
- * 鏁版嵁鍒嗘瀽鎺у埗鍣�
- */
-class AnalysisController {
-}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/BaseDustExceptionAnalysis.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/BaseDustExceptionAnalysis.kt
index 35cb387..c96f0b0 100644
--- a/src/main/java/com/flightfeather/monitor/analysis/dust/BaseDustExceptionAnalysis.kt
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/BaseDustExceptionAnalysis.kt
@@ -32,15 +32,15 @@
     /**
      * 鐢熸垚涓�鏉″紓甯稿垎鏋愮粨鏋�
      */
-    protected fun newResult(p: DustSiteData?, n: DustSiteData): DustExceptionData {
+    open fun newResult(p: DustSiteData, n: DustSiteData?): DustExceptionData {
         val eType = getExceptionType()
         return DustExceptionData().apply {
-            mnCode = n.mnCode
+            mnCode = p.mnCode
             exception = eType.des
             exceptionType = eType.value
             region = config.region
-            beginTime = if (p == null) n.lst else p.lst
-            endTime = n.lst
+            beginTime = p.lst
+            endTime = if (n == null) p.lst else n.lst
         }
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/BaseExceptionContinuous.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/BaseExceptionContinuous.kt
index 73d1a0c..5908e86 100644
--- a/src/main/java/com/flightfeather/monitor/analysis/dust/BaseExceptionContinuous.kt
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/BaseExceptionContinuous.kt
@@ -8,10 +8,17 @@
  */
 abstract class BaseExceptionContinuous(config: DustExceptionSetting) : BaseDustExceptionAnalysis(config) {
 
+    // 璧峰鏁版嵁涓嬫爣
     private var sIndex = 0
+    // 璧峰鏁版嵁瀵硅薄
     private var startData: DustSiteData? = null
+    // 鏈熬鏁版嵁涓嬫爣
     private var eIndex = -1
+    // 鏈熬鏁版嵁瀵硅薄
     private var lastData: DustSiteData? = null
+    // 璧峰鏁版嵁涓庢湯灏炬暟鎹棿闅�
+    open var durationCount = 1
+    private var existException = false
 
     /**
      * 鍒ゆ柇鏄惁婊¤冻寮傚父鏉′欢
@@ -24,10 +31,12 @@
     abstract fun judgeDuration(sIndex: Int, eIndex: Int): Boolean
 
     override fun init() {
+        super.init()
         startData = null
         lastData = null
         sIndex = 0
         eIndex = -1
+        existException = false
     }
 
     override fun onNextData(data: DustSiteData) {
@@ -36,11 +45,26 @@
             startData = data
         }
         // 鍒ゆ柇鐩搁偦鏁版嵁鏄惁杩炵画骞朵笖鏄惁婊¤冻寮傚父鍒ゆ柇
-        if (!(isContinuous(lastData, data) && judgeException(lastData, data))) {
+        if (!isContinuous(lastData, data)) {
             checkResult()
-            sIndex = eIndex
-            startData = data
+            if (eIndex - sIndex >= durationCount) {
+                sIndex = eIndex
+                startData = data
+            }
+        } else {
+            if (judgeException(lastData, data)) {
+                existException = true
+            } else {
+                checkResult()
+                if (eIndex - sIndex >= durationCount) {
+                    sIndex = eIndex
+                    startData = data
+                }
+            }
         }
+//        if (!(isContinuous(lastData, data) && judgeException(lastData, data))) {
+//
+//        }
         lastData = data
     }
 
@@ -52,8 +76,11 @@
      * 妫�鏌ヨ繛缁紓甯哥粨鏉熸椂锛屾槸鍚︾鍚堝紓甯稿瓨鍌ㄦ潯浠�
      */
     private fun checkResult() {
-        if (judgeDuration(sIndex, eIndex)) {
-            resultList.add(newResult(lastData, startData!!))
+        if (existException && judgeDuration(sIndex, eIndex)) {
+            startData?.let {
+                resultList.add(newResult(it, lastData))
+            }
+            existException = false
         }
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisController.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisController.kt
new file mode 100644
index 0000000..36ba506
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisController.kt
@@ -0,0 +1,113 @@
+package com.flightfeather.monitor.analysis.dust
+
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionData
+import com.flightfeather.monitor.domain.ds1.repository.DustExceptionDataRep
+import com.flightfeather.monitor.domain.ds1.repository.DustExceptionSettingRep
+import com.flightfeather.monitor.domain.ds1.repository.DustSiteDataRep
+import com.flightfeather.monitor.domain.ds1.repository.DustSiteStatusRep
+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 ExceptionAnalysisController(
+    private val dustExceptionDataRep: DustExceptionDataRep,
+    private val dustExceptionSettingRep: DustExceptionSettingRep,
+    private val dustSiteDataRep: DustSiteDataRep,
+    private val dustSiteStatusRep: DustSiteStatusRep,
+) {
+
+    private var running = false
+
+    private val taskList = mutableListOf<BaseDustExceptionAnalysis>()
+
+    fun init() {
+        dustExceptionSettingRep.findLatestSetting("閲戝北鍖�")?.let {
+            taskList.clear()
+            taskList.apply {
+                add(ExceptionDataMissing(it))
+                add(ExceptionNoFluctuation(it))
+                add(ExceptionApproachExceeding(it))
+                add(ExceptionExceedingTimes(it))
+                add(ExceptionSlideAverage(it))
+                add(ExceptionValueMutation(it))
+                add(ExceptionDataLowValue(it))
+                add(ExceptionDataExceed(it))
+            }
+        }
+    }
+
+    /**
+     * 鑷姩杩愯鏃剁殑澶勭悊閫昏緫
+     * 鍒嗘瀽鏄ㄥぉ鐨勬暟鎹�
+     */
+    fun autoRun() {
+        val data = dustExceptionDataRep.findLatestData()
+        val yesterday = LocalDate.now().minusDays(1)
+        if (data == null) {
+            // FIXME: 2023/10/23 搴旇鏄皢鎵�鏈夋暟鎹繘琛岀粺璁�
+            run(yesterday)
+        } else {
+            val date = LocalDateTime.ofInstant(data.endTime.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 {
+                run(it)
+            }
+        }
+    }
+
+    fun run(date: LocalDate) {
+        running = true
+        // 鍒ゆ柇瀵瑰簲鏃ユ湡鐨勫紓甯稿垎鏋愭槸鍚﹀瓨鍦�
+//        if (dustExceptionDataRep.findDataExist(date)) return
+        // 鑾峰彇鎵�鏈夊綋鍓嶄笂绾跨殑璁惧
+        val result = mutableListOf<DustExceptionData>()
+        dustSiteStatusRep.select(listOf(DeviceStatus.ONLINE, DeviceStatus.STOP)).forEach { s ->
+            s?.let {
+                taskList.forEach { it.init() }
+                // 杞鏁版嵁锛岃绠楀悇涓紓甯�
+                dustSiteDataRep.select(s.mnCode, date).takeIf { it.isNotEmpty() }?.forEach {d ->
+                    d?.let { taskList.forEach { it.onNextData(d) } }
+                }
+                // 鍚勪釜寮傚父鍒嗘瀽鍒嗗埆缁撴潫
+                taskList.forEach { it.onDone() }
+                // 瀛樺偍鍒嗘瀽缁撴灉
+                taskList.forEach {
+                    result.addAll(it.resultList)
+                }
+            }
+        }
+        // 鎵�鏈夊垎鏋愮粨鏋滃叆搴�
+        if (result.isNotEmpty()) {
+            dustExceptionDataRep.insert(result)
+        }
+        running = false
+    }
+
+    fun debugRun() {
+        val result = mutableListOf<DustExceptionData>()
+        val date = LocalDate.of(2023, 7, 2)
+        taskList.forEach { it.init() }
+        // 杞鏁版嵁锛岃绠楀悇涓紓甯�
+        val list = dustSiteDataRep.select("YZT0JS0150043", date)
+        list.takeIf { it.isNotEmpty() }?.forEach { d ->
+            d?.let { taskList[0].onNextData(d) }
+        }
+        // 鍚勪釜寮傚父鍒嗘瀽鍒嗗埆缁撴潫
+        taskList[0].onDone()
+        // 瀛樺偍鍒嗘瀽缁撴灉
+        taskList.forEach { result.addAll(it.resultList) }
+        println(result)
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataExceed.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataExceed.kt
new file mode 100644
index 0000000..d092f3e
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataExceed.kt
@@ -0,0 +1,21 @@
+package com.flightfeather.monitor.analysis.dust
+
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
+import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
+import com.flightfeather.monitor.enumration.dust.ExceptionType
+
+/**
+ * 鏁版嵁瓒呮爣寮傚父鍒嗘瀽
+ */
+class ExceptionDataExceed(config: DustExceptionSetting) : BaseExceptionContinuous(config) {
+
+    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE1
+
+    override fun judgeException(p: DustSiteData?, n: DustSiteData): Boolean {
+        return n.dustValue >= config.exceedingStandard
+    }
+
+    override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean {
+        return true
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataLowValue.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataLowValue.kt
new file mode 100644
index 0000000..3ab3121
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataLowValue.kt
@@ -0,0 +1,34 @@
+package com.flightfeather.monitor.analysis.dust
+
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionData
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
+import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
+import com.flightfeather.monitor.enumration.dust.ExceptionType
+
+/**
+ * 鏁版嵁瓒呬綆寮傚父鍒嗘瀽
+ */
+class ExceptionDataLowValue(config: DustExceptionSetting) : BaseExceptionContinuous(config) {
+
+    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE1
+
+    override fun judgeException(p: DustSiteData?, n: DustSiteData): Boolean {
+        return n.dustValue <= config.dataLow
+    }
+
+    override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean {
+        return true
+    }
+
+    override fun newResult(p: DustSiteData, n: DustSiteData?): DustExceptionData {
+        val eType = getExceptionType()
+        return DustExceptionData().apply {
+            mnCode = p.mnCode
+            exception = eType.des
+            exceptionType = eType.value
+            region = config.region
+            beginTime = n?.lst
+            endTime = n?.lst
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataMissing.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataMissing.kt
index bc526a0..13762c5 100644
--- a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataMissing.kt
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionDataMissing.kt
@@ -12,6 +12,11 @@
 
     private var lastData: DustSiteData? = null
 
+    override fun init() {
+        super.init()
+        lastData = null
+    }
+
     override fun getExceptionType(): ExceptionType = ExceptionType.TYPE0
 
     override fun onNextData(data: DustSiteData) {
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionExceedingTimes.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionExceedingTimes.kt
index a1b2496..6d2729f 100644
--- a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionExceedingTimes.kt
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionExceedingTimes.kt
@@ -16,6 +16,12 @@
     private var exceedingCount = 0
     private var startData: DustSiteData? = null
 
+    override fun init() {
+        super.init()
+        exceedingCount = 0
+        startData = null
+    }
+
     override fun getExceptionType(): ExceptionType = ExceptionType.TYPE6
 
     override fun onNextData(data: DustSiteData) {
@@ -30,16 +36,18 @@
         if (exceedingCount >= config.dayExceedBorderlineLowNum && exceedingCount < config.dayExceedBorderlineHighNum) {
             startData?.let {
                 val eType = getExceptionType()
-                val t = LocalDateTime.ofInstant(it.lst.toInstant(), ZoneId.systemDefault())
-                t.withHour(0)
-                val sT =
+                val t = LocalDateTime.ofInstant(it.lst.toInstant(), ZoneId.systemDefault()).withHour(0).withMinute(0).withSecond(0)
+                val sT = Date.from(t.atZone(ZoneId.systemDefault()).toInstant())
+                val n = t.plusDays(1).minusSeconds(1)
+                val eT = Date.from(n.atZone(ZoneId.systemDefault()).toInstant())
+
                 resultList.add(DustExceptionData().apply {
                     mnCode = it.mnCode
                     exception = eType.des
                     exceptionType = eType.value
                     region = config.region
-//                    beginTime = if (p == null) n.lst else p.lst
-//                    endTime = n.lst
+                    beginTime = sT
+                    endTime = eT
                 })
             }
         }
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionSlideAverage.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionSlideAverage.kt
new file mode 100644
index 0000000..7a17ae0
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionSlideAverage.kt
@@ -0,0 +1,128 @@
+package com.flightfeather.monitor.analysis.dust
+
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
+import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
+import com.flightfeather.monitor.enumration.dust.ExceptionType
+import kotlin.math.abs
+
+/**
+ * 婊戝姩骞冲潎鍊肩獊鍙樺紓甯�
+ */
+class ExceptionSlideAverage(config: DustExceptionSetting) : BaseDustExceptionAnalysis(config) {
+
+    private val historyDataList = mutableListOf<DustSiteData>()
+    private val tempDataList = mutableListOf<DustSiteData>()
+    private val avgListReverse = mutableListOf<Double>()
+    private var startData: DustSiteData? = null
+    private var lastData: DustSiteData? = null
+    private var sIndex = 0
+    private var eIndex = -1
+    private var existException = false
+
+    override fun init() {
+        super.init()
+        historyDataList.clear()
+        tempDataList.clear()
+        avgListReverse.clear()
+        startData = null
+        lastData = null
+        sIndex = 0
+        eIndex = -1
+        existException = false
+    }
+
+    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE7
+
+    override fun onNextData(data: DustSiteData) {
+        eIndex++
+        if (startData == null) {
+            startData = data
+        }
+        historyDataList.add(data)
+
+        // 鏁版嵁鍔犲叆涓存椂鏁扮粍
+        tempDataList.add(data)
+        // 鏁版嵁閲忚秴鍑鸿缃暟閲忔椂锛屽幓闄ゅ綋鍓嶆暟鎹粍棣栦釜鏁版嵁
+        if (tempDataList.size > config.changeTrendGroup) {
+            tempDataList.removeAt(0)
+        }
+        // 鏁版嵁閲忕瓑浜庤缃暟閲忔椂锛岃绠楀綋鍓嶆暟鎹粍鍧囧��
+        if (tempDataList.size == config.changeTrendGroup) {
+            calAvg(tempDataList)
+            if (checkSlideAvg()) {
+                existException = true
+            } else {
+                checkResult()
+            }
+        }
+        lastData = data
+    }
+
+    override fun onDone() {
+        checkResult()
+    }
+
+    /**
+     * 璁$畻涓�缁勬暟鎹殑鍧囧��
+     */
+    private fun calAvg(list: List<DustSiteData>) {
+        var total = .0
+        val count = list.size
+        if (count == 0) return
+        list.forEach { total += it.dustValue }
+        val avg = total / count
+        avgListReverse.add(0, avg)
+    }
+
+    /**
+     * 璁$畻鏁版嵁缁勪箣闂寸殑鍧囧�煎樊寮傛槸鍚﹁繛缁秴杩囬檺瀹氭瘮鐜�
+     */
+    private fun checkSlideAvg(): Boolean {
+        // 璁$畻婊戝姩鍧囧�兼渶浣庤姹備釜鏁�
+        val minSize = config.changeTrendTimes + config.changeTrendInterval
+        if (avgListReverse.size < minSize) {
+            return false
+        } else {
+            // 婊戝姩鍧囧�兼弧瓒虫暟閲忔椂锛岃绠楀潎鍊间箣闂存槸鍚﹁繛缁秴杩囬檺瀹氭瘮鐜�
+            val rateList = mutableListOf<Double>()
+            for (i in avgListReverse.indices) {
+                if (i >= config.changeTrendTimes) break
+                val r = calAvgChangeRate(avgListReverse[i], avgListReverse[i + config.changeTrendInterval])
+                rateList.add(r)
+            }
+            for (y in rateList) {
+                if (y < config.changeTrendRate) {
+                    return false
+                }
+            }
+            return true
+        }
+    }
+
+    /**
+     * 璁$畻婊戝姩鍧囧�煎彉鍖栫巼
+     */
+    private fun calAvgChangeRate(a1: Double, a2: Double): Double {
+        return if (a2 == .0) {
+            1.0
+        } else {
+            abs(a1 - a2) / a2
+        }
+    }
+
+    /**
+     * 褰撳墠鏁版嵁鏈嚭鐜板紓甯告椂锛屾垨鏁版嵁寰幆缁撴潫鏃讹紝鍒ゆ柇鍚庣画姝ラ
+     */
+    private fun checkResult() {
+        if (existException) {
+            resultList.add(newResult(startData!!, lastData))
+            existException = false
+        }
+        // 鍒ゆ柇骞舵洿鏂拌捣濮嬬偣浣嶇疆
+        val len = config.changeTrendGroup - 1 + config.changeTrendTimes + config.changeTrendInterval
+        if ((eIndex - sIndex + 1) > len) {
+            sIndex = eIndex + 1 - len
+            startData = historyDataList[sIndex]
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionValueMutation.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionValueMutation.kt
index c28e59e..3b3747e 100644
--- a/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionValueMutation.kt
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionValueMutation.kt
@@ -18,6 +18,6 @@
     }
 
     override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean {
-        return (eIndex - sIndex) >= config.mutationNum
+        return (eIndex - sIndex + 1) >= config.mutationNum
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisController.kt b/src/main/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisController.kt
new file mode 100644
index 0000000..e453da4
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisController.kt
@@ -0,0 +1,70 @@
+package com.flightfeather.monitor.analysis.dust
+
+import com.flightfeather.monitor.domain.ds1.repository.DustStatisticsValueRep
+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 StatisticAnalysisController(private val dustStatisticsValueRep: DustStatisticsValueRep) {
+
+    private var running1 = false
+    private var running2 = false
+
+    /**
+     *
+     */
+    fun autoRunDailyStatics() {
+        val data = dustStatisticsValueRep.findLatestData("day")
+        val yesterday = LocalDate.now().minusDays(1)
+        if (data == null) {
+            // FIXME: 2023/10/23 搴旇鏄皢鎵�鏈夋暟鎹繘琛岀粺璁�
+            dailyStatics(yesterday)
+        } else {
+            val date = LocalDateTime.ofInstant(data.lst.toInstant(), ZoneId.systemDefault())
+            val sT = date.plusDays(1).toLocalDate()
+            val du = DateUtil.findDurationDate(sT, yesterday)
+            du.forEach {
+                dailyStatics(it)
+            }
+        }
+    }
+
+    /**
+     *
+     */
+    fun autoRunMonthlyStatics() {
+        val data = dustStatisticsValueRep.findLatestData("month")
+        val lastMonth = LocalDate.now().minusMonths(1).withDayOfMonth(1)
+        if (data == null) {
+            // FIXME: 2023/10/23 搴旇鏄皢鎵�鏈夋暟鎹繘琛岀粺璁�
+            monthlyStatics(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 {
+                monthlyStatics(it)
+            }
+        }
+    }
+
+    fun dailyStatics(date: LocalDate) {
+        running1 = true
+//        if (dustStatisticsValueRep.findDataExist(date, "day")) return
+        dustStatisticsValueRep.dailyStatics(date)
+        running1 = false
+    }
+
+    fun monthlyStatics(date: LocalDate) {
+        running2 = true
+//        if (dustStatisticsValueRep.findDataExist(date, "month")) return
+        dustStatisticsValueRep.monthlyStatics(date)
+        running2 = false
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustExceptionSetting.java b/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustExceptionSetting.java
index 5b1f507..1290df4 100644
--- a/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustExceptionSetting.java
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustExceptionSetting.java
@@ -56,6 +56,12 @@
     @Column(name = "change_trend_rate")
     private Double changeTrendRate;
 
+    /**
+     * 婊戝姩骞冲潎鍊煎彉鍖栫巼寮傚父杩炵画娆℃暟
+     */
+    @Column(name = "change_trend_times")
+    private Integer changeTrendTimes;
+
     @Column(name = "exceeding_standard")
     private Double exceedingStandard;
 
@@ -312,6 +318,24 @@
     }
 
     /**
+     * 鑾峰彇婊戝姩骞冲潎鍊煎彉鍖栫巼寮傚父杩炵画娆℃暟
+     *
+     * @return change_trend_times - 婊戝姩骞冲潎鍊煎彉鍖栫巼寮傚父杩炵画娆℃暟
+     */
+    public Integer getChangeTrendTimes() {
+        return changeTrendTimes;
+    }
+
+    /**
+     * 璁剧疆婊戝姩骞冲潎鍊煎彉鍖栫巼寮傚父杩炵画娆℃暟
+     *
+     * @param changeTrendTimes 婊戝姩骞冲潎鍊煎彉鍖栫巼寮傚父杩炵画娆℃暟
+     */
+    public void setChangeTrendTimes(Integer changeTrendTimes) {
+        this.changeTrendTimes = changeTrendTimes;
+    }
+
+    /**
      * @return exceeding_standard
      */
     public Double getExceedingStandard() {
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustSiteLatestTime.java b/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustSiteStatus.java
similarity index 96%
rename from src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustSiteLatestTime.java
rename to src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustSiteStatus.java
index 7ed6d0e..8c9cc2f 100644
--- a/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustSiteLatestTime.java
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/entity/DustSiteStatus.java
@@ -4,7 +4,7 @@
 import javax.persistence.*;
 
 @Table(name = "du_js_t_site_latest_time")
-public class DustSiteLatestTime {
+public class DustSiteStatus {
     @Id
     @Column(name = "mn_code")
     private String mnCode;
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustSiteLatestTimeMapper.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustSiteLatestTimeMapper.kt
deleted file mode 100644
index be86347..0000000
--- a/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustSiteLatestTimeMapper.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.flightfeather.monitor.domain.ds1.mapper
-
-import com.flightfeather.monitor.domain.ds1.entity.DustSiteLatestTime
-import com.flightfeather.monitor.domain.util.MyMapper
-import org.apache.ibatis.annotations.Mapper
-
-@Mapper
-interface DustSiteLatestTimeMapper : MyMapper<DustSiteLatestTime?>
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustSiteStatusMapper.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustSiteStatusMapper.kt
new file mode 100644
index 0000000..9cc160b
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustSiteStatusMapper.kt
@@ -0,0 +1,8 @@
+package com.flightfeather.monitor.domain.ds1.mapper
+
+import com.flightfeather.monitor.domain.ds1.entity.DustSiteStatus
+import com.flightfeather.monitor.domain.util.MyMapper
+import org.apache.ibatis.annotations.Mapper
+
+@Mapper
+interface DustSiteStatusMapper : MyMapper<DustSiteStatus?>
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustStatisticsValueMapper.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustStatisticsValueMapper.kt
index 9bfc3a5..683641e 100644
--- a/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustStatisticsValueMapper.kt
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustStatisticsValueMapper.kt
@@ -3,6 +3,12 @@
 import com.flightfeather.monitor.domain.ds1.entity.DustStatisticsValue
 import com.flightfeather.monitor.domain.util.MyMapper
 import org.apache.ibatis.annotations.Mapper
+import java.time.LocalDateTime
 
 @Mapper
-interface DustStatisticsValueMapper : MyMapper<DustStatisticsValue?>
\ No newline at end of file
+interface DustStatisticsValueMapper : MyMapper<DustStatisticsValue?> {
+
+    fun dailyStatics(beginTime: LocalDateTime, endTime: LocalDateTime)
+
+    fun monthlyStatics(beginTime: LocalDateTime, endTime: LocalDateTime, count: Int)
+}
\ 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
new file mode 100644
index 0000000..2876b18
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionDataRep.kt
@@ -0,0 +1,39 @@
+package com.flightfeather.monitor.domain.ds1.repository
+
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionData
+import com.flightfeather.monitor.domain.ds1.mapper.DustExceptionDataMapper
+import org.springframework.stereotype.Repository
+import tk.mybatis.mapper.entity.Example
+import java.time.LocalDate
+
+@Repository
+class DustExceptionDataRep(private val dustExceptionDataMapper: DustExceptionDataMapper) {
+
+    /**
+     * 鑾峰彇鏈�鏂颁竴鏉¤褰�
+     */
+    fun findLatestData(): DustExceptionData? {
+        return dustExceptionDataMapper.selectOneByExample(Example(DustExceptionData::class.java).apply {
+            orderBy("endTime").desc()
+        })
+    }
+
+    /**
+     * 鍒ゆ柇鏌愬ぉ鐨勫紓甯稿垎鏋愭暟鎹槸鍚﹀瓨鍦�
+     */
+    fun findDataExist(date: LocalDate): Boolean {
+        val s = date.atStartOfDay()
+        val e = s.plusDays(1).minusSeconds(1)
+        val res = dustExceptionDataMapper.selectOneByExample(Example(DustExceptionData::class.java).apply {
+            createCriteria().andBetween("endTime", s, e)
+        })
+        return res != null
+    }
+
+    /**
+     * 瀛樺偍寮傚父鍒嗘瀽缁撴灉
+     */
+    fun insert(list: List<DustExceptionData>): Int {
+        return dustExceptionDataMapper.insertList(list)
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionSettingRep.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionSettingRep.kt
new file mode 100644
index 0000000..03f6ce1
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustExceptionSettingRep.kt
@@ -0,0 +1,21 @@
+package com.flightfeather.monitor.domain.ds1.repository
+
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
+import com.flightfeather.monitor.domain.ds1.mapper.DustExceptionSettingMapper
+import org.springframework.stereotype.Repository
+import tk.mybatis.mapper.entity.Example
+
+@Repository
+class DustExceptionSettingRep(private val dustExceptionSettingMapper: DustExceptionSettingMapper) {
+
+    /**
+     * 鑾峰彇鏈�鏂伴厤缃�
+     * @param region 鍖哄幙
+     */
+    fun findLatestSetting(region: String): DustExceptionSetting? {
+        return dustExceptionSettingMapper.selectOneByExample(Example(DustExceptionSetting::class.java).apply {
+            createCriteria().andEqualTo("region", region)
+            orderBy("version").desc()
+        })
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteDataRep.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteDataRep.kt
new file mode 100644
index 0000000..990074b
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteDataRep.kt
@@ -0,0 +1,36 @@
+package com.flightfeather.monitor.domain.ds1.repository
+
+import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
+import com.flightfeather.monitor.domain.ds1.mapper.DustSiteDataMapper
+import org.springframework.stereotype.Repository
+import tk.mybatis.mapper.entity.Example
+import java.time.LocalDate
+
+@Repository
+class DustSiteDataRep(private val dustSiteDataMapper: DustSiteDataMapper) {
+
+    /**
+     * 鑾峰彇鏌愪釜绔欑偣鏌愪竴澶╃殑鎵�鏈夎褰�
+     */
+    fun select(mnCode: String, date: LocalDate): List<DustSiteData?> {
+        val s = date.atStartOfDay()
+        val e = s.plusDays(1).minusSeconds(1)
+        return dustSiteDataMapper.selectByExample(Example(DustSiteData::class.java).apply {
+            createCriteria().andBetween("lst", s, e)
+                .andEqualTo("mnCode", mnCode)
+            orderBy("lst")
+        })
+    }
+
+    /**
+     * 鍒ゆ柇鏌愬ぉ鐨勭洃娴嬫暟鎹槸鍚﹀瓨鍦�
+     */
+    fun findDataExist(date: LocalDate): Boolean {
+        val s = date.atStartOfDay()
+        val e = s.plusDays(1).minusSeconds(1)
+        val res = dustSiteDataMapper.selectOneByExample(Example(DustSiteData::class.java).apply {
+            createCriteria().andBetween("lst", s, e)
+        })
+        return res != null
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteStatusRep.kt b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteStatusRep.kt
new file mode 100644
index 0000000..6715a8e
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustSiteStatusRep.kt
@@ -0,0 +1,25 @@
+package com.flightfeather.monitor.domain.ds1.repository
+
+import com.flightfeather.monitor.domain.ds1.entity.DustSiteStatus
+import com.flightfeather.monitor.domain.ds1.mapper.DustSiteStatusMapper
+import com.flightfeather.monitor.enumration.dust.DeviceStatus
+import org.springframework.stereotype.Repository
+import tk.mybatis.mapper.entity.Example
+
+@Repository
+class DustSiteStatusRep(private val dustSiteStatusMapper: DustSiteStatusMapper) {
+
+    /**
+     * 鑾峰彇绔欑偣鐘舵��
+     * @param status 绔欑偣鐘舵��
+     */
+    fun select(status: List<DeviceStatus>): List<DustSiteStatus?> {
+        return dustSiteStatusMapper.selectByExample(Example(DustSiteStatus::class.java).apply {
+            createCriteria().apply {
+                status.forEach {
+                    orEqualTo("deviceStatus", it.value)
+                }
+            }
+        })
+    }
+}
\ 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
new file mode 100644
index 0000000..2dfcdf3
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/domain/ds1/repository/DustStatisticsValueRep.kt
@@ -0,0 +1,49 @@
+package com.flightfeather.monitor.domain.ds1.repository
+
+import com.flightfeather.monitor.domain.ds1.entity.DustExceptionData
+import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
+import com.flightfeather.monitor.domain.ds1.entity.DustStatisticsValue
+import com.flightfeather.monitor.domain.ds1.mapper.DustStatisticsValueMapper
+import org.springframework.stereotype.Repository
+import tk.mybatis.mapper.entity.Example
+import java.time.Duration
+import java.time.LocalDate
+
+@Repository
+class DustStatisticsValueRep(private val dustStatisticsValueMapper: DustStatisticsValueMapper) {
+
+    fun findLatestData(type: String): DustStatisticsValue? {
+        return dustStatisticsValueMapper.selectOneByExample(Example(DustStatisticsValue::class.java).apply {
+            createCriteria().andEqualTo("type", type)
+            orderBy("lst").desc()
+        })
+    }
+
+
+    /**
+     * 鍒ゆ柇鏌愭棩鐨勭粺璁℃槸鍚﹀瓨鍦�
+     */
+    fun findDataExist(date: LocalDate, type: String): Boolean {
+        val s = date.atStartOfDay()
+        val e = date.atStartOfDay().minusSeconds(1)
+        val res = dustStatisticsValueMapper.selectOneByExample(Example(DustStatisticsValue::class.java).apply {
+            createCriteria().andBetween("lst", s, e)
+                .andEqualTo("type", type)
+        })
+        return res != null
+    }
+
+    fun dailyStatics(date: LocalDate) {
+        val s = date.atStartOfDay()
+        val e = s.plusDays(1).minusSeconds(1)
+        dustStatisticsValueMapper.dailyStatics(s, e)
+    }
+
+    fun monthlyStatics(date: LocalDate) {
+        val s = date.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())
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/enumration/dust/DeviceStatus.kt b/src/main/java/com/flightfeather/monitor/enumration/dust/DeviceStatus.kt
new file mode 100644
index 0000000..751df99
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/enumration/dust/DeviceStatus.kt
@@ -0,0 +1,7 @@
+package com.flightfeather.monitor.enumration.dust
+
+enum class DeviceStatus(val value: Int, val des: String) {
+    ONLINE(0, "鍦ㄧ嚎"),
+    STOP(1, "鍋滆繍"),
+    OFFLINE(2, "绂荤嚎"),
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/enumration/dust/ExceptionType.kt b/src/main/java/com/flightfeather/monitor/enumration/dust/ExceptionType.kt
index ab9e931..ccc5f77 100644
--- a/src/main/java/com/flightfeather/monitor/enumration/dust/ExceptionType.kt
+++ b/src/main/java/com/flightfeather/monitor/enumration/dust/ExceptionType.kt
@@ -2,8 +2,10 @@
 
 enum class ExceptionType(val value:Int, val des:String) {
     TYPE0(0, "鏂綉鎴栨帀绾�"),
+    TYPE1(1, "鏁版嵁瓒呬綆寮傚父"),
     TYPE3(3, "鏁版嵁闀挎椂娈垫棤娉㈠姩"),
     TYPE4(4, "閲忕骇绐佸彉寮傚父"),
     TYPE5(5, "涓磋繎瓒呮爣寮傚父"),
     TYPE6(6, "鍗曟棩瓒呮爣娆℃暟涓磋繎澶勭綒寮傚父"),
+    TYPE7(7, "婊戝姩骞冲潎鍊肩獊鍙樺紓甯�"),
 }
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/scheduledtasks/BaseTimingTask.kt b/src/main/java/com/flightfeather/monitor/scheduledtasks/BaseTimingTask.kt
index 85a343b..8ee59c5 100644
--- a/src/main/java/com/flightfeather/monitor/scheduledtasks/BaseTimingTask.kt
+++ b/src/main/java/com/flightfeather/monitor/scheduledtasks/BaseTimingTask.kt
@@ -1,14 +1,18 @@
-package cn.flightfeather.supervision.timingtask
+package com.flightfeather.monitor.scheduledtasks
 
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
 import java.time.LocalDateTime
-import java.util.concurrent.ExecutorService
-import java.util.concurrent.Executors
 
 /**
  * 瀹氭椂浠诲姟鍩虹被
  */
 abstract class BaseTimingTask {
 
+    companion object {
+        val log: Logger = LoggerFactory.getLogger(BaseTimingTask::class.java)
+    }
+
     // 璁板綍涓婃浠诲姟鎵ц鐨勬椂闂寸偣锛屽崟浣嶏細姣
     private var lastTime: LocalDateTime = LocalDateTime.MIN
 
diff --git a/src/main/java/com/flightfeather/monitor/scheduledtasks/DustDailyStatisticAnalysisTask.kt b/src/main/java/com/flightfeather/monitor/scheduledtasks/DustDailyStatisticAnalysisTask.kt
new file mode 100644
index 0000000..e7d6fad
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/scheduledtasks/DustDailyStatisticAnalysisTask.kt
@@ -0,0 +1,26 @@
+package com.flightfeather.monitor.scheduledtasks
+
+import com.flightfeather.monitor.analysis.dust.StatisticAnalysisController
+import lombok.extern.slf4j.Slf4j
+import org.springframework.stereotype.Component
+import java.time.LocalDateTime
+
+@Component
+class DustDailyStatisticAnalysisTask(private val statisticAnalysisController: StatisticAnalysisController) :
+    BaseTimingTask() {
+
+    override val period: Long = 15
+
+    override fun execute(localtime: LocalDateTime) {
+//        println("鏃ュ垎鏋愯疆璇�")
+//        println(localtime)
+        if (localtime.hour == 9 && localtime.minute == 0) {
+            doTask(localtime)
+        }
+    }
+
+    override fun doTask(localtime: LocalDateTime) {
+        log.info("鏃ュ垎鏋愭墽琛�")
+        statisticAnalysisController.autoRunDailyStatics()
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/scheduledtasks/DustExceptionAnalysisTask.kt b/src/main/java/com/flightfeather/monitor/scheduledtasks/DustExceptionAnalysisTask.kt
new file mode 100644
index 0000000..fe5472e
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/scheduledtasks/DustExceptionAnalysisTask.kt
@@ -0,0 +1,26 @@
+package com.flightfeather.monitor.scheduledtasks
+
+import com.flightfeather.monitor.analysis.dust.ExceptionAnalysisController
+import org.springframework.stereotype.Component
+import java.time.LocalDateTime
+
+@Component
+class DustExceptionAnalysisTask(private val exceptionAnalysisController: ExceptionAnalysisController) :
+    BaseTimingTask() {
+
+    override val period: Long = 15
+
+    override fun execute(localtime: LocalDateTime) {
+//        println("寮傚父鍒嗘瀽杞")
+//        println(localtime)
+        if (localtime.hour == 8 && localtime.minute == 0) {
+            doTask(localtime)
+        }
+    }
+
+    override fun doTask(localtime: LocalDateTime) {
+        log.info("寮傚父鍒嗘瀽鎵ц")
+        exceptionAnalysisController.init()
+        exceptionAnalysisController.autoRun()
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/scheduledtasks/DustMonthlyStatisticAnalysisTask.kt b/src/main/java/com/flightfeather/monitor/scheduledtasks/DustMonthlyStatisticAnalysisTask.kt
new file mode 100644
index 0000000..8656414
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/scheduledtasks/DustMonthlyStatisticAnalysisTask.kt
@@ -0,0 +1,25 @@
+package com.flightfeather.monitor.scheduledtasks
+
+import com.flightfeather.monitor.analysis.dust.StatisticAnalysisController
+import org.springframework.stereotype.Component
+import java.time.LocalDateTime
+
+@Component
+class DustMonthlyStatisticAnalysisTask(private val statisticAnalysisController: StatisticAnalysisController) :
+    BaseTimingTask() {
+
+    override val period: Long = 15
+
+    override fun execute(localtime: LocalDateTime) {
+//        println("鏈堝垎鏋愯疆璇�")
+//        println(localtime)
+        if (localtime.dayOfMonth == 2 && localtime.hour == 0 && localtime.minute == 0) {
+            doTask(localtime)
+        }
+    }
+
+    override fun doTask(localtime: LocalDateTime) {
+        log.info("鏈堝垎鏋愭墽琛�")
+        statisticAnalysisController.autoRunMonthlyStatics()
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/flightfeather/monitor/scheduledtasks/ScheduledTaskController.java b/src/main/java/com/flightfeather/monitor/scheduledtasks/ScheduledTaskController.java
deleted file mode 100644
index 0231169..0000000
--- a/src/main/java/com/flightfeather/monitor/scheduledtasks/ScheduledTaskController.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.flightfeather.monitor.scheduledtasks;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
-public class ScheduledTaskController {
-
-    /*绾跨▼姹�*/
-    private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
-    public void run(){
-    
-    }
-}
diff --git a/src/main/java/com/flightfeather/monitor/scheduledtasks/TaskController.kt b/src/main/java/com/flightfeather/monitor/scheduledtasks/TaskController.kt
index 5839d7c..02f5d16 100644
--- a/src/main/java/com/flightfeather/monitor/scheduledtasks/TaskController.kt
+++ b/src/main/java/com/flightfeather/monitor/scheduledtasks/TaskController.kt
@@ -1,6 +1,7 @@
 package com.flightfeather.monitor.scheduledtasks
 
-import cn.flightfeather.supervision.timingtask.BaseTimingTask
+import lombok.extern.slf4j.Slf4j
+import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import org.springframework.stereotype.Component
 import java.time.LocalDateTime
@@ -13,23 +14,18 @@
 /**
  * 鏁版嵁鑾峰彇鎺у埗鍣�
  */
+@Slf4j
 @Component
 class TaskController(
-        /*瀹炰緥鍚� 绫诲悕*/
-//    fetchVOC: TaskFetchVOC,
-//    pushFume: TaskPushFume,
-//    ledgerCopy: TaskLedgerCopy,
-//    ledgerRemind: TaskLedgerRemind,
-//    taskJinAnLampEnterBaseInfo: TaskJinAnLampEnterBaseInfo,
-//    taskJinAnLampDeviceData: TaskJinAnLampDeviceData,
-//    taskJinAnConstructionSiteInfo: TaskJinAnConstructionSiteInfo,
-//    taskJinAnHourlyDustData: TaskJinAnHourlyDustData
+    dustExceptionAnalysisTask: DustExceptionAnalysisTask,
+    dustDailyStatisticAnalysisTask: DustDailyStatisticAnalysisTask,
+    dustMonthlyStatisticAnalysisTask: DustMonthlyStatisticAnalysisTask,
 ) {
 
     companion object {
         private const val FETCH_PERIOD_MIN = 1L * 60
         private const val MAINTAIN_PERIOD_MIN = 5L * 60
-        val LOGGER = LoggerFactory.getLogger(TaskController::class.java)
+        val log: Logger = LoggerFactory.getLogger(TaskController::class.java)
     }
 
     private val timeTask = mutableListOf<BaseTimingTask>()
@@ -39,13 +35,13 @@
     private var maintainTime: Date = Date()
 
     init {
-        LOGGER.info("娣诲姞瀹氭椂浠诲姟")
+        log.info("娣诲姞瀹氭椂浠诲姟")
         timeTask.clear()
-
        /*鍋氱殑瀹氭椂浠诲姟鍔犺繘鏉�*/
-
-
-        LOGGER.info("娣诲姞瀹氭椂浠诲姟瀹屾垚锛屼换鍔℃�昏${timeTask.size}涓�")
+        timeTask.add(dustExceptionAnalysisTask)
+        timeTask.add(dustDailyStatisticAnalysisTask)
+        timeTask.add(dustMonthlyStatisticAnalysisTask)
+        log.info("娣诲姞瀹氭椂浠诲姟瀹屾垚锛屼换鍔℃�昏${timeTask.size}涓�")
     }
 
     fun run() {
@@ -54,7 +50,6 @@
     }
 
     private fun fetchTask(isFirst: Boolean = false) {
-        val cal = Calendar.getInstance()
         val time = LocalTime.now()
         val sec = time.second
         val delay = 60L - sec
diff --git a/src/main/java/com/flightfeather/monitor/utils/DateUtil.kt b/src/main/java/com/flightfeather/monitor/utils/DateUtil.kt
new file mode 100644
index 0000000..4aed1d4
--- /dev/null
+++ b/src/main/java/com/flightfeather/monitor/utils/DateUtil.kt
@@ -0,0 +1,24 @@
+package com.flightfeather.monitor.utils
+
+import java.time.LocalDate
+
+object DateUtil {
+
+    fun findDurationDate(s: LocalDate, e: LocalDate): List<LocalDate> {
+        val res = mutableListOf<LocalDate>()
+        while (s.isBefore(e) || s.isEqual(e)) {
+            res.add(s)
+            s.plusDays(1)
+        }
+        return res
+    }
+
+    fun findDurationMonth(s: LocalDate, e: LocalDate): List<LocalDate> {
+        val res = mutableListOf<LocalDate>()
+        while (s.monthValue <= e.monthValue) {
+            res.add(s)
+            s.plusMonths(1)
+        }
+        return res
+    }
+}
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 7469d32..8d60e75 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -2,17 +2,17 @@
   datasource:
     ds1:
       driver-class-name: com.mysql.cj.jdbc.Driver
-#      url: jdbc:mysql://localhost:3306/fume
-#      username: fume
-#      password: fume_feiyu2023
+      url: jdbc:mysql://localhost:3306/fume
+      username: fume
+      password: fume_feiyu2023
 
 #      url: jdbc:mysql://localhost:3306/qianduan_sql
 #      username: root
 #      password: 1234
 
-      url: jdbc:mysql://localhost:3306/fume
-      username: root
-      password: 123456
+#      url: jdbc:mysql://localhost:3306/fume
+#      username: root
+#      password: 123456
 
 mybatis:
   configuration:
diff --git a/src/main/resources/generator/generatorConfig4ds1.xml b/src/main/resources/generator/generatorConfig4ds1.xml
index e338511..af8aefa 100644
--- a/src/main/resources/generator/generatorConfig4ds1.xml
+++ b/src/main/resources/generator/generatorConfig4ds1.xml
@@ -50,10 +50,10 @@
 <!--               enableCountByExample="false"-->
 <!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
 <!--               enableSelectByExample="false" selectByExampleQueryId="false"/>-->
-<!--        <table tableName="du_js_t_site_latest_time" domainObjectName="DustSiteLatestTime"-->
-<!--               enableCountByExample="false"-->
-<!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
-<!--               enableSelectByExample="false" selectByExampleQueryId="false"/>-->
+        <table tableName="du_js_t_site_latest_time" domainObjectName="DustSiteStatus"
+               enableCountByExample="false"
+               enableUpdateByExample="false" enableDeleteByExample="false"
+               enableSelectByExample="false" selectByExampleQueryId="false"/>
 <!--        <table tableName="du_js_t_site_map" domainObjectName="DustSiteMap"-->
 <!--               enableCountByExample="false"-->
 <!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
@@ -62,10 +62,10 @@
 <!--               enableCountByExample="false"-->
 <!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
 <!--               enableSelectByExample="false" selectByExampleQueryId="false"/>-->
-        <table tableName="dust_exception_setting" domainObjectName="DustExceptionSetting"
-               enableCountByExample="false"
-               enableUpdateByExample="false" enableDeleteByExample="false"
-               enableSelectByExample="false" selectByExampleQueryId="false"/>
+<!--        <table tableName="dust_exception_setting" domainObjectName="DustExceptionSetting"-->
+<!--               enableCountByExample="false"-->
+<!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
+<!--               enableSelectByExample="false" selectByExampleQueryId="false"/>-->
 <!--        <table tableName="dust_global_setting" domainObjectName="DustGlobalSetting"-->
 <!--               enableCountByExample="false"-->
 <!--               enableUpdateByExample="false" enableDeleteByExample="false"-->
diff --git a/src/main/resources/mapper/ds1/DustExceptionSettingMapper.xml b/src/main/resources/mapper/ds1/DustExceptionSettingMapper.xml
index 26168f7..c514a99 100644
--- a/src/main/resources/mapper/ds1/DustExceptionSettingMapper.xml
+++ b/src/main/resources/mapper/ds1/DustExceptionSettingMapper.xml
@@ -23,6 +23,7 @@
     <result column="change_trend_group" jdbcType="INTEGER" property="changeTrendGroup" />
     <result column="change_trend_interval" jdbcType="INTEGER" property="changeTrendInterval" />
     <result column="change_trend_rate" jdbcType="DOUBLE" property="changeTrendRate" />
+    <result column="change_trend_times" jdbcType="INTEGER" property="changeTrendTimes" />
     <result column="exceeding_standard" jdbcType="DOUBLE" property="exceedingStandard" />
   </resultMap>
   <sql id="Base_Column_List">
@@ -32,6 +33,6 @@
     id, user, update_time, region, version, miss_data_minutes, data_low, long_time_no_change, 
     mutation_num, mutation_rate, near_exceed_low_value, near_exceed_high_value, near_exceed_num, 
     day_exceed_borderline_low_num, day_exceed_borderline_high_num, change_trend_group, 
-    change_trend_interval, change_trend_rate, exceeding_standard
+    change_trend_interval, change_trend_rate, change_trend_times, exceeding_standard
   </sql>
 </mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/ds1/DustSiteLatestTimeMapper.xml b/src/main/resources/mapper/ds1/DustSiteStatusMapper.xml
similarity index 91%
rename from src/main/resources/mapper/ds1/DustSiteLatestTimeMapper.xml
rename to src/main/resources/mapper/ds1/DustSiteStatusMapper.xml
index 10d9f61..c3c958a 100644
--- a/src/main/resources/mapper/ds1/DustSiteLatestTimeMapper.xml
+++ b/src/main/resources/mapper/ds1/DustSiteStatusMapper.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.flightfeather.monitor.domain.ds1.mapper.DustSiteLatestTimeMapper">
-  <resultMap id="BaseResultMap" type="com.flightfeather.monitor.domain.ds1.entity.DustSiteLatestTime">
+<mapper namespace="com.flightfeather.monitor.domain.ds1.mapper.DustSiteStatusMapper">
+  <resultMap id="BaseResultMap" type="com.flightfeather.monitor.domain.ds1.entity.DustSiteStatus">
     <!--
       WARNING - @mbg.generated
     -->
diff --git a/src/main/resources/mapper/ds1/DustStatisticsValueMapper.xml b/src/main/resources/mapper/ds1/DustStatisticsValueMapper.xml
index 40edb30..4726f1b 100644
--- a/src/main/resources/mapper/ds1/DustStatisticsValueMapper.xml
+++ b/src/main/resources/mapper/ds1/DustStatisticsValueMapper.xml
@@ -22,4 +22,42 @@
     -->
     id, mn_code, lst, day_avg, min, max, day_online, day_valid, day_exceeding, type
   </sql>
+
+  <insert id="dailyStatics">
+    insert into  dust_statistics_value(mn_code,lst,day_avg,min,max,day_online,day_valid,day_exceeding,type)
+    select  a.*
+    from  (select
+    mn_code as mn_code,
+    DATE(lst) as lst,
+    ROUND(AVG(dust_value),3)  as day_avg,
+    min(dust_value) as min,
+    max(dust_value) as max,
+    CONCAT(ROUND(COUNT(*)/96*100, 2), '%')  as day_online,
+    CONCAT(ROUND(SUM(CASE WHEN dust_value >0 THEN 1 ELSE 0 END)/96 *100, 2), '%') as day_valid,
+    CONCAT(ROUND(SUM(CASE WHEN dust_value >= 1  THEN 1 ELSE 0 END)/96*100,2),'%') as  day_exceeding,
+    'day' as type
+    from ja_t_dust_site_data_info
+    where  lst between #{beginTime} and #{endTime}
+    GROUP BY mn_code,DATE(lst)
+    ) as a
+  </insert>
+  <insert id="monthlyStatics">
+    insert into  dust_statistics_value(mn_code,lst,day_avg,min,max,day_online,day_valid,day_exceeding,type)
+    select  a.*
+    from  (
+    SELECT
+    mn_code AS mn_code,
+    DATE_FORMAT(lst, '%Y-%m-01') AS month,
+    ROUND(AVG(dust_value), 3) AS month_avg,
+    MIN(dust_value) AS min,
+    MAX(dust_value) AS max,
+    CONCAT(ROUND(COUNT(*) / #{count} * 100, 2), '%') AS month_online,
+    CONCAT(ROUND(SUM(CASE WHEN flag = 'N' OR flag = 'A' THEN 1 ELSE 0 END) / #{count} * 100, 2), '%') AS month_valid,
+    CONCAT(ROUND(SUM(CASE WHEN dust_value >= 1 THEN 1 ELSE 0 END) / #{count} * 100, 2), '%') AS month_exceeding,
+    'month' as type
+    FROM ja_t_dust_site_data_info
+    WHERE lst BETWEEN #{beginTime} and #{endTime}
+    GROUP BY mn_code, DATE_FORMAT(lst, '%Y-%m-01')
+    ) as a
+  </insert>
 </mapper>
\ No newline at end of file
diff --git a/src/test/java/com/flightfeather/monitor/QianduanApplicationTests.java b/src/test/java/com/flightfeather/monitor/MonitorApplicationTests.java
similarity index 96%
rename from src/test/java/com/flightfeather/monitor/QianduanApplicationTests.java
rename to src/test/java/com/flightfeather/monitor/MonitorApplicationTests.java
index b9f1150..4e51a49 100644
--- a/src/test/java/com/flightfeather/monitor/QianduanApplicationTests.java
+++ b/src/test/java/com/flightfeather/monitor/MonitorApplicationTests.java
@@ -9,7 +9,7 @@
 import java.util.Locale;
 
 @SpringBootTest
-class QianduanApplicationTests {
+class MonitorApplicationTests {
 
     @Test
     void contextLoads() throws ParseException {
diff --git a/src/test/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisControllerTest.kt b/src/test/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisControllerTest.kt
new file mode 100644
index 0000000..176526f
--- /dev/null
+++ b/src/test/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisControllerTest.kt
@@ -0,0 +1,33 @@
+package com.flightfeather.monitor.analysis.dust
+
+import org.junit.jupiter.api.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 ExceptionAnalysisControllerTest {
+
+    @Autowired
+    lateinit var exceptionAnalysisController: ExceptionAnalysisController
+
+    @Test
+    fun autoRun() {
+        exceptionAnalysisController.init()
+        exceptionAnalysisController.autoRun()
+    }
+
+    @Test
+    fun run() {
+        exceptionAnalysisController.init()
+        val d = LocalDate.of(2023, 7, 2)
+        exceptionAnalysisController.run(d)
+//        exceptionAnalysisController.debugRun()
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisControllerTest.kt b/src/test/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisControllerTest.kt
new file mode 100644
index 0000000..a1d4971
--- /dev/null
+++ b/src/test/java/com/flightfeather/monitor/analysis/dust/StatisticAnalysisControllerTest.kt
@@ -0,0 +1,40 @@
+package com.flightfeather.monitor.analysis.dust
+
+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 StatisticAnalysisControllerTest {
+    @Autowired
+    lateinit var statisticAnalysisController: StatisticAnalysisController
+
+    @Test
+    fun dailyStatics() {
+        val d = LocalDate.of(2023, 7, 2)
+        statisticAnalysisController.dailyStatics(d)
+    }
+
+    @Test
+    fun monthlyStatics() {
+        val d = LocalDate.of(2023, 7, 1)
+        statisticAnalysisController.monthlyStatics(d)
+    }
+
+    @Test
+    fun autoRunDailyStatics() {
+        statisticAnalysisController.autoRunDailyStatics()
+    }
+
+    @Test
+    fun autoRunMonthlyStatics() {
+        statisticAnalysisController.autoRunMonthlyStatics()
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3