feiyu02
2025-03-27 bde043c8fd1a076f44c402dd56c62d401afbfb16
1. 新增卫星遥测网格热力图计算逻辑
已修改19个文件
已添加1个文件
1065 ■■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/biz/satellite/GridGroupOption.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridUtil.kt 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/TimeUtil.kt 156 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt 178 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java 303 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteDataCalculateService.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImpl.kt 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/BaseModel.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/BaseNoSection.kt 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/BaseSOP.kt 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/epw/NoSection.kt 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/underwaygrid/GridCellAndData.kt 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/underwaygrid/GridCellSop.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/model/underwaygrid/UnderwayGridModel.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generator/generatorConfig.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/GridDataMapper.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/Test.kt 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImplTest.kt 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/biz/satellite/GridGroupOption.kt
@@ -11,7 +11,7 @@
    // ç½‘格高度,指南北方向上的网格数量
    val height: Int,
    // ç»†åˆ†ç½‘格宽度,如果网格组是细分网格,则表示对应原始网格中单个网格下细分的网格数量
    val eachWith: Int,
    val eachWidth: Int,
    // ç»†åˆ†ç½‘格高度,如果网格组是细分网格,则表示对应原始网格中单个网格下细分的网格数量
    val eachHeight: Int,
)
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridManage.kt
@@ -2,6 +2,10 @@
import com.flightfeather.uav.common.utils.MapUtil
import com.flightfeather.uav.domain.entity.*
import com.flightfeather.uav.model.underwaygrid.GridCellAndData
import com.flightfeather.uav.model.underwaygrid.GridCellSop
import com.flightfeather.uav.model.underwaygrid.UnderwayGridModel
import com.flightfeather.uav.socket.eunm.FactorType
import org.springframework.beans.BeanUtils
import kotlin.math.PI
import kotlin.math.sqrt
@@ -258,20 +262,6 @@
                dataId = gridData?.id
                groupId = k.groupId
                cellId = k.cellIndex
//                no2 = avgData.no2
//                co = avgData.co
//                h2s = avgData.h2s
//                so2 = avgData.so2
//                o3 = avgData.o3
//                pm25 = avgData.pm25
//                pm10 = avgData.pm10
//                temperature = avgData.temperature
//                humidity = avgData.humidity
//                voc = avgData.voc
//                noi = avgData.noi
//                no = avgData.no
//                windSpeed
//                windDirection
                rank
            }
            gridDataDetailList.add(dataDetail)
