jinpengyong
2023-10-18 cc120d54e26f64753e99b349599875cf6911a0af
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
package com.moral.api.service.impl;
 
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.moral.api.config.properties.AnnouncementProperties;
import com.moral.api.config.properties.SpecialCitiesProperties;
import com.moral.api.entity.CityAqiDaily;
import com.moral.api.entity.CityAqiMonthly;
import com.moral.api.entity.SysArea;
import com.moral.api.mapper.CityAqiMonthlyMapper;
import com.moral.api.service.CityAqiDailyService;
import com.moral.api.service.CityAqiMonthlyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moral.api.service.SysAreaService;
import com.moral.constant.Constants;
import com.moral.constant.RedisConstants;
import com.moral.util.AmendUtils;
import com.moral.util.ComprehensiveIndexUtils;
import com.moral.util.DateUtils;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
 
import java.text.DecimalFormat;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
 
/**
 * <p>
 * 城市aqi月数据表 服务实现类
 * </p>
 *
 * @author moral
 * @since 2021-11-05
 */
@Service
public class CityAqiMonthlyServiceImpl extends ServiceImpl<CityAqiMonthlyMapper, CityAqiMonthly> implements CityAqiMonthlyService {
 
    @Autowired
    private CityAqiMonthlyMapper cityAqiMonthlyMapper;
 
    @Autowired
    private SpecialCitiesProperties specialCitiesProperties;
 
    @Autowired
    private SysAreaService sysAreaService;
 
    @Autowired
    private CityAqiDailyService cityAqiDailyService;
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    @Autowired
    private AnnouncementProperties announcementProperties;
 
    @Override
    public List<CityAqiMonthly> getCityAqiMonthByRegionCodeAndTime(Integer regionCode, Date startDate, Date endDate) {
        QueryWrapper<CityAqiMonthly> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("city_code", regionCode);
        queryWrapper.between("time", startDate, endDate);
        return cityAqiMonthlyMapper.selectList(queryWrapper);
    }
 
    @Override
    public CityAqiMonthly getCityAqiMonthByRegionCodeAndTime(Integer regionCode, Date time) {
        time = DateUtils.getFirstDayOfMonth(time);
        QueryWrapper<CityAqiMonthly> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("city_code", regionCode);
        queryWrapper.eq("time", time);
        return cityAqiMonthlyMapper.selectOne(queryWrapper);
    }
 
    @Override
    public Map<String, Object> airQualityRankingAnnouncement(Integer regionCode, Date time) {
        Map<String, Object> result = new LinkedHashMap<>();
        String month = DateUtils.getMonth(time) + "";
        int yearMonthOfSelect = Integer.parseInt(DateUtils.dateToDateString(time, DateUtils.yyyyMM_EN));
        int nowYearMonthOfSelect = Integer.parseInt(DateUtils.getCurDate(DateUtils.yyyyMM_EN));
 
        if (yearMonthOfSelect > nowYearMonthOfSelect) {
            return result;
        }
 
        //先根据时间和地区code从redis中获取,没有再计算后存入redis
        result = (Map<String, Object>) redisTemplate.opsForValue().get(RedisConstants.AQI_ANNOUNCEMENT + "_" + regionCode + "_" + DateUtils.dateToDateString(time, DateUtils.yyyyMM_EN));
        if (result != null) {
            return result;
        }
 
        result = new LinkedHashMap<>();
        //获取xx市和所有县市区名字信息
        QueryWrapper<SysArea> sysAreaQueryWrapper = new QueryWrapper<>();
        sysAreaQueryWrapper.select("area_code", "area_name")
                .eq("parent_code", regionCode).or()
                .eq("area_code", regionCode);
        List<SysArea> sysAreas = sysAreaService.list(sysAreaQueryWrapper);
        Map<Integer, String> areasMap = new HashMap<>();
        for (SysArea sysArea : sysAreas) {
            areasMap.put(sysArea.getAreaCode(), sysArea.getAreaName());
        }
        String cityName = areasMap.remove(regionCode);
        result.put("cityName", cityName);
        result.put("areaSize", areasMap.size());
 
        //一、空气质量排名
        //1.本月xx市空气质量排名
        Map<String, Object> currentRankingResult = new HashMap<>();
 
        //获取本月xx市空气质量数据
        QueryWrapper<CityAqiMonthly> cityAqiMonthlyQueryWrapper = new QueryWrapper<>();
        cityAqiMonthlyQueryWrapper.select("value")
                .eq("city_code", regionCode)
                .eq("time", time);
        CityAqiMonthly cityAqiMonthly = cityAqiMonthlyMapper.selectOne(cityAqiMonthlyQueryWrapper);
        Double compositeIndex = null;
        String compositeIndexYearOnYear = null;
        Double pm25 = null;
        String pm25YearOnYear = null;
        if (cityAqiMonthly != null) {
            Map<String, Object> aqiMap = JSONObject.parseObject(cityAqiMonthly.getValue(), Map.class);
 
            //1.综指
            if (aqiMap.get("compositeIndex") != null) {
                compositeIndex = Double.parseDouble(aqiMap.get("compositeIndex").toString());
            }
            currentRankingResult.put("compositeIndex", compositeIndex);
 
            //2.综指同比
            if (aqiMap.get("compositeIndex_yearOnYear") != null) {
                compositeIndexYearOnYear = aqiMap.get("compositeIndex_yearOnYear").toString();
            }
            currentRankingResult.put("compositeIndex_yearOnYear", compositeIndexYearOnYear);
 
            //3.PM2.5浓度
            if (aqiMap.get("PM2_5") != null) {
                pm25 = Objects.nonNull(aqiMap.get("PM2_5"))?Double.parseDouble(aqiMap.get("PM2_5").toString()):0d;
            }
            currentRankingResult.put("PM2_5", pm25 + "ug/m³");
 
            //4.PM.5浓度同比
            if (aqiMap.get("PM2_5_yearOnYear") != null) {
                pm25YearOnYear = aqiMap.get("PM2_5_yearOnYear").toString();
            }
            currentRankingResult.put("PM2_5_yearOnYear", pm25YearOnYear);
 
            //5.168城市排名,包括综指,综指同比,pm2.5,pm2.5同比
            Map<String, Object> ranking168 = getOneSixEightCitiesRanking(regionCode, time);
            currentRankingResult.putAll(ranking168);
 
            //6.2+26城市排名,包括综指,综指同比,pm2.5,pm2.5同比
            Map<String, Object> ranking28 = getTwentyEightCitiesRanking(regionCode, time);
            currentRankingResult.putAll(ranking28);
 
            //7.河北八通道城市排名,包括综指,综指同比,pm2.5,pm2.5同比
            Map<String, Object> ranking8Channels = getHeBeiEightCitiesRanking(regionCode, time);
            currentRankingResult.putAll(ranking8Channels);
        }
 
 
        String start = DateUtils.dateToDateString(time, DateUtils.yyyy_MM_dd_CN);
        //本月最后一日
        String end = DateUtils.dateToDateString(DateUtils.getLastDayOfMonth(time), DateUtils.yyyy_MM_dd_CN);
        result.put("currentRanking", aqiQualityRankingResponse(start + "-" + end, cityName, currentRankingResult));
 
 
        //2.1-x月xx市空气质量排名
        //所有县市区codes
        List<Integer> areaCodes = new ArrayList<>(areasMap.keySet());
        //地级市code
        areaCodes.add(regionCode);
        Map<Integer, Map<String, Object>> monthlyCumulativeResult = null;
        Double cityCompositeIndex = null;
        String cityCompositeIndexYearOnYear = null;
        Double cityPM25 = null;
        String cityPM25YearOnYear = null;
        if (!"1".equals(month)) {
            Map<String, Object> cumulativeRankingResult = new HashMap<>();
 
            //获取xx市和下属所有县市区1-xx月数据
            monthlyCumulativeResult = getMonthlyCumulativeResult(time, areaCodes);
            //xx市数据
 
            if (monthlyCumulativeResult != null) {
                Map<String, Object> cityMap = monthlyCumulativeResult.remove(regionCode);
                if (cityMap != null) {
                    //地级市综指
                    cityCompositeIndex = Double.parseDouble(cityMap.get("compositeIndex").toString());
                    if (cityMap.get("compositeIndex_yearOnYear") != null) {
                        cityCompositeIndexYearOnYear = cityMap.get("compositeIndex_yearOnYear").toString();
                    }
                    //地级市PM2.5
                    cityPM25 = Double.parseDouble(cityMap.get("PM2_5").toString());
                    if (cityMap.get("PM2_5_yearOnYear") != null) {
                        cityPM25YearOnYear = cityMap.get("PM2_5_yearOnYear").toString();
                    }
                }
            }
 
            cumulativeRankingResult.put("compositeIndex", cityCompositeIndex);
            cumulativeRankingResult.put("compositeIndex_yearOnYear", cityCompositeIndexYearOnYear);
            cumulativeRankingResult.put("PM2_5", cityPM25);
            if (cityPM25 != null) {
                cumulativeRankingResult.put("PM2_5", cityPM25 + "ug/m³");
            }
            cumulativeRankingResult.put("PM2_5_yearOnYear", cityPM25YearOnYear);
 
            //5.168城市排名,包括综指,综指同比,pm2.5,pm2.5同比
            Map<String, Object> ranking168 = getOneSixEightCitiesRankingOfCumulative(regionCode, time);
            cumulativeRankingResult.putAll(ranking168);
 
            //6.2+26城市排名,包括综指,综指同比,pm2.5,pm2.5同比
            Map<String, Object> ranking28 = getTwentyEightCitiesRankingOfCumulative(regionCode, time);
            cumulativeRankingResult.putAll(ranking28);
 
            //7.河北八通道城市排名,包括综指,综指同比,pm2.5,pm2.5同比
            Map<String, Object> ranking8Channels = getHeBeiEightCitiesRankingOfCumulative(regionCode, time);
            cumulativeRankingResult.putAll(ranking8Channels);
            //开始时间,当年1月1日
            start = DateUtils.dateToDateString(DateUtils.getFirstDayOfYear(time), DateUtils.yyyy_MM_dd_CN);
            //结束时间,当月最后一天
            end = DateUtils.dateToDateString(DateUtils.getLastDayOfMonth(time), DateUtils.yyyy_MM_dd_CN);
            result.put("cumulativeRanking", aqiQualityRankingResponse(start + "-" + end, cityName, cumulativeRankingResult));
        }
 
 
        //二、各县市区空气质量情况结果集
        //获取本期xx市下所有县市区数据
        cityAqiMonthlyQueryWrapper.clear();
        areaCodes.remove(regionCode);
        cityAqiMonthlyQueryWrapper.select("city_code", "value")
                .eq("time", time)
                .in("city_code", areaCodes);
        List<CityAqiMonthly> areaData = cityAqiMonthlyMapper.selectList(cityAqiMonthlyQueryWrapper);
 
        //获取本期所有县市区与中心城区(地级市)因子对比情况
        Map<String, Object> areaCurrentMonthResult = getAreaCurrentMonthResult(areasMap, areaData, compositeIndex, compositeIndexYearOnYear, pm25, pm25YearOnYear);
 
 
        //本月县市区综指与中心城区对比
        result.put("currentCompositeIndexContrast", compositeIndexContrastResponse(month, cityName, areaCodes.size(), areaCurrentMonthResult));
        //本月县市区综指同比与中心城区对比
        result.put("currentCompositeIndexYearOnYearContrast", compositeIndexYearOnYearContrastResponse(month, cityName, areaCodes.size(), areaCurrentMonthResult));
        //本月县市区PM2.5与中心城区对比
        result.put("currentPM25Contrast", pm25tContrastResponse(month, cityName, areaCodes.size(), areaCurrentMonthResult));
        //本月县市区Pm2.5同比与中心城区对比
        result.put("currentPM25YearOnYearContrast", pm25YearOnYearContrastResponse(month, cityName, areaCodes.size(), areaCurrentMonthResult));
 
        //三、1-x月累计结果
        List<CityAqiMonthly> cumulativeList = null;
        if (!"1".equals(month)) {
            cumulativeList = new ArrayList<>();
            if (monthlyCumulativeResult != null) {
                for (Map.Entry<Integer, Map<String, Object>> entry : monthlyCumulativeResult.entrySet()) {
                    CityAqiMonthly cityAqiMonthly1 = new CityAqiMonthly();
                    cityAqiMonthly1.setCityCode(entry.getKey());
                    cityAqiMonthly1.setValue(JSONObject.toJSONString(entry.getValue()));
                    cumulativeList.add(cityAqiMonthly1);
                }
            }
 
            month = "1-" + DateUtils.getMonth(time);
            //获取1-x月所有县市区与地级市数据对比情况
            Map<String, Object> monthlyCumulativeListResultMap = getAreaCurrentMonthResult(areasMap, cumulativeList, cityCompositeIndex, cityCompositeIndexYearOnYear, cityPM25, cityPM25YearOnYear);
            //1-xx月份县市区综指与中心城区对比
            result.put("cumulativeCompositeIndexContrast", compositeIndexContrastResponse(month, cityName, areaCodes.size(), monthlyCumulativeListResultMap));
            //1-xx月份县市区综指同比与中心城区对比
            result.put("cumulativeCompositeIndexYearOnYearContrast", compositeIndexYearOnYearContrastResponse(month, cityName, areaCodes.size(), monthlyCumulativeListResultMap));
            //1-xx月份县市区PM2.5与中心城区对比
            result.put("cumulativePM25Contrast", pm25tContrastResponse(month, cityName, areaCodes.size(), monthlyCumulativeListResultMap));
            //1-xx月份县市区Pm2.5同比与中心城区对比
            result.put("cumulativePM25YearOnYearContrast", pm25YearOnYearContrastResponse(month, cityName, areaCodes.size(), monthlyCumulativeListResultMap));
        }
 
 
        //四、附件
        //1.本期综指和pm2.5考核排名报表
        List<Map<String, Object>> airQualityRankingOfCurrentReport = airQualityRankingOfCurrentReport(areaData, areasMap);
        result.put("currentAirQualityRankingReport", airQualityRankingOfCurrentReport);
 
        //2.1-x月份累计空气质量综指和pm2.5排名报表
        if (!"1".equals(month)) {
            List<Map<String, Object>> cumulativeAirQualityRankingReport = cumulativeAirQualityRankingReport(cumulativeList, areasMap);
            result.put("cumulativeAirQualityRankingReport", cumulativeAirQualityRankingReport);
        }
 
 
        //3.本期五因子(PM10,SO2,NO2,CO,O3)对比报表
        List<Map<String, Object>> currentFiveSensorsContrastReport = currentFiveSensorsContrastReport(time, areaCodes, areaData, areasMap);
        result.put("currentFiveSensorsContrastReport", currentFiveSensorsContrastReport);
 
 
        //4.1-x月份五因子(PM10,SO2,NO2,CO,O3)对比报表
        if (!"1".equals(month)) {
            List<Map<String, Object>> cumulativeFiveSensorsContrastReport = cumulativeFiveSensorsContrastReport(cumulativeList, areasMap);
            result.put("cumulativeFiveSensorsContrastReport", cumulativeFiveSensorsContrastReport);
 
        }
 
        //存入redis
        redisTemplate.opsForValue().set(RedisConstants.AQI_ANNOUNCEMENT + "_" + regionCode + "_" + DateUtils.dateToDateString(time, DateUtils.yyyyMM_EN), result, Duration.ofDays(30));
        return result;
    }
 
