feiyu02
2023-11-23 e2392116cd6f875cdc2f46bc04b04d5305f21b56
1. 修改日统计值的排序查询逻辑
已修改20个文件
已添加5个文件
534 ■■■■ 文件已修改
src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisController.kt 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/BaseExceptionContinuous.kt 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/BaseExceptionContinuousSingle.kt 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataExceed.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataLowValue.kt 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataMissing.kt 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataMissing_BackUp.kt 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionExceedingTimes.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionNoFluctuation.kt 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionSlideAverage.kt 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionValidRate.kt 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionValueMutation.kt 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/controller/FugitiveDustController.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustStatisticsValueMapper.kt 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/enumration/dust/DataStatus.kt 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/enumration/dust/ExceptionType.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/pojo/AnalysisDustData.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/service/FugitiveDustService.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/service/impl/FugitiveDustServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/utils/StringUtil.kt 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ds1/DustStatisticsValueMapper.xml 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisControllerTest.kt 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisController.kt
@@ -33,13 +33,14 @@
            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))
//                add(ExceptionNoFluctuation(it))
//                add(ExceptionApproachExceeding(it))
//                add(ExceptionExceedingTimes(it))
//                add(ExceptionSlideAverage(it))
//                add(ExceptionValueMutation(it))
//                add(ExceptionDataLowValue(it))
//                add(ExceptionDataExceed(it))
//                add(ExceptionValidRate(it))
            }
        }
    }
src/main/java/com/flightfeather/monitor/analysis/dust/RiskAnalysisController.kt
@@ -35,6 +35,9 @@
        }
    }
    /**
     * æ—¥é£Žé™©ç»Ÿè®¡,默认统计昨天的风险值
     */
    fun autoRunDaily() {
        val data = riskValueRep.findLatestData("day")
        val yesterday = LocalDate.now().minusDays(1)
@@ -54,15 +57,21 @@
        }
    }
    /**
     * æœˆé£Žé™©ç»Ÿè®¡,根据昨日最新数据所在月份,统计该月的综合风险,截至昨天
     */
    fun autoRunMonthly() {
        val data = riskValueRep.findLatestData("month")
        val lastMonth = LocalDate.now().minusMonths(1).withDayOfMonth(1)
        if (data == null) {
            runMonthly(lastMonth)
        } else {
            // èŽ·å–éœ€è¦ç»Ÿè®¡çš„æœ€æ–°æœˆä»½,是昨天所在的月份(因为监测数据是今天获取昨天一整天的数据)
            val thisMonth = LocalDate.now().minusDays(1)
            // æœ€æ–°æœˆç»Ÿè®¡è®°å½•的时间
            val date = LocalDateTime.ofInstant(data.lst.toInstant(), ZoneId.systemDefault())
            val sT = date.plusMonths(1).toLocalDate()
            val du = DateUtil.findDurationMonth(sT, lastMonth)
            val sT = date.toLocalDate()
            val du = DateUtil.findDurationMonth(sT, thisMonth)
            du.forEach {
                runMonthly(it)
            }
@@ -102,7 +111,7 @@
        }
        // æ‰€æœ‰åˆ†æžç»“果入库
        if (taskMonthly?.resultList?.isNotEmpty() == true) {
            riskValueRep.insert(taskMonthly?.resultList!!)
            riskValueRep.insertOrUpdate(taskMonthly?.resultList!!)
        }
        running2 = false
    }
src/main/java/com/flightfeather/monitor/analysis/dust/exception/BaseExceptionContinuous.kt
@@ -4,21 +4,21 @@
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
/**
 * è¿žç»­ç±»åž‹çš„异常分析基类
 * è¿žç»­ç±»åž‹çš„异常分析基类,适用于当前数据与相邻数据之间有关联关系的情况
 */
