package com.ruoyi.safe.service.impl; import com.ruoyi.dto.MapDto; import com.ruoyi.safe.dto.SafeChartItemDto; import com.ruoyi.safe.dto.SafeHiddenTypeStatDto; import com.ruoyi.safe.dto.SafeLatestEventDto; import com.ruoyi.safe.dto.SafeOverviewDto; import com.ruoyi.safe.dto.SafeTrendDto; import com.ruoyi.safe.mapper.SafeDashboardMapper; import com.ruoyi.safe.service.SafeDashboardService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; /** * 安全数据驾驶舱服务实现 */ @Service @RequiredArgsConstructor public class SafeDashboardServiceImpl implements SafeDashboardService { private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM"); private static final int TREND_MONTHS = 6; private static final int EVENT_DEFAULT_LIMIT = 10; private static final int HAZARD_RANK_DEFAULT_LIMIT = 8; private static final int RECTIFY_RANK_DEFAULT_LIMIT = 5; private static final int LIMIT_MAX = 20; private final SafeDashboardMapper safeDashboardMapper; @Override public SafeOverviewDto getOverview() { SafeOverviewDto dto = safeDashboardMapper.selectOverview(); return dto == null ? new SafeOverviewDto() : dto; } @Override public List getLatestEvents(Integer limit) { return safeDashboardMapper.selectLatestEvents(normalizeLimit(limit, EVENT_DEFAULT_LIMIT)); } @Override public List getHiddenTypeDistribution() { List stats = safeDashboardMapper.selectHiddenTypeDistribution(); long grandTotal = stats.stream().mapToLong(s -> nvl(s.getTotalCount())).sum(); List result = new ArrayList<>(); for (SafeHiddenTypeStatDto stat : stats) { int total = nvl(stat.getTotalCount()); SafeChartItemDto item = new SafeChartItemDto(); item.setName(stat.getName()); item.setValue(String.valueOf(total)); item.setRate(rate(total, grandTotal)); item.setChildren(Arrays.asList( buildChild("已整改", nvl(stat.getRectifiedCount()), total), buildChild("待整改", nvl(stat.getPendingCount()), total))); result.add(item); } return result; } @Override public List getHiddenTrend() { YearMonth endMonth = YearMonth.now(); YearMonth startMonth = endMonth.minusMonths(TREND_MONTHS - 1L); List rows = safeDashboardMapper.selectHiddenTrend(startMonth.atDay(1)); Map rowMap = rows.stream() .collect(Collectors.toMap(SafeTrendDto::getMonth, Function.identity(), (a, b) -> a)); List result = new ArrayList<>(); for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) { String key = month.format(MONTH_FORMATTER); SafeTrendDto row = rowMap.get(key); if (row == null) { row = new SafeTrendDto(); row.setMonth(key); row.setReportedCount(0); row.setCompletedCount(0); } else { row.setReportedCount(nvl(row.getReportedCount())); row.setCompletedCount(nvl(row.getCompletedCount())); } result.add(row); } return result; } @Override public List getHazardRiskDistribution() { List rows = safeDashboardMapper.selectHazardRiskDistribution(); long total = rows.stream().mapToLong(row -> parseCount(row.getValue())).sum(); rows.forEach(row -> row.setRate(rate(parseCount(row.getValue()), total))); return rows; } @Override public List getHazardTypeRanking(Integer limit) { List rows = safeDashboardMapper.selectHazardTypeRanking(); long total = rows.stream().mapToLong(row -> parseCount(row.getValue())).sum(); rows.forEach(row -> row.setRate(rate(parseCount(row.getValue()), total))); return truncate(rows, normalizeLimit(limit, HAZARD_RANK_DEFAULT_LIMIT)); } @Override public List getHiddenRectifyRanking(Integer limit) { List rows = safeDashboardMapper.selectHiddenRectifyRanking(); long total = rows.stream().mapToLong(row -> parseCount(row.getValue())).sum(); List result = new ArrayList<>(); for (MapDto row : rows) { row.setRate(rate(parseCount(row.getValue()), total)); if (!"未指派".equals(row.getName())) { result.add(row); } } return truncate(result, normalizeLimit(limit, RECTIFY_RANK_DEFAULT_LIMIT)); } private SafeChartItemDto buildChild(String name, int value, int parentTotal) { SafeChartItemDto child = new SafeChartItemDto(); child.setName(name); child.setValue(String.valueOf(value)); child.setRate(rate(value, parentTotal)); return child; } private List truncate(List rows, int limit) { return rows.size() > limit ? new ArrayList<>(rows.subList(0, limit)) : rows; } private int normalizeLimit(Integer limit, int defaultValue) { if (limit == null || limit < 1) { return defaultValue; } return Math.min(limit, LIMIT_MAX); } private int nvl(Integer value) { return value == null ? 0 : value; } private long parseCount(String value) { if (value == null || value.isBlank()) { return 0L; } try { return Long.parseLong(value.trim()); } catch (NumberFormatException e) { return 0L; } } private String rate(long part, long total) { if (total <= 0) { return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP).toPlainString(); } return BigDecimal.valueOf(part) .multiply(BigDecimal.valueOf(100)) .divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP) .toPlainString(); } }