|
@@ -0,0 +1,186 @@
|
|
|
+package org.eco.vip.reliability.ser.service.config;
|
|
|
+
|
|
|
+import org.eco.vip.reliability.ser.domain.configuration.FaultPO;
|
|
|
+import org.eco.vip.reliability.ser.domain.configuration.pojo.MonitorTableVO;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Author: wyj
|
|
|
+ * @CreateTime: 2025-08-07
|
|
|
+ * @Belongpackage org.eco.vip.reliability.ser.service.config
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class calculateServiceImpl {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成故障监控表格数据(飞机/系统/部件的故障率统计)
|
|
|
+ * @param faultList 故障数据列表(实体类集合)
|
|
|
+ * @return 监控表格数据列表
|
|
|
+ */
|
|
|
+ public List<MonitorTableVO> generateFaultMonitorTable(List<FaultPO> faultList) {
|
|
|
+ // 1. 校验输入
|
|
|
+ if (faultList == null || faultList.isEmpty()) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 确定时间范围(n月、n-1月、n-2月)
|
|
|
+ Map<String, String> monthRange = getMonthRange();
|
|
|
+ String nMonth = monthRange.get("nMonth");
|
|
|
+ String n1Month = monthRange.get("n1Month");
|
|
|
+ String n2Month = monthRange.get("n2Month");
|
|
|
+
|
|
|
+ // 3. 按监控项目和月份统计故障数量
|
|
|
+ Map<String, Map<String, Long>> itemMonthCount =inCount(faultList, n2Month, n1Month, nMonth);
|
|
|
+
|
|
|
+ // 4. 获取各月飞行时间(实际应从团级数据库查询,此处为示例)
|
|
|
+ Map<String, Double> flightTimeMap = getMonthlyFlightTime(n2Month, n1Month, nMonth);
|
|
|
+
|
|
|
+ // 5. 计算表格数据
|
|
|
+ return buildMonitorTable(itemMonthCount, flightTimeMap, n2Month, n1Month, nMonth);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取n月、n-1月、n-2月的年月字符串(格式:yyyy-MM)
|
|
|
+ */
|
|
|
+ private Map<String, String> getMonthRange() {
|
|
|
+ LocalDate now = LocalDate.now();
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
|
|
|
+ return new HashMap<String, String>() {{
|
|
|
+ put("nMonth", now.format(formatter));
|
|
|
+ put("n1Month", now.minusMonths(1).format(formatter));
|
|
|
+ put("n2Month", now.minusMonths(2).format(formatter));
|
|
|
+ }};
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统计各监控项目在指定月份的故障数量
|
|
|
+ */
|
|
|
+ private Map<String, Map<String, Long>> inCount(List<FaultPO> faultList, String n2Month, String n1Month, String nMonth) {
|
|
|
+ // 初始化三个监控项目的月份计数
|
|
|
+ Map<String, Map<String, Long>> itemMonthCount = new HashMap<>();
|
|
|
+ List<String> monitorItems = Arrays.asList("飞机", "系统", "部件");
|
|
|
+ monitorItems.forEach(item -> {
|
|
|
+ itemMonthCount.put(item, new HashMap<String, Long>() {{
|
|
|
+ put(n2Month, 0L);
|
|
|
+ put(n1Month, 0L);
|
|
|
+ put(nMonth, 0L);
|
|
|
+ }});
|
|
|
+ });
|
|
|
+
|
|
|
+ // 遍历故障数据统计数量
|
|
|
+ for (FaultPO fault : faultList) {
|
|
|
+ // 转换故障日期为年月格式
|
|
|
+ String dataMonth = convertDateToMonth(fault.getStatisticsDate());
|
|
|
+ if (dataMonth == null) continue; // 跳过日期无效的数据
|
|
|
+
|
|
|
+ // 1. 统计"飞机"维度(所有故障均计入)
|
|
|
+ if (Arrays.asList(n2Month, n1Month, nMonth).contains(dataMonth)) {
|
|
|
+ itemMonthCount.get("飞机").put(dataMonth,
|
|
|
+ itemMonthCount.get("飞机").get(dataMonth) + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 统计"系统"维度(仅包含有系统信息的故障)
|
|
|
+ if (hasText(fault.getSystems()) && Arrays.asList(n2Month, n1Month, nMonth).contains(dataMonth)) {
|
|
|
+ itemMonthCount.get("系统").put(dataMonth,
|
|
|
+ itemMonthCount.get("系统").get(dataMonth) + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 统计"部件"维度(仅包含有机件信息的故障)
|
|
|
+ if ((hasText(fault.getMachineType()) || hasText(fault.getMachineName()))
|
|
|
+ && Arrays.asList(n2Month, n1Month, nMonth).contains(dataMonth)) {
|
|
|
+ itemMonthCount.get("部件").put(dataMonth,
|
|
|
+ itemMonthCount.get("部件").get(dataMonth) + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return itemMonthCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取各月飞行时间(实际应对接团级数据库,此处为模拟)
|
|
|
+ */
|
|
|
+ private Map<String, Double> getMonthlyFlightTime(String... months) {
|
|
|
+ // 模拟从团级数据库查询每月飞行时间(单位:小时)
|
|
|
+ Map<String, Double> flightTimeMap = new HashMap<>();
|
|
|
+ for (String month : months) {
|
|
|
+ // 实际逻辑:调用接口查询该月的飞行时间总和
|
|
|
+ flightTimeMap.put(month, 1500.0); // 示例值
|
|
|
+ }
|
|
|
+ return flightTimeMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建监控表格数据(计算故障率、平均值、UCL等)
|
|
|
+ */
|
|
|
+ private List<MonitorTableVO> buildMonitorTable(
|
|
|
+ Map<String, Map<String, Long>> itemMonthCount,
|
|
|
+ Map<String, Double> flightTimeMap,
|
|
|
+ String n2Month, String n1Month, String nMonth) {
|
|
|
+
|
|
|
+ List<MonitorTableVO> result = new ArrayList<>();
|
|
|
+ int serialNumber = 1;
|
|
|
+
|
|
|
+ // 遍历三个监控项目
|
|
|
+ for (String item : Arrays.asList("飞机", "系统", "部件")) {
|
|
|
+ MonitorTableVO vo = new MonitorTableVO();
|
|
|
+ vo.setSerialNumber(serialNumber++);
|
|
|
+ vo.setMonitorItem(item);
|
|
|
+
|
|
|
+ // 获取该项目三个月的故障数量
|
|
|
+ Long n2Count = itemMonthCount.get(item).get(n2Month);
|
|
|
+ Long n1Count = itemMonthCount.get(item).get(n1Month);
|
|
|
+ Long nCount = itemMonthCount.get(item).get(nMonth);
|
|
|
+
|
|
|
+ // 获取三个月的飞行时间
|
|
|
+ double n2Flight = flightTimeMap.getOrDefault(n2Month, 0.0);
|
|
|
+ double n1Flight = flightTimeMap.getOrDefault(n1Month, 0.0);
|
|
|
+ double nFlight = flightTimeMap.getOrDefault(nMonth, 0.0);
|
|
|
+
|
|
|
+ // 计算各月故障率(故障数/飞行时间,避免除0)
|
|
|
+ vo.setN2MonthRate(calculateRate(n2Count, n2Flight));
|
|
|
+ vo.setN1MonthRate(calculateRate(n1Count, n1Flight));
|
|
|
+ vo.setNMonthRate(calculateRate(nCount, nFlight));
|
|
|
+
|
|
|
+ // 计算近三个月平均值
|
|
|
+ vo.setAverage(calculateAverage(vo.getN2MonthRate(), vo.getN1MonthRate(), vo.getNMonthRate()));
|
|
|
+ // 设置k值(实际应从配置获取,此处为示例)
|
|
|
+ vo.setK(2.0);
|
|
|
+ // 计算UCL警戒值(平均值 + k*标准差)
|
|
|
+ double std = calculateStd(vo.getN2MonthRate(), vo.getN1MonthRate(), vo.getNMonthRate());
|
|
|
+ vo.setUcl(vo.getAverage() + vo.getK() * std);
|
|
|
+ // 确定警告状态(当前月故障率 > UCL则警告)
|
|
|
+ vo.setWarningStatus(vo.getNMonthRate() > vo.getUcl() ? "警告" : "正常");
|
|
|
+ result.add(vo);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private double calculateRate(Long count, double flightTime) {
|
|
|
+ return flightTime == 0 ? 0 : count / flightTime;
|
|
|
+ }
|
|
|
+
|
|
|
+ private double calculateAverage(double... values) {
|
|
|
+ return Arrays.stream(values).average().orElse(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ private double calculateStd(double a, double b, double c) {
|
|
|
+ double avg = calculateAverage(a, b, c);
|
|
|
+ double sumPow = Math.pow(a - avg, 2) + Math.pow(b - avg, 2) + Math.pow(c - avg, 2);
|
|
|
+ return Math.sqrt(sumPow / 3);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String convertDateToMonth(Date date) {
|
|
|
+ if (date == null) return null;
|
|
|
+ LocalDate localDate = LocalDate.ofInstant(date.toInstant(), ZoneId.systemDefault());
|
|
|
+ return localDate.format(DateTimeFormatter.ofPattern("yyyy-MM"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean hasText(String str) {
|
|
|
+ return str != null && !str.trim().isEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
+}
|