    /**
     * @param startEnd 时间
     * @param cityName 地级市名字
     * @param result   当月数据map
     * @description 当月排名文字拼接
     */
    private String aqiQualityRankingResponse(String startEnd, String cityName, Map<String, Object> result) {
        Object compositeIndex = result.get("compositeIndex");
        Object compositeIndex_rank_168 = result.get("compositeIndex_rank_168");
        Object compositeIndex_rank_28 = result.get("compositeIndex_rank_28");
        Object compositeIndex_rank_8Channels = result.get("compositeIndex_rank_8Channels");
 
        Object compositeIndexYearOnYear = result.get("compositeIndex_yearOnYear");
        Object compositeIndexYearOnYear_rank_168 = result.get("compositeIndex_yearOnYear_rank_168");
        Object compositeIndexYearOnYear_rank_28 = result.get("compositeIndex_yearOnYear_rank_28");
        Object compositeIndexYearOnYear_rank_8Channels = result.get("compositeIndex_yearOnYear_rank_8Channels");
 
        //综指排名
        StringBuilder compositeIndexBuilder = new StringBuilder();
        if (compositeIndex_rank_168 != null) {
            compositeIndexBuilder.append("在168城市正排第" + compositeIndex_rank_168 + "名");
        }
        if (compositeIndex_rank_28 != null) {
            compositeIndexBuilder.append("在'2+26'城市正排第" + compositeIndex_rank_28 + "名");
        }
        if (compositeIndex_rank_8Channels != null) {
            compositeIndexBuilder.append("在河北八通道城市正排第" + compositeIndex_rank_8Channels + "名");
        }
        //综指同比排名
        StringBuilder compositeIndexYearOnYearBuilder = new StringBuilder();
        if (compositeIndexYearOnYear_rank_168 != null) {
            compositeIndexYearOnYearBuilder.append("在168城市正排第" + compositeIndexYearOnYear_rank_168 + "名");
        }
        if (compositeIndexYearOnYear_rank_28 != null) {
            compositeIndexYearOnYearBuilder.append("在'2+26'城市正排第" + compositeIndexYearOnYear_rank_28 + "名");
        }
        if (compositeIndexYearOnYear_rank_8Channels != null) {
            compositeIndexYearOnYearBuilder.append("在河北八通道城市正排第" + compositeIndexYearOnYear_rank_8Channels + "名");
        }
 
 
        Object pm2_5 = result.get("PM2_5");
        Object pm2_5_rank_168 = result.get("PM2_5_rank_168");
        Object pm2_5_rank_28 = result.get("PM2_5_rank_28");
        Object pm2_5_rank_8Channels = result.get("PM2_5_rank_8Channels");
 
        Object pm2_5YearOnYear = result.get("PM2_5_yearOnYear");
        Object pm2_5YearOnYear_rank_168 = result.get("PM2_5_yearOnYear_rank_168");
        Object pm2_5YearOnYear_rank_28 = result.get("PM2_5_yearOnYear_rank_28");
        Object pm2_5YearOnYear_rank_8Channels = result.get("PM2_5_yearOnYear_rank_8Channels");
 
        //PM2.5排名
        StringBuilder pm25Builder = new StringBuilder();
        if (pm2_5_rank_168 != null) {
            pm25Builder.append("在168城市正排第" + pm2_5_rank_168 + "名");
        }
        if (pm2_5_rank_28 != null) {
            pm25Builder.append("在'2+26'城市正排第" + pm2_5_rank_28 + "名");
        }
        if (pm2_5_rank_8Channels != null) {
            pm25Builder.append("在河北八通道城市正排第" + pm2_5_rank_8Channels + "名");
        }
        //PM2.5同比排名
        StringBuilder pm25YearOnYearBuilder = new StringBuilder();
        if (pm2_5YearOnYear_rank_168 != null) {
            pm25YearOnYearBuilder.append("在168城市正排第" + pm2_5YearOnYear_rank_168 + "名");
        }
        if (pm2_5YearOnYear_rank_28 != null) {
            pm25YearOnYearBuilder.append("在'2+26'城市正排第" + pm2_5YearOnYear_rank_28 + "名");
        }
        if (pm2_5YearOnYear_rank_8Channels != null) {
            pm25YearOnYearBuilder.append("在河北八通道城市正排第" + pm2_5YearOnYear_rank_8Channels + "名");
        }
 
        String currentRanking = announcementProperties.getCurrentRanking();
        currentRanking = currentRanking.replace("{start-end}", startEnd)
                .replace("{cityName}", cityName)
                .replace("{compositeIndex}", compositeIndex == null ? "_" : compositeIndex.toString())
                .replace("{compositeIndexRanking}", compositeIndexBuilder.toString().equals("") ? "_" : compositeIndexBuilder.toString())
                .replace("{compositeIndexYearOnYearRanking}", compositeIndexYearOnYearBuilder.toString().equals("") ? "_" : compositeIndexYearOnYearBuilder.toString())
                .replace("{PM2_5}", pm2_5 == null ? "_" : pm2_5.toString())
                .replace("{PM2_5Ranking}", pm25Builder.toString().equals("") ? "_" : pm25Builder.toString())
                .replace("{PM2_5YearOnYearRanking}", pm25YearOnYearBuilder.toString().equals("") ? "_" : pm25YearOnYearBuilder.toString());
        String strCompositeIndexYearOnYear = "_";
        if (compositeIndexYearOnYear != null) {
            if (compositeIndexYearOnYear.toString().startsWith("-")) {
                strCompositeIndexYearOnYear = compositeIndexYearOnYear.toString().replace("-", "下降");
            } else if (Double.parseDouble(compositeIndexYearOnYear.toString().replace("%", "")) == 0d) {
                strCompositeIndexYearOnYear = compositeIndexYearOnYear.toString();
            } else {
                strCompositeIndexYearOnYear = "上升" + compositeIndexYearOnYear;
            }
        }
        String strPM25YearOnYear = "_";
        if (pm2_5YearOnYear != null) {
            if (pm2_5YearOnYear.toString().startsWith("-")) {
                strPM25YearOnYear = pm2_5YearOnYear.toString().replace("-", "下降");
            } else {
                strPM25YearOnYear = "上升" + pm2_5YearOnYear;
            }
        }
        currentRanking = currentRanking.replace("{compositeIndexYearOnYear}", strCompositeIndexYearOnYear).replace("{PM2_5YearOnYear}", strPM25YearOnYear);
 
        return currentRanking;
    }
 
