Browse Source

研判分析--step8基本完成

master
buaixuexideshitongxue 2 weeks ago
parent
commit
06d65d9843
  1. 26
      src/main/java/com/biutag/supervision/controller/work/NegativeReportController.java
  2. 3
      src/main/java/com/biutag/supervision/pojo/dto/report/OverviewSection.java
  3. 4
      src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java
  4. 7
      src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java
  5. 3
      src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineDetailSection.java
  6. 4
      src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLinePersonRankItem.java
  7. 3
      src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineRankItem.java
  8. 4
      src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcRequestDTO.java
  9. 24
      src/main/java/com/biutag/supervision/pojo/dto/report/problemType/ReportProblemTypeStatsRequestDTO.java
  10. 24
      src/main/java/com/biutag/supervision/pojo/dto/report/problemType/ReportProblemTypeStatsResponseDTO.java
  11. 3
      src/main/java/com/biutag/supervision/pojo/param/NegativeQueryParam.java
  12. 3
      src/main/java/com/biutag/supervision/pojo/param/PoliceQueryParam.java
  13. 3
      src/main/java/com/biutag/supervision/pojo/vo/NegativeQueryVo.java
  14. 22
      src/main/java/com/biutag/supervision/repository/supdepart/SupDepartResourceService.java
  15. 7
      src/main/java/com/biutag/supervision/service/NegativeQueryService.java
  16. 29
      src/main/java/com/biutag/supervision/service/NegativeTaskService.java
  17. 5
      src/main/java/com/biutag/supervision/service/SupPoliceService.java
  18. 3
      src/main/java/com/biutag/supervision/service/negativeReport/NegativeReportService.java
  19. 138
      src/main/java/com/biutag/supervision/service/negativeReport/NegativeReportServiceImpl.java
  20. 14
      src/main/java/com/biutag/supervision/service/report/ReportProblemTypeStatsService.java
  21. 3
      src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java
  22. 8
      src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java
  23. 206
      src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java
  24. 28
      src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java
  25. 12
      src/main/java/com/biutag/supervision/service/report/impl/ReportDataServiceImpl.java
  26. 61
      src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java
  27. 102
      src/main/java/com/biutag/supervision/service/report/impl/ReportProblemTypeStatsServiceImpl.java
  28. 45
      src/main/java/com/biutag/supervision/util/ReportTrendUtil.java
  29. BIN
      src/main/resources/static/templates/督审一体化平台研判分析报告.docx

26
src/main/java/com/biutag/supervision/controller/work/NegativeReportController.java

@ -1,28 +1,48 @@
package com.biutag.supervision.controller.work; package com.biutag.supervision.controller.work;
import com.biutag.supervision.common.UserContextHolder;
import com.biutag.supervision.pojo.Result;
import com.biutag.supervision.pojo.entity.NegativeTask;
import com.biutag.supervision.pojo.model.UserAuth;
import com.biutag.supervision.pojo.param.NegativeQueryParam; import com.biutag.supervision.pojo.param.NegativeQueryParam;
import com.biutag.supervision.service.NegativeTaskService;
import com.biutag.supervision.service.negativeReport.NegativeReportService; import com.biutag.supervision.service.negativeReport.NegativeReportService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.io.UnsupportedEncodingException; @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("negative") @RequestMapping("negative")
@RestController @RestController
public class NegativeReportController { public class NegativeReportController {
private final NegativeReportService negativeReportService; private final NegativeReportService negativeReportService;
private final NegativeTaskService negativeTaskService;
@Deprecated
@Operation(summary = "生成研判分析报告") @Operation(summary = "生成研判分析报告")
@PostMapping("/generateReport") @PostMapping("/generateReport")
public void generateReport(@RequestBody NegativeQueryParam request, HttpServletResponse response) throws UnsupportedEncodingException { public void generateReport(@RequestBody NegativeQueryParam request, HttpServletResponse response) {
negativeReportService.generateReport(request, response); negativeReportService.generateReport(request, response);
} }
@Operation(summary = "生成研判分析报告任务")
@PostMapping("/export/report")
public Result<Void> generateReport(@RequestBody NegativeQueryParam request) {
request.setCurrent(1);
request.setSize(1000000);
UserAuth currentUser = UserContextHolder.getCurrentUser();
request.setCurrentUser(currentUser);
NegativeTask negativeTask = negativeTaskService.saveReportTask(request);
negativeReportService.exportReport(request, negativeTask.getId());
return Result.success();
}
} }

3
src/main/java/com/biutag/supervision/pojo/dto/report/OverviewSection.java

@ -76,6 +76,9 @@ public class OverviewSection {
@Schema(description = "问责问题数", example = "5") @Schema(description = "问责问题数", example = "5")
private Integer accountabilityProblemTotal; private Integer accountabilityProblemTotal;
@Schema(description = "问责率 问责问题条数/办结的条数")
private BigDecimal accountabilityNegativeRate;
@Schema(description = "问责总人次", example = "58") @Schema(description = "问责总人次", example = "58")
private Integer accountabilityTotal; private Integer accountabilityTotal;

4
src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsRequestDTO.java

@ -1,5 +1,6 @@
package com.biutag.supervision.pojo.dto.report.accountability; package com.biutag.supervision.pojo.dto.report.accountability;
import com.biutag.supervision.pojo.model.UserAuth;
import com.biutag.supervision.pojo.vo.NegativeQueryVo; import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter; import lombok.Getter;
@ -27,5 +28,8 @@ public class ReportAccountabilityStatsRequestDTO {
@Schema(description = "原始问题列表") @Schema(description = "原始问题列表")
private List<NegativeQueryVo> negativeQueryVoList; private List<NegativeQueryVo> negativeQueryVoList;
private UserAuth currentUser;
} }

7
src/main/java/com/biutag/supervision/pojo/dto/report/accountability/ReportAccountabilityStatsResponseDTO.java

@ -9,6 +9,7 @@ import lombok.Setter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -48,12 +49,12 @@ public class ReportAccountabilityStatsResponseDTO {
private List<NegativeBlame> unitBlames = new ArrayList<>(); private List<NegativeBlame> unitBlames = new ArrayList<>();
@Schema(description = "问责人员TOP3") @Schema(description = "问责人员TOP3")
private List<BusinessLinePersonRankItem> topPersons; private List<BusinessLinePersonRankItem> topPersons = new ArrayList<>();
@Schema(description = "个人问责类型次数map") @Schema(description = "个人问责类型次数map")
private Map<String, Integer> personalTypeCountMap; private Map<String, Integer> personalTypeCountMap = new HashMap<>();
@Schema(description = "单位问责类型次数map") @Schema(description = "单位问责类型次数map")
private Map<String, Integer> unitTypeCountMap; private Map<String, Integer> unitTypeCountMap = new HashMap<>();
} }

3
src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineDetailSection.java

