Browse Source

研判分析--初步完成step5

master
buaixuexideshitongxue 2 weeks ago
parent
commit
0024b96723
  1. 3
      src/main/java/com/biutag/supervision/mapper/SupDepartMapper.java
  2. 3
      src/main/java/com/biutag/supervision/pojo/dto/report/businessLine/BusinessLineDetailSection.java
  3. 7
      src/main/java/com/biutag/supervision/repository/supdepart/SupDepartResourceService.java
  4. 384
      src/main/java/com/biutag/supervision/service/report/ReportDataServiceImpl.java
  5. 19
      src/main/resources/mapper/SupDepartMapper.xml

3
src/main/java/com/biutag/supervision/mapper/SupDepartMapper.java

@ -66,6 +66,9 @@ public interface SupDepartMapper extends BaseMapper<SupDepart> {
List<DepartAndSubDepartDto> getDepartAndSubDepart(SupDepartGroupParam param);
List<DepartAndSubDepartDto> getDepartAndSubDepartWithoutGroup(SupDepartGroupParam param);
@Select("<script>"
+ "SELECT id as departId, statistics_group_id as groupId FROM sup_depart WHERE id IN "
+ "<foreach item='item' index='index' collection='list' open='(' separator=',' close=')'>"

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

@ -31,6 +31,9 @@ public class BusinessLineDetailSection {
@Schema(description = "下发总数")
private Integer totalIssued;
@Schema(description = "已办结数据数量", example = "1100")
private Integer closedCount;
@Schema(description = "查实总数(属实+基本属实)")
private Integer verifiedTotal;

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

@ -60,7 +60,12 @@ public class SupDepartResourceService extends BaseDAO {
*/
public Map<String, DepartAndSubDepartDto> getDepartAndSubDepart(SupDepartGroupParam param) {
List<DepartAndSubDepartDto> departAndSubDepart = supDepartMapper.getDepartAndSubDepart(param);
List<DepartAndSubDepartDto> departAndSubDepart;
if (Objects.isNull(param.getGroupId())) {
departAndSubDepart = supDepartMapper.getDepartAndSubDepartWithoutGroup(param);
} else {
departAndSubDepart = supDepartMapper.getDepartAndSubDepart(param);
}
for (DepartAndSubDepartDto dto : departAndSubDepart) {
Set<String> childIds = Optional.ofNullable(dto.getChildIdsStr())
.filter(StrUtil::isNotBlank)

384
src/main/java/com/biutag/supervision/service/report/ReportDataServiceImpl.java

@ -16,6 +16,8 @@ import com.biutag.supervision.pojo.dto.report.businessLine.BusinessLineDetailSec
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;
@ -66,6 +68,13 @@ public class ReportDataServiceImpl implements ReportDataService {
@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));
@ -73,12 +82,19 @@ public class ReportDataServiceImpl implements ReportDataService {
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;
@ -255,109 +271,155 @@ public class ReportDataServiceImpl implements ReportDataService {
* @param periodEnd
* @return
*/
private List<BusinessLineDetailSection> buildBusinessLineDetailSections(NegativeQueryParam request, String periodStart, String periodEnd) {
List<BusinessLineDetailSection> list = new ArrayList<>();
// 第一条
BusinessLineDetailSection section1 = new BusinessLineDetailSection();
section1.setOrderNo("一");
section1.setBusinessLineName("执法监督");
section1.setBusinessFatherLineName("执法办案");
section1.setTotalIssued(12);
section1.setVerifiedTotal(8);
section1.setVerifiedRate(new BigDecimal("66.67"));
section1.setAccountabilityTotal(5);
section1.setAccountabilityRate(new BigDecimal("62.50"));
section1.setPersonalAccountabilityCount(3);
section1.setDepartmentAccountabilityCount(2);
section1.setTopProblemTypes(Arrays.asList(
buildRankItem("执法程序问题", 3, "37.50"),
buildRankItem("案件管理问题", 2, "25.00"),
buildRankItem("执法作风问题", 2, "25.00")
));
section1.setTopUnits(Arrays.asList(
buildRankItem("XX派出所", 2, "25.00"),
buildRankItem("XX大队", 2, "25.00"),
buildRankItem("XX中队", 1, "12.50")
));
section1.setTopPersons(Arrays.asList(
buildPersonRankItem("张三", "XX派出所", "民警", 2, "25.00"),
buildPersonRankItem("李四", "XX大队", "辅警", 1, "12.50"),
buildPersonRankItem("王五", "XX中队", "民警", 1, "12.50")
));
section1.setMomRate(new BigDecimal("20.00"));
section1.setMomTrend(TrendEnum.UP);
section1.setYoyRate(new BigDecimal("10.00"));
section1.setYoyTrend(TrendEnum.DOWN);
list.add(section1);
// 第二条
BusinessLineDetailSection section2 = new BusinessLineDetailSection();
section2.setOrderNo("二");
section2.setBusinessLineName("案件管理");
section2.setBusinessFatherLineName("执法办案");
section2.setTotalIssued(9);
section2.setVerifiedTotal(6);
section2.setVerifiedRate(new BigDecimal("66.67"));
section2.setAccountabilityTotal(4);
section2.setAccountabilityRate(new BigDecimal("50.00"));
section2.setPersonalAccountabilityCount(2);
section2.setDepartmentAccountabilityCount(2);
section2.setTopProblemTypes(Arrays.asList(
buildRankItem("案件审核把关不严", 2, "33.33"),
buildRankItem("卷宗管理不规范", 2, "33.33"),
buildRankItem("系统录入不及时", 1, "16.67")
));
section2.setTopUnits(Arrays.asList(
buildRankItem("XX法制大队", 2, "33.33"),
buildRankItem("XX派出所", 1, "16.67"),
buildRankItem("XX治安大队", 1, "16.67")
));
section2.setTopPersons(Arrays.asList(
buildPersonRankItem("赵六", "XX法制大队", "民警", 2, "33.33"),
buildPersonRankItem("孙七", "XX派出所", "民警", 1, "16.67"),
buildPersonRankItem("周八", "XX治安大队", "辅警", 1, "16.67")
));
section2.setMomRate(new BigDecimal("12.50"));
section2.setMomTrend(TrendEnum.DOWN);
section2.setYoyRate(new BigDecimal("8.00"));
section2.setYoyTrend(TrendEnum.UP);
list.add(section2);
// 第三条
BusinessLineDetailSection section3 = new BusinessLineDetailSection();
section3.setOrderNo("三");
section3.setBusinessLineName("作风建设");
section3.setBusinessFatherLineName("队伍管理");
section3.setTotalIssued(7);
section3.setVerifiedTotal(5);
section3.setVerifiedRate(new BigDecimal("71.43"));
section3.setAccountabilityTotal(3);
section3.setAccountabilityRate(new BigDecimal("60.00"));
section3.setPersonalAccountabilityCount(2);
section3.setDepartmentAccountabilityCount(1);
section3.setTopProblemTypes(Arrays.asList(
buildRankItem("纪律作风问题", 2, "40.00"),
buildRankItem("窗口服务问题", 1, "20.00"),
buildRankItem("值班备勤问题", 1, "20.00")
));
section3.setTopUnits(Arrays.asList(
buildRankItem("XX交警大队", 2, "40.00"),
buildRankItem("XX派出所", 1, "20.00"),
buildRankItem("XX巡特警大队", 1, "20.00")
));
section3.setTopPersons(Arrays.asList(
buildPersonRankItem("吴九", "XX交警大队", "民警", 2, "40.00"),
buildPersonRankItem("郑十", "XX派出所", "辅警", 1, "20.00"),
buildPersonRankItem("钱一", "XX巡特警大队", "民警", 1, "20.00")
));
section3.setMomRate(new BigDecimal("0.00"));
section3.setMomTrend(TrendEnum.STABLE);
section3.setYoyRate(new BigDecimal("15.00"));
section3.setYoyTrend(TrendEnum.UP);
list.add(section3);
return list;
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) {
@ -694,4 +756,120 @@ public class ReportDataServiceImpl implements ReportDataService {
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;
}
}

19
src/main/resources/mapper/SupDepartMapper.xml

@ -13,4 +13,23 @@
GROUP BY parent.id, parent.name
</select>
<select id="getDepartAndSubDepartWithoutGroup"
resultType="com.biutag.supervision.pojo.dto.DepartAndSubDepartDto">
SELECT
parent.id AS parentId,
parent.short_name AS parentName,
GROUP_CONCAT(child.id) AS childIdsStr
FROM sup_depart parent
LEFT JOIN sup_depart child
ON child.pid = parent.id
AND child.level = #{childLevel}
WHERE parent.level = #{parentLevel}
GROUP BY parent.id, parent.name
</select>
</mapper>

Loading…
Cancel
Save