    /**
     * @param month    月份
     * @param cityName 地级市名字
     * @param result   当月数据map
     * @description 县市区与中心城市对比文字拼接
     */
    private String compositeIndexContrastResponse(String month, String cityName, Integer areaSize, Map<String, Object> result) {
        Object compositeIndex = result.get("compositeIndex");
        List<String> compositeIndexLowerList = (List<String>) result.get("compositeIndexLower");
        List<String> compositeIndexHigherList = (List<String>) result.get("compositeIndexHigher");
        List<String> compositeIndexEqualList = (List<String>) result.get("compositeIndexEqual");
 
 
        //综指对比
        String compositeIndexLower = compositeIndexLowerList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String compositeIndexHigher = compositeIndexHigherList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String compositeIndexEqual = compositeIndexEqualList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
 
        StringBuilder builder = new StringBuilder();
        if (compositeIndexLowerList.size() != 0) {
            builder.append("有" + compositeIndexLowerList.size() + "个县(市、区)空气质量综合指数低于中心城区,分别为:").append(compositeIndexLower + ",");
        }
        if (compositeIndexEqualList.size() != 0) {
            builder.append(compositeIndexEqual + "" + compositeIndexEqualList.size() + "个县(市、区)空气质量综合指数与中心城区持平");
        }
        if (compositeIndexHigherList.size() != 0) {
            builder.append("有" + compositeIndexHigherList.size() + "个县(市、区)空气质量综合指数高于中心城区,分别为:").append(compositeIndexHigher);
        }
 
 
        String currentContrastCompositeIndex = announcementProperties.getContrastCompositeIndex();
        currentContrastCompositeIndex = currentContrastCompositeIndex.replace("{month}", month)
                .replace("{cityName}", cityName)
                .replace("{compositeIndex}", compositeIndex == null ? "_" : compositeIndex.toString())
                .replace("{areaSize}", areaSize + "")
                .replace("{details}", builder.toString().equals("") ? "_" : builder.toString());
        return currentContrastCompositeIndex;
    }
 
    /**
     * @param month    月份
     * @param cityName 地级市名字
     * @param result   当月数据map
     * @description 当月排名文字拼接
     */
    private String compositeIndexYearOnYearContrastResponse(String month, String cityName, Integer areaSize, Map<String, Object> result) {
        Object compositeIndexYearOnYear = result.get("compositeIndexYearOnYear");
        List<String> compositeIndexYearOnYearLowerList = (List<String>) result.get("compositeIndexYearOnYearLower");
        List<String> compositeIndexYearOnYearHigherList = (List<String>) result.get("compositeIndexYearOnYearHigher");
        List<String> compositeIndexYearOnYearEqualList = (List<String>) result.get("compositeIndexYearOnYearEqual");
        List<String> compositeIndexYearOnYearHigherOfPositiveList = (List<String>) result.get("compositeIndexYearOnYearHigherOfPositive");
        List<String> compositeIndexYearOnYearHigherOfNegativeList = (List<String>) result.get("compositeIndexYearOnYearHigherOfNegative");
        List<String> compositeIndexYearOnYearHigherOfZeroList = (List<String>) result.get("compositeIndexYearOnYearHigherOfZero");
 
        //综指同比对比
        String compositeIndexYearOnYearLower = compositeIndexYearOnYearLowerList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String compositeIndexYearOnYearEqual = compositeIndexYearOnYearEqualList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String compositeIndexYearOnYearHigherOfPositive = compositeIndexYearOnYearHigherOfPositiveList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String compositeIndexYearOnYearHigherOfNegative = compositeIndexYearOnYearHigherOfNegativeList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
 
 
        StringBuilder builder = new StringBuilder();
        if (compositeIndexYearOnYearLowerList.size() != 0) {
            builder.append("有" + compositeIndexYearOnYearLowerList.size() + "个县(市、区)空气质量综合指数同比改善幅度大于中心城区,分别为:")
                    .append(compositeIndexYearOnYearLower + ";");
        }
        if (compositeIndexYearOnYearEqualList.size() != 0) {
            builder.append(compositeIndexYearOnYearEqual + "" + compositeIndexYearOnYearEqualList.size() + "个县(市、区)空气质量综合指数同比改善幅度与中心城区持平;");
        }
        if (compositeIndexYearOnYearHigherList.size() != 0) {
            builder.append("有" + compositeIndexYearOnYearHigherList.size() + "个县(市、区)空气质量综合指数同比改善幅度小于中心城区,");
            if (compositeIndexYearOnYearHigherOfPositiveList.size() != 0) {
                builder.append("其中有" + compositeIndexYearOnYearHigherOfPositiveList.size() + "个县(市、区)空气质量综合指数同比上升,分别为:" + compositeIndexYearOnYearHigherOfPositive + ",");
            }
            if (compositeIndexYearOnYearHigherOfZeroList.size() != 0) {
                builder.append("其中有" + compositeIndexYearOnYearHigherOfZeroList.size() + "个县(市、区)空气质量综合指数同比持平,");
            }
            if (compositeIndexYearOnYearHigherOfNegativeList.size() != 0) {
                builder.append("其中有" + compositeIndexYearOnYearHigherOfNegativeList.size() + "个县(市、区)空气质量综合指数同比下降,分别为:" + compositeIndexYearOnYearHigherOfNegative);
            }
        }
 
 
        String strCompositeIndexYearOnYear = "_";
        if (compositeIndexYearOnYear != null) {
            if (compositeIndexYearOnYear.toString().startsWith("-")) {
                strCompositeIndexYearOnYear = compositeIndexYearOnYear.toString().replace("-", "下降");
            } else if (Double.parseDouble(compositeIndexYearOnYear.toString().replace("%", "")) == 0d) {
                strCompositeIndexYearOnYear = compositeIndexYearOnYear.toString();
            } else {
                strCompositeIndexYearOnYear = "上升" + compositeIndexYearOnYear;
            }
        }
        String currentContrastCompositeIndexYearOnYear = announcementProperties.getContrastCompositeIndexYearOnYear();
        currentContrastCompositeIndexYearOnYear = currentContrastCompositeIndexYearOnYear.replace("{month}", month)
                .replace("{cityName}", cityName)
                .replace("{compositeIndexYearOnYear}", strCompositeIndexYearOnYear)
                .replace("{areaSize}", areaSize + "")
                .replace("{details}", builder.toString().equals("") ? "_" : builder.toString());
 
 
        return currentContrastCompositeIndexYearOnYear;
    }
 
