From f73e82c4d44337c4f0af284ff4e5fcaa66d978a5 Mon Sep 17 00:00:00 2001 From: buaixuexideshitongxue <2936013465@qq.com> Date: Mon, 9 Mar 2026 18:48:29 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A0=94=E5=88=A4=E5=88=86=E6=9E=90--step6?= =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E9=87=8D=E6=9E=84=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pojo/dto/report/ReportViewModel.java | 4 +- ...on.java => AccountabilityUnitSection.java} | 2 +- ...ReportAccountabilitySectionRequestDTO.java | 21 + .../ReportAccountabilityStatsRequestDTO.java | 24 + .../ReportAccountabilityStatsResponseDTO.java | 41 + .../base/ReportBaseQueryRequestDTO.java | 16 + .../base/ReportBaseQueryResponseDTO.java | 25 + .../ReportBusinessLineSectionRequestDTO.java | 21 + .../closed/ClosedStatsCalcRequestDTO.java | 19 + .../closed/ClosedStatsCalcResponseDTO.java | 44 + .../ReportOverviewSectionRequestDTO.java | 21 + ...ortUnitInvestigationSectionRequestDTO.java | 21 + .../ReportAccountabilitySectionService.java | 30 + .../ReportAccountabilityStatsService.java | 17 + .../report/ReportBaseQueryService.java | 17 + .../ReportBusinessLineSectionService.java | 27 + .../report/ReportClosedStatsService.java | 14 + .../service/report/ReportDataServiceImpl.java | 875 ------------------ .../report/ReportOverviewSectionService.java | 17 + ...ReportUnitInvestigationSectionService.java | 16 + ...eportAccountabilitySectionServiceImpl.java | 175 ++++ .../ReportAccountabilityStatsServiceImpl.java | 76 ++ .../impl/ReportBaseQueryServiceImpl.java | 53 ++ .../ReportBusinessLineSectionServiceImpl.java | 425 +++++++++ .../impl/ReportClosedStatsServiceImpl.java | 63 ++ .../report/impl/ReportDataServiceImpl.java | 68 ++ .../ReportOverviewSectionServiceImpl.java | 268 ++++++ ...rtUnitInvestigationSectionServiceImpl.java | 118 +++ ...审一体化平台研判分析报告.docx | Bin 80365 -> 15663 bytes 29 files changed, 1640 insertions(+), 878 deletions(-) rename src/main/java/com/biutag/supervision/pojo/dto/report/accountability/{AccountabilityDepartmentSection.java => AccountabilityUnitSection.java} (92%) create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilitySectionRequestDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryRequestDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryResponseDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/ReportBusinessLineSectionRequestDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcRequestDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcResponseDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/overview/ReportOverviewSectionRequestDTO.java create mode 100644 src/main/java/com/biutag/supervision/pojo/dto/report/unitInvestigation/ReportUnitInvestigationSectionRequestDTO.java create mode 100644 src/main/java/com/biutag/supervision/service/report/ReportAccountabilitySectionService.java create mode 100644 src/main/java/com/biutag/supervision/service/report/ReportAccountabilityStatsService.java create mode 100644 src/main/java/com/biutag/supervision/service/report/ReportBaseQueryService.java create mode 100644 src/main/java/com/biutag/supervision/service/report/ReportBusinessLineSectionService.java create mode 100644 src/main/java/com/biutag/supervision/service/report/ReportClosedStatsService.java delete mode 100644 src/main/java/com/biutag/supervision/service/report/ReportDataServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/ReportOverviewSectionService.java create mode 100644 src/main/java/com/biutag/supervision/service/report/ReportUnitInvestigationSectionService.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportBaseQueryServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportDataServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java create mode 100644 src/main/java/com/biutag/supervision/service/report/impl/ReportUnitInvestigationSectionServiceImpl.java diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/ReportViewModel.java b/src/main/java/com/biutag/supervision/pojo/dto/report/ReportViewModel.java index c479913..83e019c 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/ReportViewModel.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/ReportViewModel.java @@ -1,6 +1,6 @@ package com.biutag.supervision.pojo.dto.report; -import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityDepartmentSection; +import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityUnitSection; import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityOverviewSection; import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityPersonalSection; import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineDetailSection; @@ -53,7 +53,7 @@ public class ReportViewModel { // 分开 预留可修改空间 @Schema(description = "单位问责追责情况明细") - private AccountabilityDepartmentSection accountabilityUnitDetailSection; + private AccountabilityUnitSection accountabilityUnitDetailSection; @Schema(description = "个人问责追责情况") private AccountabilityPersonalSection accountabilityPersonOverviewSection; diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/AccountabilityDepartmentSection.java b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/AccountabilityUnitSection.java similarity index 92% rename from src/main/java/com/biutag/supervision/pojo/dto/report/accountability/AccountabilityDepartmentSection.java rename to src/main/java/com/biutag/supervision/pojo/dto/report/accountability/AccountabilityUnitSection.java index 5bcaaea..a47d29c 100644 --- a/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/AccountabilityDepartmentSection.java +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/AccountabilityUnitSection.java @@ -10,7 +10,7 @@ import java.util.List; @Getter @Setter @Schema(description = "对单位追责问责情况") -public class AccountabilityDepartmentSection { +public class AccountabilityUnitSection { @Schema(description = "问责单位总次数", example = "6") private Integer totalCount; diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilitySectionRequestDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilitySectionRequestDTO.java new file mode 100644 index 0000000..aa431d2 --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilitySectionRequestDTO.java @@ -0,0 +1,21 @@ +package com.biutag.supervision.pojo.dto.report.accountability; + +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Schema(description = "报表问责模块构建请求DTO") +public class ReportAccountabilitySectionRequestDTO { + + @Schema(description = "查询参数") + private NegativeQueryParam negativeQueryParam; + + @Schema(description = "统计开始时间", example = "2026年3月1日") + private String periodStart; + + @Schema(description = "统计结束时间", example = "2026年3月31日") + private String periodEnd; +} \ No newline at end of file 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 new file mode 100644 index 0000000..654ad04 --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java @@ -0,0 +1,24 @@ +package com.biutag.supervision.pojo.dto.report.accountability; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * @ClassName ReportAccountabilityStatsRequestDTO + * @Description 报表问责统计请求DTO + * @Author shihao + * @Date 2026/3/9 15:29 + */ +@Getter +@Setter +@Schema(description = "报表问责统计请求DTO") +public class ReportAccountabilityStatsRequestDTO { + + @Schema(description = "问题ID列表") + private List negativeIds = new ArrayList<>(); + +} \ 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 new file mode 100644 index 0000000..f28a91a --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java @@ -0,0 +1,41 @@ +package com.biutag.supervision.pojo.dto.report.accountability; + + +import com.biutag.supervision.pojo.entity.NegativeBlame; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * @ClassName ReportAccountabilityStatsResponseDTO + * @Description 报表问责统计结果DTO + * @Author shihao + * @Date 2026/3/9 15:29 + */ +@Getter +@Setter +@Schema(description = "报表问责统计结果DTO") +public class ReportAccountabilityStatsResponseDTO { + + @Schema(description = "问责总数 = 个人问责 + 领导问责 + 单位问责", example = "12") + private int total; + + @Schema(description = "个人问责数 = 个人问责 + 领导问责", example = "8") + private int personal; + + @Schema(description = "单位问责数", example = "4") + private int unit; + + @Schema(description = "个人问责列表") + private List personalBlames = new ArrayList<>(); + + @Schema(description = "领导问责列表") + private List leadBlames = new ArrayList<>(); + + @Schema(description = "单位问责列表") + private List unitBlames = new ArrayList<>(); + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryRequestDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryRequestDTO.java new file mode 100644 index 0000000..42f5db3 --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryRequestDTO.java @@ -0,0 +1,16 @@ +package com.biutag.supervision.pojo.dto.report.base; + +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Schema(description = "报表基础查询请求DTO") +public class ReportBaseQueryRequestDTO { + + @Schema(description = "报表查询参数") + private NegativeQueryParam negativeQueryParam; + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryResponseDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryResponseDTO.java new file mode 100644 index 0000000..df1fd64 --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/base/ReportBaseQueryResponseDTO.java @@ -0,0 +1,25 @@ +package com.biutag.supervision.pojo.dto.report.base; + +import com.biutag.supervision.pojo.vo.NegativeQueryVo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@Schema(description = "报表基础查询结果DTO") +public class ReportBaseQueryResponseDTO { + + @Schema(description = "本期数据列表") + private List currentList = new ArrayList<>(); + + @Schema(description = "环比数据列表") + private List momList = new ArrayList<>(); + + @Schema(description = "同比数据列表") + private List yoyList = new ArrayList<>(); + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/ReportBusinessLineSectionRequestDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/ReportBusinessLineSectionRequestDTO.java new file mode 100644 index 0000000..76868bc --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/ReportBusinessLineSectionRequestDTO.java @@ -0,0 +1,21 @@ +package com.biutag.supervision.pojo.dto.report.businessLine; + +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Schema(description = "报表业务条线模块构建请求DTO") +public class ReportBusinessLineSectionRequestDTO { + + @Schema(description = "查询参数") + private NegativeQueryParam negativeQueryParam; + + @Schema(description = "统计开始时间", example = "2026年3月1日") + private String periodStart; + + @Schema(description = "统计结束时间", example = "2026年3月31日") + private String periodEnd; +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcRequestDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcRequestDTO.java new file mode 100644 index 0000000..619b82c --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcRequestDTO.java @@ -0,0 +1,19 @@ +package com.biutag.supervision.pojo.dto.report.closed; + +import com.biutag.supervision.pojo.vo.NegativeQueryVo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@Schema(description = "办结统计计算请求DTO") +public class ClosedStatsCalcRequestDTO { + + @Schema(description = "待统计的问题数据列表") + private List negativeQueryVoList = new ArrayList<>(); + +} \ No newline at end of file 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 new file mode 100644 index 0000000..e953186 --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcResponseDTO.java @@ -0,0 +1,44 @@ +package com.biutag.supervision.pojo.dto.report.closed; + +import com.biutag.supervision.pojo.vo.NegativeQueryVo; +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; + +@Getter +@Setter +@Schema(description = "办结统计计算结果DTO") +public class ClosedStatsCalcResponseDTO { + + @Schema(description = "办结总数") + private int closedCount; + + @Schema(description = "属实数量") + private int verifiedCount; + + @Schema(description = "基本属实数量") + private int basicallyVerifiedCount; + + @Schema(description = "不属实数量") + private int unverifiedCount; + + @Schema(description = "查实率(百分比)") + private BigDecimal verifiedRate; + + @Schema(description = "办结问题列表") + private List closedList = new ArrayList<>(); + + @Schema(description = "属实问题列表") + private List verifiedList = new ArrayList<>(); + + @Schema(description = "基本属实问题列表") + private List basicallyVerifiedList = new ArrayList<>(); + + @Schema(description = "不属实问题列表") + private List unverifiedList = new ArrayList<>(); + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/overview/ReportOverviewSectionRequestDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/overview/ReportOverviewSectionRequestDTO.java new file mode 100644 index 0000000..ed701fd --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/overview/ReportOverviewSectionRequestDTO.java @@ -0,0 +1,21 @@ +package com.biutag.supervision.pojo.dto.report.overview; + +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Schema(description = "报表总体概览构建请求DTO") +public class ReportOverviewSectionRequestDTO { + + @Schema(description = "查询参数") + private NegativeQueryParam negativeQueryParam; + + @Schema(description = "统计开始时间", example = "2026年3月1日") + private String periodStart; + + @Schema(description = "统计结束时间", example = "2026年3月31日") + private String periodEnd; +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/pojo/dto/report/unitInvestigation/ReportUnitInvestigationSectionRequestDTO.java b/src/main/java/com/biutag/supervision/pojo/dto/report/unitInvestigation/ReportUnitInvestigationSectionRequestDTO.java new file mode 100644 index 0000000..62dc8cf --- /dev/null +++ b/src/main/java/com/biutag/supervision/pojo/dto/report/unitInvestigation/ReportUnitInvestigationSectionRequestDTO.java @@ -0,0 +1,21 @@ +package com.biutag.supervision.pojo.dto.report.unitInvestigation; + +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Schema(description = "报表单位查处模块构建请求DTO") +public class ReportUnitInvestigationSectionRequestDTO { + + @Schema(description = "查询参数") + private NegativeQueryParam negativeQueryParam; + + @Schema(description = "统计开始时间", example = "2026年3月1日") + private String periodStart; + + @Schema(description = "统计结束时间", example = "2026年3月31日") + private String periodEnd; +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportAccountabilitySectionService.java b/src/main/java/com/biutag/supervision/service/report/ReportAccountabilitySectionService.java new file mode 100644 index 0000000..c895b1c --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/ReportAccountabilitySectionService.java @@ -0,0 +1,30 @@ +package com.biutag.supervision.service.report; + +import com.biutag.supervision.pojo.dto.report.accountability.*; + +public interface ReportAccountabilitySectionService { + + /** + * 构建问责追责总览 + * + * @param requestDTO 请求参数 + * @return 构建结果 + */ + AccountabilityOverviewSection buildAccountabilityOverviewSection(ReportAccountabilitySectionRequestDTO requestDTO); + + /** + * 构建单位问责明细 + * + * @param requestDTO 请求参数 + * @return 构建结果 + */ + AccountabilityUnitSection buildAccountabilityUnitDetailSection(ReportAccountabilitySectionRequestDTO requestDTO); + + /** + * 构建个人问责明细 + * + * @param requestDTO 请求参数 + * @return 构建结果 + */ + AccountabilityPersonalSection buildAccountabilityPersonalOverviewSection(ReportAccountabilitySectionRequestDTO requestDTO); +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportAccountabilityStatsService.java b/src/main/java/com/biutag/supervision/service/report/ReportAccountabilityStatsService.java new file mode 100644 index 0000000..e4ad398 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/ReportAccountabilityStatsService.java @@ -0,0 +1,17 @@ +package com.biutag.supervision.service.report; + +import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsRequestDTO; +import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO; + + +public interface ReportAccountabilityStatsService { + + /** + * 计算问责统计数据 + * + * @param requestDTO 请求参数 + * @return 统计结果 + */ + ReportAccountabilityStatsResponseDTO calculateAccountabilityStats(ReportAccountabilityStatsRequestDTO requestDTO); + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportBaseQueryService.java b/src/main/java/com/biutag/supervision/service/report/ReportBaseQueryService.java new file mode 100644 index 0000000..a13c338 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/ReportBaseQueryService.java @@ -0,0 +1,17 @@ +package com.biutag.supervision.service.report; + +import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryRequestDTO; +import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryResponseDTO; + + +public interface ReportBaseQueryService { + + /** + * 查询报表本期、环比、同比基础数据 + * + * @param requestDTO 查询请求 + * @return 查询结果 + */ + ReportBaseQueryResponseDTO queryBaseData(ReportBaseQueryRequestDTO requestDTO); + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportBusinessLineSectionService.java b/src/main/java/com/biutag/supervision/service/report/ReportBusinessLineSectionService.java new file mode 100644 index 0000000..457b795 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/ReportBusinessLineSectionService.java @@ -0,0 +1,27 @@ +package com.biutag.supervision.service.report; + +import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineDetailSection; +import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineOverviewSection; +import com.biutag.supervision.pojo.dto.report.businessLine.ReportBusinessLineSectionRequestDTO; +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.List; + +public interface ReportBusinessLineSectionService { + + /** + * 构建业务条线总览 + * + * @param requestDTO 请求参数 + * @return 构建结果 + */ + BusinessLineOverviewSection buildBusinessLineOverviewSection(ReportBusinessLineSectionRequestDTO requestDTO); + + /** + * 构建业务条线明细 + * + * @param requestDTO 请求参数 + * @return 构建结果 + */ + List buildBusinessLineDetailSections(ReportBusinessLineSectionRequestDTO requestDTO); +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportClosedStatsService.java b/src/main/java/com/biutag/supervision/service/report/ReportClosedStatsService.java new file mode 100644 index 0000000..5852250 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/ReportClosedStatsService.java @@ -0,0 +1,14 @@ +package com.biutag.supervision.service.report; + +import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcRequestDTO; +import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO; + + +public interface ReportClosedStatsService { + + /** + * 计算办结统计数据 + */ + ClosedStatsCalcResponseDTO calculateClosedStats(ClosedStatsCalcRequestDTO requestDTO); + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportDataServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/ReportDataServiceImpl.java deleted file mode 100644 index bae68be..0000000 --- a/src/main/java/com/biutag/supervision/service/report/ReportDataServiceImpl.java +++ /dev/null @@ -1,875 +0,0 @@ -package com.biutag.supervision.service.report; - -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.DepartAndSubDepartDto; -import com.biutag.supervision.pojo.dto.report.OverviewSection; -import com.biutag.supervision.pojo.dto.report.ReportViewModel; -import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityDepartmentSection; -import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityOverviewSection; -import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityPersonalSection; -import com.biutag.supervision.pojo.dto.report.accountability.AccountabilityTypeItem; -import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineDetailSection; -import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineOverviewSection; -import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLinePersonRankItem; -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.dto.report.unitInvestigation.UnitInvestigationItem; -import com.biutag.supervision.pojo.dto.report.unitInvestigation.UnitInvestigationOverviewSection; -import com.biutag.supervision.pojo.entity.NegativeBlame; -import com.biutag.supervision.pojo.enums.report.TrendEnum; -import com.biutag.supervision.pojo.param.NegativeQueryParam; -import com.biutag.supervision.pojo.param.SupDepartGroupParam; -import com.biutag.supervision.pojo.param.negativeBlame.NegativeBlameQueryParam; -import com.biutag.supervision.pojo.vo.DictProblemSourceTree; -import com.biutag.supervision.pojo.vo.NegativeQueryVo; -import com.biutag.supervision.repository.negative.NegativeResourceService; -import com.biutag.supervision.repository.negativeBlame.NegativeBlameResourceService; -import com.biutag.supervision.repository.supdepart.SupDepartResourceService; -import com.biutag.supervision.service.NegativeQueryService; -import com.biutag.supervision.service.SupDictProblemSourceService; -import com.biutag.supervision.util.ChartRenderUtil; -import com.biutag.supervision.util.DateCompareRangeUtil; -import com.biutag.supervision.util.ReportTrendUtil; -import com.biutag.supervision.util.TimeUtil; -import com.deepoove.poi.data.PictureRenderData; -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; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -@Service -@Slf4j -public class ReportDataServiceImpl implements ReportDataService { - - @Resource - private NegativeResourceService negativeResourceService; - - @Resource - private NegativeBlameResourceService negativeBlameResourceService; - - @Resource - private NegativeQueryService negativeQueryService; - - @Resource - private SupDictProblemSourceService supDictProblemSourceService; - - @Resource - private SupDepartResourceService supDepartResourceService; - - @Resource - private ReportClosedStatsService reportClosedStatsService; - - @Resource - private ReportBaseQueryService reportBaseQueryService; - - // 一定要拆分为弱领域模型 不然不能维护 - @Override - public ReportViewModel buildViewModel(NegativeQueryParam request) { - String periodStart = TimeUtil.formatDate(request.getCrtTime().get(0)); - String periodEnd = TimeUtil.formatDate(request.getCrtTime().get(1)); - ReportViewModel vm = new ReportViewModel(); - vm.setPeriodStart(periodStart); - vm.setPeriodEnd(periodEnd); - // 总体概览 - vm.setOverviewSection(buildOverviewSection(request, periodStart, periodEnd)); - // 各业务条线情况-总览部分 - vm.setBusinessLineOverviewSection(buildBusinessLineOverviewSection(request, periodStart, periodEnd)); - // 各业务条线情况-明细部分 - vm.setBusinessLineDetailSections(buildBusinessLineDetailSections(request, periodStart, periodEnd)); - // 单位查处情况总览 - vm.setUnitInvestigationOverviewSection(buildUnitInvestigationOverviewSection(request, periodStart, periodEnd)); - // 问责追责情况总览 - vm.setAccountabilityOverviewSection(buildAccountabilityOverviewSection(request, periodStart, periodEnd)); - // 单位问责追责情况明细 - vm.setAccountabilityUnitDetailSection(buildAccountabilityUnitDetailSection(request, periodStart, periodEnd)); - // 个人问责追责情况 - vm.setAccountabilityPersonOverviewSection(buildAccountabilityPersonOverviewSection(request, periodStart, periodEnd)); -// System.out.println(1/0); - return vm; - } - - private AccountabilityPersonalSection buildAccountabilityPersonOverviewSection(NegativeQueryParam request, String periodStart, String periodEnd) { - NegativeQueryParam ztnegativeQueryParam = request.newQueryParam(); - List ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); - List ztNegativeIds = ztNegativeList.stream().map(NegativeQueryVo::getId).toList(); - AccountabilityStats accountabilityStats = buildAccountabilityStats(ztNegativeIds); - // 个人问责 - Map> leadMap = accountabilityStats.getLeadBlames().stream().collect(Collectors.groupingBy(NegativeBlame::getLeadHandleResultName)); - Map> personMap = accountabilityStats.getPersonalBlames().stream().collect(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; - }) - ); - AccountabilityPersonalSection accountabilityPersonalSection = new AccountabilityPersonalSection(); - accountabilityPersonalSection.setTotalCount(accountabilityStats.getPersonal()); - // 构造 typeItems - List typeItems = mergedMap.entrySet().stream() - .map(entry -> { - AccountabilityTypeItem item = new AccountabilityTypeItem(); - item.setTypeName(entry.getKey()); - item.setCount(entry.getValue().size()); - return item; - }) - .sorted(Comparator.comparing(AccountabilityTypeItem::getCount).reversed()) - .toList(); - accountabilityPersonalSection.setTypeItems(typeItems); - - // 饼图 - Map pieData = new LinkedHashMap<>(); - for (AccountabilityTypeItem typeItem : typeItems) { - pieData.put(typeItem.getTypeName(), typeItem.getCount()); - } - byte[] pieBytes = ChartRenderUtil.piePng("单位问责情况", pieData, 5, 900, 520); - PictureRenderData picture = Pictures.ofBytes(pieBytes, PictureType.PNG) - .size(500, 300) - .create(); - accountabilityPersonalSection.setPersonPieChart(picture); - - return accountabilityPersonalSection; - } - - /** - * 单位问责情况 - * - * @param request - * @param periodStart - * @param periodEnd - * @return - */ - private AccountabilityDepartmentSection buildAccountabilityUnitDetailSection(NegativeQueryParam request, String periodStart, String periodEnd) { - NegativeQueryParam ztnegativeQueryParam = request.newQueryParam(); - List ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); - List ztNegativeIds = ztNegativeList.stream().map(NegativeQueryVo::getId).toList(); - AccountabilityStats accountabilityStats = buildAccountabilityStats(ztNegativeIds); - // 单位问责 - Map> unitMap = accountabilityStats.getUnitBlames().stream().collect(Collectors.groupingBy(NegativeBlame::getHandleResultName)); - - AccountabilityDepartmentSection accountabilityDepartmentSection = new AccountabilityDepartmentSection(); - accountabilityDepartmentSection.setTotalCount(accountabilityStats.getUnit()); - // 构造 typeItems - List typeItems = unitMap.entrySet().stream() - .map(entry -> { - AccountabilityTypeItem item = new AccountabilityTypeItem(); - item.setTypeName(entry.getKey()); - item.setCount(entry.getValue().size()); - return item; - }) - .sorted(Comparator.comparing(AccountabilityTypeItem::getCount).reversed()) - .toList(); - accountabilityDepartmentSection.setTypeItems(typeItems); - - // 饼图 - Map pieData = new LinkedHashMap<>(); - for (AccountabilityTypeItem typeItem : typeItems) { - pieData.put(typeItem.getTypeName(), typeItem.getCount()); - } - byte[] pieBytes = ChartRenderUtil.piePng("单位问责情况", pieData, 5, 900, 520); - PictureRenderData picture = Pictures.ofBytes(pieBytes, PictureType.PNG) - .size(500, 300) - .create(); - accountabilityDepartmentSection.setDepartPieChart(picture); - return accountabilityDepartmentSection; - } - - /** - * 问责追责总览 - * - * @param request - * @param periodStart - * @param periodEnd - * @return - */ - private AccountabilityOverviewSection buildAccountabilityOverviewSection(NegativeQueryParam request, String periodStart, String periodEnd) { - // 总体数据 - NegativeQueryParam ztnegativeQueryParam = request.newQueryParam(); - List ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); - List tzNegativeIds = ztNegativeList.stream().map(NegativeQueryVo::getId).toList(); - AccountabilityStats accountabilityStats = buildAccountabilityStats(tzNegativeIds); - AccountabilityOverviewSection accountabilityOverviewSection = new AccountabilityOverviewSection(); - accountabilityOverviewSection.setPeriodStart(periodStart); - accountabilityOverviewSection.setPeriodEnd(periodEnd); - accountabilityOverviewSection.setProblemTypeCount(ztNegativeList.size()); - accountabilityOverviewSection.setPersonalAccountabilityCount(accountabilityStats.personal); - accountabilityOverviewSection.setDepartmentAccountabilityCount(accountabilityStats.unit); - return accountabilityOverviewSection; - } - - private UnitInvestigationOverviewSection buildUnitInvestigationOverviewSection(NegativeQueryParam request, - String periodStart, - String periodEnd) { - DateCompareRangeUtil.CompareDateRange compareDateRange = DateCompareRangeUtil.buildCompareDateRange(request.getCrtTime().get(0), request.getCrtTime().get(1)); - // 总体数据 - NegativeQueryParam ztnegativeQueryParam = request.newQueryParam(); - List ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); - SupDepartGroupParam supDepartGroupParam = new SupDepartGroupParam(); - supDepartGroupParam.setParentLevel(2); - supDepartGroupParam.setChildLevel(3); - Map departAndSubDepart = supDepartResourceService.getDepartAndSubDepart(supDepartGroupParam); - List topUnits = new ArrayList<>(); - for (DepartAndSubDepartDto value : departAndSubDepart.values()) { - Set allDepartIds = value.getAllDepartIds(); - List voList = ztNegativeList.stream().filter(one -> allDepartIds.contains(one.getInvolveDepartId())).toList(); - log.info(value.getParentName() + "的数量=====================" + voList.size()); - if (CollectionUtil.isNotEmpty(voList)) { - UnitInvestigationItem unitInvestigationItem = new UnitInvestigationItem(); - unitInvestigationItem.setUnitName(value.getParentName()); - unitInvestigationItem.setIssuedProblemCount(voList.size()); - List csList = voList.stream() - .filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode()) - || CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) - .toList(); - unitInvestigationItem.setVerifiedProblemCount(csList.size()); - unitInvestigationItem.setVerifiedRate(ReportTrendUtil.percent(csList.size(), voList.size())); - topUnits.add(unitInvestigationItem); - } - } - topUnits.sort(Comparator.comparing(UnitInvestigationItem::getVerifiedProblemCount).reversed()); - topUnits = topUnits.stream().limit(3).toList(); - UnitInvestigationOverviewSection section = new UnitInvestigationOverviewSection(); - section.setPeriodStart(periodStart); - section.setPeriodEnd(periodEnd); - section.setTopUnits(topUnits); - // 柱状图 - Map> seriesData = new LinkedHashMap<>(); - Map issuedMap = new LinkedHashMap<>(); - Map verifiedMap = new LinkedHashMap<>(); - for (UnitInvestigationItem item : topUnits) { - issuedMap.put(item.getUnitName(), item.getIssuedProblemCount()); - verifiedMap.put(item.getUnitName(), item.getVerifiedProblemCount()); - } - seriesData.put("下发问题数", issuedMap); - seriesData.put("查实问题数", verifiedMap); - byte[] barBytes = ChartRenderUtil.groupedBarPng("单位查处情况", seriesData, "单位", "数量", 1000, 520); - PictureRenderData picture = Pictures.ofBytes(barBytes, PictureType.PNG) - .size(500, 300) - .create(); - section.setUnitBarChart(picture); - return section; - } - - /** - * 业务条线的明细 - * - * @param request - * @param periodStart - * @param periodEnd - * @return - */ - private List buildBusinessLineDetailSections(NegativeQueryParam request, - String periodStart, - String periodEnd) { - DateCompareRangeUtil.CompareDateRange compareDateRange = DateCompareRangeUtil.buildCompareDateRange(request.getCrtTime().get(0), request.getCrtTime().get(1)); - - // 本期数据 - NegativeQueryParam currentQueryParam = request.newQueryParam(); - List currentList = negativeQueryService.page(currentQueryParam).getRecords(); - - // 环比数据 - NegativeQueryParam momQueryParam = request.newQueryParam(); - momQueryParam.setCrtTime(compareDateRange.mom()); - List momList = negativeQueryService.page(momQueryParam).getRecords(); - - // 同比数据 - NegativeQueryParam yoyQueryParam = request.newQueryParam(); - yoyQueryParam.setCrtTime(compareDateRange.yoy()); - List yoyList = negativeQueryService.page(yoyQueryParam).getRecords(); - - 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(); - - if (CollUtil.isEmpty(lineList)) { - continue; - } - - BusinessLineDetailSection section = new BusinessLineDetailSection(); - section.setOrderNo(toChineseOrderNo(index++)); - section.setBusinessFatherLineName(fatherBusinessLineName); - // 这里明细项名称按父级条线展示;若你模板里想展示别的,可自行替换 - section.setBusinessLineName(fatherBusinessLineName); - - // 1. 下发总数 - int totalIssued = lineList.size(); - section.setTotalIssued(totalIssued); - - // 2. 已办结数 - List closedList = lineList.stream() - .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) - .toList(); - section.setClosedCount(closedList.size()); - - // 3. 查实总数 / 查实率 - ClosedStatsCalcRequestDTO closedStatsCalcRequestDTO = new ClosedStatsCalcRequestDTO(); - closedStatsCalcRequestDTO.setNegativeQueryVoList(lineList); - ClosedStatsCalcResponseDTO closedStats = reportClosedStatsService.calcClosedStats(closedStatsCalcRequestDTO); - - int verifiedTotal = Optional.ofNullable(closedStats.getClosedCount()).orElse(0); - section.setVerifiedTotal(verifiedTotal); - section.setVerifiedRate(Optional.ofNullable(closedStats.getVerifiedRate()).orElse(BigDecimal.ZERO)); - - // 4. 问责统计:按本条线内“属实 + 基本属实”的问题统计 - 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(); - - AccountabilityStats accountabilityStats = buildAccountabilityStats(verifiedNegativeIds); - section.setAccountabilityTotal(accountabilityStats.getTotal()); - section.setAccountabilityRate(ReportTrendUtil.calcRate(accountabilityStats.getTotal(), verifiedTotal)); - section.setPersonalAccountabilityCount(accountabilityStats.getPersonal()); - section.setDepartmentAccountabilityCount(accountabilityStats.getUnit()); - - // 5. 问题类型 TOP3(本条线下的二级/叶子问题类型) - 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); - - // 6. 重点单位 TOP3 - 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); - - // 7. 重点人员 TOP3 - List topPersons = buildTopPersons(lineList, totalIssued); - section.setTopPersons(topPersons); - - // 8. 环比 / 同比(按该父级条线的问题下发总数比较) - 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); - } - - return result; - } - - private BusinessLineRankItem buildRankItem(String name, Integer count, String rate) { - BusinessLineRankItem item = new BusinessLineRankItem(); - item.setName(name); - item.setCount(count); - item.setRate(new BigDecimal(rate)); - return item; - } - - private BusinessLinePersonRankItem buildPersonRankItem(String personName, String unitName, String identityName, Integer count, String rate) { - BusinessLinePersonRankItem item = new BusinessLinePersonRankItem(); - item.setPersonName(personName); - item.setUnitName(unitName); - item.setIdentityName(identityName); - item.setCount(count); - item.setRate(new BigDecimal(rate)); - return item; - } - - /** - * 业务条线的总览 - * - * @param request - * @param periodStart - * @param periodEnd - * @return - */ - private BusinessLineOverviewSection buildBusinessLineOverviewSection(NegativeQueryParam request, String periodStart, String periodEnd) { - // 总体数据 - NegativeQueryParam ztNegativeQueryParam = request.newQueryParam(); - List ztNegativeList = negativeQueryService.page(ztNegativeQueryParam).getRecords(); - Map idMap = supDictProblemSourceService.buildIdMap(); - // 计数 - Map aggByParentLabel = ztNegativeList.stream() - .map(NegativeQueryVo::getProblemSourcesCode) // 收集二级id - .map(childId -> parentLabel2Level(childId, idMap)) // 解析未一级label - .collect(Collectors.groupingBy(s -> s, Collectors.counting())); - // 排序 - List> sorted = aggByParentLabel.entrySet().stream() - .sorted((a, b) -> Long.compare(b.getValue(), a.getValue())) - .toList(); - // 3)拼接总览文本(全部列出) - StringBuilder businessLineOverviewText = new StringBuilder(); - for (int i = 0; i < sorted.size(); i++) { - String label = sorted.get(i).getKey(); - int cnt = Math.toIntExact(sorted.get(i).getValue()); - businessLineOverviewText.append(i + 1) - .append("、") - .append(label) - .append(",") - .append(cnt) - .append("条,占比") - .append(ReportTrendUtil.percent(cnt, ztNegativeList.size())) - .append("%;"); - } - BusinessLineOverviewSection businessLineOverviewSection = new BusinessLineOverviewSection(); - businessLineOverviewSection.setPeriodStart(periodStart); - businessLineOverviewSection.setPeriodEnd(periodEnd); - businessLineOverviewSection.setBusinessLineTotal(ztNegativeList.size()); - businessLineOverviewSection.setBusinessLineOverviewText(businessLineOverviewText.toString()); - - Map pieData = new LinkedHashMap<>(); - for (Map.Entry entry : sorted) { - pieData.put(entry.getKey(), entry.getValue()); - } - byte[] pieBytes = ChartRenderUtil.piePng("占比统计", pieData, 5, 900, 520); - PictureRenderData picture = Pictures.ofBytes(pieBytes, PictureType.PNG) - .size(500, 300) - .create(); - businessLineOverviewSection.setProblemPieChart(picture); - return businessLineOverviewSection; - } - - /** - * 总体情况计算 - * - * @param request - * @param periodStart - * @param periodEnd - * @return - */ - private OverviewSection buildOverviewSection(NegativeQueryParam request, String periodStart, String periodEnd) { - - DateCompareRangeUtil.CompareDateRange compareDateRange = DateCompareRangeUtil.buildCompareDateRange(request.getCrtTime().get(0), request.getCrtTime().get(1)); - // 总体数据 - NegativeQueryParam ztnegativeQueryParam = request.newQueryParam(); - List ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); - // 环比数据 - NegativeQueryParam hbNegativeQueryParam = request.newQueryParam(); - hbNegativeQueryParam.setCrtTime(compareDateRange.mom()); - List hbNegativList = negativeQueryService.page(hbNegativeQueryParam).getRecords(); - // 同比数据 - NegativeQueryParam tbNegativeQueryParam = request.newQueryParam(); - tbNegativeQueryParam.setCrtTime(compareDateRange.yoy()); - List tbNegativList = negativeQueryService.page(tbNegativeQueryParam).getRecords(); - // 市局下发数据 - List sjxfNegativeList = ztNegativeList.stream().filter(one -> Objects.equals(0, one.getCrtDepartLevel())).toList(); - // 分县市局下发数据 - List fxsjxfNegativeList = ztNegativeList.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(); - // 办结中基本属实数据 - List bjjbssNegativeList = bjNegativeList.stream().filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())).toList(); - // 办结中不属实数据 - List bjbssNegativeList = bjNegativeList.stream().filter(one -> CheckStatusEnum.FALSE_SET.contains(one.getCheckStatusCode())).toList(); - // 属实 基本属实中的问责数据 - List ssNegativeIds = Stream.concat(bjssNegativeList.stream(), bjjbssNegativeList.stream()) - .map(NegativeQueryVo::getId).filter(StrUtil::isNotBlank).distinct().toList(); - AccountabilityStats currentAccountabilityStats = buildAccountabilityStats(ssNegativeIds); - // ==================== 环比问责数据 ==================== - // 环比办结数据 - List hbBjNegativeList = hbNegativList.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(); - // 环比属实 + 基本属实中的问责数据 - List hbNegativeIds = Stream.concat(hbBjssNegativeList.stream(), hbBjjbssNegativeList.stream()) - .map(NegativeQueryVo::getId) - .filter(StrUtil::isNotBlank) - .distinct() - .toList(); - AccountabilityStats momAccountabilityStats = buildAccountabilityStats(hbNegativeIds); - int hbAccountabilityTotal = momAccountabilityStats.getTotal(); - // ==================== 同比问责数据 ==================== - // 同比办结数据 - List tbBjNegativeList = tbNegativList.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(); - // 同比属实 + 基本属实中的问责数据 - List tbNegativeIds = Stream.concat(tbBjssNegativeList.stream(), tbBjjbssNegativeList.stream()) - .map(NegativeQueryVo::getId) - .filter(StrUtil::isNotBlank) - .distinct() - .toList(); - AccountabilityStats yoyAccountabilityStats = buildAccountabilityStats(tbNegativeIds); - int tbAccountabilityTotal = yoyAccountabilityStats.getTotal(); - // 总问责数 - int accountabilityTotal = currentAccountabilityStats.getTotal(); - // 个人问责数 - int personalAccountability = currentAccountabilityStats.getPersonal(); - // 单位问责数 - int unitAccountability = currentAccountabilityStats.getUnit(); - // 第一段 - int current = ztNegativeList.size(); - int mom = hbNegativList.size(); - int yoy = tbNegativList.size(); - 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()); - // 办结查实率 - // 1) 本期/环比/同比 查实率(都是 %,BigDecimal) - BigDecimal curVerifiedRate = calcVerifiedRate(ztNegativeList); - BigDecimal momVerifiedRate = calcVerifiedRate(hbNegativList); - BigDecimal yoyVerifiedRate = calcVerifiedRate(tbNegativList); - overviewSection.setVerifiedRate(curVerifiedRate); - // 3) 查实率环比(注意:率对率) - overviewSection.setVerifiedMomRate(ReportTrendUtil.calcRate(curVerifiedRate, momVerifiedRate)); - overviewSection.setVerifiedMomTrend(ReportTrendUtil.calcTrend(curVerifiedRate, momVerifiedRate)); - // 4) 查实率同比(注意:率对率) - overviewSection.setVerifiedYoyRate(ReportTrendUtil.calcRate(curVerifiedRate, yoyVerifiedRate)); - overviewSection.setVerifiedYoyTrend(ReportTrendUtil.calcTrend(curVerifiedRate, yoyVerifiedRate)); - // 5) 问责数据 - overviewSection.setAccountabilityTotal(accountabilityTotal); - overviewSection.setPersonalAccountability(personalAccountability); - overviewSection.setUnitAccountability(unitAccountability); - overviewSection.setAccountabilityMomRate(ReportTrendUtil.calcRate(accountabilityTotal, hbAccountabilityTotal)); - overviewSection.setAccountabilityMomTrend(ReportTrendUtil.calcTrend(accountabilityTotal, hbAccountabilityTotal)); - overviewSection.setAccountabilityYoyRate(ReportTrendUtil.calcRate(accountabilityTotal, tbAccountabilityTotal)); - overviewSection.setAccountabilityYoyTrend(ReportTrendUtil.calcTrend(accountabilityTotal, tbAccountabilityTotal)); - // 集中问题 - Map.Entry problemEntry = ReportTrendUtil.topBy(NegativeQueryVo::getProblemSources, bjssNegativeList, bjjbssNegativeList); - String problemSource = problemEntry != null ? problemEntry.getKey() : null; - Long problemSourceCount = problemEntry != null ? problemEntry.getValue() : 0; - overviewSection.setTopProblemProject(problemSource); - // 重点关注单位 - Map.Entry departEntry = ReportTrendUtil.topBy(NegativeQueryVo::getInvolveDepartName, bjssNegativeList, bjjbssNegativeList); - String departName = departEntry != null ? departEntry.getKey() : null; - Long departNameCount = departEntry != null ? departEntry.getValue() : 0; - overviewSection.setTopProblemUnit(departName); - return overviewSection; - } - - - // 查实率 - private BigDecimal calcVerifiedRate(List list) { - // 办结 - List closed = list.stream().filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())).toList(); - - 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); - } - - - private String parentLabel2Level(String childId, Map idMap) { - if (StrUtil.isBlank(childId)) { - return "未归类"; - } - DictProblemSourceTree child = idMap.get(childId); - if (child == null) { - return "未归类"; - } - DictProblemSourceTree parent = idMap.get(child.getParentId()); - // 若 child 没父,说明 child 自己就是一级(兜底) - return parent != null ? StrUtil.blankToDefault(parent.getLabel(), "未归类") - : StrUtil.blankToDefault(child.getLabel(), "未归类"); - } - - - private AccountabilityStats buildAccountabilityStats(List negativeIds) { - AccountabilityStats stats = new AccountabilityStats(); - if (CollUtil.isEmpty(negativeIds)) { - return stats; - } - NegativeBlameQueryParam queryParam = new NegativeBlameQueryParam(); - queryParam.setNegativeIds(negativeIds); - List negativeBlames = negativeBlameResourceService.query(queryParam); - // 个人问责 - List personalBlames = negativeBlames.stream() - .filter(one -> "personal".equals(one.getType())) - .filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) - .filter(one -> !"不予追责".equals(one.getHandleResultName())) - .toList(); - // 个人问责中的领导问责 - Set seenLead = new HashSet<>(); - List leadBlames = personalBlames.stream() - .filter(one -> StrUtil.isNotBlank(one.getLeadHandleResultName())) - .filter(one -> !"不予追责".equals(one.getLeadHandleResultName())) - .filter(one -> seenLead.add(one.getNegativeId() + "_" + one.getLeadHandleResultName() + "_" + one.getLeadName())) - .toList(); - // 单位问责 - List unitBlames = negativeBlames.stream() - .filter(one -> "department".equals(one.getType())) - .filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) - .filter(one -> !"不予追责".equals(one.getHandleResultName())) - .toList(); - int personalCount = personalBlames.size() + leadBlames.size(); - int unitCount = unitBlames.size(); - stats.setPersonal(personalCount); - stats.setUnit(unitCount); - stats.setTotal(personalCount + unitCount); - - stats.setPersonalBlames(personalBlames); - stats.setLeadBlames(leadBlames); - stats.setUnitBlames(unitBlames); - return stats; - } - - - @Data - private static class AccountabilityStats { - - /** - * 问责总数 = 个人问责 + 领导问责 + 单位问责 - */ - private int total; - - /** - * 个人问责数 = 个人问责 + 领导问责 - */ - private int personal; - - /** - * 单位问责数 - */ - private int unit; - - - /** - * 个人问责 - */ - private List personalBlames = new ArrayList<>(); - - /** - * 领导问责 - */ - private List leadBlames = new ArrayList<>(); - - /** - * 单位问责 - */ - private List unitBlames = new ArrayList<>(); - } - - - private String leafProblemLabel(String problemSourceCode, Map idMap) { - if (StrUtil.isBlank(problemSourceCode)) { - return "未归类"; - } - DictProblemSourceTree node = idMap.get(problemSourceCode); - if (node == null || StrUtil.isBlank(node.getLabel())) { - return "未归类"; - } - return node.getLabel(); - } - - private String safePercentString(int numerator, int denominator) { - return ReportTrendUtil.percent(numerator, denominator).toPlainString(); - } - - private String toChineseOrderNo(int index) { - String[] arr = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}; - if (index >= 1 && index <= arr.length) { - return arr[index - 1]; - } - return String.valueOf(index); - } - - private List buildTopPersons(List lineList, int totalIssued) { - Map personAggMap = new LinkedHashMap<>(); - - for (NegativeQueryVo vo : lineList) { - String personName = readStringByGetter(vo, - "getInvolvePersonName", - "getPersonName", - "getPoliceName", - "getHandlePersonName", - "getName"); - - if (StrUtil.isBlank(personName)) { - continue; - } - - String unitName = firstNotBlank( - readStringByGetter(vo, "getInvolveDepartName"), - readStringByGetter(vo, "getUnitName"), - readStringByGetter(vo, "getDepartName"), - "未知单位" - ); - - String identityName = firstNotBlank( - readStringByGetter(vo, "getIdentityName"), - readStringByGetter(vo, "getInvolveIdentityName"), - readStringByGetter(vo, "getPoliceTypeName"), - readStringByGetter(vo, "getUserTypeName"), - "未知身份" - ); - - String key = personName + "||" + unitName + "||" + identityName; - PersonAgg agg = personAggMap.computeIfAbsent(key, k -> { - PersonAgg x = new PersonAgg(); - x.setPersonName(personName); - x.setUnitName(unitName); - x.setIdentityName(identityName); - x.setCount(0); - return x; - }); - agg.setCount(agg.getCount() + 1); - } - - return personAggMap.values().stream() - .sorted(Comparator.comparing(PersonAgg::getCount).reversed()) - .limit(3) - .map(one -> buildPersonRankItem( - one.getPersonName(), - one.getUnitName(), - one.getIdentityName(), - one.getCount(), - safePercentString(one.getCount(), totalIssued) - )) - .toList(); - } - - private String readStringByGetter(Object target, String... getterNames) { - if (target == null || getterNames == null) { - return null; - } - for (String getterName : getterNames) { - try { - java.lang.reflect.Method method = target.getClass().getMethod(getterName); - Object value = method.invoke(target); - if (value instanceof String str && StrUtil.isNotBlank(str)) { - return str; - } - } catch (Exception ignored) { - } - } - return null; - } - - private String firstNotBlank(String... values) { - if (values == null) { - return null; - } - for (String value : values) { - if (StrUtil.isNotBlank(value)) { - return value; - } - } - return null; - } - - @Data - private static class PersonAgg { - private String personName; - private String unitName; - private String identityName; - private int count; - } - -} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportOverviewSectionService.java b/src/main/java/com/biutag/supervision/service/report/ReportOverviewSectionService.java new file mode 100644 index 0000000..3be54e1 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/ReportOverviewSectionService.java @@ -0,0 +1,17 @@ +package com.biutag.supervision.service.report; + +import com.biutag.supervision.pojo.dto.report.OverviewSection; +import com.biutag.supervision.pojo.dto.report.overview.ReportOverviewSectionRequestDTO; +import io.swagger.v3.oas.annotations.media.Schema; + +public interface ReportOverviewSectionService { + + /** + * 构建总体概览数据 + * + * @param requestDTO 请求参数 + * @return 构建结果 + */ + OverviewSection buildOverviewSection(ReportOverviewSectionRequestDTO requestDTO); + +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/ReportUnitInvestigationSectionService.java b/src/main/java/com/biutag/supervision/service/report/ReportUnitInvestigationSectionService.java new file mode 100644 index 0000000..765baac --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/ReportUnitInvestigationSectionService.java @@ -0,0 +1,16 @@ +package com.biutag.supervision.service.report; + +import com.biutag.supervision.pojo.dto.report.unitInvestigation.ReportUnitInvestigationSectionRequestDTO; +import com.biutag.supervision.pojo.dto.report.unitInvestigation.UnitInvestigationOverviewSection; +import io.swagger.v3.oas.annotations.media.Schema; + +public interface ReportUnitInvestigationSectionService { + + /** + * 构建单位查处情况总览 + * + * @param requestDTO 请求参数 + * @return 构建结果 + */ + UnitInvestigationOverviewSection buildUnitInvestigationOverviewSection(ReportUnitInvestigationSectionRequestDTO requestDTO); +} \ 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 new file mode 100644 index 0000000..2f012eb --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java @@ -0,0 +1,175 @@ +package com.biutag.supervision.service.report.impl; + +import com.biutag.supervision.pojo.dto.report.accountability.*; +import com.biutag.supervision.pojo.entity.NegativeBlame; +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import com.biutag.supervision.pojo.vo.NegativeQueryVo; +import com.biutag.supervision.service.NegativeQueryService; +import com.biutag.supervision.service.report.ReportAccountabilitySectionService; +import com.biutag.supervision.service.report.ReportAccountabilityStatsService; +import com.biutag.supervision.util.ChartRenderUtil; +import com.deepoove.poi.data.PictureRenderData; +import com.deepoove.poi.data.PictureType; +import com.deepoove.poi.data.Pictures; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class ReportAccountabilitySectionServiceImpl implements ReportAccountabilitySectionService { + + @Resource + private NegativeQueryService negativeQueryService; + + @Resource + private ReportAccountabilityStatsService reportAccountabilityStatsService; + + @Override + public AccountabilityOverviewSection buildAccountabilityOverviewSection(ReportAccountabilitySectionRequestDTO requestDTO) { + 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(); + 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); + + AccountabilityOverviewSection section = new AccountabilityOverviewSection(); + section.setPeriodStart(periodStart); + section.setPeriodEnd(periodEnd); + section.setProblemTypeCount(currentList.size()); + section.setPersonalAccountabilityCount(statsResponseDTO.getPersonal()); + section.setDepartmentAccountabilityCount(statsResponseDTO.getUnit()); + + return section; + } + + @Override + public AccountabilityUnitSection buildAccountabilityUnitDetailSection(ReportAccountabilitySectionRequestDTO requestDTO) { + + if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { + return new AccountabilityUnitSection(); + } + + NegativeQueryParam request = requestDTO.getNegativeQueryParam(); + + NegativeQueryParam currentQueryParam = request.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)); + + AccountabilityUnitSection section = new AccountabilityUnitSection(); + section.setTotalCount(statsResponseDTO.getUnit()); + + List typeItems = unitMap.entrySet().stream() + .map(entry -> { + AccountabilityTypeItem item = new AccountabilityTypeItem(); + item.setTypeName(entry.getKey()); + item.setCount(entry.getValue().size()); + 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()); + } + + byte[] pieBytes = ChartRenderUtil.piePng("单位问责情况", pieData, 5, 900, 520); + PictureRenderData picture = Pictures.ofBytes(pieBytes, PictureType.PNG) + .size(500, 300) + .create(); + section.setDepartPieChart(picture); + return section; + } + + @Override + public AccountabilityPersonalSection buildAccountabilityPersonalOverviewSection(ReportAccountabilitySectionRequestDTO requestDTO) { + if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { + return new AccountabilityPersonalSection(); + } + + NegativeQueryParam request = requestDTO.getNegativeQueryParam(); + + NegativeQueryParam currentQueryParam = request.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; + }) + ); + + AccountabilityPersonalSection section = new AccountabilityPersonalSection(); + section.setTotalCount(statsResponseDTO.getPersonal()); + + List typeItems = mergedMap.entrySet().stream() + .map(entry -> { + AccountabilityTypeItem item = new AccountabilityTypeItem(); + item.setTypeName(entry.getKey()); + item.setCount(entry.getValue().size()); + 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()); + } + + byte[] pieBytes = ChartRenderUtil.piePng("个人问责情况", pieData, 5, 900, 520); + PictureRenderData picture = Pictures.ofBytes(pieBytes, PictureType.PNG) + .size(500, 300) + .create(); + section.setPersonPieChart(picture); + 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 new file mode 100644 index 0000000..3ed55d6 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java @@ -0,0 +1,76 @@ +package com.biutag.supervision.service.report.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsRequestDTO; +import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO; +import com.biutag.supervision.pojo.entity.NegativeBlame; +import com.biutag.supervision.pojo.param.negativeBlame.NegativeBlameQueryParam; +import com.biutag.supervision.repository.negativeBlame.NegativeBlameResourceService; +import com.biutag.supervision.service.report.ReportAccountabilityStatsService; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Service +@Schema(description = "报表问责统计服务") +public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilityStatsService { + + @Resource + private NegativeBlameResourceService negativeBlameResourceService; + + @Override + public ReportAccountabilityStatsResponseDTO calculateAccountabilityStats(ReportAccountabilityStatsRequestDTO requestDTO) { + ReportAccountabilityStatsResponseDTO responseDTO = new ReportAccountabilityStatsResponseDTO(); + + if (requestDTO == null || CollUtil.isEmpty(requestDTO.getNegativeIds())) { + return responseDTO; + } + + NegativeBlameQueryParam queryParam = new NegativeBlameQueryParam(); + queryParam.setNegativeIds(requestDTO.getNegativeIds()); + + List negativeBlames = negativeBlameResourceService.query(queryParam); + + // 个人问责 + List personalBlames = negativeBlames.stream() + .filter(one -> "personal".equals(one.getType())) + .filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) + .filter(one -> !"不予追责".equals(one.getHandleResultName())) + .toList(); + + // 个人问责中的领导问责 + Set seenLead = new HashSet<>(); + List leadBlames = personalBlames.stream() + .filter(one -> StrUtil.isNotBlank(one.getLeadHandleResultName())) + .filter(one -> !"不予追责".equals(one.getLeadHandleResultName())) + .filter(one -> seenLead.add( + one.getNegativeId() + "_" + one.getLeadHandleResultName() + "_" + one.getLeadName() + )) + .toList(); + + // 单位问责 + List unitBlames = negativeBlames.stream() + .filter(one -> "department".equals(one.getType())) + .filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) + .filter(one -> !"不予追责".equals(one.getHandleResultName())) + .toList(); + + int personalCount = personalBlames.size() + leadBlames.size(); + int unitCount = unitBlames.size(); + + responseDTO.setPersonal(personalCount); + responseDTO.setUnit(unitCount); + responseDTO.setTotal(personalCount + unitCount); + + responseDTO.setPersonalBlames(personalBlames); + responseDTO.setLeadBlames(leadBlames); + responseDTO.setUnitBlames(unitBlames); + + return responseDTO; + } +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportBaseQueryServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportBaseQueryServiceImpl.java new file mode 100644 index 0000000..119b6bb --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportBaseQueryServiceImpl.java @@ -0,0 +1,53 @@ +package com.biutag.supervision.service.report.impl; + +import cn.hutool.core.collection.CollUtil; +import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryRequestDTO; +import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryResponseDTO; +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import com.biutag.supervision.pojo.vo.NegativeQueryVo; +import com.biutag.supervision.service.NegativeQueryService; +import com.biutag.supervision.service.report.ReportBaseQueryService; +import com.biutag.supervision.util.DateCompareRangeUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Schema(description = "报表基础查询服务") +public class ReportBaseQueryServiceImpl implements ReportBaseQueryService { + + @Resource + private NegativeQueryService negativeQueryService; + + @Override + public ReportBaseQueryResponseDTO queryBaseData(ReportBaseQueryRequestDTO requestDTO) { + ReportBaseQueryResponseDTO responseDTO = new ReportBaseQueryResponseDTO(); + + if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { + return responseDTO; + } + NegativeQueryParam request = requestDTO.getNegativeQueryParam(); + if (CollUtil.isEmpty(request.getCrtTime()) || request.getCrtTime().size() < 2) { + return responseDTO; + } + DateCompareRangeUtil.CompareDateRange compareDateRange = DateCompareRangeUtil.buildCompareDateRange(request.getCrtTime().get(0), request.getCrtTime().get(1)); + // 本期 + NegativeQueryParam currentQueryParam = request.newQueryParam(); + List currentList = negativeQueryService.page(currentQueryParam).getRecords(); + // 环比 + NegativeQueryParam momQueryParam = request.newQueryParam(); + momQueryParam.setCrtTime(compareDateRange.mom()); + List momList = negativeQueryService.page(momQueryParam).getRecords(); + // 同比 + NegativeQueryParam yoyQueryParam = request.newQueryParam(); + yoyQueryParam.setCrtTime(compareDateRange.yoy()); + List yoyList = negativeQueryService.page(yoyQueryParam).getRecords(); + responseDTO.setCurrentList(currentList != null ? currentList : new ArrayList<>()); + responseDTO.setMomList(momList != null ? momList : new ArrayList<>()); + responseDTO.setYoyList(yoyList != null ? yoyList : new ArrayList<>()); + return responseDTO; + } +} \ 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 new file mode 100644 index 0000000..a6c8b69 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java @@ -0,0 +1,425 @@ +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.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; +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.businessLine.*; +import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcRequestDTO; +import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO; +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.NegativeQueryService; +import com.biutag.supervision.service.SupDictProblemSourceService; +import com.biutag.supervision.service.report.ReportAccountabilityStatsService; +import com.biutag.supervision.service.report.ReportBaseQueryService; +import com.biutag.supervision.service.report.ReportBusinessLineSectionService; +import com.biutag.supervision.service.report.ReportClosedStatsService; +import com.biutag.supervision.util.ChartRenderUtil; +import com.biutag.supervision.util.ReportTrendUtil; +import com.deepoove.poi.data.PictureRenderData; +import com.deepoove.poi.data.PictureType; +import com.deepoove.poi.data.Pictures; +import jakarta.annotation.Resource; +import lombok.Data; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineSectionService { + + @Resource + private NegativeQueryService negativeQueryService; + + @Resource + private SupDictProblemSourceService supDictProblemSourceService; + + @Resource + private ReportBaseQueryService reportBaseQueryService; + + @Resource + private ReportClosedStatsService reportClosedStatsService; + + @Resource + private ReportAccountabilityStatsService reportAccountabilityStatsService; + + @Override + public BusinessLineOverviewSection buildBusinessLineOverviewSection(ReportBusinessLineSectionRequestDTO requestDTO) { + + if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { + return new BusinessLineOverviewSection(); + } + + NegativeQueryParam request = requestDTO.getNegativeQueryParam(); + String periodStart = requestDTO.getPeriodStart(); + String periodEnd = requestDTO.getPeriodEnd(); + + NegativeQueryParam currentQueryParam = request.newQueryParam(); + List currentList = negativeQueryService.page(currentQueryParam).getRecords(); + + Map idMap = supDictProblemSourceService.buildIdMap(); + + Map aggByParentLabel = currentList.stream() + .map(NegativeQueryVo::getProblemSourcesCode) + .map(childId -> parentLabel2Level(childId, idMap)) + .collect(Collectors.groupingBy(s -> s, Collectors.counting())); + + List> sorted = aggByParentLabel.entrySet().stream() + .sorted((a, b) -> Long.compare(b.getValue(), a.getValue())) + .toList(); + + StringBuilder businessLineOverviewText = new StringBuilder(); + for (int i = 0; i < sorted.size(); i++) { + String label = sorted.get(i).getKey(); + int cnt = Math.toIntExact(sorted.get(i).getValue()); + businessLineOverviewText.append(i + 1) + .append("、") + .append(label) + .append(",") + .append(cnt) + .append("条,占比") + .append(ReportTrendUtil.percent(cnt, currentList.size())) + .append("%;"); + } + + BusinessLineOverviewSection section = new BusinessLineOverviewSection(); + section.setPeriodStart(periodStart); + section.setPeriodEnd(periodEnd); + section.setBusinessLineTotal(currentList.size()); + section.setBusinessLineOverviewText(businessLineOverviewText.toString()); + + Map pieData = new LinkedHashMap<>(); + for (Map.Entry entry : sorted) { + pieData.put(entry.getKey(), entry.getValue()); + } + + byte[] pieBytes = ChartRenderUtil.piePng("占比统计", pieData, 5, 900, 520); + PictureRenderData picture = Pictures.ofBytes(pieBytes, PictureType.PNG) + .size(500, 300) + .create(); + section.setProblemPieChart(picture); + return section; + } + + @Override + public List buildBusinessLineDetailSections(ReportBusinessLineSectionRequestDTO requestDTO) { + 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(); + + 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(); + if (CollUtil.isEmpty(lineList)) { + continue; + } + BusinessLineDetailSection section = new BusinessLineDetailSection(); + section.setOrderNo(toChineseOrderNo(index++)); + section.setBusinessFatherLineName(fatherBusinessLineName); + section.setBusinessLineName(fatherBusinessLineName); + + 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); + 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(); + + ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); + statsRequestDTO.setNegativeIds(verifiedNegativeIds); + ReportAccountabilityStatsResponseDTO accountabilityStats = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); + section.setAccountabilityTotal(accountabilityStats.getTotal()); + section.setAccountabilityRate(ReportTrendUtil.calcRate(accountabilityStats.getTotal(), verifiedTotal)); + section.setPersonalAccountabilityCount(accountabilityStats.getPersonal()); + section.setDepartmentAccountabilityCount(accountabilityStats.getUnit()); + + 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); + } + + return result; + } + + /** + * 根据问题名称、数量、占比构建排名项 + */ + private BusinessLineRankItem buildRankItem(String name, Integer count, String rate) { + BusinessLineRankItem item = new BusinessLineRankItem(); + item.setName(name); + item.setCount(count); + item.setRate(new BigDecimal(rate)); + return item; + } + + /** + * 根据人员、单位、身份、数量、占比构建人员排名项 + */ + private BusinessLinePersonRankItem buildPersonRankItem(String personName, String unitName, String identityName, Integer count, String rate) { + BusinessLinePersonRankItem item = new BusinessLinePersonRankItem(); + item.setPersonName(personName); + item.setUnitName(unitName); + item.setIdentityName(identityName); + item.setCount(count); + item.setRate(new BigDecimal(rate)); + return item; + } + + /** + * 根据子级问题来源ID,解析父级业务条线名称 + */ + private String parentLabel2Level(String childId, Map idMap) { + if (StrUtil.isBlank(childId)) { + return "未归类"; + } + DictProblemSourceTree child = idMap.get(childId); + if (child == null) { + return "未归类"; + } + DictProblemSourceTree parent = idMap.get(child.getParentId()); + return parent != null ? StrUtil.blankToDefault(parent.getLabel(), "未归类") + : StrUtil.blankToDefault(child.getLabel(), "未归类"); + } + + /** + * 根据问题来源ID获取当前节点名称 + */ + private String leafProblemLabel(String problemSourceCode, Map idMap) { + if (StrUtil.isBlank(problemSourceCode)) { + return "未归类"; + } + DictProblemSourceTree node = idMap.get(problemSourceCode); + if (node == null || StrUtil.isBlank(node.getLabel())) { + return "未归类"; + } + return node.getLabel(); + } + + /** + * 安全计算占比字符串 + */ + private String safePercentString(int numerator, int denominator) { + return ReportTrendUtil.percent(numerator, denominator).toPlainString(); + } + + /** + * 阿拉伯数字序号转中文序号 + */ + private String toChineseOrderNo(int index) { + String[] arr = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十"}; + if (index >= 1 && index <= arr.length) { + return arr[index - 1]; + } + return String.valueOf(index); + } + + /** + * 构建重点人员TOP3 + */ + private List buildTopPersons(List lineList, int totalIssued) { + Map personAggMap = new LinkedHashMap<>(); + + for (NegativeQueryVo vo : lineList) { + String personName = readStringByGetter(vo, + "getInvolvePersonName", + "getPersonName", + "getPoliceName", + "getHandlePersonName", + "getName"); + + if (StrUtil.isBlank(personName)) { + continue; + } + + String unitName = firstNotBlank( + readStringByGetter(vo, "getInvolveDepartName"), + readStringByGetter(vo, "getUnitName"), + readStringByGetter(vo, "getDepartName"), + "未知单位" + ); + + String identityName = firstNotBlank( + readStringByGetter(vo, "getIdentityName"), + readStringByGetter(vo, "getInvolveIdentityName"), + readStringByGetter(vo, "getPoliceTypeName"), + readStringByGetter(vo, "getUserTypeName"), + "未知身份" + ); + + String key = personName + "||" + unitName + "||" + identityName; + PersonAgg agg = personAggMap.computeIfAbsent(key, k -> { + PersonAgg x = new PersonAgg(); + x.setPersonName(personName); + x.setUnitName(unitName); + x.setIdentityName(identityName); + x.setCount(0); + return x; + }); + agg.setCount(agg.getCount() + 1); + } + + return personAggMap.values().stream() + .sorted(Comparator.comparing(PersonAgg::getCount).reversed()) + .limit(3) + .map(one -> buildPersonRankItem( + one.getPersonName(), + one.getUnitName(), + one.getIdentityName(), + one.getCount(), + safePercentString(one.getCount(), totalIssued) + )) + .toList(); + } + + /** + * 通过反射按顺序读取字符串属性 + */ + private String readStringByGetter(Object target, String... getterNames) { + if (target == null || getterNames == null) { + return null; + } + for (String getterName : getterNames) { + try { + java.lang.reflect.Method method = target.getClass().getMethod(getterName); + Object value = method.invoke(target); + if (value instanceof String str && StrUtil.isNotBlank(str)) { + return str; + } + } catch (Exception ignored) { + } + } + return null; + } + + /** + * 返回第一个非空白字符串 + */ + private String firstNotBlank(String... values) { + if (values == null) { + return null; + } + for (String value : values) { + if (StrUtil.isNotBlank(value)) { + return value; + } + } + return null; + } + + /** + * 重点人员聚合对象 + */ + @Data + private static class PersonAgg { + private String personName; + private String unitName; + private String identityName; + private int count; + } +} + 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 new file mode 100644 index 0000000..ffd78c3 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java @@ -0,0 +1,63 @@ +package com.biutag.supervision.service.report.impl; + +import com.biutag.supervision.constants.enums.CheckStatusEnum; +import com.biutag.supervision.constants.enums.ProcessingStatusEnum; +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; +import com.biutag.supervision.service.report.ReportClosedStatsService; +import com.biutag.supervision.util.ReportTrendUtil; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; + +@Service +public class ReportClosedStatsServiceImpl implements ReportClosedStatsService { + + @Override + public ClosedStatsCalcResponseDTO calculateClosedStats(ClosedStatsCalcRequestDTO requestDTO) { + + List list = + requestDTO == null || requestDTO.getNegativeQueryVoList() == null + ? Collections.emptyList() + : requestDTO.getNegativeQueryVoList(); + + List closedList = list.stream() + .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) + .toList(); + + List verifiedList = closedList.stream() + .filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) + .toList(); + + List basicallyVerifiedList = closedList.stream() + .filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) + .toList(); + + List unverifiedList = closedList.stream() + .filter(one -> CheckStatusEnum.FALSE_SET.contains(one.getCheckStatusCode())) + .toList(); + + BigDecimal verifiedRate = ReportTrendUtil.percent( + verifiedList.size() + basicallyVerifiedList.size(), + closedList.size() + ); + + ClosedStatsCalcResponseDTO responseDTO = new ClosedStatsCalcResponseDTO(); + + responseDTO.setClosedCount(closedList.size()); + responseDTO.setVerifiedCount(verifiedList.size()); + responseDTO.setBasicallyVerifiedCount(basicallyVerifiedList.size()); + responseDTO.setUnverifiedCount(unverifiedList.size()); + responseDTO.setVerifiedRate(verifiedRate); + + responseDTO.setClosedList(closedList); + responseDTO.setVerifiedList(verifiedList); + responseDTO.setBasicallyVerifiedList(basicallyVerifiedList); + responseDTO.setUnverifiedList(unverifiedList); + + return responseDTO; + } +} \ No newline at end of file diff --git a/src/main/java/com/biutag/supervision/service/report/impl/ReportDataServiceImpl.java b/src/main/java/com/biutag/supervision/service/report/impl/ReportDataServiceImpl.java new file mode 100644 index 0000000..091ef5f --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportDataServiceImpl.java @@ -0,0 +1,68 @@ +package com.biutag.supervision.service.report.impl; + +import com.biutag.supervision.pojo.dto.report.ReportViewModel; +import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilitySectionRequestDTO; +import com.biutag.supervision.pojo.dto.report.businessLine.ReportBusinessLineSectionRequestDTO; +import com.biutag.supervision.pojo.dto.report.overview.ReportOverviewSectionRequestDTO; +import com.biutag.supervision.pojo.dto.report.unitInvestigation.ReportUnitInvestigationSectionRequestDTO; +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import com.biutag.supervision.service.report.*; +import com.biutag.supervision.util.TimeUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class ReportDataServiceImpl implements ReportDataService { + + @Resource + private ReportOverviewSectionService reportOverviewSectionService; + @Resource + private ReportAccountabilitySectionService reportAccountabilitySectionService; + @Resource + private ReportBusinessLineSectionService reportBusinessLineSectionService; + @Resource + private ReportUnitInvestigationSectionService reportUnitInvestigationSectionService; + + // 仅负责报表各模块编排,不承载具体统计逻辑 + @Override + public ReportViewModel buildViewModel(NegativeQueryParam request) { + String periodStart = TimeUtil.formatDate(request.getCrtTime().get(0)); + String periodEnd = TimeUtil.formatDate(request.getCrtTime().get(1)); + ReportViewModel vm = new ReportViewModel(); + vm.setPeriodStart(periodStart); + vm.setPeriodEnd(periodEnd); + // 总体概览 + ReportOverviewSectionRequestDTO overviewRequestDTO = new ReportOverviewSectionRequestDTO(); + overviewRequestDTO.setNegativeQueryParam(request); + overviewRequestDTO.setPeriodStart(periodStart); + overviewRequestDTO.setPeriodEnd(periodEnd); + vm.setOverviewSection(reportOverviewSectionService.buildOverviewSection(overviewRequestDTO)); + // 业务条线 + ReportBusinessLineSectionRequestDTO businessLineRequestDTO = new ReportBusinessLineSectionRequestDTO(); + businessLineRequestDTO.setNegativeQueryParam(request); + businessLineRequestDTO.setPeriodStart(periodStart); + businessLineRequestDTO.setPeriodEnd(periodEnd); + // 条线总览 + vm.setBusinessLineOverviewSection(reportBusinessLineSectionService.buildBusinessLineOverviewSection(businessLineRequestDTO)); + // 条线明细 + vm.setBusinessLineDetailSections(reportBusinessLineSectionService.buildBusinessLineDetailSections(businessLineRequestDTO)); + // 单位查处情况总览 + ReportUnitInvestigationSectionRequestDTO unitRequestDTO = new ReportUnitInvestigationSectionRequestDTO(); + unitRequestDTO.setNegativeQueryParam(request); + unitRequestDTO.setPeriodStart(periodStart); + unitRequestDTO.setPeriodEnd(periodEnd); + vm.setUnitInvestigationOverviewSection(reportUnitInvestigationSectionService.buildUnitInvestigationOverviewSection(unitRequestDTO)); + // 问责情况 + ReportAccountabilitySectionRequestDTO accountabilityRequestDTO = new ReportAccountabilitySectionRequestDTO(); + accountabilityRequestDTO.setNegativeQueryParam(request); + accountabilityRequestDTO.setPeriodStart(periodStart); + accountabilityRequestDTO.setPeriodEnd(periodEnd); + vm.setAccountabilityOverviewSection(reportAccountabilitySectionService.buildAccountabilityOverviewSection(accountabilityRequestDTO)); + vm.setAccountabilityUnitDetailSection(reportAccountabilitySectionService.buildAccountabilityUnitDetailSection(accountabilityRequestDTO)); + vm.setAccountabilityPersonOverviewSection(reportAccountabilitySectionService.buildAccountabilityPersonalOverviewSection(accountabilityRequestDTO)); +// System.out.println(1/0); + return vm; + } +} \ 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 new file mode 100644 index 0000000..e6fe0f2 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java @@ -0,0 +1,268 @@ +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.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.ReportOverviewSectionService; +import com.biutag.supervision.util.ReportTrendUtil; +import jakarta.annotation.Resource; +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 + * @Description 报表总体概览构建服务实现类 + * @Author shihao + * @Date 2026/3/9 + */ +@Service +public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionService { + + /** + * 报表基础查询服务 + * 统一查询本期、环比、同比三类基础数据 + */ + @Resource + private ReportBaseQueryService reportBaseQueryService; + + /** + * 问责统计服务 + * 统一计算个人问责、单位问责、总问责等数据 + */ + @Resource + private ReportAccountabilityStatsService reportAccountabilityStatsService; + + /** + * 构建总体概览数据 + * + * @param requestDTO 总体概览构建请求DTO + * @return 总体概览构建结果DTO + */ + @Override + public OverviewSection buildOverviewSection(ReportOverviewSectionRequestDTO requestDTO) { + if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { + return new OverviewSection(); + } + + NegativeQueryParam request = requestDTO.getNegativeQueryParam(); + String periodStart = requestDTO.getPeriodStart(); + String periodEnd = requestDTO.getPeriodEnd(); + + // 查询本期、环比、同比基础数据 + ReportBaseQueryRequestDTO baseRequestDTO = new ReportBaseQueryRequestDTO(); + baseRequestDTO.setNegativeQueryParam(request); + ReportBaseQueryResponseDTO baseQueryResponseDTO = reportBaseQueryService.queryBaseData(baseRequestDTO); + + List ztNegativeList = baseQueryResponseDTO.getCurrentList(); + List hbNegativeList = baseQueryResponseDTO.getMomList(); + List tbNegativeList = baseQueryResponseDTO.getYoyList(); + + // 市局下发数据 + List sjxfNegativeList = ztNegativeList.stream() + .filter(one -> Objects.equals(0, one.getCrtDepartLevel())) + .toList(); + + // 分县市局下发数据 + List fxsjxfNegativeList = ztNegativeList.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(); + + // 本期办结中基本属实数据 + List bjjbssNegativeList = bjNegativeList.stream() + .filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) + .toList(); + + // 本期办结中不属实数据 + List bjbssNegativeList = bjNegativeList.stream() + .filter(one -> CheckStatusEnum.FALSE_SET.contains(one.getCheckStatusCode())) + .toList(); + + // 本期属实 + 基本属实问题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(); + + 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(); + + 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.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.setTopProblemProject(problemEntry != null ? problemEntry.getKey() : null); + + // 重点关注单位 + Map.Entry departEntry = + ReportTrendUtil.topBy(NegativeQueryVo::getInvolveDepartName, bjssNegativeList, bjjbssNegativeList); + overviewSection.setTopProblemUnit(departEntry != null ? departEntry.getKey() : null); + return overviewSection; + } + + /** + * 计算查实率 + * 查实率 = (属实数 + 基本属实数)/ 办结数 * 100 + * + * @param list 问题数据列表 + * @return 查实率 + */ + private BigDecimal calcVerifiedRate(List list) { + // 办结数据 + List closed = list.stream() + .filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) + .toList(); + + 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 new file mode 100644 index 0000000..e931af5 --- /dev/null +++ b/src/main/java/com/biutag/supervision/service/report/impl/ReportUnitInvestigationSectionServiceImpl.java @@ -0,0 +1,118 @@ +package com.biutag.supervision.service.report.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.biutag.supervision.constants.enums.CheckStatusEnum; +import com.biutag.supervision.pojo.dto.DepartAndSubDepartDto; +import com.biutag.supervision.pojo.dto.report.unitInvestigation.ReportUnitInvestigationSectionRequestDTO; +import com.biutag.supervision.pojo.dto.report.unitInvestigation.UnitInvestigationItem; +import com.biutag.supervision.pojo.dto.report.unitInvestigation.UnitInvestigationOverviewSection; +import com.biutag.supervision.pojo.param.NegativeQueryParam; +import com.biutag.supervision.pojo.param.SupDepartGroupParam; +import com.biutag.supervision.pojo.vo.NegativeQueryVo; +import com.biutag.supervision.repository.supdepart.SupDepartResourceService; +import com.biutag.supervision.service.NegativeQueryService; +import com.biutag.supervision.service.report.ReportUnitInvestigationSectionService; +import com.biutag.supervision.util.ChartRenderUtil; +import com.biutag.supervision.util.ReportTrendUtil; +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.*; + +/** + * @ClassName ReportUnitInvestigationSectionServiceImpl + * @Description 报表单位查处模块构建服务实现类 + * @Author shihao + * @Date 2026/3/9 + */ +@Service +@Slf4j +public class ReportUnitInvestigationSectionServiceImpl implements ReportUnitInvestigationSectionService { + + @Resource + private NegativeQueryService negativeQueryService; + + @Resource + private SupDepartResourceService supDepartResourceService; + + @Override + public UnitInvestigationOverviewSection buildUnitInvestigationOverviewSection(ReportUnitInvestigationSectionRequestDTO requestDTO) { + if (requestDTO == null || requestDTO.getNegativeQueryParam() == null) { + return new UnitInvestigationOverviewSection(); + } + + NegativeQueryParam request = requestDTO.getNegativeQueryParam(); + String periodStart = requestDTO.getPeriodStart(); + String periodEnd = requestDTO.getPeriodEnd(); + + // 本期问题数据 + NegativeQueryParam currentQueryParam = request.newQueryParam(); + List currentList = negativeQueryService.page(currentQueryParam).getRecords(); + + // 查询父子部门关系 + SupDepartGroupParam supDepartGroupParam = new SupDepartGroupParam(); + supDepartGroupParam.setParentLevel(2); + supDepartGroupParam.setChildLevel(3); + Map departAndSubDepart = + supDepartResourceService.getDepartAndSubDepart(supDepartGroupParam); + + List topUnits = new ArrayList<>(); + for (DepartAndSubDepartDto value : departAndSubDepart.values()) { + Set allDepartIds = value.getAllDepartIds(); + + List voList = currentList.stream() + .filter(one -> allDepartIds.contains(one.getInvolveDepartId())) + .toList(); + + log.info(value.getParentName() + "的数量=====================" + voList.size()); + + if (CollectionUtil.isNotEmpty(voList)) { + UnitInvestigationItem item = new UnitInvestigationItem(); + item.setUnitName(value.getParentName()); + item.setIssuedProblemCount(voList.size()); + + List csList = voList.stream() + .filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode()) + || CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) + .toList(); + + item.setVerifiedProblemCount(csList.size()); + item.setVerifiedRate(ReportTrendUtil.percent(csList.size(), voList.size())); + topUnits.add(item); + } + } + + topUnits.sort(Comparator.comparing(UnitInvestigationItem::getVerifiedProblemCount).reversed()); + topUnits = topUnits.stream().limit(3).toList(); + + UnitInvestigationOverviewSection section = new UnitInvestigationOverviewSection(); + section.setPeriodStart(periodStart); + section.setPeriodEnd(periodEnd); + section.setTopUnits(topUnits); + + // 柱状图 + Map> seriesData = new LinkedHashMap<>(); + Map issuedMap = new LinkedHashMap<>(); + Map verifiedMap = new LinkedHashMap<>(); + + for (UnitInvestigationItem item : topUnits) { + issuedMap.put(item.getUnitName(), item.getIssuedProblemCount()); + verifiedMap.put(item.getUnitName(), item.getVerifiedProblemCount()); + } + + seriesData.put("下发问题数", issuedMap); + seriesData.put("查实问题数", verifiedMap); + + byte[] barBytes = ChartRenderUtil.groupedBarPng("单位查处情况", seriesData, "单位", "数量", 1000, 520); + PictureRenderData picture = Pictures.ofBytes(barBytes, PictureType.PNG) + .size(500, 300) + .create(); + section.setUnitBarChart(picture); + + return section; + } +} \ No newline at end of file diff --git a/src/main/resources/static/templates/督审一体化平台研判分析报告.docx b/src/main/resources/static/templates/督审一体化平台研判分析报告.docx index 0badf438dcf9eb93d9fa632241d753b9a96412cc..3fe6b2e432e69ba9b2d1f318b5de8a44ddf3e019 100644 GIT binary patch delta 7764 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 delta 72744 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 A_y7O^