From b7b520bfe8b35683112284861f0dca8e645cbd56 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期二, 31 十二月 2024 10:22:40 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/hc-satellite-data-import-1227_2'

---
 src/main/kotlin/com/flightfeather/uav/lightshare/bean/GridDataImportResult.kt                  |   12 +
 src/main/resources/mapper/GridAodMapper.xml                                                    |   18 +
 src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt                             |  193 ++++++++++++++++
 src/main/resources/mapper/GridAodDetailMapper.xml                                              |   20 +
 src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodDetailMapper.kt                     |    8 
 src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java                              |    1 
 src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt                    |   61 ++++
 src/main/resources/templates/GridData-AOD-Template.xlsx                                        |    0 
 src/main/kotlin/com/flightfeather/uav/domain/entity/GridAod.java                               |   59 ++++
 src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt |  141 +++++++++++
 src/main/resources/templates/GridData-PM2.5-Template.xlsx                                      |    0 
 src/main/kotlin/com/flightfeather/uav/domain/entity/GridAodDetail.java                         |   92 +++++++
 src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodMapper.kt                           |    8 
 src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt          |   17 +
 src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt           |   47 +++
 src/main/kotlin/com/flightfeather/uav/domain/mapper/GridDataDetailMapper.kt                    |    4 
 src/main/resources/mapper/GridDataDetailMapper.xml                                             |   11 
 17 files changed, 685 insertions(+), 7 deletions(-)

diff --git a/src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt b/src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt
index ea62b09..423644f 100644
--- a/src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt
+++ b/src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt
@@ -2,10 +2,15 @@
 
 import com.alibaba.fastjson.JSONObject
 import com.flightfeather.uav.common.exception.BizException
+import com.flightfeather.uav.domain.entity.GridAodDetail
+import com.flightfeather.uav.domain.entity.GridDataDetail
 import com.flightfeather.uav.domain.entity.RealTimeData
 import com.flightfeather.uav.domain.entity.RealTimeDataVehicle
 import com.flightfeather.uav.socket.bean.AirData
 import org.apache.poi.hssf.usermodel.HSSFWorkbook
+import org.apache.poi.ss.usermodel.Cell
+import org.apache.poi.ss.usermodel.CellType
+import org.apache.poi.ss.util.CellAddress
 import org.apache.poi.xssf.streaming.SXSSFWorkbook
 import java.io.File
 import java.io.FileInputStream