    /**
     * @param month    月份
     * @param cityName 地级市名字
     * @param result   当月数据map
     * @description PM2.5拼接
     */
    private String pm25tContrastResponse(String month, String cityName, Integer areaSize, Map<String, Object> result) {
        Object pm25 = result.get("PM2_5");
        List<String> pm25LowerList = (List<String>) result.get("PM2_5Lower");
        List<String> pm25HigherList = (List<String>) result.get("PM2_5Higher");
        List<String> pm25EqualList = (List<String>) result.get("PM2_5Equal");
 
 
        //PM2.5对比
        String pm25Lower = pm25LowerList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String pm25Higher = pm25HigherList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String pm25Equal = pm25EqualList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
 
        StringBuilder builder = new StringBuilder();
        if (pm25LowerList.size() != 0) {
            builder.append("有" + pm25LowerList.size() + "个县(市、区)PM2.5累计浓度低于中心城区,分别为:").append(pm25Lower);
        }
        if (pm25EqualList.size() != 0) {
            builder.append(pm25Equal + "" + pm25EqualList.size() + "个县(市、区)PM2.5累计浓度与中心城区持平,");
        }
        if (pm25HigherList.size() != 0) {
            builder.append("有" + pm25HigherList.size() + "个县(市、区)PM2.5累计浓度高于中心城区,分别为:").append(pm25Higher);
        }
 
        String propertiesCurrentContrastPm25 = announcementProperties.getContrastPm25();
        propertiesCurrentContrastPm25 = propertiesCurrentContrastPm25.replace("{month}", month)
                .replace("{cityName}", cityName)
                .replace("{PM2_5}", pm25 == null ? "_" : pm25.toString())
                .replace("{areaSize}", areaSize + "")
                .replace("{details}", builder.toString().equals("") ? "_" : builder.toString());
        return propertiesCurrentContrastPm25;
    }
 
 
    /**
     * @param month    月份
     * @param cityName 地级市名字
     * @param result   当月数据map
     * @description PM2.5同比对比文字拼接
     */
    private String pm25YearOnYearContrastResponse(String month, String cityName, Integer areaSize, Map<String, Object> result) {
        Object pm25YearOnYear = result.get("PM2_5YearOnYear");
 
        List<String> pm25YearOnYearLowerList = (List<String>) result.get("PM2_5YearOnYearLower");
        List<String> pm25YearOnYearHigherList = (List<String>) result.get("PM2_5YearOnYearHigher");
        List<String> pm25YearOnYearEqualList = (List<String>) result.get("PM2_5YearOnYearEqual");
        List<String> pm25YearOnYearLowerOfPositiveList = (List<String>) result.get("pm25YearOnYearLowerOfPositive");
        List<String> pm25YearOnYearLowerOfNegativeList = (List<String>) result.get("pm25YearOnYearLowerOfNegative");
        List<String> pm25YearOnYearLowerOfZeroList = (List<String>) result.get("pm25YearOnYearLowerOfZero");
 
 
        //PM2.5同比对比
        String pm25YearOnYearHigher = pm25YearOnYearHigherList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String pm25YearOnYearEqual = pm25YearOnYearEqualList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String pm25YearOnYearLowerOfPositive = pm25YearOnYearLowerOfPositiveList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
        String pm25YearOnYearLowerOfNegative = pm25YearOnYearLowerOfNegativeList.stream()
                .map(String::valueOf).collect(Collectors.joining(","));
 
        StringBuilder builder = new StringBuilder();
        if (pm25YearOnYearLowerList.size() != 0) {
            builder.append("有" + pm25YearOnYearLowerList.size() + "个县(市、区)PM2.5累计浓度同比改善幅度大于中心城区,");
            if (pm25YearOnYearLowerOfNegativeList.size() != 0) {
                builder.append("其中有" + pm25YearOnYearLowerOfNegativeList.size() + "个县(市、区)PM2.5累计浓度同比下降,分别为:")
                        .append(pm25YearOnYearLowerOfNegative);
            }
            if (pm25YearOnYearLowerOfZeroList.size() != 0) {
                builder.append("有" + pm25YearOnYearLowerOfZeroList.size() + "个县(市、区)PM2.5累计浓度同比持平,");
            }
            if (pm25YearOnYearLowerOfPositiveList.size() != 0) {
                builder.append("有" + pm25YearOnYearLowerOfPositiveList.size() + "个县(市、区)PM2.5累计浓度同比上升,分别为:").append(pm25YearOnYearLowerOfPositive);
            }
        }
        if (pm25YearOnYearEqualList.size() != 0) {
            builder.append(pm25YearOnYearEqual + "" + pm25YearOnYearEqualList.size() + "个县(市、区)PM2.5累计浓度同比改善幅度与中心城区持平;");
        }
        if (pm25YearOnYearHigherList.size() != 0) {
            builder.append("有" + pm25YearOnYearHigherList.size() + "个县(市、区)PM2.5累计浓度同比改善幅度小于中心城区,分别为:").append(pm25YearOnYearHigher);
        }
 
 
        String strPM25IndexYearOnYear = "_";
        if (pm25YearOnYear != null) {
            if (pm25YearOnYear.toString().startsWith("-")) {
                strPM25IndexYearOnYear = pm25YearOnYear.toString().replace("-", "下降");
            } else if (Double.parseDouble(pm25YearOnYear.toString().replace("%", "")) == 0d) {
                strPM25IndexYearOnYear = pm25YearOnYear.toString();
            } else {
                strPM25IndexYearOnYear = "上升" + pm25YearOnYear;
            }
        }
 
        String currentContrastPm25YearOnYear = announcementProperties.getContrastPm25YearOnYear();
        currentContrastPm25YearOnYear = currentContrastPm25YearOnYear.replace("{month}", month)
                .replace("{cityName}", cityName)
                .replace("{PM2_5YearOnYear}", strPM25IndexYearOnYear)
                .replace("{areaSize}", areaSize + "")
                .replace("{details}", builder.toString().equals("") ? "_" : builder.toString());
        return currentContrastPm25YearOnYear;
    }
 
    /**
     * @param data       数据集合
     * @param regionCode 当前地区编码
     * @param rankField  排名字段
     * @description 根据某字段获取排名
     */
    private Integer ranking(List<CityAqiMonthly> data, Integer regionCode, String rankField) {
        Integer rank = null;
        data = data.stream().sorted((o1, o2) -> {
            Map<String, Object> map1 = JSONObject.parseObject(o1.getValue(), Map.class);
            Map<String, Object> map2 = JSONObject.parseObject(o2.getValue(), Map.class);
            Object b1 = map1.get(rankField);
            Object b2 = map2.get(rankField);
 
            if (b1 != null && b2 != null) {
                double aDouble1 = Double.parseDouble(b1.toString().replace("%", ""));
                double aDouble2 = Double.parseDouble(b2.toString().replace("%", ""));
                return aDouble1 > aDouble2 ? 1 : -1;
            } else if (b1 == null && b2 == null) {
                return 0;
            } else if (b1 == null) {
                return -1;
            } else {
                return 1;
            }
        }).collect(Collectors.toList());
        for (int i = 0; i < data.size(); i++) {
            Integer cityCode = data.get(i).getCityCode();
            if (cityCode.equals(regionCode)) {
                Map<String, Object> map = JSONObject.parseObject(data.get(i).getValue(), Map.class);
                if (map.get(rankField) != null) {
                    rank = i + 1;
                }
                break;
            }
        }
        return rank;
    }
 
 
    /**
     * @param regionCode 地区编码
     * @param time       时间
     * @description 本市在168城市中排名情况
     */
    private Map<String, Object> getOneSixEightCitiesRanking(Integer regionCode, Date time) {
        Map<String, Object> result = new HashMap<>();
 
        if (specialCitiesProperties.isOneSixEightCities(regionCode)) {
 
            QueryWrapper<CityAqiMonthly> queryWrapper = new QueryWrapper<>();
            List<SysArea> oneSixEightCities = specialCitiesProperties.getOneSixEightCities();
            List<Integer> oneSixEightCitiesCodes = oneSixEightCities.stream()
                    .map(SysArea::getAreaCode)
                    .collect(Collectors.toList());
            //获取168城市数据
            queryWrapper.clear();
            queryWrapper.select("city_code", "value")
                    .eq("time", time)
                    .in("city_code", oneSixEightCitiesCodes);
            List<CityAqiMonthly> monthlyData168 = cityAqiMonthlyMapper.selectList(queryWrapper);
 
            //综指168城市排名
            Integer compositeIndexRank = ranking(monthlyData168, regionCode, "compositeIndex");
            //综指同比168城市排名
            Integer compositeIndexYearOnYearRank = ranking(monthlyData168, regionCode, "compositeIndex_yearOnYear");
 
            //PM2.5浓度168城市排名
            Integer pm25Rank = ranking(monthlyData168, regionCode, "PM2_5");
            //PM2.5浓度同比168城市排名
            Integer pm25YearOnYearRank = ranking(monthlyData168, regionCode, "PM2_5_yearOnYear");
 
 
            //存入结果集
            result.put("compositeIndex_rank_168", compositeIndexRank == null ? "_" : compositeIndexRank);
            result.put("compositeIndex_yearOnYear_rank_168", compositeIndexYearOnYearRank == null ? "_" : compositeIndexYearOnYearRank);
            result.put("PM2_5_rank_168", pm25Rank == null ? "_" : pm25Rank);
            result.put("PM2_5_yearOnYear_rank_168", pm25YearOnYearRank == null ? "_" : pm25YearOnYearRank);
        }
        return result;
    }
 
 
    //1-x月168城市排名
    private Map<String, Object> getOneSixEightCitiesRankingOfCumulative(Integer regionCode, Date time) {
        Map<String, Object> result = new HashMap<>();
 
        if (specialCitiesProperties.isOneSixEightCities(regionCode)) {
            List<SysArea> oneSixEightCities = specialCitiesProperties.getOneSixEightCities();
            List<Integer> oneSixEightCitiesCodes = oneSixEightCities.stream()
                    .map(SysArea::getAreaCode)
                    .collect(Collectors.toList());
 
            //168城市1-x月累计
            Map<Integer, Map<String, Object>> cumulative168Result = getMonthlyCumulativeResult(time, oneSixEightCitiesCodes);
            List<CityAqiMonthly> cumulativeData168 = new ArrayList<>();
            for (Map.Entry<Integer, Map<String, Object>> entry : cumulative168Result.entrySet()) {
                CityAqiMonthly cityAqiMonthly = new CityAqiMonthly();
                Integer cityCode = entry.getKey();
                Map<String, Object> value = entry.getValue();
                cityAqiMonthly.setCityCode(cityCode);
                cityAqiMonthly.setValue(JSONObject.toJSONString(value));
                cumulativeData168.add(cityAqiMonthly);
            }
 
 
            //综指168城市排名
            Integer compositeIndexRank = ranking(cumulativeData168, regionCode, "compositeIndex");
            //综指同比168城市排名
            Integer compositeIndexYearOnYearRank = ranking(cumulativeData168, regionCode, "compositeIndex_yearOnYear");
 
            //PM2.5浓度168城市排名
            Integer pm25Rank = ranking(cumulativeData168, regionCode, "PM2_5");
            //PM2.5浓度同比168城市排名
            Integer pm25YearOnYearRank = ranking(cumulativeData168, regionCode, "PM2_5_yearOnYear");
 
 
            //存入结果集
            result.put("compositeIndex_rank_168", compositeIndexRank == null ? "_" : compositeIndexRank);
            result.put("compositeIndex_yearOnYear_rank_168", compositeIndexYearOnYearRank == null ? "_" : compositeIndexYearOnYearRank);
            result.put("PM2_5_rank_168", pm25Rank == null ? "_" : pm25Rank);
            result.put("PM2_5_yearOnYear_rank_168", pm25YearOnYearRank == null ? "_" : pm25YearOnYearRank);
        }
        return result;
    }
 
