cuilei
2025-06-17 b5d02520af582a86aa95d7903558a5bf50a77aa7
lxzn-module-mdc/src/main/java/org/jeecg/modules/mdc/service/impl/MdcEquipmentFaultInfoServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,298 @@
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<MdcEquipmentFaultInfoMapper, MdcEquipmentFaultInfo> 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<MdcEquipmentFaultInfo>().eq(MdcEquipmentFaultInfo::getTheDate, validDate));
        } catch (Exception e) {
            log.error("参数格式不对", e);
        }
        List<Equipment> equipmentList = equipmentService.list();
        if (equipmentList == null || equipmentList.isEmpty()) {
            return;
        }
        Map<String, MdcEquipmentFaultInfo> 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<MdcSystemParameters>().eq(MdcSystemParameters::getCode, "equip_log_statis_time"));
        if (mdcSystemParameters != null) {
            planTime = mdcSystemParameters.getValue();
        }
        List<String> 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<EquFaultRecord> equFaultRecordList = this.baseMapper.findFaultRecord(equipmentIdList, startTime, endTime);
        if (equFaultRecordList != null && !equFaultRecordList.isEmpty()) {
            // ä¿®æ•´æ—¶é—´
            Map<String, List<EquFaultRecord>> equFaultRecordMap = equFaultRecordList.stream().collect(Collectors.groupingBy(EquFaultRecord::getEquipmentId));
            equFaultRecordMap.forEach((key, value) -> {
                if (map.containsKey(key)) {
                    MdcEquipmentFaultInfo equFaultRecords = map.get(key);
                    long faultLong = calculateTotalFaultDuration(value, start, end);
                    equFaultRecords.setFaultLong((int) faultLong);
                    if (faultLong != 0) {
                        equFaultRecords.setFaultRate(new BigDecimal(faultLong).divide(new BigDecimal("86400"), 2, RoundingMode.HALF_UP));
                    }
                    // è®¡ç®—去除故障时长的加工时间
                    // step.1 æŸ¥è¯¢åŠ å·¥æ—¶é—´
                    List<MdcEquipmentRunningSection> mdcEquipmentRunningSections = mdcEquipmentRunningSectionService.selectRunningData(key, start, end);
                    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);
                            }
                        }
                        // step.2 è®¡ç®—去除故障时长的加工时间
                        long processingTime = calculateProcessingTimeWithoutFaults(mdcEquipmentRunningSections, value, start, end);
                        equFaultRecords.setRemoveFaultRunLong((int) processingTime);
                        if (faultLong != 0) {
                            // è®¡ç®—去除故障时长的利用率
                            BigDecimal removeFaultRate = new BigDecimal(processingTime).divide(new BigDecimal("86400").subtract(new BigDecimal(faultLong)), 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<EquFaultRecord> records, Date startTime, Date endTime) {
        LocalDateTime start = DateUtils.convertToLocalDateTime(startTime);
        LocalDateTime end = DateUtils.convertToLocalDateTime(endTime);
        // ä¿®æ­£è®°å½•æ—¶é—´
        List<EquFaultRecord> correctedRecords = correctRecordTimes(records, start, end);
        // æŒ‰å¼€å§‹æ—¶é—´æŽ’序
        correctedRecords.sort(Comparator.comparing(EquFaultRecord::getStartTime));
        // åˆå¹¶é‡å æ—¶é—´æ®µ
        List<TimeInterval> mergedIntervals = mergeIntervals(correctedRecords);
        // è®¡ç®—总时长(秒)
        return mergedIntervals.stream()
                .mapToLong(interval -> ChronoUnit.SECONDS.between(interval.getStart(), interval.getEnd()))
                .sum();
    }
    private static List<EquFaultRecord> correctRecordTimes(List<EquFaultRecord> 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<TimeInterval> mergeIntervals(List<EquFaultRecord> records) {
        List<TimeInterval> 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<TimeInterval> 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<MdcEquipmentRunningSection> runningSections,
            List<EquFaultRecord> faultRecords,
            Date startTime,
            Date endTime) {
        // è½¬æ¢ä¸ºLocalDateTime进行处理
        LocalDateTime start = DateUtils.convertToLocalDateTime(startTime);
        LocalDateTime end = DateUtils.convertToLocalDateTime(endTime);
        // å°†æ•…障记录转换为时间区间并合并重叠部分
//        List<TimeInterval> faultIntervals = faultRecords.stream()
//                .map(record -> new TimeInterval(
//                        convertToLocalDateTime(record.getStartTime()),
//                        convertToLocalDateTime(record.getEndTime())))
//                .collect(Collectors.toList());
        List<TimeInterval> mergedFaultIntervals = mergeIntervals(faultRecords);
        long totalProcessingTime = 0;
        // éåŽ†æ¯ä¸ªåŠ å·¥åŒºé—´ï¼ŒæŽ’é™¤æ•…éšœæ—¶é—´
        for (MdcEquipmentRunningSection section : runningSections) {
            LocalDateTime sectionStart = DateUtils.convertToLocalDateTime(section.getStartTime());
            LocalDateTime sectionEnd = DateUtils.convertToLocalDateTime(section.getEndTime());
            // æŽ’除故障时间后的有效加工时间
            List<TimeInterval> validIntervals = excludeFaultsFromSection(
                    new TimeInterval(sectionStart, sectionEnd),
                    mergedFaultIntervals);
            // ç´¯åŠ æœ‰æ•ˆåŠ å·¥æ—¶é—´ï¼ˆç§’ï¼‰
            for (TimeInterval interval : validIntervals) {
                totalProcessingTime += ChronoUnit.SECONDS.between(interval.getStart(), interval.getEnd());
            }
        }
        return totalProcessingTime;
    }
    // ä»Žè¿è¡ŒåŒºé—´ä¸­æŽ’除故障时间
    private List<TimeInterval> excludeFaultsFromSection(
            TimeInterval section,
            List<TimeInterval> faultIntervals) {
        List<TimeInterval> validIntervals = new ArrayList<>();
        validIntervals.add(section);
        // éåŽ†æ¯ä¸ªæ•…éšœåŒºé—´ï¼Œä»Žæœ‰æ•ˆåŒºé—´ä¸­æ‰£é™¤
        for (TimeInterval fault : faultIntervals) {
            List<TimeInterval> 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<TimeInterval> 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()));
        }
    }
}