feiyu02
7 天以前 594de76ed51fd49fb79b912212bb0052a63e7671
2026.4.9
已修改19个文件
127 ■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedData.kt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/exception/BizException.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/repository/SourceTraceRep.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/repository/impl/AirDataRepImpl.kt 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/bean/DataVo.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/DataAnalysisService.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImpl.kt 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/MissionServiceImpl.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImpl.kt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/BaseResPack.kt 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/DataAnalysisController.kt 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/epw/EPWDataPrep.kt 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-pro.yml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceControllerTest.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/common/net/ShenXinServiceTest.kt 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImplTest.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/MissionServiceImplTest.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/sourcetrace/model/PollutedData.kt
@@ -203,7 +203,9 @@
                excGroup = exceptionDataGroup().map { ExcGroup(it, e.first.main) }
                avgPer = excGroup?.mapNotNull { it.per }?.average()
                if (avgPer?.isNaN() == true) avgPer = .0
                avgRate = excGroup?.mapNotNull { it.rate }?.average()
                if (avgRate?.isNaN() == true) avgRate = .0
            }
        }
    }
src/main/kotlin/com/flightfeather/uav/common/exception/BizException.kt
@@ -3,7 +3,7 @@
/**
 * 允许接口返回的业务层面的错误
 */
class BizException : Exception {
class BizException : RuntimeException {
    constructor():super()
    constructor(message: String) : super(message)
    constructor(message: String, cause: Throwable?) : super(message, cause)
src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt
@@ -105,6 +105,10 @@
        return gridDataMapper.insert(gridData)
    }
    fun updateGridData(gridData: GridData): Int {
        return gridDataMapper.updateByPrimaryKey(gridData)
    }
    fun insertGridDataDetail(gridDataDetails: List<GridDataDetail?>): Int {
        return gridDataDetailMapper.insertList(gridDataDetails)
    }
src/main/kotlin/com/flightfeather/uav/domain/repository/SourceTraceRep.kt
@@ -133,7 +133,8 @@
                    else -> null
                }
            }
            stMsgCache[key] = stMsgList
            // Fixme 2026.1.21 溯源记录的缓存逻辑暂缺失,此处处理不恰当
