From 1d1174cbf704129359a73049d3c947f0defde9e9 Mon Sep 17 00:00:00 2001 From: buaixuexideshitongxue <2936013465@qq.com> Date: Tue, 10 Mar 2026 22:48:00 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A0=94=E5=88=A4=E5=88=86=E6=9E=90--step7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pojo/dto/report/OverviewSection.java | 6 + .../ReportAccountabilityStatsRequestDTO.java | 9 +- .../ReportAccountabilityStatsResponseDTO.java | 24 +- .../BusinessLinePersonRankItem.java | 6 +- .../businessLine/BusinessLineRankItem.java | 4 + .../closed/ClosedStatsCalcResponseDTO.java | 4 + ...eportAccountabilitySectionServiceImpl.java | 87 ++---- .../ReportAccountabilityStatsServiceImpl.java | 213 +++++++++++++- .../ReportBusinessLineSectionServiceImpl.java | 112 +++---- .../impl/ReportClosedStatsServiceImpl.java | 18 +- .../ReportOverviewSectionServiceImpl.java | 275 +++++++----------- ...rtUnitInvestigationSectionServiceImpl.java | 7 +- .../supervision/util/ReportTrendUtil.java | 1 + ...审一体化平台研判分析报告.docx | Bin 15663 -> 15897 bytes 14 files changed, 440 insertions(+), 326 deletions(-) diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/OverviewSection.java b/src/main/java/com/biutag/supervision/pojo/dto/report/OverviewSection.java index e08c281..f9cec7c 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/OverviewSection.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/OverviewSection.java @@ -70,6 +70,12 @@ public class OverviewSection { @Schema(description = "查实率同比变化率", example = "5.1") private BigDecimal verifiedYoyRate; + @Schema(description = "查实和基本查实数和", example = "420") + private Integer verifiedAndBasicallyVerifiedCount; + + @Schema(description = "问责问题数", example = "5") + private Integer accountabilityProblemTotal; + @Schema(description = "问责总人次", example = "58") private Integer accountabilityTotal; diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java index 654ad04..7aa7bb8 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java @@ -1,5 +1,6 @@ package com.biutag.supervision.pojo.dto.report.accountability; +import com.biutag.supervision.pojo.vo.NegativeQueryVo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; @@ -18,7 +19,13 @@ import java.util.List; @Schema(description = "报表问责统计请求DTO") public class ReportAccountabilityStatsRequestDTO { - @Schema(description = "问题ID列表") + @Deprecated + @Schema(description = "属实、部分问题ID列表") private List negativeIds = new ArrayList<>(); + + @Schema(description = "原始问题列表") + private List negativeQueryVoList; + + } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java index f28a91a..b6acb1b 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java @@ -1,13 +1,16 @@ package com.biutag.supervision.pojo.dto.report.accountability; +import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLinePersonRankItem; import com.biutag.supervision.pojo.entity.NegativeBlame; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * @ClassName ReportAccountabilityStatsResponseDTO @@ -20,13 +23,19 @@ import java.util.List; @Schema(description = "报表问责统计结果DTO") public class ReportAccountabilityStatsResponseDTO { - @Schema(description = "问责总数 = 个人问责 + 领导问责 + 单位问责", example = "12") + @Schema(description = "问责问题条数") + private int accountabilityNegativeCount; + + @Schema(description = "问责率 问责问题条数/办结的条数") + private BigDecimal accountabilityNegativeRate; + + @Schema(description = "问责总人次数 = 个人问责 + 领导问责 + 单位问责", example = "12") private int total; - @Schema(description = "个人问责数 = 个人问责 + 领导问责", example = "8") + @Schema(description = "个人问责人次数 = 个人问责 + 领导问责", example = "8") private int personal; - @Schema(description = "单位问责数", example = "4") + @Schema(description = "单位问责人次数", example = "4") private int unit; @Schema(description = "个人问责列表") @@ -38,4 +47,13 @@ public class ReportAccountabilityStatsResponseDTO { @Schema(description = "单位问责列表") private List unitBlames = new ArrayList<>(); + @Schema(description = "问责人员TOP3") + private List topPersons; + + @Schema(description = "个人问责类型次数map") + private Map personalTypeCountMap; + + @Schema(description = "单位问责类型次数map") + private Map unitTypeCountMap; + } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLinePersonRankItem.java b/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLinePersonRankItem.java index 81c5aa0..3089920 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLinePersonRankItem.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLinePersonRankItem.java @@ -1,14 +1,16 @@ package com.biutag.supervision.pojo.dto.report.businessLine; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; +import lombok.*; import java.math.BigDecimal; @Getter @Setter @Schema(description = "业务条线重点人员排行项") +@Builder +@AllArgsConstructor +@NoArgsConstructor public class BusinessLinePersonRankItem { @Schema(description = "人员姓名") diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineRankItem.java b/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineRankItem.java index 4a2458c..83a968c 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineRankItem.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineRankItem.java @@ -1,7 +1,9 @@ package com.biutag.supervision.pojo.dto.report.businessLine; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.math.BigDecimal; @@ -9,6 +11,8 @@ import java.math.BigDecimal; @Getter @Setter @Schema(description = "业务条线排行项") +@AllArgsConstructor +@NoArgsConstructor public class BusinessLineRankItem { @Schema(description = "名称,如 执法程序问题 / 某某派出所") diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcResponseDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcResponseDTO.java index e953186..cb84b42 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcResponseDTO.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcResponseDTO.java @@ -1,5 +1,6 @@ package com.biutag.supervision.pojo.dto.report.closed; +import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineRankItem; import com.biutag.supervision.pojo.vo.NegativeQueryVo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; @@ -41,4 +42,7 @@ public class ClosedStatsCalcResponseDTO { @Schema(description = "不属实问题列表") private List unverifiedList = new ArrayList<>(); + @Schema(description = "问题单位排名") + private List topUnits; + } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java index 2f012eb..a3b4ea1 100644 --- a/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java @@ -1,5 +1,6 @@ package com.biutag.supervision.service.report.impl; +import cn.hutool.core.util.StrUtil; import com.biutag.supervision.pojo.dto.report.accountability.*; import com.biutag.supervision.pojo.entity.NegativeBlame; import com.biutag.supervision.pojo.param.NegativeQueryParam; @@ -12,11 +13,13 @@ import com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.data.PictureType; import com.deepoove.poi.data.Pictures; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.*; @Service +@Slf4j public class ReportAccountabilitySectionServiceImpl implements ReportAccountabilitySectionService { @Resource @@ -27,76 +30,54 @@ public class ReportAccountabilitySectionServiceImpl implements ReportAccountabil @Override public AccountabilityOverviewSection buildAccountabilityOverviewSection(ReportAccountabilitySectionRequestDTO requestDTO) { + log.info("问责情况总览开始计算======================================================================================="); if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { return new AccountabilityOverviewSection(); } - NegativeQueryParam request = requestDTO.getNegativeQueryParam(); String periodStart = requestDTO.getPeriodStart(); String periodEnd = requestDTO.getPeriodEnd(); - NegativeQueryParam currentQueryParam = request.newQueryParam(); + NegativeQueryParam currentQueryParam = requestDTO.getNegativeQueryParam().newQueryParam(); List currentList = negativeQueryService.page(currentQueryParam).getRecords(); - - List negativeIds = currentList.stream() - .map(NegativeQueryVo::getId) - .filter(Objects::nonNull) - .toList(); - ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); - statsRequestDTO.setNegativeIds(negativeIds); - ReportAccountabilityStatsResponseDTO statsResponseDTO = - reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); - + statsRequestDTO.setNegativeQueryVoList(currentList); + ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); AccountabilityOverviewSection section = new AccountabilityOverviewSection(); section.setPeriodStart(periodStart); section.setPeriodEnd(periodEnd); section.setProblemTypeCount(currentList.size()); section.setPersonalAccountabilityCount(statsResponseDTO.getPersonal()); section.setDepartmentAccountabilityCount(statsResponseDTO.getUnit()); - + log.info("问责情况总览开始计算结束======================================================================================="); return section; } @Override public AccountabilityUnitSection buildAccountabilityUnitDetailSection(ReportAccountabilitySectionRequestDTO requestDTO) { + log.info("对单位追责问责情况开始计算======================================================================================="); if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { return new AccountabilityUnitSection(); } - NegativeQueryParam request = requestDTO.getNegativeQueryParam(); - - NegativeQueryParam currentQueryParam = request.newQueryParam(); + NegativeQueryParam currentQueryParam = requestDTO.getNegativeQueryParam().newQueryParam(); List currentList = negativeQueryService.page(currentQueryParam).getRecords(); - - List negativeIds = currentList.stream() - .map(NegativeQueryVo::getId) - .filter(Objects::nonNull) - .toList(); - ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); - statsRequestDTO.setNegativeIds(negativeIds); - ReportAccountabilityStatsResponseDTO statsResponseDTO = - reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); - - Map> unitMap = statsResponseDTO.getUnitBlames().stream() - .collect(java.util.stream.Collectors.groupingBy(NegativeBlame::getHandleResultName)); - + statsRequestDTO.setNegativeQueryVoList(currentList); + ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); AccountabilityUnitSection section = new AccountabilityUnitSection(); section.setTotalCount(statsResponseDTO.getUnit()); - - List typeItems = unitMap.entrySet().stream() + List typeItems = statsResponseDTO.getUnitTypeCountMap().entrySet().stream() .map(entry -> { AccountabilityTypeItem item = new AccountabilityTypeItem(); item.setTypeName(entry.getKey()); - item.setCount(entry.getValue().size()); + item.setCount(entry.getValue()); return item; }) .sorted(Comparator.comparing(AccountabilityTypeItem::getCount).reversed()) .toList(); section.setTypeItems(typeItems); - Map pieData = new LinkedHashMap<>(); for (AccountabilityTypeItem typeItem : typeItems) { pieData.put(typeItem.getTypeName(), typeItem.getCount()); @@ -107,53 +88,28 @@ public class ReportAccountabilitySectionServiceImpl implements ReportAccountabil .size(500, 300) .create(); section.setDepartPieChart(picture); + log.info("对单位追责问责情况计算结束======================================================================================="); return section; } @Override public AccountabilityPersonalSection buildAccountabilityPersonalOverviewSection(ReportAccountabilitySectionRequestDTO requestDTO) { + log.info("对个人追责问责情况计算开始======================================================================================="); if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { return new AccountabilityPersonalSection(); } - - NegativeQueryParam request = requestDTO.getNegativeQueryParam(); - - NegativeQueryParam currentQueryParam = request.newQueryParam(); + NegativeQueryParam currentQueryParam = requestDTO.getNegativeQueryParam().newQueryParam(); List currentList = negativeQueryService.page(currentQueryParam).getRecords(); - - List negativeIds = currentList.stream() - .map(NegativeQueryVo::getId) - .filter(Objects::nonNull) - .toList(); - ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); - statsRequestDTO.setNegativeIds(negativeIds); - ReportAccountabilityStatsResponseDTO statsResponseDTO = - reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); - - Map> leadMap = statsResponseDTO.getLeadBlames().stream() - .collect(java.util.stream.Collectors.groupingBy(NegativeBlame::getLeadHandleResultName)); - - Map> personMap = statsResponseDTO.getPersonalBlames().stream() - .collect(java.util.stream.Collectors.groupingBy(NegativeBlame::getHandleResultName)); - - Map> mergedMap = new HashMap<>(personMap); - leadMap.forEach((key, value) -> - mergedMap.merge(key, value, (list1, list2) -> { - List list = new ArrayList<>(list1); - list.addAll(list2); - return list; - }) - ); - + statsRequestDTO.setNegativeQueryVoList(currentList); + ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); AccountabilityPersonalSection section = new AccountabilityPersonalSection(); section.setTotalCount(statsResponseDTO.getPersonal()); - - List typeItems = mergedMap.entrySet().stream() + List typeItems = statsResponseDTO.getPersonalTypeCountMap().entrySet().stream() .map(entry -> { AccountabilityTypeItem item = new AccountabilityTypeItem(); item.setTypeName(entry.getKey()); - item.setCount(entry.getValue().size()); + item.setCount(entry.getValue()); return item; }) .sorted(Comparator.comparing(AccountabilityTypeItem::getCount).reversed()) @@ -170,6 +126,7 @@ public class ReportAccountabilitySectionServiceImpl implements ReportAccountabil .size(500, 300) .create(); section.setPersonPieChart(picture); + log.info("对个人追责问责情况计算结束======================================================================================="); return section; } } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java index 3ed55d6..9331e0e 100644 --- a/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java @@ -2,48 +2,84 @@ package com.biutag.supervision.service.report.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; +import com.biutag.supervision.constants.enums.ProcessingStatusEnum; import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsRequestDTO; import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO; +import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLinePersonRankItem; import com.biutag.supervision.pojo.entity.NegativeBlame; +import com.biutag.supervision.pojo.entity.SupDictData; +import com.biutag.supervision.pojo.entity.SupPolice; +import com.biutag.supervision.pojo.model.PoliceModel; +import com.biutag.supervision.pojo.param.PoliceQueryParam; +import com.biutag.supervision.pojo.param.SupPoliceQueryParam; import com.biutag.supervision.pojo.param.negativeBlame.NegativeBlameQueryParam; +import com.biutag.supervision.pojo.vo.NegativeQueryVo; import com.biutag.supervision.repository.negativeBlame.NegativeBlameResourceService; +import com.biutag.supervision.repository.supPolice.SupPoliceResourceService; +import com.biutag.supervision.service.SupDictDataService; +import com.biutag.supervision.service.SupPoliceService; import com.biutag.supervision.service.report.ReportAccountabilityStatsService; +import com.biutag.supervision.util.ReportTrendUtil; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; @Service @Schema(description = "报表问责统计服务") +@Slf4j public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilityStatsService { @Resource private NegativeBlameResourceService negativeBlameResourceService; + @Resource + private SupPoliceService supPoliceService; + + @Resource + private SupDictDataService supDictDataService; + @Override public ReportAccountabilityStatsResponseDTO calculateAccountabilityStats(ReportAccountabilityStatsRequestDTO requestDTO) { ReportAccountabilityStatsResponseDTO responseDTO = new ReportAccountabilityStatsResponseDTO(); - if (requestDTO == null || CollUtil.isEmpty(requestDTO.getNegativeIds())) { + if (requestDTO == null || CollUtil.isEmpty(requestDTO.getNegativeQueryVoList())) { + return responseDTO; + } + // 1. 办结数据 + List closedNegativeList = requestDTO.getNegativeQueryVoList().stream() + .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) + .toList(); + log.info("办结数据数量: {}", closedNegativeList.size()); + if (CollUtil.isEmpty(closedNegativeList)) { return responseDTO; } + // 2. 提取办结问题ID,作为问责查询范围 + List closedNegativeIds = closedNegativeList.stream() + .map(NegativeQueryVo::getId) + .filter(StrUtil::isNotBlank) + .distinct() + .toList(); + log.info("去重后的办结问题ID数量: {}", closedNegativeIds.size()); NegativeBlameQueryParam queryParam = new NegativeBlameQueryParam(); - queryParam.setNegativeIds(requestDTO.getNegativeIds()); - + queryParam.setNegativeIds(closedNegativeIds); List negativeBlames = negativeBlameResourceService.query(queryParam); + log.info("查询到的问责记录总数: {}", negativeBlames.size()); - // 个人问责 + + // 3. 个人问责 List personalBlames = negativeBlames.stream() .filter(one -> "personal".equals(one.getType())) .filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) .filter(one -> !"不予追责".equals(one.getHandleResultName())) .toList(); - - // 个人问责中的领导问责 + log.info("个人问责记录数量: {}", personalBlames.size()); + // 4. 领导问责(从个人问责记录中拆分,按 negativeId + 领导姓名 + 领导处理结果 去重) Set seenLead = new HashSet<>(); List leadBlames = personalBlames.stream() .filter(one -> StrUtil.isNotBlank(one.getLeadHandleResultName())) @@ -52,25 +88,170 @@ public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilit one.getNegativeId() + "_" + one.getLeadHandleResultName() + "_" + one.getLeadName() )) .toList(); - - // 单位问责 + log.info("领导问责记录数量: {} (去重后)", leadBlames.size()); + // 5. 单位问责 List unitBlames = negativeBlames.stream() .filter(one -> "department".equals(one.getType())) .filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) .filter(one -> !"不予追责".equals(one.getHandleResultName())) .toList(); + log.info("单位问责记录数量: {}", unitBlames.size()); + // 6. 统计人次数 + int personalCount = personalBlames.stream() + .mapToInt(one -> countHandleResult(one.getHandleResultName())) + .sum(); + log.info("涉及个人人次数:" + personalCount); + int leadCount = leadBlames.stream() + .mapToInt(one -> countHandleResult(one.getLeadHandleResultName())) + .sum(); + log.info("领导人次数:" + leadCount); + int unitCount = unitBlames.stream() + .mapToInt(one -> countHandleResult(one.getHandleResultName())) + .sum(); + log.info("单位问责次数" + unitCount); + int finalPersonalCount = personalCount + leadCount; + int totalCount = finalPersonalCount + unitCount; + + // 7. 统计问责问题条数:三类问责记录中的 negativeId 去重 + Set accountabilityNegativeIds = new HashSet<>(); + + personalBlames.stream() + .map(NegativeBlame::getNegativeId) + .filter(StrUtil::isNotBlank) + .forEach(accountabilityNegativeIds::add); + + leadBlames.stream() + .map(NegativeBlame::getNegativeId) + .filter(StrUtil::isNotBlank) + .forEach(accountabilityNegativeIds::add); + + unitBlames.stream() + .map(NegativeBlame::getNegativeId) + .filter(StrUtil::isNotBlank) + .forEach(accountabilityNegativeIds::add); + int accountabilityNegativeCount = accountabilityNegativeIds.size(); + // 8. 问责率 = 问责问题条数 / 办结条数 + BigDecimal accountabilityNegativeRate = ReportTrendUtil.percent(accountabilityNegativeCount, closedNegativeList.size()); - int personalCount = personalBlames.size() + leadBlames.size(); - int unitCount = unitBlames.size(); + // 9. 计算个人问责类型次数map(包含个人和领导,并拆分"、") + Map personalTypeCountMap = new HashMap<>(); - responseDTO.setPersonal(personalCount); + // 处理个人问责记录 + personalBlames.forEach(blame -> + addHandleResultsToMap(personalTypeCountMap, blame.getHandleResultName()) + ); + + // 处理领导问责记录 + leadBlames.forEach(blame -> + addHandleResultsToMap(personalTypeCountMap, blame.getLeadHandleResultName()) + ); + // 10. 计算单位问责类型次数map(拆分"、") + Map unitTypeCountMap = new HashMap<>(); + unitBlames.forEach(blame -> + addHandleResultsToMap(unitTypeCountMap, blame.getHandleResultName()) + ); + + // 11. 计算问责人员TOP3 + List topPersons = calculateTopPersons(personalBlames); + + // 问责率 + responseDTO.setAccountabilityNegativeRate(accountabilityNegativeRate); + // 问责问题条数 + responseDTO.setAccountabilityNegativeCount(accountabilityNegativeCount); + responseDTO.setPersonal(finalPersonalCount); responseDTO.setUnit(unitCount); - responseDTO.setTotal(personalCount + unitCount); + responseDTO.setTotal(totalCount); responseDTO.setPersonalBlames(personalBlames); responseDTO.setLeadBlames(leadBlames); responseDTO.setUnitBlames(unitBlames); - + responseDTO.setTopPersons(topPersons); return responseDTO; } + + private boolean hasValidHandleResult(String handleResultName) { + return countHandleResult(handleResultName) > 0; + } + + + /** + * 将处理结果拆分后添加到统计Map中 + */ + private void addHandleResultsToMap(Map map, String handleResultName) { + if (StrUtil.isBlank(handleResultName)) { + return; + } + + StrUtil.splitTrim(handleResultName, "、").stream() + .filter(StrUtil::isNotBlank) + .filter(item -> !"不予追责".equals(item)) + .map(String::trim) + .forEach(result -> + map.put(result, map.getOrDefault(result, 0) + 1) + ); + } + + + + private int countHandleResult(String handleResultName) { + if (StrUtil.isBlank(handleResultName)) { + return 0; + } + + return StrUtil.splitTrim(handleResultName, "、").stream() + .filter(StrUtil::isNotBlank) + .filter(item -> !"不予追责".equals(item)) + .map(String::trim) + .toList() + .size(); + } + + /** + * 计算问责人员TOP3 + */ + private List calculateTopPersons(List personalBlames) { + if (CollUtil.isEmpty(personalBlames)) { + return Collections.emptyList(); + } + List supDictData = supDictDataService.listByDictType("personType"); + Map dictValueLabelMap = supDictData.stream() + .collect(Collectors.toMap( + SupDictData::getDictValue, + SupDictData::getDictLabel, + (v1, v2) -> v1, + LinkedHashMap::new + )); + return personalBlames.stream() + .collect(Collectors.groupingBy( + blame -> String.join("|", + Objects.toString(blame.getNegativeId(), ""), + Objects.toString(blame.getBlameEmpNo(), "") + ) + )) + .entrySet().stream() + .sorted((entry1, entry2) -> Integer.compare(entry2.getValue().size(), entry1.getValue().size())) + .map(entry -> { + List value = entry.getValue(); + NegativeBlame blame = value.get(0); + + PoliceQueryParam policeQueryParam = new PoliceQueryParam(); + policeQueryParam.setEmpNo(blame.getBlameEmpNo()); + List records = supPoliceService.page(policeQueryParam).getRecords(); + String unitName = "未知"; + String identityName = "未知"; + if (CollUtil.isNotEmpty(records)){ + unitName = records.get(0).getParentDepartShortName() + records.get(0).getDepartShortName(); + identityName = dictValueLabelMap.get(records.get(0).getPersonType()); + } + + return BusinessLinePersonRankItem.builder() + .personName(blame.getBlameName()) + .unitName(unitName) + .identityName(identityName) + .count(value.size()) + .build(); + }) + .toList(); + } + } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java index a6c8b69..679d311 100644 --- a/src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java @@ -1,8 +1,8 @@ package com.biutag.supervision.service.report.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; -import com.biutag.supervision.constants.enums.CheckStatusEnum; import com.biutag.supervision.constants.enums.ProcessingStatusEnum; import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsRequestDTO; import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO; @@ -11,9 +11,12 @@ import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryResponseDTO; import com.biutag.supervision.pojo.dto.report.businessLine.*; import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcRequestDTO; import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO; +import com.biutag.supervision.pojo.entity.NegativeBlame; +import com.biutag.supervision.pojo.entity.NegativeProblemRelation; import com.biutag.supervision.pojo.param.NegativeQueryParam; import com.biutag.supervision.pojo.vo.DictProblemSourceTree; import com.biutag.supervision.pojo.vo.NegativeQueryVo; +import com.biutag.supervision.service.NegativeProblemRelationService; import com.biutag.supervision.service.NegativeQueryService; import com.biutag.supervision.service.SupDictProblemSourceService; import com.biutag.supervision.service.report.ReportAccountabilityStatsService; @@ -27,6 +30,7 @@ import com.deepoove.poi.data.PictureType; import com.deepoove.poi.data.Pictures; import jakarta.annotation.Resource; import lombok.Data; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.math.BigDecimal; @@ -34,6 +38,7 @@ import java.util.*; import java.util.stream.Collectors; @Service +@Slf4j public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineSectionService { @Resource @@ -50,10 +55,12 @@ public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineS @Resource private ReportAccountabilityStatsService reportAccountabilityStatsService; + @Resource + private NegativeProblemRelationService negativeProblemRelationService; @Override public BusinessLineOverviewSection buildBusinessLineOverviewSection(ReportBusinessLineSectionRequestDTO requestDTO) { - + log.info("条线总览开始计算======================================================================================="); if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { return new BusinessLineOverviewSection(); } @@ -106,55 +113,58 @@ public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineS .size(500, 300) .create(); section.setProblemPieChart(picture); + log.info("条线总览计算结束======================================================================================="); return section; } @Override public List buildBusinessLineDetailSections(ReportBusinessLineSectionRequestDTO requestDTO) { + log.info("条线明细开始计算======================================================================================="); if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { return new ArrayList<>(); } NegativeQueryParam request = requestDTO.getNegativeQueryParam(); - + // 查询本期、环比、同比三期基础数据 ReportBaseQueryRequestDTO baseRequestDTO = new ReportBaseQueryRequestDTO(); baseRequestDTO.setNegativeQueryParam(request); ReportBaseQueryResponseDTO baseQueryResponseDTO = reportBaseQueryService.queryBaseData(baseRequestDTO); - List currentList = baseQueryResponseDTO.getCurrentList(); List momList = baseQueryResponseDTO.getMomList(); List yoyList = baseQueryResponseDTO.getYoyList(); + // 构建问题来源字典ID映射,用于解析业务条线 Map idMap = supDictProblemSourceService.buildIdMap(); - + // 本期按业务条线分组 Map> currentGroup = currentList.stream() .collect(Collectors.groupingBy( vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), LinkedHashMap::new, Collectors.toList() )); - + // 环比分组 Map> momGroup = momList.stream() .collect(Collectors.groupingBy( vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), LinkedHashMap::new, Collectors.toList() )); - + // 同比分组 Map> yoyGroup = yoyList.stream() .collect(Collectors.groupingBy( vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), LinkedHashMap::new, Collectors.toList() )); - List>> sortedEntries = currentGroup.entrySet().stream() .sorted((a, b) -> Integer.compare(b.getValue().size(), a.getValue().size())) .toList(); + /** + * 遍历每个业务条线进行统计 + */ List result = new ArrayList<>(); int index = 1; - for (Map.Entry> entry : sortedEntries) { String fatherBusinessLineName = entry.getKey(); List lineList = entry.getValue(); @@ -164,85 +174,59 @@ public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineS BusinessLineDetailSection section = new BusinessLineDetailSection(); section.setOrderNo(toChineseOrderNo(index++)); section.setBusinessFatherLineName(fatherBusinessLineName); - section.setBusinessLineName(fatherBusinessLineName); + section.setBusinessLineName(lineList.get(0).getProblemSources()); int totalIssued = lineList.size(); section.setTotalIssued(totalIssued); - List closedList = lineList.stream() - .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) - .toList(); - section.setClosedCount(closedList.size()); - + // 办结 / 查实统计 ClosedStatsCalcRequestDTO closedStatsCalcRequestDTO = new ClosedStatsCalcRequestDTO(); closedStatsCalcRequestDTO.setNegativeQueryVoList(lineList); ClosedStatsCalcResponseDTO closedStats = reportClosedStatsService.calculateClosedStats(closedStatsCalcRequestDTO); - - int verifiedTotal = Optional.ofNullable(closedStats.getClosedCount()).orElse(0); + int verifiedTotal = closedStats.getVerifiedCount() + closedStats.getBasicallyVerifiedCount(); + section.setClosedCount(closedStats.getClosedCount()); section.setVerifiedTotal(verifiedTotal); - section.setVerifiedRate(Optional.ofNullable(closedStats.getVerifiedRate()).orElse(BigDecimal.ZERO)); - - List verifiedNegativeIds = closedList.stream() - .filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode()) - || CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) - .map(NegativeQueryVo::getId) - .filter(StrUtil::isNotBlank) - .distinct() - .toList(); - + section.setVerifiedRate(closedStats.getVerifiedRate()); + // 问责统计 ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); - statsRequestDTO.setNegativeIds(verifiedNegativeIds); + statsRequestDTO.setNegativeQueryVoList(lineList); ReportAccountabilityStatsResponseDTO accountabilityStats = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); section.setAccountabilityTotal(accountabilityStats.getTotal()); - section.setAccountabilityRate(ReportTrendUtil.calcRate(accountabilityStats.getTotal(), verifiedTotal)); + section.setAccountabilityRate(accountabilityStats.getAccountabilityNegativeRate()); section.setPersonalAccountabilityCount(accountabilityStats.getPersonal()); section.setDepartmentAccountabilityCount(accountabilityStats.getUnit()); + //问题类型 TOP3 +// Set collect = lineList.stream().map(NegativeQueryVo::getId).collect(Collectors.toSet()); +// List negativeProblemRelations = negativeProblemRelationService.list(collect); +// // 1. 分组统计,value为所有数据的List +// Map> groupedMap = negativeProblemRelations.stream() +// .collect(Collectors.groupingBy( +// relation -> relation.getOneLevelContent() + +// relation.getTwoLevelContent() + +// relation.getThreeLevelContent() +// )); +// // 2. 按List大小(数量)降序排序 +// List>> sortedList = groupedMap.entrySet().stream() +// .sorted((entry1, entry2) -> Integer.compare(entry2.getValue().size(), entry1.getValue().size())) +// .collect(Collectors.toList()); +// section.setTopProblemTypes(topProblemTypes); + + // 重点单位 TOP3 + section.setTopUnits(closedStats.getTopUnits().stream().limit(3).toList()); + // 重点人员 TOP3 + section.setTopPersons(accountabilityStats.getTopPersons().stream().limit(3).toList()); - List topProblemTypes = lineList.stream() - .collect(Collectors.groupingBy( - vo -> leafProblemLabel(vo.getProblemSourcesCode(), idMap), - Collectors.counting() - )) - .entrySet().stream() - .sorted((a, b) -> Long.compare(b.getValue(), a.getValue())) - .limit(3) - .map(e -> buildRankItem( - e.getKey(), - e.getValue().intValue(), - safePercentString(e.getValue().intValue(), totalIssued) - )) - .toList(); - section.setTopProblemTypes(topProblemTypes); - - List topUnits = lineList.stream() - .filter(one -> StrUtil.isNotBlank(one.getInvolveDepartName())) - .collect(Collectors.groupingBy(NegativeQueryVo::getInvolveDepartName, Collectors.counting())) - .entrySet().stream() - .sorted((a, b) -> Long.compare(b.getValue(), a.getValue())) - .limit(3) - .map(e -> buildRankItem( - e.getKey(), - e.getValue().intValue(), - safePercentString(e.getValue().intValue(), totalIssued) - )) - .toList(); - section.setTopUnits(topUnits); - - List topPersons = buildTopPersons(lineList, totalIssued); - section.setTopPersons(topPersons); int currentCount = totalIssued; int momCount = momGroup.getOrDefault(fatherBusinessLineName, Collections.emptyList()).size(); int yoyCount = yoyGroup.getOrDefault(fatherBusinessLineName, Collections.emptyList()).size(); - section.setMomRate(ReportTrendUtil.calcRate(currentCount, momCount)); section.setMomTrend(ReportTrendUtil.calcTrend(currentCount, momCount)); section.setYoyRate(ReportTrendUtil.calcRate(currentCount, yoyCount)); section.setYoyTrend(ReportTrendUtil.calcTrend(currentCount, yoyCount)); - result.add(section); } - + log.info("条线明细计算结束======================================================================================="); return result; } diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java index ffd78c3..3990754 100644 --- a/src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java @@ -1,7 +1,9 @@ package com.biutag.supervision.service.report.impl; +import cn.hutool.core.util.StrUtil; import com.biutag.supervision.constants.enums.CheckStatusEnum; import com.biutag.supervision.constants.enums.ProcessingStatusEnum; +import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineRankItem; import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcRequestDTO; import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO; import com.biutag.supervision.pojo.vo.NegativeQueryVo; @@ -12,6 +14,7 @@ import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; @Service public class ReportClosedStatsServiceImpl implements ReportClosedStatsService { @@ -45,6 +48,19 @@ public class ReportClosedStatsServiceImpl implements ReportClosedStatsService { closedList.size() ); + + // 4. 计算重点单位 TOP3(已办结且部门名称不为空) + List topUnits = closedList.stream() + .filter(one -> StrUtil.isNotBlank(one.getInvolveDepartName())) + .collect(Collectors.groupingBy(NegativeQueryVo::getInvolveDepartName, Collectors.counting())) + .entrySet().stream() + .sorted((a, b) -> Long.compare(b.getValue(), a.getValue())) + .map(e -> new BusinessLineRankItem( + e.getKey(), + e.getValue().intValue(), + ReportTrendUtil.percent(e.getValue().intValue(), closedList.size()) + )) + .toList(); ClosedStatsCalcResponseDTO responseDTO = new ClosedStatsCalcResponseDTO(); responseDTO.setClosedCount(closedList.size()); @@ -57,7 +73,7 @@ public class ReportClosedStatsServiceImpl implements ReportClosedStatsService { responseDTO.setVerifiedList(verifiedList); responseDTO.setBasicallyVerifiedList(basicallyVerifiedList); responseDTO.setUnverifiedList(unverifiedList); - + responseDTO.setTopUnits(topUnits); return responseDTO; } } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java index e6fe0f2..b286146 100644 --- a/src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java @@ -1,28 +1,28 @@ package com.biutag.supervision.service.report.impl; -import cn.hutool.core.util.StrUtil; -import com.biutag.supervision.constants.enums.CheckStatusEnum; -import com.biutag.supervision.constants.enums.ProcessingStatusEnum; import com.biutag.supervision.pojo.dto.report.OverviewSection; import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsRequestDTO; import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO; import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryRequestDTO; import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryResponseDTO; +import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcRequestDTO; +import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO; import com.biutag.supervision.pojo.dto.report.overview.ReportOverviewSectionRequestDTO; import com.biutag.supervision.pojo.param.NegativeQueryParam; import com.biutag.supervision.pojo.vo.NegativeQueryVo; import com.biutag.supervision.service.report.ReportAccountabilityStatsService; import com.biutag.supervision.service.report.ReportBaseQueryService; +import com.biutag.supervision.service.report.ReportClosedStatsService; import com.biutag.supervision.service.report.ReportOverviewSectionService; import com.biutag.supervision.util.ReportTrendUtil; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.stream.Stream; /** * @ClassName ReportOverviewSectionServiceImpl @@ -31,6 +31,7 @@ import java.util.stream.Stream; * @Date 2026/3/9 */ @Service +@Slf4j public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionService { /** @@ -47,6 +48,13 @@ public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionSe @Resource private ReportAccountabilityStatsService reportAccountabilityStatsService; + + /** + * 办结/查实统计服务 + */ + @Resource + private ReportClosedStatsService reportClosedStatsService; + /** * 构建总体概览数据 * @@ -58,7 +66,7 @@ public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionSe if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { return new OverviewSection(); } - + log.info("总览数据开始计算======================================================================================="); NegativeQueryParam request = requestDTO.getNegativeQueryParam(); String periodStart = requestDTO.getPeriodStart(); String periodEnd = requestDTO.getPeriodEnd(); @@ -68,201 +76,124 @@ public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionSe baseRequestDTO.setNegativeQueryParam(request); ReportBaseQueryResponseDTO baseQueryResponseDTO = reportBaseQueryService.queryBaseData(baseRequestDTO); - List ztNegativeList = baseQueryResponseDTO.getCurrentList(); - List hbNegativeList = baseQueryResponseDTO.getMomList(); - List tbNegativeList = baseQueryResponseDTO.getYoyList(); - // 市局下发数据 - List sjxfNegativeList = ztNegativeList.stream() + List currentList = baseQueryResponseDTO.getCurrentList(); + List momList = baseQueryResponseDTO.getMomList(); + List yoyList = baseQueryResponseDTO.getYoyList(); + + // 2. 基础分组数据 + List cityIssuedList = currentList.stream() .filter(one -> Objects.equals(0, one.getCrtDepartLevel())) .toList(); - // 分县市局下发数据 - List fxsjxfNegativeList = ztNegativeList.stream() + List countyIssuedList = currentList.stream() .filter(one -> Objects.equals(2, one.getCrtDepartLevel())) .toList(); - // 本期办结数据 - List bjNegativeList = ztNegativeList.stream() - .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) - .toList(); - - // 本期办结中属实数据 - List bjssNegativeList = bjNegativeList.stream() - .filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) - .toList(); + // 3. 办结/查实统计 + ClosedStatsCalcResponseDTO currentClosedStats = calculateClosedStats(currentList); + ClosedStatsCalcResponseDTO momClosedStats = calculateClosedStats(momList); + ClosedStatsCalcResponseDTO yoyClosedStats = calculateClosedStats(yoyList); - // 本期办结中基本属实数据 - List bjjbssNegativeList = bjNegativeList.stream() - .filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) - .toList(); + // 4. 问责统计 + ReportAccountabilityStatsResponseDTO currentAccountabilityStats = calculateAccountabilityStats(currentList); + ReportAccountabilityStatsResponseDTO momAccountabilityStats = calculateAccountabilityStats(momList); + ReportAccountabilityStatsResponseDTO yoyAccountabilityStats = calculateAccountabilityStats(yoyList); - // 本期办结中不属实数据 - List bjbssNegativeList = bjNegativeList.stream() - .filter(one -> CheckStatusEnum.FALSE_SET.contains(one.getCheckStatusCode())) - .toList(); + // 5. 环比/同比基础值 + int currentTotal = currentList.size(); + int momTotal = momList.size(); + int yoyTotal = yoyList.size(); - // 本期属实 + 基本属实问题ID,用于计算问责数据 - List ssNegativeIds = Stream.concat(bjssNegativeList.stream(), bjjbssNegativeList.stream()) - .map(NegativeQueryVo::getId) - .filter(StrUtil::isNotBlank) - .distinct() - .toList(); - - ReportAccountabilityStatsRequestDTO currentRequestDTO = new ReportAccountabilityStatsRequestDTO(); - currentRequestDTO.setNegativeIds(ssNegativeIds); - ReportAccountabilityStatsResponseDTO currentAccountabilityStats = - reportAccountabilityStatsService.calculateAccountabilityStats(currentRequestDTO); - - // ==================== 环比问责数据 ==================== - - // 环比办结数据 - List hbBjNegativeList = hbNegativeList.stream() - .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) - .toList(); - - // 环比办结中属实数据 - List hbBjssNegativeList = hbBjNegativeList.stream() - .filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) - .toList(); - - // 环比办结中基本属实数据 - List hbBjjbssNegativeList = hbBjNegativeList.stream() - .filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) - .toList(); - - // 环比属实 + 基本属实问题ID - List hbNegativeIds = Stream.concat(hbBjssNegativeList.stream(), hbBjjbssNegativeList.stream()) - .map(NegativeQueryVo::getId) - .filter(StrUtil::isNotBlank) - .distinct() - .toList(); + BigDecimal currentVerifiedRate = defaultZero(currentClosedStats.getVerifiedRate()); + BigDecimal momVerifiedRate = defaultZero(momClosedStats.getVerifiedRate()); + BigDecimal yoyVerifiedRate = defaultZero(yoyClosedStats.getVerifiedRate()); - ReportAccountabilityStatsRequestDTO momRequestDTO = new ReportAccountabilityStatsRequestDTO(); - momRequestDTO.setNegativeIds(hbNegativeIds); - ReportAccountabilityStatsResponseDTO momAccountabilityStats = - reportAccountabilityStatsService.calculateAccountabilityStats(momRequestDTO); - - // ==================== 同比问责数据 ==================== - - // 同比办结数据 - List tbBjNegativeList = tbNegativeList.stream() - .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) - .toList(); - - // 同比办结中属实数据 - List tbBjssNegativeList = tbBjNegativeList.stream() - .filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) - .toList(); - - // 同比办结中基本属实数据 - List tbBjjbssNegativeList = tbBjNegativeList.stream() - .filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) - .toList(); - - // 同比属实 + 基本属实问题ID - List tbNegativeIds = Stream.concat(tbBjssNegativeList.stream(), tbBjjbssNegativeList.stream()) - .map(NegativeQueryVo::getId) - .filter(StrUtil::isNotBlank) - .distinct() - .toList(); - - ReportAccountabilityStatsRequestDTO yoyRequestDTO = new ReportAccountabilityStatsRequestDTO(); - yoyRequestDTO.setNegativeIds(tbNegativeIds); - ReportAccountabilityStatsResponseDTO yoyAccountabilityStats = - reportAccountabilityStatsService.calculateAccountabilityStats(yoyRequestDTO); - - // 本期、环比、同比问题总数 - int current = ztNegativeList.size(); - int mom = hbNegativeList.size(); - int yoy = tbNegativeList.size(); + int currentAccountabilityTotal = currentAccountabilityStats.getTotal(); + int momAccountabilityTotal = momAccountabilityStats.getTotal(); + int yoyAccountabilityTotal = yoyAccountabilityStats.getTotal(); + // 6. 组装结果 OverviewSection overviewSection = new OverviewSection(); - - // 统计区间 overviewSection.setPeriodStart(periodStart); overviewSection.setPeriodEnd(periodEnd); - // 总下发数及环比、同比 - overviewSection.setTotalIssued(ztNegativeList.size()); - overviewSection.setMomRate(ReportTrendUtil.calcRate(current, mom)); - overviewSection.setMomTrend(ReportTrendUtil.calcTrend(current, mom)); - overviewSection.setYoyRate(ReportTrendUtil.calcRate(current, yoy)); - overviewSection.setYoyTrend(ReportTrendUtil.calcTrend(current, yoy)); - - // 市局 / 分县市局下发情况 - overviewSection.setCityIssued(sjxfNegativeList.size()); - overviewSection.setCityRate(ReportTrendUtil.percent(sjxfNegativeList.size(), ztNegativeList.size())); - overviewSection.setCountyIssued(fxsjxfNegativeList.size()); - overviewSection.setCountyRate(ReportTrendUtil.percent(fxsjxfNegativeList.size(), ztNegativeList.size())); - - // 办结情况 - overviewSection.setClosedCount(bjNegativeList.size()); - overviewSection.setVerifiedCount(bjssNegativeList.size()); - overviewSection.setBasicallyVerifiedCount(bjjbssNegativeList.size()); - overviewSection.setUnverifiedCount(bjbssNegativeList.size()); - - // 查实率及环比、同比 - BigDecimal curVerifiedRate = calcVerifiedRate(ztNegativeList); - BigDecimal momVerifiedRate = calcVerifiedRate(hbNegativeList); - BigDecimal yoyVerifiedRate = calcVerifiedRate(tbNegativeList); - - overviewSection.setVerifiedRate(curVerifiedRate); - overviewSection.setVerifiedMomRate(ReportTrendUtil.calcRate(curVerifiedRate, momVerifiedRate)); - overviewSection.setVerifiedMomTrend(ReportTrendUtil.calcTrend(curVerifiedRate, momVerifiedRate)); - overviewSection.setVerifiedYoyRate(ReportTrendUtil.calcRate(curVerifiedRate, yoyVerifiedRate)); - overviewSection.setVerifiedYoyTrend(ReportTrendUtil.calcTrend(curVerifiedRate, yoyVerifiedRate)); - - // 问责数据及环比、同比 - int accountabilityTotal = currentAccountabilityStats.getTotal(); - overviewSection.setAccountabilityTotal(accountabilityTotal); + // 总下发 + overviewSection.setTotalIssued(currentTotal); + overviewSection.setMomRate(ReportTrendUtil.calcRate(currentTotal, momTotal)); + overviewSection.setMomTrend(ReportTrendUtil.calcTrend(currentTotal, momTotal)); + overviewSection.setYoyRate(ReportTrendUtil.calcRate(currentTotal, yoyTotal)); + overviewSection.setYoyTrend(ReportTrendUtil.calcTrend(currentTotal, yoyTotal)); + + // 市局 / 分县市局下发 + overviewSection.setCityIssued(cityIssuedList.size()); + overviewSection.setCityRate(ReportTrendUtil.percent(cityIssuedList.size(), currentTotal)); + overviewSection.setCountyIssued(countyIssuedList.size()); + overviewSection.setCountyRate(ReportTrendUtil.percent(countyIssuedList.size(), currentTotal)); + + // 办结 / 核查 + overviewSection.setClosedCount(currentClosedStats.getClosedCount()); + overviewSection.setVerifiedCount(currentClosedStats.getVerifiedCount()); + overviewSection.setBasicallyVerifiedCount(currentClosedStats.getBasicallyVerifiedCount()); + overviewSection.setUnverifiedCount(currentClosedStats.getUnverifiedCount()); + overviewSection.setVerifiedAndBasicallyVerifiedCount(currentClosedStats.getVerifiedCount() + currentClosedStats.getBasicallyVerifiedCount()); + + // 查实率 + overviewSection.setVerifiedRate(currentVerifiedRate); + overviewSection.setVerifiedMomRate(ReportTrendUtil.calcRate(currentVerifiedRate, momVerifiedRate)); + overviewSection.setVerifiedMomTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, momVerifiedRate)); + overviewSection.setVerifiedYoyRate(ReportTrendUtil.calcRate(currentVerifiedRate, yoyVerifiedRate)); + overviewSection.setVerifiedYoyTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, yoyVerifiedRate)); + + // 问责统计 + overviewSection.setAccountabilityProblemTotal(currentAccountabilityStats.getAccountabilityNegativeCount()); + overviewSection.setAccountabilityTotal(currentAccountabilityTotal); overviewSection.setPersonalAccountability(currentAccountabilityStats.getPersonal()); overviewSection.setUnitAccountability(currentAccountabilityStats.getUnit()); - overviewSection.setAccountabilityMomRate(ReportTrendUtil.calcRate(accountabilityTotal, momAccountabilityStats.getTotal())); - overviewSection.setAccountabilityMomTrend(ReportTrendUtil.calcTrend(accountabilityTotal, momAccountabilityStats.getTotal())); - overviewSection.setAccountabilityYoyRate(ReportTrendUtil.calcRate(accountabilityTotal, yoyAccountabilityStats.getTotal())); - overviewSection.setAccountabilityYoyTrend(ReportTrendUtil.calcTrend(accountabilityTotal, yoyAccountabilityStats.getTotal())); - - // 集中问题 - Map.Entry problemEntry = - ReportTrendUtil.topBy(NegativeQueryVo::getProblemSources, bjssNegativeList, bjjbssNegativeList); + overviewSection.setAccountabilityMomRate(ReportTrendUtil.calcRate(currentAccountabilityTotal, momAccountabilityTotal)); + overviewSection.setAccountabilityMomTrend(ReportTrendUtil.calcTrend(currentAccountabilityTotal, momAccountabilityTotal)); + overviewSection.setAccountabilityYoyRate(ReportTrendUtil.calcRate(currentAccountabilityTotal, yoyAccountabilityTotal)); + overviewSection.setAccountabilityYoyTrend(ReportTrendUtil.calcTrend(currentAccountabilityTotal, yoyAccountabilityTotal)); + + // 集中问题(基于属实 + 基本属实) + Map.Entry problemEntry = ReportTrendUtil.topBy( + NegativeQueryVo::getProblemSources, + currentClosedStats.getVerifiedList(), + currentClosedStats.getBasicallyVerifiedList() + ); overviewSection.setTopProblemProject(problemEntry != null ? problemEntry.getKey() : null); - // 重点关注单位 - Map.Entry departEntry = - ReportTrendUtil.topBy(NegativeQueryVo::getInvolveDepartName, bjssNegativeList, bjjbssNegativeList); + // 重点关注单位(基于属实 + 基本属实) + Map.Entry departEntry = ReportTrendUtil.topBy(NegativeQueryVo::getInvolveDepartName, + currentClosedStats.getVerifiedList(), + currentClosedStats.getBasicallyVerifiedList() + ); overviewSection.setTopProblemUnit(departEntry != null ? departEntry.getKey() : null); + log.info("总览数据计算结束======================================================================================="); return overviewSection; } + private ClosedStatsCalcResponseDTO calculateClosedStats(List list) { + ClosedStatsCalcRequestDTO requestDTO = new ClosedStatsCalcRequestDTO(); + requestDTO.setNegativeQueryVoList(list); + return reportClosedStatsService.calculateClosedStats(requestDTO); + } + + /** - * 计算查实率 - * 查实率 = (属实数 + 基本属实数)/ 办结数 * 100 - * - * @param list 问题数据列表 - * @return 查实率 + * 统一计算问责统计 */ - private BigDecimal calcVerifiedRate(List list) { - // 办结数据 - List closed = list.stream() - .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) - .toList(); + private ReportAccountabilityStatsResponseDTO calculateAccountabilityStats(List list) { + ReportAccountabilityStatsRequestDTO requestDTO = new ReportAccountabilityStatsRequestDTO(); + requestDTO.setNegativeQueryVoList(list); + return reportAccountabilityStatsService.calculateAccountabilityStats(requestDTO); + } + + private BigDecimal defaultZero(BigDecimal value) { + return value == null ? BigDecimal.ZERO : value; + } - int closedCount = closed.size(); - if (closedCount == 0) { - return BigDecimal.ZERO; - } - // 属实数 - int verified = (int) closed.stream() - .filter(n -> CheckStatusEnum.TRUE_SET.contains(n.getCheckStatusCode())) - .count(); - // 基本属实数 - int partVerified = (int) closed.stream() - .filter(n -> CheckStatusEnum.PART_TRUE_SET.contains(n.getCheckStatusCode())) - .count(); - return ReportTrendUtil.percent(verified + partVerified, closedCount); - } } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportUnitInvestigationSectionServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportUnitInvestigationSectionServiceImpl.java index e931af5..8481ded 100644 --- a/src/main/java/com/biutag/supervision/service/report/impl/ReportUnitInvestigationSectionServiceImpl.java +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportUnitInvestigationSectionServiceImpl.java @@ -41,6 +41,7 @@ public class ReportUnitInvestigationSectionServiceImpl implements ReportUnitInve @Override public UnitInvestigationOverviewSection buildUnitInvestigationOverviewSection(ReportUnitInvestigationSectionRequestDTO requestDTO) { + log.info("单位查处情况总览开始计算======================================================================================="); if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { return new UnitInvestigationOverviewSection(); } @@ -88,7 +89,9 @@ public class ReportUnitInvestigationSectionServiceImpl implements ReportUnitInve topUnits.sort(Comparator.comparing(UnitInvestigationItem::getVerifiedProblemCount).reversed()); topUnits = topUnits.stream().limit(3).toList(); - + for (int i = 0; i < topUnits.size(); i++) { + topUnits.get(i).setRank(i + 1); + } UnitInvestigationOverviewSection section = new UnitInvestigationOverviewSection(); section.setPeriodStart(periodStart); section.setPeriodEnd(periodEnd); @@ -112,7 +115,7 @@ public class ReportUnitInvestigationSectionServiceImpl implements ReportUnitInve .size(500, 300) .create(); section.setUnitBarChart(picture); - + log.info("单位查处情况总览计算结束======================================================================================="); return section; } } \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/util/ReportTrendUtil.java b/src/main/java/com/biutag/supervision/util/ReportTrendUtil.java index 119aed4..28633f8 100644 --- a/src/main/java/com/biutag/supervision/util/ReportTrendUtil.java +++ b/src/main/java/com/biutag/supervision/util/ReportTrendUtil.java @@ -107,6 +107,7 @@ public class ReportTrendUtil { return TrendEnum.STABLE; } + @SafeVarargs public static Map.Entry topBy(Function mapper, List... lists) { return Arrays.stream(lists) diff --git a/src/main/resources/static/templates/督审一体化平台研判分析报告.docx b/src/main/resources/static/templates/督审一体化平台研判分析报告.docx index 3fe6b2e432e69ba9b2d1f318b5de8a44ddf3e019..dcd537fa762e430670ded58074f77700450b2adc 100644 GIT binary patch delta 8045 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 JB;J2^{{uw=!VUlc