package org.jeecg.modules.mdc.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.commons.lang.StringUtils; import org.jeecg.modules.mdc.entity.*; import org.jeecg.modules.mdc.mapper.MdcEquipmentFaultInfoMapper; import org.jeecg.modules.mdc.service.IEquipmentService; import org.jeecg.modules.mdc.service.IMdcEquipmentFaultInfoService; import org.jeecg.modules.mdc.service.IMdcEquipmentRunningSectionService; import org.jeecg.modules.mdc.service.IMdcSystemParametersService; import org.jeecg.modules.mdc.util.DateUtils; import org.jeecg.modules.mdc.vo.EquFaultRecord; import org.jeecg.modules.mdc.vo.TimeInterval; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; /** * @Description: 故障率表 * @Author: Lius * @Date: 2025-06-16 * @Version: V1.0 */ @Service public class MdcEquipmentFaultInfoServiceImpl extends ServiceImpl implements IMdcEquipmentFaultInfoService { @Resource private IEquipmentService equipmentService; @Resource private IMdcSystemParametersService mdcSystemParametersService; @Resource private IMdcEquipmentRunningSectionService mdcEquipmentRunningSectionService; @Override @Transactional(rollbackFor = {Exception.class}) public void runningAllEquFaultStatistical(String dateTime) { String validDate = LocalDate.now().minusDays(1).toString().replaceAll("-", ""); if (StringUtils.isNotBlank(dateTime)) { validDate = DateUtils.format(DateUtils.toDate(dateTime, DateUtils.STRDATE), DateUtils.STRDATE); } try { this.remove(new LambdaQueryWrapper().eq(MdcEquipmentFaultInfo::getTheDate, validDate)); } catch (Exception e) { log.error("参数格式不对", e); } List equipmentList = equipmentService.list(); if (equipmentList == null || equipmentList.isEmpty()) { return; } Map map = new HashMap<>(); String finalValidDate = validDate; equipmentList.forEach(equipment -> { MdcEquipmentFaultInfo mdcEquipmentFaultInfo = new MdcEquipmentFaultInfo(equipment.getEquipmentid(), finalValidDate); map.put(equipment.getEquipmentid(), mdcEquipmentFaultInfo); }); String planTime = "00:00:00"; MdcSystemParameters mdcSystemParameters = mdcSystemParametersService.getOne(new LambdaQueryWrapper().eq(MdcSystemParameters::getCode, "equip_log_statis_time")); if (mdcSystemParameters != null) { planTime = mdcSystemParameters.getValue(); } List equipmentIdList = equipmentList.stream().map(Equipment::getEquipmentid).collect(Collectors.toList()); String startTime = DateUtils.format(DateUtils.setTimeForDay(DateUtils.toDate(validDate, DateUtils.STRDATE), planTime), DateUtils.STR_DATE_TIME_SMALL); Date start = DateUtils.toDate(startTime, DateUtils.STR_DATE_TIME_SMALL); String endTime = DateUtils.format(DateUtils.addDays(DateUtils.toDate(startTime, DateUtils.STR_DATE_TIME_SMALL), 1), DateUtils.STR_DATE_TIME_SMALL); Date end = DateUtils.toDate(endTime, DateUtils.STR_DATE_TIME_SMALL); //查询故障记录 List equFaultRecordList = this.baseMapper.findFaultRecord(equipmentIdList, startTime, endTime); if (equFaultRecordList != null && !equFaultRecordList.isEmpty()) { // 修整时间 Map> equFaultRecordMap = equFaultRecordList.stream().collect(Collectors.groupingBy(EquFaultRecord::getEquipmentId)); map.forEach((key, value1) -> { MdcEquipmentFaultInfo equFaultRecords = value1; if (equFaultRecordMap.containsKey(key)) { List value = equFaultRecordMap.get(key); long faultLong = calculateTotalFaultDuration(value, start, end); equFaultRecords.setFaultLong((int) faultLong); if (faultLong != 0) { equFaultRecords.setFaultRate(new BigDecimal(faultLong).divide(new BigDecimal("864"), 2, RoundingMode.HALF_UP)); } // 计算去除故障时长的加工时间 // step.1 查询加工时间 List mdcEquipmentRunningSections = mdcEquipmentRunningSectionService.listEquipmentRunningSectionRun(key, start.getTime(), end.getTime()); if (mdcEquipmentRunningSections != null && !mdcEquipmentRunningSections.isEmpty()) { // 时间修正 if (mdcEquipmentRunningSections.get(0).getStartTime().before(start)) { mdcEquipmentRunningSections.get(0).setStartTime(start); } if (mdcEquipmentRunningSections.size() > 1) { if (mdcEquipmentRunningSections.get(mdcEquipmentRunningSections.size() - 1).getEndTime().after(end)) { mdcEquipmentRunningSections.get(mdcEquipmentRunningSections.size() - 1).setEndTime(end); } } else { if (mdcEquipmentRunningSections.get(0).getEndTime().after(end)) { mdcEquipmentRunningSections.get(0).setEndTime(end); } } List collect = mdcEquipmentRunningSections.stream().filter(mdcEquipmentRunningSection -> mdcEquipmentRunningSection.getStatus() == 3).collect(Collectors.toList()); if (!collect.isEmpty()) { // step.2 计算去除故障时长的加工时间 long processingTime = calculateProcessingTimeWithoutFaults(collect, value, start, end); equFaultRecords.setRemoveFaultRunLong((int) processingTime); if (faultLong != 0 && faultLong != 86400) { // 计算去除故障时长的利用率 BigDecimal removeFaultRate = new BigDecimal(processingTime).divide(new BigDecimal("864").subtract(new BigDecimal(faultLong)), 2, RoundingMode.HALF_UP); equFaultRecords.setRemoveFaultRate(removeFaultRate); } } } } else { List mdcEquipmentRunningSections = mdcEquipmentRunningSectionService.listEquipmentRunningSectionRun(key, start.getTime(), end.getTime()); if (mdcEquipmentRunningSections != null && !mdcEquipmentRunningSections.isEmpty()) { // 时间修正 if (mdcEquipmentRunningSections.get(0).getStartTime().before(start)) { mdcEquipmentRunningSections.get(0).setStartTime(start); } if (mdcEquipmentRunningSections.size() > 1) { if (mdcEquipmentRunningSections.get(mdcEquipmentRunningSections.size() - 1).getEndTime().after(end)) { mdcEquipmentRunningSections.get(mdcEquipmentRunningSections.size() - 1).setEndTime(end); } } else { if (mdcEquipmentRunningSections.get(0).getEndTime().after(end)) { mdcEquipmentRunningSections.get(0).setEndTime(end); } } List collect = mdcEquipmentRunningSections.stream().filter(mdcEquipmentRunningSection -> mdcEquipmentRunningSection.getStatus() == 3).collect(Collectors.toList()); if (!collect.isEmpty()) { long totalProcessingTime = 0; for (MdcEquipmentRunningSection mdcEquipmentRunningSection : collect) { totalProcessingTime += ChronoUnit.SECONDS.between(DateUtils.convertToLocalDateTime(mdcEquipmentRunningSection.getStartTime()), DateUtils.convertToLocalDateTime(mdcEquipmentRunningSection.getEndTime())); } equFaultRecords.setRemoveFaultRunLong((int) totalProcessingTime); // 计算去除故障时长的利用率 BigDecimal removeFaultRate = new BigDecimal(totalProcessingTime).divide(new BigDecimal("864"), 2, RoundingMode.HALF_UP); equFaultRecords.setRemoveFaultRate(removeFaultRate); } } } map.put(key, equFaultRecords); }); } if (!map.isEmpty()) { this.saveBatch(new ArrayList<>(map.values())); } } public static long calculateTotalFaultDuration(List records, Date startTime, Date endTime) { LocalDateTime start = DateUtils.convertToLocalDateTime(startTime); LocalDateTime end = DateUtils.convertToLocalDateTime(endTime); // 修正记录时间 List correctedRecords = correctRecordTimes(records, start, end); // 按开始时间排序 correctedRecords.sort(Comparator.comparing(EquFaultRecord::getStartTime)); // 合并重叠时间段 List mergedIntervals = mergeIntervals(correctedRecords); // 计算总时长(秒) return mergedIntervals.stream() .mapToLong(interval -> ChronoUnit.SECONDS.between(interval.getStart(), interval.getEnd())) .sum(); } private static List correctRecordTimes(List records, LocalDateTime startTime, LocalDateTime endTime) { return records.stream() .map(record -> { LocalDateTime recordStart = DateUtils.convertToLocalDateTime(record.getStartTime()); LocalDateTime recordEnd = record.getEndTime() != null ? DateUtils.convertToLocalDateTime(record.getEndTime()) : null; // 修正开始时间 LocalDateTime correctedStart = recordStart.isBefore(startTime) ? startTime : recordStart; // 修正结束时间 LocalDateTime correctedEnd = recordEnd == null || recordEnd.isAfter(endTime) ? endTime : recordEnd; // 创建修正后的记录 return new EquFaultRecord( record.getEquipmentId(), DateUtils.convertToDate(correctedStart), DateUtils.convertToDate(correctedEnd) ); }) .collect(Collectors.toList()); } private static List mergeIntervals(List records) { List intervals = records.stream() .map(record -> new TimeInterval( DateUtils.convertToLocalDateTime(record.getStartTime()), DateUtils.convertToLocalDateTime(record.getEndTime()))) .collect(Collectors.toList()); if (intervals.isEmpty()) { return Collections.emptyList(); } List merged = new ArrayList<>(); TimeInterval current = intervals.get(0); for (int i = 1; i < intervals.size(); i++) { TimeInterval next = intervals.get(i); if (next.getStart().isBefore(current.getEnd()) || next.getStart().equals(current.getEnd())) { // 有重叠,合并区间 current.setEnd(current.getEnd().isAfter(next.getEnd()) ? current.getEnd() : next.getEnd()); } else { // 无重叠,添加当前区间并更新当前区间 merged.add(current); current = next; } } merged.add(current); // 添加最后一个区间 return merged; } // 计算去除故障时长后的加工时间 private long calculateProcessingTimeWithoutFaults( List runningSections, List faultRecords, Date startTime, Date endTime) { // 转换为LocalDateTime进行处理 LocalDateTime start = DateUtils.convertToLocalDateTime(startTime); LocalDateTime end = DateUtils.convertToLocalDateTime(endTime); // 修正记录时间 List correctedRecords = correctRecordTimes(faultRecords, start, end); List mergedFaultIntervals = mergeIntervals(correctedRecords); long totalProcessingTime = 0; // 遍历每个加工区间,排除故障时间 for (MdcEquipmentRunningSection section : runningSections) { LocalDateTime sectionStart = DateUtils.convertToLocalDateTime(section.getStartTime()); LocalDateTime sectionEnd = DateUtils.convertToLocalDateTime(section.getEndTime()); // 排除故障时间后的有效加工时间 List validIntervals = excludeFaultsFromSection( new TimeInterval(sectionStart, sectionEnd), mergedFaultIntervals); // 累加有效加工时间(秒) for (TimeInterval interval : validIntervals) { totalProcessingTime += ChronoUnit.SECONDS.between(interval.getStart(), interval.getEnd()); } } return totalProcessingTime; } // 从运行区间中排除故障时间 private List excludeFaultsFromSection( TimeInterval section, List faultIntervals) { List validIntervals = new ArrayList<>(); validIntervals.add(section); // 遍历每个故障区间,从有效区间中扣除 for (TimeInterval fault : faultIntervals) { List newValidIntervals = new ArrayList<>(); for (TimeInterval valid : validIntervals) { // 计算有效区间与故障区间的交集 if (isOverlapping(valid, fault)) { // 分割有效区间 splitInterval(valid, fault, newValidIntervals); } else { // 无交集,保留原有效区间 newValidIntervals.add(valid); } } validIntervals = newValidIntervals; } return validIntervals; } // 判断两个时间区间是否重叠 private boolean isOverlapping(TimeInterval a, TimeInterval b) { return a.getStart().isBefore(b.getEnd()) && b.getStart().isBefore(a.getEnd()); } // 分割区间(扣除重叠部分) private void splitInterval( TimeInterval valid, TimeInterval fault, List result) { // 重叠前的部分 if (valid.getStart().isBefore(fault.getStart())) { result.add(new TimeInterval(valid.getStart(), fault.getStart())); } // 重叠后的部分 if (valid.getEnd().isAfter(fault.getEnd())) { result.add(new TimeInterval(fault.getEnd(), valid.getEnd())); } } }