    //1-x月2+26城市排名
    private Map<String, Object> getTwentyEightCitiesRankingOfCumulative(Integer regionCode, Date time) {
        Map<String, Object> result = new HashMap<>();
 
        if (specialCitiesProperties.isTwentyEightCities(regionCode)) {
            List<SysArea> twentyCities = specialCitiesProperties.getTwentyEightCities();
            List<Integer> twentyCitiesCodes = twentyCities.stream()
                    .map(SysArea::getAreaCode)
                    .collect(Collectors.toList());
 
            //168城市1-x月累计
            Map<Integer, Map<String, Object>> cumulative168Result = getMonthlyCumulativeResult(time, twentyCitiesCodes);
            List<CityAqiMonthly> cumulativeData168 = new ArrayList<>();
            for (Map.Entry<Integer, Map<String, Object>> entry : cumulative168Result.entrySet()) {
                CityAqiMonthly cityAqiMonthly = new CityAqiMonthly();
                Integer cityCode = entry.getKey();
                Map<String, Object> value = entry.getValue();
                cityAqiMonthly.setCityCode(cityCode);
                cityAqiMonthly.setValue(JSONObject.toJSONString(value));
                cumulativeData168.add(cityAqiMonthly);
            }
 
 
            //综指168城市排名
            Integer compositeIndexRank = ranking(cumulativeData168, regionCode, "compositeIndex");
            //综指同比168城市排名
            Integer compositeIndexYearOnYearRank = ranking(cumulativeData168, regionCode, "compositeIndex_yearOnYear");
 
            //PM2.5浓度168城市排名
            Integer pm25Rank = ranking(cumulativeData168, regionCode, "PM2_5");
            //PM2.5浓度同比168城市排名
            Integer pm25YearOnYearRank = ranking(cumulativeData168, regionCode, "PM2_5_yearOnYear");
 
 
            //存入结果集
            result.put("compositeIndex_rank_28", compositeIndexRank == null ? "_" : compositeIndexRank);
            result.put("compositeIndex_yearOnYear_rank_28", compositeIndexYearOnYearRank == null ? "_" : compositeIndexYearOnYearRank);
            result.put("PM2_5_rank_28", pm25Rank == null ? "_" : pm25Rank);
            result.put("PM2_5_yearOnYear_rank_28", pm25YearOnYearRank == null ? "_" : pm25YearOnYearRank);
        }
        return result;
    }
 
    //1-x月河北八通道城市排名
    private Map<String, Object> getHeBeiEightCitiesRankingOfCumulative(Integer regionCode, Date time) {
        Map<String, Object> result = new HashMap<>();
 
        if (specialCitiesProperties.isHeBeiEightCities(regionCode)) {
            List<SysArea> heBeiEightCities = specialCitiesProperties.getHeBeiEightCities();
            List<Integer> heBeiEightCitiesCodes = heBeiEightCities.stream()
                    .map(SysArea::getAreaCode)
                    .collect(Collectors.toList());
 
            //168城市1-x月累计
            Map<Integer, Map<String, Object>> cumulative168Result = getMonthlyCumulativeResult(time, heBeiEightCitiesCodes);
            List<CityAqiMonthly> cumulativeData168 = new ArrayList<>();
            for (Map.Entry<Integer, Map<String, Object>> entry : cumulative168Result.entrySet()) {
                CityAqiMonthly cityAqiMonthly = new CityAqiMonthly();
                Integer cityCode = entry.getKey();
                Map<String, Object> value = entry.getValue();
                cityAqiMonthly.setCityCode(cityCode);
                cityAqiMonthly.setValue(JSONObject.toJSONString(value));
                cumulativeData168.add(cityAqiMonthly);
            }
 
 
            //综指168城市排名
            Integer compositeIndexRank = ranking(cumulativeData168, regionCode, "compositeIndex");
            //综指同比168城市排名
            Integer compositeIndexYearOnYearRank = ranking(cumulativeData168, regionCode, "compositeIndex_yearOnYear");
 
            //PM2.5浓度168城市排名
            Integer pm25Rank = ranking(cumulativeData168, regionCode, "PM2_5");
            //PM2.5浓度同比168城市排名
            Integer pm25YearOnYearRank = ranking(cumulativeData168, regionCode, "PM2_5_yearOnYear");
 
 
            //存入结果集
            result.put("compositeIndex_rank_8channels", compositeIndexRank == null ? "_" : compositeIndexRank);
            result.put("compositeIndex_YearOnYear_rank_8channels", compositeIndexYearOnYearRank == null ? "_" : compositeIndexYearOnYearRank);
            result.put("PM2_5_rank_8channels", pm25Rank == null ? "_" : pm25Rank);
            result.put("PM2_5_yearOnYear_rank_8channels", pm25YearOnYearRank == null ? "_" : pm25YearOnYearRank);
        }
        return result;
    }
 
 
    /**
     * @param regionCode 地区编码
     * @param time       时间
     * @description 本市在2+26城市中排名情况
     */
    private Map<String, Object> getTwentyEightCitiesRanking(Integer regionCode, Date time) {
        Map<String, Object> result = new HashMap<>();
 
        if (specialCitiesProperties.isTwentyEightCities(regionCode)) {
 
            QueryWrapper<CityAqiMonthly> queryWrapper = new QueryWrapper<>();
            List<SysArea> twentyEightCities = specialCitiesProperties.getTwentyEightCities();
            List<Integer> twentyEightCitiesCodes = twentyEightCities.stream()
                    .map(SysArea::getAreaCode)
                    .collect(Collectors.toList());
            //获取2+26城市数据
            queryWrapper.select("city_code", "value")
                    .eq("time", time)
                    .in("city_code", twentyEightCitiesCodes);
            List<CityAqiMonthly> monthlyData28 = cityAqiMonthlyMapper.selectList(queryWrapper);
 
            //综指2+26城市排名
            Integer compositeIndexRank = ranking(monthlyData28, regionCode, "compositeIndex");
            //综指同比2+26城市排名
            Integer compositeIndexYearOnYearRank = ranking(monthlyData28, regionCode, "compositeIndex_yearOnYear");
 
            //PM2.5浓度2+26城市排名
            Integer pm25Rank = ranking(monthlyData28, regionCode, "PM2_5");
            //PM2.5浓度同比2+26城市排名
            Integer pm25YearOnYearRank = ranking(monthlyData28, regionCode, "PM2_5_yearOnYear");
 
 
            //存入结果集
            result.put("compositeIndex_rank_28", compositeIndexRank == null ? "_" : compositeIndexRank);
            result.put("compositeIndex_yearOnYear_rank_28", compositeIndexYearOnYearRank == null ? "_" : compositeIndexYearOnYearRank);
            result.put("PM2_5_rank_28", pm25Rank == null ? "_" : pm25Rank);
            result.put("PM2_5_yearOnYear_rank_28", pm25YearOnYearRank == null ? "_" : pm25YearOnYearRank);
        }
        return result;
    }
 
    /**
     * @param regionCode 地区编码
     * @param time       时间
     * @description 本市在河北八通道城市中排名情况
     */
    private Map<String, Object> getHeBeiEightCitiesRanking(Integer regionCode, Date time) {
        Map<String, Object> result = new HashMap<>();
 
        if (specialCitiesProperties.isHeBeiEightCities(regionCode)) {
            QueryWrapper<CityAqiMonthly> queryWrapper = new QueryWrapper<>();
            List<SysArea> heBeiEightCities = specialCitiesProperties.getHeBeiEightCities();
            List<Integer> heBeiEightCitiesCodes = heBeiEightCities.stream()
                    .map(SysArea::getAreaCode)
                    .collect(Collectors.toList());
            //获取2+26城市数据
            queryWrapper.select("city_code", "value")
                    .eq("time", time)
                    .in("city_code", heBeiEightCitiesCodes);
            List<CityAqiMonthly> monthlyData8Channels = cityAqiMonthlyMapper.selectList(queryWrapper);
 
            //综指八通道城市排名
            Integer compositeIndexRank = ranking(monthlyData8Channels, regionCode, "compositeIndex");
            //综指同比八通道城市排名
            Integer compositeIndexYearOnYearRank = ranking(monthlyData8Channels, regionCode, "compositeIndex_yearOnYear");
 
            //PM2.5浓度八通道城市排名
            Integer pm25Rank = ranking(monthlyData8Channels, regionCode, "PM2_5");
            //PM2.5浓度同比八通道城市排名
            Integer pm25YearOnYearRank = ranking(monthlyData8Channels, regionCode, "PM2_5_yearOnYear");
 
 
            //存入结果集
            result.put("compositeIndex_rank_8channels", compositeIndexRank == null ? "_" : compositeIndexRank);
            result.put("compositeIndex_yearOnYear_rank_8channels", compositeIndexYearOnYearRank == null ? "_" : compositeIndexYearOnYearRank);
            result.put("PM2_5_rank_8channels", pm25Rank == null ? "_" : pm25Rank);
            result.put("PM2_5_yearOnYear_rank_8channels", pm25YearOnYearRank == null ? "_" : pm25YearOnYearRank);
        }
        return result;
    }
 
