package cn.iocoder.yudao.module.mes.service.dv.statistics;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.module.mes.controller.admin.dv.statistics.vo.MesDvMachineryStatisticsRespVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.dv.borrow.MesDvBorrowDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.dv.checkrecord.MesDvCheckRecordDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryTypeDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.dv.maintenrecord.MesDvMaintenRecordDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.dv.repair.MesDvRepairDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.dv.borrow.MesDvBorrowMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.dv.checkrecord.MesDvCheckRecordMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.dv.maintenrecord.MesDvMaintenRecordMapper;
|
import cn.iocoder.yudao.module.mes.dal.mysql.dv.repair.MesDvRepairMapper;
|
import cn.iocoder.yudao.module.mes.service.dv.machinery.MesDvMachineryService;
|
import cn.iocoder.yudao.module.mes.service.dv.machinery.MesDvMachineryTypeService;
|
import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkshopService;
|
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.time.Duration;
|
import java.time.LocalDateTime;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
|
/**
|
* MES 设备统计分析 Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesDvStatisticsServiceImpl implements MesDvStatisticsService {
|
|
private static final BigDecimal MINUTES_PER_HOUR = BigDecimal.valueOf(60);
|
|
@Resource
|
private MesDvMachineryService machineryService;
|
@Resource
|
private MesDvMachineryTypeService machineryTypeService;
|
@Resource
|
private MesMdWorkshopService workshopService;
|
@Resource
|
private MesProProcessService processService;
|
@Resource
|
private MesDvRepairMapper repairMapper;
|
@Resource
|
private MesDvCheckRecordMapper checkRecordMapper;
|
@Resource
|
private MesDvMaintenRecordMapper maintenRecordMapper;
|
@Resource
|
private MesDvBorrowMapper borrowMapper;
|
|
@Override
|
public List<MesDvMachineryStatisticsRespVO> getMachineryStatistics(LocalDateTime beginTime,
|
LocalDateTime endTime,
|
Long machineryId) {
|
// 1. 查询设备
|
List<MesDvMachineryDO> machineryList = machineryService.getMachineryList();
|
if (machineryId != null) {
|
machineryList = machineryList.stream()
|
.filter(m -> Objects.equals(m.getId(), machineryId)).collect(Collectors.toList());
|
}
|
if (CollUtil.isEmpty(machineryList)) {
|
return Collections.emptyList();
|
}
|
Set<Long> machineryIds = convertSet(machineryList, MesDvMachineryDO::getId);
|
|
// 2. 查询区间内各类单据
|
List<MesDvRepairDO> repairList = repairMapper.selectList(
|
new LambdaQueryWrapperX<MesDvRepairDO>()
|
.in(MesDvRepairDO::getMachineryId, machineryIds)
|
.betweenIfPresent(MesDvRepairDO::getRequireDate, beginTime, endTime));
|
List<MesDvCheckRecordDO> checkRecordList = checkRecordMapper.selectList(
|
new LambdaQueryWrapperX<MesDvCheckRecordDO>()
|
.in(MesDvCheckRecordDO::getMachineryId, machineryIds)
|
.betweenIfPresent(MesDvCheckRecordDO::getCheckTime, beginTime, endTime));
|
List<MesDvMaintenRecordDO> maintenRecordList = maintenRecordMapper.selectList(
|
new LambdaQueryWrapperX<MesDvMaintenRecordDO>()
|
.in(MesDvMaintenRecordDO::getMachineryId, machineryIds)
|
.betweenIfPresent(MesDvMaintenRecordDO::getMaintenTime, beginTime, endTime));
|
List<MesDvBorrowDO> borrowList = borrowMapper.selectList(
|
new LambdaQueryWrapperX<MesDvBorrowDO>()
|
.in(MesDvBorrowDO::getMachineryId, machineryIds)
|
.betweenIfPresent(MesDvBorrowDO::getBorrowTime, beginTime, endTime));
|
|
Map<Long, List<MesDvRepairDO>> repairMap = repairList.stream()
|
.collect(Collectors.groupingBy(MesDvRepairDO::getMachineryId));
|
Map<Long, Long> checkCountMap = checkRecordList.stream()
|
.collect(Collectors.groupingBy(MesDvCheckRecordDO::getMachineryId, Collectors.counting()));
|
Map<Long, Long> maintenCountMap = maintenRecordList.stream()
|
.collect(Collectors.groupingBy(MesDvMaintenRecordDO::getMachineryId, Collectors.counting()));
|
Map<Long, Long> borrowCountMap = borrowList.stream()
|
.collect(Collectors.groupingBy(MesDvBorrowDO::getMachineryId, Collectors.counting()));
|
|
// 3. 名称解析
|
Map<Long, MesDvMachineryTypeDO> typeMap = machineryTypeService.getMachineryTypeMap(
|
convertSet(machineryList, MesDvMachineryDO::getMachineryTypeId));
|
Map<Long, cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO> workshopMap =
|
workshopService.getWorkshopMap(convertSet(machineryList, MesDvMachineryDO::getWorkshopId));
|
Map<Long, cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO> processMap =
|
processService.getProcessMap(convertSet(machineryList, MesDvMachineryDO::getProcessId));
|
|
// 4. 逐台设备汇总
|
long totalMinutes = Math.max(Duration.between(beginTime, endTime).toMinutes(), 1);
|
LocalDateTime now = LocalDateTime.now();
|
List<MesDvMachineryStatisticsRespVO> result = new ArrayList<>(machineryList.size());
|
for (MesDvMachineryDO machinery : machineryList) {
|
MesDvMachineryStatisticsRespVO vo = new MesDvMachineryStatisticsRespVO();
|
vo.setMachineryId(machinery.getId());
|
vo.setMachineryCode(machinery.getCode());
|
vo.setMachineryName(machinery.getName());
|
vo.setStatus(machinery.getStatus());
|
cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen(typeMap,
|
machinery.getMachineryTypeId(), type -> vo.setMachineryTypeName(type.getName()));
|
cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen(workshopMap,
|
machinery.getWorkshopId(), workshop -> vo.setWorkshopName(workshop.getName()));
|
cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen(processMap,
|
machinery.getProcessId(), process -> vo.setProcessName(process.getName()));
|
|
List<MesDvRepairDO> repairs = repairMap.getOrDefault(machinery.getId(), Collections.emptyList());
|
vo.setRepairCount(repairs.size());
|
vo.setCheckCount(checkCountMap.getOrDefault(machinery.getId(), 0L).intValue());
|
vo.setMaintenCount(maintenCountMap.getOrDefault(machinery.getId(), 0L).intValue());
|
vo.setBorrowCount(borrowCountMap.getOrDefault(machinery.getId(), 0L).intValue());
|
|
// 累计维修耗时:优先取登记的耗时,未登记时按报修→完成时间估算
|
BigDecimal repairHours = BigDecimal.ZERO;
|
long downMinutes = 0L;
|
LocalDateTime lastRepairTime = null;
|
for (MesDvRepairDO repair : repairs) {
|
if (lastRepairTime == null || repair.getRequireDate().isAfter(lastRepairTime)) {
|
lastRepairTime = repair.getRequireDate();
|
}
|
LocalDateTime repairEnd = repair.getFinishDate() != null ? repair.getFinishDate() : now;
|
if (repair.getDurationHours() != null) {
|
repairHours = repairHours.add(repair.getDurationHours());
|
} else {
|
long minutes = Math.max(Duration.between(repair.getRequireDate(), repairEnd).toMinutes(), 0);
|
repairHours = repairHours.add(BigDecimal.valueOf(minutes)
|
.divide(MINUTES_PER_HOUR, 2, RoundingMode.HALF_UP));
|
}
|
// 停机时长:仅统计落在区间内的部分
|
LocalDateTime downStart = repair.getRequireDate().isBefore(beginTime) ? beginTime : repair.getRequireDate();
|
LocalDateTime downEnd = repairEnd.isAfter(endTime) ? endTime : repairEnd;
|
if (downEnd.isAfter(downStart)) {
|
downMinutes += Duration.between(downStart, downEnd).toMinutes();
|
}
|
}
|
vo.setRepairHours(repairHours.setScale(2, RoundingMode.HALF_UP));
|
vo.setLastRepairTime(lastRepairTime);
|
vo.setDownHours(BigDecimal.valueOf(downMinutes)
|
.divide(MINUTES_PER_HOUR, 2, RoundingMode.HALF_UP));
|
// 使用率 =(统计时长 - 停机时长)/ 统计时长,区间内无停机即 100%
|
long usedMinutes = Math.max(totalMinutes - downMinutes, 0L);
|
vo.setUsageRate(BigDecimal.valueOf(usedMinutes)
|
.multiply(BigDecimal.valueOf(100))
|
.divide(BigDecimal.valueOf(totalMinutes), 2, RoundingMode.HALF_UP));
|
result.add(vo);
|
}
|
// 使用率升序,故障多的排前面,便于关注问题设备
|
result.sort(Comparator.comparing(MesDvMachineryStatisticsRespVO::getUsageRate)
|
.thenComparing(MesDvMachineryStatisticsRespVO::getRepairCount, Comparator.reverseOrder()));
|
return result;
|
}
|
|
}
|