@ -40,6 +40,9 @@ public class BusinessLineDetailSection {
@Schema(description = "查实率") @Schema(description = "查实率")
private BigDecimal verifiedRate; private BigDecimal verifiedRate;
@Schema(description = "问责问题条数")
private int accountabilityNegativeCount;
@Schema(description = "问责总次数") @Schema(description = "问责总次数")
private Integer accountabilityTotal; private Integer accountabilityTotal;

4
src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLinePersonRankItem.java

@ -13,6 +13,10 @@ import java.math.BigDecimal;
@NoArgsConstructor @NoArgsConstructor
public class BusinessLinePersonRankItem { public class BusinessLinePersonRankItem {
@Schema(description = "序号")
private Integer orderNo;
@Schema(description = "人员姓名") @Schema(description = "人员姓名")
private String personName; private String personName;

3
src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineRankItem.java

@ -15,6 +15,9 @@ import java.math.BigDecimal;
@NoArgsConstructor @NoArgsConstructor
public class BusinessLineRankItem { public class BusinessLineRankItem {
@Schema(description = "序号")
private Integer orderNo;
@Schema(description = "名称,如 执法程序问题 / 某某派出所") @Schema(description = "名称,如 执法程序问题 / 某某派出所")
private String name; private String name;

4
src/main/java/com/biutag/supervision/pojo/dto/report/closed/ClosedStatsCalcRequestDTO.java

@ -2,7 +2,9 @@ package com.biutag.supervision.pojo.dto.report.closed;
import com.biutag.supervision.pojo.vo.NegativeQueryVo; import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList; import java.util.ArrayList;
@ -11,6 +13,8 @@ import java.util.List;
@Getter @Getter
@Setter @Setter
@Schema(description = "办结统计计算请求DTO") @Schema(description = "办结统计计算请求DTO")
@AllArgsConstructor
@NoArgsConstructor
public class ClosedStatsCalcRequestDTO { public class ClosedStatsCalcRequestDTO {
@Schema(description = "待统计的问题数据列表") @Schema(description = "待统计的问题数据列表")

24
src/main/java/com/biutag/supervision/pojo/dto/report/problemType/ReportProblemTypeStatsRequestDTO.java

@ -0,0 +1,24 @@
package com.biutag.supervision.pojo.dto.report.problemType;
import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @ClassName ReportProblemTypeStatsRequestDTO
* @Description TODO
* @Author shihao
* @Date 2026/3/11 14:39
*/
@Getter
@Setter
@Schema(description = "问题统计请求DTO")
public class ReportProblemTypeStatsRequestDTO {
@Schema(description = "原始问题列表")
private List<NegativeQueryVo> negativeQueryVoList;
}

24
src/main/java/com/biutag/supervision/pojo/dto/report/problemType/ReportProblemTypeStatsResponseDTO.java

@ -0,0 +1,24 @@
package com.biutag.supervision.pojo.dto.report.problemType;
import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineRankItem;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @ClassName ReportProblemTypeStatsResponseDTO
* @Description TODO
* @Author shihao
* @Date 2026/3/11 14:42
*/
@Getter
@Setter
@Schema(description = "问题统计响应DTO")
public class ReportProblemTypeStatsResponseDTO {
@Schema(description = "问题类型TOP列表")
private List<BusinessLineRankItem> topProblemTypes;
}

3
src/main/java/com/biutag/supervision/pojo/param/NegativeQueryParam.java

@ -2,6 +2,7 @@ package com.biutag.supervision.pojo.param;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.biutag.supervision.pojo.model.UserAuth;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter; import lombok.Getter;
@ -116,6 +117,8 @@ public class NegativeQueryParam extends BasePage {
@TableField("issuingDepartName") @TableField("issuingDepartName")
private String issuingDepartName; private String issuingDepartName;
private UserAuth currentUser;
public NegativeQueryParam newQueryParam() { public NegativeQueryParam newQueryParam() {
NegativeQueryParam target = new NegativeQueryParam(); NegativeQueryParam target = new NegativeQueryParam();

3
src/main/java/com/biutag/supervision/pojo/param/PoliceQueryParam.java

@ -1,5 +1,6 @@
package com.biutag.supervision.pojo.param; package com.biutag.supervision.pojo.param;
import com.biutag.supervision.pojo.model.UserAuth;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -25,4 +26,6 @@ public class PoliceQueryParam extends BasePage {
private List<String> idCodes; private List<String> idCodes;
//启动or //启动or
private Boolean isOr; private Boolean isOr;
private UserAuth currentUser;
} }

3
src/main/java/com/biutag/supervision/pojo/vo/NegativeQueryVo.java

@ -209,4 +209,7 @@ public class NegativeQueryVo {
@Schema(description = "核查结论code") @Schema(description = "核查结论code")
private String checkStatusCode; private String checkStatusCode;
@Schema(description = "二级部门ID")
private String secondInvolveDepartId;
} }

22
src/main/java/com/biutag/supervision/repository/supdepart/SupDepartResourceService.java

@ -123,5 +123,27 @@ public class SupDepartResourceService extends BaseDAO {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
/**
* 查询所有二级单位返回 id -> shortName
*/
public Map<String, String> getAllSecondDepartNameMap() {
LambdaQueryWrapper<SupDepart> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SupDepart::getLevel, "2");
List<SupDepart> secondDeparts = supDepartMapper.selectList(wrapper);
if (CollectionUtil.isEmpty(secondDeparts)) {
return Collections.emptyMap();
}
return secondDeparts.stream()
.filter(depart -> StrUtil.isNotBlank(depart.getId()))
.collect(Collectors.toMap(
SupDepart::getId,
SupDepart::getShortName,
(a, b) -> a,
LinkedHashMap::new
));
}
} }

7
src/main/java/com/biutag/supervision/service/NegativeQueryService.java

@ -37,7 +37,10 @@ public class NegativeQueryService {
private final SupDepartService departService; private final SupDepartService departService;
public Page<NegativeQueryVo> page(NegativeQueryParam param) { public Page<NegativeQueryVo> page(NegativeQueryParam param) {
UserAuth user = UserContextHolder.getCurrentUser(); UserAuth user = param.getCurrentUser();
if (user == null) {
user = UserContextHolder.getCurrentUser();
}
if (!AppConstants.USER_TYPE_SUPER.equals(user.getUserType()) && (user.getRoleCodes().isEmpty() || user.getAuthSources().isEmpty() || user.getAuthDepartIds().isEmpty())) { if (!AppConstants.USER_TYPE_SUPER.equals(user.getUserType()) && (user.getRoleCodes().isEmpty() || user.getAuthSources().isEmpty() || user.getAuthDepartIds().isEmpty())) {
return new Page<NegativeQueryVo>().setTotal(0).setRecords(new ArrayList<>()); return new Page<NegativeQueryVo>().setTotal(0).setRecords(new ArrayList<>());
} }
@ -212,7 +215,7 @@ public class NegativeQueryService {
NegativeQueryVo vo = new NegativeQueryVo(); NegativeQueryVo vo = new NegativeQueryVo();
BeanUtils.copyProperties(item, vo); BeanUtils.copyProperties(item, vo);
if (Objects.nonNull(item.getFirstDistributeTime()) && !ProcessingStatusEnum.completed.name().equals(item.getProcessingStatus())) { if (Objects.nonNull(item.getFirstDistributeTime()) && !ProcessingStatusEnum.completed.name().equals(item.getProcessingStatus())) {
vo.setRemainingDuration(TimeUtil.getRemainingDuration(item.getFirstDistributeTime(), item.getMaxSignDuration(), item.getMaxHandleDuration(), item.getExtensionDays(), item.getFlowKey())); // vo.setRemainingDuration(TimeUtil.getRemainingDuration(item.getFirstDistributeTime(), item.getMaxSignDuration(), item.getMaxHandleDuration(), item.getExtensionDays(), item.getFlowKey()));
} }
return vo; return vo;
}).toList(); }).toList();

29
src/main/java/com/biutag/supervision/service/NegativeTaskService.java

@ -18,6 +18,7 @@ import com.biutag.supervision.pojo.dto.*;
import com.biutag.supervision.pojo.entity.*; import com.biutag.supervision.pojo.entity.*;
import com.biutag.supervision.pojo.model.ModelClueTaskDepartModel; import com.biutag.supervision.pojo.model.ModelClueTaskDepartModel;
import com.biutag.supervision.pojo.model.UserAuth; import com.biutag.supervision.pojo.model.UserAuth;
import com.biutag.supervision.pojo.param.NegativeQueryParam;
import com.biutag.supervision.pojo.param.NegativeTaskQueryParam; import com.biutag.supervision.pojo.param.NegativeTaskQueryParam;
import com.biutag.supervision.pojo.vo.ExportNegativeBlameLeaderVo; import com.biutag.supervision.pojo.vo.ExportNegativeBlameLeaderVo;
import com.biutag.supervision.pojo.vo.ExportNegativeBlameVo; import com.biutag.supervision.pojo.vo.ExportNegativeBlameVo;
@ -33,6 +34,8 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -87,6 +90,32 @@ public class NegativeTaskService extends ServiceImpl<NegativeTaskMapper, Negativ
return task; return task;
} }
public NegativeTask saveReportTask(NegativeQueryParam request) {
NegativeTask task = new NegativeTask();
task.setId(IdUtil.simpleUUID());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String start = request.getCrtTime().get(0)
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate()
.format(formatter);
String end = request.getCrtTime().get(1)
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate()
.format(formatter);
task.setTaskName(String.format("分析报告_%s_%s", start, end));
task.setImportRow(-1);
task.setCrtTime(LocalDateTime.now());
task.setStatus(NegativeTaskStatusEnum.PADDING.getValue());
task.setCategory(NegativeTaskCategoryEnum.EXPORT.getValue());
UserAuth user = UserContextHolder.getCurrentUser();
task.setCrtUser(user.getNickName());
task.setCrtUsername(user.getUserName());
save(task);
return task;
}
@Async @Async
public void exportExcel(List<NegativeQueryVo> data, String negativeTaskId) { public void exportExcel(List<NegativeQueryVo> data, String negativeTaskId) {
List<SupDictData> suspectProblem = dictDataService.listByDictType("suspectProblem"); List<SupDictData> suspectProblem = dictDataService.listByDictType("suspectProblem");

5
src/main/java/com/biutag/supervision/service/SupPoliceService.java

@ -33,7 +33,10 @@ public class SupPoliceService extends ServiceImpl<SupPoliceMapper, SupPolice> {
public Page<PoliceModel> page(PoliceQueryParam param) { public Page<PoliceModel> page(PoliceQueryParam param) {
QueryWrapper<PoliceModel> queryWrapper = new QueryWrapper<>(); QueryWrapper<PoliceModel> queryWrapper = new QueryWrapper<>();
UserAuth user = UserContextHolder.getCurrentUser(); UserAuth user = param.getCurrentUser();
if (user == null) {
user = UserContextHolder.getCurrentUser();
}
// 权限 // 权限
if (!AppConstants.USER_TYPE_SUPER.equals(user.getUserType()) && !user.getRoleCodes().contains(RoleCodeEnum.FIRST_ADMIN.getCode())) { if (!AppConstants.USER_TYPE_SUPER.equals(user.getUserType()) && !user.getRoleCodes().contains(RoleCodeEnum.FIRST_ADMIN.getCode())) {
if (user.getAuthDepartIds().isEmpty() || user.getRoleCodes().isEmpty()) { if (user.getAuthDepartIds().isEmpty() || user.getRoleCodes().isEmpty()) {

3
src/main/java/com/biutag/supervision/service/negativeReport/NegativeReportService.java

@ -1,9 +1,12 @@
package com.biutag.supervision.service.negativeReport; package com.biutag.supervision.service.negativeReport;
import com.biutag.supervision.pojo.model.UserAuth;
import com.biutag.supervision.pojo.param.NegativeQueryParam; import com.biutag.supervision.pojo.param.NegativeQueryParam;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
public interface NegativeReportService { public interface NegativeReportService {
void generateReport(NegativeQueryParam request, HttpServletResponse response); void generateReport(NegativeQueryParam request, HttpServletResponse response);
void exportReport(NegativeQueryParam request, String id);
} }

138
src/main/java/com/biutag/supervision/service/negativeReport/NegativeReportServiceImpl.java

@ -1,7 +1,12 @@
package com.biutag.supervision.service.negativeReport; package com.biutag.supervision.service.negativeReport;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.biutag.supervision.constants.enums.NegativeTaskStatusEnum;
import com.biutag.supervision.pojo.dto.report.ReportViewModel; import com.biutag.supervision.pojo.dto.report.ReportViewModel;
import com.biutag.supervision.pojo.entity.NegativeTask;
import com.biutag.supervision.pojo.param.NegativeQueryParam; import com.biutag.supervision.pojo.param.NegativeQueryParam;
import com.biutag.supervision.service.FileService;
import com.biutag.supervision.service.NegativeTaskService;
import com.biutag.supervision.service.report.ReportDataService; import com.biutag.supervision.service.report.ReportDataService;
import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.XWPFTemplate;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@ -10,12 +15,16 @@ import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
/** /**
* @ClassName NegativeReportServiceImpl * @ClassName NegativeReportServiceImpl
@ -32,49 +41,136 @@ public class NegativeReportServiceImpl implements NegativeReportService {
private final ReportDataService reportDataService; private final ReportDataService reportDataService;
private final NegativeTaskService negativeTaskService;
private final FileService fileService;
public void generateReport(NegativeQueryParam request, HttpServletResponse response) { public void generateReport(NegativeQueryParam request, HttpServletResponse response) {
request.setCurrent(1); request.setCurrent(1);
request.setSize(1000000); request.setSize(1000000);
// 你要返回的模板路径 log.info("开始生成报告, crtTime={}, request={}", request.getCrtTime(), request);
String templatePath = "static/templates/督审一体化平台研判分析报告.docx"; String templatePath = "static/templates/督审一体化平台研判分析报告.docx";
ClassPathResource resource = new ClassPathResource(templatePath); ClassPathResource resource = new ClassPathResource(templatePath);
if (!resource.exists()) { if (!resource.exists()) {
// 资源不存在,返回 404 log.warn("报告模板不存在, templatePath={}", templatePath);
response.setStatus(HttpServletResponse.SC_NOT_FOUND); response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.setContentType("application/json;charset=UTF-8"); response.setContentType("application/json;charset=UTF-8");
try { try {
response.getWriter().write("{\"message\":\"模板文件不存在: " + templatePath + "\"}"); response.getWriter().write("{\"message\":\"模板文件不存在: " + templatePath + "\"}");
} catch (IOException ignored) {} } catch (IOException ignored) {
}
return; return;
} }
// 1) 准备模板变量(含图表)
ReportViewModel vm = reportDataService.buildViewModel(request);
// 2) 响应头(docx 正确类型)
String downloadName = "督审一体化平台研判分析报告.docx"; String downloadName = "督审一体化平台研判分析报告.docx";
String encoded = URLEncoder.encode(downloadName, StandardCharsets.UTF_8).replaceAll("\\+", "%20"); String encoded = URLEncoder.encode(downloadName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
String contentDisposition = "attachment; filename=\"" + encoded + "\"; filename*=UTF-8''" + encoded; String contentDisposition = "attachment; filename=\"" + encoded + "\"; filename*=UTF-8''" + encoded;
response.reset();
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", contentDisposition);
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
// 3) 关键:compile + render + write(不要 StreamUtils.copy)
try (InputStream in = resource.getInputStream(); try (InputStream in = resource.getInputStream();
XWPFTemplate template = XWPFTemplate.compile(in).render(vm); XWPFTemplate template = XWPFTemplate.compile(in);
ServletOutputStream out = response.getOutputStream()) { ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ReportViewModel vm = reportDataService.buildViewModel(request);
template.render(vm);
template.write(bos);
byte[] bytes = bos.toByteArray();
log.info("报告生成完成,准备输出, size={} bytes", bytes.length);
response.reset();
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition", contentDisposition);
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentLengthLong(bytes.length);
template.write(out); ServletOutputStream out = response.getOutputStream();
out.write(bytes);
out.flush(); out.flush();
log.info("报告下载成功, fileName={}, size={} bytes", downloadName, bytes.length);
} catch (Exception e) { } catch (Exception e) {
log.error("生成/下载报告失败", e); log.error("生成/下载报告失败", e);
// 如果你们有统一异常处理,可以直接抛出去 if (!response.isCommitted()) {
// throw new RuntimeException("生成报告失败", e); try {
response.reset();
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"message\":\"生成报告失败\"}");
} catch (IOException ioException) {
log.error("回写失败响应异常", ioException);
}
}
}
}
@Async
public void exportReport(NegativeQueryParam request, String negativeTaskId) {
try {
byte[] bytes = buildReportBytes(request);
String filePath = fileService.upload(
new ByteArrayInputStream(bytes),
bytes.length,
".docx"
);
negativeTaskService.update(
new LambdaUpdateWrapper<NegativeTask>()
.eq(NegativeTask::getId, negativeTaskId)
.set(NegativeTask::getStatus, NegativeTaskStatusEnum.SUCCESS.getValue())
.set(NegativeTask::getFilePath, filePath)
.set(NegativeTask::getUpdTime, LocalDateTime.now())
);
log.info("报告任务成功, taskId={}, filePath={}", negativeTaskId, filePath);
} catch (Exception e) {
log.error("报告任务失败, taskId={}", negativeTaskId, e);
negativeTaskService.update(
new LambdaUpdateWrapper<NegativeTask>()
.eq(NegativeTask::getId, negativeTaskId)
.set(NegativeTask::getStatus, NegativeTaskStatusEnum.FAIL.getValue())
.set(NegativeTask::getUpdTime, LocalDateTime.now())
);
}
}
public byte[] buildReportBytes(NegativeQueryParam request) {
request.setCurrent(1);
request.setSize(1000000);
log.info("开始生成报告, crtTime={}, request={}", request.getCrtTime(), request);
String templatePath = "static/templates/督审一体化平台研判分析报告.docx";
ClassPathResource resource = new ClassPathResource(templatePath);
if (!resource.exists()) {
throw new RuntimeException("报告模板不存在: " + templatePath);
}
try (InputStream in = resource.getInputStream();
XWPFTemplate template = XWPFTemplate.compile(in);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
ReportViewModel vm = reportDataService.buildViewModel(request);
template.render(vm);
template.write(bos);
byte[] bytes = bos.toByteArray();
log.info("报告生成完成, size={} bytes", bytes.length);
return bytes;
} catch (Exception e) {
throw new RuntimeException("生成报告失败", e);
} }
} }
} }

14
src/main/java/com/biutag/supervision/service/report/ReportProblemTypeStatsService.java

@ -0,0 +1,14 @@
package com.biutag.supervision.service.report;
import com.biutag.supervision.pojo.dto.report.problemType.ReportProblemTypeStatsRequestDTO;
import com.biutag.supervision.pojo.dto.report.problemType.ReportProblemTypeStatsResponseDTO;
public interface ReportProblemTypeStatsService {
/**
* 计算问题类型相关
* @param reportProblemTypeStatsRequestDTO
* @return
*/
ReportProblemTypeStatsResponseDTO calculateProblemTypeStats(ReportProblemTypeStatsRequestDTO reportProblemTypeStatsRequestDTO);
}

3
src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilitySectionServiceImpl.java

@ -42,6 +42,7 @@ public class ReportAccountabilitySectionServiceImpl implements ReportAccountabil
List<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); List<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords();
ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO();
statsRequestDTO.setNegativeQueryVoList(currentList); statsRequestDTO.setNegativeQueryVoList(currentList);
statsRequestDTO.setCurrentUser(currentQueryParam.getCurrentUser());
ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO);
AccountabilityOverviewSection section = new AccountabilityOverviewSection(); AccountabilityOverviewSection section = new AccountabilityOverviewSection();
section.setPeriodStart(periodStart); section.setPeriodStart(periodStart);
@ -65,6 +66,7 @@ public class ReportAccountabilitySectionServiceImpl implements ReportAccountabil
List<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); List<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords();
ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO();
statsRequestDTO.setNegativeQueryVoList(currentList); statsRequestDTO.setNegativeQueryVoList(currentList);
statsRequestDTO.setCurrentUser(currentQueryParam.getCurrentUser());
ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO);
AccountabilityUnitSection section = new AccountabilityUnitSection(); AccountabilityUnitSection section = new AccountabilityUnitSection();
section.setTotalCount(statsResponseDTO.getUnit()); section.setTotalCount(statsResponseDTO.getUnit());
@ -102,6 +104,7 @@ public class ReportAccountabilitySectionServiceImpl implements ReportAccountabil
List<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords(); List<NegativeQueryVo> currentList = negativeQueryService.page(currentQueryParam).getRecords();
ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO();
statsRequestDTO.setNegativeQueryVoList(currentList); statsRequestDTO.setNegativeQueryVoList(currentList);
statsRequestDTO.setCurrentUser(currentQueryParam.getCurrentUser());
ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); ReportAccountabilityStatsResponseDTO statsResponseDTO = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO);
AccountabilityPersonalSection section = new AccountabilityPersonalSection(); AccountabilityPersonalSection section = new AccountabilityPersonalSection();
section.setTotalCount(statsResponseDTO.getPersonal()); section.setTotalCount(statsResponseDTO.getPersonal());

8
src/main/java/com/biutag/supervision/service/report/impl/ReportAccountabilityStatsServiceImpl.java

@ -27,6 +27,7 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -152,7 +153,7 @@ public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilit
); );
// 11. 计算问责人员TOP3 // 11. 计算问责人员TOP3
List<BusinessLinePersonRankItem> topPersons = calculateTopPersons(personalBlames); List<BusinessLinePersonRankItem> topPersons = calculateTopPersons(personalBlames, requestDTO);
// 问责率 // 问责率
responseDTO.setAccountabilityNegativeRate(accountabilityNegativeRate); responseDTO.setAccountabilityNegativeRate(accountabilityNegativeRate);
@ -211,7 +212,7 @@ public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilit
/** /**
* 计算问责人员TOP3 * 计算问责人员TOP3
*/ */
private List<BusinessLinePersonRankItem> calculateTopPersons(List<NegativeBlame> personalBlames) { private List<BusinessLinePersonRankItem> calculateTopPersons(List<NegativeBlame> personalBlames, ReportAccountabilityStatsRequestDTO requestDTO) {
if (CollUtil.isEmpty(personalBlames)) { if (CollUtil.isEmpty(personalBlames)) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -223,6 +224,7 @@ public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilit
(v1, v2) -> v1, (v1, v2) -> v1,
LinkedHashMap::new LinkedHashMap::new
)); ));
AtomicInteger index = new AtomicInteger(1);
return personalBlames.stream() return personalBlames.stream()
.collect(Collectors.groupingBy( .collect(Collectors.groupingBy(
blame -> String.join("|", blame -> String.join("|",
@ -238,6 +240,7 @@ public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilit
PoliceQueryParam policeQueryParam = new PoliceQueryParam(); PoliceQueryParam policeQueryParam = new PoliceQueryParam();
policeQueryParam.setEmpNo(blame.getBlameEmpNo()); policeQueryParam.setEmpNo(blame.getBlameEmpNo());
policeQueryParam.setCurrentUser(requestDTO.getCurrentUser());
List<PoliceModel> records = supPoliceService.page(policeQueryParam).getRecords(); List<PoliceModel> records = supPoliceService.page(policeQueryParam).getRecords();
String unitName = "未知"; String unitName = "未知";
String identityName = "未知"; String identityName = "未知";
@ -247,6 +250,7 @@ public class ReportAccountabilityStatsServiceImpl implements ReportAccountabilit
} }
return BusinessLinePersonRankItem.builder() return BusinessLinePersonRankItem.builder()
.orderNo(index.getAndIncrement())
.personName(blame.getBlameName()) .personName(blame.getBlameName())
.unitName(unitName) .unitName(unitName)
.identityName(identityName) .identityName(identityName)

206
src/main/java/com/biutag/supervision/service/report/impl/ReportBusinessLineSectionServiceImpl.java

@ -11,18 +11,18 @@ import com.biutag.supervision.pojo.dto.report.base.ReportBaseQueryResponseDTO;
import com.biutag.supervision.pojo.dto.report.businessLine.*; 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.ClosedStatsCalcRequestDTO;
import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO; import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO;
import com.biutag.supervision.pojo.dto.report.problemType.ReportProblemTypeStatsRequestDTO;
import com.biutag.supervision.pojo.dto.report.problemType.ReportProblemTypeStatsResponseDTO;
import com.biutag.supervision.pojo.entity.NegativeBlame; import com.biutag.supervision.pojo.entity.NegativeBlame;
import com.biutag.supervision.pojo.entity.NegativeProblemRelation; import com.biutag.supervision.pojo.entity.NegativeProblemRelation;
import com.biutag.supervision.pojo.param.NegativeQueryParam; import com.biutag.supervision.pojo.param.NegativeQueryParam;
import com.biutag.supervision.pojo.vo.DictProblemSourceTree; import com.biutag.supervision.pojo.vo.DictProblemSourceTree;
import com.biutag.supervision.pojo.vo.NegativeQueryVo; import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import com.biutag.supervision.repository.supdepart.SupDepartResourceService;
import com.biutag.supervision.service.NegativeProblemRelationService; import com.biutag.supervision.service.NegativeProblemRelationService;
import com.biutag.supervision.service.NegativeQueryService; import com.biutag.supervision.service.NegativeQueryService;
import com.biutag.supervision.service.SupDictProblemSourceService; import com.biutag.supervision.service.SupDictProblemSourceService;
import com.biutag.supervision.service.report.ReportAccountabilityStatsService; import com.biutag.supervision.service.report.*;
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.ChartRenderUtil;
import com.biutag.supervision.util.ReportTrendUtil; import com.biutag.supervision.util.ReportTrendUtil;
import com.deepoove.poi.data.PictureRenderData; import com.deepoove.poi.data.PictureRenderData;
@ -31,6 +31,7 @@ import com.deepoove.poi.data.Pictures;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.One;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -55,8 +56,12 @@ public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineS
@Resource @Resource
private ReportAccountabilityStatsService reportAccountabilityStatsService; private ReportAccountabilityStatsService reportAccountabilityStatsService;
@Resource @Resource
private NegativeProblemRelationService negativeProblemRelationService; private ReportProblemTypeStatsService reportProblemTypeStatsService;
@Override @Override
public BusinessLineOverviewSection buildBusinessLineOverviewSection(ReportBusinessLineSectionRequestDTO requestDTO) { public BusinessLineOverviewSection buildBusinessLineOverviewSection(ReportBusinessLineSectionRequestDTO requestDTO) {
@ -190,69 +195,41 @@ public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineS
// 问责统计 // 问责统计
ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO(); ReportAccountabilityStatsRequestDTO statsRequestDTO = new ReportAccountabilityStatsRequestDTO();
statsRequestDTO.setNegativeQueryVoList(lineList); statsRequestDTO.setNegativeQueryVoList(lineList);
statsRequestDTO.setCurrentUser(request.getCurrentUser());
ReportAccountabilityStatsResponseDTO accountabilityStats = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO); ReportAccountabilityStatsResponseDTO accountabilityStats = reportAccountabilityStatsService.calculateAccountabilityStats(statsRequestDTO);
section.setAccountabilityNegativeCount(accountabilityStats.getAccountabilityNegativeCount());
section.setAccountabilityTotal(accountabilityStats.getTotal()); section.setAccountabilityTotal(accountabilityStats.getTotal());
section.setAccountabilityRate(accountabilityStats.getAccountabilityNegativeRate()); section.setAccountabilityRate(accountabilityStats.getAccountabilityNegativeRate());
section.setPersonalAccountabilityCount(accountabilityStats.getPersonal()); section.setPersonalAccountabilityCount(accountabilityStats.getPersonal());
section.setDepartmentAccountabilityCount(accountabilityStats.getUnit()); section.setDepartmentAccountabilityCount(accountabilityStats.getUnit());
//问题类型 TOP3 //问题类型 TOP3
// Set<String> collect = lineList.stream().map(NegativeQueryVo::getId).collect(Collectors.toSet()); ReportProblemTypeStatsRequestDTO reportProblemTypeStatsRequestDTO = new ReportProblemTypeStatsRequestDTO();
// List<NegativeProblemRelation> negativeProblemRelations = negativeProblemRelationService.list(collect); reportProblemTypeStatsRequestDTO.setNegativeQueryVoList(lineList);
// // 1. 分组统计,value为所有数据的List ReportProblemTypeStatsResponseDTO reportProblemTypeStatsResponseDTO = reportProblemTypeStatsService.calculateProblemTypeStats(reportProblemTypeStatsRequestDTO);
// Map<String, List<NegativeProblemRelation>> groupedMap = negativeProblemRelations.stream() section.setTopProblemTypes(reportProblemTypeStatsResponseDTO.getTopProblemTypes());
// .collect(Collectors.groupingBy(
// relation -> relation.getOneLevelContent() +
// relation.getTwoLevelContent() +
// relation.getThreeLevelContent()
// ));
// // 2. 按List大小(数量)降序排序
// List<Map.Entry<String, List<NegativeProblemRelation>>> sortedList = groupedMap.entrySet().stream()
// .sorted((entry1, entry2) -> Integer.compare(entry2.getValue().size(), entry1.getValue().size()))
// .collect(Collectors.toList());
// section.setTopProblemTypes(topProblemTypes);
// 重点单位 TOP3 // 重点单位 TOP3
section.setTopUnits(closedStats.getTopUnits().stream().limit(3).toList()); section.setTopUnits(closedStats.getTopUnits().stream().limit(3).toList());
// 重点人员 TOP3 // 重点人员 TOP3
section.setTopPersons(accountabilityStats.getTopPersons().stream().limit(3).toList()); section.setTopPersons(accountabilityStats.getTopPersons().stream().limit(3).toList());
BigDecimal currentVerifiedRate = closedStats.getVerifiedRate();
ClosedStatsCalcRequestDTO momRequestDTO = new ClosedStatsCalcRequestDTO();
int currentCount = totalIssued; momRequestDTO.setNegativeQueryVoList(momGroup.getOrDefault(fatherBusinessLineName, Collections.emptyList()));
int momCount = momGroup.getOrDefault(fatherBusinessLineName, Collections.emptyList()).size(); ClosedStatsCalcResponseDTO momClosedStats = reportClosedStatsService.calculateClosedStats(momRequestDTO);
int yoyCount = yoyGroup.getOrDefault(fatherBusinessLineName, Collections.emptyList()).size(); ClosedStatsCalcRequestDTO yoyRequestDTO = new ClosedStatsCalcRequestDTO();
section.setMomRate(ReportTrendUtil.calcRate(currentCount, momCount)); yoyRequestDTO.setNegativeQueryVoList(yoyGroup.getOrDefault(fatherBusinessLineName, Collections.emptyList()));
section.setMomTrend(ReportTrendUtil.calcTrend(currentCount, momCount)); ClosedStatsCalcResponseDTO yoyClosedStats = reportClosedStatsService.calculateClosedStats(yoyRequestDTO);
section.setYoyRate(ReportTrendUtil.calcRate(currentCount, yoyCount)); BigDecimal momVerifiedRate = momClosedStats.getVerifiedRate();
section.setYoyTrend(ReportTrendUtil.calcTrend(currentCount, yoyCount)); BigDecimal yoyVerifiedRate = yoyClosedStats.getVerifiedRate();
section.setMomRate(ReportTrendUtil.calcDiff(currentVerifiedRate, momVerifiedRate));
section.setMomTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, momVerifiedRate));
section.setYoyRate(ReportTrendUtil.calcDiff(currentVerifiedRate, yoyVerifiedRate));
section.setYoyTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, yoyVerifiedRate));
result.add(section); result.add(section);
} }
log.info("条线明细计算结束======================================================================================="); log.info("条线明细计算结束=======================================================================================");
return result; 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解析父级业务条线名称 * 根据子级问题来源ID解析父级业务条线名称
@ -270,27 +247,6 @@ public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineS
: StrUtil.blankToDefault(child.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();
}
/** /**
* 阿拉伯数字序号转中文序号 * 阿拉伯数字序号转中文序号
*/ */
@ -302,108 +258,8 @@ public class ReportBusinessLineSectionServiceImpl implements ReportBusinessLineS
return String.valueOf(index); return String.valueOf(index);
} }
/** private BigDecimal defaultZero(BigDecimal value) {
* 构建重点人员TOP3 return value == null ? BigDecimal.ZERO : value;
*/
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;
} }
} }