    /**
     * @param areasMap                 所有县市区信息 areaCode--areaName
     * @param areaData                 所有县市区数据
     * @param compositeIndex           中心城区(地级市)综指
     * @param compositeIndexYearOnYear 中心城区(地级市)综指同比
     * @param pm25                     中心城区(地级市)pm.5浓度
     * @param pm25YearOnYear           中心城区(地级市)pm2.5同比
     * @description 获取本期所有县市区与中心城区(地级市)因子对比情况
     */
    private Map<String, Object> getAreaCurrentMonthResult(Map<Integer, String> areasMap, List<CityAqiMonthly> areaData, Double compositeIndex, String compositeIndexYearOnYear, Double pm25, String pm25YearOnYear) {
        Map<String, Object> result = new HashMap<>();
        result.put("compositeIndex", compositeIndex);
        result.put("compositeIndexYearOnYear", compositeIndexYearOnYear);
        result.put("PM2_5", null);
        if (pm25 != null) {
            result.put("PM2_5", pm25 + "ug/m³");
        }
        result.put("PM2_5YearOnYear", pm25YearOnYear);
 
 
        //综指低于中心城区(地级市)集合
        List<String> compositeIndexLowerList = new ArrayList<>();
        //综指高于中心城区(地级市)集合
        List<String> compositeIndexHigherList = new ArrayList<>();
        //综指等于中心城区(地级市)集合
        List<String> compositeIndexEqualList = new ArrayList<>();
 
        //综指同比低于中心城区(地级市)集合
        List<String> compositeIndexYearOnYearLowerList = new ArrayList<>();
        //综指同比高于中心城区(地级市)集合
        List<String> compositeIndexYearOnYearHigherList = new ArrayList<>();
        //综指同比等于中心城区(地级市)集合
        List<String> compositeIndexYearOnYearEqualList = new ArrayList<>();
        //综指同比高于于中心城区(地级市)的地区中综指同比为正的
        List<String> compositeIndexYearOnYearHigherOfPositiveList = new ArrayList<>();
        //综指同比高于于中心城区(地级市)的地区中综指同比为负的
        List<String> compositeIndexYearOnYearHigherOfNegativeList = new ArrayList<>();
        //综指同比高于于中心城区(地级市)的地区中综指同比为0的
        List<String> compositeIndexYearOnYearHigherOfZeroList = new ArrayList<>();
 
 
        //pm2.5低于中心城区(地级市)集合
        List<String> pm25LowerList = new ArrayList<>();
        //pm2.5高于中心城区(地级市)集合
        List<String> pm25HigherList = new ArrayList<>();
        //pm2.5等于中心城区(地级市)集合
        List<String> pm25EqualList = new ArrayList<>();
 
        //pm2.5同比低于中心城区(地级市)集合
        List<String> pm25YearOnYearLowerList = new ArrayList<>();
        //pm2.5同比高于于中心城区(地级市)集合
        List<String> pm25YearOnYearHigherList = new ArrayList<>();
        ///pm2.5同比等于中心城区(地级市)集合
        List<String> pm25YearOnYearEqualList = new ArrayList<>();
        //pm2.5同比低于于中心城区(地级市)的地区中综指同比为正的
        List<String> pm25YearOnYearLowerOfPositiveList = new ArrayList<>();
        //pm2.5同比低于于中心城区(地级市)的地区中综指同比为负的
        List<String> pm25YearOnYearLowerOfNegativeList = new ArrayList<>();
        //pm2.5同比低于于中心城区(地级市)的地区中综指同比0的
        List<String> pm25YearOnYearLowerOfZeroList = new ArrayList<>();
 
 
        Double cityCompositeIndexYearOnYear = null;
        if (compositeIndexYearOnYear != null) {
            cityCompositeIndexYearOnYear = Double.parseDouble(compositeIndexYearOnYear.replace("%", ""));
        }
        Double citypm25YearOnYear = null;
        if (pm25YearOnYear != null) {
            citypm25YearOnYear = Double.parseDouble(pm25YearOnYear.replace("%", ""));
        }
 
 
        for (CityAqiMonthly areaDatum : areaData) {
            Integer areaCode = areaDatum.getCityCode();
            Map<String, Object> valueMap = JSONObject.parseObject(areaDatum.getValue(), Map.class);
            double compositeIndexValue = Double.parseDouble(valueMap.get("compositeIndex").toString());
 
            Double compositeIndexYearOnYearValue = null;
            if (valueMap.get("compositeIndex_yearOnYear") != null) {
                compositeIndexYearOnYearValue = Double.parseDouble(valueMap.get("compositeIndex_yearOnYear").toString().replace("%", ""));
            }
 
            int pm25Value = (int) Double.parseDouble(valueMap.get("PM2_5").toString());
            Double pm25YearOnYearValue = null;
            if (valueMap.get("PM2_5_yearOnYear") != null) {
                pm25YearOnYearValue = Double.parseDouble(valueMap.get("PM2_5_yearOnYear").toString().replace("%", ""));
            }
 
            String areaName = areasMap.get(areaCode);
            if (compositeIndexValue < compositeIndex) {
                compositeIndexLowerList.add(areaName + "(" + compositeIndexValue + ")");
            } else if (compositeIndexValue > compositeIndex) {
                compositeIndexHigherList.add(areaName + "(" + compositeIndexValue + ")");
            } else {
                compositeIndexEqualList.add(areaName + "(" + compositeIndexValue + ")");
            }
 
            if (cityCompositeIndexYearOnYear != null && compositeIndexYearOnYearValue != null) {
                String compositeIndex_yearOnYear = valueMap.get("compositeIndex_yearOnYear").toString();
                if (compositeIndexYearOnYearValue > 0d) {
                    compositeIndex_yearOnYear = "上升" + compositeIndex_yearOnYear;
                } else if (compositeIndexYearOnYearValue < 0d) {
                    compositeIndex_yearOnYear = compositeIndex_yearOnYear.replace("-", "下降");
                }
 
                if (compositeIndexYearOnYearValue > cityCompositeIndexYearOnYear) {
 
                    compositeIndexYearOnYearHigherList.add(areaName + "(" + compositeIndex_yearOnYear + ")");
                    if (compositeIndexYearOnYearValue > 0) {
                        compositeIndexYearOnYearHigherOfPositiveList.add(areaName + "(" + compositeIndex_yearOnYear + ")");
                    } else if (compositeIndexYearOnYearValue < 0) {
                        compositeIndexYearOnYearHigherOfNegativeList.add(areaName + "(" + compositeIndex_yearOnYear + ")");
                    } else {
                        compositeIndexYearOnYearHigherOfZeroList.add(areaName + "(" + compositeIndex_yearOnYear + ")");
                    }
                } else if (compositeIndexYearOnYearValue < cityCompositeIndexYearOnYear) {
                    compositeIndexYearOnYearLowerList.add(areaName + "(" + compositeIndex_yearOnYear + ")");
                } else {
                    compositeIndexYearOnYearEqualList.add(areaName + "(" + compositeIndex_yearOnYear + ")");
                }
            }
 
 
            if (pm25Value < pm25) {
                pm25LowerList.add(areaName + "(" + pm25Value + "ug/m³)");
            } else if (pm25Value > pm25) {
                pm25HigherList.add(areaName + "(" + pm25Value + "ug/m³)");
            } else {
                pm25EqualList.add(areaName + "(" + pm25Value + "ug/m³)");
            }
 
            if (citypm25YearOnYear != null && pm25YearOnYearValue != null) {
                String pm2_5_yearOnYear = valueMap.get("PM2_5_yearOnYear").toString();
                if (pm25YearOnYearValue > 0d) {
                    pm2_5_yearOnYear = "上升" + pm2_5_yearOnYear;
                } else if (pm25YearOnYearValue < 0d) {
                    pm2_5_yearOnYear = pm2_5_yearOnYear.replace("-", "下降");
                }
 
                if (pm25YearOnYearValue < citypm25YearOnYear) {
                    pm25YearOnYearLowerList.add(areaName + "(" + pm2_5_yearOnYear + ")");
                    if (pm25YearOnYearValue > 0) {
                        pm25YearOnYearLowerOfPositiveList.add(areaName + "(" + pm2_5_yearOnYear + ")");
                    } else if (pm25YearOnYearValue < 0) {
                        pm25YearOnYearLowerOfNegativeList.add(areaName + "(" + pm2_5_yearOnYear + ")");
                    } else {
                        pm25YearOnYearLowerOfZeroList.add(areaName + "(" + pm2_5_yearOnYear + ")");
                    }
                } else if (pm25YearOnYearValue > citypm25YearOnYear) {
                    pm25YearOnYearHigherList.add(areaName + "(" + pm2_5_yearOnYear + ")");
                } else {
                    pm25YearOnYearEqualList.add(areaName + "(" + pm2_5_yearOnYear + ")");
                }
            }
 
        }
        result.put("compositeIndexLower", compositeIndexLowerList);
        result.put("compositeIndexHigher", compositeIndexHigherList);
        result.put("compositeIndexEqual", compositeIndexEqualList);
        result.put("compositeIndexYearOnYearHigher", compositeIndexYearOnYearHigherList);
        result.put("compositeIndexYearOnYearLower", compositeIndexYearOnYearLowerList);
        result.put("compositeIndexYearOnYearEqual", compositeIndexYearOnYearEqualList);
        result.put("compositeIndexYearOnYearHigherOfPositive", compositeIndexYearOnYearHigherOfPositiveList);
        result.put("compositeIndexYearOnYearHigherOfNegative", compositeIndexYearOnYearHigherOfNegativeList);
        result.put("compositeIndexYearOnYearHigherOfZero", compositeIndexYearOnYearHigherOfZeroList);
 
        result.put("PM2_5Lower", pm25LowerList);
        result.put("PM2_5Higher", pm25HigherList);
        result.put("PM2_5Equal", pm25EqualList);
        result.put("PM2_5YearOnYearHigher", pm25YearOnYearHigherList);
        result.put("PM2_5YearOnYearLower", pm25YearOnYearLowerList);
        result.put("PM2_5YearOnYearEqual", pm25YearOnYearEqualList);
        result.put("pm25YearOnYearLowerOfPositive", pm25YearOnYearLowerOfPositiveList);
        result.put("pm25YearOnYearLowerOfNegative", pm25YearOnYearLowerOfNegativeList);
        result.put("pm25YearOnYearLowerOfZero", pm25YearOnYearLowerOfZeroList);
 
        return result;
    }
 
    //1-x月累计结果
    public Map<Integer, Map<String, Object>> getMonthlyCumulativeResult(Date time, List<Integer> regionCodes) {
 
        //开始时间,当年1月1日
        Date start = DateUtils.getFirstDayOfYear(time);
        //结束时间,当月最后一天
        Date end = DateUtils.getLastDayOfMonth(time);
 
        //获取所有地区当年1-x月的日数据
        QueryWrapper<CityAqiDaily> cityAqiDailyQueryWrapper = new QueryWrapper<>();
        cityAqiDailyQueryWrapper.select("city_code", "value")
                .ge("time", start)
                .le("time", end)
                .in("city_code", regionCodes);
        List<CityAqiDaily> cityAqiDailyList = cityAqiDailyService.list(cityAqiDailyQueryWrapper);
        if (cityAqiDailyList.size() == 0) {
            return null;
        }
 
        Map<Integer, Map<String, Object>> currentMap = getMonthCumulative(cityAqiDailyList);
 
        //获取所有地区上年1-x月的日数据,用于计算同比
        cityAqiDailyQueryWrapper.clear();
        cityAqiDailyQueryWrapper.select("city_code", "value")
                .ge("time", DateUtils.addYears(start, -1))
                .le("time", DateUtils.addYears(end, -1))
                .in("city_code", regionCodes);
        List<CityAqiDaily> lastCityAqiDailyList = cityAqiDailyService.list(cityAqiDailyQueryWrapper);
        Map<Integer, Map<String, Object>> lastMap = getMonthCumulative(lastCityAqiDailyList);
 
        //计算各因子同比
        for (Map.Entry<Integer, Map<String, Object>> entry : currentMap.entrySet()) {
            Integer regionCode = entry.getKey();
            Map<String, Object> current = entry.getValue();
            Map<String, Object> last = lastMap.get(regionCode);
            Map<String, Object> map = yearOnYearOfSensor(last, current);
            if (map != null) {
                currentMap.put(regionCode, yearOnYearOfSensor(last, current));
            }
        }
        return currentMap;
    }
 
