| | |
| | | // 返回乡镇和街道名称组合 |
| | | return address.township |
| | | } |
| | | |
| | | /** |
| | | * 数据清洗 |
| | | * 1. 修复由于硬件设备卡顿导致的数据采样时间不变问题,采用自动累加数据周期的方式修改采样时间 |
| | | * @param data 原始数据列表 |
| | | * @param period 数据周期,单位:秒 |
| | | * @return 清洗后需要修改的数据列表 |
| | | */ |
| | | fun dataClean(dataList: List<BaseRealTimeData>, period: Long): List<BaseRealTimeData> { |
| | | val cleanedData = mutableListOf<BaseRealTimeData>() |
| | | var errorData: BaseRealTimeData? = null |
| | | dataList.forEachIndexed { index, data -> |
| | | if (index == 0) { |
| | | return@forEachIndexed |
| | | } |
| | | val lastOne = dataList[index - 1] |
| | | if (errorData == null) { |
| | | if (data.dataTime!!.time == lastOne.dataTime!!.time) { |
| | | data.dataTime?.time = lastOne.dataTime?.time!!.plus(period * 1000) |
| | | cleanedData.add(data) |
| | | errorData = lastOne |
| | | } |
| | | } else { |
| | | if (data.dataTime!!.time == errorData!!.dataTime!!.time) { |
| | | data.dataTime?.time = lastOne.dataTime?.time!!.plus(period * 1000) |
| | | cleanedData.add(data) |
| | | } else { |
| | | errorData = null |
| | | } |
| | | } |
| | | } |
| | | return cleanedData |
| | | } |
| | | } |
| | |
| | | // 走航清单信息 |
| | | class MissionInfo : Mission() { |
| | | // 首要污染物 |
| | | var mainFactor: String? = null |
| | | // var mainFactor: String? = null |
| | | |
| | | // 监测异常因子 |
| | | var abnormalFactors: List<FactorType>? = null |
| | |
| | | val missionInfo = MissionInfo() |
| | | BeanUtils.copyProperties(mission, missionInfo) |
| | | missionInfo.apply { |
| | | mainFactor = factorMap.maxByOrNull { it.value }?.key?.name |
| | | // mainFactor = factorMap.maxByOrNull { it.value }?.key?.name |
| | | this.abnormalFactors = abnormalFactors |
| | | this.sceneCount = sceneCount |
| | | } |
| | |
| | | val missionInfo = MissionInfo() |
| | | BeanUtils.copyProperties(mission, missionInfo) |
| | | missionInfo.apply { |
| | | mainFactor = factorMap.maxByOrNull { it.value }?.key?.name |
| | | // mainFactor = factorMap.maxByOrNull { it.value }?.key?.name |
| | | this.abnormalFactors = abnormalFactors |
| | | this.sceneCount = sceneCount |
| | | this.scenes = scenes |
| | |
| | | @Column(name = "end_time") |
| | | private Date endTime; |
| | | |
| | | /** |
| | | * 数据是否已经拉取入库 |
| | | */ |
| | | @Column(name = "data_pulled") |
| | | private Boolean dataPulled; |
| | | |
| | |
| | | private Float kilometres; |
| | | |
| | | /** |
| | | * 所属区域 |
| | | * 走航围绕主要区域 |
| | | */ |
| | | private String region; |
| | | |
| | | /** |
| | | * 走航围绕中心区域半径,公里 |
| | | */ |
| | | private Float radius; |
| | | |
| | | /** |
| | | * 空气质量等级 |
| | |
| | | @Column(name = "pollution_degree") |
| | | private String pollutionDegree; |
| | | |
| | | /** |
| | | * 空气质量等级指数AQI |
| | | */ |
| | | private Integer aqi; |
| | | |
| | | /** |
| | | * 首要污染因子 |
| | | */ |
| | | @Column(name = "main_factor") |
| | | private String mainFactor; |
| | | |
| | | /** |
| | | * @return mission_code |
| | |
| | | } |
| | | |
| | | /** |
| | | * @return data_pulled |
| | | * 获取数据是否已经拉取入库 |
| | | * |
| | | * @return data_pulled - 数据是否已经拉取入库 |
| | | */ |
| | | public Boolean getDataPulled() { |
| | | return dataPulled; |
| | | } |
| | | |
| | | /** |
| | | * @param dataPulled |
| | | * 设置数据是否已经拉取入库 |
| | | * |
| | | * @param dataPulled 数据是否已经拉取入库 |
| | | */ |
| | | public void setDataPulled(Boolean dataPulled) { |
| | | this.dataPulled = dataPulled; |
| | |
| | | } |
| | | |
| | | /** |
| | | * 获取所属区域 |
| | | * 获取走航围绕主要区域 |
| | | * |
| | | * @return region - 所属区域 |
| | | * @return region - 走航围绕主要区域 |
| | | */ |
| | | public String getRegion() { |
| | | return region; |
| | | } |
| | | |
| | | /** |
| | | * 设置所属区域 |
| | | * 设置走航围绕主要区域 |
| | | * |
| | | * @param region 所属区域 |
| | | * @param region 走航围绕主要区域 |
| | | */ |
| | | public void setRegion(String region) { |
| | | this.region = region == null ? null : region.trim(); |
| | | } |
| | | |
| | | /** |
| | | * 获取走航围绕中心区域半径,公里 |
| | | * |
| | | * @return radius - 走航围绕中心区域半径,公里 |
| | | */ |
| | | public Float getRadius() { |
| | | return radius; |
| | | } |
| | | |
| | | /** |
| | | * 设置走航围绕中心区域半径,公里 |
| | | * |
| | | * @param radius 走航围绕中心区域半径,公里 |
| | | */ |
| | | public void setRadius(Float radius) { |
| | | this.radius = radius; |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | /** |
| | | * @return aqi |
| | | * 获取空气质量等级指数AQI |
| | | * |
| | | * @return aqi - 空气质量等级指数AQI |
| | | */ |
| | | public Integer getAqi() { |
| | | return aqi; |
| | | } |
| | | |
| | | /** |
| | | * @param aqi |
| | | * 设置空气质量等级指数AQI |
| | | * |
| | | * @param aqi 空气质量等级指数AQI |
| | | */ |
| | | public void setAqi(Integer aqi) { |
| | | this.aqi = aqi; |
| | | } |
| | | |
| | | /** |
| | | * 获取首要污染因子 |
| | | * |
| | | * @return main_factor - 首要污染因子 |
| | | */ |
| | | public String getMainFactor() { |
| | | return mainFactor; |
| | | } |
| | | |
| | | /** |
| | | * 设置首要污染因子 |
| | | * |
| | | * @param mainFactor 首要污染因子 |
| | | */ |
| | | public void setMainFactor(String mainFactor) { |
| | | this.mainFactor = mainFactor == null ? null : mainFactor.trim(); |
| | | } |
| | | } |
| | |
| | | return delegate.insertByDeviceType(deviceType, type, data) |
| | | } |
| | | |
| | | fun updateData(deviceType: UWDeviceType?, data: List<BaseRealTimeData>, type: Int? = 0): Int { |
| | | return delegate.updateByDeviceType(deviceType, type, data) |
| | | } |
| | | |
| | | fun deleteData(mission: Mission, type: Int? = 0): Int { |
| | | if (mission.deviceCode == null || mission.startTime == null || mission.endTime == null) { |
| | | throw BizException("要删除的走航任务缺失设备编号或采样时间范围,无法删除对应监测数据") |
| | |
| | | } |
| | | |
| | | /** |
| | | * 统一的update方法 |
| | | * @param deviceType 设备类型 |
| | | * @param type 数据统计周期,0:秒级值;1:分钟值 |
| | | * @param data 数据 |
| | | */ |
| | | fun updateByDeviceType(deviceType: UWDeviceType?, type: Int? = 0, data: List<BaseRealTimeData>): Int { |
| | | return byDeviceType(deviceType, type, { |
| | | var count = 0 |
| | | data.forEach { count += realTimeDataVehicleMapper.updateByPrimaryKeySelective(it as RealTimeDataVehicle) } |
| | | count |
| | | }, { |
| | | var count = 0 |
| | | data.forEach { count += realTimeDataUavMapper.updateByPrimaryKeySelective(it as RealTimeDataUav) } |
| | | count |
| | | }, { |
| | | var count = 0 |
| | | data.forEach { count += realTimeDataGridMapper.updateByPrimaryKeySelective(it as RealTimeDataGrid) } |
| | | count |
| | | }, { |
| | | var count = 0 |
| | | data.forEach { count += realTimeDataGridMinMapper.updateByPrimaryKeySelective(it as RealTimeDataGridMin) } |
| | | count |
| | | }) ?: 0 |
| | | } |
| | | |
| | | /** |
| | | * 统一的delete方法 |
| | | * @param deviceType 设备类型 |
| | | * @param type 数据统计周期,0:秒级值;1:分钟值 |
| | |
| | | */ |
| | | fun generateMissionSummary(startTime: Date, endTime: Date, areaVo: AreaVo): MissionSummary.Summary |
| | | |
| | | fun generateMissionSummary(missionCode: String): MissionSummary.Summary |
| | | |
| | | /** |
| | | * 生成走航任务清单(按时间和区域筛选) |
| | | * 根据时间范围和地理区域查询走航任务,并生成包含统计信息的任务列表 |
| | |
| | | fun generateMissionDetail(startTime: Date, endTime: Date, areaVo: AreaVo): List<MissionDetail> |
| | | |
| | | /** |
| | | * 生成走航任务详情(按任务编号筛选) |
| | | * 根据任务编号查询并生成详细的任务报告,包含任务完整信息、场景数据和统计结果 |
| | | * @param missionCode 任务编号,用于唯一标识特定的走航任务 |
| | | * @return 任务详情对象,包含任务完整信息、场景数据和统计结果 |
| | | */ |
| | | fun generateMissionDetail(missionCode: String): MissionDetail |
| | | |
| | | /** |
| | | * 获取走航任务详情(直接处理任务数据) |
| | | * 处理已有的任务、污染线索和实时数据,生成详细任务报告 |
| | | * @param keyScenes 关键场景列表,用于分析走航是否经过该区域 |
| | |
| | | |
| | | fun generateClueByRiskArea(startTime: Date, endTime: Date, areaVo: AreaVo): List<MissionRiskArea.ClueByArea> |
| | | |
| | | fun generateClueByRiskArea(missionCode: String): List<MissionRiskArea.ClueByArea> |
| | | |
| | | fun generateClueByRiskArea(keyScenes: List<SceneInfo?>, pollutedClues: List<PollutedClue?>): List<MissionRiskArea.ClueByArea> |
| | | |
| | | fun generateGridFusion(factorTypes: List<FactorType>, startTime: Date, endTime: Date, areaVo: AreaVo): |
| | |
| | | return summary |
| | | } |
| | | |
| | | override fun generateMissionSummary(missionCode: String): MissionSummary.Summary { |
| | | val mission = missionRep.findOne(missionCode) ?: throw BizException("走航任务不存在") |
| | | val clues = sourceTraceRep.fetchList(mission.deviceCode, mission.startTime, mission.endTime, MsgType.PolClue) as List<PollutedClue?> |
| | | val summary = MissionSummary().execute(mission.startTime, mission.endTime, listOf(mission), clues) |
| | | return summary |
| | | } |
| | | |
| | | /** |
| | | * 生成走航任务清单(按时间和区域筛选) |
| | | * 根据时间范围和行政区划查询走航任务,并关联污染线索数据生成任务列表 |
| | |
| | | return generateMissionDetail(keyScenes, missionCluesData) |
| | | } |
| | | |
| | | override fun generateMissionDetail(missionCode: String): MissionInventory.MissionDetail { |
| | | val mission = missionRep.findOne(missionCode) ?: throw BizException("任务不存在") |
| | | val missionClues = sourceTraceRep.fetchList(mission.deviceCode, mission.startTime, mission.endTime, MsgType.PolClue) as List<PollutedClue?> |
| | | val realTimeData = realTimeDataRep.fetchData(mission) |
| | | val keyScenes = sceneInfoRep.findBySceneTypes( |
| | | listOf( |
| | | SceneType.TYPE19.value, |
| | | SceneType.TYPE20.value, |
| | | SceneType.TYPE21.value |
| | | ) |
| | | ) |
| | | return MissionInventory().generateMissionDetail(keyScenes, mission, missionClues, realTimeData) |
| | | } |
| | | |
| | | /** |
| | | * 生成走航任务详情(直接处理任务数据) |
| | | * 接收已关联的任务-污染线索-实时数据三元组,生成详细任务报告 |
| | |
| | | return generateClueByRiskArea(keyScenes, clues) |
| | | } |
| | | |
| | | override fun generateClueByRiskArea(missionCode: String): List<MissionRiskArea.ClueByArea> { |
| | | val mission = missionRep.findOne(missionCode) ?: throw BizException("任务不存在") |
| | | val pollutedClues = sourceTraceRep.fetchList(mission.deviceCode, mission.startTime, mission.endTime, MsgType.PolClue) as List<PollutedClue?> |
| | | val keyScenes = sceneInfoRep.findBySceneTypes( |
| | | listOf( |
| | | SceneType.TYPE19.value, |
| | | SceneType.TYPE20.value, |
| | | SceneType.TYPE21.value |
| | | ) |
| | | ) |
| | | return generateClueByRiskArea(keyScenes, pollutedClues) |
| | | } |
| | | |
| | | override fun generateClueByRiskArea( |
| | | keyScenes: List<SceneInfo?>, |
| | | pollutedClues: List<PollutedClue?>, |
| | |
| | | ) |
| | | } |
| | | |
| | | @ApiOperation(value = "生成走航任务汇总统计") |
| | | @GetMapping("/report/missionSummary/one") |
| | | fun generateOneMissionSummary( |
| | | @ApiParam("任务编号") @RequestParam missionCode: String, |
| | | ) = resPack { dataAnalysisService.generateMissionSummary(missionCode) } |
| | | |
| | | @ApiOperation(value = "生成走航任务清单") |
| | | @PostMapping("/report/missionList") |
| | | fun generateMissionList( |
| | |
| | | ) |
| | | } |
| | | |
| | | @ApiOperation(value = "生成走航任务详情") |
| | | @GetMapping("/report/missionDetail/one") |
| | | fun generateOneMissionDetail( |
| | | @ApiParam("任务编号") @RequestParam missionCode: String, |
| | | ) = resPack { dataAnalysisService.generateMissionDetail(missionCode) } |
| | | |
| | | @ApiOperation(value = "走航典型隐患区域统计") |
| | | @PostMapping("/report/clueByRiskArea") |
| | | fun generateClueByRiskArea( |
| | |
| | | ) |
| | | } |
| | | |
| | | @ApiOperation(value = "走航典型隐患区域统计") |
| | | @GetMapping("/report/clueByRiskArea/one") |
| | | fun generateOneClueByRiskArea( |
| | | @ApiParam("任务编号") @RequestParam missionCode: String, |
| | | ) = resPack { dataAnalysisService.generateClueByRiskArea(missionCode) } |
| | | |
| | | @ApiOperation(value = "叠加融合分析") |
| | | @PostMapping("/report/gridFusion") |
| | | fun generateGridFusion( |
| | |
| | | <property name="suppressAllComments" value="true"/> |
| | | </commentGenerator> |
| | | <!--数据库链接URL,用户名、密码 --> |
| | | <!-- <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://47.100.191.150:3306/dronemonitor?serverTimezone=Asia/Shanghai"--> |
| | | <!-- userId="remoteU1"--> |
| | | <!-- password="eSoF8DnzfGTlhAjE">--> |
| | | <!-- </jdbcConnection>--> |
| | | <jdbcConnection driverClass="com.mysql.jdbc.Driver" |
| | | connectionURL="jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai" |
| | | userId="root" |
| | | password="123456"> |
| | | <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://47.100.191.150:3306/dronemonitor?serverTimezone=Asia/Shanghai" |
| | | userId="remoteU1" |
| | | password="eSoF8DnzfGTlhAjE"> |
| | | </jdbcConnection> |
| | | <!-- <jdbcConnection driverClass="com.mysql.jdbc.Driver"--> |
| | | <!-- connectionURL="jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai"--> |
| | | <!-- userId="root"--> |
| | | <!-- password="123456">--> |
| | | <!-- </jdbcConnection>--> |
| | | <javaTypeResolver> |
| | | <property name="forceBigDecimals" value="false"/> |
| | | </javaTypeResolver> |
| | |
| | | <result column="town_name" jdbcType="VARCHAR" property="townName" /> |
| | | <result column="kilometres" jdbcType="REAL" property="kilometres" /> |
| | | <result column="region" jdbcType="VARCHAR" property="region" /> |
| | | <result column="radius" jdbcType="REAL" property="radius" /> |
| | | <result column="pollution_degree" jdbcType="VARCHAR" property="pollutionDegree" /> |
| | | <result column="aqi" jdbcType="INTEGER" property="aqi" /> |
| | | <result column="main_factor" jdbcType="VARCHAR" property="mainFactor" /> |
| | | </resultMap> |
| | | <sql id="Base_Column_List"> |
| | | <!-- |
| | |
| | | --> |
| | | mission_code, device_type, device_code, start_time, end_time, data_pulled, province_code, |
| | | province_name, city_code, city_name, district_code, district_name, town_code, town_name, |
| | | kilometres, region, pollution_degree, aqi |
| | | kilometres, region, radius, pollution_degree, aqi, main_factor |
| | | </sql> |
| | | </mapper> |
| | |
| | | import com.flightfeather.uav.common.utils.MapUtil |
| | | import com.flightfeather.uav.domain.repository.MissionRep |
| | | import com.flightfeather.uav.domain.repository.RealTimeDataRep |
| | | import com.flightfeather.uav.socket.eunm.UWDeviceType |
| | | import org.junit.Test |
| | | import org.junit.runner.RunWith |
| | | import org.springframework.beans.factory.annotation.Autowired |
| | | import org.springframework.boot.test.context.SpringBootTest |
| | | import org.springframework.test.context.junit4.SpringRunner |
| | | |
| | | //@RunWith(SpringRunner::class) |
| | | //@SpringBootTest |
| | | @RunWith(SpringRunner::class) |
| | | @SpringBootTest |
| | | class MissionUtilTest { |
| | | |
| | | // @Autowired |
| | | @Autowired |
| | | lateinit var missionRep: MissionRep |
| | | |
| | | // @Autowired |
| | | @Autowired |
| | | lateinit var realTimeDataRep: RealTimeDataRep |
| | | |
| | | @Test |
| | | fun calKilometres() { |
| | | // val m = missionRep.findOne("20250819") ?: return |
| | | // val data = realTimeDataRep.fetchData(m) |
| | | // MissionUtil.calKilometres(data) |
| | | val d = MapUtil.getDistance(121.425187, 31.225907, 121.425196, 31.225892) |
| | | println(d) |
| | | val d1 = MapUtil.getDistance(121.425196, 31.225892, 121.425187, 31.225907) |
| | | println(d1) |
| | | val m = missionRep.findOne("20250819") ?: return |
| | | val data = realTimeDataRep.fetchData(m) |
| | | MissionUtil.calKilometres(data) |
| | | // val d = MapUtil.getDistance(121.425187, 31.225907, 121.425196, 31.225892) |
| | | // println(d) |
| | | // val d1 = MapUtil.getDistance(121.425196, 31.225892, 121.425187, 31.225907) |
| | | // println(d1) |
| | | } |
| | | |
| | | @Test |
| | | fun dataClean() { |
| | | val m = missionRep.findOne("SH-CN-20250411") ?: return |
| | | val data = realTimeDataRep.fetchData(m) |
| | | val cleanedData = MissionUtil.dataClean(data, 4) |
| | | realTimeDataRep.updateData(UWDeviceType.fromValue(m.deviceType), cleanedData) |
| | | println(cleanedData.size) |
| | | } |
| | | } |
| | |
| | | // "SH-CN-20240723(02)", |
| | | //// "SH-CN-20250723(01)" |
| | | // ) |
| | | val startTime = LocalDateTime.of(2025, 7, 1, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant() |
| | | val endTime = LocalDateTime.of(2025, 9, 30, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant() |
| | | // val startTime = LocalDateTime.of(2024, 12, 31, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant() |
| | | val startTime = LocalDateTime.of(2024, 12, 4, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant() |
| | | val endTime = LocalDateTime.of(2025, 4, 11, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant() |
| | | val missions = missionMapper.selectByExample(Example(Mission::class.java).apply { |
| | | createCriteria().andBetween("startTime", startTime, endTime) |
| | | }) |
| | |
| | | // "SH-CN-20240723(02)", |
| | | //// "SH-CN-20250723(01)" |
| | | // ) |
| | | val startTime = LocalDateTime.of(2025, 7, 1, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant() |
| | | val endTime = LocalDateTime.of(2025, 9, 30, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant() |
| | | val startTime = LocalDateTime.of(2024, 12, 4, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant() |
| | | val endTime = LocalDateTime.of(2025, 4, 11, 23, 59, 59).atZone(ZoneId.systemDefault()).toInstant() |
| | | val missions = missionMapper.selectByExample(Example(Mission::class.java).apply { |
| | | createCriteria().andBetween("startTime", startTime, endTime) |
| | | }) |