1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package cn.flightfeather.supervision.business.autooutput.dataanalysis
 
import cn.flightfeather.supervision.business.autooutput.AopOutput
import cn.flightfeather.supervision.business.autooutput.datasource.AopDataConfig
import cn.flightfeather.supervision.business.autooutput.datasource.AopDataSource
import cn.flightfeather.supervision.business.autooutput.datasource.AopDbMapper
import cn.flightfeather.supervision.business.autooutput.datasource.AopSceneTypeCheck
import cn.flightfeather.supervision.domain.ds1.entity.DustDataResult
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import kotlin.math.round
 
/**
 * 监测数据分析入库
 * 根据每月为一个周期,统计当月的超标次数、均值、最大最小值、超区均值百分比、数据个数、有效率等数据
 */
abstract class AopDataAnalysis<T>(
    private val aopDbMapper: AopDbMapper,
    private val aopSceneTypeCheck: AopSceneTypeCheck,
    private val aopOutput: AopOutput,
) {
 
    /**
     * 统计数据 临时存储结构
     */
    inner class TempResult(
        var total: Double = .0,
        var count: Int = 0,
    ){
        var avg: Double = -1.0
            get() {
                if (field == -1.0) {
                    field = avg()
                }
                return field
            }
 
        private fun avg(): Double {
            return if (count == 0) {
                .0
            } else {
                round((total / count) * 1000) / 1000
            }
        }
    }
 
    //数据源
    private var source: AopDataSource? = null
 
    fun setResource(topTaskGuid: String?, sceneType: Int, year: Int, month: Int) {
        source = AopDataSource(aopDbMapper, aopSceneTypeCheck)
        val st = LocalDateTime.of(year, month, 1, 0, 0, 0)
        val et = st.plusMonths(1).minusSeconds(1)
        val sTime = Date.from(st.atZone(ZoneId.systemDefault()).toInstant())
        val eTime = Date.from(et.atZone(ZoneId.systemDefault()).toInstant())
        val config = AopDataConfig(topTaskGuid = topTaskGuid, sceneType = sceneType, startTime = sTime, endTime = eTime)
        source?.setResource(config)
    }
 
    /**
     * 执行统计逻辑
     */
    fun execute(avg: Double? = null) {
        //计算区均值
        val dAvg = avg ?: districtAvg(source)
        println("均值:${dAvg}")
        //循环处理每个场景
        source?.loop { _, evaluationScene ->
            //获取原始监测数据
            val dataList = fetchDataResources(evaluationScene)
            //计算统计结果
            var tempExceedTimes = TempResult()
            var tempAvg = TempResult()
            var tempMax = TempResult()
            var tempMin = TempResult()
            dataList.forEach {
                // 监测点有多台设备时,每台设备单独统计,取均值最高的为统计结果
                val _tempExceedTimes = TempResult()
                val _tempAvg = TempResult()
                val _tempMax = TempResult()
                val _tempMin = TempResult()
                it.forEach { t ->
                    t?.let {
                        exceedTimes(t, _tempExceedTimes)
                        avg(t, _tempAvg)
                        max(t, _tempMax)
                        min(t, _tempMin)
                    }
                }
                // 保留均值最高的一台设备
                if (_tempAvg.avg > tempAvg.avg) {
                    tempExceedTimes = _tempExceedTimes
                    tempAvg = _tempAvg
                    tempMax = _tempMax
                    tempMin = _tempMin
                }
            }
            val dustDataResult = DustDataResult().apply {
                drSceneId = evaluationScene.scene.value?.guid
                drSceneName = evaluationScene.scene.value?.name
                drTime = source?.config?.startTime
                drExceedTimes = tempExceedTimes.count
                drAvg = tempAvg.avg
                drMax = tempMax.total
                drMin = tempMin.total
                drOverAvgPer = overAvgRate(drAvg, dAvg)
                drDataNum = count(dataList)
                drEffectiveRate = effectiveRate(dataList, evaluationScene)
            }
            //更新入库
            aopOutput.toDbDataResult(dustDataResult)
        }
    }
 
    /**
     * 计算区均值
     * 当前为范围内全部监测点的均值
     */
    abstract fun districtAvg(source: AopDataSource?): Double?
 
    /**
     * 获取原始监测数据
     */
    abstract fun fetchDataResources(evaluationScene: AopDataSource.EvaluationScene): List<List<T?>>
 
    /**
     * 超标次数
     */
    abstract fun exceedTimes(data: T, t: TempResult)
 
    /**
     * 月均值
     */
    abstract fun avg(data: T, t: TempResult)
 
    /**
     * 最大值
     */
    abstract fun max(data: T, t: TempResult)
 
    /**
     * 最小值
     */
    abstract fun min(data: T, t: TempResult)
 
    /**
     * 超月均值百分比
     */
    open fun overAvgRate(avg: Double, dAvg: Double?): Double? {
        return if (dAvg != null && dAvg != .0) {
            round(((avg - dAvg) / dAvg) * 1000) / 1000
        } else {
            .0
        }
    }
 
    /**
     * 数据个数
     */
    open fun count(dataList: List<List<T?>>): Int {
        var count = 0
        dataList.forEach {
            count += it.size
        }
        return count
    }
 
    /**
     * 有效率
     */
    abstract fun effectiveRate(dataList: List<List<T?>>, evaluationScene: AopDataSource.EvaluationScene): Double
}