abstract class BaseExceptionContinuous(config: DustExceptionSetting) : BaseDustExceptionAnalysis(config) {
    // èµ·å§‹æ•°æ®ä¸‹æ ‡
    private var sIndex = 0
    protected var sIndex = 0
    // èµ·å§‹æ•°æ®å¯¹è±¡
    private var startData: DustSiteData? = null
    protected var startData: DustSiteData? = null
    // æœ«å°¾æ•°æ®ä¸‹æ ‡
    private var eIndex = -1
    protected var eIndex = -1
    // æœ«å°¾æ•°æ®å¯¹è±¡
    private var lastData: DustSiteData? = null
    protected var lastData: DustSiteData? = null
    // èµ·å§‹æ•°æ®ä¸Žæœ«å°¾æ•°æ®é—´éš”
    open var durationCount = 1
    private var existException = false
    protected var existException = false
    /**
     * åˆ¤æ–­æ˜¯å¦æ»¡è¶³å¼‚常条件
@@ -75,7 +75,7 @@
    /**
     * æ£€æŸ¥è¿žç»­å¼‚常结束时,是否符合异常存储条件
     */
    private fun checkResult() {
    open fun checkResult() {
        if (existException && judgeDuration(sIndex, eIndex)) {
            startData?.let {
                resultList.add(newResult(it, lastData))
src/main/java/com/flightfeather/monitor/analysis/dust/exception/BaseExceptionContinuousSingle.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
package com.flightfeather.monitor.analysis.dust.exception
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
/**
 * è¿žç»­ç±»åž‹çš„异常分析基类,区别于父类的地方在于此种异常只和单个数据本身有关,于相邻数据无关
 */
abstract class BaseExceptionContinuousSingle(config: DustExceptionSetting) : BaseExceptionContinuous(config) {
    override fun onNextData(data: DustSiteData) {
        eIndex++
        if (lastData == null) {
            startData = data
        }
        // åˆ¤æ–­ç›¸é‚»æ•°æ®æ˜¯å¦è¿žç»­å¹¶ä¸”是否满足异常判断
        if (!isContinuous(lastData, data)) {
            checkResult()
            sIndex = eIndex
            startData = data
        } else {
            if (judgeException(lastData, data)) {
                // ä¿®æ”¹äº†èµ·å§‹æ•°æ®çš„位置,变更为出现异常的该值,而不是原来的出现异常的数据的前一个值
                if (!existException) {
                    sIndex = eIndex
                    startData = data
                }
                existException = true
            } else {
                checkResult()
            }
        }
        lastData = data
    }
}
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataExceed.kt
@@ -2,17 +2,18 @@
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
import com.flightfeather.monitor.enumration.dust.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
/**
 * æ•°æ®è¶…标异常分析
 */
class ExceptionDataExceed(config: DustExceptionSetting) : BaseExceptionContinuous(config) {
class ExceptionDataExceed(config: DustExceptionSetting) : BaseExceptionContinuousSingle(config) {
    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE2
    override fun judgeException(p: DustSiteData?, n: DustSiteData): Boolean {
        return n.dustValue >= config.exceedingStandard
        return n.dustValue >= config.exceedingStandard && n.flag == DataStatus.N.value
    }
    override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean {
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataLowValue.kt
@@ -3,32 +3,24 @@
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.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
/**
 * æ•°æ®è¶…低异常分析
 */
class ExceptionDataLowValue(config: DustExceptionSetting) : BaseExceptionContinuous(config) {
class ExceptionDataLowValue(config: DustExceptionSetting) : BaseExceptionContinuousSingle(config) {
    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE1
    override fun judgeException(p: DustSiteData?, n: DustSiteData): Boolean {
        return n.dustValue <= config.dataLow
        val b1 = n.flag == DataStatus.OUT_MIN.value
        val b2 = n.dustValue <= config.dataLow && n.flag == DataStatus.N.value
        val b3 = n.flag == DataStatus.Q.value
        return b1 || b2 || b3
    }
    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
        }
    }
}
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataMissing.kt
@@ -2,35 +2,68 @@
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
import com.flightfeather.monitor.enumration.dust.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
import java.time.Duration
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
/**
 * æ•°æ®ç¼ºå¤±å¼‚常分析
 */
class ExceptionDataMissing(config: DustExceptionSetting) : BaseDustExceptionAnalysis(config) {
    private var lastData: DustSiteData? = null
    override fun init() {
        super.init()
        lastData = null
    }
class ExceptionDataMissing(config: DustExceptionSetting) : BaseExceptionContinuous(config) {
    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE0
    override fun onNextData(data: DustSiteData) {
        lastData?.let {
            val t1 = it.lst
            val t2 = data.lst
            if (Duration.between(t1?.toInstant(), t2.toInstant()).toMinutes() > config.missDataMinutes) {
                resultList.add(newResult(it, data))
//    override fun onNextData(data: DustSiteData) {
//        lastData?.let {
//            val t1 = it.lst
//            val t2 = data.lst
//            val b1 = Duration.between(t1?.toInstant(), t2.toInstant()).toMinutes() >= config.missDataMinutes
//            if (b1) {
//                resultList.add(newResult(it, data))
//            }
//        }
//        lastData = data
//    }
    override fun judgeException(p: DustSiteData?, n: DustSiteData): Boolean {
        // æ•°æ®ç¼ºå¤±å¼‚常不同于其他异常的点在于当日首个数据如果不存在,需要做一次判断
        var pData: DustSiteData? = null
        if (p == null) {
            //当首个数据进入时,需要判断是否为当日的第一个数据
            val time = LocalDateTime.ofInstant(n.lst.toInstant(), ZoneId.systemDefault())
            if (time.hour == 0 && time.minute == 0) {
                return false
            }
            // å¦‚果缺失当日首个数据,则需要将当前数据n和当日0点进行比较,记录数据缺失异常
            else {
                startData = DustSiteData().apply {
                    mnCode = n.mnCode
                    lst = Date.from(time.withHour(0).withMinute(0).withSecond(0).atZone(ZoneId.systemDefault())
                        .toInstant())
                    flag = DataStatus.A.value
                }
                pData = startData
            }
        }
        lastData = data
        if (pData == null) return false
        val t1 = pData.lst
        val t2 = n.lst
        val b1 = Duration.between(t1?.toInstant(), t2.toInstant()).toMinutes() >= config.missDataMinutes
        val b2 = n.flag == DataStatus.A.value || n.flag == DataStatus.D.value
        return b1 || b2
    }
    override fun onDone() {
        //do noting
    override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean {
        return true
    }
    /**
     * é’ˆå¯¹æ•°æ®ç¼ºå¤±å¼‚常, å¯¹æ•°æ®çš„连续性不做判断
     */
    override fun isContinuous(d1: DustSiteData?, d2: DustSiteData): Boolean {
        return true
    }
}
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionDataMissing_BackUp.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package com.flightfeather.monitor.analysis.dust.exception
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
import com.flightfeather.monitor.enumration.dust.ExceptionType
import java.time.Duration
/**
 * æ•°æ®ç¼ºå¤±å¼‚常分析
 */
class ExceptionDataMissing_BackUp(config: DustExceptionSetting) : BaseDustExceptionAnalysis(config) {
    private var lastData: DustSiteData? = null
    override fun init() {
        super.init()
        lastData = null
    }
    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE0
    override fun onNextData(data: DustSiteData) {
        lastData?.let {
            val t1 = it.lst
            val t2 = data.lst
            val b1 = Duration.between(t1?.toInstant(), t2.toInstant()).toMinutes() >= config.missDataMinutes
            if (b1) {
                resultList.add(newResult(it, data))
            }
        }
        lastData = data
    }
    override fun onDone() {
        //do noting
    }
}
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionExceedingTimes.kt
@@ -3,6 +3,7 @@
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.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
import java.time.LocalDateTime
import java.time.ZoneId
@@ -27,7 +28,7 @@
    override fun onNextData(data: DustSiteData) {
        if (startData == null) startData = data
        if (data.dustValue >= config.exceedingStandard) {
        if (data.dustValue >= config.exceedingStandard && data.flag == DataStatus.N.value) {
            exceedingCount++
        }
    }
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionNoFluctuation.kt
@@ -2,6 +2,7 @@
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
import com.flightfeather.monitor.enumration.dust.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
/**
@@ -13,7 +14,10 @@
    override fun judgeException(p: DustSiteData?, n: DustSiteData): Boolean {
        if (p == null) return false
        return p.dustValue == n.dustValue
        val b1 = p.dustValue == n.dustValue
        val b2 = p.flag != DataStatus.A.value && p.flag != DataStatus.D.value
        val b3 = n.flag != DataStatus.A.value && n.flag != DataStatus.D.value
        return b1 && b2 && b3
    }
    override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean {
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionSlideAverage.kt
@@ -2,6 +2,7 @@
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
import com.flightfeather.monitor.enumration.dust.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
import kotlin.math.abs
@@ -12,7 +13,7 @@
    private val historyDataList = mutableListOf<DustSiteData>()
    private val tempDataList = mutableListOf<DustSiteData>()
    private val avgListReverse = mutableListOf<Double>()
    private val avgListReverse = mutableListOf<Pair<Double, Boolean>>()
    private var startData: DustSiteData? = null
    private var lastData: DustSiteData? = null
    private var sIndex = 0
@@ -67,11 +68,17 @@
     */
    private fun calAvg(list: List<DustSiteData>) {
        var total = .0
        var valid = true
        val count = list.size
        if (count == 0) return
        list.forEach { total += it.dustValue }
        list.forEach {
            total += it.dustValue
            if (it.flag != DataStatus.N.value) {
                valid = false
            }
        }
        val avg = total / count
        avgListReverse.add(0, avg)
        avgListReverse.add(0, Pair(avg, valid))
    }
    /**
@@ -84,14 +91,14 @@
            return false
        } else {
            // æ»‘动均值满足数量时,计算均值之间是否连续超过限定比率
            val rateList = mutableListOf<Double>()
            val rateList = mutableListOf<Pair<Double, Boolean>>()
            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) {
                if (!y.second || y.first < config.changeTrendRate) {
                    return false
                }
            }
@@ -102,11 +109,12 @@
    /**
     * è®¡ç®—滑动均值变化率
     */
    private fun calAvgChangeRate(a1: Double, a2: Double): Double {
        return if (a2 == .0) {
            1.0
    private fun calAvgChangeRate(a1: Pair<Double, Boolean>, a2: Pair<Double, Boolean>): Pair<Double, Boolean> {
        val valid = a1.second && a2.second
        return if (a2.first == .0) {
            Pair(1.0, valid)
        } else {
            abs(a1 - a2) / a2
            Pair(abs(a1.first - a2.first) / a2.first, valid)
        }
    }
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionValidRate.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
package com.flightfeather.monitor.analysis.dust.exception
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.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
/**
 * æ•°æ®æœ‰æ•ˆçއ异叏
 */
class ExceptionValidRate(config: DustExceptionSetting) : BaseDustExceptionAnalysis(config) {
    private var count = 0
    private val total = 96
    private var startData: DustSiteData? = null
    override fun init() {
        super.init()
        count = 0
        startData = null
    }
    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE8
    override fun onNextData(data: DustSiteData) {
        if (startData == null) startData = data
        if (data.flag == DataStatus.N.value) {
            count++
        }
    }
    override fun onDone() {
        val rate = count / total
        if (rate < 0.9) {
            startData?.let {
                val eType = getExceptionType()
                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 = sT
                    endTime = eT
                })
            }
        }
    }
}
src/main/java/com/flightfeather/monitor/analysis/dust/exception/ExceptionValueMutation.kt
@@ -2,6 +2,7 @@
import com.flightfeather.monitor.domain.ds1.entity.DustExceptionSetting
import com.flightfeather.monitor.domain.ds1.entity.DustSiteData
import com.flightfeather.monitor.enumration.dust.DataStatus
import com.flightfeather.monitor.enumration.dust.ExceptionType
import kotlin.math.abs
@@ -10,14 +11,28 @@
 */
class ExceptionValueMutation(config: DustExceptionSetting) : BaseExceptionContinuous(config) {
    /**
     * æœ¬å¼‚常的连续发生次数会根据异常的程度变化
     * å½“突变的量级超过设定值1倍是,连续发生次数要求减少1倍
     */
    private var special = false
    override fun getExceptionType(): ExceptionType = ExceptionType.TYPE4
    override fun judgeException(p: DustSiteData?, n: DustSiteData): Boolean {
        if (p == null) return false
        return abs((p.dustValue - n.dustValue) / p.dustValue) >= config.mutationRate
        val r = abs((p.dustValue - n.dustValue) / p.dustValue)
        val b1 = r >= (2 * config.mutationRate) && n.flag == DataStatus.N.value
        val b2 = r >= config.mutationRate && n.flag == DataStatus.N.value
        val b3 = n.flag == DataStatus.OUT_MAX.value
        if (b1) special = true
        return b1 || b2 || b3
    }
    override fun judgeDuration(sIndex: Int, eIndex: Int): Boolean {
        return (eIndex - sIndex + 1) >= config.mutationNum
        val b1 = special && (eIndex - sIndex) >= (config.mutationNum / 2)
        val b2 = (eIndex - sIndex) >= config.mutationNum
        special = false
        return b1 || b2
    }
}
src/main/java/com/flightfeather/monitor/controller/FugitiveDustController.java
@@ -19,7 +19,6 @@
    private FugitiveDustService fugitiveDustService;
    //扬尘 ç›‘测点历史数据  åŽç«¯åˆ†é¡µ
    @GetMapping("/history1")
    public Result conditonQueryAbnormalData3(@RequestParam(defaultValue = "1") Integer page,
@@ -35,12 +34,14 @@
       List<DustSiteData> list= fugitiveDustService.conditonQueryhistoryallData(siteName,mnCode, beginTime,endTime,scenarioType);
        return Result.success(list);
    }
//    è¿”回监测点数据中的不同的场景
    @GetMapping("/scenario")
    public Result conditonQueryHistoryData(){
        List<DustSiteData> list = fugitiveDustService.scenarioData();
        return Result.success(list);
    }
// è¿”回所有站点名字
    @GetMapping("/sitename")
    public Result allSiteName(){
@@ -57,17 +58,26 @@
//    æ ¹æ®ç«™ç‚¹åå­—和时段进行统计分析 åŽç«¯åˆ†é¡µ
    @GetMapping("/analysistime")
    public Result analysisByTime( @RequestParam(defaultValue = "1") Integer page,
                                  @RequestParam(defaultValue = "20")Integer pageSize,String siteName,String beginTime, String endTime){
    PageBean pageBean = fugitiveDustService.pageAnalysisTime(page,pageSize,siteName,beginTime,endTime);
    public Result analysisByTime(
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "20") Integer pageSize,
            String siteName,
            String beginTime,
            String endTime,
            String orderProp,
            Boolean asc) {
        PageBean pageBean = fugitiveDustService.pageAnalysisTime(page, pageSize, siteName, beginTime, endTime,
                orderProp, asc);
    return Result.success(pageBean);
}
    //动态计算分析数据  ä¸åˆ†é¡µ
    @GetMapping("/analysisall")
    public Result analysisAll(String siteName,String beginTime, String endTime){
        List<AnalysisDustData> list = fugitiveDustService.analysisAll(siteName,beginTime,endTime);
        return Result.success(list);
    }
//获得不同的异常类型
    @GetMapping("/exceptiontype")
    public Result getExceptionType(){
@@ -83,7 +93,6 @@
    PageBean pageBean =  fugitiveDustService.getExceptionData(page,pageSize,siteName,exceptionType,beginTime,endTime);
    return Result.success(pageBean);
}
    //条件查询异常数据 ä¸åˆ†é¡µ
@@ -107,7 +116,6 @@
        List<DustExceptionData> list = fugitiveDustService.getExceptionSitenameAndCode(exceptionType,beginTime,endTime,street,dutyCompany,siteName);
        return Result.success(list);
    }
    //   æ ¹æ®æ—¶é—´,地址,运维商,点位名称,返回该异常类型的个数
@@ -139,6 +147,7 @@
        fugitiveDustService.addAuditNotes(auditInfo);
        return Result.success();
    }
    /*返回审核表所有数据*/
    @PostMapping("/auditAllData")
    public Result getAuditAllData(){
src/main/java/com/flightfeather/monitor/domain/ds1/mapper/DustStatisticsValueMapper.kt
@@ -2,6 +2,7 @@
import com.flightfeather.monitor.domain.ds1.entity.DustStatisticsValue
import com.flightfeather.monitor.domain.util.MyMapper
import com.flightfeather.monitor.pojo.AnalysisDustData
import org.apache.ibatis.annotations.Mapper
import java.time.LocalDateTime
@@ -11,4 +12,10 @@
    fun dailyStatics(beginTime: LocalDateTime, endTime: LocalDateTime)
    fun monthlyStatics(beginTime: LocalDateTime, endTime: LocalDateTime, count: Int)
    /**
     * æ ¹æ®æ¡ä»¶æŽ’序查询
     */
    fun selectByOrder(siteName: String, beginTime: String, endTime: String, orderProp: String?, asc: Boolean):
            List<AnalysisDustData?>
}
src/main/java/com/flightfeather/monitor/domain/ds1/repository/RiskValueRep.kt
@@ -35,6 +35,37 @@
    }
    /**
     * æ‰¹é‡æ’入或更新,仅限同一日的或同一月的批量数据
     * @param list
     */
    fun insertOrUpdate(list: List<RiskValue>): Int {
        if (list.isEmpty()) return 0
        val newDataList = mutableListOf<RiskValue>()
        val oldDataList = mutableListOf<RiskValue>()
        val dataList = riskValueMapper.selectByExample(Example(RiskValue::class.java).apply {
            createCriteria().andEqualTo("lst", list[0].lst)
                .andEqualTo("type", list[0].type)
        })
        list.forEach { l ->
            val r = dataList.find { d ->
                d?.mnCode == l.mnCode
            }
            if (r != null) {
                l.id = r.id
                oldDataList.add(l)
            } else {
                newDataList.add(l)
            }
        }
        val r1 = riskValueMapper.insertList(newDataList)
        var r2 = 0
        oldDataList.forEach {
            r2 += riskValueMapper.updateByPrimaryKey(it)
        }
        return r1 + r2
    }
    /**
     * æŸ¥è¯¢
     * @param mnCode
     * @param date
src/main/java/com/flightfeather/monitor/enumration/dust/DataStatus.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.flightfeather.monitor.enumration.dust
enum class DataStatus(val value: String, val des: String) {
    N("N", "正常"),
    C("C", "设备校准"),
    D("D", "设备断开"),
    P("P", "一起电源故障"),
    OUT_MIN("-", "超过数据设定范围下限"),
    OUT_MAX("+", "超过数据设定范围上限"),
    Q("Q", "低于全市国控点PM2.5平均浓度二分之一"),
    VALID(">", "颗粒物有效数据大于90%"),
    INVALID("<", "颗粒物有效数据小于90%"),
    R("R", "风速大于8m/s和雨、雪等天气条件"),
    J("J", "开展计量检定或比对测试"),
    A("A", "补传"),
}
src/main/java/com/flightfeather/monitor/enumration/dust/ExceptionType.kt
@@ -1,7 +1,7 @@
package com.flightfeather.monitor.enumration.dust
enum class ExceptionType(val value:Int, val des:String) {
    TYPE0(0, "断网或掉线"),
    TYPE0(0, "数据缺失异常"),
    TYPE1(1, "数据超低异常"),
    TYPE2(2, "数据超标"),
    TYPE3(3, "数据长时段无波动"),
@@ -9,4 +9,5 @@
    TYPE5(5, "临近超标异常"),
    TYPE6(6, "单日超标次数临近处罚异常"),
    TYPE7(7, "滑动平均值突变异常"),
    TYPE8(8, "有效率异常"),
}
src/main/java/com/flightfeather/monitor/pojo/AnalysisDustData.java
@@ -21,8 +21,8 @@
    private Double dayAvg;
    private Double min;
    private Double max;
    private String dayOnline;
    private String dayValid;
    private String  dayExceeding;
    private Double dayOnline;
    private Double dayValid;
    private Double  dayExceeding;
    private String  type;
}
src/main/java/com/flightfeather/monitor/service/FugitiveDustService.java
@@ -1,6 +1,7 @@
package com.flightfeather.monitor.service;
import com.flightfeather.monitor.pojo.*;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@@ -16,7 +17,8 @@
    List<AnalysisDustData> analysisByTime(String siteName, String beginTime, String endTime);
    PageBean pageAnalysisTime(Integer page, Integer pageSize, String siteName, String beginTime, String endTime);
    PageBean pageAnalysisTime(Integer page, Integer pageSize, String siteName, String beginTime, String endTime, String orderProp,
                              Boolean asc);
    List<DustExceptionType> getExceptionType();
@@ -36,6 +38,7 @@
    List<AnalysisDustData> analysisAll(String siteName, String beginTime, String endTime);
    List<DustSiteData> conditonQueryhistoryallData(String siteName, String mnCode, String beginTime, String endTime, String[] scenarioType);
    /*新增审计信息*/
    void addAuditNotes(AuditInfo auditInfo);
src/main/java/com/flightfeather/monitor/service/impl/FugitiveDustServiceImpl.java
@@ -1,13 +1,16 @@
package com.flightfeather.monitor.service.impl;
import com.flightfeather.monitor.domain.ds1.mapper.DustStatisticsValueMapper;
import com.flightfeather.monitor.mapper.FugitiveDustMapper;
import com.flightfeather.monitor.pojo.*;
import com.flightfeather.monitor.service.FugitiveDustService;
import com.flightfeather.monitor.utils.StringUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;
import java.time.LocalDateTime;
import java.util.List;
@@ -18,6 +21,9 @@
    @Autowired
    private FugitiveDustMapper fugitiveDustMapper;
    @Autowired
    private DustStatisticsValueMapper dustStatisticsValueMapper;
    @Override
    public PageBean page(Integer page, Integer pageSize, String siteName, String mnCode, String beginTime, String endTime,String[] scenarioType) {
@@ -58,17 +64,17 @@
    }
    @Override
    public PageBean pageAnalysisTime(Integer page, Integer pageSize, String siteName, String beginTime, String endTime) {
    public PageBean pageAnalysisTime(Integer page, Integer pageSize, String siteName, String beginTime,
                                     String endTime, String orderProp,
                                     Boolean asc) {
        //设置分页参数
        PageHelper.startPage(page,pageSize);
        //执行查询
        List<AnalysisDustData> infoList=fugitiveDustMapper.analysisByTime(siteName,beginTime,endTime);
        Page<AnalysisDustData> p = PageHelper.startPage(page, pageSize);
        //获取查询结果
        Page<AnalysisDustData> p=(Page<AnalysisDustData>)infoList;
        String prop = StringUtil.INSTANCE.camelCaseToUnderline(orderProp);
        dustStatisticsValueMapper.selectByOrder(siteName, beginTime, endTime, prop, asc);
        //封装PageBean对象*/
        PageBean pageBean=new PageBean(p.getTotal(),p.getResult());
        return  pageBean;
        //封装PageBean对象
        return new PageBean(p.getTotal(), p.getResult());
    }
    @Override
src/main/java/com/flightfeather/monitor/utils/StringUtil.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.flightfeather.monitor.utils
/**
 * æ–‡æœ¬å·¥å…·
 */
object StringUtil {
    /**
     * é©¼å³°å‘½åæ³•文本转下划线文本
     * @param t
     * @return
     */
    fun camelCaseToUnderline(t: String?): String? {
        t ?: return null
        val result = StringBuilder()
        t.forEach {
            if (it.isUpperCase()) {
                result.append('_')
                result.append(it.lowercaseChar())
            } else {
                result.append(it)
            }
        }
        return result.toString()
    }
}
src/main/resources/application.yml
@@ -3,9 +3,9 @@
    ds1:
      driver-class-name: com.mysql.cj.jdbc.Driver
#      ç”Ÿäº§çŽ¯å¢ƒ
#      url: jdbc:mysql://localhost:3306/fume?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&allowMultiQueries=true&useSSL=false
#      username: fume
#      password: fume_feiyu2023
      url: jdbc:mysql://localhost:3306/fume?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&allowMultiQueries=true&useSSL=false
      username: fume
      password: fume_feiyu2023
#      url: jdbc:mysql://localhost:3306/qianduan_sql?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&allowMultiQueries=true&useSSL=false
#      username: root
@@ -15,14 +15,14 @@
#      username: root
#      password: 123456
      url: jdbc:mysql://114.215.109.124:3306/fume?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&allowMultiQueries=true&useSSL=false
      username: fumeRemote
      password: feiyu2023
#      url: jdbc:mysql://114.215.109.124:3306/fume?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&allowMultiQueries=true&useSSL=false
#      username: fumeRemote
#      password: feiyu2023
mybatis:
  configuration:
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
    map-underscore-to-camel-case: true
  type-aliases-package: com.flightfeather.monitor.domain.ds1.entity
  mapper-locations: classpath*:mapper/**/*.xml
src/main/resources/mapper/ds1/DustStatisticsValueMapper.xml
@@ -32,9 +32,9 @@
    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,
        ROUND(COUNT(*)/96, 4) as day_online,
        ROUND(SUM(CASE WHEN dust_value >0 THEN 1 ELSE 0 END)/96, 4) as day_valid,
        ROUND(SUM(CASE WHEN dust_value >= 1 THEN 1 ELSE 0 END)/96, 4) as day_exceeding,
    'day' as type
    from ja_t_dust_site_data_info
    where  lst between #{beginTime} and #{endTime}
@@ -51,13 +51,55 @@
    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,
        ROUND(COUNT(*) / #{count}, 4) AS month_online,
        ROUND(SUM(CASE WHEN flag = 'N' OR flag = 'A' THEN 1 ELSE 0 END) / #{count}, 4) AS month_valid,
        ROUND(SUM(CASE WHEN dust_value >= 1 THEN 1 ELSE 0 END) / #{count}, 4) 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>
    <!--    æ ¹æ®ç«™ç‚¹åå­—和时段进行统计分析-->
    <select id="selectByOrder" resultType="com.flightfeather.monitor.pojo.AnalysisDustData">
        select c.name,d.*
        from dust_statistics_value as d
        left join ja_t_dust_site_info as c on c.mn_code = d.mn_code
        <where>
            <if test="siteName != null and siteName != ''">
                and c.name = #{siteName}
            </if>
            <if test="beginTime != null and endTime != null">
                and d.lst between #{beginTime} and #{endTime} and d.type = 'day'
            </if>
        </where>
        <if test="orderProp == 'lst'">
            order by d.lst
        </if>
        <if test="orderProp == 'day_avg'">
            order by d.day_avg
        </if>
        <if test="orderProp == 'min'">
            order by d.min
        </if>
        <if test="orderProp == 'max'">
            order by d.max
        </if>
        <if test="orderProp == 'day_online'">
            order by d.day_online
        </if>
        <if test="orderProp == 'day_valid'">
            order by d.day_valid
        </if>
        <if test="orderProp == 'day_exceeding'">
            order by d.day_exceeding
        </if>
        <if test="orderProp != null and asc">
            asc
        </if>
        <if test="orderProp != null and !asc">
            desc
        </if>
    </select>
</mapper>
src/test/java/com/flightfeather/monitor/analysis/dust/ExceptionAnalysisControllerTest.kt
@@ -27,9 +27,9 @@
    @Test
    fun run() {
        exceptionAnalysisController.init()
        var d1 = LocalDate.of(2023, 10, 26)
        val d2 = LocalDate.of(2023, 10, 26)
        while (Duration.between(d1.atStartOfDay(), d2.atStartOfDay()).toDays() >= 0L) {
        var d1 = LocalDate.of(2023, 7, 1)
        val d2 = LocalDate.of(2023, 11, 21)
        while (d1.isEqual(d2) || d1.isBefore(d2)) {
            exceptionAnalysisController.run(d1)
            d1 = d1.plusDays(1)
        }