From 016cb399ef5d81cb2b148add870289e011ca23ad Mon Sep 17 00:00:00 2001 From: duwenyuan <1351851645@qq.com> Date: Wed, 15 Oct 2025 15:13:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=95=B0=E6=8D=AE=E5=88=86?= =?UTF-8?q?=E6=9E=90=E6=9C=8D=E5=8A=A1=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DataAnalysisController.java | 130 +++++ .../mapper/GardsSampleStatAnalysisMapper.java | 225 ++++++++ .../xml/GardsSampleStatAnalysisMapper.xml | 534 ++++++++++++++++++ .../service/ISampleStatAnalysisService.java | 27 + .../impl/SampleStatAnalysisService.java | 432 ++++++++++++++ .../util/DistributionAnalysisToolkit.java | 288 ++++++++++ 6 files changed, 1636 insertions(+) create mode 100644 jeecg-module-data-analyze/src/main/java/org/jeecg/controller/DataAnalysisController.java create mode 100644 jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/GardsSampleStatAnalysisMapper.java create mode 100644 jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/xml/GardsSampleStatAnalysisMapper.xml create mode 100644 jeecg-module-data-analyze/src/main/java/org/jeecg/service/ISampleStatAnalysisService.java create mode 100644 jeecg-module-data-analyze/src/main/java/org/jeecg/service/impl/SampleStatAnalysisService.java create mode 100644 jeecg-module-data-analyze/src/main/java/org/jeecg/util/DistributionAnalysisToolkit.java diff --git a/jeecg-module-data-analyze/src/main/java/org/jeecg/controller/DataAnalysisController.java b/jeecg-module-data-analyze/src/main/java/org/jeecg/controller/DataAnalysisController.java new file mode 100644 index 0000000..cb8e3d2 --- /dev/null +++ b/jeecg-module-data-analyze/src/main/java/org/jeecg/controller/DataAnalysisController.java @@ -0,0 +1,130 @@ +package org.jeecg.controller; + + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.util.DateUtils; +import org.jeecg.service.ISampleStatAnalysisService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDate; +import java.util.Date; +import java.util.Objects; + +@RestController +@RequestMapping("dataAnalysis") +@Api(value = "数据分析", tags = "数据分析") +public class DataAnalysisController { + @Autowired + private ISampleStatAnalysisService sampleStatAnalysisService; + + /*** 样品监测结果回放 + * + * @param sampleType + * @param dataSource + * @param startDate + * @param endDate + * @return + */ + @GetMapping("/getSampleMonitorResult") + @ApiOperation(value = "样品监测结果回放", notes = "样品监测结果回放") + public Result getSampleMonitorResult(String sampleType, Integer dataSource, @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, + @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { + + return sampleStatAnalysisService.getSampleMonitorResult(sampleType, dataSource, startDate, endDate); + } + + /*** 样品统计分析 + * + * @param station + * @param dataSource + * @param startDate + * @param endDate + * @return + */ + @GetMapping("/getSampleStatAnalysis") + @ApiOperation(value = "样品统计分析", notes = "样品统计分析") + public Result getSampleStatAnalysis(String station, Integer dataSource, @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, + @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { + return sampleStatAnalysisService.getSampleStatAnalysis(station, dataSource, startDate, endDate); + + } + + /*** 样品等级时序分析 + * 样品等级时序分析 + * @param sampleType 样品类型 + * @param station 台站编码 + * @param dataSource 数据源 + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return 返回样品等级信息 + */ + @GetMapping("/getSampleGradeAnalysis") + @ApiOperation(value = "样品等级时序分析", notes = "样品等级时序分析") + public Result getSampleGradeAnalysis(String sampleType, String station, Integer dataSource, @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, + @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { + Result result = sampleStatAnalysisService.getSampleGradeAnalysis(sampleType, station, startDate, endDate, dataSource); + + return result; + } + + /*** 样品活度浓度区间频率分析 + * + * @param sampleType 样品类型-颗粒物、气体 + * @param station 台站编码 + * @param nuclideName 核素名称 + * @param dataSource 数据源 + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return 返回样品获取浓度区间信息 + */ + @GetMapping("/getActConcIntvlAnalysis") + @ApiOperation(value = "样品活度浓度区间频率分析", notes = "样品活度浓度区间频率分析") + public Result getSampleActConcIntvlAnalysis(String sampleType, String station, String nuclideName, Integer dataSource, @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, + @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { + + return sampleStatAnalysisService.getSampleActConcIntvlAnalysis(sampleType, station, nuclideName, dataSource, startDate, endDate); + } + + /*** 样品活度浓度时序分析 + * + * @param sampleType 样品类型-颗粒物、气体 + * @param station 台站编码 + * @param nuclideName 核素名称 + * @param dataSource 数据源 + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return 返回样品获取浓度时序信息 + */ + @GetMapping("/getActConcTimeSeqAnalysis") + @ApiOperation(value = "样品活度浓度时序分析", notes = "样品活度浓度时序分析") + public Result getSampleActConcTimeSeqAnalysis(String sampleType, String station, String nuclideName, Integer dataSource, @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, + @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { + return sampleStatAnalysisService.getSampleActConcTimeSeqAnalysis(sampleType, station, nuclideName, dataSource, startDate, endDate); + } + + /*** 核素活度浓度对比分析 + * + * @param sampleType + * @param stationIds + * @param nuclideName + * @param dataSource + * @param startDate + * @param endDate + * @return + */ + @GetMapping("/getNuclideActivityConcAnalyze") + @ApiOperation(value = "核素活度浓度对比分析", notes = "核素活度浓度对比分析") + public Result getNuclideActivityConcAnalyze(String sampleType, Integer[] stationIds, String nuclideName, Integer dataSource, @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, + @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { + return sampleStatAnalysisService.getNuclideActivityConcAnalyze(sampleType, stationIds, nuclideName, dataSource, startDate, endDate); + + } + +} diff --git a/jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/GardsSampleStatAnalysisMapper.java b/jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/GardsSampleStatAnalysisMapper.java new file mode 100644 index 0000000..438c9de --- /dev/null +++ b/jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/GardsSampleStatAnalysisMapper.java @@ -0,0 +1,225 @@ +package org.jeecg.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.jeecg.entity.*; +import org.jeecg.modules.base.entity.original.GardsSampleData; + +import java.util.List; + +@Mapper +public interface GardsSampleStatAnalysisMapper extends BaseMapper { + + List getSampleStatAnalysis(String station, String startDate, String endDate); + + List selectByStationIds(@Param("stationIds") List stationIds, @Param("startTime") String startTime, @Param("endTime") String endTime); + + //region 样品等级时序分析 + + + List getSampleGradeAnalysis(String sampleType, String station, + @Param("startTime") String startTime, @Param("endTime") String endTime, Integer dataSource); + + List getRnAutoSampleGradeAnalysis(String sampleType, String station, + @Param("startTime") String startTime, @Param("endTime") String endTime); + + List getRnManSampleGradeAnalysis(String sampleType, String station, + @Param("startTime") String startTime, @Param("endTime") String endTime); + + //endregion + + /*** 获取样品类型P中元素的浓度活度、MDC信息 + * 获取样品中元素的浓度活度、MDC信息 + * @param station 台站编码 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 返回List + */ + List getSamplePNuclideActConcIntvl(String station, @Param("startTime") String startTime, @Param("endTime") String endTime); + + //region 获取样品的级别和阈值 + + List getRnAutoSampleLevel(String station, @Param("startTime") String startTime, @Param("endTime") String endTime); + + List getRnManSampleLevel(String station, @Param("startTime") String startTime, @Param("endTime") String endTime); + + //endregion + + //region RNAUTO 获取样品中元素的浓度活度、MDC信息 + + /*** 获取样品中元素的浓度活度、MDC信息 + * 查询RNAUTO.GARDS_NUCL_IDED中的活度浓度、MDC信息 + * @param station 台站编码 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 返回List + */ + List getRnautoPNuclideActConcIntvl(String sampleType,String station,String nuclideName, @Param("startTime") String startTime, @Param("endTime") String endTime); + + /*** 获取样品中元素的浓度活度、MDC信息 + * 查询RNAUTO.GARDS_XE_RESULTS中的活度浓度、MDC信息 + * @param station + * @param startTime + * @param endTime + * @return + */ + List getRnautoNuclideActConcIntvl(String sampleType,String station,String nuclideName, @Param("startTime") String startTime, @Param("endTime") String endTime); + + + //endregion + + //region RNMAN 获取样品中元素的浓度活度、MDC信息 + + /*** 获取样品中元素的浓度活度、MDC信息 + * 查询RNAUTO.GARDS_NUCL_IDED中的活度浓度、MDC信息 + * @param station 台站编码 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 返回List + */ + List getRnmanPNuclideActConcIntvl(String sampleType,String station,String nuclideName, @Param("startTime") String startTime, @Param("endTime") String endTime); + + /*** 获取样品中元素的浓度活度、MDC信息 + * 查询RNAUTO.GARDS_XE_RESULTS中的活度浓度、MDC信息 + * @param station + * @param startTime + * @param endTime + * @return + */ + List getRnmanNuclideActConcIntvl(String sampleType,String station,String nuclideName, @Param("startTime") String startTime, @Param("endTime") String endTime); + + //endregion + + + //region 样品统计分析 + + /** + * RnAuto--获取样品中识别到的核素集合 + */ + + List getRnAutoIdentifiedNuclides(String station, @Param("startTime") String startTime, @Param("endTime") String endTime); + + /** + * RnAuto-- 核素等级时序分析 + */ + + List getRnAutoNuclideTimeSeriesAnalysis(String station, @Param("startTime") String startTime, @Param("endTime") String endTime); + + /** + * RnMan--获取样品中识别到的核素集合 + */ + List getRnManIdentifiedNuclides(String station, @Param("startTime") String startTime, @Param("endTime") String endTime); + + /** + * RnMan--核素等级时序分析 + * + * @return List + */ + List getRnManNuclideTimeSeriesAnalysis(String station, @Param("startTime") String startTime, @Param("endTime") String endTime); + + + + /** + * 精确查询(单个站点 + 单个核素) + * @param stationId 站点ID (必填) + * @param nuclideName 核素名称 (必填) + * @return 匹配的记录列表 + */ + List selectByStationAndNuclide( + @Param("schemaName") String schemaName, + @Param("stationId") Integer stationId, + @Param("nuclideName") String nuclideName, + @Param("startTime") String startTime, + @Param("endTime") String endTime + ); + + /** + * 多站点 + 多核素查询 + * @param stationIds 站点ID集合 (非空) + * @param nuclideNames 核素名称集合 (非空) + * @return 匹配的记录列表 + */ + List selectByStationsAndNuclides( + @Param("schemaName") String schemaName, + @Param("stationIds") List stationIds, + @Param("nuclideNames") List nuclideNames, + @Param("startTime") String startTime, + @Param("endTime") String endTime + ); + + /** + * 多站点 + 单核素查询 + * @param stationIds 站点ID集合 (非空) + * @param nuclideName 单个核素名称 (必填) + * @return 匹配的记录列表 + */ + List selectByStationsAndNuclide( + @Param("schemaName") String schemaName, + @Param("stationIds") List stationIds, + @Param("nuclideName") String nuclideName, + @Param("startTime") String startTime, + @Param("endTime") String endTime + ); + + /** + * 单站点 + 多核素查询 + * @param stationId 单个站点ID (必填) + * @param nuclideNames 核素名称集合 (非空) + * @return 匹配的记录列表 + */ + List selectByStationAndNuclides( + @Param("schemaName") String schemaName, + @Param("stationId") Integer stationId, + @Param("nuclideNames") List nuclideNames, + @Param("startTime") String startTime, + @Param("endTime") String endTime + + ); + + /** + * 动态条件查询(所有参数均可为空) + * @param stationIds 站点ID集合 (可选) + * @param nuclideNames 核素名称集合 (可选) + * @param startTime 开始时间 (可选) + * @param endTime 结束时间 (可选) + * @return 匹配的记录列表 + */ + List selectByCondition( + @Param("schemaName") String schemaName, + @Param("stationIds") List stationIds, + @Param("nuclideNames") List nuclideNames, + @Param("startTime") String startTime, + @Param("endTime") String endTime + ); + + + + + + + + + + + + //endregion + + + //region 核素活度浓度对比分析 + List getRnAutoAnalyzeNuclideActivityConc(String sampleType, String nuclideName, @Param("stationIds") Integer[] stationIds, @Param("startTime") String startTime, @Param("endTime") String endTime); + + List getRnManAnalyzeNuclideActivityConc(String sampleType, String nuclideName, @Param("stationIds") Integer[] stationIds, @Param("startTime") String startTime, @Param("endTime") String endTime); + //endregion + + //region 样品监测结果 + List getRnAutoSampleResult(String sampleType, @Param("startTime") String startTime, @Param("endTime") String endTime); + + List getRnManSampleResult(String sampleType, @Param("startTime") String startTime, @Param("endTime") String endTime); + + + + //endregion + + +} diff --git a/jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/xml/GardsSampleStatAnalysisMapper.xml b/jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/xml/GardsSampleStatAnalysisMapper.xml new file mode 100644 index 0000000..948020f --- /dev/null +++ b/jeecg-module-data-analyze/src/main/java/org/jeecg/mapper/xml/GardsSampleStatAnalysisMapper.xml @@ -0,0 +1,534 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jeecg-module-data-analyze/src/main/java/org/jeecg/service/ISampleStatAnalysisService.java b/jeecg-module-data-analyze/src/main/java/org/jeecg/service/ISampleStatAnalysisService.java new file mode 100644 index 0000000..8f49104 --- /dev/null +++ b/jeecg-module-data-analyze/src/main/java/org/jeecg/service/ISampleStatAnalysisService.java @@ -0,0 +1,27 @@ +package org.jeecg.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.jeecg.common.api.vo.Result; +import org.jeecg.modules.base.entity.original.GardsSampleData; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.Date; +import java.util.List; + +public interface ISampleStatAnalysisService extends IService { + + Result getSampleMonitorResult(String sampleType, Integer dataSource, Date startDate, Date endDate); + + Result getSampleStatAnalysis(String station, Integer dataSource, Date startDate, Date endDate); + + Result getSampleGradeAnalysis(String sampleType, String station, Date startDate, Date endDate, Integer dataSource); + + Result getSampleActConcIntvlAnalysis(String sampleType, String station, String nuclideName, Integer dataSource, Date startDate, Date endDate); + + + Result getSampleActConcTimeSeqAnalysis(String sampleType, String station, String nuclideName, Integer dataSource, Date startDate, Date endDate); + + Result getNuclideActivityConcAnalyze(String sampleType, Integer[] stationIds, String nuclideName, Integer dataSource, Date startDate, Date endDate); + +} diff --git a/jeecg-module-data-analyze/src/main/java/org/jeecg/service/impl/SampleStatAnalysisService.java b/jeecg-module-data-analyze/src/main/java/org/jeecg/service/impl/SampleStatAnalysisService.java new file mode 100644 index 0000000..fd781a8 --- /dev/null +++ b/jeecg-module-data-analyze/src/main/java/org/jeecg/service/impl/SampleStatAnalysisService.java @@ -0,0 +1,432 @@ +package org.jeecg.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.jeecg.common.api.vo.Result; +import org.jeecg.common.util.DateUtils; +import org.jeecg.entity.GardsThresholdResultHis; +import org.jeecg.modules.base.entity.original.GardsSampleData; +import org.jeecg.entity.NuclideActConcIntvl; +import org.jeecg.entity.SampleLevelData; +import org.jeecg.entity.StationInfoData; +import org.jeecg.mapper.GardsSampleStatAnalysisMapper; +import org.jeecg.service.ISampleStatAnalysisService; +import org.jeecg.util.DistributionAnalysisToolkit; +import org.springframework.stereotype.Service; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + + +@Service +@DS("ora") +public class SampleStatAnalysisService extends ServiceImpl implements ISampleStatAnalysisService { + + + public Result getSampleMonitorResult(String sampleType, Integer dataSource, Date startDate, Date endDate) { + Result result = new Result(); + //声明返回用的结果map + Map resultMap = new HashMap<>(); + List StationInfoDataList = new ArrayList<>(); + + //region 局部变量 + if (StringUtils.isBlank(sampleType)) { + result.error500("SampleType Code cannot be null"); + return result; + } + if (Objects.isNull(startDate)) { + result.error500("The start time cannot be empty"); + return result; + } + String startTime = DateUtils.formatDate(startDate, "yyyy-MM-dd") + " 00:00:00"; + if (Objects.isNull(endDate)) { + result.error500("The end time cannot be empty"); + return result; + } + String endTime = DateUtils.formatDate(endDate, "yyyy-MM-dd") + " 23:59:59"; + //endregion + + switch (dataSource) { + case 1: + StationInfoDataList = this.baseMapper.getRnAutoSampleResult(sampleType, startTime, endTime); + + break; + case 2: + StationInfoDataList = this.baseMapper.getRnManSampleResult(sampleType, startTime, endTime); + + break; + } + //时间段内有多少和台站 + + Map> groupedByMonth = StationInfoDataList.stream() + .collect(Collectors.groupingBy(station -> + station.getCollectStop().toInstant() + .atZone(ZoneId.of("UTC")) + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + )); + + + resultMap.put("SampleMonitorResultList", groupedByMonth); + + result.setSuccess(true); + result.setResult(resultMap); + + return result; + } + + + /*** 样品统计分析 + * 样品统计分析 + * @param stationCode + * @param startDate + * @param endDate + * @return + */ + @Override + public Result getSampleStatAnalysis(String stationCode, Integer dataSource, Date startDate, Date endDate) { + //声明返回用的结果map + Map resultMap = new HashMap<>(); + List nuclideActConcIntvlList = new ArrayList<>(); + List sampleLevelDataList = new ArrayList<>(); + List thresholdResultHisDataList = new ArrayList<>(); + + String schemaName = dataSource == 1 ? "RNAUTO" : "RNMAN"; + //region 局部变量 + Result result = new Result(); + if (StringUtils.isBlank(stationCode)) { + result.error500("Station Code cannot be null"); + return result; + } + if (Objects.isNull(startDate)) { + result.error500("The start time cannot be empty"); + return result; + } + String startTime = DateUtils.formatDate(startDate, "yyyy-MM-dd") + " 00:00:00"; + if (Objects.isNull(endDate)) { + result.error500("The end time cannot be empty"); + return result; + } + String endTime = DateUtils.formatDate(endDate, "yyyy-MM-dd") + " 23:59:59"; + //endregion + switch (dataSource) { + //RNAUTO + case 1: + //获取样品中识别到的核素集合 + nuclideActConcIntvlList = this.baseMapper.getRnAutoIdentifiedNuclides(stationCode, startTime, endTime); + + //核素等级时序分析 + sampleLevelDataList = this.baseMapper.getRnAutoNuclideTimeSeriesAnalysis(stationCode, startTime, endTime); + break; + //RNMAN + case 2: + //获取样品中识别到的核素集合 + nuclideActConcIntvlList = this.baseMapper.getRnManIdentifiedNuclides(stationCode, startTime, endTime); + + //核素等级时序分析 + sampleLevelDataList = this.baseMapper.getRnManNuclideTimeSeriesAnalysis(stationCode, startTime, endTime); + break; + } + //key=核素名称,value=获取样品中识别到的核素集合 + Map> groupedByNuclideName = nuclideActConcIntvlList.stream() + .filter(p->p.getNuclideName()!=null) + .collect(Collectors.groupingBy(NuclideActConcIntvl::getNuclideName)); + //查询级别 getSample + List nuclideNames = new ArrayList<>(groupedByNuclideName.keySet()); + //通过台站ID、核素名称查找阈值 + thresholdResultHisDataList = this.baseMapper.selectByStationAndNuclides(schemaName, Integer.valueOf(stationCode), nuclideNames, startTime, endTime); + + resultMap.put("nuclideActConcIntvlList", groupedByNuclideName); + resultMap.put("sampleLevelDataList", sampleLevelDataList); + resultMap.put("thresholdResultHisDataList", thresholdResultHisDataList); + result.setSuccess(true); + result.setResult(resultMap); + + return result; + } + + /** + * 获取指定时间范围内的样品等级 + * + * + */ + @Override + public Result getSampleGradeAnalysis(String sampleType, String station, Date startDate, Date endDate, Integer dataSource) { + + //声明返回用的结果map + Map resultMap = new HashMap<>(); + List sampleDataList = new ArrayList<>(); + //region 局部变量 + Result result = new Result(); + if (StringUtils.isBlank(sampleType)) { + result.error500("SampleType Code cannot be null"); + return result; + } + if (StringUtils.isBlank(station)) { + result.error500("Station Code cannot be null"); + return result; + } + if (Objects.isNull(startDate)) { + result.error500("The start time cannot be empty"); + return result; + } + String startTime = DateUtils.formatDate(startDate, "yyyy-MM-dd") + " 00:00:00"; + if (Objects.isNull(endDate)) { + result.error500("The end time cannot be empty"); + return result; + } + String endTime = DateUtils.formatDate(endDate, "yyyy-MM-dd") + " 23:59:59"; + //endregion + switch (dataSource) { + case 1: + sampleDataList = this.baseMapper.getRnAutoSampleGradeAnalysis(sampleType, station, startTime, endTime); + + break; + case 2: + sampleDataList = this.baseMapper.getRnManSampleGradeAnalysis(sampleType, station, startTime, endTime); + break; + + } + + resultMap.put("sampleDataList", sampleDataList); + result.setSuccess(true); + result.setResult(resultMap); + + + return result; + } + + /*** 样品活度浓度区间频率分析 + * 样品活度浓度区间频率分析 + * @param sampleType 样品类型 + * @param station 台站编码 + * @param nuclideName 核素名称 + * @param dataSource 数据源 + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return 返回样品活度浓度区间信息 + */ + @Override + public Result getSampleActConcIntvlAnalysis(String sampleType, String station, String nuclideName, Integer dataSource, Date startDate, Date endDate) { + //声明返回用的结果map + Map resultMap = new HashMap<>(); + List nuclideActConcIntvls = new ArrayList<>(); + //region 局部变量 + Result result = new Result(); + if (StringUtils.isBlank(sampleType)) { + result.error500("SampleType Code cannot be null"); + return result; + } + if (StringUtils.isBlank(nuclideName)) { + result.error500("nuclideName Code cannot be null"); + return result; + } + if (StringUtils.isBlank(station)) { + result.error500("Station Code cannot be null"); + return result; + } + if (Objects.isNull(startDate)) { + result.error500("The start time cannot be empty"); + return result; + } + String startTime = DateUtils.formatDate(startDate, "yyyy-MM-dd") + " 00:00:00"; + if (Objects.isNull(endDate)) { + result.error500("The end time cannot be empty"); + return result; + } + String endTime = DateUtils.formatDate(endDate, "yyyy-MM-dd") + " 23:59:59"; + //endregion + + //根据数据源、样品类型查询样品的浓度 + switch (sampleType) { + case "P": + switch (dataSource) { + //RNAUTO + case 1: + nuclideActConcIntvls = this.baseMapper.getRnautoPNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + break; + //RNMAN + case 2: + nuclideActConcIntvls = this.baseMapper.getRnautoNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + break; + } + break; + case "B": + switch (dataSource) { + case 1: + nuclideActConcIntvls = this.baseMapper.getRnmanPNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + break; + case 2: + nuclideActConcIntvls = this.baseMapper.getRnmanNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + break; + + } + break; + + } + + //获取浓度出现的次数 + //获取浓度值集合 + List data = DistributionAnalysisToolkit.convertConcToDoubleList(nuclideActConcIntvls); + // 设置区间参数 + double start = 0; // 区间起始值 + double step = 200; // 区间步长(宽度) + + + // 1. 区间统计 + List stats = DistributionAnalysisToolkit.calculateIntervalStats(data, start, step); + // 3. 累积分布函数 + List cdfPoints = DistributionAnalysisToolkit.calculateCDF(data); + // 4. 核密度估计 + List kdePoints = DistributionAnalysisToolkit.autoKDE(data, DistributionAnalysisToolkit.GAUSSIAN_KERNEL); + //获取所有浓度的累积 + List cumulative = DistributionAnalysisToolkit.cumulativeSum(data); + //获取95%累积线 + double percentile95 = DistributionAnalysisToolkit.calculate95thPercentile(data); + + resultMap.put("stats", stats); + resultMap.put("cdfPoints", cdfPoints); + resultMap.put("kdePoints", kdePoints); + resultMap.put("cumulative", cumulative); + resultMap.put("percentile95", percentile95); + result.setSuccess(true); + result.setResult(resultMap); + return result; + } + + /*** 核素活度浓度时序分析 + * 核素活度浓度时序分析 + * @param sampleType 样品类型 + * @param station 台站编码 + * @param nuclideName 核素名 + * @param dataSource 数据源 + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return 返回核素活度浓度信息 + */ + @Override + public Result getSampleActConcTimeSeqAnalysis(String sampleType, String station, String nuclideName, Integer dataSource, Date startDate, Date endDate) { + Result result = new Result(); + //声明返回用的结果map + Map resultMap = new HashMap<>(); + //region 局部变量 + + if (StringUtils.isBlank(sampleType)) { + result.error500("SampleType Code cannot be null"); + return result; + } + if (StringUtils.isBlank(nuclideName)) { + result.error500("nuclideName Code cannot be null"); + return result; + } + if (StringUtils.isBlank(station)) { + result.error500("Station Code cannot be null"); + return result; + } + if (Objects.isNull(startDate)) { + result.error500("The start time cannot be empty"); + return result; + } + String startTime = DateUtils.formatDate(startDate, "yyyy-MM-dd") + " 00:00:00"; + if (Objects.isNull(endDate)) { + result.error500("The end time cannot be empty"); + return result; + } + String endTime = DateUtils.formatDate(endDate, "yyyy-MM-dd") + " 23:59:59"; + //endregion + //获取样品阈值级别和阈值 + List sampleDatas = new ArrayList<>(); + //核素的阈值 + List thresholdResultHisList = new ArrayList<>(); + List nuclideActConcIntvls = new ArrayList<>(); + nuclideActConcIntvls = switch (sampleType) { + case "P" -> { + sampleDatas = this.baseMapper.getRnAutoSampleLevel(station, startTime, endTime); + yield switch (dataSource) { + //RNAUTO + case 1 -> + this.baseMapper.getRnautoPNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + //RNMAN + case 2 -> + this.baseMapper.getRnautoNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + default -> nuclideActConcIntvls; + }; + } + case "B" -> { + sampleDatas = this.baseMapper.getRnManSampleLevel(station, startTime, endTime); + yield switch (dataSource) { + case 1 -> + this.baseMapper.getRnmanPNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + case 2 -> + this.baseMapper.getRnmanNuclideActConcIntvl(sampleType, station, nuclideName, startTime, endTime); + default -> nuclideActConcIntvls; + }; + } + default -> nuclideActConcIntvls; + }; + String schemaName = dataSource == 1 ? "RNAUTO" : "RNMAN"; + + thresholdResultHisList = this.baseMapper.selectByCondition(schemaName, Arrays.asList(Integer.valueOf(station)) + , Arrays.asList(nuclideName), startTime, endTime); + resultMap.put("sampleDataList", sampleDatas); + resultMap.put("nuclideInfoList", nuclideActConcIntvls); + resultMap.put("thresholdResultHisList", thresholdResultHisList); + + result.setSuccess(true); + result.setResult(resultMap); + return result; + } + + /*** 核素活度浓度对比分析 + * 核素活度浓度对比分析 + * @param sampleType 样品类型 + * @param stationIds 台站ID集合 + * @param nuclideName 核素名 + * @param dataSource 数据源 + * @param startDate 开始时间 + * @param endDate 结束时间 + * @return + */ + public Result getNuclideActivityConcAnalyze(String sampleType, Integer[] stationIds, String nuclideName, Integer dataSource, Date startDate, Date endDate) { + + Result result = new Result(); + Map resultMap = new HashMap<>(); + List nuclideActConcIntvls = new ArrayList<>(); + //region 局部变量 + if (Objects.isNull(startDate)) { + result.error500("The start time cannot be empty"); + return result; + } + String startTime = DateUtils.formatDate(startDate, "yyyy-MM-dd") + " 00:00:00"; + if (Objects.isNull(endDate)) { + result.error500("The end time cannot be empty"); + return result; + } + String endTime = DateUtils.formatDate(endDate, "yyyy-MM-dd") + " 23:59:59"; + + if (Objects.isNull(stationIds)) { + result.setSuccess(true); + result.setResult(Collections.emptyList()); + return result; + } + //endregion + switch (dataSource) { + case 1: + nuclideActConcIntvls = this.baseMapper.getRnAutoAnalyzeNuclideActivityConc(sampleType, nuclideName, stationIds, startTime, endTime); + break; + case 2: + nuclideActConcIntvls = this.baseMapper.getRnManAnalyzeNuclideActivityConc(sampleType, nuclideName, stationIds, startTime, endTime); + break; + + } + resultMap.put("nuclideInfoList", nuclideActConcIntvls); + result.setSuccess(true); + result.setResult(resultMap); + + return result; + } + + +} diff --git a/jeecg-module-data-analyze/src/main/java/org/jeecg/util/DistributionAnalysisToolkit.java b/jeecg-module-data-analyze/src/main/java/org/jeecg/util/DistributionAnalysisToolkit.java new file mode 100644 index 0000000..28a3954 --- /dev/null +++ b/jeecg-module-data-analyze/src/main/java/org/jeecg/util/DistributionAnalysisToolkit.java @@ -0,0 +1,288 @@ +package org.jeecg.util; + +import org.jeecg.entity.NuclideActConcIntvl; + +import java.util.*; +import java.util.stream.Collectors; + +public class DistributionAnalysisToolkit { + /** + * 区间统计结果 + */ + public static class IntervalStat { + private final String interval; + private final int count; + private final List values; + + public IntervalStat(String interval, int count, List values) { + this.interval = interval; + this.count = count; + this.values = values; + } + + public String getInterval() { return interval; } + public int getCount() { return count; } + public List getValues() { return values; } + } + + /** + * KDE曲线点 + */ + public static class KDEPoint { + private final double x; + private final double density; + + public KDEPoint(double x, double density) { + this.x = x; + this.density = density; + } + + public double getX() { return x; } + public double getDensity() { return density; } + } + + /** + * CDF曲线点 + */ + public static class CDFPoint { + private final double value; + private final double cumulativeProb; + + public CDFPoint(double value, double cumulativeProb) { + this.value = value; + this.cumulativeProb = cumulativeProb; + } + + public double getValue() { return value; } + public double getCumulativeProb() { return cumulativeProb; } + } + /** + * 数据区间统计 + * + * @param data 原始数据 + * @param start 起始值 + * @param step 区间宽度 + * @return 区间统计结果列表 + */ + public static List calculateIntervalStats(List data, double start, double step) { + if (data == null || data.isEmpty()) { + throw new IllegalArgumentException("数据不能为空"); + } + + // 计算结束边界 + double max = Collections.max(data); + double end = Math.ceil(max / step) * step + step; + + // 初始化区间映射 + Map> intervalMap = new TreeMap<>(); + for (double lower = start; lower < end; lower += step) { + double upper = lower + step; + String key = String.format("[%.1f, %.1f)", lower, upper); + intervalMap.put(key, new ArrayList<>()); + } + + // 分配数据到区间 + for (double value : data) { + double lower = Math.floor(value / step) * step; + String key = String.format("[%.1f, %.1f)", lower, lower + step); + intervalMap.get(key).add(value); + } + + // 转换为统计结果对象 + List stats = new ArrayList<>(); + for (Map.Entry> entry : intervalMap.entrySet()) { + stats.add(new IntervalStat(entry.getKey(), entry.getValue().size(), entry.getValue())); + } + + return stats; + } + + + /** + * 计算95%累积线 + * + * @param data 原始数据 + * @return 95%累积线值 + */ + public static double calculate95thPercentile(List data) { + if (data == null || data.isEmpty()) { + throw new IllegalArgumentException("数据不能为空"); + } + + // 排序数据 + List sortedData = new ArrayList<>(data); + Collections.sort(sortedData); + + int n = sortedData.size(); + double position = 0.95 * (n - 1); + + int lowerIndex = (int) Math.floor(position); + int upperIndex = (int) Math.ceil(position); + + if (lowerIndex == upperIndex) { + return sortedData.get(lowerIndex); + } + + // 线性插值 + double lowerValue = sortedData.get(lowerIndex); + double upperValue = sortedData.get(upperIndex); + double fraction = position - lowerIndex; + + return lowerValue + fraction * (upperValue - lowerValue); + } + + + /** + * 计算累积分布函数(CDF) + * + * @param data 原始数据 + * @return CDF点列表 + */ + public static List calculateCDF(List data) { + if (data == null || data.isEmpty()) { + throw new IllegalArgumentException("数据不能为空"); + } + + // 排序数据 + List sortedData = new ArrayList<>(data); + Collections.sort(sortedData); + + // 计算累积分布 + List cdfPoints = new ArrayList<>(); + int n = sortedData.size(); + + for (int i = 0; i < n; i++) { + double value = sortedData.get(i); + double cumulativeProbability = (i + 1.0) / n; + cdfPoints.add(new CDFPoint(value, cumulativeProbability)); + } + + return cdfPoints; + } + + + + /** + * 核函数接口 + */ + @FunctionalInterface + public interface KernelFunction { + double apply(double u); + } + + // 常用核函数实现 + public static final KernelFunction GAUSSIAN_KERNEL = u -> Math.exp(-0.5 * u * u) / Math.sqrt(2 * Math.PI); + public static final KernelFunction EPANECHNIKOV_KERNEL = u -> (Math.abs(u) <= 1) ? 0.75 * (1 - u * u) : 0; + public static final KernelFunction TRIANGULAR_KERNEL = u -> (Math.abs(u) <= 1) ? 1 - Math.abs(u) : 0; + + + + /** + * 使用Silverman规则计算最佳带宽 + */ + public static double calculateBandwidthSilverman(List data) { + int n = data.size(); + if (n <= 1) return 1.0; + + // 计算标准差 + double mean = data.stream().mapToDouble(Double::doubleValue).average().orElse(0.0); + double variance = data.stream() + .mapToDouble(x -> Math.pow(x - mean, 2)) + .average() + .orElse(0.0); + double sigma = Math.sqrt(variance); + + // 计算四分位距(IQR) + List sortedData = new ArrayList<>(data); + Collections.sort(sortedData); + + double q1 = sortedData.get((int) Math.ceil(0.25 * n - 1)); + double q3 = sortedData.get((int) Math.ceil(0.75 * n - 1)); + double iqr = q3 - q1; + + // Silverman规则 + return 0.9 * Math.min(sigma, iqr / 1.34) * Math.pow(n, -0.2); + } + + /** + * 核密度估计 + */ + public static List kernelDensityEstimate( + List data, KernelFunction kernel, double bandwidth) { + + if (data == null || data.isEmpty()) { + throw new IllegalArgumentException("数据不能为空"); + } + + // 计算数据范围 + double min = Collections.min(data); + double max = Collections.max(data); + double range = max - min; + double minX = min - 0.1 * range; + double maxX = max + 0.1 * range; + + // 生成评估点 + int numPoints = 200; + double step = (maxX - minX) / (numPoints - 1); + + List kdePoints = new ArrayList<>(); + int n = data.size(); + + for (int i = 0; i < numPoints; i++) { + double x = minX + i * step; + double sum = 0.0; + + for (double value : data) { + double u = (x - value) / bandwidth; + sum += kernel.apply(u); + } + + double density = sum / (n * bandwidth); + kdePoints.add(new KDEPoint(x, density)); + } + + return kdePoints; + } + + /** + * 自动KDE计算(自动选择带宽) + */ + public static List autoKDE(List data, KernelFunction kernel) { + double bandwidth = calculateBandwidthSilverman(data); + return kernelDensityEstimate(data, kernel, bandwidth); + } + + + + //获取浓度值集合 + public static List convertConcToDoubleList(List nuclideList) { + return nuclideList.stream() // 创建流 + .map(NuclideActConcIntvl::getConc) // 提取conc值 + .collect(Collectors.toList()); // 收集为List + } + //累积和 + public static List cumulativeSum(List data) { + List result = new ArrayList<>(); + double sum = 0.0; + + for (double value : data) { + sum += value; + result.add(sum); + } + + return result; + } + + + + + + + + + + + + + +}