|  |  | 
 |  |  | package com.moral.api.service.impl; | 
 |  |  |  | 
 |  |  | import com.alibaba.fastjson.JSON; | 
 |  |  | import com.alibaba.fastjson.JSONArray; | 
 |  |  | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 
 |  |  | import com.moral.api.config.properties.SpecialCitiesProperties; | 
 |  |  | import com.moral.api.entity.CityAqi; | 
 |  |  | import com.moral.api.entity.CityAqiDaily; | 
 |  |  | import com.moral.api.entity.CityAqiYearly; | 
 |  |  | import com.moral.api.entity.SysArea; | 
 |  |  | import com.moral.api.mapper.CityAqiYearlyMapper; | 
 |  |  | import com.moral.api.pojo.dto.cityAQI.CityPollutionLevel; | 
 |  |  | import com.moral.api.pojo.dto.cityAQI.ComplianceDaysDTO; | 
 |  |  | import com.moral.api.pojo.dto.cityAQI.DataPercentRange; | 
 |  |  | import com.moral.api.pojo.vo.cityAQI.ComplianceDaysVO; | 
 |  |  | import com.moral.api.service.CityAqiDailyService; | 
 |  |  | import com.moral.api.service.CityAqiYearlyService; | 
 |  |  | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | 
 |  |  | import com.moral.api.service.SysAreaService; | 
 |  |  | import com.moral.constant.Constants; | 
 |  |  | import com.moral.util.AQIUtils; | 
 |  |  | import com.moral.util.AmendUtils; | 
 |  |  | import com.moral.util.DateUtils; | 
 |  |  | import com.moral.util.MathUtils; | 
 |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
 |  |  | import org.springframework.stereotype.Service; | 
 |  |  | import org.springframework.util.ObjectUtils; | 
 |  |  |  | 
 |  |  | import java.text.DateFormat; | 
 |  |  | import java.text.SimpleDateFormat; | 
 |  |  | import java.util.*; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * <p> | 
 |  |  | 
 |  |  | @Service | 
 |  |  | public class CityAqiYearlyServiceImpl extends ServiceImpl<CityAqiYearlyMapper, CityAqiYearly> implements CityAqiYearlyService { | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     CityAqiYearlyMapper cityAqiYearlyMapper; | 
 |  |  |     @Autowired | 
 |  |  |     SpecialCitiesProperties specialCitiesProperties; | 
 |  |  |     @Autowired | 
 |  |  |     SysAreaService sysAreaService; | 
 |  |  |     @Autowired | 
 |  |  |     CityAqiDailyService cityAqiDailyService; | 
 |  |  |  | 
 |  |  |     @Override | 
 |  |  |     public List<CityAqiYearly> getCityAqiYearlyByRegionCodeAndTime(Integer regionCode, Date startDate, Date endDate) { | 
 |  |  |         QueryWrapper<CityAqiYearly> queryWrapper = new QueryWrapper<>(); | 
 |  |  |         queryWrapper.eq("city_code", regionCode); | 
 |  |  |         queryWrapper.between("time", startDate, endDate); | 
 |  |  |         return cityAqiYearlyMapper.selectList(queryWrapper); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Override | 
 |  |  |     public Map<String, DataPercentRange> analysisPollutionLevel(String year, Integer cityCode) { | 
 |  |  |         //判断是否为今年,如果是今年则使用日数据进行查询,否则使用年数据 | 
 |  |  |         boolean thisYear = isThisYear(year); | 
 |  |  |         //获取开始结束时间 | 
 |  |  |         Date yearDate = DateUtils.getDate(year, "yyyy"); | 
 |  |  |         Date startDate = DateUtils.getFirstDayOfYear(yearDate); | 
 |  |  |         Date endDate; | 
 |  |  |         if (thisYear) | 
 |  |  |             endDate = DateUtils.addDays(new Date(), -1); | 
 |  |  |         else | 
 |  |  |             endDate = DateUtils.getLastDayOfYear(yearDate); | 
 |  |  |         //判断是否属于2+26城市 | 
 |  |  |         List<SysArea> twentyEightCities = null; | 
 |  |  |         if (specialCitiesProperties.isTwentyEightCities(cityCode)) | 
 |  |  |             twentyEightCities = specialCitiesProperties.getTwentyEightCities(); | 
 |  |  |         //判断是否属于河北通道城市 | 
 |  |  |         List<SysArea> heBeiEightCities = null; | 
 |  |  |         if (specialCitiesProperties.isHeBeiEightCities(cityCode)) | 
 |  |  |             heBeiEightCities = specialCitiesProperties.getHeBeiEightCities(); | 
 |  |  |         //获取市所在省的所有城市 | 
 |  |  |         //如果是直辖市则不需要排名 | 
 |  |  |         List<SysArea> cities = null; | 
 |  |  |         if (!cityCode.toString().substring(2).equals("0000")) { | 
 |  |  |             String provinceCode = cityCode.toString().substring(0, 2) + "0000"; | 
 |  |  |             cities = sysAreaService.getChildren(Integer.parseInt(provinceCode)); | 
 |  |  |         } | 
 |  |  |         //获取城市 | 
 |  |  |         SysArea city = sysAreaService.getAreaByCode(cityCode); | 
 |  |  |         //计算优良天数 | 
 |  |  |         DataPercentRange fineDays = calculateFineDays(cities, twentyEightCities, heBeiEightCities, startDate, endDate, city); | 
 |  |  |         //计算6参以及综合指数排名 | 
 |  |  |         Map<String, DataPercentRange> sixParamMap = calculateSixParam(thisYear, startDate, endDate, city, cities, twentyEightCities, heBeiEightCities); | 
 |  |  |         Map<String, DataPercentRange> result = new HashMap<>(); | 
 |  |  |         if (fineDays != null) | 
 |  |  |             result.put("fineDays", fineDays); | 
 |  |  |         if (sixParamMap != null) | 
 |  |  |             result.putAll(sixParamMap); | 
 |  |  |         if (result.size() == 0) | 
 |  |  |             return null; | 
 |  |  |         return result; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Override | 
 |  |  |     public List<ComplianceDaysDTO> analysisComplianceDays(String year, Integer cityCode) { | 
 |  |  |         List<ComplianceDaysDTO> dtos = new ArrayList<>(); | 
 |  |  |         //获取指定年份开始结束时间 | 
 |  |  |         Date posYear = DateUtils.getDate(year, "yyyy"); | 
 |  |  |         Date posYearStartDate = DateUtils.getFirstDayOfYear(posYear); | 
 |  |  |         Date posYearEndDate = DateUtils.getLastDayOfYear(posYear); | 
 |  |  |         //获取同比年份开始结束时间 | 
 |  |  |         String comYearStr = (Integer.parseInt(year)-1)+""; | 
 |  |  |         Date comYear = DateUtils.getDate(comYearStr,"yyyy"); | 
 |  |  |         Date comYearStartDate = DateUtils.getFirstDayOfYear(comYear); | 
 |  |  |         Date comYearEndDate = DateUtils.getLastDayOfYear(comYear); | 
 |  |  |         //查询指定年和同比年的数据 | 
 |  |  |         List<CityAqiDaily> posYearDatas = cityAqiDailyService.getCityAqiDailyByRegionCodeAndTime(cityCode, posYearStartDate, posYearEndDate); | 
 |  |  |         List<CityAqiDaily> comYearDatas = cityAqiDailyService.getCityAqiDailyByRegionCodeAndTime(cityCode, comYearStartDate, comYearEndDate); | 
 |  |  |         //计算指定年份最大月份 | 
 |  |  |         int month = maxMonth(posYearDatas); | 
 |  |  |         if(month==0) | 
 |  |  |             return dtos; | 
 |  |  |         //循环计算每个月的数据 | 
 |  |  |         for (int i = 1; i <= month; i++) { | 
 |  |  |             ComplianceDaysDTO dto = analysisComplianceDaysForMonth(posYearDatas, comYearDatas, i); | 
 |  |  |             dtos.add(dto); | 
 |  |  |         } | 
 |  |  |         return dtos; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //计算每个月的达标天数统计分析数据 | 
 |  |  |     private ComplianceDaysDTO analysisComplianceDaysForMonth(List<CityAqiDaily> posYearDatas, | 
 |  |  |                                                             List<CityAqiDaily> comYearDatas, | 
 |  |  |                                                             int month){ | 
 |  |  |         ComplianceDaysDTO dto = new ComplianceDaysDTO(); | 
 |  |  |         //取出指定月份数据 | 
 |  |  |         List<CityAqiDaily> posMonthDatas = new ArrayList<>(); | 
 |  |  |         List<CityAqiDaily> comMonthDatas = new ArrayList<>(); | 
 |  |  |         for (CityAqiDaily posYearData : posYearDatas) { | 
 |  |  |             Date time = posYearData.getTime(); | 
 |  |  |             if(DateUtils.getMonth(time)==month) | 
 |  |  |                 posMonthDatas.add(posYearData); | 
 |  |  |         } | 
 |  |  |         for (CityAqiDaily comYearData : comYearDatas) { | 
 |  |  |             Date time = comYearData.getTime(); | 
 |  |  |             if(DateUtils.getMonth(time)==month) | 
 |  |  |                 comMonthDatas.add(comYearData); | 
 |  |  |         } | 
 |  |  |         //计算指定年份对应的月份数据 | 
 |  |  |         for (CityAqiDaily posMonthData : posMonthDatas) { | 
 |  |  |             //获取数据 | 
 |  |  |             Map<String,String> dataMap = JSON.parseObject(posMonthData.getValue(),Map.class); | 
 |  |  |             String aqi = String.valueOf(dataMap.get("AQI")); | 
 |  |  |             String PM2_5 = String.valueOf(dataMap.get("PM2_5")); | 
 |  |  |             String PM10 = String.valueOf(dataMap.get("PM10")); | 
 |  |  |             String SO2 = String.valueOf(dataMap.get("SO2")); | 
 |  |  |             String NO2 = String.valueOf(dataMap.get("NO2")); | 
 |  |  |             String O3 = String.valueOf(dataMap.get("O3")); | 
 |  |  |             String CO = String.valueOf(dataMap.get("CO")); | 
 |  |  |             //判断aqi以及6因子是否达标 | 
 |  |  |             if(aqi!=null){ | 
 |  |  |                 if(AQIUtils.aqiIsStandard(Integer.parseInt(aqi))) | 
 |  |  |                     dto.setAqiComplianceDays(dto.getAqiComplianceDays()+1); | 
 |  |  |             } | 
 |  |  |             if(PM2_5!=null){ | 
 |  |  |                 if(!AQIUtils.PM2_5IsStandard(Double.parseDouble(PM2_5))) | 
 |  |  |                     dto.setPM2_5Days(dto.getPM2_5Days()+1); | 
 |  |  |             } | 
 |  |  |             if(PM10!=null){ | 
 |  |  |                 if(!AQIUtils.PM10IsStandard(Double.parseDouble(PM10))) | 
 |  |  |                     dto.setPM10Days(dto.getPM10Days()+1); | 
 |  |  |             } | 
 |  |  |             if(SO2!=null){ | 
 |  |  |                 if(!AQIUtils.SO2IsStandard(Double.parseDouble(SO2))) | 
 |  |  |                     dto.setSO2Days(dto.getSO2Days()+1); | 
 |  |  |             } | 
 |  |  |             if(NO2!=null){ | 
 |  |  |                 if(!AQIUtils.NO2IsStandard(Double.parseDouble(NO2))) | 
 |  |  |                     dto.setNO2Days(dto.getNO2Days()+1); | 
 |  |  |             } | 
 |  |  |             if(O3!=null){ | 
 |  |  |                 if(!AQIUtils.O3IsStandard(Double.parseDouble(O3))) | 
 |  |  |                     dto.setO3Days(dto.getO3Days()+1); | 
 |  |  |             } | 
 |  |  |             if(CO!=null){ | 
 |  |  |                 if(!AQIUtils.COIsStandard(Double.parseDouble(CO))) | 
 |  |  |                     dto.setCODays(dto.getCODays()+1); | 
 |  |  |             } | 
 |  |  |             //获取首要污染物 | 
 |  |  |             Object primaryPollutantO = dataMap.get("primaryPollutant"); | 
 |  |  |             if(primaryPollutantO!=null){ | 
 |  |  |                 JSONArray primaryPollutantArray = (JSONArray) primaryPollutantO; | 
 |  |  |                 List<String> primaryPollutant = JSON.parseObject(primaryPollutantArray.toJSONString(),List.class); | 
 |  |  |                 for (String s : primaryPollutant) { | 
 |  |  |                     if(s.equals("PM2.5")) | 
 |  |  |                         dto.setPM2_5FirstDays(dto.getPM2_5FirstDays()+1); | 
 |  |  |                     if(s.equals("PM10")) | 
 |  |  |                         dto.setPM10FirstDays(dto.getPM10FirstDays()+1); | 
 |  |  |                     if(s.equals("SO2")) | 
 |  |  |                         dto.setSO2FirstDays(dto.getSO2FirstDays()+1); | 
 |  |  |                     if(s.equals("NO2")) | 
 |  |  |                         dto.setNO2FirstDays(dto.getNO2FirstDays()+1); | 
 |  |  |                     if(s.equals("CO")) | 
 |  |  |                         dto.setCOFirstDays(dto.getCOFirstDays()+1); | 
 |  |  |                     if(s.equals("O3")) | 
 |  |  |                         dto.setO3FirstDays(dto.getO3FirstDays()+1); | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |         //计算同期对比数据 | 
 |  |  |         for (CityAqiDaily comMonthData : comMonthDatas) { | 
 |  |  |             //获取数据 | 
 |  |  |             Map<String,String> dataMap = JSON.parseObject(comMonthData.getValue(),Map.class); | 
 |  |  |             String aqi = String.valueOf(dataMap.get("AQI")); | 
 |  |  |             //判断aqi是否达标 | 
 |  |  |             if(aqi!=null){ | 
 |  |  |                 if(AQIUtils.aqiIsStandard(Integer.parseInt(aqi))) | 
 |  |  |                     dto.setComAqiComplianceDays(dto.getComAqiComplianceDays()+1); | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |         //计算指定年份和同期年份达标率 | 
 |  |  |         Double posAqiComplianceDays = Double.parseDouble(dto.getAqiComplianceDays()+""); | 
 |  |  |         Double posDays = Double.parseDouble(posMonthDatas.size()+""); | 
 |  |  |         Double comAqiComplianceDays = Double.parseDouble(dto.getComAqiComplianceDays()+""); | 
 |  |  |         Double comDays = Double.parseDouble(comMonthDatas.size()+""); | 
 |  |  |         if(posDays==0d) | 
 |  |  |             dto.setAqiCompliancePer(0d); | 
 |  |  |         else | 
 |  |  |             dto.setAqiCompliancePer(MathUtils.division(posAqiComplianceDays*100,posDays,2)); | 
 |  |  |  | 
 |  |  |         if(comDays==0d) | 
 |  |  |             dto.setComAqiCompliancePer(0d); | 
 |  |  |         else | 
 |  |  |             dto.setComAqiCompliancePer(MathUtils.division(comAqiComplianceDays*100,comDays,2)); | 
 |  |  |  | 
 |  |  |         dto.setMonth(month); | 
 |  |  |         return dto; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     //计算优良天数和同比以及省内,28城市,省内通道的排名。 | 
 |  |  |     private DataPercentRange calculateFineDays(List<SysArea> provinceCities, | 
 |  |  |                                                List<SysArea> twentyEightCities, | 
 |  |  |                                                List<SysArea> heBeiEightCities, | 
 |  |  |                                                Date startDate, | 
 |  |  |                                                Date endDate, | 
 |  |  |                                                SysArea city) { | 
 |  |  |         DataPercentRange dataPercentRange = new DataPercentRange(); | 
 |  |  |  | 
 |  |  |         //查询优良天气数 | 
 |  |  |         CityPollutionLevel cityPollutionLevel = cityAqiDailyService.calculateDaysByTimeAndSysArea(city, startDate, endDate); | 
 |  |  |         if (cityPollutionLevel == null) | 
 |  |  |             return null; | 
 |  |  |         Integer fineDays = cityPollutionLevel.getExcellentWeatherDays() + cityPollutionLevel.getGoodWeatherDays(); | 
 |  |  |         //计算同比数据 | 
 |  |  |         Date compareStartDate = DateUtils.addMonths(startDate, -12); | 
 |  |  |         Date compareEndDate = DateUtils.addMonths(endDate, -12); | 
 |  |  |         CityPollutionLevel cityPollutionLevelCompare = cityAqiDailyService.calculateDaysByTimeAndSysArea(city, compareStartDate, compareEndDate); | 
 |  |  |         String percent = null; | 
 |  |  |         if (cityPollutionLevelCompare != null) { | 
 |  |  |             Integer compareFineDays = cityPollutionLevelCompare.getExcellentWeatherDays() + cityPollutionLevelCompare.getGoodWeatherDays(); | 
 |  |  |             Integer percentInt = fineDays - compareFineDays; | 
 |  |  |             if (percentInt > 0) { | 
 |  |  |                 percent = "+" + percentInt + " 天"; | 
 |  |  |             } else { | 
 |  |  |                 percent = percentInt + " 天"; | 
 |  |  |             } | 
 |  |  |  | 
 |  |  |         } | 
 |  |  |         //计算省内排名 | 
 |  |  |         Integer provinceRange = null; | 
 |  |  |         if (provinceCities != null) | 
 |  |  |             provinceRange = calculateFineDaysRange(provinceCities, city, startDate, endDate); | 
 |  |  |         //计算2+26城市排名 | 
 |  |  |         Integer twentyEightRange = null; | 
 |  |  |         if (twentyEightCities != null) | 
 |  |  |             twentyEightRange = calculateFineDaysRange(twentyEightCities, city, startDate, endDate); | 
 |  |  |         //计算河北省内通道排名 | 
 |  |  |         Integer provinceChannelRange = null; | 
 |  |  |         if (heBeiEightCities != null) | 
 |  |  |             provinceChannelRange = calculateFineDaysRange(heBeiEightCities, city, startDate, endDate); | 
 |  |  |         dataPercentRange.setConcentration(fineDays + " 天"); | 
 |  |  |         dataPercentRange.setProvinceChannelRange(provinceChannelRange); | 
 |  |  |         dataPercentRange.setTwentyEightCitiesRange(twentyEightRange); | 
 |  |  |         dataPercentRange.setProvinceRange(provinceRange); | 
 |  |  |         dataPercentRange.setPercent(percent); | 
 |  |  |         return dataPercentRange; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     //计算六参以及综指平均浓度以及同比数据和排名情况 | 
 |  |  |     private Map<String, DataPercentRange> calculateSixParam(boolean thisYear, | 
 |  |  |                                                             Date startDate, | 
 |  |  |                                                             Date endDate, | 
 |  |  |                                                             SysArea city, | 
 |  |  |                                                             List<SysArea> provinceCities, | 
 |  |  |                                                             List<SysArea> twentyEightCities, | 
 |  |  |                                                             List<SysArea> heBeiEightCities) { | 
 |  |  |         Integer cityCode = city.getAreaCode(); | 
 |  |  |         Map<String, DataPercentRange> result = new HashMap<>(); | 
 |  |  |         //查询平均浓度,判断是否为今年,如果不是今年则用年数据进行计算,是今年则用天数据进行计算 | 
 |  |  |         Map<String, Double> concentration = getConcentration(thisYear, startDate, endDate, cityCode); | 
 |  |  |         if (concentration == null) | 
 |  |  |             return null; | 
 |  |  |         //查询同比数据 | 
 |  |  |         Date compareStartDate = DateUtils.addMonths(startDate, -12); | 
 |  |  |         Date compareEndDate = DateUtils.addMonths(endDate, -12); | 
 |  |  |         Map<String, Double> compareCentration = getConcentration(thisYear, compareStartDate, compareEndDate, cityCode); | 
 |  |  |         //计算6参以及综指同比结果 | 
 |  |  |         Map<String, String> compareResult = null; | 
 |  |  |         if (compareCentration != null) | 
 |  |  |             compareResult = calculateSixParamYOY(concentration, compareCentration); | 
 |  |  |         //计算省内排名 | 
 |  |  |         Map<String, Integer> provinceRangeResult = null; | 
 |  |  |         if (provinceCities != null) | 
 |  |  |             provinceRangeResult = sixParamRange(provinceCities, city, startDate, endDate, thisYear); | 
 |  |  |         //计算2+26排名 | 
 |  |  |         Map<String, Integer> twentyEightRangeResult = null; | 
 |  |  |         if (twentyEightCities != null) | 
 |  |  |             twentyEightRangeResult = sixParamRange(twentyEightCities, city, startDate, endDate, thisYear); | 
 |  |  |         //计算省内通道排名 | 
 |  |  |         Map<String, Integer> provinceChannelRangeResult = null; | 
 |  |  |         if (heBeiEightCities != null) | 
 |  |  |             provinceChannelRangeResult = sixParamRange(heBeiEightCities, city, startDate, endDate, thisYear); | 
 |  |  |         //封装返回数据 | 
 |  |  |         DataPercentRange pm2_5 = new DataPercentRange(); | 
 |  |  |         pm2_5.setConcentration(concentration.get("PM2_5").intValue() + " μg/m³"); | 
 |  |  |         DataPercentRange PM2_5 = packageSixParam(concentration, compareResult, provinceRangeResult, twentyEightRangeResult, provinceChannelRangeResult, "PM2_5", 0, "μg/m³"); | 
 |  |  |         DataPercentRange PM10 = packageSixParam(concentration, compareResult, provinceRangeResult, twentyEightRangeResult, provinceChannelRangeResult, "PM10", 0, "μg/m³"); | 
 |  |  |         DataPercentRange SO2 = packageSixParam(concentration, compareResult, provinceRangeResult, twentyEightRangeResult, provinceChannelRangeResult, "SO2", 0, "μg/m³"); | 
 |  |  |         DataPercentRange NO2 = packageSixParam(concentration, compareResult, provinceRangeResult, twentyEightRangeResult, provinceChannelRangeResult, "NO2", 0, "μg/m³"); | 
 |  |  |         DataPercentRange O3 = packageSixParam(concentration, compareResult, provinceRangeResult, twentyEightRangeResult, provinceChannelRangeResult, "O3", 0, "μg/m³"); | 
 |  |  |         DataPercentRange CO = packageSixParam(concentration, compareResult, provinceRangeResult, twentyEightRangeResult, provinceChannelRangeResult, "CO", 1, "mg/m³"); | 
 |  |  |         DataPercentRange compositeIndex = packageSixParam(concentration, compareResult, provinceRangeResult, twentyEightRangeResult, provinceChannelRangeResult, "compositeIndex", 3, ""); | 
 |  |  |         result.put("PM2_5", PM2_5); | 
 |  |  |         result.put("PM10", PM10); | 
 |  |  |         result.put("SO2", SO2); | 
 |  |  |         result.put("NO2", NO2); | 
 |  |  |         result.put("O3", O3); | 
 |  |  |         result.put("CO", CO); | 
 |  |  |         result.put("compositeIndex", compositeIndex); | 
 |  |  |         return result; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //打包六参以及综合指数数据对象 | 
 |  |  |     private DataPercentRange packageSixParam(Map<String, Double> concentration,//对应浓度/天数 | 
 |  |  |                                              Map<String, String> compareResult,//同比结果 | 
 |  |  |                                              Map<String, Integer> provinceRange,//省内排名 | 
 |  |  |                                              Map<String, Integer> twentyEightRange,//2+26排名 | 
 |  |  |                                              Map<String, Integer> heBeiEightCitiesRange,//省内通道排名 | 
 |  |  |                                              String sensor,//因子 | 
 |  |  |                                              int decimal,//保留小数位 | 
 |  |  |                                              String unit)//单位 | 
 |  |  |     { | 
 |  |  |         DataPercentRange data = new DataPercentRange(); | 
 |  |  |         if (decimal == 0) | 
 |  |  |             data.setConcentration(concentration.get(sensor).intValue() + " " + unit); | 
 |  |  |         else | 
 |  |  |             data.setConcentration(AmendUtils.sciCal(concentration.get(sensor), decimal) + " " + unit); | 
 |  |  |         if (compareResult != null) | 
 |  |  |             data.setPercent(compareResult.get(sensor)); | 
 |  |  |         if (provinceRange != null) | 
 |  |  |             data.setProvinceRange(provinceRange.get(sensor)); | 
 |  |  |         if (twentyEightRange != null) | 
 |  |  |             data.setTwentyEightCitiesRange(twentyEightRange.get(sensor)); | 
 |  |  |         if (heBeiEightCitiesRange != null) | 
 |  |  |             data.setProvinceChannelRange(heBeiEightCitiesRange.get(sensor)); | 
 |  |  |         return data; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //计算六参和综合指数排名 | 
 |  |  |     private Map<String, Integer> sixParamRange(List<SysArea> cities, SysArea posCity, Date startDate, Date endDate, boolean thisYear) { | 
 |  |  |         Map<String, Double> pm2_5Map = new HashMap<>(); | 
 |  |  |         Map<String, Double> pm10Map = new HashMap<>(); | 
 |  |  |         Map<String, Double> so2Map = new HashMap<>(); | 
 |  |  |         Map<String, Double> no2Map = new HashMap<>(); | 
 |  |  |         Map<String, Double> o3Map = new HashMap<>(); | 
 |  |  |         Map<String, Double> coMap = new HashMap<>(); | 
 |  |  |         Map<String, Double> compositeIndexMap = new HashMap<>(); | 
 |  |  |  | 
 |  |  |         for (SysArea city : cities) { | 
 |  |  |             Map<String, Double> concentration = getConcentration(thisYear, startDate, endDate, city.getAreaCode()); | 
 |  |  |             if (concentration == null) | 
 |  |  |                 continue; | 
 |  |  |             Object pm2_5o = concentration.get("PM2_5"); | 
 |  |  |             pm2_5Map.put(city.getAreaCode().toString(), Double.valueOf(pm2_5o.toString())); | 
 |  |  |  | 
 |  |  |             Object pm10o = concentration.get("PM10"); | 
 |  |  |             pm10Map.put(city.getAreaCode().toString(), Double.valueOf(pm10o.toString())); | 
 |  |  |  | 
 |  |  |             Object so2o = concentration.get("SO2"); | 
 |  |  |             so2Map.put(city.getAreaCode().toString(), Double.valueOf(so2o.toString())); | 
 |  |  |  | 
 |  |  |             Object no2o = concentration.get("NO2"); | 
 |  |  |             no2Map.put(city.getAreaCode().toString(), Double.valueOf(no2o.toString())); | 
 |  |  |  | 
 |  |  |             Object o3o = concentration.get("O3"); | 
 |  |  |             o3Map.put(city.getAreaCode().toString(), Double.valueOf(o3o.toString())); | 
 |  |  |  | 
 |  |  |             Object coo = concentration.get("CO"); | 
 |  |  |             coMap.put(city.getAreaCode().toString(), Double.valueOf(coo.toString())); | 
 |  |  |  | 
 |  |  |             Object concentrationo = concentration.get("compositeIndex"); | 
 |  |  |             compositeIndexMap.put(city.getAreaCode().toString(), Double.valueOf(concentrationo.toString())); | 
 |  |  |         } | 
 |  |  |         Map<String, Integer> result = new HashMap<>(); | 
 |  |  |         result.put("PM2_5", rangeMap(pm2_5Map, posCity.getAreaCode().toString())); | 
 |  |  |         result.put("SO2", rangeMap(so2Map, posCity.getAreaCode().toString())); | 
 |  |  |         result.put("NO2", rangeMap(no2Map, posCity.getAreaCode().toString())); | 
 |  |  |         result.put("CO", rangeMap(coMap, posCity.getAreaCode().toString())); | 
 |  |  |         result.put("O3", rangeMap(o3Map, posCity.getAreaCode().toString())); | 
 |  |  |         result.put("PM10", rangeMap(pm10Map, posCity.getAreaCode().toString())); | 
 |  |  |         result.put("compositeIndex", rangeMap(compositeIndexMap, posCity.getAreaCode().toString())); | 
 |  |  |         return result; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //根域map的value进行升序排序,获取排名 | 
 |  |  |     private Integer rangeMap(Map<String, Double> map, String cityCode) { | 
 |  |  |         Set<Map.Entry<String, Double>> entries = map.entrySet(); | 
 |  |  |         List<Map.Entry<String, Double>> list = new ArrayList<>(entries); | 
 |  |  |         list.sort(Comparator.comparing(value -> value.getValue())); | 
 |  |  |         for (Map.Entry<String, Double> entry : list) { | 
 |  |  |             if (cityCode.equals(entry.getKey())) | 
 |  |  |                 return list.indexOf(entry) + 1; | 
 |  |  |         } | 
 |  |  |         return null; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     //计算六参和综合指数同期对比结果 | 
 |  |  |     private Map<String, String> calculateSixParamYOY(Map<String, Double> dataMap, Map<String, Double> compareDataMap) { | 
 |  |  |         Map<String, String> result = new HashMap<>(); | 
 |  |  |  | 
 |  |  |         Double pm2_5 = calculateSensorYOY(dataMap, compareDataMap, "PM2_5"); | 
 |  |  |         if (pm2_5 != null) | 
 |  |  |             result.put("PM2_5", pm2_5.intValue() > 0 ? "+" + pm2_5.intValue() + " μg/m³" : pm2_5.intValue() + " μg/m³"); | 
 |  |  |  | 
 |  |  |         Double pm10 = calculateSensorYOY(dataMap, compareDataMap, "PM10"); | 
 |  |  |         if (pm10 != null) | 
 |  |  |             result.put("PM10", pm10.intValue() > 0 ? "+" + pm10.intValue() + " μg/m³" : pm10.intValue() + " μg/m³"); | 
 |  |  |  | 
 |  |  |         Double so2 = calculateSensorYOY(dataMap, compareDataMap, "SO2"); | 
 |  |  |         if (so2 != null) | 
 |  |  |             result.put("SO2", so2.intValue() > 0 ? "+" + so2.intValue() + " μg/m³" : so2.intValue() + " μg/m³"); | 
 |  |  |  | 
 |  |  |  | 
 |  |  |         Double no2 = calculateSensorYOY(dataMap, compareDataMap, "NO2"); | 
 |  |  |         if (no2 != null) | 
 |  |  |             result.put("NO2", no2.intValue() > 0 ? "+" + no2.intValue() + " μg/m³" : no2.intValue() + " μg/m³"); | 
 |  |  |  | 
 |  |  |  | 
 |  |  |         Double o3 = calculateSensorYOY(dataMap, compareDataMap, "O3"); | 
 |  |  |         if (o3 != null) | 
 |  |  |             result.put("O3", o3.intValue() > 0 ? "+" + o3.intValue() + " μg/m³" : o3.intValue() + " μg/m³"); | 
 |  |  |  | 
 |  |  |  | 
 |  |  |         Double co = calculateSensorYOY(dataMap, compareDataMap, "CO"); | 
 |  |  |         if (co != null) { | 
 |  |  |             co = AmendUtils.sciCal(co, 1); | 
 |  |  |             result.put("CO", co.intValue() > 0 ? "+" + co.intValue() + " mg/m³" : co.intValue() + " mg/m³"); | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         //计算综合指数同比数据 | 
 |  |  |         Object compositeIndexO = dataMap.get("compositeIndex"); | 
 |  |  |         Object compareCompositeIndexO = compareDataMap.get("compositeIndex"); | 
 |  |  |         Double compositeIndex = Double.valueOf(compositeIndexO.toString()); | 
 |  |  |         Double compareCompositeIndex = Double.valueOf(compareCompositeIndexO.toString()); | 
 |  |  |         if (compositeIndex != null && compareCompositeIndex != null) { | 
 |  |  |             Double compareResult = MathUtils.division(compositeIndex - compareCompositeIndex, compareCompositeIndex, 3); | 
 |  |  |             compareResult = MathUtils.mul(compareResult, 100); | 
 |  |  |             result.put("compositeIndex", compareResult > 0 ? "+" + compareResult + " %" : compareResult + " %"); | 
 |  |  |         } | 
 |  |  |         if (result.size() != 7) | 
 |  |  |             return null; | 
 |  |  |  | 
 |  |  |         return result; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //计算单因子同比结果 | 
 |  |  |     private Double calculateSensorYOY(Map<String, Double> dataMap, Map<String, Double> compareDataMap, String sensor) { | 
 |  |  |         Object dataO = dataMap.get(sensor); | 
 |  |  |         Double data = Double.valueOf(dataO.toString()); | 
 |  |  |  | 
 |  |  |         Object cdataO = compareDataMap.get(sensor); | 
 |  |  |         Double compareData = Double.valueOf(cdataO.toString()); | 
 |  |  |         if (data != null && compareData != null) | 
 |  |  |             return data - compareData; | 
 |  |  |         return null; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //获取城市对应时间的6参以及综合指数均值 | 
 |  |  |     private Map<String, Double> getConcentration(boolean thisYear, Date startDate, Date endDate, Integer cityCode) { | 
 |  |  |         if (thisYear) { | 
 |  |  |             List<CityAqiDaily> cityAqiDailies = cityAqiDailyService.getCityAqiDailyByRegionCodeAndTime(cityCode, startDate, endDate); | 
 |  |  |             if (ObjectUtils.isEmpty(cityAqiDailies)) | 
 |  |  |                 return null; | 
 |  |  |             return calculate6ParamAvg(cityAqiDailies); | 
 |  |  |         } else { | 
 |  |  |             List<CityAqiYearly> cityAqiYearlies = getCityAqiYearlyByRegionCodeAndTime(cityCode, startDate, endDate); | 
 |  |  |             if (ObjectUtils.isEmpty(cityAqiYearlies)) | 
 |  |  |                 return null; | 
 |  |  |             CityAqiYearly cityAqiYearly = cityAqiYearlies.get(0); | 
 |  |  |             return JSON.parseObject(cityAqiYearly.getValue(), Map.class); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //计算6参以及综合指数平均值 | 
 |  |  |     private Map<String, Double> calculate6ParamAvg(List<CityAqiDaily> cityAqiList) { | 
 |  |  |         Double co = calculatePercent(cityAqiList, "CO", 95); | 
 |  |  |         Double pm2_5 = calculateSensorAvg(cityAqiList, "PM2_5"); | 
 |  |  |         Double pm10 = calculateSensorAvg(cityAqiList, "PM10"); | 
 |  |  |         Double so2 = calculateSensorAvg(cityAqiList, "SO2"); | 
 |  |  |         Double no2 = calculateSensorAvg(cityAqiList, "NO2"); | 
 |  |  |         Double o3 = calculatePercent(cityAqiList, "O3", 90); | 
 |  |  |         Double compositeIndex = calculateSensorAvg(cityAqiList, "compositeIndex"); | 
 |  |  |         Map<String, Double> result = new HashMap<>(); | 
 |  |  |         result.put("CO", co); | 
 |  |  |         result.put("NO2", no2); | 
 |  |  |         result.put("SO2", so2); | 
 |  |  |         result.put("O3", o3); | 
 |  |  |         result.put("PM2_5", pm2_5); | 
 |  |  |         result.put("PM10", pm10); | 
 |  |  |         result.put("compositeIndex", compositeIndex); | 
 |  |  |         return result; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //计算因子的平均值 | 
 |  |  |     private Double calculateSensorAvg(List<CityAqiDaily> cityAqiList, String sensor) { | 
 |  |  |         Double sum = 0d; | 
 |  |  |         int num = 0; | 
 |  |  |         for (CityAqiDaily cityAqi : cityAqiList) { | 
 |  |  |             String value = cityAqi.getValue(); | 
 |  |  |             if (value == null) | 
 |  |  |                 continue; | 
 |  |  |             Map<String, Object> valueMap = JSON.parseObject(value, Map.class); | 
 |  |  |             Object sensorValueObject = valueMap.get(sensor); | 
 |  |  |             if (sensorValueObject == null) | 
 |  |  |                 continue; | 
 |  |  |             Double sensorValue = Double.valueOf(sensorValueObject.toString()); | 
 |  |  |             sum = MathUtils.add(sum, sensorValue); | 
 |  |  |             num++; | 
 |  |  |         } | 
 |  |  |         if (num == 0) | 
 |  |  |             return null; | 
 |  |  |         Double avg = MathUtils.division(sum, num, 2); | 
 |  |  |         return avg; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //计算百分位 | 
 |  |  |     private Double calculatePercent(List<CityAqiDaily> cityAqiList, String sensor, int percent) { | 
 |  |  |         List<Double> datas = new ArrayList<>(); | 
 |  |  |         for (CityAqiDaily cityAqi : cityAqiList) { | 
 |  |  |             String value = cityAqi.getValue(); | 
 |  |  |             if (value == null) | 
 |  |  |                 continue; | 
 |  |  |             Map<String, Object> valueMap = JSON.parseObject(value, Map.class); | 
 |  |  |             Object sensorValueObject = valueMap.get(sensor); | 
 |  |  |             if (sensorValueObject == null) | 
 |  |  |                 continue; | 
 |  |  |             Double sensorValue = Double.valueOf(sensorValueObject.toString()); | 
 |  |  |             datas.add(sensorValue); | 
 |  |  |         } | 
 |  |  |         if (datas.size() == 0) | 
 |  |  |             return null; | 
 |  |  |         datas.sort(Comparator.comparing(value -> value)); | 
 |  |  |         Double avg = AmendUtils.percentile(datas, percent); | 
 |  |  |         return avg; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //计算优良天数排名 | 
 |  |  |     private Integer calculateFineDaysRange(List<SysArea> cities, SysArea posCity, Date startDate, Date endDate) { | 
 |  |  |         List<CityPollutionLevel> result = new ArrayList<>(); | 
 |  |  |         for (SysArea city : cities) { | 
 |  |  |             CityPollutionLevel cityPollutionLevel = cityAqiDailyService.calculateDaysByTimeAndSysArea(city, startDate, endDate); | 
 |  |  |             result.add(cityPollutionLevel); | 
 |  |  |         } | 
 |  |  |         //排序 | 
 |  |  |         result.sort(Comparator.comparing(value -> value.getGoodWeatherDays() + value.getExcellentWeatherDays())); | 
 |  |  |         //倒序排名 | 
 |  |  |         Collections.reverse(result); | 
 |  |  |         for (CityPollutionLevel value : result) { | 
 |  |  |             if (value.getRegionName().equals(posCity.getAreaName())) | 
 |  |  |                 return result.indexOf(value); | 
 |  |  |         } | 
 |  |  |         return null; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //判断是否为今年 | 
 |  |  |     private boolean isThisYear(String year) { | 
 |  |  |         return DateUtils.dateToDateString(new Date(), "yyyy").equals(year); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     //查询数据集合最大月份 | 
 |  |  |     private int maxMonth( List<CityAqiDaily> datas){ | 
 |  |  |         int i = 0; | 
 |  |  |         for (CityAqiDaily data : datas) { | 
 |  |  |             Date time = data.getTime(); | 
 |  |  |             int month = DateUtils.getMonth(time); | 
 |  |  |             if(month>i) | 
 |  |  |                 i = month; | 
 |  |  |         } | 
 |  |  |         return i; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  | } |