28
src/main/java/com/biutag/supervision/service/report/impl/ReportClosedStatsServiceImpl.java

@ -7,18 +7,25 @@ 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.ClosedStatsCalcRequestDTO;
import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO; import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO;
import com.biutag.supervision.pojo.vo.NegativeQueryVo; import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import com.biutag.supervision.repository.supdepart.SupDepartResourceService;
import com.biutag.supervision.service.report.ReportClosedStatsService; import com.biutag.supervision.service.report.ReportClosedStatsService;
import com.biutag.supervision.util.ReportTrendUtil; import com.biutag.supervision.util.ReportTrendUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
public class ReportClosedStatsServiceImpl implements ReportClosedStatsService { public class ReportClosedStatsServiceImpl implements ReportClosedStatsService {
@Resource
private SupDepartResourceService supDepartResourceService;
@Override @Override
public ClosedStatsCalcResponseDTO calculateClosedStats(ClosedStatsCalcRequestDTO requestDTO) { public ClosedStatsCalcResponseDTO calculateClosedStats(ClosedStatsCalcRequestDTO requestDTO) {
@ -50,17 +57,32 @@ public class ReportClosedStatsServiceImpl implements ReportClosedStatsService {
// 4. 计算重点单位 TOP3(已办结且部门名称不为空) // 4. 计算重点单位 TOP3(已办结且部门名称不为空)
Map<String, String> allSecondDepartNameMap = supDepartResourceService.getAllSecondDepartNameMap();
AtomicInteger index = new AtomicInteger(1);
List<BusinessLineRankItem> topUnits = closedList.stream() List<BusinessLineRankItem> topUnits = closedList.stream()
.filter(one -> StrUtil.isNotBlank(one.getInvolveDepartName())) .filter(one -> StrUtil.isNotBlank(one.getSecondInvolveDepartId()))
.collect(Collectors.groupingBy(NegativeQueryVo::getInvolveDepartName, Collectors.counting())) .collect(Collectors.groupingBy(NegativeQueryVo::getSecondInvolveDepartId, Collectors.counting()))
.entrySet().stream() .entrySet().stream()
.filter(e -> StrUtil.isNotBlank(allSecondDepartNameMap.get(e.getKey())))
.sorted((a, b) -> Long.compare(b.getValue(), a.getValue())) .sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
.map(e -> new BusinessLineRankItem( .map(e -> new BusinessLineRankItem(
e.getKey(), index.getAndIncrement(),
allSecondDepartNameMap.get(e.getKey()),
e.getValue().intValue(), e.getValue().intValue(),
ReportTrendUtil.percent(e.getValue().intValue(), closedList.size()) ReportTrendUtil.percent(e.getValue().intValue(), closedList.size())
)) ))
.toList(); .toList();
// List<BusinessLineRankItem> topUnits = closedList.stream()
// .filter(one -> StrUtil.isNotBlank(one.getInvolveDepartName()))
// .collect(Collectors.groupingBy(NegativeQueryVo::getInvolveDepartName, Collectors.counting()))
// .entrySet().stream()
// .sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
// .map(e -> new BusinessLineRankItem(
// e.getKey(),
// e.getValue().intValue(),
// ReportTrendUtil.percent(e.getValue().intValue(), closedList.size())
// ))
// .toList();
ClosedStatsCalcResponseDTO responseDTO = new ClosedStatsCalcResponseDTO(); ClosedStatsCalcResponseDTO responseDTO = new ClosedStatsCalcResponseDTO();
responseDTO.setClosedCount(closedList.size()); responseDTO.setClosedCount(closedList.size());

12
src/main/java/com/biutag/supervision/service/report/impl/ReportDataServiceImpl.java

@ -28,18 +28,24 @@ public class ReportDataServiceImpl implements ReportDataService {
// 仅负责报表各模块编排,不承载具体统计逻辑 // 仅负责报表各模块编排,不承载具体统计逻辑
@Override @Override
public ReportViewModel buildViewModel(NegativeQueryParam request) { public ReportViewModel buildViewModel(NegativeQueryParam request) {
long start = System.currentTimeMillis();
String periodStart = TimeUtil.formatDate(request.getCrtTime().get(0)); String periodStart = TimeUtil.formatDate(request.getCrtTime().get(0));
String periodEnd = TimeUtil.formatDate(request.getCrtTime().get(1)); String periodEnd = TimeUtil.formatDate(request.getCrtTime().get(1));
ReportViewModel vm = new ReportViewModel(); ReportViewModel vm = new ReportViewModel();
vm.setPeriodStart(periodStart); vm.setPeriodStart(periodStart);
vm.setPeriodEnd(periodEnd); vm.setPeriodEnd(periodEnd);
// 总体概览 // 总体概览
long overviewStart = System.currentTimeMillis();
ReportOverviewSectionRequestDTO overviewRequestDTO = new ReportOverviewSectionRequestDTO(); ReportOverviewSectionRequestDTO overviewRequestDTO = new ReportOverviewSectionRequestDTO();
overviewRequestDTO.setNegativeQueryParam(request); overviewRequestDTO.setNegativeQueryParam(request);
overviewRequestDTO.setPeriodStart(periodStart); overviewRequestDTO.setPeriodStart(periodStart);
overviewRequestDTO.setPeriodEnd(periodEnd); overviewRequestDTO.setPeriodEnd(periodEnd);
vm.setOverviewSection(reportOverviewSectionService.buildOverviewSection(overviewRequestDTO)); vm.setOverviewSection(reportOverviewSectionService.buildOverviewSection(overviewRequestDTO));
log.info("总体概览耗时:{} ms", System.currentTimeMillis() - overviewStart);
// 业务条线 // 业务条线
long businessStart = System.currentTimeMillis();
ReportBusinessLineSectionRequestDTO businessLineRequestDTO = new ReportBusinessLineSectionRequestDTO(); ReportBusinessLineSectionRequestDTO businessLineRequestDTO = new ReportBusinessLineSectionRequestDTO();
businessLineRequestDTO.setNegativeQueryParam(request); businessLineRequestDTO.setNegativeQueryParam(request);
businessLineRequestDTO.setPeriodStart(periodStart); businessLineRequestDTO.setPeriodStart(periodStart);
@ -48,13 +54,17 @@ public class ReportDataServiceImpl implements ReportDataService {
vm.setBusinessLineOverviewSection(reportBusinessLineSectionService.buildBusinessLineOverviewSection(businessLineRequestDTO)); vm.setBusinessLineOverviewSection(reportBusinessLineSectionService.buildBusinessLineOverviewSection(businessLineRequestDTO));
// 条线明细 // 条线明细
vm.setBusinessLineDetailSections(reportBusinessLineSectionService.buildBusinessLineDetailSections(businessLineRequestDTO)); vm.setBusinessLineDetailSections(reportBusinessLineSectionService.buildBusinessLineDetailSections(businessLineRequestDTO));
log.info("业务条线耗时:{} ms", System.currentTimeMillis() - businessStart);
// 单位查处情况总览 // 单位查处情况总览
long unitStart = System.currentTimeMillis();
ReportUnitInvestigationSectionRequestDTO unitRequestDTO = new ReportUnitInvestigationSectionRequestDTO(); ReportUnitInvestigationSectionRequestDTO unitRequestDTO = new ReportUnitInvestigationSectionRequestDTO();
unitRequestDTO.setNegativeQueryParam(request); unitRequestDTO.setNegativeQueryParam(request);
unitRequestDTO.setPeriodStart(periodStart); unitRequestDTO.setPeriodStart(periodStart);
unitRequestDTO.setPeriodEnd(periodEnd); unitRequestDTO.setPeriodEnd(periodEnd);
vm.setUnitInvestigationOverviewSection(reportUnitInvestigationSectionService.buildUnitInvestigationOverviewSection(unitRequestDTO)); vm.setUnitInvestigationOverviewSection(reportUnitInvestigationSectionService.buildUnitInvestigationOverviewSection(unitRequestDTO));
log.info("单位查处耗时:{} ms", System.currentTimeMillis() - unitStart);
// 问责情况 // 问责情况
long accountabilityStart = System.currentTimeMillis();
ReportAccountabilitySectionRequestDTO accountabilityRequestDTO = new ReportAccountabilitySectionRequestDTO(); ReportAccountabilitySectionRequestDTO accountabilityRequestDTO = new ReportAccountabilitySectionRequestDTO();
accountabilityRequestDTO.setNegativeQueryParam(request); accountabilityRequestDTO.setNegativeQueryParam(request);
accountabilityRequestDTO.setPeriodStart(periodStart); accountabilityRequestDTO.setPeriodStart(periodStart);
@ -62,6 +72,8 @@ public class ReportDataServiceImpl implements ReportDataService {
vm.setAccountabilityOverviewSection(reportAccountabilitySectionService.buildAccountabilityOverviewSection(accountabilityRequestDTO)); vm.setAccountabilityOverviewSection(reportAccountabilitySectionService.buildAccountabilityOverviewSection(accountabilityRequestDTO));
vm.setAccountabilityUnitDetailSection(reportAccountabilitySectionService.buildAccountabilityUnitDetailSection(accountabilityRequestDTO)); vm.setAccountabilityUnitDetailSection(reportAccountabilitySectionService.buildAccountabilityUnitDetailSection(accountabilityRequestDTO));
vm.setAccountabilityPersonOverviewSection(reportAccountabilitySectionService.buildAccountabilityPersonalOverviewSection(accountabilityRequestDTO)); vm.setAccountabilityPersonOverviewSection(reportAccountabilitySectionService.buildAccountabilityPersonalOverviewSection(accountabilityRequestDTO));
log.info("问责统计耗时:{} ms", System.currentTimeMillis() - accountabilityStart);
log.info("报表整体生成耗时:{} ms", System.currentTimeMillis() - start);
// System.out.println(1/0); // System.out.println(1/0);
return vm; return vm;
} }

61
src/main/java/com/biutag/supervision/service/report/impl/ReportOverviewSectionServiceImpl.java

@ -1,5 +1,6 @@
package com.biutag.supervision.service.report.impl; package com.biutag.supervision.service.report.impl;
import cn.hutool.core.util.StrUtil;
import com.biutag.supervision.pojo.dto.report.OverviewSection; 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.ReportAccountabilityStatsRequestDTO;
import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO; import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO;
@ -10,6 +11,7 @@ import com.biutag.supervision.pojo.dto.report.closed.ClosedStatsCalcResponseDTO;
import com.biutag.supervision.pojo.dto.report.overview.ReportOverviewSectionRequestDTO; import com.biutag.supervision.pojo.dto.report.overview.ReportOverviewSectionRequestDTO;
import com.biutag.supervision.pojo.param.NegativeQueryParam; import com.biutag.supervision.pojo.param.NegativeQueryParam;
import com.biutag.supervision.pojo.vo.NegativeQueryVo; import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import com.biutag.supervision.repository.supdepart.SupDepartResourceService;
import com.biutag.supervision.service.report.ReportAccountabilityStatsService; import com.biutag.supervision.service.report.ReportAccountabilityStatsService;
import com.biutag.supervision.service.report.ReportBaseQueryService; import com.biutag.supervision.service.report.ReportBaseQueryService;
import com.biutag.supervision.service.report.ReportClosedStatsService; import com.biutag.supervision.service.report.ReportClosedStatsService;
@ -55,6 +57,9 @@ public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionSe
@Resource @Resource
private ReportClosedStatsService reportClosedStatsService; private ReportClosedStatsService reportClosedStatsService;
@Resource
private SupDepartResourceService supDepartResourceService;
/** /**
* 构建总体概览数据 * 构建总体概览数据
* *
@ -96,9 +101,9 @@ public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionSe
ClosedStatsCalcResponseDTO yoyClosedStats = calculateClosedStats(yoyList); ClosedStatsCalcResponseDTO yoyClosedStats = calculateClosedStats(yoyList);
// 4. 问责统计 // 4. 问责统计
ReportAccountabilityStatsResponseDTO currentAccountabilityStats = calculateAccountabilityStats(currentList); ReportAccountabilityStatsResponseDTO currentAccountabilityStats = calculateAccountabilityStats(currentList,requestDTO);
ReportAccountabilityStatsResponseDTO momAccountabilityStats = calculateAccountabilityStats(momList); ReportAccountabilityStatsResponseDTO momAccountabilityStats = calculateAccountabilityStats(momList, requestDTO);
ReportAccountabilityStatsResponseDTO yoyAccountabilityStats = calculateAccountabilityStats(yoyList); ReportAccountabilityStatsResponseDTO yoyAccountabilityStats = calculateAccountabilityStats(yoyList, requestDTO);
// 5. 环比/同比基础值 // 5. 环比/同比基础值
int currentTotal = currentList.size(); int currentTotal = currentList.size();
@ -139,36 +144,67 @@ public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionSe
overviewSection.setVerifiedAndBasicallyVerifiedCount(currentClosedStats.getVerifiedCount() + currentClosedStats.getBasicallyVerifiedCount()); overviewSection.setVerifiedAndBasicallyVerifiedCount(currentClosedStats.getVerifiedCount() + currentClosedStats.getBasicallyVerifiedCount());
// 查实率 // 查实率
log.info("设置查实率前原始数据,currentVerifiedRate={}, momVerifiedRate={}, yoyVerifiedRate={}", currentVerifiedRate, momVerifiedRate, yoyVerifiedRate);
overviewSection.setVerifiedRate(currentVerifiedRate); overviewSection.setVerifiedRate(currentVerifiedRate);
overviewSection.setVerifiedMomRate(ReportTrendUtil.calcRate(currentVerifiedRate, momVerifiedRate)); overviewSection.setVerifiedMomRate(ReportTrendUtil.calcAbsDiff(currentVerifiedRate, momVerifiedRate));
overviewSection.setVerifiedMomTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, momVerifiedRate)); overviewSection.setVerifiedMomTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, momVerifiedRate));
overviewSection.setVerifiedYoyRate(ReportTrendUtil.calcRate(currentVerifiedRate, yoyVerifiedRate)); overviewSection.setVerifiedYoyRate(ReportTrendUtil.calcAbsDiff(currentVerifiedRate, yoyVerifiedRate));
overviewSection.setVerifiedYoyTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, yoyVerifiedRate)); overviewSection.setVerifiedYoyTrend(ReportTrendUtil.calcTrend(currentVerifiedRate, yoyVerifiedRate));
// 问责统计 // 问责统计
log.info("设置问责统计前原始数据,accountabilityProblemTotal={}, currentAccountabilityTotal={}, personalAccountability={}, unitAccountability={}, momAccountabilityTotal={}, yoyAccountabilityTotal={}",
currentAccountabilityStats.getAccountabilityNegativeCount(),
currentAccountabilityTotal,
currentAccountabilityStats.getPersonal(),
currentAccountabilityStats.getUnit(),
momAccountabilityTotal,
yoyAccountabilityTotal);
overviewSection.setAccountabilityProblemTotal(currentAccountabilityStats.getAccountabilityNegativeCount()); overviewSection.setAccountabilityProblemTotal(currentAccountabilityStats.getAccountabilityNegativeCount());
overviewSection.setAccountabilityNegativeRate(currentAccountabilityStats.getAccountabilityNegativeRate());
overviewSection.setAccountabilityTotal(currentAccountabilityTotal); overviewSection.setAccountabilityTotal(currentAccountabilityTotal);
overviewSection.setPersonalAccountability(currentAccountabilityStats.getPersonal()); overviewSection.setPersonalAccountability(currentAccountabilityStats.getPersonal());
overviewSection.setUnitAccountability(currentAccountabilityStats.getUnit()); overviewSection.setUnitAccountability(currentAccountabilityStats.getUnit());
overviewSection.setAccountabilityMomRate(ReportTrendUtil.calcRate(currentAccountabilityTotal, momAccountabilityTotal)); overviewSection.setAccountabilityMomRate(ReportTrendUtil.calcAbsDiff(currentAccountabilityStats.getAccountabilityNegativeRate(), momAccountabilityStats.getAccountabilityNegativeRate()));
overviewSection.setAccountabilityMomTrend(ReportTrendUtil.calcTrend(currentAccountabilityTotal, momAccountabilityTotal)); overviewSection.setAccountabilityMomTrend(ReportTrendUtil.calcTrend(currentAccountabilityTotal, momAccountabilityTotal));
overviewSection.setAccountabilityYoyRate(ReportTrendUtil.calcRate(currentAccountabilityTotal, yoyAccountabilityTotal)); overviewSection.setAccountabilityYoyRate(ReportTrendUtil.calcAbsDiff(momAccountabilityStats.getAccountabilityNegativeRate(), yoyAccountabilityStats.getAccountabilityNegativeRate()));
overviewSection.setAccountabilityYoyTrend(ReportTrendUtil.calcTrend(currentAccountabilityTotal, yoyAccountabilityTotal)); overviewSection.setAccountabilityYoyTrend(ReportTrendUtil.calcTrend(currentAccountabilityTotal, yoyAccountabilityTotal));
// 集中问题(基于属实 + 基本属实) // 集中问题(基于属实 + 基本属实)
Map.Entry<String, Long> problemEntry = ReportTrendUtil.topBy( List<Map.Entry<String, Long>> problemRankList = ReportTrendUtil.rankBy(
NegativeQueryVo::getProblemSources, NegativeQueryVo::getProblemSources,
currentClosedStats.getVerifiedList(), currentClosedStats.getVerifiedList(),
currentClosedStats.getBasicallyVerifiedList() currentClosedStats.getBasicallyVerifiedList()
); );
overviewSection.setTopProblemProject(problemEntry != null ? problemEntry.getKey() : null); List<Map.Entry<String, Long>> problemRankListTop3 = problemRankList.stream().limit(3).toList();
String topProblemProject = "";
for (Map.Entry<String, Long> stringLongEntry : problemRankListTop3) {
topProblemProject += stringLongEntry.getKey() +"、";
}
if (StrUtil.isNotBlank(topProblemProject)) {
topProblemProject = StrUtil.removeSuffix(topProblemProject, "、");
}
// 重点关注单位(基于属实 + 基本属实) // 重点关注单位(基于属实 + 基本属实)
Map.Entry<String, Long> departEntry = ReportTrendUtil.topBy(NegativeQueryVo::getInvolveDepartName, List<Map.Entry<String, Long>> departRankList = ReportTrendUtil.rankBy(
NegativeQueryVo::getSecondInvolveDepartId,
currentClosedStats.getVerifiedList(), currentClosedStats.getVerifiedList(),
currentClosedStats.getBasicallyVerifiedList() currentClosedStats.getBasicallyVerifiedList()
); );
overviewSection.setTopProblemUnit(departEntry != null ? departEntry.getKey() : null); Map<String, String> allSecondDepartNameMap = supDepartResourceService.getAllSecondDepartNameMap();
List<Map.Entry<String, Long>> departRankListTop3 = departRankList.stream().limit(3).toList();
String topProblemUnit = "";
for (Map.Entry<String, Long> stringLongEntry : departRankListTop3) {
String departName = allSecondDepartNameMap.get(stringLongEntry.getKey());
if (StrUtil.isNotBlank(departName)) {
topProblemUnit += departName + "、";
}
}
if (StrUtil.isNotBlank(topProblemUnit)) {
topProblemUnit = StrUtil.removeSuffix(topProblemUnit, "、");
}
overviewSection.setTopProblemProject(topProblemProject);
overviewSection.setTopProblemUnit(topProblemUnit);
log.info("总览数据计算结束======================================================================================="); log.info("总览数据计算结束=======================================================================================");
return overviewSection; return overviewSection;
} }
@ -183,9 +219,10 @@ public class ReportOverviewSectionServiceImpl implements ReportOverviewSectionSe
/** /**
* 统一计算问责统计 * 统一计算问责统计
*/ */
private ReportAccountabilityStatsResponseDTO calculateAccountabilityStats(List<NegativeQueryVo> list) { private ReportAccountabilityStatsResponseDTO calculateAccountabilityStats(List<NegativeQueryVo> list, ReportOverviewSectionRequestDTO reportOverviewSectionRequestDTO) {
ReportAccountabilityStatsRequestDTO requestDTO = new ReportAccountabilityStatsRequestDTO(); ReportAccountabilityStatsRequestDTO requestDTO = new ReportAccountabilityStatsRequestDTO();
requestDTO.setNegativeQueryVoList(list); requestDTO.setNegativeQueryVoList(list);
requestDTO.setCurrentUser(reportOverviewSectionRequestDTO.getNegativeQueryParam().getCurrentUser());
return reportAccountabilityStatsService.calculateAccountabilityStats(requestDTO); return reportAccountabilityStatsService.calculateAccountabilityStats(requestDTO);
} }

102
src/main/java/com/biutag/supervision/service/report/impl/ReportProblemTypeStatsServiceImpl.java

@ -0,0 +1,102 @@
package com.biutag.supervision.service.report.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.biutag.supervision.constants.enums.ProcessingStatusEnum;
import com.biutag.supervision.pojo.dto.report.accountability.ReportAccountabilityStatsResponseDTO;
import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineRankItem;
import com.biutag.supervision.pojo.dto.report.problemType.ReportProblemTypeStatsRequestDTO;
import com.biutag.supervision.pojo.dto.report.problemType.ReportProblemTypeStatsResponseDTO;
import com.biutag.supervision.pojo.entity.NegativeProblemRelation;
import com.biutag.supervision.pojo.vo.NegativeQueryVo;
import com.biutag.supervision.service.NegativeProblemRelationService;
import com.biutag.supervision.service.report.ReportProblemTypeStatsService;
import com.biutag.supervision.util.ReportTrendUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* @ClassName ReportProblemTypeStatsServiceImpl
* @Description ReportProblemTypeStatsServiceImpl
* @Author shihao
* @Date 2026/3/11 14:37
*/
@Service
@Slf4j
public class ReportProblemTypeStatsServiceImpl implements ReportProblemTypeStatsService {
@Resource
private NegativeProblemRelationService negativeProblemRelationService;
@Override
public ReportProblemTypeStatsResponseDTO calculateProblemTypeStats(ReportProblemTypeStatsRequestDTO requestDTO) {
ReportProblemTypeStatsResponseDTO responseDTO = new ReportProblemTypeStatsResponseDTO();
if (requestDTO == null || CollUtil.isEmpty(requestDTO.getNegativeQueryVoList())) {
return responseDTO;
}
// 1. 过滤办结问题
List<NegativeQueryVo> closedNegativeList = requestDTO.getNegativeQueryVoList().stream()
.filter(one -> ProcessingStatusEnum.completed.name().equals(one.getProcessingStatus()))
.toList();
if (CollUtil.isEmpty(closedNegativeList)) {
return responseDTO;
}
// 2. 查询问题类型关联数据
Set<String> negativeIds = closedNegativeList.stream()
.map(NegativeQueryVo::getId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toSet());
List<NegativeProblemRelation> relationList = negativeProblemRelationService.list(negativeIds);
if (CollUtil.isEmpty(relationList)) {
return responseDTO;
}
// 3. 按问题ID去重,每个问题只保留一条问题类型记录
List<NegativeProblemRelation> distinctRelationList = relationList.stream()
.collect(Collectors.collectingAndThen(
Collectors.toMap(
NegativeProblemRelation::getNegativeId,
relation -> relation,
(first, second) -> first
),
map -> new ArrayList<>(map.values())
));
// 4. 按问题类型分组统计数量
Map<String, Long> problemTypeCountMap = distinctRelationList.stream()
.collect(Collectors.groupingBy(
this::buildProblemTypeName,
Collectors.counting()
));
// 5. 取TOP3
AtomicInteger index = new AtomicInteger(1);
List<BusinessLineRankItem> topProblemTypes = problemTypeCountMap.entrySet().stream()
.sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
.limit(3)
.map(entry -> new BusinessLineRankItem(
index.getAndIncrement(),
entry.getKey(),
entry.getValue().intValue(),
ReportTrendUtil.percent(entry.getValue().intValue(), distinctRelationList.size())
))
.toList();
responseDTO.setTopProblemTypes(topProblemTypes);
return responseDTO;
}
/**
* 构建问题类型展示名称一级-二级-三级
*/
private String buildProblemTypeName(NegativeProblemRelation relation) {
return String.join("/",
Objects.toString(relation.getOneLevelContent(), ""),
Objects.toString(relation.getTwoLevelContent(), ""),
Objects.toString(relation.getThreeLevelContent(), "")
);
}
}

45
src/main/java/com/biutag/supervision/util/ReportTrendUtil.java

@ -107,6 +107,26 @@ public class ReportTrendUtil {
return TrendEnum.STABLE; return TrendEnum.STABLE;
} }
@SafeVarargs
public static <E, T> List<Map.Entry<T, Long>> rankBy(Function<E, T> mapper, List<E>... lists) {
return Arrays.stream(lists)
.filter(Objects::nonNull)
.flatMap(List::stream)
.map(mapper)
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
))
.entrySet()
.stream()
.sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
.toList();
}
@SafeVarargs @SafeVarargs
public static <E, T> Map.Entry<T, Long> topBy(Function<E, T> mapper, List<E>... lists) { public static <E, T> Map.Entry<T, Long> topBy(Function<E, T> mapper, List<E>... lists) {
@ -124,5 +144,30 @@ public class ReportTrendUtil {
.orElse(null); .orElse(null);
} }
/**
* 计算百分比差值
* 例如
* 上月64%本月40%结果=-24.00
*/
public static BigDecimal calcDiff(BigDecimal current, BigDecimal prev) {
if (current == null) {
current = BigDecimal.ZERO;
}
if (prev == null) {
prev = BigDecimal.ZERO;
}
return current.subtract(prev).setScale(2, RoundingMode.HALF_UP);
}
/**
* 计算百分比绝对变化值
* 例如
* 上月64%本月40%结果=24.00
*/
public static BigDecimal calcAbsDiff(BigDecimal current, BigDecimal prev) {
return calcDiff(current, prev).abs().setScale(2, RoundingMode.HALF_UP);
}
} }

BIN
src/main/resources/static/templates/督审一体化平台研判分析报告.docx

Binary file not shown.
Loading…
Cancel
Save