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) {
|
Date initDate = null;
|
|
if (StringUtils.isNotBlank(dateTime)) {
|
initDate = DateUtils.toDate(dateTime, DateUtils.STRDATE);
|
} else {
|
// 取最后的统计时间
|
String date = this.baseMapper.getMaxStaticsData();
|
if (date != null) {
|
initDate = DateUtils.toDate(date, DateUtils.STRDATE);
|
} else {
|
// 初次取值 取最早时间记录
|
MdcEquipmentRunningSection equipmentRunningSection = mdcEquipmentRunningSectionService.getFirstRecord();
|
if (equipmentRunningSection != null) {
|
initDate = equipmentRunningSection.getStartTime();
|
}
|
}
|
}
|
Date endDate = DateUtils.addDays(DateUtils.getNow(), -1);
|
List<String> dateList = DateUtils.getDatesStringList2(initDate, endDate);
|
|
if (dateList.isEmpty()) {
|
return;
|
}
|
try {
|
this.remove(new LambdaQueryWrapper<MdcEquipmentFaultInfo>().in(MdcEquipmentFaultInfo::getTheDate, dateList));
|
} catch (Exception e) {
|
log.error("参数格式不对", e);
|
}
|
|
List<Equipment> equipmentList = equipmentService.list();
|
if (equipmentList == null || equipmentList.isEmpty()) {
|
return;
|
}
|
|
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());
|
|
for (String validDate : dateList) {
|
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 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));
|
map.forEach((key, value1) -> {
|
MdcEquipmentFaultInfo equFaultRecords = value1;
|
if (equFaultRecordMap.containsKey(key)) {
|
List<EquFaultRecord> 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<MdcEquipmentRunningSection> 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<MdcEquipmentRunningSection> 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<MdcEquipmentRunningSection> 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<MdcEquipmentRunningSection> 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<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<EquFaultRecord> correctedRecords = correctRecordTimes(faultRecords, start, end);
|
List<TimeInterval> mergedFaultIntervals = mergeIntervals(correctedRecords);
|
|
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()));
|
}
|
}
|
|
}
|