@@ -286,6 +276,58 @@
        return gridDataDetailList
    }
    /**
     * è®¡ç®—热力图网格,即网格周边扩散影响权重计算
     * @param gridDataDetail ç½‘格监测数据
     * @param gridCellList åŒºåŸŸç½‘格数组
     * @param option åŒºåŸŸç½‘格参数信息
     * @param searchLength è®¡ç®—周边八方向(上下左右及四个对角)网格的长度
     * @return å‘¨è¾¹ç½‘格及对应的监测数据结果
     */
    fun heatMap(
        gridDataDetail: GridDataDetail, gridCellList: List<GridCell?>,
        option: GridGroupOption, searchLength: Int,
    ): List<GridDataDetail> {
        // æ‰¾åˆ°ç½‘格数据对应的网格信息
        val gridCell = gridCellList.find { it?.cellIndex == gridDataDetail.cellId }
            ?: throw IllegalArgumentException("网格数据和给定的区域网格不匹配")
        // èŽ·å–å‘¨è¾¹ç½‘æ ¼
        val surroundGridCellList =
            SatelliteGridUtil.searchDiffuseGrid(gridDataDetail.cellId, gridCellList, option, searchLength)
        // ä½¿ç”¨èµ°èˆªç½‘格权重模型,计算周边网格的监测数据值
        val underwayGridModel = UnderwayGridModel()
        val dataList = listOf(GridCellAndData(gridCell, gridDataDetail))
        val gridCellSopList = surroundGridCellList.map {
            GridCellSop(
                it,
                it.id.toString(),
                it.cellIndex.toString(),
                it.cellIndex.toString()
            ) }
        underwayGridModel.execute(dataList, gridCellSopList)
        val resMap = underwayGridModel.outputResult()
        // æ ¼å¼åŒ–结果并返回
        val result = mutableListOf<GridDataDetail>()
        gridCellSopList.forEach {
            val resGridDataDetail = GridDataDetail().apply {
                dataId = gridDataDetail.dataId
                groupId = gridDataDetail.groupId
                cellId = it.gridCell.cellIndex
            }
            val key = "${it.sourceName};${it.index}"
            val d = resMap[key]
            d?.forEach { (t, u) ->
                val avg = u["综合(${t})"]?.average ?: .0
                resGridDataDetail.setFactorValue(FactorType.getByName(t), avg.toFloat())
            }
            result.add(resGridDataDetail)
        }
        return result
    }
}
src/main/kotlin/com/flightfeather/uav/biz/satellite/SatelliteGridUtil.kt
@@ -3,6 +3,7 @@
import com.flightfeather.uav.common.utils.MapUtil
import com.flightfeather.uav.domain.entity.GridCell
import kotlin.math.ceil
import kotlin.math.floor
/**
 * å«æ˜Ÿç½‘格计算工具
@@ -49,26 +50,118 @@
        option: GridGroupOption,
        searchLength: Int,
    ): List<GridCell> {
        return emptyList()
        val hOffset = option.eachWidth;
        val wOffset = 1;
        val cellIdMin = 1
        val cellIdMax = option.width * option.height
        val searchWidth = 0 - searchLength
        val searchHeight = 0 - searchLength
        val result = mutableListOf<GridCell>()
        val eachRange = getCellWidthRange(gridCellIndex, option.eachWidth, option.eachHeight)?: return emptyList()
        val groupRange = getCellWidthRange(
            ceil(gridCellIndex.toDouble() / (option.eachWidth * option.eachHeight)).toInt(),
            option.width / option.eachWidth,
            option.height / option.eachHeight
        ) ?: return emptyList()
        for (w in searchWidth..searchLength) {
            // å…ˆè¿›è¡Œæ¨ªå‘的坐标变换
            var _cellId = gridCellIndex + w * wOffset;
            if (_cellId < eachRange.first || _cellId > eachRange.second) {
                val cellOffset = if (_cellId < eachRange.first) _cellId - eachRange.first else _cellId - eachRange.second
                val groupOffset = if (cellOffset / option.eachWidth > 0) {
                    ceil(cellOffset.toDouble() / option.eachWidth).toInt()
                } else {
                    floor(cellOffset.toDouble() / option.eachWidth).toInt()
                }
                val newEachRange =
                    (eachRange.first + groupOffset * option.eachWidth * option.eachHeight) to
                            (eachRange.second + groupOffset * option.eachWidth * option.eachHeight)
                _cellId = if (groupOffset > 0) {
                    newEachRange.first + cellOffset - wOffset
                } else {
                    newEachRange.second + cellOffset + wOffset;
                }
                val _groupId = ceil(_cellId.toDouble() / (option.eachWidth * option.eachHeight)).toInt()
                if (_groupId < groupRange.first || _groupId > groupRange.second) {
                    continue;
                }
            }
            for (h in searchHeight..searchLength) {
                if (w == 0 && h == 0) continue;
                val _eachRange = getCellWidthRange(_cellId, option.eachWidth, option.eachHeight) ?: return emptyList()
                val wOffset = _cellId - _eachRange.first;
                var _resCellId = _cellId + h * hOffset;
                if (_resCellId < cellIdMin || _resCellId > cellIdMax) continue;
                val total = option.eachWidth * option.eachHeight;
                val x = ceil(_cellId.toDouble() / total).toInt() - 1;
                val eachCellIdMin = 1 + x * total;
                val eachCellIdMax = total + x * total;
                val topCell = eachCellIdMin + wOffset;
                val bottomCell = eachCellIdMax - option.eachWidth + 1 + wOffset;
                if (_resCellId < eachCellIdMin || _resCellId > eachCellIdMax) {
                    val cellOffset = if (_resCellId < eachCellIdMin) {
                        _resCellId - topCell
                    } else {
                        _resCellId - bottomCell;
                    }
                    val newTopCell = if (cellOffset > 0) {
                        topCell + option.width * option.eachHeight
                    } else {
                        topCell - option.width * option.eachHeight;
                    }
                    val newBottomCell = if (cellOffset > 0) {
                        bottomCell + option.width * option.eachHeight
                    } else {
                        bottomCell - option.width * option.eachHeight;
                    }
                    _resCellId = if (cellOffset > 0) {
                        newTopCell + cellOffset - hOffset
                    } else {
                        newBottomCell + cellOffset + hOffset;
                    }
                }
                gridCellList.find { it?.cellIndex == _resCellId }?.let { result.add(it) }
            }
        }
        return result;
    }
    /**
     * Fixme 2025.3.14: å‘¨è¾¹ç½‘格的查找,后续通过将网格用坐标点的表示方式来直接计算(x, y)
     * æ ¹æ®ç½‘格索引,获取其所在东西方向的网格索引范围
     * @param cellIndex ç½‘格索引
     * @param width ç½‘格宽度,指东西方向上的网格数量
     * @param height ç½‘格高度,指南北方向上的网格数量
     * @return è¿”回网格索引值范围
     */
    fun getCellWidthRange(cellIndex: Int, width: Int, height: Int): Pair<Double, Double>? {
    fun getCellWidthRange(cellIndex: Int, width: Int, height: Int): Pair<Int, Int>? {
        val total = width * height;
        val x = ceil(cellIndex.toDouble() / total) - 1;
        val x = (ceil(cellIndex.toDouble() / total) - 1).toInt()
        val first = 1 + x * total
        val last = width + x * total;
        var scale = 0;
        while (scale < height) {
            val min = first + scale * width;
            val max = last + scale * width;
            if (cellIndex >= min && cellIndex <= max) {
            if (cellIndex in min..max) {
                return min to max
            }
            scale++;
src/main/kotlin/com/flightfeather/uav/common/utils/TimeUtil.kt
@@ -1,34 +1,152 @@
package com.flightfeather.uav.common.utils
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.time.Duration
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import kotlin.math.max
import kotlin.math.min
/**
 * @author riku
 * Date: 2019/9/16
 */
class TimeUtil {
object TimeUtil {
    companion object {
        /**
         * æ˜¯å¦æ˜¯ç¬¬äºŒå¤©æˆ–更新的时间
         */
        fun isNextDay(oldTime: Date, newTime: Date): Boolean {
            val oldC = Calendar.getInstance().apply {
                time = oldTime
            }
            val newC = Calendar.getInstance().apply {
                time = newTime
            }
    /**
     * æ˜¯å¦æ˜¯ç¬¬äºŒå¤©æˆ–更新的时间
     */
    fun isNextDay(oldTime: Date, newTime: Date): Boolean {
        val oldC = Calendar.getInstance().apply {
            time = oldTime
        }
        val newC = Calendar.getInstance().apply {
            time = newTime
        }
            return when {
                newC[Calendar.YEAR] > oldC[Calendar.YEAR] -> true
                newC[Calendar.YEAR] == oldC[Calendar.YEAR] -> newC[Calendar.DAY_OF_YEAR] > oldC[Calendar.DAY_OF_YEAR]
                else -> false
            }
        return when {
            newC[Calendar.YEAR] > oldC[Calendar.YEAR] -> true
            newC[Calendar.YEAR] == oldC[Calendar.YEAR] -> newC[Calendar.DAY_OF_YEAR] > oldC[Calendar.DAY_OF_YEAR]
            else -> false
        }
    }
    /**
     * èŽ·å–æŸæ®µæ—¶é—´åœ¨æ¯æ—¥ä¸­çš„æ—¶æ®µ
     * "凌晨 0 - 6", "早上 6 - 9", "上午 9 - 12", "中午 12 - 14", "下午 14 - 17", "傍晚 17 - 20", "夜间 20 - 0"
     * å½“这段时间跨越了时段时,按照60%的时间所在时段为最终时段,否则采用后一个时段
     * @return æ—¶æ®µå’Œæ—¶æ®µçš„起止时间 <时段, å¼€å§‹æ—¶é—´, ç»“束时间>
     */
    fun getDayTimeTag(start: Date, end: Date): Triple<String, Date, Date>? {
        var sLocal = LocalDateTime.ofInstant(start.toInstant(), ZoneId.systemDefault())
        var eLocal = LocalDateTime.ofInstant(end.toInstant(), ZoneId.systemDefault())
        val duration = Duration.between(sLocal, eLocal)
        if (duration.toDays() > 1) return null
        if (duration.isNegative) {
            val temp = sLocal
            sLocal = eLocal
            eLocal = temp
        }
        val sDay = sLocal.dayOfMonth
        val eDay = eLocal.dayOfMonth
        val ranges = listOf(
            Triple(0, 6, "凌晨"), Triple(6, 9, "早上"),
            Triple(9, 12, "上午"), Triple(12, 14, "中午"),
            Triple(14, 17, "下午"), Triple(17, 20, "傍晚"), Triple(20, 24, "夜间")
        )
        val periodList = mutableListOf<Pair<Triple<String, Date, Date>, Long>>()
        if (sDay < eDay) {
            val dayStart = sLocal.plusDays(1).withHour(0).withMinute(0).withSecond(0)
            val firstRange = sLocal to dayStart
            val secondRange = dayStart to eLocal
            ranges.forEachIndexed { i, r ->
                // åˆ¤æ–­æ—¶é—´èŒƒå›´æ˜¯å¦å’Œè¯¥æ—¶æ®µæœ‰äº¤é›†
                checkPeriodTime(firstRange.first, firstRange.second, r.first to r.second)?.let {
                    val t = firstRange.first.withMinute(0).withSecond(0)
                    periodList.add(
                        Triple(
                            r.third,
                            Date.from(t.withHour(r.first).atZone(ZoneId.systemDefault()).toInstant()),
                            if (r.second == 24) {
                                Date.from(
                                    t.withHour(0).plusDays(1).minusSeconds(1)
                                        .atZone(ZoneId.systemDefault()).toInstant()
                                )
                            } else {
                                Date.from(t.withHour(r.second).atZone(ZoneId.systemDefault()).toInstant())
                            }
                        ) to it.toMinutes()
                    )
                }
                checkPeriodTime(secondRange.first, secondRange.second, r.first to r.second)?.let {
                    val t = secondRange.first.withMinute(0).withSecond(0)
                    periodList.add(
                        Triple(
                            r.third,
                            Date.from(t.withHour(r.first).atZone(ZoneId.systemDefault()).toInstant()),
                            if (r.second == 24) {
                                Date.from(
                                    t.withHour(0).plusDays(1).minusSeconds(1)
                                        .atZone(ZoneId.systemDefault()).toInstant()
                                )
                            } else {
                                Date.from(t.withHour(r.second).atZone(ZoneId.systemDefault()).toInstant())
                            }
                        ) to it.toMinutes()
                    )
                }
            }
        } else {
            val range = sLocal to eLocal
            ranges.forEachIndexed { i, r ->
                // åˆ¤æ–­æ—¶é—´èŒƒå›´æ˜¯å¦å’Œè¯¥æ—¶æ®µæœ‰äº¤é›†
                checkPeriodTime(range.first, range.second, r.first to r.second)?.let {
                    val t = range.first.withMinute(0).withSecond(0)
                    periodList.add(
                        Triple(
                            r.third,
                            Date.from(t.withHour(r.first).atZone(ZoneId.systemDefault()).toInstant()),
                            if (r.second == 24) {
                                Date.from(
                                    t.withHour(0).plusDays(1).minusSeconds(1)
                                        .atZone(ZoneId.systemDefault()).toInstant()
                                )
                            } else {
                                Date.from(t.withHour(r.second).atZone(ZoneId.systemDefault()).toInstant())
                            }
                        ) to it.toMinutes()
                    )
                }
            }
        }
        if (periodList.isEmpty()) return null
        periodList.sortByDescending { it.second }
        val maxOne = periodList.first()
        return maxOne.first
    }
    private fun checkPeriodTime(start: LocalDateTime, end: LocalDateTime, hourRange: Pair<Int, Int>): Duration? {
        return if (start.hour in hourRange.first..hourRange.second) {
            Duration.between(
                start,
                end.withHour(min(hourRange.second, end.hour)).withMinute(0).withSecond(0)
            )
        } else if (start.hour < hourRange.first && end.hour > hourRange.second) {
            Duration.between(
                start.withHour(hourRange.first).withMinute(0).withSecond(0),
                end.withHour(hourRange.second).withMinute(0).withSecond(0),
            )
        } else if (end.hour in hourRange.first..hourRange.second) {
            Duration.between(
                start.withHour(max(hourRange.first, start.hour)).withMinute(0).withSecond(0),
                end,
            )
        } else {
            null
        }
    }
}
src/main/kotlin/com/flightfeather/uav/domain/entity/ExpandFun.kt
@@ -1,10 +1,19 @@
package com.flightfeather.uav.domain.entity
import com.flightfeather.uav.biz.dataprocess.AvgPair
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.common.utils.GsonUtils
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.socket.bean.AirData
import com.flightfeather.uav.socket.eunm.FactorType
import com.flightfeather.uav.socket.eunm.FactorType.*
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.*
import kotlin.math.atan
import kotlin.math.cos
import kotlin.math.round
import kotlin.math.sin
/**
 * æ•°æ®åº“表实体扩展方法
@@ -105,4 +114,171 @@
            factorData = mvPowerC
        },
    )
}
}
/** GridDataDetail-start ********************************************************************/
/**
 * æ ¹æ®ç›‘测因子类型赋值
 */
fun GridDataDetail.setFactorValue(type: FactorType?, value: Float) {
    when (type) {
        NO -> no = value
        NO2 -> no2 = value
        CO -> co = value
        H2S -> h2s = value
        SO2 -> so2 = value
        O3 -> o3 = value
        PM25 -> pm25 = value
        PM10 -> pm10 = value
        TEMPERATURE -> temperature = value
        HUMIDITY -> humidity = value
        VOC -> voc = value
        NOI -> noi = value
        WIND_SPEED -> windSpeed = value
        WIND_DIRECTION -> windDirection = value
        LNG -> TODO("no such factor")
        LAT -> TODO("no such factor")
        VELOCITY -> TODO("no such factor")
        TIME -> TODO("no such factor")
        HEIGHT -> TODO("no such factor")
    }
}
fun List<GridDataDetail>.avg(): GridDataDetail {
    //风向采用单位矢量法求取均值
    var u = .0//东西方位分量总和
    var v = .0//南北方位分量总和
    var c = 0//风向数据计数
    //除风向外的其他因子采用算术平均法求取均值
    val tmpList = mutableListOf<AvgPair>()
    repeat(18) {
        tmpList.add(AvgPair(0f, 0))
    }
    forEach { f ->
        //风向
        f.windDirection?.let { w ->
            val r = Math.toRadians(w.toDouble())
            u += sin(r)
            v += cos(r)
            c++
        }
        //其余因子
        tmpList[0].apply {
            f.no2?.let {
                t += it
                this.c++
            }
        }
        tmpList[1].apply {
            f.co?.let {
                t += it
                this.c++
            }
        }
        tmpList[2].apply {
            f.h2s?.let {
                t += it
                this.c++
            }
        }
        tmpList[3].apply {
            f.so2?.let {
                t += it
                this.c++
            }
        }
        tmpList[4].apply {
            f.o3?.let {
                t += it
                this.c++
            }
        }
        tmpList[5].apply {
            f.pm25?.let {
                t += it
                this.c++
            }
        }
        tmpList[6].apply {
            f.pm10?.let {
                t += it
                this.c++
            }
        }
        tmpList[7].apply {
            f.temperature?.let {
                t += it
                this.c++
            }
        }
        tmpList[8].apply {
            f.humidity?.let {
                t += it
                this.c++
            }
        }
        tmpList[9].apply {
            f.voc?.let {
                t += it
                this.c++
            }
        }
        tmpList[10].apply {
            f.noi?.let {
                t += it
                this.c++
            }
        }
        tmpList[11].apply {
            f.windSpeed?.let {
                t += it
                this.c++
            }
        }
        tmpList[12].apply {
            f.no?.let {
                t += it
                this.c++
            }
        }
    }
    return GridDataDetail().apply {
        no2 = tmpList[0].avg()
        co = tmpList[1].avg()
        h2s = tmpList[2].avg()
        so2 = tmpList[3].avg()
        o3 = tmpList[4].avg()
        pm25 = tmpList[5].avg()
        pm10 = tmpList[6].avg()
        temperature = tmpList[7].avg()
        humidity = tmpList[8].avg()
        voc = tmpList[9].avg()
        noi = tmpList[10].avg()
        windSpeed = tmpList[11].avg()
        no = tmpList[12].avg()
        if (c != 0) {
            val avgU = u / c
            val avgV = v / c
            var a = atan(avgU / avgV)
            a = Math.toDegrees(a)
            /**
             * avgU>0;avgV>0: çœŸå®žè§’度处于第一象限,修正值为+0°
             * avgU>0;avgV<0: çœŸå®žè§’度处于第二象限,修正值为+180°
             * avgU<0;avgV<0: çœŸå®žè§’度处于第三象限,修正值为+180°
             * avgU<0;avgV>0: çœŸå®žè§’度处于第四象限,修正值为+360°
             */
            a += if (avgV > 0) {
                if (avgU > 0) 0 else 360
            } else {
                180
            }
            windDirection = round(a.toFloat())
        }
    }
}
/** GridDataDetail-over ********************************************************************/
src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java
@@ -33,6 +33,71 @@
    private String mixDataId;
    /**
     * æ‰€å±žåŒºåŸŸï¼ˆèµ°èˆªç›‘测融合网格)
     */
    private String zone;
    /**
     * å¤§æ°”污染等级(优、良、轻度污染、中度污染、重度污染)
     */
    @Column(name = "pollution_degree")
    private String pollutionDegree;
    /**
     * å¤§æ°”污染等级编号(优、良、轻度污染、中度污染、重度污染)
     */
    @Column(name = "pollution_degree_index")
    private Integer pollutionDegreeIndex;
    /**
     * èµ°èˆªä»»åŠ¡ç¼–å·
     */
    @Column(name = "mission_code")
    private String missionCode;
    @Column(name = "province_code")
    private String provinceCode;
    @Column(name = "province_name")
    private String provinceName;
    @Column(name = "city_code")
    private String cityCode;
    @Column(name = "city_name")
    private String cityName;
    @Column(name = "district_code")
    private String districtCode;
    @Column(name = "district_name")
    private String districtName;
    @Column(name = "town_code")
    private String townCode;
    @Column(name = "town_name")
    private String townName;
    /**
     * æ‰€å¤„每日的时段,"凌晨 0 - 6", "早上 6 - 9", "上午 9 - 12", "中午 12 - 14", "下午 14 - 17", "傍晚 17 - 20", "夜间 20 - 0"
     */
    @Column(name = "day_time_period")
    private String dayTimePeriod;
    /**
     * æ—¥æ—¶æ®µå¼€å§‹æ—¶é—´
     */
    @Column(name = "day_time_period_start")
    private Date dayTimePeriodStart;
    /**
     * æ—¥æ—¶æ®µç»“束时间
     */
    @Column(name = "day_time_period_end")
    private Date dayTimePeriodEnd;
    /**
     * @return id
     */
    public Integer getId() {
@@ -117,4 +182,242 @@
    public void setMixDataId(String mixDataId) {
        this.mixDataId = mixDataId == null ? null : mixDataId.trim();
    }
    /**
     * èŽ·å–æ‰€å±žåŒºåŸŸï¼ˆèµ°èˆªç›‘æµ‹èžåˆç½‘æ ¼ï¼‰
     *
     * @return zone - æ‰€å±žåŒºåŸŸï¼ˆèµ°èˆªç›‘测融合网格)
     */
    public String getZone() {
        return zone;
    }
    /**
     * è®¾ç½®æ‰€å±žåŒºåŸŸï¼ˆèµ°èˆªç›‘测融合网格)
     *
     * @param zone æ‰€å±žåŒºåŸŸï¼ˆèµ°èˆªç›‘测融合网格)
     */
    public void setZone(String zone) {
        this.zone = zone == null ? null : zone.trim();
    }
    /**
     * èŽ·å–å¤§æ°”æ±¡æŸ“ç­‰çº§ï¼ˆä¼˜ã€è‰¯ã€è½»åº¦æ±¡æŸ“ã€ä¸­åº¦æ±¡æŸ“ã€é‡åº¦æ±¡æŸ“ï¼‰
     *
     * @return pollution_degree - å¤§æ°”污染等级(优、良、轻度污染、中度污染、重度污染)
     */
    public String getPollutionDegree() {
        return pollutionDegree;
    }
    /**
     * è®¾ç½®å¤§æ°”污染等级(优、良、轻度污染、中度污染、重度污染)
     *
     * @param pollutionDegree å¤§æ°”污染等级(优、良、轻度污染、中度污染、重度污染)
     */
    public void setPollutionDegree(String pollutionDegree) {
        this.pollutionDegree = pollutionDegree == null ? null : pollutionDegree.trim();
    }
    /**
     * èŽ·å–å¤§æ°”æ±¡æŸ“ç­‰çº§ç¼–å·ï¼ˆä¼˜ã€è‰¯ã€è½»åº¦æ±¡æŸ“ã€ä¸­åº¦æ±¡æŸ“ã€é‡åº¦æ±¡æŸ“ï¼‰
     *
     * @return pollution_degree_index - å¤§æ°”污染等级编号(优、良、轻度污染、中度污染、重度污染)
     */
    public Integer getPollutionDegreeIndex() {
        return pollutionDegreeIndex;
    }
    /**
     * è®¾ç½®å¤§æ°”污染等级编号(优、良、轻度污染、中度污染、重度污染)
     *
     * @param pollutionDegreeIndex å¤§æ°”污染等级编号(优、良、轻度污染、中度污染、重度污染)
     */
    public void setPollutionDegreeIndex(Integer pollutionDegreeIndex) {
        this.pollutionDegreeIndex = pollutionDegreeIndex;
    }
    /**
     * èŽ·å–èµ°èˆªä»»åŠ¡ç¼–å·
     *
     * @return mission_code - èµ°èˆªä»»åŠ¡ç¼–å·
     */
    public String getMissionCode() {
        return missionCode;
    }
    /**
     * è®¾ç½®èµ°èˆªä»»åŠ¡ç¼–å·
     *
     * @param missionCode èµ°èˆªä»»åŠ¡ç¼–å·
     */
    public void setMissionCode(String missionCode) {
        this.missionCode = missionCode == null ? null : missionCode.trim();
    }
    /**
     * @return province_code
     */
    public String getProvinceCode() {
        return provinceCode;
    }
    /**
     * @param provinceCode
     */
    public void setProvinceCode(String provinceCode) {
        this.provinceCode = provinceCode == null ? null : provinceCode.trim();
    }
    /**
     * @return province_name
     */
    public String getProvinceName() {
        return provinceName;
    }
    /**
     * @param provinceName
     */
    public void setProvinceName(String provinceName) {
        this.provinceName = provinceName == null ? null : provinceName.trim();
    }
    /**
     * @return city_code
     */
    public String getCityCode() {
        return cityCode;
    }
    /**
     * @param cityCode
     */
    public void setCityCode(String cityCode) {
        this.cityCode = cityCode == null ? null : cityCode.trim();
    }
    /**
     * @return city_name
     */
    public String getCityName() {
        return cityName;
    }
    /**
     * @param cityName
     */
    public void setCityName(String cityName) {
        this.cityName = cityName == null ? null : cityName.trim();
    }
    /**
     * @return district_code
     */
    public String getDistrictCode() {
        return districtCode;
    }
    /**
     * @param districtCode
     */
    public void setDistrictCode(String districtCode) {
        this.districtCode = districtCode == null ? null : districtCode.trim();
    }
    /**
     * @return district_name
     */
    public String getDistrictName() {
        return districtName;
    }
    /**
     * @param districtName
     */
    public void setDistrictName(String districtName) {
        this.districtName = districtName == null ? null : districtName.trim();
    }
    /**
     * @return town_code
     */
    public String getTownCode() {
        return townCode;
    }
    /**
     * @param townCode
     */
    public void setTownCode(String townCode) {
        this.townCode = townCode == null ? null : townCode.trim();
    }
    /**
     * @return town_name
     */
    public String getTownName() {
        return townName;
    }
    /**
     * @param townName
     */
    public void setTownName(String townName) {
        this.townName = townName == null ? null : townName.trim();
    }
    /**
     * èŽ·å–æ‰€å¤„æ¯æ—¥çš„æ—¶æ®µï¼Œ"凌晨 0 - 6", "早上 6 - 9", "上午 9 - 12", "中午 12 - 14", "下午 14 - 17", "傍晚 17 - 20", "夜间 20 - 0"
     *
     * @return day_time_period - æ‰€å¤„每日的时段,"凌晨 0 - 6", "早上 6 - 9", "上午 9 - 12", "中午 12 - 14", "下午 14 - 17", "傍晚 17 - 20", "夜间 20 - 0"
     */
    public String getDayTimePeriod() {
        return dayTimePeriod;
    }
    /**
     * è®¾ç½®æ‰€å¤„每日的时段,"凌晨 0 - 6", "早上 6 - 9", "上午 9 - 12", "中午 12 - 14", "下午 14 - 17", "傍晚 17 - 20", "夜间 20 - 0"
     *
     * @param dayTimePeriod æ‰€å¤„每日的时段,"凌晨 0 - 6", "早上 6 - 9", "上午 9 - 12", "中午 12 - 14", "下午 14 - 17", "傍晚 17 - 20", "夜间 20 - 0"
     */
    public void setDayTimePeriod(String dayTimePeriod) {
        this.dayTimePeriod = dayTimePeriod == null ? null : dayTimePeriod.trim();
    }
    /**
     * èŽ·å–æ—¥æ—¶æ®µå¼€å§‹æ—¶é—´
     *
     * @return day_time_period_start - æ—¥æ—¶æ®µå¼€å§‹æ—¶é—´
     */
    public Date getDayTimePeriodStart() {
        return dayTimePeriodStart;
    }
    /**
     * è®¾ç½®æ—¥æ—¶æ®µå¼€å§‹æ—¶é—´
     *
     * @param dayTimePeriodStart æ—¥æ—¶æ®µå¼€å§‹æ—¶é—´
     */
    public void setDayTimePeriodStart(Date dayTimePeriodStart) {
        this.dayTimePeriodStart = dayTimePeriodStart;
    }
    /**
     * èŽ·å–æ—¥æ—¶æ®µç»“æŸæ—¶é—´
     *
     * @return day_time_period_end - æ—¥æ—¶æ®µç»“束时间
     */
    public Date getDayTimePeriodEnd() {
        return dayTimePeriodEnd;
    }
    /**
     * è®¾ç½®æ—¥æ—¶æ®µç»“束时间
     *
     * @param dayTimePeriodEnd æ—¥æ—¶æ®µç»“束时间
     */
    public void setDayTimePeriodEnd(Date dayTimePeriodEnd) {
        this.dayTimePeriodEnd = dayTimePeriodEnd;
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteDataCalculateService.kt
@@ -40,7 +40,7 @@
    /**
     * å°†èµ°èˆªç½‘格数据生成对应的热力网格图
     * @param groupId ä½¿ç”¨çš„网格组id
     * @param gridDataDetail ä½¿ç”¨çš„走航网格数据
     * @param gridDataDetailList ä½¿ç”¨çš„走航网格数据
     */
    fun buildHeatmap(groupId: Int, gridDataDetail: List<GridDataDetail>): List<GridDataDetail>
    fun buildHeatmap(groupId: Int, gridDataDetailList: List<GridDataDetail>, searchLength:Int): List<GridDataDetail>
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImpl.kt
@@ -1,11 +1,11 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.biz.satellite.GridGroupOption
import com.flightfeather.uav.biz.satellite.SatelliteGridManage
import com.flightfeather.uav.biz.satellite.SatelliteGridUtil
import com.flightfeather.uav.common.exception.BizException
import com.flightfeather.uav.domain.entity.GridCell
import com.flightfeather.uav.domain.entity.GridData
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.entity.GridGroup
import com.flightfeather.uav.common.utils.TimeUtil
import com.flightfeather.uav.domain.entity.*
import com.flightfeather.uav.domain.repository.MissionRep
import com.flightfeather.uav.domain.repository.RealTimeDataRep
import com.flightfeather.uav.domain.repository.SatelliteGridRep
@@ -138,9 +138,11 @@
        val mission = missionRep.findOne(missionCode) ?: throw BizException("任务不存在")
        val data = realTimeDataRep.fetchData(mission)
        // æŸ¥æ‰¾æ˜¯å¦å·²æœ‰èµ°èˆªèžåˆè®°å½•
        val oldGridDataList = satelliteGridRep.fetchGridData(GridData().apply {
            this.groupId = groupId
            mixDataId = missionCode
            this.type = SatelliteDataType.Monitor.value.toByte()
        })
        if (oldGridDataList.isEmpty()) {
@@ -149,7 +151,23 @@
                this.groupId = groupId
                dataTime = mission.startTime
                type = SatelliteDataType.Monitor.value.toByte()
                mixDataId = mission.missionCode
                this.missionCode = mission.missionCode
                // Fixme 2025.3.27: è¡Œæ”¿åŒºåˆ’在走航任务添加对应字段后进行赋值
                provinceCode
                provinceName
                cityCode
                cityName
                districtCode
                districtName = mission.districtName
                // Fixme 2025.3.27: æ‰€å±žç›‘测点区域目前需要通过用户选择确定
                zone
                pollutionDegreeIndex
                pollutionDegree
                val period = TimeUtil.getDayTimeTag(mission.startTime, mission.endTime)
                dayTimePeriod = period?.first
                dayTimePeriodStart = period?.second
                dayTimePeriodEnd = period?.third
            }
            satelliteGridRep.insertGridData(newGridData)
@@ -181,8 +199,37 @@
        }
    }
    override fun buildHeatmap(groupId: Int, gridDataDetail: List<GridDataDetail>): List<GridDataDetail> {
    override fun buildHeatmap(groupId: Int, gridDataDetailList: List<GridDataDetail>, searchLength:Int): List<GridDataDetail> {
        val gridCellList = satelliteGridRep.fetchGridCell(groupId)
        val originCellIdList = gridDataDetailList.map { it.cellId }
        // Fixme 2025.3.24: æ­¤å¤„根据现有的网格信息设计方式,使用临时的参数,后续将网格通过二维坐标形式表示,此处参数去除
        val option = GridGroupOption(120, 90, 10, 10)
        val resMap = mutableMapOf<Int, MutableList<GridDataDetail>>()
        // å¾ªçŽ¯è®¡ç®—æ¯ä¸ªç½‘æ ¼çš„å‘¨è¾¹æ‰©æ•£ç½‘æ ¼ç»“æžœ
        gridDataDetailList.forEach {gdd ->
            SatelliteGridManage.heatMap(gdd, gridCellList, option, searchLength).forEach {r ->
                if (!originCellIdList.contains(r.cellId)) {
                    if (!resMap.containsKey(r.cellId)) {
                        resMap[r.cellId] = mutableListOf()
                    }
                    resMap[r.cellId]?.add(r)
                }
            }
        }
        // å°†æ‰€æœ‰ç»“果格式化,同时重叠网格进行监测数据均值计算
        val result = mutableListOf<GridDataDetail>()
        resMap.forEach { (_, v) ->
            result.add(v.avg().apply {
                this.dataId = v.first().dataId
                this.groupId = v.first().groupId
                this.cellId = v.first().cellId
            })
        }
        result.addAll(gridDataDetailList)
        return result
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt
@@ -149,6 +149,7 @@
    @PostMapping("/product/underway/heatmap/build")
    fun buildUnderwayHeatmap(
        @ApiParam("使用的网格组id") @RequestParam groupId: Int,
        @ApiParam("使用的走航网格数据") @RequestBody gridDataDetail: List<GridDataDetail>
    ) = resPack { satelliteDataCalculateService.buildHeatmap(groupId, gridDataDetail) }
        @ApiParam("搜索网格距离") @RequestParam searchLength:Int,
        @ApiParam("使用的走航网格数据") @RequestBody gridDataDetailList: List<GridDataDetail>
    ) = resPack { satelliteDataCalculateService.buildHeatmap(groupId, gridDataDetailList, searchLength) }
}
src/main/kotlin/com/flightfeather/uav/model/BaseModel.kt
@@ -198,6 +198,12 @@
        return rMap
    }
    /**
     * å°†è®¡ç®—结果格式化为多层级的键对值结构
     * ç¬¬ä¸€å±‚按照不同污染源的索引值进行分类
     * ç¬¬äºŒå±‚按照监测因子类型进行分类
     * ç¬¬ä¸‰å±‚按照自定义的标签进行分类
     */
    private fun formatConversion2(e: BaseEffect) {
        val rKey = "${e.sourceName};${e.index}"
        if (!rMap.containsKey(rKey)) {
src/main/kotlin/com/flightfeather/uav/model/BaseNoSection.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
package com.flightfeather.uav.model
/**
 *
 * @date 2025/3/24
 * @author feiyu02
 */
open class BaseNoSection<M : BaseMData, S : BaseSOP> : BaseSection<M, S>() {
    override val sectionValues: List<Double> = listOf(1.0)
    override val sectionType: List<String> = listOf("综合")
    override val tagClz: Class<out BaseTag> = NoTag::class.java
    override fun onSectionValue(mData: M, sop: S, effect: BaseEffect): Double {
        return .0
    }
}
src/main/kotlin/com/flightfeather/uav/model/BaseSOP.kt
@@ -6,18 +6,18 @@
 * Source of pollution
 * æ±¡æŸ“源 åŸºç±»
 */
open class BaseSOP() {
open class BaseSOP(val sourceId: String, val sourceName: String, val index: String) {
    // æ±¡æŸ“源标识
    lateinit var sourceId: String
    lateinit var sourceName: String
    lateinit var index: String
    constructor(sourceId: String, sourceName: String, index: String) : this() {
        this.sourceId = sourceId
        this.sourceName = sourceName
        this.index = index
    }
//    lateinit var sourceId: String
//    lateinit var sourceName: String
//    lateinit var index: String
//
//    constructor() : this() {
//        this.sourceId = sourceId
//        this.sourceName = sourceName
//        this.index = index
//    }
    /**
     * ä¸­å¿ƒç»åº¦
     */
src/main/kotlin/com/flightfeather/uav/model/epw/NoSection.kt
@@ -6,14 +6,4 @@
/**
 * ä¸åšåˆ†ç±»ç»Ÿè®¡
 */
class NoSection : BaseSection<DataVo, BaseSOP>() {
    override val sectionValues: List<Double> = listOf(1.0)
    override val sectionType: List<String> = listOf("综合")
    override val tagClz: Class<out BaseTag> = NoTag::class.java
    override fun onSectionValue(mData: DataVo, sop: BaseSOP, effect: BaseEffect): Double {
        return .0
    }
}
class NoSection : BaseNoSection<DataVo, BaseSOP>()
src/main/kotlin/com/flightfeather/uav/model/underwaygrid/GridCellAndData.kt
@@ -15,25 +15,20 @@
    override fun getFactorData(type: FactorType): Double? {
        return when (type) {
//            NO2 -> NO2
//            CO -> CO
//            H2S -> H2S
//            SO2 -> SO2
//            O3 -> O3
            NO2 -> gridDataDetail.no2.toDouble()
            CO -> gridDataDetail.co.toDouble()
            H2S -> gridDataDetail.h2s.toDouble()
            SO2 -> gridDataDetail.so2.toDouble()
            O3 -> gridDataDetail.o3.toDouble()
            PM25 -> gridDataDetail.pm25.toDouble()
//            PM10 -> PM10
//            TEMPERATURE -> TEMPERATURE
//            HUMIDITY -> HUMIDITY
//            VOC -> VOC
//            NOI -> NOI
//            LNG -> LNG
//            LAT -> LAT
//            VELOCITY -> VELOCITY
//            TIME -> TIME
//            WIND_SPEED -> WIND_SPEED
//            WIND_DIRECTION -> WIND_DIRECTION
//            HEIGHT -> HEIGHT
//            NO -> NO
            PM10 -> gridDataDetail.pm10.toDouble()
            TEMPERATURE -> gridDataDetail.temperature.toDouble()
            HUMIDITY -> gridDataDetail.humidity.toDouble()
            VOC -> gridDataDetail.voc.toDouble()
            NOI -> gridDataDetail.noi.toDouble()
            WIND_SPEED -> gridDataDetail.windSpeed.toDouble()
            WIND_DIRECTION -> gridDataDetail.windDirection.toDouble()
            NO -> gridDataDetail.no.toDouble()
            else -> null
        }
    }
src/main/kotlin/com/flightfeather/uav/model/underwaygrid/GridCellSop.kt
@@ -11,7 +11,7 @@
class GridCellSop : BaseSOP {
    val gridCell:GridCell
    constructor(gridCell: GridCell) : super(){
    constructor(gridCell: GridCell) : super("", "", "") {
        this.gridCell = gridCell
    }
    constructor(gridCell: GridCell, sourceId: String, sourceName: String, index: String) : super(
src/main/kotlin/com/flightfeather/uav/model/underwaygrid/UnderwayGridModel.kt
@@ -1,9 +1,7 @@
package com.flightfeather.uav.model.underwaygrid
import com.flightfeather.uav.model.BaseDataPrep
import com.flightfeather.uav.model.BaseModel
import com.flightfeather.uav.model.BaseSection
import com.flightfeather.uav.model.BaseWeight
import com.flightfeather.uav.model.*
import com.flightfeather.uav.model.epw.NoSection
import com.flightfeather.uav.model.epw.WeightType
import com.flightfeather.uav.socket.eunm.FactorType
@@ -19,7 +17,7 @@
    override var weights: List<BaseWeight<GridCellAndData, GridCellSop>> = listOf(GridWindDirWeight(), GridWindDisWeight())
    override var sections: List<BaseSection<GridCellAndData, GridCellSop>> = emptyList()
    override var sections: List<BaseSection<GridCellAndData, GridCellSop>> = listOf(BaseNoSection())
    override fun mDataCheck(m: GridCellAndData): Boolean {
        return m.gridDataDetail.pm25 != null
src/main/resources/generator/generatorConfig.xml
@@ -68,7 +68,7 @@
<!--        <table tableName="segment_info" domainObjectName="SegmentInfo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="grid_group" domainObjectName="GridGroup" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="grid_cell" domainObjectName="GridCell" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
<!--        <table tableName="grid_data" domainObjectName="GridData" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
        <table tableName="grid_data_detail" domainObjectName="GridDataDetail" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
        <table tableName="grid_data" domainObjectName="GridData" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
<!--        <table tableName="grid_data_detail" domainObjectName="GridDataDetail" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
    </context>
</generatorConfiguration>
src/main/resources/mapper/GridDataMapper.xml
@@ -10,11 +10,28 @@
    <result column="data_time" jdbcType="TIMESTAMP" property="dataTime" />
    <result column="type" jdbcType="TINYINT" property="type" />
    <result column="mix_data_id" jdbcType="VARCHAR" property="mixDataId" />
    <result column="zone" jdbcType="VARCHAR" property="zone" />
    <result column="pollution_degree" jdbcType="VARCHAR" property="pollutionDegree" />
    <result column="pollution_degree_index" jdbcType="INTEGER" property="pollutionDegreeIndex" />
    <result column="mission_code" jdbcType="VARCHAR" property="missionCode" />
    <result column="province_code" jdbcType="VARCHAR" property="provinceCode" />
    <result column="province_name" jdbcType="VARCHAR" property="provinceName" />
    <result column="city_code" jdbcType="VARCHAR" property="cityCode" />
    <result column="city_name" jdbcType="VARCHAR" property="cityName" />
    <result column="district_code" jdbcType="VARCHAR" property="districtCode" />
    <result column="district_name" jdbcType="VARCHAR" property="districtName" />
    <result column="town_code" jdbcType="VARCHAR" property="townCode" />
    <result column="town_name" jdbcType="VARCHAR" property="townName" />
    <result column="day_time_period" jdbcType="VARCHAR" property="dayTimePeriod" />
    <result column="day_time_period_start" jdbcType="TIMESTAMP" property="dayTimePeriodStart" />
    <result column="day_time_period_end" jdbcType="TIMESTAMP" property="dayTimePeriodEnd" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--
      WARNING - @mbg.generated
    -->
    id, group_id, data_time, type, mix_data_id
    id, group_id, data_time, type, mix_data_id, zone, pollution_degree, pollution_degree_index,
    mission_code, province_code, province_name, city_code, city_name, district_code,
    district_name, town_code, town_name, day_time_period, day_time_period_start, day_time_period_end
  </sql>
</mapper>
src/test/kotlin/com/flightfeather/uav/Test.kt
@@ -3,6 +3,7 @@
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.common.utils.FileExchange
import com.flightfeather.uav.common.utils.FileUtil
import com.flightfeather.uav.common.utils.TimeUtil
import com.flightfeather.uav.domain.entity.BaseRealTimeData
import com.flightfeather.uav.domain.entity.Company
import com.flightfeather.uav.domain.entity.GridDataDetail
@@ -152,4 +153,14 @@
        println(dataDetail)
    }
    @Test
    fun getDayTimeTag() {
        val period = TimeUtil.getDayTimeTag(
            Date(2024, 10, 10, 10, 25, 0),
            Date(2024, 10, 10, 14, 40, 0)
        )
        println("${period?.first};${period?.second};${period?.third}")
    }
}
src/test/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteDataCalculateServiceImplTest.kt
@@ -1,7 +1,12 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.common.utils.TimeUtil
import com.flightfeather.uav.domain.entity.GridData
import com.flightfeather.uav.domain.entity.GridDataDetail
import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
import com.flightfeather.uav.domain.mapper.GridDataMapper
import com.flightfeather.uav.domain.mapper.MissionMapper
import com.flightfeather.uav.lightshare.eunm.SatelliteDataType
import com.flightfeather.uav.lightshare.service.SatelliteDataCalculateService
import org.junit.Test
import org.junit.runner.RunWith
@@ -19,7 +24,13 @@
    lateinit var satelliteDataCalculateService: SatelliteDataCalculateService
    @Autowired
    lateinit var gridDataMapper: GridDataMapper
    @Autowired
    lateinit var gridDataDetailMapper: GridDataDetailMapper
    @Autowired
    lateinit var missionMapper: MissionMapper
    /**
     * åˆ·æ–°æ¯ç»„数据的数据排名
@@ -62,13 +73,31 @@
    fun dataFusion() {
        val missionList =
            listOf(
                "SH-CN-20241216",
                "SH-CN-20241202",
                "SH-CN-20241127",
                "SH-CN-20241126-1",
                "SH-CN-20241126-2",
                "SH-CN-20241108",
                "SH-CN-20240823"
//                "SH-CN-20241216",
//                "SH-CN-20241202",
//                "SH-CN-20241127",
//                "SH-CN-20241126-1",
//                "SH-CN-20241126-2",
//                "SH-CN-20241108",
//                "SH-CN-20240823"
                "SH-CN-20240723-01",
                "SH-CN-20240723-02",
                "SH-CN-20240830",
                "SH-CN-20240906",
                "SH-CN-20241204",
                "SH-CN-20241210",
                "SH-CN-20241213",
                "SH-CN-20241218",
                "SH-CN-20241220",
                "SH-CN-20241224",
                "SH-CN-20241226",
                "SH-CN-20241227",
                "SH-CN-20241231",
                "SH-CN-20250106",
                "SH-CN-20250108",
                "SH-CN-20250113",
                "SH-CN-20250116",
                "SH-CN-20250120"
            )
        missionList.forEach { m ->
            satelliteDataCalculateService.dataFusion(m, 3)
@@ -77,7 +106,17 @@
    }
    @Test
    fun splitDataAndDataFusion() {
    fun refreshDayTimePeriod() {
        gridDataMapper.select(GridData().apply { type = SatelliteDataType.Monitor.value.toByte() }).forEach { gd ->
            missionMapper.selectByPrimaryKey(gd?.missionCode)?.let { m ->
                TimeUtil.getDayTimeTag(m.startTime, m.endTime)?.let { p ->
                    gd?.dayTimePeriod = p.first
                    gd?.dayTimePeriodStart = p.second
                    gd?.dayTimePeriodEnd = p.third
                    gridDataMapper.updateByPrimaryKey(gd)
                }
            }
        }
    }
}