29 changed files with 1640 additions and 878 deletions
@ -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; |
||||||
|
} |
||||||
@ -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<String> negativeIds = new ArrayList<>(); |
||||||
|
|
||||||
|
} |
||||||
@ -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<NegativeBlame> personalBlames = new ArrayList<>(); |
||||||
|
|
||||||
|
@Schema(description = "领导问责列表") |
||||||
|
private List<NegativeBlame> leadBlames = new ArrayList<>(); |
||||||
|
|
||||||
|
@Schema(description = "单位问责列表") |
||||||
|
private List<NegativeBlame> unitBlames = new ArrayList<>(); |
||||||
|
|
||||||
|
} |
||||||
@ -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; |
||||||
|
|
||||||
|
} |
||||||
@ -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<NegativeQueryVo> currentList = new ArrayList<>(); |
||||||
|
|
||||||
|
@Schema(description = "环比数据列表") |
||||||
|
private List<NegativeQueryVo> momList = new ArrayList<>(); |
||||||
|
|
||||||
|
@Schema(description = "同比数据列表") |
||||||
|
private List<NegativeQueryVo> yoyList = new ArrayList<>(); |
||||||
|
|
||||||
|
} |
||||||
@ -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; |
||||||
|
} |
||||||
@ -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<NegativeQueryVo> negativeQueryVoList = new ArrayList<>(); |
||||||
|
|
||||||
|
} |
||||||
@ -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<NegativeQueryVo> closedList = new ArrayList<>(); |
||||||
|
|
||||||
|
@Schema(description = "属实问题列表") |
||||||
|
private List<NegativeQueryVo> verifiedList = new ArrayList<>(); |
||||||
|
|
||||||
|
@Schema(description = "基本属实问题列表") |
||||||
|
private List<NegativeQueryVo> basicallyVerifiedList = new ArrayList<>(); |
||||||
|
|
||||||
|
@Schema(description = "不属实问题列表") |
||||||
|
private List<NegativeQueryVo> unverifiedList = new ArrayList<>(); |
||||||
|
|
||||||
|
} |
||||||
@ -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; |
||||||
|
} |
||||||
@ -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; |
||||||
|
} |
||||||
@ -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); |
||||||
|
} |
||||||
@ -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); |
||||||
|
|
||||||
|
} |
||||||
@ -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); |
||||||
|
|
||||||
|
} |
||||||
@ -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<BusinessLineDetailSection> buildBusinessLineDetailSections(ReportBusinessLineSectionRequestDTO requestDTO); |
||||||
|
} |
||||||
@ -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); |
||||||
|
|
||||||
|
} |
||||||
@ -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<NegativeQueryVo> ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); |
|
||||||
List<String> ztNegativeIds = ztNegativeList.stream().map(NegativeQueryVo::getId).toList(); |
|
||||||
AccountabilityStats accountabilityStats = buildAccountabilityStats(ztNegativeIds); |
|
||||||
// 个人问责
|
|
||||||
Map<String, List<NegativeBlame>> leadMap = accountabilityStats.getLeadBlames().stream().collect(Collectors.groupingBy(NegativeBlame::getLeadHandleResultName)); |
|
||||||
Map<String, List<NegativeBlame>> personMap = accountabilityStats.getPersonalBlames().stream().collect(Collectors.groupingBy(NegativeBlame::getHandleResultName)); |
|
||||||
Map<String, List<NegativeBlame>> mergedMap = new HashMap<>(personMap); |
|
||||||
leadMap.forEach((key, value) -> |
|
||||||
mergedMap.merge(key, value, (list1, list2) -> { |
|
||||||
List<NegativeBlame> list = new ArrayList<>(list1); |
|
||||||
list.addAll(list2); |
|
||||||
return list; |
|
||||||
}) |
|
||||||
); |
|
||||||
AccountabilityPersonalSection accountabilityPersonalSection = new AccountabilityPersonalSection(); |
|
||||||
accountabilityPersonalSection.setTotalCount(accountabilityStats.getPersonal()); |
|
||||||
// 构造 typeItems
|
|
||||||
List<AccountabilityTypeItem> 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<String, Number> 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<NegativeQueryVo> ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); |
|
||||||
List<String> ztNegativeIds = ztNegativeList.stream().map(NegativeQueryVo::getId).toList(); |
|
||||||
AccountabilityStats accountabilityStats = buildAccountabilityStats(ztNegativeIds); |
|
||||||
// 单位问责
|
|
||||||
Map<String, List<NegativeBlame>> unitMap = accountabilityStats.getUnitBlames().stream().collect(Collectors.groupingBy(NegativeBlame::getHandleResultName)); |
|
||||||
|
|
||||||
AccountabilityDepartmentSection accountabilityDepartmentSection = new AccountabilityDepartmentSection(); |
|
||||||
accountabilityDepartmentSection.setTotalCount(accountabilityStats.getUnit()); |
|
||||||
// 构造 typeItems
|
|
||||||
List<AccountabilityTypeItem> 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<String, Number> 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<NegativeQueryVo> ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); |
|
||||||
List<String> 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<NegativeQueryVo> ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); |
|
||||||
SupDepartGroupParam supDepartGroupParam = new SupDepartGroupParam(); |
|
||||||
supDepartGroupParam.setParentLevel(2); |
|
||||||
supDepartGroupParam.setChildLevel(3); |
|
||||||
Map<String, DepartAndSubDepartDto> departAndSubDepart = supDepartResourceService.getDepartAndSubDepart(supDepartGroupParam); |
|
||||||
List<UnitInvestigationItem> topUnits = new ArrayList<>(); |
|
||||||
for (DepartAndSubDepartDto value : departAndSubDepart.values()) { |
|
||||||
Set<String> allDepartIds = value.getAllDepartIds(); |
|
||||||
List<NegativeQueryVo> 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<NegativeQueryVo> 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<String, Map<String, Number>> seriesData = new LinkedHashMap<>(); |
|
||||||
Map<String, Number> issuedMap = new LinkedHashMap<>(); |
|
||||||
Map<String, Number> 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<BusinessLineDetailSection> 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<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); |
|
||||||
|
|
||||||
// 环比数据
|
|
||||||
NegativeQueryParam momQueryParam = request.newQueryParam(); |
|
||||||
momQueryParam.setCrtTime(compareDateRange.mom()); |
|
||||||
List<NegativeQueryVo> momList = negativeQueryService.page(momQueryParam).getRecords(); |
|
||||||
|
|
||||||
// 同比数据
|
|
||||||
NegativeQueryParam yoyQueryParam = request.newQueryParam(); |
|
||||||
yoyQueryParam.setCrtTime(compareDateRange.yoy()); |
|
||||||
List<NegativeQueryVo> yoyList = negativeQueryService.page(yoyQueryParam).getRecords(); |
|
||||||
|
|
||||||
Map<String, DictProblemSourceTree> idMap = supDictProblemSourceService.buildIdMap(); |
|
||||||
|
|
||||||
// 按“父级业务条线”分组
|
|
||||||
Map<String, List<NegativeQueryVo>> currentGroup = currentList.stream() |
|
||||||
.collect(Collectors.groupingBy( |
|
||||||
vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), |
|
||||||
LinkedHashMap::new, |
|
||||||
Collectors.toList() |
|
||||||
)); |
|
||||||
|
|
||||||
Map<String, List<NegativeQueryVo>> momGroup = momList.stream() |
|
||||||
.collect(Collectors.groupingBy( |
|
||||||
vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), |
|
||||||
LinkedHashMap::new, |
|
||||||
Collectors.toList() |
|
||||||
)); |
|
||||||
|
|
||||||
Map<String, List<NegativeQueryVo>> yoyGroup = yoyList.stream() |
|
||||||
.collect(Collectors.groupingBy( |
|
||||||
vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), |
|
||||||
LinkedHashMap::new, |
|
||||||
Collectors.toList() |
|
||||||
)); |
|
||||||
|
|
||||||
// 按本期数量倒序
|
|
||||||
List<Map.Entry<String, List<NegativeQueryVo>>> sortedEntries = currentGroup.entrySet().stream() |
|
||||||
.sorted((a, b) -> Integer.compare(b.getValue().size(), a.getValue().size())) |
|
||||||
.toList(); |
|
||||||
|
|
||||||
List<BusinessLineDetailSection> result = new ArrayList<>(); |
|
||||||
int index = 1; |
|
||||||
|
|
||||||
for (Map.Entry<String, List<NegativeQueryVo>> entry : sortedEntries) { |
|
||||||
String fatherBusinessLineName = entry.getKey(); |
|
||||||
List<NegativeQueryVo> 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<NegativeQueryVo> 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<String> 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<BusinessLineRankItem> 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<BusinessLineRankItem> 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<BusinessLinePersonRankItem> 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<NegativeQueryVo> ztNegativeList = negativeQueryService.page(ztNegativeQueryParam).getRecords(); |
|
||||||
Map<String, DictProblemSourceTree> idMap = supDictProblemSourceService.buildIdMap(); |
|
||||||
// 计数
|
|
||||||
Map<String, Long> aggByParentLabel = ztNegativeList.stream() |
|
||||||
.map(NegativeQueryVo::getProblemSourcesCode) // 收集二级id
|
|
||||||
.map(childId -> parentLabel2Level(childId, idMap)) // 解析未一级label
|
|
||||||
.collect(Collectors.groupingBy(s -> s, Collectors.counting())); |
|
||||||
// 排序
|
|
||||||
List<Map.Entry<String, Long>> 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<String, Number> pieData = new LinkedHashMap<>(); |
|
||||||
for (Map.Entry<String, Long> 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<NegativeQueryVo> ztNegativeList = negativeQueryService.page(ztnegativeQueryParam).getRecords(); |
|
||||||
// 环比数据
|
|
||||||
NegativeQueryParam hbNegativeQueryParam = request.newQueryParam(); |
|
||||||
hbNegativeQueryParam.setCrtTime(compareDateRange.mom()); |
|
||||||
List<NegativeQueryVo> hbNegativList = negativeQueryService.page(hbNegativeQueryParam).getRecords(); |
|
||||||
// 同比数据
|
|
||||||
NegativeQueryParam tbNegativeQueryParam = request.newQueryParam(); |
|
||||||
tbNegativeQueryParam.setCrtTime(compareDateRange.yoy()); |
|
||||||
List<NegativeQueryVo> tbNegativList = negativeQueryService.page(tbNegativeQueryParam).getRecords(); |
|
||||||
// 市局下发数据
|
|
||||||
List<NegativeQueryVo> sjxfNegativeList = ztNegativeList.stream().filter(one -> Objects.equals(0, one.getCrtDepartLevel())).toList(); |
|
||||||
// 分县市局下发数据
|
|
||||||
List<NegativeQueryVo> fxsjxfNegativeList = ztNegativeList.stream().filter(one -> Objects.equals(2, one.getCrtDepartLevel())).toList(); |
|
||||||
// 办结数据
|
|
||||||
List<NegativeQueryVo> bjNegativeList = ztNegativeList.stream().filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())).toList(); |
|
||||||
// 办结中属实数据
|
|
||||||
List<NegativeQueryVo> bjssNegativeList = bjNegativeList.stream().filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())).toList(); |
|
||||||
// 办结中基本属实数据
|
|
||||||
List<NegativeQueryVo> bjjbssNegativeList = bjNegativeList.stream().filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())).toList(); |
|
||||||
// 办结中不属实数据
|
|
||||||
List<NegativeQueryVo> bjbssNegativeList = bjNegativeList.stream().filter(one -> CheckStatusEnum.FALSE_SET.contains(one.getCheckStatusCode())).toList(); |
|
||||||
// 属实 基本属实中的问责数据
|
|
||||||
List<String> ssNegativeIds = Stream.concat(bjssNegativeList.stream(), bjjbssNegativeList.stream()) |
|
||||||
.map(NegativeQueryVo::getId).filter(StrUtil::isNotBlank).distinct().toList(); |
|
||||||
AccountabilityStats currentAccountabilityStats = buildAccountabilityStats(ssNegativeIds); |
|
||||||
// ==================== 环比问责数据 ====================
|
|
||||||
// 环比办结数据
|
|
||||||
List<NegativeQueryVo> hbBjNegativeList = hbNegativList.stream() |
|
||||||
.filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) |
|
||||||
.toList(); |
|
||||||
// 环比办结中属实数据
|
|
||||||
List<NegativeQueryVo> hbBjssNegativeList = hbBjNegativeList.stream() |
|
||||||
.filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) |
|
||||||
.toList(); |
|
||||||
// 环比办结中基本属实数据
|
|
||||||
List<NegativeQueryVo> hbBjjbssNegativeList = hbBjNegativeList.stream() |
|
||||||
.filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) |
|
||||||
.toList(); |
|
||||||
// 环比属实 + 基本属实中的问责数据
|
|
||||||
List<String> hbNegativeIds = Stream.concat(hbBjssNegativeList.stream(), hbBjjbssNegativeList.stream()) |
|
||||||
.map(NegativeQueryVo::getId) |
|
||||||
.filter(StrUtil::isNotBlank) |
|
||||||
.distinct() |
|
||||||
.toList(); |
|
||||||
AccountabilityStats momAccountabilityStats = buildAccountabilityStats(hbNegativeIds); |
|
||||||
int hbAccountabilityTotal = momAccountabilityStats.getTotal(); |
|
||||||
// ==================== 同比问责数据 ====================
|
|
||||||
// 同比办结数据
|
|
||||||
List<NegativeQueryVo> tbBjNegativeList = tbNegativList.stream() |
|
||||||
.filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) |
|
||||||
.toList(); |
|
||||||
// 同比办结中属实数据
|
|
||||||
List<NegativeQueryVo> tbBjssNegativeList = tbBjNegativeList.stream() |
|
||||||
.filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) |
|
||||||
.toList(); |
|
||||||
// 同比办结中基本属实数据
|
|
||||||
List<NegativeQueryVo> tbBjjbssNegativeList = tbBjNegativeList.stream() |
|
||||||
.filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) |
|
||||||
.toList(); |
|
||||||
// 同比属实 + 基本属实中的问责数据
|
|
||||||
List<String> 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<String, Long> 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<String, Long> 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<NegativeQueryVo> list) { |
|
||||||
// 办结
|
|
||||||
List<NegativeQueryVo> 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<String, DictProblemSourceTree> 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<String> negativeIds) { |
|
||||||
AccountabilityStats stats = new AccountabilityStats(); |
|
||||||
if (CollUtil.isEmpty(negativeIds)) { |
|
||||||
return stats; |
|
||||||
} |
|
||||||
NegativeBlameQueryParam queryParam = new NegativeBlameQueryParam(); |
|
||||||
queryParam.setNegativeIds(negativeIds); |
|
||||||
List<NegativeBlame> negativeBlames = negativeBlameResourceService.query(queryParam); |
|
||||||
// 个人问责
|
|
||||||
List<NegativeBlame> personalBlames = negativeBlames.stream() |
|
||||||
.filter(one -> "personal".equals(one.getType())) |
|
||||||
.filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) |
|
||||||
.filter(one -> !"不予追责".equals(one.getHandleResultName())) |
|
||||||
.toList(); |
|
||||||
// 个人问责中的领导问责
|
|
||||||
Set<String> seenLead = new HashSet<>(); |
|
||||||
List<NegativeBlame> 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<NegativeBlame> 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<NegativeBlame> personalBlames = new ArrayList<>(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 领导问责 |
|
||||||
*/ |
|
||||||
private List<NegativeBlame> leadBlames = new ArrayList<>(); |
|
||||||
|
|
||||||
/** |
|
||||||
* 单位问责 |
|
||||||
*/ |
|
||||||
private List<NegativeBlame> unitBlames = new ArrayList<>(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private String leafProblemLabel(String problemSourceCode, Map<String, DictProblemSourceTree> 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<BusinessLinePersonRankItem> buildTopPersons(List<NegativeQueryVo> lineList, int totalIssued) { |
|
||||||
Map<String, PersonAgg> 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; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -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); |
||||||
|
|
||||||
|
} |
||||||
@ -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); |
||||||
|
} |
||||||
@ -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<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); |
||||||
|
|
||||||
|
List<String> 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<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); |
||||||
|
|
||||||
|
List<String> negativeIds = currentList.stream() |
||||||
|
.map(NegativeQueryVo::getId) |
||||||
|
.filter(Objects::nonNull) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); |
||||||
|
statsRequestDTO.setNegativeIds(negativeIds); |
||||||
|
ReportAccountabilityStatsResponseDTO statsResponseDTO = |
||||||
|
reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); |
||||||
|
|
||||||
|
Map<String, List<NegativeBlame>> unitMap = statsResponseDTO.getUnitBlames().stream() |
||||||
|
.collect(java.util.stream.Collectors.groupingBy(NegativeBlame::getHandleResultName)); |
||||||
|
|
||||||
|
AccountabilityUnitSection section = new AccountabilityUnitSection(); |
||||||
|
section.setTotalCount(statsResponseDTO.getUnit()); |
||||||
|
|
||||||
|
List<AccountabilityTypeItem> 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<String, Number> 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<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); |
||||||
|
|
||||||
|
List<String> negativeIds = currentList.stream() |
||||||
|
.map(NegativeQueryVo::getId) |
||||||
|
.filter(Objects::nonNull) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); |
||||||
|
statsRequestDTO.setNegativeIds(negativeIds); |
||||||
|
ReportAccountabilityStatsResponseDTO statsResponseDTO = |
||||||
|
reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); |
||||||
|
|
||||||
|
Map<String, List<NegativeBlame>> leadMap = statsResponseDTO.getLeadBlames().stream() |
||||||
|
.collect(java.util.stream.Collectors.groupingBy(NegativeBlame::getLeadHandleResultName)); |
||||||
|
|
||||||
|
Map<String, List<NegativeBlame>> personMap = statsResponseDTO.getPersonalBlames().stream() |
||||||
|
.collect(java.util.stream.Collectors.groupingBy(NegativeBlame::getHandleResultName)); |
||||||
|
|
||||||
|
Map<String, List<NegativeBlame>> mergedMap = new HashMap<>(personMap); |
||||||
|
leadMap.forEach((key, value) -> |
||||||
|
mergedMap.merge(key, value, (list1, list2) -> { |
||||||
|
List<NegativeBlame> list = new ArrayList<>(list1); |
||||||
|
list.addAll(list2); |
||||||
|
return list; |
||||||
|
}) |
||||||
|
); |
||||||
|
|
||||||
|
AccountabilityPersonalSection section = new AccountabilityPersonalSection(); |
||||||
|
section.setTotalCount(statsResponseDTO.getPersonal()); |
||||||
|
|
||||||
|
List<AccountabilityTypeItem> 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<String, Number> 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; |
||||||
|
} |
||||||
|
} |
||||||
@ -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<NegativeBlame> negativeBlames = negativeBlameResourceService.query(queryParam); |
||||||
|
|
||||||
|
// 个人问责
|
||||||
|
List<NegativeBlame> personalBlames = negativeBlames.stream() |
||||||
|
.filter(one -> "personal".equals(one.getType())) |
||||||
|
.filter(one -> StrUtil.isNotBlank(one.getHandleResultName())) |
||||||
|
.filter(one -> !"不予追责".equals(one.getHandleResultName())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 个人问责中的领导问责
|
||||||
|
Set<String> seenLead = new HashSet<>(); |
||||||
|
List<NegativeBlame> 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<NegativeBlame> 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; |
||||||
|
} |
||||||
|
} |
||||||
@ -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<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); |
||||||
|
// 环比
|
||||||
|
NegativeQueryParam momQueryParam = request.newQueryParam(); |
||||||
|
momQueryParam.setCrtTime(compareDateRange.mom()); |
||||||
|
List<NegativeQueryVo> momList = negativeQueryService.page(momQueryParam).getRecords(); |
||||||
|
// 同比
|
||||||
|
NegativeQueryParam yoyQueryParam = request.newQueryParam(); |
||||||
|
yoyQueryParam.setCrtTime(compareDateRange.yoy()); |
||||||
|
List<NegativeQueryVo> 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; |
||||||
|
} |
||||||
|
} |
||||||
@ -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<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); |
||||||
|
|
||||||
|
Map<String, DictProblemSourceTree> idMap = supDictProblemSourceService.buildIdMap(); |
||||||
|
|
||||||
|
Map<String, Long> aggByParentLabel = currentList.stream() |
||||||
|
.map(NegativeQueryVo::getProblemSourcesCode) |
||||||
|
.map(childId -> parentLabel2Level(childId, idMap)) |
||||||
|
.collect(Collectors.groupingBy(s -> s, Collectors.counting())); |
||||||
|
|
||||||
|
List<Map.Entry<String, Long>> 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<String, Number> pieData = new LinkedHashMap<>(); |
||||||
|
for (Map.Entry<String, Long> 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<BusinessLineDetailSection> 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<NegativeQueryVo> currentList = baseQueryResponseDTO.getCurrentList(); |
||||||
|
List<NegativeQueryVo> momList = baseQueryResponseDTO.getMomList(); |
||||||
|
List<NegativeQueryVo> yoyList = baseQueryResponseDTO.getYoyList(); |
||||||
|
|
||||||
|
Map<String, DictProblemSourceTree> idMap = supDictProblemSourceService.buildIdMap(); |
||||||
|
|
||||||
|
Map<String, List<NegativeQueryVo>> currentGroup = currentList.stream() |
||||||
|
.collect(Collectors.groupingBy( |
||||||
|
vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), |
||||||
|
LinkedHashMap::new, |
||||||
|
Collectors.toList() |
||||||
|
)); |
||||||
|
|
||||||
|
Map<String, List<NegativeQueryVo>> momGroup = momList.stream() |
||||||
|
.collect(Collectors.groupingBy( |
||||||
|
vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), |
||||||
|
LinkedHashMap::new, |
||||||
|
Collectors.toList() |
||||||
|
)); |
||||||
|
|
||||||
|
Map<String, List<NegativeQueryVo>> yoyGroup = yoyList.stream() |
||||||
|
.collect(Collectors.groupingBy( |
||||||
|
vo -> parentLabel2Level(vo.getProblemSourcesCode(), idMap), |
||||||
|
LinkedHashMap::new, |
||||||
|
Collectors.toList() |
||||||
|
)); |
||||||
|
|
||||||
|
List<Map.Entry<String, List<NegativeQueryVo>>> sortedEntries = currentGroup.entrySet().stream() |
||||||
|
.sorted((a, b) -> Integer.compare(b.getValue().size(), a.getValue().size())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
List<BusinessLineDetailSection> result = new ArrayList<>(); |
||||||
|
int index = 1; |
||||||
|
|
||||||
|
for (Map.Entry<String, List<NegativeQueryVo>> entry : sortedEntries) { |
||||||
|
String fatherBusinessLineName = entry.getKey(); |
||||||
|
List<NegativeQueryVo> 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<NegativeQueryVo> 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<String> 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<BusinessLineRankItem> 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<BusinessLineRankItem> 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<BusinessLinePersonRankItem> 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<String, DictProblemSourceTree> 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<String, DictProblemSourceTree> 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<BusinessLinePersonRankItem> buildTopPersons(List<NegativeQueryVo> lineList, int totalIssued) { |
||||||
|
Map<String, PersonAgg> 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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -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<NegativeQueryVo> list = |
||||||
|
requestDTO == null || requestDTO.getNegativeQueryVoList() == null |
||||||
|
? Collections.emptyList() |
||||||
|
: requestDTO.getNegativeQueryVoList(); |
||||||
|
|
||||||
|
List<NegativeQueryVo> closedList = list.stream() |
||||||
|
.filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
List<NegativeQueryVo> verifiedList = closedList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
List<NegativeQueryVo> basicallyVerifiedList = closedList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
List<NegativeQueryVo> 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; |
||||||
|
} |
||||||
|
} |
||||||
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
@ -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<NegativeQueryVo> ztNegativeList = baseQueryResponseDTO.getCurrentList(); |
||||||
|
List<NegativeQueryVo> hbNegativeList = baseQueryResponseDTO.getMomList(); |
||||||
|
List<NegativeQueryVo> tbNegativeList = baseQueryResponseDTO.getYoyList(); |
||||||
|
|
||||||
|
// 市局下发数据
|
||||||
|
List<NegativeQueryVo> sjxfNegativeList = ztNegativeList.stream() |
||||||
|
.filter(one -> Objects.equals(0, one.getCrtDepartLevel())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 分县市局下发数据
|
||||||
|
List<NegativeQueryVo> fxsjxfNegativeList = ztNegativeList.stream() |
||||||
|
.filter(one -> Objects.equals(2, one.getCrtDepartLevel())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 本期办结数据
|
||||||
|
List<NegativeQueryVo> bjNegativeList = ztNegativeList.stream() |
||||||
|
.filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 本期办结中属实数据
|
||||||
|
List<NegativeQueryVo> bjssNegativeList = bjNegativeList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 本期办结中基本属实数据
|
||||||
|
List<NegativeQueryVo> bjjbssNegativeList = bjNegativeList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 本期办结中不属实数据
|
||||||
|
List<NegativeQueryVo> bjbssNegativeList = bjNegativeList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.FALSE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 本期属实 + 基本属实问题ID,用于计算问责数据
|
||||||
|
List<String> 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<NegativeQueryVo> hbBjNegativeList = hbNegativeList.stream() |
||||||
|
.filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 环比办结中属实数据
|
||||||
|
List<NegativeQueryVo> hbBjssNegativeList = hbBjNegativeList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 环比办结中基本属实数据
|
||||||
|
List<NegativeQueryVo> hbBjjbssNegativeList = hbBjNegativeList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 环比属实 + 基本属实问题ID
|
||||||
|
List<String> 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<NegativeQueryVo> tbBjNegativeList = tbNegativeList.stream() |
||||||
|
.filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 同比办结中属实数据
|
||||||
|
List<NegativeQueryVo> tbBjssNegativeList = tbBjNegativeList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 同比办结中基本属实数据
|
||||||
|
List<NegativeQueryVo> tbBjjbssNegativeList = tbBjNegativeList.stream() |
||||||
|
.filter(one -> CheckStatusEnum.PART_TRUE_SET.contains(one.getCheckStatusCode())) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
// 同比属实 + 基本属实问题ID
|
||||||
|
List<String> 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<String, Long> problemEntry = |
||||||
|
ReportTrendUtil.topBy(NegativeQueryVo::getProblemSources, bjssNegativeList, bjjbssNegativeList); |
||||||
|
overviewSection.setTopProblemProject(problemEntry != null ? problemEntry.getKey() : null); |
||||||
|
|
||||||
|
// 重点关注单位
|
||||||
|
Map.Entry<String, Long> departEntry = |
||||||
|
ReportTrendUtil.topBy(NegativeQueryVo::getInvolveDepartName, bjssNegativeList, bjjbssNegativeList); |
||||||
|
overviewSection.setTopProblemUnit(departEntry != null ? departEntry.getKey() : null); |
||||||
|
return overviewSection; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 计算查实率 |
||||||
|
* 查实率 = (属实数 + 基本属实数)/ 办结数 * 100 |
||||||
|
* |
||||||
|
* @param list 问题数据列表 |
||||||
|
* @return 查实率 |
||||||
|
*/ |
||||||
|
private BigDecimal calcVerifiedRate(List<NegativeQueryVo> list) { |
||||||
|
// 办结数据
|
||||||
|
List<NegativeQueryVo> 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); |
||||||
|
} |
||||||
|
} |
||||||
@ -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<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); |
||||||
|
|
||||||
|
// 查询父子部门关系
|
||||||
|
SupDepartGroupParam supDepartGroupParam = new SupDepartGroupParam(); |
||||||
|
supDepartGroupParam.setParentLevel(2); |
||||||
|
supDepartGroupParam.setChildLevel(3); |
||||||
|
Map<String, DepartAndSubDepartDto> departAndSubDepart = |
||||||
|
supDepartResourceService.getDepartAndSubDepart(supDepartGroupParam); |
||||||
|
|
||||||
|
List<UnitInvestigationItem> topUnits = new ArrayList<>(); |
||||||
|
for (DepartAndSubDepartDto value : departAndSubDepart.values()) { |
||||||
|
Set<String> allDepartIds = value.getAllDepartIds(); |
||||||
|
|
||||||
|
List<NegativeQueryVo> 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<NegativeQueryVo> 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<String, Map<String, Number>> seriesData = new LinkedHashMap<>(); |
||||||
|
Map<String, Number> issuedMap = new LinkedHashMap<>(); |
||||||
|
Map<String, Number> 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; |
||||||
|
} |
||||||
|
} |
||||||
Binary file not shown.
Loading…
Reference in new issue