@@ -53,7 +58,7 @@
                     if (cellIterator.hasNext()) {
                         val cellText = cellIterator.next().stringCellValue
                         if (!cellText.equals(head)) {
-                            throw BizException("鏂囦欢鏍煎紡閿欒, 琛ㄥご[${head}]搴旇涓篬${cellText}]")
+                            throw BizException("鏂囦欢鏍煎紡閿欒, 琛ㄥご[${cellText}]搴旇涓篬${head}]")
                         }
                     } else {
                         throw BizException("鏂囦欢鏍煎紡閿欒, 琛ㄥご[${head}]缂哄け")
@@ -93,6 +98,192 @@
     }
 
     /**
+     * 杞崲PM2.5琛ㄦ牸鏁版嵁
+     */
+    fun exchangeGridData(file: InputStream, correctRangeGridCells: Set<Int>): List<GridDataDetail> {
+        // 妯′豢宸叉湁浠g爜鍒ゆ柇琛ㄥご姝g‘鎬� 骞跺湪閿欒鏃舵姏鍑哄紓甯�
+        val headers = listOf(
+            "pointid",
+            "PM2.5"
+        )
+        val result = mutableListOf<GridDataDetail>()
+        try {
+            ExcelUtil.readXLXS(file, headerCheck = {
+                val cellIterator = it.cellIterator()
+                val headIterator = headers.iterator()
+                while (headIterator.hasNext()) {
+                    val head = headIterator.next()
+                    if (cellIterator.hasNext()) {
+                        val cellText = cellIterator.next().stringCellValue
+                        if (!cellText.equals(head)) {
+                            throw BizException("鏂囦欢鏍煎紡閿欒, 琛ㄥご[${cellText}]搴旇涓篬${head}]")
+                        }
+                    } else {
+                        throw BizException("鏂囦欢鏍煎紡閿欒, 琛ㄥご[${head}]缂哄け")
+                    }
+                }
+                true
+            },
+                // 鍒ゆ柇鍗曞厓鏍兼暟鎹纭�э紝骞跺湪鎶ラ敊鍚庢姏鍑哄紓甯�
+                onRow = {
+                    val data = GridDataDetail().apply {
+                        // 杞崲缃戞牸缁勫崟鍏冩牸id
+                        // 寰楀埌褰撳墠鍗曞厓鏍肩殑瀹氫綅淇℃伅 锛坋g: B3,BA3...锛�
+                        val cellIdCellPosStr = CellAddress(it.rowNum, 0).formatAsString()
+                        // 寰楀埌褰撳墠鍗曞厓鏍兼暟鎹被鍨�
+                        val cellIdCellType = it.getCell(0).cellType
+                        when (cellIdCellType) {
+                            CellType.NUMERIC -> {
+                                // 褰撳�间负鏁板瓧绫诲瀷鏃惰浆鍖栦负缃戞牸鍗曞厓鏍糹d
+                                this.cellId = it.getCell(0)?.numericCellValue?.toInt()
+                            }
+                            else -> {
+                                throw BizException("鍗曞厓鏍糩${cellIdCellPosStr}]涓嶆槸鏁板瓧绫诲瀷")
+                            }
+                        }
+
+                        // 杞崲PM2.5
+                        // 寰楀埌褰撳墠鍗曞厓鏍肩殑瀹氫綅淇℃伅 锛坋g: B3,BA3...锛�
+                        val pm25CellPosStr = CellAddress(it.rowNum, 1).formatAsString()
+                        // 寰楀埌褰撳墠鍗曞厓鏍兼暟鎹被鍨�
+                        val pm25CellType = it.getCell(1).cellType
+                        when (pm25CellType) {
+                            CellType.STRING -> {
+                                // 褰撳�间负瀛楃涓叉椂鏈変袱绉嶆儏鍐�
+                                // 绌虹櫧鎴栬�呮槸鈥�/鈥欏瓧绗� 杞寲涓虹┖鍊�
+                                // 鍚﹀垯鎶ラ敊
+                                val stringValue = it.getCell(1)?.stringCellValue?.trim()
+                                if (stringValue != null) {
+                                    if (stringValue == "/" || stringValue.isBlank()) {
+                                        this.pm25 = null
+                                    }
+                                }else {
+                                    throw BizException("鍗曞厓鏍糩${pm25CellPosStr}]涓嶆槸鏁板瓧绫诲瀷鎴栬�呮枃鏈被鍨�")
+                                }
+                            }
+                            CellType.NUMERIC -> {
+                                // 褰撳�间负鏁板瓧绫诲瀷鏃惰浆鍖栦负pm2.5鏁版嵁
+                                this.pm25 = it.getCell(1)?.numericCellValue?.toFloat()
+                            }
+                            else -> {
+                                throw BizException("鍗曞厓鏍糩${pm25CellPosStr}]涓嶆槸鏁板瓧绫诲瀷")
+                            }
+                        }
+                    }
+                    result.add(data)
+                })
+        } catch (e: BizException) {
+            throw e
+        }
+        // 鍒ゆ柇缃戞牸鍗曞厓鏍肩紪鍙锋槸鍚﹀湪姝g‘鐨勮寖鍥村唴
+        val resultCellIdSet = result.asSequence().map { it.cellId ?: -1 }.toSet()
+        // 鐢ㄦ埛瀵煎叆涓己灏戠殑鐨勫崟鍏冩牸
+        val shortCells = correctRangeGridCells - resultCellIdSet
+        // excel 涓鍑虹殑鐨勫崟鍏冩牸
+        val outCells = resultCellIdSet - correctRangeGridCells
+        if (shortCells.isNotEmpty()) {
+            throw BizException("瀵煎叆鏁版嵁涓己灏戜互涓嬬綉鏍煎崟鍏冩牸锛�${shortCells.joinToString(",")}")
+        }
+        if (outCells.isNotEmpty()) {
+            throw BizException("瀵煎叆鏁版嵁涓湁澶氫綑缃戞牸鍗曞厓鏍硷細${outCells.joinToString(",")}")
+        }
+        return result
+    }
+
+    /**
+     * 杞崲AOD琛ㄦ牸鏁版嵁
+     */
+    fun exchangeGridAod(file: InputStream, correctRangeGridCells: Set<Int>): List<GridAodDetail> {
+        // 妯′豢宸叉湁浠g爜鍒ゆ柇琛ㄥご姝g‘鎬� 骞跺湪閿欒鏃舵姏鍑哄紓甯�
+        val headers = listOf(
+            "pointid",
+            "AOD"
+        )
+        val result = mutableListOf<GridAodDetail>()
+        try {
+            ExcelUtil.readXLXS(file, headerCheck = {
+                val cellIterator = it.cellIterator()
+                val headIterator = headers.iterator()
+                while (headIterator.hasNext()) {
+                    val head = headIterator.next()
+                    if (cellIterator.hasNext()) {
+                        val cellText = cellIterator.next().stringCellValue
+                        if (!cellText.equals(head)) {
+                            throw BizException("鏂囦欢鏍煎紡閿欒, 琛ㄥご[${cellText}]搴旇涓篬${head}]")
+                        }
+                    } else {
+                        throw BizException("鏂囦欢鏍煎紡閿欒, 琛ㄥご[${head}]缂哄け")
+                    }
+                }
+                true
+            },
+                // 鍒ゆ柇鍗曞厓鏍兼暟鎹纭�э紝骞跺湪鎶ラ敊鍚庢姏鍑哄紓甯�
+                onRow = {
+                    val data = GridAodDetail().apply {
+                        // 杞崲缃戞牸缁勫崟鍏冩牸id
+                        // 寰楀埌褰撳墠鍗曞厓鏍肩殑瀹氫綅淇℃伅 锛坋g: B3,BA3...锛�
+                        val cellIdCellPosStr = CellAddress(it.rowNum, 0).formatAsString()
+                        // 寰楀埌褰撳墠鍗曞厓鏍兼暟鎹被鍨�
+                        val cellIdCellType = it.getCell(0).cellType
+                        when (cellIdCellType) {
+                            CellType.NUMERIC -> {
+                                // 褰撳�间负鏁板瓧绫诲瀷鏃惰浆鍖栦负缃戞牸鍗曞厓鏍糹d
+                                this.cellId = it.getCell(0)?.numericCellValue?.toInt()
+                            }
+                            else -> {
+                                throw BizException("鍗曞厓鏍糩${cellIdCellPosStr}]涓嶆槸鏁板瓧绫诲瀷")
+                            }
+                        }
+
+                        // 杞崲AOD
+                        // 寰楀埌褰撳墠鍗曞厓鏍肩殑瀹氫綅淇℃伅 锛坋g: B3,BA3...锛�
+                        val aodCellPosStr = CellAddress(it.rowNum, 1).formatAsString()
+                        // 寰楀埌褰撳墠鍗曞厓鏍兼暟鎹被鍨�
+                        val aodCellType = it.getCell(1).cellType
+                        when (aodCellType) {
+                            CellType.STRING -> {
+                                // 褰撳�间负瀛楃涓叉椂鏈変袱绉嶆儏鍐�
+                                // 绌虹櫧鎴栬�呮槸鈥�/鈥欏瓧绗� 杞寲涓虹┖鍊�
+                                // 鍚﹀垯鎶ラ敊
+                                val stringValue = it.getCell(1)?.stringCellValue?.trim()
+                                if (stringValue != null) {
+                                    if (stringValue == "/" || stringValue.isBlank()) {
+                                        this.aod = null
+                                    }
+                                }else {
+                                    throw BizException("鍗曞厓鏍糩${aodCellPosStr}]涓嶆槸鏁板瓧绫诲瀷鎴栬�呮枃鏈被鍨�")
+                                }
+                            }
+                            CellType.NUMERIC -> {
+                                // 褰撳�间负鏁板瓧绫诲瀷鏃惰浆鍖栦负pm2.5鏁版嵁
+                                this.aod = it.getCell(1)?.numericCellValue?.toFloat()
+                            }
+                            else -> {
+                                throw BizException("鍗曞厓鏍糩${aodCellPosStr}]涓嶆槸鏁板瓧绫诲瀷")
+                            }
+                        }
+                    }
+                    result.add(data)
+                })
+        } catch (e: BizException) {
+            throw e
+        }
+        // 鍒ゆ柇缃戞牸鍗曞厓鏍肩紪鍙锋槸鍚﹀湪姝g‘鐨勮寖鍥村唴
+        val resultCellIdSet = result.asSequence().map { it.cellId ?: -1 }.toSet()
+        // 鐢ㄦ埛瀵煎叆涓己灏戠殑鐨勫崟鍏冩牸
+        val shortCells = correctRangeGridCells - resultCellIdSet
+        // excel 涓鍑虹殑鐨勫崟鍏冩牸
+        val outCells = resultCellIdSet - correctRangeGridCells
+        if (shortCells.isNotEmpty()) {
+            throw BizException("瀵煎叆鏁版嵁涓己灏戜互涓嬬綉鏍煎崟鍏冩牸锛�${shortCells.joinToString(",")}")
+        }
+        if (outCells.isNotEmpty()) {
+            throw BizException("瀵煎叆鏁版嵁涓湁澶氫綑缃戞牸鍗曞厓鏍硷細${outCells.joinToString(",")}")
+        }
+        return result
+    }
+
+    /**
      * 杞崲杞﹁浇璧拌埅鏁版嵁
      */
     fun exchangeVehicleData(deviceCode: String, file: InputStream): List<RealTimeDataVehicle> {
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/entity/GridAod.java b/src/main/kotlin/com/flightfeather/uav/domain/entity/GridAod.java
new file mode 100644
index 0000000..de6d5de
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/domain/entity/GridAod.java
@@ -0,0 +1,59 @@
+package com.flightfeather.uav.domain.entity;
+
+import javax.persistence.*;
+import java.util.Date;
+
+@Table(name = "grid_aod")
+public class GridAod {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    @Column(name = "group_id")
+    private Integer groupId;
+
+    @Column(name = "data_time")
+    private Date dataTime;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * @return group_id
+     */
+    public Integer getGroupId() {
+        return groupId;
+    }
+
+    /**
+     * @param groupId
+     */
+    public void setGroupId(Integer groupId) {
+        this.groupId = groupId;
+    }
+
+    /**
+     * @return data_time
+     */
+    public Date getDataTime() {
+        return dataTime;
+    }
+
+    /**
+     * @param dataTime
+     */
+    public void setDataTime(Date dataTime) {
+        this.dataTime = dataTime;
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/entity/GridAodDetail.java b/src/main/kotlin/com/flightfeather/uav/domain/entity/GridAodDetail.java
new file mode 100644
index 0000000..15b16ad
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/domain/entity/GridAodDetail.java
@@ -0,0 +1,92 @@
+package com.flightfeather.uav.domain.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Table(name = "grid_aod_detail")
+public class GridAodDetail {
+    @Id
+    private Integer id;
+
+    @Column(name = "aod_id")
+    private Integer aodId;
+
+    @Column(name = "group_id")
+    private Integer groupId;
+
+    @Column(name = "cell_id")
+    private Integer cellId;
+
+    private Float aod;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * @return aod_id
+     */
+    public Integer getAodId() {
+        return aodId;
+    }
+
+    /**
+     * @param aodId
+     */
+    public void setAodId(Integer aodId) {
+        this.aodId = aodId;
+    }
+
+    /**
+     * @return group_id
+     */
+    public Integer getGroupId() {
+        return groupId;
+    }
+
+    /**
+     * @param groupId
+     */
+    public void setGroupId(Integer groupId) {
+        this.groupId = groupId;
+    }
+
+    /**
+     * @return cell_id
+     */
+    public Integer getCellId() {
+        return cellId;
+    }
+
+    /**
+     * @param cellId
+     */
+    public void setCellId(Integer cellId) {
+        this.cellId = cellId;
+    }
+
+    /**
+     * @return aod
+     */
+    public Float getAod() {
+        return aod;
+    }
+
+    /**
+     * @param aod
+     */
+    public void setAod(Float aod) {
+        this.aod = aod;
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java b/src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java
index e008649..2273b64 100644
--- a/src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java
+++ b/src/main/kotlin/com/flightfeather/uav/domain/entity/GridData.java
@@ -6,6 +6,7 @@
 @Table(name = "grid_data")
 public class GridData {
     @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
     /**
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodDetailMapper.kt b/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodDetailMapper.kt
new file mode 100644
index 0000000..4576917
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodDetailMapper.kt
@@ -0,0 +1,8 @@
+package com.flightfeather.uav.domain.mapper
+
+import com.flightfeather.uav.domain.MyMapper
+import com.flightfeather.uav.domain.entity.GridAodDetail
+import org.apache.ibatis.annotations.Mapper
+
+@Mapper
+interface GridAodDetailMapper : MyMapper<GridAodDetail?>
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodMapper.kt b/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodMapper.kt
new file mode 100644
index 0000000..73b0da3
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridAodMapper.kt
@@ -0,0 +1,8 @@
+package com.flightfeather.uav.domain.mapper
+
+import com.flightfeather.uav.domain.MyMapper
+import com.flightfeather.uav.domain.entity.GridAod
+import org.apache.ibatis.annotations.Mapper
+
+@Mapper
+interface GridAodMapper : MyMapper<GridAod?>
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridDataDetailMapper.kt b/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridDataDetailMapper.kt
index 1a6f152..cf4437e 100644
--- a/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridDataDetailMapper.kt
+++ b/src/main/kotlin/com/flightfeather/uav/domain/mapper/GridDataDetailMapper.kt
@@ -5,4 +5,6 @@
 import org.apache.ibatis.annotations.Mapper
 
 @Mapper
-interface GridDataDetailMapper : MyMapper<GridDataDetail?>
\ No newline at end of file
+interface GridDataDetailMapper : MyMapper<GridDataDetail?> {
+    fun updatePM25Batch(gridDataDetails: List<GridDataDetail>)
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt b/src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt
index 2c0db63..b88bc35 100644
--- a/src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt
+++ b/src/main/kotlin/com/flightfeather/uav/domain/repository/SatelliteGridRep.kt
@@ -1,9 +1,8 @@
 package com.flightfeather.uav.domain.repository
 
-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.domain.entity.*
+import com.flightfeather.uav.domain.mapper.GridAodDetailMapper
+import com.flightfeather.uav.domain.mapper.GridAodMapper
 import com.flightfeather.uav.domain.mapper.GridCellMapper
 import com.flightfeather.uav.domain.mapper.GridDataDetailMapper
 import com.flightfeather.uav.domain.mapper.GridDataMapper
@@ -24,6 +23,8 @@
     private val gridCellMapper: GridCellMapper,
     private val gridDataMapper: GridDataMapper,
     private val gridDataDetailMapper: GridDataDetailMapper,
+    private val gridAodMapper: GridAodMapper,
+    private val gridAodDetailMapper: GridAodDetailMapper,
 ) {
 
     fun fetchGridGroup(areaVo: AreaVo): List<GridGroup?> {
@@ -59,4 +60,56 @@
             orderBy("cellId")
         })
     }
+
+    fun insertGridDataAndDetail(data: GridData, gridDataDetails: List<GridDataDetail>) {
+        gridDataMapper.insert(data)
+        gridDataDetails.forEach {
+            it.dataId = data.id
+            it.groupId = data.groupId
+        }
+        gridDataDetailMapper.insertList(gridDataDetails)
+    }
+
+    fun updatePM25Batch(gridDataDetails: List<GridDataDetail>) {
+        gridDataDetailMapper.updatePM25Batch(gridDataDetails)
+    }
+
+
+    //    aod 鐩稿叧鎿嶄綔
+    fun fetchGridAod(groupId: Int, dataTime: LocalDateTime?): List<GridAod?> {
+        return gridAodMapper.selectByExample(Example(GridAod::class.java).apply {
+            createCriteria().andEqualTo("groupId", groupId)
+                .andEqualTo("dataTime", dataTime)
+        })
+    }
+
+    fun fetchGridAodDetail(aodId: Int, groupId: Int?, cellId: Int?): List<GridAodDetail?> {
+        return gridAodDetailMapper.selectByExample(Example(GridAodDetail::class.java).apply {
+            createCriteria().andEqualTo("aodId", aodId)
+                .andEqualTo("groupId", groupId)
+                .andEqualTo("cellId", cellId)
+            orderBy("cellId")
+        })
+    }
+
+    fun insertGridAodAndDetail(aod: GridAod, gridAodDetails: List<GridAodDetail>) {
+        gridAodMapper.insert(aod)
+        gridAodDetails.forEach {
+            it.aodId = aod.id
+            it.groupId = aod.groupId
+        }
+        gridAodDetailMapper.insertList(gridAodDetails)
+    }
+
+    fun updateGridAodBatch(gridDataDetails: List<GridAodDetail>) {
+        gridDataDetails.forEach {
+            gridAodDetailMapper.updateByExample(it, Example(GridAodDetail::class.java).apply {
+                createCriteria().andEqualTo("aodId", it.aodId)
+                    .andEqualTo("groupId", it.groupId)
+                    .andEqualTo("cellId", it.cellId)
+            })
+        }
+
+    }
+
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/bean/GridDataImportResult.kt b/src/main/kotlin/com/flightfeather/uav/lightshare/bean/GridDataImportResult.kt
new file mode 100644
index 0000000..7afad90
--- /dev/null
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/bean/GridDataImportResult.kt
@@ -0,0 +1,12 @@
+package com.flightfeather.uav.lightshare.bean
+
+import com.fasterxml.jackson.annotation.JsonInclude
+
+/**
+ * 缃戞牸鏁版嵁瀵煎叆澶勭悊缁撴灉
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+data class GridDataImportResult(
+    val success: Boolean,
+    val result: String
+)
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt b/src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt
index 8263119..97014cb 100644
--- a/src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/service/SatelliteTelemetryService.kt
@@ -1,12 +1,17 @@
 package com.flightfeather.uav.lightshare.service
 
+import com.flightfeather.uav.common.exception.BizException
+import com.flightfeather.uav.domain.entity.GridAod
 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.lightshare.bean.AreaVo
 import com.flightfeather.uav.lightshare.bean.DataHead
+import com.flightfeather.uav.lightshare.bean.GridDataImportResult
+import org.springframework.web.multipart.MultipartFile
 import java.time.LocalDateTime
+import javax.servlet.http.HttpServletResponse
 
 /**
  *
@@ -22,4 +27,16 @@
     fun fetchGridData(groupId: Int, dataTime: LocalDateTime?, type: Int?): List<GridData?>
 
     fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?>
+
+    @Throws(BizException::class)
+    fun importGridData(groupId: Int, dataTime: LocalDateTime?, update: Boolean, file: MultipartFile): GridDataImportResult?
+
+    fun downloadTemplate(response: HttpServletResponse): Boolean
+
+    fun fetchGridAod(groupId: Int, dataTime: LocalDateTime?): List<GridAod?>
+
+    @Throws(BizException::class)
+    fun importGridAOD(groupId: Int, dataTime: LocalDateTime?, update: Boolean, file: MultipartFile): GridDataImportResult?
+
+    fun downloadAODTemplate(response: HttpServletResponse): Boolean
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt b/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt
index 60ef723..db1be82 100644
--- a/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/SatelliteTelemetryServiceImpl.kt
@@ -1,5 +1,8 @@
 package com.flightfeather.uav.lightshare.service.impl
 
+import com.flightfeather.uav.common.exception.BizException
+import com.flightfeather.uav.common.utils.FileExchange
+import com.flightfeather.uav.domain.entity.GridAod
 import com.flightfeather.uav.domain.entity.GridCell
 import com.flightfeather.uav.domain.entity.GridData
 import com.flightfeather.uav.domain.entity.GridDataDetail
@@ -7,10 +10,17 @@
 import com.flightfeather.uav.domain.repository.SatelliteGridRep
 import com.flightfeather.uav.lightshare.bean.AreaVo
 import com.flightfeather.uav.lightshare.bean.DataHead
+import com.flightfeather.uav.lightshare.bean.GridDataImportResult
 import com.flightfeather.uav.lightshare.service.SatelliteTelemetryService
 import com.github.pagehelper.PageHelper
 import org.springframework.stereotype.Service
+import org.springframework.web.multipart.MultipartFile
+import java.io.ByteArrayInputStream
+import java.io.File
 import java.time.LocalDateTime
+import java.time.ZoneId
+import java.util.*
+import javax.servlet.http.HttpServletResponse
 
 /**
  *
@@ -20,6 +30,7 @@
 @Service
 class SatelliteTelemetryServiceImpl(private val satelliteGridRep: SatelliteGridRep) : SatelliteTelemetryService {
 
+    private val fileExchange = FileExchange()
     override fun fetchGridGroup(areaVo: AreaVo, page: Int?, perPage: Int?): Pair<DataHead, List<GridGroup?>> {
         val pageInfo = PageHelper.startPage<GridGroup>(page ?: 1, perPage ?: 100)
         val res = satelliteGridRep.fetchGridGroup(areaVo)
@@ -34,7 +45,137 @@
         return satelliteGridRep.fetchGridData(groupId, dataTime, type)
     }
 
+    override fun fetchGridAod(groupId: Int, dataTime: LocalDateTime?): List<GridAod?> {
+        return satelliteGridRep.fetchGridAod(groupId, dataTime)
+    }
+
     override fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?> {
         return satelliteGridRep.fetchGridDataDetail(dataId, groupId, cellId)
     }
+
+    override fun importGridData(groupId: Int, dataTime: LocalDateTime?, update: Boolean, file: MultipartFile): GridDataImportResult? {
+        // 鍥犱负鏄鍏ュ崼鏄熼仴娴嬫暟鎹� type濮嬬粓涓�0
+        val type = 0
+        // 棣栧厛鍒ゆ柇鏂囦欢绫诲瀷锛屾枃浠剁被鍨嬩笉鏄痻lsx鐩存帴鎶ラ敊
+        if (!file.contentType!!.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
+            throw BizException("鏂囦欢绫诲瀷閿欒锛岃涓婁紶xlsx绫诲瀷鏂囦欢")
+        }
+        // 鏍¢獙 鐢ㄦ埛鏇存柊鎸囦护 鍜� 鏁版嵁搴撲腑缃戞牸鏁版嵁瀛樺湪涓庡惁 鏄惁鍖归厤锛屼笉鍖归厤鎶涘嚭閿欒
+        // 杩欎釜杩囩▼闇�瑕佹煡璇㈡暟鎹簱涓綉鏍肩粍鏁版嵁
+        val gridData = satelliteGridRep.fetchGridData(groupId, dataTime, type)
+        // 灏嗙敤鎴峰鍏ョ殑鏂囦欢杞崲涓烘暟鎹�
+        // 杞崲鐨勮繃绋嬮渶瑕佺綉鏍煎崟鍏冩牸鏁版嵁 浠ュ垽鏂綉鏍煎崟鍏冩牸鏄惁鍦ㄦ纭殑鑼冨洿鍐�
+        val gridCellsInDBSet = satelliteGridRep.fetchGridCell(groupId).asSequence().map { it?.id ?: -1 }.toSet()
+        val importData
+                = fileExchange.exchangeGridData(ByteArrayInputStream(file.bytes), gridCellsInDBSet)
+        if (update) {
+            // 鐢ㄦ埛闇�瑕佹墽琛屾洿鏂�
+            if (gridData.isEmpty()) {
+                throw BizException("鎸囦护閿欒锛屾暟鎹簱瀵瑰簲缃戞牸缁勫拰鏃ユ湡涓嬩笉瀛樺湪閬ユ祴鏁版嵁锛岃鎵ц鎻掑叆鎿嶄綔")
+            }
+            importData.forEach {
+                it.dataId = gridData[0]?.id
+                it.groupId = gridData[0]?.groupId
+            }
+            satelliteGridRep.updatePM25Batch(importData)
+            return GridDataImportResult(true, "瑕嗙洊鎴愬姛")
+        }else {
+            // 鐢ㄦ埛闇�瑕佹墽琛屾彃鍏�
+            if (gridData.isNotEmpty()) {
+                throw BizException("鎸囦护閿欒锛屾暟鎹簱瀵瑰簲缃戞牸缁勫拰鏃ユ湡涓嬪凡瀛樺湪閬ユ祴鏁版嵁锛岃鎵ц鏇存柊鎿嶄綔")
+            }
+            val gridDataEntity = GridData()
+            gridDataEntity.groupId = groupId
+            gridDataEntity.dataTime = dataTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
+                ?.let { Date(it) }
+            gridDataEntity.type = type.toByte()
+            satelliteGridRep.insertGridDataAndDetail(gridDataEntity, importData)
+            return GridDataImportResult(true, "瀵煎叆鎴愬姛")
+        }
+    }
+
+    override fun downloadTemplate(response: HttpServletResponse): Boolean {
+        val fileName = "GridData-PM2.5-Template.xlsx"
+        val path = (Thread.currentThread().contextClassLoader?.getResource("/")?.path
+            ?: "src/main/resources") + "/templates/" + fileName
+        val file = File(path)
+        if (file.exists()) {
+            val fName = Base64.getEncoder().encodeToString(fileName.toByteArray())
+            response.apply {
+                setHeader("Content-Disposition", "attachment;filename=$fName")
+                setHeader("fileName", fName)
+                addHeader("Access-Control-Expose-Headers", "fileName")
+                contentType = "application/vnd.ms-excel;charset=UTF-8"
+                setHeader("Pragma", "no-cache")
+                setHeader("Cache-Control", "no-cache")
+                setDateHeader("Expires", 0)
+            }
+            response.outputStream.write(file.readBytes())
+        }
+        return true
+    }
+
+    override fun importGridAOD(
+        groupId: Int,
+        dataTime: LocalDateTime?,
+        update: Boolean,
+        file: MultipartFile
+    ): GridDataImportResult? {
+        // 棣栧厛鍒ゆ柇鏂囦欢绫诲瀷锛屾枃浠剁被鍨嬩笉鏄痻lsx鐩存帴鎶ラ敊
+        if (!file.contentType!!.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
+            throw BizException("鏂囦欢绫诲瀷閿欒锛岃涓婁紶xlsx绫诲瀷鏂囦欢")
+        }
+        // 鏍¢獙 鐢ㄦ埛鏇存柊鎸囦护 鍜� 鏁版嵁搴撲腑缃戞牸鏁版嵁瀛樺湪涓庡惁 鏄惁鍖归厤锛屼笉鍖归厤鎶涘嚭閿欒
+        // 杩欎釜杩囩▼闇�瑕佹煡璇㈡暟鎹簱涓綉鏍肩粍鏁版嵁
+        val gridAod = satelliteGridRep.fetchGridAod(groupId, dataTime)
+        // 灏嗙敤鎴峰鍏ョ殑鏂囦欢杞崲涓烘暟鎹�
+        // 杞崲鐨勮繃绋嬮渶瑕佺綉鏍煎崟鍏冩牸鏁版嵁 浠ュ垽鏂綉鏍煎崟鍏冩牸鏄惁鍦ㄦ纭殑鑼冨洿鍐�
+        val gridCellsInDBSet = satelliteGridRep.fetchGridCell(groupId).asSequence().map { it?.id ?: -1 }.toSet()
+        val importAod
+                = fileExchange.exchangeGridAod(ByteArrayInputStream(file.bytes), gridCellsInDBSet)
+        if (update) {
+            // 鐢ㄦ埛闇�瑕佹墽琛屾洿鏂�
+            if (gridAod.isEmpty()) {
+                throw BizException("鎸囦护閿欒锛屾暟鎹簱瀵瑰簲缃戞牸缁勫拰鏃ユ湡涓嬩笉瀛樺湪AOD鏁版嵁锛岃鎵ц鎻掑叆鎿嶄綔")
+            }
+            importAod.forEach {
+                it.aodId = gridAod[0]?.id
+                it.groupId = gridAod[0]?.groupId
+            }
+            satelliteGridRep.updateGridAodBatch(importAod)
+            return GridDataImportResult(true, "瑕嗙洊鎴愬姛")
+        }else {
+            // 鐢ㄦ埛闇�瑕佹墽琛屾彃鍏�
+            if (gridAod.isNotEmpty()) {
+                throw BizException("鎸囦护閿欒锛屾暟鎹簱瀵瑰簲缃戞牸缁勫拰鏃ユ湡涓嬪凡瀛樺湪AOD鏁版嵁锛岃鎵ц鏇存柊鎿嶄綔")
+            }
+            val gridAodEntity = GridAod()
+            gridAodEntity.groupId = groupId
+            gridAodEntity.dataTime = dataTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
+                ?.let { Date(it) }
+            satelliteGridRep.insertGridAodAndDetail(gridAodEntity, importAod)
+            return GridDataImportResult(true, "瀵煎叆鎴愬姛")
+        }
+    }
+
+    override fun downloadAODTemplate(response: HttpServletResponse): Boolean {
+        val fileName = "GridData-AOD-Template.xlsx"
+        val path = (Thread.currentThread().contextClassLoader?.getResource("/")?.path
+            ?: "src/main/resources") + "/templates/" + fileName
+        val file = File(path)
+        if (file.exists()) {
+            val fName = Base64.getEncoder().encodeToString(fileName.toByteArray())
+            response.apply {
+                setHeader("Content-Disposition", "attachment;filename=$fName")
+                setHeader("fileName", fName)
+                addHeader("Access-Control-Expose-Headers", "fileName")
+                contentType = "application/vnd.ms-excel;charset=UTF-8"
+                setHeader("Pragma", "no-cache")
+                setHeader("Cache-Control", "no-cache")
+                setDateHeader("Expires", 0)
+            }
+            response.outputStream.write(file.readBytes())
+        }
+        return true
+    }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt b/src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt
index 2ac67d6..f5b6175 100644
--- a/src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt
+++ b/src/main/kotlin/com/flightfeather/uav/lightshare/web/SatelliteTelemetryController.kt
@@ -6,8 +6,12 @@
 import io.swagger.annotations.Api
 import io.swagger.annotations.ApiOperation
 import io.swagger.annotations.ApiParam
+import org.springframework.format.annotation.DateTimeFormat
 import org.springframework.web.bind.annotation.*
+import org.springframework.web.multipart.MultipartFile
+import springfox.documentation.annotations.ApiIgnore
 import java.time.LocalDateTime
+import javax.servlet.http.HttpServletResponse
 
 /**
  * 鍗槦閬ユ祴
@@ -38,7 +42,7 @@
     fun fetchGridData(
         @ApiParam("缃戞牸缁刬d") @RequestParam groupId: Int,
         @ApiParam("閬ユ祴鏁版嵁鏃堕棿")
-        @RequestParam(required = false) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") dataTime: LocalDateTime?,
+        @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") dataTime: LocalDateTime?,
         @ApiParam("閬ユ祴鏁版嵁绫诲瀷", allowableValues = "0锛氬師濮嬪崼鏄熼仴娴嬫暟鎹紱1锛氳瀺鍚堟暟鎹�") @RequestParam(required = false) type: Int?,
     ) = resPack { satelliteTelemetryService.fetchGridData(groupId, dataTime, type) }
 
@@ -49,4 +53,45 @@
         @ApiParam("缃戞牸缁刬d") @RequestParam(required = false) groupId: Int?,
         @ApiParam("缃戞牸鍗曞厓鏍糹d") @RequestParam(required = false) cellId: Int?,
     ) = resPack { satelliteTelemetryService.fetchGridDataDetail(dataId, groupId, cellId) }
+
+
+    @ApiOperation(value = "瀵煎叆鍗槦閬ユ祴PM2.5缁撴灉鏁版嵁")
+    @PostMapping("/import/grid/data")
+    fun importGridData(
+        @ApiParam("缃戞牸缁刬d") @RequestParam groupId: Int,
+        @ApiParam("閬ユ祴鏁版嵁鏃堕棿")
+        @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") dateTime: LocalDateTime,
+        @ApiParam("瑕嗙洊鏃ф暟鎹� 0: 涓嶈鐩� 1: 瑕嗙洊") @RequestParam update: Boolean,
+        @RequestParam("excel") file: MultipartFile,
+    ) = resPack {
+        satelliteTelemetryService.importGridData(groupId, dateTime, update, file)
+    }
+
+    @ApiOperation(value = "涓嬭浇鍗槦閬ユ祴PM2.5缁撴灉鏁版嵁瀵煎叆妯℃澘")
+    @GetMapping("/import/grid/data/download/template")
+    fun downloadTemplate(@ApiIgnore response: HttpServletResponse) = satelliteTelemetryService.downloadTemplate(response)
+
+    @ApiOperation(value = "鑾峰彇缃戞牸缁勪笅鐨勫崼鏄熼仴娴媋od鏁版嵁")
+    @GetMapping("/grid/aod")
+    fun fetchGridAod(
+        @ApiParam("缃戞牸缁刬d") @RequestParam groupId: Int,
+        @ApiParam("閬ユ祴鏁版嵁鏃堕棿")
+        @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") dataTime: LocalDateTime?,
+    ) = resPack { satelliteTelemetryService.fetchGridAod(groupId, dataTime) }
+
+    @ApiOperation(value = "瀵煎叆鍗槦閬ユ祴Aod缁撴灉鏁版嵁")
+    @PostMapping("/import/grid/aod")
+    fun importGridAOD(
+        @ApiParam("缃戞牸缁刬d") @RequestParam groupId: Int,
+        @ApiParam("閬ユ祴鏁版嵁鏃堕棿")
+        @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") dateTime: LocalDateTime,
+        @ApiParam("瑕嗙洊鏃ф暟鎹� 0: 涓嶈鐩� 1: 瑕嗙洊") @RequestParam update: Boolean,
+        @RequestParam("excel") file: MultipartFile,
+    ) = resPack {
+        satelliteTelemetryService.importGridAOD(groupId, dateTime, update, file)
+    }
+
+    @ApiOperation(value = "涓嬭浇鍗槦閬ユ祴Aod缁撴灉鏁版嵁瀵煎叆妯℃澘")
+    @GetMapping("/import/grid/aod/download/template")
+    fun downloadAODTemplate(@ApiIgnore response: HttpServletResponse) = satelliteTelemetryService.downloadAODTemplate(response)
 }
\ No newline at end of file
diff --git a/src/main/resources/mapper/GridAodDetailMapper.xml b/src/main/resources/mapper/GridAodDetailMapper.xml
new file mode 100644
index 0000000..c860a3f
--- /dev/null
+++ b/src/main/resources/mapper/GridAodDetailMapper.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.flightfeather.uav.domain.mapper.GridAodDetailMapper">
+  <resultMap id="BaseResultMap" type="com.flightfeather.uav.domain.entity.GridAodDetail">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="aod_id" jdbcType="INTEGER" property="aodId" />
+    <result column="group_id" jdbcType="INTEGER" property="groupId" />
+    <result column="cell_id" jdbcType="INTEGER" property="cellId" />
+    <result column="aod" jdbcType="REAL" property="aod" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    id, aod_id, group_id, cell_id, aod
+  </sql>
+</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/GridAodMapper.xml b/src/main/resources/mapper/GridAodMapper.xml
new file mode 100644
index 0000000..48fb717
--- /dev/null
+++ b/src/main/resources/mapper/GridAodMapper.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.flightfeather.uav.domain.mapper.GridAodMapper">
+  <resultMap id="BaseResultMap" type="com.flightfeather.uav.domain.entity.GridAod">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="group_id" jdbcType="INTEGER" property="groupId" />
+    <result column="data_time" jdbcType="TIMESTAMP" property="dataTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    id, group_id, data_time
+  </sql>
+</mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/GridDataDetailMapper.xml b/src/main/resources/mapper/GridDataDetailMapper.xml
index 6312fe3..7574d75 100644
--- a/src/main/resources/mapper/GridDataDetailMapper.xml
+++ b/src/main/resources/mapper/GridDataDetailMapper.xml
@@ -18,4 +18,15 @@
     -->
     id, data_id, group_id, cell_id, PM25, rank
   </sql>
+
+  <!-- 娣诲姞鎵归噺鏇存柊PM25鐨勫嚱鏁� -->
+  <update id="updatePM25Batch" parameterType="java.util.List">
+    <foreach collection="list" item="item" separator=";">
+      UPDATE grid_data_detail
+      SET PM25 = #{item.pm25}
+      WHERE data_id = #{item.dataId}
+      AND group_id = #{item.groupId}
+      AND cell_id = #{item.cellId}
+    </foreach>
+  </update>
 </mapper>
\ No newline at end of file
diff --git a/src/main/resources/templates/GridData-AOD-Template.xlsx b/src/main/resources/templates/GridData-AOD-Template.xlsx
new file mode 100644
index 0000000..e75b413
--- /dev/null
+++ b/src/main/resources/templates/GridData-AOD-Template.xlsx
Binary files differ
diff --git a/src/main/resources/templates/GridData-PM2.5-Template.xlsx b/src/main/resources/templates/GridData-PM2.5-Template.xlsx
new file mode 100644
index 0000000..26054f7
--- /dev/null
+++ b/src/main/resources/templates/GridData-PM2.5-Template.xlsx
Binary files differ

--
Gitblit v1.9.3