|
@@ -11,6 +11,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotlockstock.vo.IotLockStockPageReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotlockstock.vo.IotLockStockPageReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomPageReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomPageReqVO;
|
|
|
|
+import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomRespVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderPageReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderRespVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderRespVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveReqVO;
|
|
@@ -254,6 +255,7 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
|
|
}
|
|
}
|
|
// 找出距离0最近的数,作为工单的最近保养距离数据
|
|
// 找出距离0最近的数,作为工单的最近保养距离数据
|
|
Object closet = chooseNearestDistance(runningTimeDistance, runningKiloDistance, naturalDateDistance);
|
|
Object closet = chooseNearestDistance(runningTimeDistance, runningKiloDistance, naturalDateDistance);
|
|
|
|
+ // key距离单位(小时 公里 天) value最小的距离值
|
|
Map<String, Object> tempDistance = new HashMap<>();
|
|
Map<String, Object> tempDistance = new HashMap<>();
|
|
if (closet == runningTimeDistance) {
|
|
if (closet == runningTimeDistance) {
|
|
tempDistance.put("H", closet);
|
|
tempDistance.put("H", closet);
|
|
@@ -577,6 +579,366 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
+ public PageResult<IotDeviceRespVO> maintenanceSearch(IotMainWorkOrderPageReqVO pageReqVO) {
|
|
|
|
+ // 所有保养计划 明细中待保养的最近距离 里程/时间/自然日
|
|
|
|
+ Set<Long> deviceIds = new HashSet<>();
|
|
|
|
+ Set<Long> orderDeviceIds = new HashSet<>();
|
|
|
|
+ // 查询保养计划明细中不包含 deviceIds 的设备id集合
|
|
|
|
+ List<IotMaintenanceBomDO> mainBomS = new ArrayList<>();
|
|
|
|
+ Set<Long> mainBomDeviceIds = new HashSet<>();
|
|
|
|
+
|
|
|
|
+ IotMaintenanceBomPageReqVO mainBomReqVO = new IotMaintenanceBomPageReqVO();
|
|
|
|
+ mainBomS = iotMaintenanceBomMapper.selectList(mainBomReqVO);
|
|
|
|
+ Set<String> boundedMultiAttrNames = new HashSet<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(mainBomS)) {
|
|
|
|
+ mainBomDeviceIds = CollUtil.isEmpty(mainBomS)
|
|
|
|
+ ? Collections.emptySet()
|
|
|
|
+ : mainBomS.stream()
|
|
|
|
+ .map(IotMaintenanceBomDO::getDeviceId) // 获取 deviceId
|
|
|
|
+ .filter(Objects::nonNull) // 过滤非空值
|
|
|
|
+ .collect(Collectors.toSet()); // 收集到 Set 中
|
|
|
|
+ // 查询所有保养计划 保养项 中已经绑定的 多个累计时长 公里数 属性名称值
|
|
|
|
+ mainBomS.forEach(bom -> {
|
|
|
|
+ if (StrUtil.isNotBlank(bom.getType())) {
|
|
|
|
+ // 累计公里数属性
|
|
|
|
+ boundedMultiAttrNames.add(bom.getType());
|
|
|
|
+ }
|
|
|
|
+ if (StrUtil.isNotBlank(bom.getCode())) {
|
|
|
|
+ // 累计时长属性
|
|
|
|
+ boundedMultiAttrNames.add(bom.getCode());
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ deviceIds.addAll(mainBomDeviceIds);
|
|
|
|
+ if (CollUtil.isEmpty(deviceIds)){
|
|
|
|
+ // 没有设备信息,返回空列表
|
|
|
|
+ return PageResult.empty();
|
|
|
|
+ }
|
|
|
|
+ // 查询 运行记录模板中包含多个累计 时长 公里数 属性的集合
|
|
|
|
+ List<IotDeviceRunLogRespVO> multipleAccumulatedData = new ArrayList<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(deviceIds) && CollUtil.isNotEmpty(boundedMultiAttrNames)) {
|
|
|
|
+ multipleAccumulatedData = iotDeviceRunLogService.multipleAccumulatedData(deviceIds, boundedMultiAttrNames);
|
|
|
|
+ }
|
|
|
|
+ // key(设备id-累计时长属性名称) value时长属性累计时长数值
|
|
|
|
+ Map<String, BigDecimal> tempTotalRunDataPair = new HashMap<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(multipleAccumulatedData)) {
|
|
|
|
+ multipleAccumulatedData.forEach(data -> {
|
|
|
|
+ String uniqueKey = StrUtil.join("-", data.getDeviceId(), data.getPointName());
|
|
|
|
+ tempTotalRunDataPair.put(uniqueKey, data.getTotalRunTime());
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 查询 运行记录模板中 正常的累计时长 公里数集合
|
|
|
|
+ Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap = iotDeviceRunLogService.getDeviceRunLogMap(new ArrayList<>(deviceIds));
|
|
|
|
+ // 以设备为维度统计每个设备相关的保养项的最近保养距离 key设备id value设备下每个保养项的的最小保养距离集合
|
|
|
|
+ Map<Long, List<Map<String, Object>>> orderDistancePair = new HashMap<>();
|
|
|
|
+ // 设备保养明细 key设备id value设备保养工单明细下所有保养规则数据最小值
|
|
|
|
+ Map<Long, String> resultMap = new HashMap<>();
|
|
|
|
+ // 设备保养明细 key设备id-保养项分组名称 value设备保养项分组下最近的保养距离
|
|
|
|
+ Map<String, String> groupResultMap = new HashMap<>();
|
|
|
|
+ // 以设备为维度统计每个设备相关的保养项(分组)的最近保养距离 key设备id-保养项分组名称 value设备下每个保养项的的最小保养距离集合
|
|
|
|
+ Map<String, List<Map<String, Object>>> minBomGroupDistancePair = new HashMap<>();
|
|
|
|
+ // 以“设备id-分组bom名称-bomNodeId”为维度统计每个设备相关的保养项的最近保养距离关联的对象 key设备id-分组bom名称-bomNodeId
|
|
|
|
+ // value设备下每个保养项的的最小保养距离关联的保养项对象
|
|
|
|
+ Map<String, IotMaintenanceBomDO> minBomDistancePair = new HashMap<>();
|
|
|
|
+ // 以“设备id-分组bom名称-bomNodeId”为维度统计每个设备相关的保养项的最近保养距离关联的对象 key设备id-分组bom名称-bomNodeId
|
|
|
|
+ // value设备下每个保养项的的最小保养距离 数值
|
|
|
|
+ Map<String, String> bomDistancePair = new HashMap<>();
|
|
|
|
+ // key设备id value设备对应的各个bom分组及分组下的最短保养距离
|
|
|
|
+ Map<Long, List<IotMaintenanceBomDO>> deviceBomGroupPair = new HashMap<>();
|
|
|
|
+ // key设备id value设备对应的各个bom分组及分组下的最短保养距离
|
|
|
|
+ Map<Long, List<IotMaintenanceBomRespVO>> resultDeviceBomGroupPair = new HashMap<>();
|
|
|
|
+ // key设备id-bomNodeId value保养项的累计运行时长/里程
|
|
|
|
+ Map<String, IotMaintenanceBomRespVO> maintenanceBomRespPair = new HashMap<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(mainBomS)) {
|
|
|
|
+ // 遍历保养计划明细 计算 保养计划中的设备 的最近的保养时间
|
|
|
|
+ mainBomS.forEach(bom -> {
|
|
|
|
+ // 拷贝一份保养明细对象 设置 累计运行时长/里程 使用
|
|
|
|
+ IotMaintenanceBomRespVO bomResp = new IotMaintenanceBomRespVO();
|
|
|
|
+ BeanUtils.copyProperties(bom, bomResp);
|
|
|
|
+ BigDecimal runningTimeDistance = null;
|
|
|
|
+ BigDecimal runningKiloDistance = null;
|
|
|
|
+ BigDecimal naturalDateDistance = null;
|
|
|
|
+ // 计算每个保养项 每个保养规则下的 距离保养时间 单位 小时
|
|
|
|
+ if (ObjUtil.isNotEmpty(bom.getRunningTimeRule()) && 0 == bom.getRunningTimeRule()) {
|
|
|
|
+ // 运行时间保养规则
|
|
|
|
+ BigDecimal totalRunTime = BigDecimal.ZERO;
|
|
|
|
+ if (deviceRunLogMap.containsKey(bom.getDeviceId())) {
|
|
|
|
+ totalRunTime = deviceRunLogMap.get(bom.getDeviceId()).getTotalRunTime();
|
|
|
|
+ } else {
|
|
|
|
+ // 运行记录模板中包含多个累计时长 公里数类型的属性
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getCode());
|
|
|
|
+ if (tempTotalRunDataPair.containsKey(uniqueKey)) {
|
|
|
|
+ totalRunTime = tempTotalRunDataPair.get(uniqueKey);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ BigDecimal lastRunningTime = bom.getLastRunningTime(); // 上次保养运行时间
|
|
|
|
+ BigDecimal runningTimePeriod = bom.getNextRunningTime(); // 运行时间周期
|
|
|
|
+ BigDecimal timePeriodLead = bom.getTimePeriodLead(); // 运行时间周期提前量
|
|
|
|
+ runningTimeDistance = runningTimePeriod.subtract(totalRunTime.subtract(lastRunningTime));
|
|
|
|
+ bomResp.setTotalRunTime(totalRunTime);
|
|
|
|
+ }
|
|
|
|
+ if (ObjUtil.isNotEmpty(bom.getMileageRule()) && 0 == bom.getMileageRule()) {
|
|
|
|
+ // 运行里程保养规则 累计运行里程规则 累计运行里程 >= (上次保养运行里程+运行里程周期-提前量)
|
|
|
|
+ BigDecimal totalMileage = BigDecimal.ZERO;
|
|
|
|
+ if (deviceRunLogMap.containsKey(bom.getDeviceId())) {
|
|
|
|
+ totalMileage = deviceRunLogMap.get(bom.getDeviceId()).getTotalMileage();
|
|
|
|
+ } else {
|
|
|
|
+ // 运行记录模板中包含多个累计时长 公里数类型的属性
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getType());
|
|
|
|
+ if (tempTotalRunDataPair.containsKey(uniqueKey)) {
|
|
|
|
+ totalMileage = tempTotalRunDataPair.get(uniqueKey);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ BigDecimal lastRunningKilo = bom.getLastRunningKilometers(); // 上次保养运行里程
|
|
|
|
+ BigDecimal runningKiloPeriod = bom.getNextRunningKilometers(); // 运行里程周期
|
|
|
|
+ BigDecimal kiloCycleLead = bom.getKiloCycleLead(); // 运行里程周期提前量
|
|
|
|
+ runningKiloDistance = runningKiloPeriod.subtract(totalMileage.subtract(lastRunningKilo));
|
|
|
|
+ bomResp.setTotalMileage(totalMileage);
|
|
|
|
+ }
|
|
|
|
+ if (ObjUtil.isNotEmpty(bom.getNaturalDateRule()) && 0 == bom.getNaturalDateRule()) {
|
|
|
|
+ // 自然日期保养规则
|
|
|
|
+ LocalDateTime lastNaturalDate = bom.getLastNaturalDate(); // 上次保养自然日期
|
|
|
|
+ BigDecimal naturalDatePeriod = bom.getNextNaturalDate(); // 自然日周期
|
|
|
|
+ BigDecimal natualDateLead = bom.getNaturalDatePeriodLead(); // 自然日周期提前量
|
|
|
|
+ if (ObjUtil.isNotEmpty(lastNaturalDate) && ObjUtil.isNotEmpty(naturalDatePeriod) && ObjUtil.isNotEmpty(natualDateLead)) {
|
|
|
|
+ // 计算有效天数 = 自然日周期 - 提前量
|
|
|
|
+ long days = naturalDatePeriod.longValue(); // 转为长整型天数
|
|
|
|
+ // 计算目标日期:上次保养日期 + 有效天数(注意:LocalDateTime加天数会自动处理日期进位)
|
|
|
|
+ LocalDateTime targetDate = lastNaturalDate.plusDays(days);
|
|
|
|
+ // 获取当前日期时间
|
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
|
+ // 计算日期差值(以天为单位)
|
|
|
|
+ naturalDateDistance = new BigDecimal(ChronoUnit.DAYS.between(now, targetDate));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 按照保养项的父BOM节点分组统计 最短保养距离
|
|
|
|
+ // 先按照 保养项目 层级分组 电驱空压机->油气分离器滤芯
|
|
|
|
+ String bomNodeName = bom.getName();
|
|
|
|
+ Long bomNodeId = bom.getBomNodeId();
|
|
|
|
+ String uniqueKey = StrUtil.EMPTY;
|
|
|
|
+ String uniqueBomKey = StrUtil.EMPTY;
|
|
|
|
+ String uniqueBomNodeIdKey = StrUtil.EMPTY;
|
|
|
|
+ if (StrUtil.isNotBlank(bomNodeName)) {
|
|
|
|
+ String[] bomNodeNameAttr = bomNodeName.split("->");
|
|
|
|
+ if (ObjUtil.isNotEmpty(bomNodeNameAttr) && ObjUtil.isNotEmpty(bomNodeId) && bomNodeNameAttr.length > 1) {
|
|
|
|
+ // 当前保养项是 多级 BOM 可以分组统计 每个分组下的 最短保养距离 key"设备id-电驱空压机"
|
|
|
|
+ uniqueKey = StrUtil.join("-", bom.getDeviceId(), bomNodeNameAttr[0]);
|
|
|
|
+ uniqueBomKey = StrUtil.join("-", bom.getDeviceId(), bomNodeNameAttr[0], bomNodeId);
|
|
|
|
+ uniqueBomNodeIdKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 设置每个保养项的 累计运行时长/里程
|
|
|
|
+ maintenanceBomRespPair.put(uniqueBomNodeIdKey, bomResp);
|
|
|
|
+
|
|
|
|
+ IotMaintenanceBomDO tempBom = new IotMaintenanceBomDO();
|
|
|
|
+ tempBom.setDeviceId(bom.getDeviceId());
|
|
|
|
+ tempBom.setBomNodeId(bom.getBomNodeId());
|
|
|
|
+ tempBom.setName(bom.getName());
|
|
|
|
+ tempBom.setRunningTimeRule(bom.getRunningTimeRule());
|
|
|
|
+ tempBom.setMileageRule(bom.getMileageRule());
|
|
|
|
+ tempBom.setNaturalDateRule(bom.getNaturalDateRule());
|
|
|
|
+ // 找出距离0最近的数,作为工单的最近保养距离数据
|
|
|
|
+ Object closet = chooseNearestDistance(runningTimeDistance, runningKiloDistance, naturalDateDistance);
|
|
|
|
+ String tempMinDistance = StrUtil.EMPTY;
|
|
|
|
+ Map<String, Object> tempDistance = new HashMap<>();
|
|
|
|
+ if (closet == runningTimeDistance) {
|
|
|
|
+ tempDistance.put("H", closet);
|
|
|
|
+ tempMinDistance = StrUtil.join(" ", closet, "H");
|
|
|
|
+ // 运行时长
|
|
|
|
+ tempBom.setLastRunningTime(bom.getLastRunningTime());
|
|
|
|
+ tempBom.setNextRunningTime(bom.getNextRunningTime());
|
|
|
|
+ tempBom.setTimePeriodLead(bom.getTimePeriodLead());
|
|
|
|
+ } else if (closet == runningKiloDistance) {
|
|
|
|
+ tempDistance.put("KM", closet);
|
|
|
|
+ tempMinDistance = StrUtil.join(" ", closet, "KM");
|
|
|
|
+ // 运行里程
|
|
|
|
+ tempBom.setLastRunningKilometers(bom.getLastRunningKilometers());
|
|
|
|
+ tempBom.setNextRunningKilometers(bom.getNextRunningKilometers());
|
|
|
|
+ tempBom.setKiloCycleLead(bom.getKiloCycleLead());
|
|
|
|
+ } else if (closet == naturalDateDistance) {
|
|
|
|
+ tempDistance.put("D", closet);
|
|
|
|
+ tempMinDistance = StrUtil.join(" ", closet, "D");
|
|
|
|
+ // 自然日期
|
|
|
|
+ tempBom.setLastNaturalDate(bom.getLastNaturalDate());
|
|
|
|
+ tempBom.setNextNaturalDate(bom.getNextNaturalDate());
|
|
|
|
+ tempBom.setNaturalDatePeriodLead(bom.getNaturalDatePeriodLead());
|
|
|
|
+ }
|
|
|
|
+ // 保存每个保养项对象 之后与 每个保养项分组的 最短保养距离匹配
|
|
|
|
+ minBomDistancePair.put(uniqueBomKey, tempBom);
|
|
|
|
+ // 保存每个保养项的最短距离 之后与 每个保养项分组的 最短保养距离匹配
|
|
|
|
+ bomDistancePair.put(uniqueBomKey, tempMinDistance);
|
|
|
|
+ if (orderDistancePair.containsKey(bom.getDeviceId())) {
|
|
|
|
+ List<Map<String, Object>> tempDistances = orderDistancePair.get(bom.getDeviceId());
|
|
|
|
+ tempDistances.add(tempDistance);
|
|
|
|
+ orderDistancePair.put(bom.getDeviceId(), tempDistances);
|
|
|
|
+ } else {
|
|
|
|
+ List<Map<String, Object>> tempDistances = new ArrayList<>();
|
|
|
|
+ tempDistances.add(tempDistance);
|
|
|
|
+ orderDistancePair.put(bom.getDeviceId(), tempDistances);
|
|
|
|
+ }
|
|
|
|
+ // 按照保养项的父BOM节点分组统计 最短保养距离
|
|
|
|
+ // 先按照 保养项目 层级分组 电驱空压机->油气分离器滤芯
|
|
|
|
+ if (StrUtil.isNotBlank(uniqueKey)) {
|
|
|
|
+ if (minBomGroupDistancePair.containsKey(uniqueKey)) {
|
|
|
|
+ List<Map<String, Object>> tempDistances = minBomGroupDistancePair.get(uniqueKey);
|
|
|
|
+ tempDistances.add(tempDistance);
|
|
|
|
+ minBomGroupDistancePair.put(uniqueKey, tempDistances);
|
|
|
|
+ } else {
|
|
|
|
+ List<Map<String, Object>> tempDistances = new ArrayList<>();
|
|
|
|
+ tempDistances.add(tempDistance);
|
|
|
|
+ minBomGroupDistancePair.put(uniqueKey, tempDistances);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ // 以“设备id-保养项分组” 为维度 统计每个设备保养项分组下 距离最近的保养数据
|
|
|
|
+ groupResultMap = findGroupClosestToZero(minBomGroupDistancePair);
|
|
|
|
+ List<Map.Entry<String, String>> keys = groupResultMap.entrySet().stream().filter(e -> e.getKey().contains("530-")).collect(Collectors.toList());
|
|
|
|
+ // minBomDistancePair bomDistancePair 循环这2个对象 组装每个分组需要显示的最短保养距离 BOM对象
|
|
|
|
+ if (CollUtil.isNotEmpty(bomDistancePair)) {
|
|
|
|
+ Map<String, String> finalGroupResultMap = groupResultMap;
|
|
|
|
+ bomDistancePair.forEach((k, v) -> {
|
|
|
|
+ // k设备id-分组bom名称-bomNodeId v设备下每个保养项的的最小保养距离 数值
|
|
|
|
+ // 分割出 k 的前部分 “设备id-分组bom名称”
|
|
|
|
+ String[] firstKeyAttr = splitAtSecondHyphen(k);
|
|
|
|
+ if (ObjUtil.isNotEmpty(firstKeyAttr) && firstKeyAttr.length > 1) {
|
|
|
|
+ String firstKeyStr = firstKeyAttr[0];
|
|
|
|
+ Long deviceId = 0l;
|
|
|
|
+ if (StrUtil.isNotBlank(firstKeyStr)) {
|
|
|
|
+ String[] deviceIdAttr = firstKeyStr.split("-");
|
|
|
|
+ if (ObjUtil.isNotEmpty(deviceIdAttr) && deviceIdAttr.length > 1) {
|
|
|
|
+ deviceId = Long.valueOf(deviceIdAttr[0]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (finalGroupResultMap.containsKey(firstKeyAttr[0])) {
|
|
|
|
+ // "-2249.00 H"
|
|
|
|
+ String groupMinDistance = finalGroupResultMap.get(firstKeyAttr[0]);
|
|
|
|
+ // 去掉 距离单位 获得 数值
|
|
|
|
+ if (StrUtil.isNotBlank(groupMinDistance)) {
|
|
|
|
+ if (StrUtil.equals(groupMinDistance, v)) {
|
|
|
|
+ // 根据 k 找到 minBomDistancePair 中对应的 最小距离 保养对象
|
|
|
|
+ if (minBomDistancePair.containsKey(k)) {
|
|
|
|
+ IotMaintenanceBomDO tempBom = minBomDistancePair.get(k);
|
|
|
|
+ if (deviceBomGroupPair.containsKey(deviceId)) {
|
|
|
|
+ List<IotMaintenanceBomDO> tempBomS = deviceBomGroupPair.get(deviceId);
|
|
|
|
+ tempBomS.add(tempBom);
|
|
|
|
+ deviceBomGroupPair.put(deviceId, tempBomS);
|
|
|
|
+ } else {
|
|
|
|
+ List<IotMaintenanceBomDO> tempBomS = new ArrayList<>();
|
|
|
|
+ tempBomS.add(tempBom);
|
|
|
|
+ deviceBomGroupPair.put(deviceId, tempBomS);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 重新整理 deviceBomGroupPair 集合 每个 设备的保养项分组只保留1个对象 因为存在 相同保养距离的保养项
|
|
|
|
+ if (CollUtil.isNotEmpty(deviceBomGroupPair)) {
|
|
|
|
+ deviceBomGroupPair.forEach((k,v) -> {
|
|
|
|
+ // k设备id v分组bom中距离保养最近的对象
|
|
|
|
+ Set<String> bomNames = new HashSet<>();
|
|
|
|
+ List<IotMaintenanceBomRespVO> copyBomS = new ArrayList<>();
|
|
|
|
+ v.forEach(bom -> {
|
|
|
|
+ String leveledBomName = bom.getName();
|
|
|
|
+ String[] bomNameAttr = leveledBomName.split("->");
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId());
|
|
|
|
+ if (ObjUtil.isNotEmpty(bomNameAttr) && bomNameAttr.length > 1) {
|
|
|
|
+ if (!bomNames.contains(bomNameAttr[0])) {
|
|
|
|
+ IotMaintenanceBomRespVO bomResp = new IotMaintenanceBomRespVO();
|
|
|
|
+ BeanUtils.copyProperties(bom, bomResp);
|
|
|
|
+ if (maintenanceBomRespPair.containsKey(uniqueKey)) {
|
|
|
|
+ IotMaintenanceBomRespVO tempBomResp = maintenanceBomRespPair.get(uniqueKey);
|
|
|
|
+ bomResp.setTotalRunTime(tempBomResp.getTotalRunTime());
|
|
|
|
+ bomResp.setTotalMileage(tempBomResp.getTotalMileage());
|
|
|
|
+ }
|
|
|
|
+ copyBomS.add(bomResp);
|
|
|
|
+ }
|
|
|
|
+ bomNames.add(bomNameAttr[0]);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ resultDeviceBomGroupPair.put(k, copyBomS);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 以设备id 为维度 统计每个保养计划明细中 距离最近的保养数据
|
|
|
|
+ resultMap = findClosestToZero(orderDistancePair);
|
|
|
|
+ // 对集合 resultMap 中所有数据进行排序 按照 map 的value值 去除后面的 字符后 升序排列
|
|
|
|
+ // 排序后输出一个 List<Long> 类型的集合,排序对应上面的排序规则
|
|
|
|
+ List<Long> sortedDeviceIds = sortByNumericValue(resultMap);
|
|
|
|
+ try {
|
|
|
|
+ // 左侧组织树 组织层级查询
|
|
|
|
+ Set<Long> ids = new HashSet<>();
|
|
|
|
+ if (Objects.nonNull(pageReqVO.getDeptId())) {
|
|
|
|
+ ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
|
|
|
|
+ ids.add(pageReqVO.getDeptId());
|
|
|
|
+ }
|
|
|
|
+ // 不查询保养工单表 暂时传一个不会出现的设备id
|
|
|
|
+ orderDeviceIds.add(Long.MIN_VALUE);
|
|
|
|
+ List<IotDeviceRespVO> alarmDevices = iotDeviceMapper.deviceAlarmDistances(sortedDeviceIds, orderDeviceIds, mainBomDeviceIds);
|
|
|
|
+ // 处理当前分页数据 拼接上已经排序的 筛选出的设备保养项 最小保养距离
|
|
|
|
+ List<Long> alarmDeviceIds = new ArrayList<>();
|
|
|
|
+ Map<Long, IotDeviceRespVO> alarmDevicePair = new HashMap<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(alarmDevices)) {
|
|
|
|
+ for (IotDeviceRespVO device : alarmDevices) {
|
|
|
|
+ if (resultMap.containsKey(device.getId())) {
|
|
|
|
+ device.setMainDistance(resultMap.get(device.getId()));
|
|
|
|
+ alarmDeviceIds.add(device.getId());
|
|
|
|
+ }
|
|
|
|
+ alarmDevicePair.put(device.getId(), device);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 查询所有设备列表 通过SQL形式 使用 FIELD 字段
|
|
|
|
+ IPage<IotDeviceRespVO> page = iotDeviceMapper.allDeviceDistances(
|
|
|
|
+ new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO, alarmDeviceIds, ids);
|
|
|
|
+ if (CollUtil.isNotEmpty(page.getRecords())) {
|
|
|
|
+ page.getRecords().forEach(device -> {
|
|
|
|
+ if (alarmDevicePair.containsKey(device.getId())) {
|
|
|
|
+ device.setMainDistance(alarmDevicePair.get(device.getId()).getMainDistance());
|
|
|
|
+ device.setPlanId(alarmDevicePair.get(device.getId()).getPlanId());
|
|
|
|
+ device.setWorkOrderId(alarmDevicePair.get(device.getId()).getWorkOrderId());
|
|
|
|
+ }
|
|
|
|
+ // 查询 每个设备对应的 保养项 分组 集合 已经设置了 最短距离
|
|
|
|
+ if (resultDeviceBomGroupPair.containsKey(device.getId())) {
|
|
|
|
+ List<IotMaintenanceBomRespVO> tempBomS = resultDeviceBomGroupPair.get(device.getId());
|
|
|
|
+ device.setGroupBomDistances(tempBomS);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ return new PageResult<>(page.getRecords(), page.getTotal());
|
|
|
|
+ } catch (Exception exception) {
|
|
|
|
+ if (exception.getMessage().contains("Table does not exist")) {
|
|
|
|
+ return PageResult.empty();
|
|
|
|
+ }
|
|
|
|
+ throw exception;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String[] splitAtSecondHyphen(String str) {
|
|
|
|
+ int firstIndex = str.indexOf('-');
|
|
|
|
+ if (firstIndex == -1) {
|
|
|
|
+ // 没有找到任何 '-',返回整个字符串和空字符串
|
|
|
|
+ return new String[]{str, ""};
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 从第一个 '-' 后开始查找第二个 '-'
|
|
|
|
+ int secondIndex = str.indexOf('-', firstIndex + 1);
|
|
|
|
+ if (secondIndex == -1) {
|
|
|
|
+ // 没有找到第二个 '-',返回整个字符串和空字符串
|
|
|
|
+ return new String[]{str, ""};
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 分割字符串
|
|
|
|
+ String part1 = str.substring(0, secondIndex);
|
|
|
|
+ String part2 = str.substring(secondIndex + 1);
|
|
|
|
+ return new String[]{part1, part2};
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 排序 Map<Long, String> 中的元素 删除 类似 D、 H、 KM 后进行升序排列
|
|
* 排序 Map<Long, String> 中的元素 删除 类似 D、 H、 KM 后进行升序排列
|
|
* @param map
|
|
* @param map
|
|
@@ -654,6 +1016,52 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 找出每个设备对应的bom保养项(层级分组)集合中 距离保养最短的 数据
|
|
|
|
+ *
|
|
|
|
+ * @param minBomGroupDistancePair key设备id-保养项一级分组名称
|
|
|
|
+ */
|
|
|
|
+ private Map<String, String> findGroupClosestToZero(Map<String, List<Map<String, Object>>> minBomGroupDistancePair) {
|
|
|
|
+ Map<String, String> result = new HashMap<>();
|
|
|
|
+ for (Map.Entry<String, List<Map<String, Object>>> entry : minBomGroupDistancePair.entrySet()) {
|
|
|
|
+ String uniqueKey = entry.getKey(); // 设备id-保养项节点第一层级名称
|
|
|
|
+ List<Map<String, Object>> mapList = entry.getValue();
|
|
|
|
+ // 存储所有有效值(原始值、单位、转换值)
|
|
|
|
+ List<Triple<BigDecimal, String, BigDecimal>> allValues = new ArrayList<>();
|
|
|
|
+ // 收集所有值并进行单位转换
|
|
|
|
+ for (Map<String, Object> map : mapList) {
|
|
|
|
+ for (Map.Entry<String, Object> valueEntry : map.entrySet()) {
|
|
|
|
+ if (valueEntry.getValue() instanceof BigDecimal) {
|
|
|
|
+ BigDecimal value = (BigDecimal) valueEntry.getValue();
|
|
|
|
+ String unit = valueEntry.getKey();
|
|
|
|
+ BigDecimal convertedValue;
|
|
|
|
+ // 小时转换为天
|
|
|
|
+ if ("H".equals(unit)) {
|
|
|
|
+ convertedValue = value.divide(BigDecimal.valueOf(24), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
|
+ } else {
|
|
|
|
+ convertedValue = value;
|
|
|
|
+ }
|
|
|
|
+ allValues.add(new Triple<>(value, unit, convertedValue));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 如果没有有效值,跳过
|
|
|
|
+ if (allValues.isEmpty()) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ // 找到转换后值最小的值
|
|
|
|
+ Triple<BigDecimal, String, BigDecimal> minTriple = allValues.get(0);
|
|
|
|
+ for (Triple<BigDecimal, String, BigDecimal> triple : allValues) {
|
|
|
|
+ if (triple.getThird().compareTo(minTriple.getThird()) < 0) {
|
|
|
|
+ minTriple = triple;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 格式化为字符串: "原始值 单位"
|
|
|
|
+ result.put(uniqueKey, minTriple.getFirst() + " " + minTriple.getSecond());
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 将Map转换为String格式:value1 key1; value2 key2
|
|
* 将Map转换为String格式:value1 key1; value2 key2
|
|
*/
|
|
*/
|
|
@@ -971,7 +1379,6 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
|
|
}
|
|
}
|
|
// 如果在填报工单时 填写了 保养项 中的 ‘运行时间周期(H)’ 保存时需要同步到 保养工单 关联的 保养计划的 对应的保养项的 ‘运行时间周期(H)’
|
|
// 如果在填报工单时 填写了 保养项 中的 ‘运行时间周期(H)’ 保存时需要同步到 保养工单 关联的 保养计划的 对应的保养项的 ‘运行时间周期(H)’
|
|
// 包含 延时保养 的情况
|
|
// 包含 延时保养 的情况
|
|
-
|
|
|
|
// 只扣减本地库存 不处理SAP库存
|
|
// 只扣减本地库存 不处理SAP库存
|
|
if (CollUtil.isNotEmpty(factoryIds) && CollUtil.isNotEmpty(costCenterIds) && CollUtil.isNotEmpty(materialCodes)) {
|
|
if (CollUtil.isNotEmpty(factoryIds) && CollUtil.isNotEmpty(costCenterIds) && CollUtil.isNotEmpty(materialCodes)) {
|
|
IotLockStockPageReqVO reqVO = new IotLockStockPageReqVO();
|
|
IotLockStockPageReqVO reqVO = new IotLockStockPageReqVO();
|