    /**
     * @param last    上年数据
     * @param current 当前数据
     * @description 计算各因子同比
     */
    private Map<String, Object> yearOnYearOfSensor(Map<String, Object> last, Map<String, Object> current) {
        if (last == null) {
            return null;
        }
        //需要计算同比的因子
        List<String> sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2", "CO", "O3", "compositeIndex");
        for (String sensor : sensors) {
            //上年本月该因子值
            double lastValue = Double.parseDouble(last.get(sensor).toString());
            //当前该因子值
            double currentValue = Double.parseDouble(current.get(sensor).toString());
            DecimalFormat decimalFormat = new DecimalFormat("0.00%");
            String format = decimalFormat.format((currentValue - lastValue) / lastValue);
            current.put(sensor + "_yearOnYear", format);
            current.put(sensor + "_last", lastValue);
        }
        return current;
    }
 
    /**
     * @param data 各个地区的数据集合
     * @description 计算1-x月各因子均值
     */
    private Map<Integer, Map<String, Object>> getMonthCumulative(List<CityAqiDaily> data) {
        Map<Integer, Map<String, Object>> result = new HashMap<>();
        //需要均值计算的因子
        List<String> sensors = Arrays.asList("PM2_5", "PM10", "SO2", "NO2");
        //按city_code分组
        Map<Integer, List<CityAqiDaily>> cityDataMap = data.stream()
                .collect(Collectors.groupingBy(CityAqiDaily::getCityCode));
        //1-x月均值计算
        cityDataMap.forEach((cityCode, list) -> {
            Map<String, Object> jsonMap = new HashMap<>();
            Map<String, Object> params = new HashMap<>();
            List<Map<String, Object>> temp = new ArrayList<>();
            for (CityAqiDaily cityAqiDaily : list) {
                Map<String, Object> valueMap = JSONObject.parseObject(cityAqiDaily.getValue(), Map.class);
                Map<String, Object> tempMap = new HashMap<>();
                Map<String, Object> hashMap = new HashMap<>();
                tempMap.put(Constants.SENSOR_CODE_CO, valueMap.get("CO"));
                tempMap.put(Constants.SENSOR_CODE_O3, valueMap.get("O3"));
                hashMap.put("value", JSONObject.toJSONString(tempMap));
                temp.add(hashMap);
            }
            params.put("data", temp);
            //1. CO 95百分位计算并修约
            Map<String, Object> coAvgOfWeekOrMonth = AmendUtils.getCOAvgOfWeekOrMonth(params);
            if (!ObjectUtils.isEmpty(coAvgOfWeekOrMonth)) {
                jsonMap.put("CO", coAvgOfWeekOrMonth.get(Constants.SENSOR_CODE_CO));
            }
 
            //2. O3 90百分位计算并修约
            Map<String, Object> o3AvgOfWeekOrMonth = AmendUtils.getO3AvgOfWeekOrMonth(params);
            if (!ObjectUtils.isEmpty(o3AvgOfWeekOrMonth)) {
                jsonMap.put("O3", o3AvgOfWeekOrMonth.get(Constants.SENSOR_CODE_O3));
            }
 
            sensors.forEach(sensor -> {
                OptionalDouble optionalDouble = list.stream().flatMapToDouble(v -> {
                    Map<String, Object> dataValue = JSONObject.parseObject(v.getValue(), Map.class);
                    double aDouble = Double.parseDouble(dataValue.get(sensor).toString());
                    return DoubleStream.of(aDouble);
                }).average();
                if (optionalDouble.isPresent()) {
                    //银行家算法修约
                    jsonMap.put(sensor, AmendUtils.sciCal(optionalDouble.getAsDouble(), 0));
                }
            });
 
            //1-x月综指
            Double compositeIndex = ComprehensiveIndexUtils.dailyData(jsonMap);
            jsonMap.put("compositeIndex", compositeIndex);
            result.put(cityCode, jsonMap);
        });
        return result;
    }
 
    /**
     * 1.考核排名计算公式:(空气质量综合指数绝对值排名×20%+空气质量指数改善幅度排名×30%)+(PM2.5平均浓度绝对值排名×20%+PM2.5平均浓度改善幅度排名×30%)。
     * 2.加权得分值越小,空气质量考核综合评价越好。
     * 3.排名位次数值相加得分相同的情况下,优先按照PM2.5月均浓度值、改善幅度确定排名先后,平均浓度值低、下降幅度大的排名靠前。
     *
     * @param list     所有县市区数据
     * @param areasMap 所有县市区信息 areaCode--areaName
     * @description 本期综指和pm2.5考核排名报表
     */
    private List<Map<String, Object>> airQualityRankingOfCurrentReport(List<CityAqiMonthly> list, Map<Integer, String> areasMap) {
        List<Map<String, Object>> result = new ArrayList<>();
 
        Map<Integer, CityAqiMonthly> dataMap = new HashMap<>();
        for (CityAqiMonthly cityAqiMonthly : list) {
            dataMap.put(cityAqiMonthly.getCityCode(), cityAqiMonthly);
        }
 
 
        for (Map.Entry<Integer, String> entry : areasMap.entrySet()) {
            Map<String, Object> resultMap = new HashMap<>();
            Integer regionCode = entry.getKey();
            String areaName = entry.getValue();
            resultMap.put("areaName", areaName);
 
            //本期综指
            resultMap.put("compositeIndex", null);
            //综指同比
            resultMap.put("compositeIndexYearOnYear", null);
            //本期PM2.5
            resultMap.put("PM2_5", null);
            //PM2.5同比
            resultMap.put("PM2_5YearOnYear", null);
            if (dataMap.get(regionCode) != null) {
                Map<String, Object> valueMap = JSONObject.parseObject(dataMap.get(regionCode).getValue(), Map.class);
 
                resultMap.put("compositeIndex", valueMap.get("compositeIndex"));
                resultMap.put("compositeIndexYearOnYear", valueMap.get("compositeIndex_yearOnYear"));
 
                resultMap.put("PM2_5", valueMap.get("PM2_5"));
                resultMap.put("PM2_5YearOnYear", valueMap.get("PM2_5_yearOnYear"));
            }
            result.add(resultMap);
        }
 
        //1.按综指绝对值排名
        result.sort((o1, o2) -> {
            if (o1.get("compositeIndex") != null && o2.get("compositeIndex") != null) {
                double compositeIndexAbs1 = Math.abs(Double.parseDouble(o1.get("compositeIndex").toString()));
                double compositeIndexAbs2 = Math.abs(Double.parseDouble(o2.get("compositeIndex").toString()));
                return compositeIndexAbs1 > compositeIndexAbs2 ? 1 : -1;
            } else if (o1.get("compositeIndex") == null && o2.get("compositeIndex") == null) {
                return 0;
            } else if (o1.get("compositeIndex") == null) {
                return -1;
            } else {
                return 1;
            }
        });
        //放入排名字段
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> map = result.get(i);
            map.put("compositeIndexRank", i + 1);
        }
 
