|
|
@@ -1,111 +1,148 @@
|
|
1
|
1
|
package com.water.data_engine.service;
|
|
2
|
2
|
|
|
3
|
|
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
4
|
|
-import com.water.data_engine.entity.DataReport;
|
|
5
|
|
-import com.water.data_engine.entity.ReportTemplate;
|
|
6
|
|
-import com.water.data_engine.mapper.DataReportMapper;
|
|
7
|
|
-import com.water.data_engine.mapper.ReportTemplateMapper;
|
|
8
|
|
-import lombok.RequiredArgsConstructor;
|
|
|
3
|
+import com.water.data_engine.mapper.CleaningTaskMapper;
|
|
|
4
|
+import com.water.data_engine.mapper.QualityScoreMapper;
|
|
|
5
|
+import com.water.data_engine.model.CleaningTask;
|
|
|
6
|
+import com.water.data_engine.model.QualityScore;
|
|
|
7
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
9
|
8
|
import org.springframework.stereotype.Service;
|
|
10
|
9
|
|
|
11
|
|
-import java.time.LocalDate;
|
|
12
|
10
|
import java.time.LocalDateTime;
|
|
13
|
|
-import java.util.*;
|
|
|
11
|
+import java.util.HashMap;
|
|
|
12
|
+import java.util.List;
|
|
|
13
|
+import java.util.Map;
|
|
14
|
14
|
|
|
|
15
|
+/**
|
|
|
16
|
+ * 报表生成服务
|
|
|
17
|
+ */
|
|
15
|
18
|
@Service
|
|
16
|
|
-@RequiredArgsConstructor
|
|
17
|
19
|
public class ReportService {
|
|
18
|
20
|
|
|
19
|
|
- private final DataReportMapper reportMapper;
|
|
20
|
|
- private final ReportTemplateMapper templateMapper;
|
|
|
21
|
+ @Autowired
|
|
|
22
|
+ private CleaningTaskMapper cleaningTaskMapper;
|
|
|
23
|
+
|
|
|
24
|
+ @Autowired
|
|
|
25
|
+ private QualityScoreMapper qualityScoreMapper;
|
|
21
|
26
|
|
|
22
|
27
|
/**
|
|
23
|
|
- * 自动生成报表
|
|
|
28
|
+ * 生成水质报表
|
|
24
|
29
|
*/
|
|
25
|
|
- public DataReport generateReport(String reportType, String period) {
|
|
26
|
|
- DataReport report = new DataReport();
|
|
27
|
|
- report.setReportNo("RPT-" + System.currentTimeMillis());
|
|
28
|
|
- report.setReportType(reportType); // daily/weekly/monthly/yearly
|
|
29
|
|
- report.setPeriod(period);
|
|
30
|
|
- report.setTitle(reportType + " 报表 " + period);
|
|
31
|
|
-
|
|
32
|
|
- // Generate content based on type
|
|
33
|
|
- Map<String, Object> content = new LinkedHashMap<>();
|
|
34
|
|
- content.put("generatedAt", LocalDateTime.now());
|
|
|
30
|
+ public Map<String, Object> generateQualityReport(String period) {
|
|
|
31
|
+ Map<String, Object> content = new HashMap<>();
|
|
|
32
|
+ content.put("reportType", "water_quality");
|
|
35
|
33
|
content.put("period", period);
|
|
36
|
34
|
|
|
37
|
|
- switch (reportType) {
|
|
38
|
|
- case "daily" -> {
|
|
39
|
|
- content.put("totalSupply", 12500.0 + Math.random() * 2000);
|
|
40
|
|
- content.put("totalConsumption", 11000.0 + Math.random() * 1500);
|
|
41
|
|
- content.put("alertCount", (int)(Math.random() * 10));
|
|
42
|
|
- content.put("waterQualityRate", 98.5 + Math.random() * 1.5);
|
|
43
|
|
- }
|
|
44
|
|
- case "weekly" -> {
|
|
45
|
|
- content.put("avgDailySupply", 12000.0 + Math.random() * 1000);
|
|
46
|
|
- content.put("peakDay", "周三");
|
|
47
|
|
- content.put("totalAlerts", (int)(Math.random() * 50));
|
|
48
|
|
- content.put("avgQualityRate", 98.0 + Math.random() * 2.0);
|
|
49
|
|
- }
|
|
50
|
|
- case "monthly" -> {
|
|
51
|
|
- content.put("totalSupply", 380000.0 + Math.random() * 50000);
|
|
52
|
|
- content.put("totalConsumption", 350000.0 + Math.random() * 40000);
|
|
53
|
|
- content.put("leakageRate", 8.0 + Math.random() * 4);
|
|
54
|
|
- content.put("complaints", (int)(Math.random() * 30));
|
|
55
|
|
- }
|
|
56
|
|
- case "yearly" -> {
|
|
57
|
|
- content.put("totalSupply", 4500000.0 + Math.random() * 500000);
|
|
58
|
|
- content.put("yoyGrowth", -5.0 + Math.random() * 15);
|
|
59
|
|
- content.put("infrastructureInvestment", 2500000.0);
|
|
60
|
|
- content.put("serviceCoverage", 95.0 + Math.random() * 5);
|
|
61
|
|
- }
|
|
|
35
|
+ String reportType = period;
|
|
|
36
|
+ if ("daily".equals(reportType)) {
|
|
|
37
|
+ content.put("totalSupply", 12500.0 + Math.random() * 2000);
|
|
|
38
|
+ content.put("totalConsumption", 11000.0 + Math.random() * 1500);
|
|
|
39
|
+ content.put("alertCount", (int)(Math.random() * 10));
|
|
|
40
|
+ content.put("waterQualityRate", 98.5 + Math.random() * 1.5);
|
|
|
41
|
+ } else if ("weekly".equals(reportType)) {
|
|
|
42
|
+ content.put("avgDailySupply", 12000.0 + Math.random() * 1000);
|
|
|
43
|
+ content.put("peakDay", "周三");
|
|
|
44
|
+ content.put("totalAlerts", (int)(Math.random() * 50));
|
|
|
45
|
+ content.put("avgQualityRate", 98.0 + Math.random() * 2.0);
|
|
|
46
|
+ } else if ("monthly".equals(reportType)) {
|
|
|
47
|
+ content.put("totalSupply", 380000.0 + Math.random() * 50000);
|
|
|
48
|
+ content.put("totalConsumption", 350000.0 + Math.random() * 40000);
|
|
|
49
|
+ content.put("leakageRate", 8.0 + Math.random() * 4);
|
|
|
50
|
+ content.put("complaints", (int)(Math.random() * 30));
|
|
|
51
|
+ } else if ("yearly".equals(reportType)) {
|
|
|
52
|
+ content.put("totalSupply", 4500000.0 + Math.random() * 500000);
|
|
|
53
|
+ content.put("yoyGrowth", -5.0 + Math.random() * 15);
|
|
|
54
|
+ content.put("infrastructureInvestment", 2500000.0);
|
|
|
55
|
+ content.put("serviceCoverage", 95.0 + Math.random() * 5);
|
|
62
|
56
|
}
|
|
63
|
|
- report.setContent(content.toString());
|
|
64
|
|
- report.setStatus("GENERATED");
|
|
65
|
|
- report.setCreatedTime(LocalDateTime.now());
|
|
66
|
|
-
|
|
67
|
|
- reportMapper.insert(report);
|
|
68
|
|
- return report;
|
|
|
57
|
+
|
|
|
58
|
+ content.put("generatedAt", LocalDateTime.now());
|
|
|
59
|
+
|
|
|
60
|
+ return content;
|
|
69
|
61
|
}
|
|
70
|
62
|
|
|
71
|
63
|
/**
|
|
72
|
|
- * 获取报表列表
|
|
|
64
|
+ * 生成数据治理报表
|
|
73
|
65
|
*/
|
|
74
|
|
- public List<DataReport> listReports(String reportType, String status) {
|
|
75
|
|
- LambdaQueryWrapper<DataReport> wrapper = new LambdaQueryWrapper<>();
|
|
76
|
|
- if (reportType != null && !reportType.isBlank()) wrapper.eq(DataReport::getReportType, reportType);
|
|
77
|
|
- if (status != null && !status.isBlank()) wrapper.eq(DataReport::getStatus, status);
|
|
78
|
|
- return reportMapper.selectList(wrapper.orderByDesc(DataReport::getCreatedTime));
|
|
79
|
|
- }
|
|
|
66
|
+ public Map<String, Object> generateGovernanceReport(String period) {
|
|
|
67
|
+ Map<String, Object> content = new HashMap<>();
|
|
|
68
|
+ content.put("reportType", "data_governance");
|
|
|
69
|
+ content.put("period", period);
|
|
80
|
70
|
|
|
81
|
|
- /**
|
|
82
|
|
- * 获取报表详情
|
|
83
|
|
- */
|
|
84
|
|
- public DataReport getReport(Long id) {
|
|
85
|
|
- return reportMapper.selectById(id);
|
|
|
71
|
+ // 获取最近的数据清洗任务统计
|
|
|
72
|
+ List<CleaningTask> recentTasks = cleaningTaskMapper.selectRecentTasks(30);
|
|
|
73
|
+
|
|
|
74
|
+ long totalTasks = recentTasks.size();
|
|
|
75
|
+ long completedTasks = recentTasks.stream().filter(task -> "completed".equals(task.getStatus())).count();
|
|
|
76
|
+ long failedTasks = recentTasks.stream().filter(task -> "failed".equals(task.getStatus())).count();
|
|
|
77
|
+
|
|
|
78
|
+ content.put("totalCleaningTasks", totalTasks);
|
|
|
79
|
+ content.put("completedTasks", completedTasks);
|
|
|
80
|
+ content.put("failedTasks", failedTasks);
|
|
|
81
|
+ content.put("successRate", totalTasks > 0 ? (double)completedTasks / totalTasks * 100 : 100.0);
|
|
|
82
|
+
|
|
|
83
|
+ // 获取质量评分统计
|
|
|
84
|
+ List<QualityScore> recentScores = qualityScoreMapper.selectRecentScores(30);
|
|
|
85
|
+
|
|
|
86
|
+ if (!recentScores.isEmpty()) {
|
|
|
87
|
+ double avgScore = recentScores.stream()
|
|
|
88
|
+ .mapToDouble(QualityScore::getScore)
|
|
|
89
|
+ .average()
|
|
|
90
|
+ .orElse(0.0);
|
|
|
91
|
+
|
|
|
92
|
+ content.put("avgQualityScore", avgScore);
|
|
|
93
|
+ content.put("minQualityScore", recentScores.stream()
|
|
|
94
|
+ .mapToDouble(QualityScore::getScore)
|
|
|
95
|
+ .min()
|
|
|
96
|
+ .orElse(0.0));
|
|
|
97
|
+ content.put("maxQualityScore", recentScores.stream()
|
|
|
98
|
+ .mapToDouble(QualityScore::getScore)
|
|
|
99
|
+ .max()
|
|
|
100
|
+ .orElse(0.0));
|
|
|
101
|
+ }
|
|
|
102
|
+
|
|
|
103
|
+ content.put("generatedAt", LocalDateTime.now());
|
|
|
104
|
+ return content;
|
|
86
|
105
|
}
|
|
87
|
106
|
|
|
88
|
107
|
/**
|
|
89
|
|
- * 发布报表
|
|
|
108
|
+ * 生成告警报表
|
|
90
|
109
|
*/
|
|
91
|
|
- public void publishReport(Long id) {
|
|
92
|
|
- DataReport report = reportMapper.selectById(id);
|
|
93
|
|
- if (report == null) throw new RuntimeException("报表不存在");
|
|
94
|
|
- report.setStatus("PUBLISHED");
|
|
95
|
|
- report.setPublishedTime(LocalDateTime.now());
|
|
96
|
|
- reportMapper.updateById(report);
|
|
|
110
|
+ public Map<String, Object> generateAlertReport(String period) {
|
|
|
111
|
+ Map<String, Object> content = new HashMap<>();
|
|
|
112
|
+ content.put("reportType", "alert_report");
|
|
|
113
|
+ content.put("period", period);
|
|
|
114
|
+
|
|
|
115
|
+ // 模拟告警数据
|
|
|
116
|
+ content.put("totalAlerts", (int)(Math.random() * 100));
|
|
|
117
|
+ content.put("criticalAlerts", (int)(Math.random() * 10));
|
|
|
118
|
+ content.put("warningAlerts", (int)(Math.random() * 30));
|
|
|
119
|
+ content.put("infoAlerts", (int)(Math.random() * 60));
|
|
|
120
|
+
|
|
|
121
|
+ content.put("alertsResolved", (int)(Math.random() * 80));
|
|
|
122
|
+ content.put("pendingAlerts", (int)(Math.random() * 20));
|
|
|
123
|
+
|
|
|
124
|
+ content.put("generatedAt", LocalDateTime.now());
|
|
|
125
|
+ return content;
|
|
97
|
126
|
}
|
|
98
|
127
|
|
|
99
|
128
|
/**
|
|
100
|
|
- * 模板管理
|
|
|
129
|
+ * 生成综合报表
|
|
101
|
130
|
*/
|
|
102
|
|
- public List<ReportTemplate> listTemplates() {
|
|
103
|
|
- return templateMapper.selectList(null);
|
|
104
|
|
- }
|
|
|
131
|
+ public Map<String, Object> generateComprehensiveReport(String period) {
|
|
|
132
|
+ Map<String, Object> content = new HashMap<>();
|
|
|
133
|
+ content.put("reportType", "comprehensive");
|
|
|
134
|
+ content.put("period", period);
|
|
|
135
|
+
|
|
|
136
|
+ // 合并所有报表数据
|
|
|
137
|
+ Map<String, Object> qualityData = generateQualityReport(period);
|
|
|
138
|
+ Map<String, Object> governanceData = generateGovernanceReport(period);
|
|
|
139
|
+ Map<String, Object> alertData = generateAlertReport(period);
|
|
105
|
140
|
|
|
106
|
|
- public ReportTemplate createTemplate(ReportTemplate template) {
|
|
107
|
|
- template.setCreatedTime(LocalDateTime.now());
|
|
108
|
|
- templateMapper.insert(template);
|
|
109
|
|
- return template;
|
|
|
141
|
+ content.putAll(qualityData);
|
|
|
142
|
+ content.putAll(governanceData);
|
|
|
143
|
+ content.putAll(alertData);
|
|
|
144
|
+
|
|
|
145
|
+ content.put("generatedAt", LocalDateTime.now());
|
|
|
146
|
+ return content;
|
|
110
|
147
|
}
|
|
111
|
|
-}
|
|
|
148
|
+}
|