//            stMsgCache[key] = stMsgList
        }
        // 筛选出异常数据PollutedClue中异常百分比大于minPer的
        return stMsgList.filter {
src/main/kotlin/com/flightfeather/uav/domain/repository/impl/AirDataRepImpl.kt
@@ -35,11 +35,11 @@
    private val tmpVehicleDataList = mutableListOf<BaseRealTimeData>()
    // 走航监测校准系数
    private val calibrationMap = mutableMapOf<String, MutableMap<Int, Float>>()
    private val calibrationMap = mutableMapOf<String?, MutableMap<Int, Float>>()
    // 走航监测校准系数更新时间
    private var cUpdateTime = LocalDateTime.now()
    // 走航监测校准系数更新时间间隔(分钟)
    private val cInterval = 5L
    private val cInterval = 1L
    override fun saveAirData(dataPackage: AirDataPackage): Int {
        val data = RealTimeData().apply {
@@ -135,7 +135,7 @@
                    val d = vo.toBaseRealTimeData(RealTimeDataVehicle::class.java)
                    /***************************************************************************************************/
                    // FIXME: 2021/10/27 车载监测部分因子量级调整
                    calibration(d, UWDeviceType.VEHICLE)
                    calibration(d, d.deviceCode)
                    /***************************************************************************************************/
                    realTimeDataVehicleMapper.insert(d)
                    res.add(d)
@@ -267,20 +267,20 @@
        }
    }
    private fun calibration(data: BaseRealTimeData, type: UWDeviceType) {
    private fun calibration(data: BaseRealTimeData, deviceCode: String?) {
        //1. 校准系数按照一定时间间隔进行刷新
        val now = LocalDateTime.now()
        if (calibrationMap.isEmpty() || now.minusMinutes(cInterval).isAfter(cUpdateTime)) {
        if (calibrationMap[deviceCode].isNullOrEmpty() || now.minusMinutes(cInterval).isAfter(cUpdateTime)) {
            cUpdateTime = now
            calibrationMap[type.value] = mutableMapOf()
            calibrationMap[deviceCode] = mutableMapOf()
            factorCalibrationMapper.selectByExample(Example(FactorCalibration::class.java).apply {
                createCriteria().andEqualTo("deviceType", type.value)
                createCriteria().andEqualTo("deviceType", deviceCode)
            }).forEach {
                calibrationMap[type.value]?.put(it.factorId, it.factorScale)
                calibrationMap[deviceCode]?.put(it.factorId, it.factorScale)
            }
        }
        //2. 根据校准系数计算
        calibrationMap[type.value]?.let{
        calibrationMap[deviceCode]?.let {
            data.voc = data.voc?.times(it[FactorType.VOC.value] ?: 1f)
            data.co = data.co?.times(it[FactorType.CO.value] ?: 1f)
            data.pm25 = data.pm25?.times(it[FactorType.PM25.value] ?: 1f)
src/main/kotlin/com/flightfeather/uav/lightshare/bean/DataVo.kt
@@ -35,6 +35,15 @@
        return null
    }
    fun setFactorData(type: FactorType, value: Double?) {
        if (values == null) throw IllegalStateException(this.javaClass.name + ": 监测数据数组为null")
        for (d in values!!) {
            if (d.factorName == type.name) {
                d.factorData = value
            }
        }
    }
    fun toRowContent(): Array<Any> {
        val row = mutableListOf<Any>()
        row.add(deviceCode ?: "")
src/main/kotlin/com/flightfeather/uav/lightshare/service/DataAnalysisService.kt
@@ -12,6 +12,7 @@
import com.flightfeather.uav.domain.entity.Mission
import com.flightfeather.uav.domain.entity.SceneInfo
import com.flightfeather.uav.lightshare.bean.AreaVo
import com.flightfeather.uav.lightshare.bean.DataHead
import com.flightfeather.uav.lightshare.bean.GridDataDetailMixVo
import com.flightfeather.uav.lightshare.eunm.PollutionDegree
import com.flightfeather.uav.socket.eunm.FactorType
@@ -42,7 +43,7 @@
     * @param minPer 最小污染百分比,用于筛选异常数据点(可选)
     * @return 历史污染溯源结果的字符串表示(具体格式需参考实现类)
     */
    fun fetchHistory(missionCode: String, minPer: Double?): String
    fun fetchHistory(missionCode: String, minPer: Double?, page: Int?, perPage: Int?): Pair<DataHead, String>
    /**
     * 生成走航任务汇总统计
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImpl.kt
@@ -15,13 +15,16 @@
import com.flightfeather.uav.domain.mapper.MissionMapper
import com.flightfeather.uav.domain.repository.*
import com.flightfeather.uav.lightshare.bean.AreaVo
import com.flightfeather.uav.lightshare.bean.DataHead
import com.flightfeather.uav.lightshare.bean.GridDataDetailMixVo
import com.flightfeather.uav.lightshare.bean.SourceTraceMsgVo
import com.flightfeather.uav.lightshare.eunm.PollutionDegree
import com.flightfeather.uav.lightshare.eunm.SceneType
import com.flightfeather.uav.lightshare.service.DataAnalysisService
import com.flightfeather.uav.lightshare.service.SatelliteDataCalculateService
import com.flightfeather.uav.socket.eunm.FactorType
import com.flightfeather.uav.socket.sender.MsgType
import com.github.pagehelper.PageHelper
import org.springframework.stereotype.Service
import java.util.*
@@ -81,11 +84,15 @@
     * @return 历史污染溯源结果的JSON字符串,具体格式由sourceTraceRep实现决定
     * @throws BizException 当走航任务不存在时抛出
     */
    override fun fetchHistory(missionCode: String, minPer: Double?): String {
    override fun fetchHistory(missionCode: String, minPer: Double?, page: Int?, perPage: Int?): Pair<DataHead, String> {
        val mission = missionRep.findOne(missionCode) ?: throw BizException("走航任务不存在")
        val p = if (page != null && perPage != null) {
            PageHelper.startPage<SourceTraceMsgVo>(page, perPage)
        } else {
            null
        }
        val res = sourceTraceRep.fetchList(mission.deviceCode, mission.startTime, mission.endTime, minPer = minPer ?: 0.5)
        return GsonUtils.gson.toJson(res)
        return DataHead(p?.pageNum ?: 1, p?.pages ?: 1) to GsonUtils.gson.toJson(res)
    }
    /**
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/MissionServiceImpl.kt
@@ -94,7 +94,7 @@
        val data = realTimeDataRep.fetchData(mission)
        mission.kilometres = MissionUtil.calKilometres(data).toFloat()
        // todo: 计算走航任务所在中心区域
//        mission.region = MissionUtil.calRegion(data)
        mission.region = MissionUtil.calRegion(data)
        return updateMission(mission)
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImpl.kt
@@ -142,6 +142,7 @@
        // 查询走航任务及对应走航监测数据
        val mission = missionRep.findOne(missionCode) ?: throw BizException("任务不存在")
        val data = realTimeDataRep.fetchData(mission)
        if (data.isEmpty()) throw BizException("没有走航数据,无法生成走航网格")
        // 查找是否已有走航融合记录
        val oldGridDataList = satelliteGridRep.fetchGridData(GridData().apply {
@@ -184,6 +185,7 @@
            return gridDataDetailList
        } else {
            satelliteGridRep.updateGridData(gridData)
            val oldGridData = oldGridDataList.first()
            val oldGridDataDetailList = satelliteGridRep.fetchGridDataDetail(oldGridData?.id, oldGridData?.groupId)
            // 查询网格单元格信息
src/main/kotlin/com/flightfeather/uav/lightshare/web/BaseResPack.kt
@@ -23,5 +23,8 @@
        }
    } catch (e: BizException) {
        BaseResponse(false, message = e.message ?: "")
    } catch (e: Exception) {
        e.printStackTrace()
        BaseResponse(false, message = e.message ?: "服务器出现内部错误")
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/web/DataAnalysisController.kt
@@ -33,7 +33,9 @@
    fun fetchHistory(
        @ApiParam("走航任务编号") @RequestParam missionCode: String,
        @ApiParam("最小污染百分比,用于筛选异常数据点(可选)") @RequestParam(required = false) minPer: Double? = null,
    ) = resPack { dataAnalysisService.fetchHistory(missionCode, minPer) }
        @RequestParam(value = "page", required = false) page: Int?,
        @RequestParam(value = "perPage", required = false) perPage: Int?,
    ) = resPack { dataAnalysisService.fetchHistory(missionCode, minPer, page, perPage) }
    @ApiOperation(value = "生成走航任务汇总统计")
    @PostMapping("/report/missionSummary")
src/main/kotlin/com/flightfeather/uav/model/epw/EPWDataPrep.kt
@@ -12,6 +12,7 @@
import kotlin.math.min
import kotlin.math.round
import kotlin.math.sqrt
import kotlin.time.times
/**
 * 数据平滑预处理
@@ -148,6 +149,7 @@
            i = 0
        }
        while (i < mDataList.size) {
            // 针对每个监测因子,分别做数据平滑处理
            for (y in mDataList[i].values?.indices ?: 0..0) {
                val it = mDataList[i].values?.get(y) ?: continue
                val vMax = FactorType.getVMin(it.factorName) ?: continue
@@ -192,6 +194,29 @@
                }
            }
            // 根据物理规律,剔除或修正不合理的数据
            val data = mDataList[i]
            // 1. PM2.5 应该始终小于PM10
            val pm25 = data.getFactorData(FactorType.PM25)
            val pm10 = data.getFactorData(FactorType.PM10)
            if (pm25 != null && pm10 != null) {
                // 若pm2.5大于pm10
                if (pm25 >= pm10){
                    val lastIndex = i - 1
                    // 则将pm2.5修改为前一个数据的值
                    if (lastIndex >= 0) {
                        data.setFactorData(FactorType.PM25, mDataList[lastIndex].getFactorData(FactorType.PM25))
                    } else {
                        if (lastData.isEmpty()) {
                            // 没有历史数据时,修改为pm10的80%(后续待优化比例 2026.3.6)
                            data.setFactorData(FactorType.PM25, data.getFactorData(FactorType.PM10)?.times(.8))
                        } else {
                            data.setFactorData(FactorType.PM25, lastData.last().getFactorData(FactorType.PM25))
                        }
                    }
                }
            }
            i++
        }
src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt
@@ -72,6 +72,8 @@
    fun saveToDataBase(dataPackage: AirDataPackage): List<BaseRealTimeData>? {
        when (dataPackage.commandUnit) {
            AirCommandUnit.AirData.value -> {
                // 存储前判断数据是否有效
                if (!isValid(dataPackage)) return null
                // 以json格式存储原始数据
                airDataRep.saveAirData(dataPackage)
                // 进行预处理后,存储至对应数据表
@@ -145,4 +147,13 @@
        return sb.toString()
    }
    /**
     * 数据有效性判断
     */
    private fun isValid(dataPackage: AirDataPackage): Boolean {
        if (dataPackage.dataTime == null) return false
        val check1 = dataPackage.dataTime!!.time < Date().time
        return check1
    }
}
src/main/resources/application-pro.yml
@@ -1,15 +1,15 @@
spring:
  datasource:
    #    线上服务器 47
#    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
#    username: dronemonitor
#    password: dronemonitor_hackxrnomxm
    #    线上服务器 114
    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: dronemonitor
    password: dronemonitor_hackxrnomxm
    #    线上服务器 114
#    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
#    username: dronemonitor
#    password: dronemonitor_hackxrnomxm
springfox:
  documentation:
    swagger:
src/test/kotlin/com/flightfeather/uav/biz/sourcetrace/SourceTraceControllerTest.kt
@@ -39,7 +39,7 @@
    @Test
    fun autoSourceTrace() {
        val sourceTraceController = SourceTraceController(sceneInfoRep, sourceTraceRep, true)
        val startTime = LocalDateTime.of(2025, 11, 19, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant()
        val startTime = LocalDateTime.of(2025, 10, 1, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant()
//        val endTime = LocalDateTime.of(2025, 11, 19, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant()
//        val startTime = LocalDateTime.of(2025, 11, 1, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant()
        val endTime = LocalDateTime.of(2025, 12, 31, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant()
@@ -67,7 +67,7 @@
    @Test
    fun deleteSourceTrace() {
        val startTime = LocalDateTime.of(2025, 11, 19, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant()
        val startTime = LocalDateTime.of(2025, 12, 18, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant()
//        val endTime = LocalDateTime.of(2025, 11, 19, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant()
//        val startTime = LocalDateTime.of(2025, 11, 1, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant()
        val endTime = LocalDateTime.of(2025, 12, 31, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant()
src/test/kotlin/com/flightfeather/uav/common/net/ShenXinServiceTest.kt
@@ -12,15 +12,15 @@
    @Test
    fun fetchData() {
        val mission = Mission().apply {
            missionCode = "SHJA-20240813"
            missionCode = "20260119"
            deviceType = "0a"
            deviceCode = "TX105"
            startTime = Date.from(LocalDateTime.of(2024, 8, 13, 11, 30, 0, 0).atZone(ZoneId.systemDefault())
            startTime = Date.from(LocalDateTime.of(2026, 1, 19, 8, 30, 0, 0).atZone(ZoneId.systemDefault())
                .toInstant())
            endTime = Date.from(LocalDateTime.of(2024, 8, 13, 17, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant())
            endTime = Date.from(LocalDateTime.of(2026, 1, 19, 16, 30, 0, 0).atZone(ZoneId.systemDefault()).toInstant())
            districtName = "静安区"
        }
        val date = LocalDateTime.of(2024, 8, 13, 15, 43, 0, 0)
        val date = LocalDateTime.of(2026, 1, 19, 14, 0, 0, 0)
        val res = ShenXinService.fetchData(mission, date)
        println(res)
    }
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/DataAnalysisServiceImplTest.kt
@@ -34,7 +34,7 @@
    @Test
    fun fetchHistory() {
        dataAnalysisService.fetchHistory("SH-CN-20250723(01)", .0)
        dataAnalysisService.fetchHistory("SH-CN-20260121", .0, 1, 10000)
    }
    @Test
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/MissionServiceImplTest.kt
@@ -34,7 +34,7 @@
    @Test
    fun calMissionInfo() {
        missionMapper.selectByExample(Example(Mission::class.java).apply {
            createCriteria().andBetween("startTime", "2025-12-11 00:00:00", "2025-12-11 23:59:59")
            createCriteria().andBetween("startTime", "2026-01-29 00:00:00", "2026-12-31 23:59:59")
        }).forEach {mission ->
            mission?.let { missionService.calMissionInfo(it.missionCode) }
            Thread.sleep(1000)