        //2.按空气质量改善幅度(综指同比)排名
        result.sort((o1, o2) -> {
            if (o1.get("compositeIndexYearOnYear") != null && o2.get("compositeIndexYearOnYear") != null) {
                double compositeIndexYearOnYear1 = Double.parseDouble(o1.get("compositeIndexYearOnYear").toString().replace("%", ""));
                double compositeIndexYearOnYear2 = Double.parseDouble(o2.get("compositeIndexYearOnYear").toString().replace("%", ""));
                return compositeIndexYearOnYear1 > compositeIndexYearOnYear2 ? 1 : -1;
            } else if (o1.get("compositeIndexYearOnYear") == null && o2.get("compositeIndexYearOnYear") == null) {
                return 0;
            } else if (o1.get("compositeIndexYearOnYear") == null) {
                return -1;
            } else {
                return 1;
            }
        });
        //放入排名字段
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> map = result.get(i);
            map.put("compositeIndexYearOnYearRank", i + 1);
        }
 
        //3.按pm2.5浓度绝对值排名
        result.sort((o1, o2) -> {
            if (o1.get("PM2_5") != null && o2.get("PM2_5") != null) {
                double compositeIndexAbs1 = Math.abs(Double.parseDouble(o1.get("PM2_5").toString()));
                double compositeIndexAbs2 = Math.abs(Double.parseDouble(o2.get("PM2_5").toString()));
                return compositeIndexAbs1 > compositeIndexAbs2 ? 1 : -1;
            } else if (o1.get("PM2_5") == null && o2.get("PM2_5") == null) {
                return 0;
            } else if (o1.get("PM2_5") == null) {
                return -1;
            } else {
                return 1;
            }
        });
        //放入排名字段
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> map = result.get(i);
            map.put("PM2_5Rank", i + 1);
        }
 
        //4.按pm2.5改善幅度排名
        result.sort((o1, o2) -> {
            if (o1.get("PM2_5YearOnYear") != null && o2.get("PM2_5YearOnYear") != null) {
                double pm25YearOnYear1 = Double.parseDouble(o1.get("PM2_5YearOnYear").toString().replace("%", ""));
                double pm25YearOnYear2 = Double.parseDouble(o2.get("PM2_5YearOnYear").toString().replace("%", ""));
                return pm25YearOnYear1 > pm25YearOnYear2 ? 1 : -1;
            } else if (o1.get("PM2_5YearOnYear") == null && o2.get("PM2_5YearOnYear") == null) {
                return 0;
            } else if (o1.get("PM2_5YearOnYear") == null) {
                return -1;
            } else {
                return 1;
            }
        });
        //放入排名字段
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> map = result.get(i);
            map.put("PM2_5YearOnYearRank", i + 1);
        }
 
        //加权得分计算
        for (Map<String, Object> map : result) {
            int compositeIndexRank = Integer.parseInt(map.get("compositeIndexRank").toString());
            int compositeIndexYearOnYearRank = Integer.parseInt(map.get("compositeIndexYearOnYearRank").toString());
            int pm25Rank = Integer.parseInt(map.get("PM2_5Rank").toString());
            int pm25YearOnYearRank = Integer.parseInt(map.get("PM2_5YearOnYearRank").toString());
 
            double score = compositeIndexRank * 0.2 + compositeIndexYearOnYearRank * 0.3 + pm25Rank * 0.2 + pm25YearOnYearRank * 0.3;
            String format = String.format("%.1f", score);
            map.put("score", Double.parseDouble(format));
        }
 
 
        //最终排序
        result.sort((o1, o2) -> {
            double score1 = Double.parseDouble(o1.get("score").toString());
            double score2 = Double.parseDouble(o2.get("score").toString());
            if (score1 > score2) {
                return 1;
            } else if (score1 < score2) {
                return -1;
            }
 
            //排名位次数值相加得分相同的情况下,优先按照PM2.5月均浓度值、改善幅度确定排名先后,平均浓度值低、下降幅度大的排名靠前。
            int pm251 = Integer.parseInt(o1.get("PM2_5").toString());
            int pm252 = Integer.parseInt(o2.get("PM2_5").toString());
 
            if (pm251 > pm252) {
                return 1;
            } else if (pm251 < pm252) {
                return -1;
            }
 
            //pm2.5浓度相同,再按照改善幅度排名
            double pm25YearOnYear1 = Double.parseDouble(o1.get("PM2_5YearOnYearRank").toString().replace("%", ""));
            double pm25YearOnYear2 = Double.parseDouble(o2.get("PM2_5YearOnYearRank").toString().replace("%", ""));
            return pm25YearOnYear1 > pm25YearOnYear2 ? 1 : -1;
        });
        //放入最终排名字段
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> map = result.get(i);
            map.put("resultRank", i + 1);
        }
        for (Map<String, Object> map : result) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (entry.getValue() == null) {
                    map.put(entry.getKey(), "");
                }
            }
        }
 
 
        return result;
    }
 
    /**
     * @param list     所有县市区1-x月份数据
     * @param areasMap 所有县市区信息 areaCode--areaName
     * @description 1-x月份累计空气质量综指和pm2.5排名报表
     */
    private List<Map<String, Object>> cumulativeAirQualityRankingReport(List<CityAqiMonthly> list, Map<Integer, String> areasMap) {
        List<Map<String, Object>> result = new ArrayList<>();
 
 
        Map<Integer, CityAqiMonthly> dataMap = new HashMap<>();
        for (CityAqiMonthly cityAqiMonthly : list) {
            dataMap.put(cityAqiMonthly.getCityCode(), cityAqiMonthly);
        }
 
        for (Map.Entry<Integer, String> entry : areasMap.entrySet()) {
            Map<String, Object> resultMap = new HashMap<>();
            Integer regionCode = entry.getKey();
            String areaName = entry.getValue();
            resultMap.put("areaName", areaName);
 
            //本期综指
            resultMap.put("compositeIndex", null);
            //上期综指
            resultMap.put("compositeIndexLast", null);
            //综指同比
            resultMap.put("compositeIndexYearOnYear", null);
            //本期PM2.5
            resultMap.put("PM2_5", null);
            //上期PM2.5
            resultMap.put("PM2_5Last", null);
            //PM2.5同比
            resultMap.put("PM2_5YearOnYear", null);
            if (dataMap.get(regionCode) != null) {
                Map<String, Object> valueMap = JSONObject.parseObject(dataMap.get(regionCode).getValue(), Map.class);
 
                //综指本期,上期,同比
                resultMap.put("compositeIndex", valueMap.get("compositeIndex"));
                resultMap.put("compositeIndexLast", valueMap.get("compositeIndex_last"));
                resultMap.put("compositeIndexYearOnYear", valueMap.get("compositeIndex_yearOnYear"));
 
                //PM2.5本期,上期,同比
                resultMap.put("PM2_5", valueMap.get("PM2_5"));
                resultMap.put("PM2_5Last", valueMap.get("PM2_5_last"));
                resultMap.put("PM2_5YearOnYear", valueMap.get("PM2_5_yearOnYear"));
            }
            result.add(resultMap);
        }
 
        //按pm2.5同比排名
        result.sort((o1, o2) -> {
            if (o1.get("PM2_5YearOnYear") != null && o2.get("PM2_5YearOnYear") != null) {
                double pm25YearOnYear1 = Double.parseDouble(o1.get("PM2_5YearOnYear").toString().replace("%", ""));
                double pm25YearOnYear2 = Double.parseDouble(o2.get("PM2_5YearOnYear").toString().replace("%", ""));
                return pm25YearOnYear1 > pm25YearOnYear2 ? 1 : -1;
            } else if (o1.get("PM2_5YearOnYear") == null && o2.get("PM2_5YearOnYear") == null) {
                return 0;
            } else if (o1.get("PM2_5YearOnYear") == null) {
                return -1;
            } else {
                return 1;
            }
        });
        //放入排名字段
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> map = result.get(i);
            map.put("PM2_5YearOnYearRank", i + 1);
        }
 
 
        //按综指变化幅度排名
        result.sort((o1, o2) -> {
            if (o1.get("compositeIndexYearOnYear") != null && o2.get("compositeIndexYearOnYear") != null) {
                double compositeIndexYearOnYear1 = Double.parseDouble(o1.get("compositeIndexYearOnYear").toString().replace("%", ""));
                double compositeIndexYearOnYear2 = Double.parseDouble(o2.get("compositeIndexYearOnYear").toString().replace("%", ""));
                return compositeIndexYearOnYear1 > compositeIndexYearOnYear2 ? 1 : -1;
            } else if (o1.get("compositeIndexYearOnYear") == null && o2.get("compositeIndexYearOnYear") == null) {
                return 0;
            } else if (o1.get("compositeIndexYearOnYear") == null) {
                return -1;
            } else {
                return 1;
            }
        });
        //放入排名字段
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> map = result.get(i);
            map.put("compositeIndexYearOnYearRank", i + 1);
        }
        for (Map<String, Object> map : result) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (entry.getValue() == null) {
                    map.put(entry.getKey(), "");
                }
            }
        }
 
        return result;
    }
 
    /**
     * @param time      本期时间
     * @param areaCodes 所有县市区code集合
     * @param areaData  所有县市区本期数据
     * @param areasMap  所有县市区信息
     * @description 本期五因子(PM10,SO2,NO2,CO,O3)对比报表
     */
    private List<Map<String, Object>> currentFiveSensorsContrastReport(Date time, List<Integer> areaCodes, List<CityAqiMonthly> areaData, Map<Integer, String> areasMap) {
        List<Map<String, Object>> result = new ArrayList<>();
 
        //本期数据
        Map<Integer, CityAqiMonthly> dataCurrent = new HashMap<>();
        for (CityAqiMonthly cityAqiMonthly : areaData) {
            dataCurrent.put(cityAqiMonthly.getCityCode(), cityAqiMonthly);
        }
 
 
        //获取上年同期数据
        QueryWrapper<CityAqiMonthly> queryWrapper = new QueryWrapper<>();
        queryWrapper.clear();
        queryWrapper.select("city_code", "value")
                .eq("time", DateUtils.addYears(time, -1))
                .in("city_code", areaCodes);
        List<CityAqiMonthly> monthlyDataLast = cityAqiMonthlyMapper.selectList(queryWrapper);
        Map<Integer, CityAqiMonthly> dataLast = new HashMap<>();
        for (CityAqiMonthly cityAqiMonthly : monthlyDataLast) {
            dataLast.put(cityAqiMonthly.getCityCode(), cityAqiMonthly);
        }
 
 
        //报表中需要对比的五因子
        List<String> sensors = Arrays.asList("PM10", "SO2", "NO2", "CO", "O3");
        for (Map.Entry<Integer, String> entry : areasMap.entrySet()) {
            Map<String, Object> resultMap = new HashMap<>();
            String areaName = entry.getValue();
            Integer regionCode = entry.getKey();
            resultMap.put("areaName", areaName);
 
            for (String sensor : sensors) {
                resultMap.put(sensor, null);
                resultMap.put(sensor + "YearOnYear", null);
                if (dataCurrent.get(regionCode) != null) {
                    Map<String, Object> currentValue = JSONObject.parseObject(dataCurrent.get(regionCode).getValue(), Map.class);
                    resultMap.put(sensor, currentValue.get(sensor));
                    resultMap.put(sensor + "YearOnYear", currentValue.get(sensor + "_yearOnYear"));
                }
 
                //上年同期五因子浓度
                resultMap.put(sensor + "Last", null);
                if (dataLast.get(regionCode) != null) {
                    Map<String, Object> lastValue = JSONObject.parseObject(dataLast.get(regionCode).getValue(), Map.class);
                    //上年同期五因子浓度
                    resultMap.put(sensor + "Last", lastValue.get(sensor));
                }
            }
            result.add(resultMap);
        }
        for (Map<String, Object> map : result) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (entry.getValue() == null) {
                    map.put(entry.getKey(), "");
                }
            }
        }
        return result;
    }
 
    /**
     * @param areaData 所有县市区1-x月份数据,其中包含上年同期五因子浓度值
     * @param areasMap 所有县市区信息
     * @description 1-x月份五因子(PM10,SO2,NO2,CO,O3)对比报表
     */
    private List<Map<String, Object>> cumulativeFiveSensorsContrastReport(List<CityAqiMonthly> areaData, Map<Integer, String> areasMap) {
        List<Map<String, Object>> result = new ArrayList<>();
 
        //本期数据
        Map<Integer, CityAqiMonthly> dataCurrent = new HashMap<>();
        for (CityAqiMonthly cityAqiMonthly : areaData) {
            dataCurrent.put(cityAqiMonthly.getCityCode(), cityAqiMonthly);
        }
 
 
        List<String> sensors = Arrays.asList("PM10", "SO2", "NO2", "CO", "O3");
        for (Map.Entry<Integer, String> entry : areasMap.entrySet()) {
            Map<String, Object> resultMap = new HashMap<>();
            String areaName = entry.getValue();
            Integer regionCode = entry.getKey();
            resultMap.put("areaName", areaName);
            for (String sensor : sensors) {
                resultMap.put(sensor, null);
                resultMap.put(sensor + "Last", null);
                resultMap.put(sensor + "YearOnYear", null);
                if (dataCurrent.get(regionCode) != null) {
                    Map<String, Object> valueMap = JSONObject.parseObject(dataCurrent.get(regionCode).getValue(), Map.class);
                    resultMap.put(sensor, valueMap.get(sensor));
                    resultMap.put(sensor + "Last", valueMap.get(sensor + "_last"));
                    resultMap.put(sensor + "YearOnYear", valueMap.get(sensor + "_yearOnYear"));
                }
            }
            result.add(resultMap);
        }
 
        for (Map<String, Object> map : result) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (entry.getValue() == null) {
                    map.put(entry.getKey(), "");
                }
            }
        }
        return result;
    }
}