云
2026-10-26 80eb4f90939402440c7179afe0935069ef85fcf8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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<SafeLatestEventDto> getLatestEvents(Integer limit) {
        return safeDashboardMapper.selectLatestEvents(normalizeLimit(limit, EVENT_DEFAULT_LIMIT));
    }
 
    @Override
    public List<SafeChartItemDto> getHiddenTypeDistribution() {
        List<SafeHiddenTypeStatDto> stats = safeDashboardMapper.selectHiddenTypeDistribution();
        long grandTotal = stats.stream().mapToLong(s -> nvl(s.getTotalCount())).sum();
        List<SafeChartItemDto> 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<SafeTrendDto> getHiddenTrend() {
        YearMonth endMonth = YearMonth.now();
        YearMonth startMonth = endMonth.minusMonths(TREND_MONTHS - 1L);
        List<SafeTrendDto> rows = safeDashboardMapper.selectHiddenTrend(startMonth.atDay(1));
        Map<String, SafeTrendDto> rowMap = rows.stream()
                .collect(Collectors.toMap(SafeTrendDto::getMonth, Function.identity(), (a, b) -> a));
 
        List<SafeTrendDto> 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<MapDto> getHazardRiskDistribution() {
        List<MapDto> 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<MapDto> getHazardTypeRanking(Integer limit) {
        List<MapDto> 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<MapDto> getHiddenRectifyRanking(Integer limit) {
        List<MapDto> rows = safeDashboardMapper.selectHiddenRectifyRanking();
        long total = rows.stream().mapToLong(row -> parseCount(row.getValue())).sum();
        List<MapDto> 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<MapDto> truncate(List<MapDto> 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();
    }
}