feiyu02
2025-09-04 707b00a0ca6604c249a110b376ac1e44e408e624
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
package com.flightfeather.uav.biz.report
 
import com.flightfeather.uav.biz.sourcetrace.model.PollutedClue
import com.flightfeather.uav.domain.entity.Mission
import com.flightfeather.uav.domain.repository.MissionRep
import com.flightfeather.uav.lightshare.bean.AreaVo
import com.flightfeather.uav.socket.eunm.FactorType
import com.flightfeather.uav.socket.sender.MsgType
import org.springframework.stereotype.Component
import java.util.*
import kotlin.math.round
 
/**
 * 走航任务汇总
 * @date 2025/8/22
 * @author feiyu02
 */
class MissionSummary() {
 
    data class Summary(
        // 汇总周期开始时间
        val startTime: Date,
        // 汇总周期结束时间
        val endTime: Date,
        // 走航区域信息
        val area: AreaVo,
        // 走航次数
        val count: Int,
        // 总里程数(公里)
        val kilometres: Double,
        // 涉及区域
        val regionList: List<String>,
        // 各等级空气质量背景走航次数,<空气质量等级,次数,占比>
        val countByDegree: List<Triple<String, Int, Double>>,
        // 问题总数
        val probCount:Int,
        // 高风险场景总数
        val highRiskSceneCount:Int,
        // 问题按监测因子类型分布情况, <因子类型,次数,占比>
        val probByFactor:List<Triple<String, Int, Double>>
    )
 
    /**
     * 根据时间范围查询走航任务并生成统计结果
     * @param startTime 统计开始时间
     * @param endTime 统计结束时间
     * @param missions 走航任务列表(外部传入,避免重复查询)
     * @param clues 污染线索列表(用于问题统计)
     * @return 走航任务统计结果Summary
     */
    fun execute(startTime: Date, endTime: Date, missions: List<Mission?>, clues: List<PollutedClue?>): Summary {
        // 1. 查询指定时间范围内的走航任务
        if (missions.isEmpty()) {
            return Summary(
                startTime = startTime,
                endTime = endTime,
                area = AreaVo(), // 空任务时返回默认区域信息
                count = 0,
                kilometres = 0.0,
                regionList = emptyList(),
                countByDegree = emptyList(),
                probCount = 0,
                highRiskSceneCount = 0,
                probByFactor = emptyList()
            )
        }
 
        // 2. 基础统计:总任务数、总里程
        val totalCount = missions.size
        val totalKilometres = missions.sumOf { it?.kilometres?.toDouble() ?: 0.0 }
 
        // 3. 区域信息:取首个任务的行政区划信息(如存在多区域可扩展为合并逻辑)
        val firstMission = missions.first()
        val area = AreaVo().apply {
            provinceCode = firstMission?.provinceCode
            provinceName = firstMission?.provinceName
            cityCode = firstMission?.cityCode
            cityName = firstMission?.cityName
            districtCode = firstMission?.districtCode
            districtName = firstMission?.districtName
            townCode = firstMission?.townCode
            townName = firstMission?.townName
        }
 
        // 4. 涉及区域列表:去重收集所有任务的region字段
        val regionList = missions.mapNotNull { it?.region }.distinct()
 
        // 5. 空气质量等级分布:按pollutionDegree分组统计次数及占比
        val degreeGroups = missions
            .filter { it?.pollutionDegree != null } // 过滤无效等级
            .groupBy { it?.pollutionDegree!! }
            .mapValues { it.value.size }
        val countByDegree = degreeGroups.map { (degree, count) ->
            Triple(degree, count, count.toDouble() / totalCount)
        }
 
        // 6. 问题相关统计
        val clueRes = calClue(clues)
        val probCount = clueRes.first // 需关联问题表统计
        val highRiskSceneCount = clueRes.second // 需关联场景表统计
        val probByFactor = clueRes.third
 
        // 7. 构建并返回统计结果
        return Summary(
            startTime = startTime,
            endTime = endTime,
            area = area,
            count = totalCount,
            kilometres = totalKilometres,
            regionList = regionList,
            countByDegree = countByDegree,
            probCount = probCount,
            highRiskSceneCount = highRiskSceneCount,
            probByFactor = probByFactor
        )
    }
 
    private fun calClue(clues: List<PollutedClue?>): Triple<Int, Int, List<Triple<String, Int, Double>>> {
        var probCount = 0
        var highRiskSceneCount = 0
        val probByFactorMap = mutableMapOf<FactorType, Int>()
        clues.forEach { c ->
            if (c?.msgType == MsgType.PolClue.value) {
                c.pollutedSource?.sceneList?.size?.let { s -> highRiskSceneCount += s }
                c.pollutedData?.statisticMap?.keys?.forEach { k ->
                    probCount++
                    if (!probByFactorMap.containsKey(k)) {
                        probByFactorMap[k] = 0
                    }
                    probByFactorMap[k] = probByFactorMap[k]!! + 1
                }
            }
        }
        val probByFactor = probByFactorMap.entries.map {
            val per = if(probCount == 0) .0 else round(it.value.toDouble() / probCount * 100) / 100
            Triple(it.key.des, it.value, per)
        }
        return Triple(probCount, highRiskSceneCount, probByFactor)
    }
}