|
@@ -9,14 +9,12 @@ import cn.hutool.core.util.StrUtil;
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
|
|
+import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
|
|
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.iotmaintenancebom.vo.IotMaintenanceBomRespVO;
|
|
-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.IotMainWorkOrderSaveReqVO;
|
|
|
|
-import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.IotMainWorkOrderSaveVO;
|
|
|
|
|
|
+import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorder.vo.*;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomPageReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomPageReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomRespVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomRespVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomSaveReqVO;
|
|
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomSaveReqVO;
|
|
@@ -42,6 +40,8 @@ import cn.iocoder.yudao.module.pms.dal.redis.BizNoRedisDAO;
|
|
import cn.iocoder.yudao.module.pms.service.IotDeviceService;
|
|
import cn.iocoder.yudao.module.pms.service.IotDeviceService;
|
|
import cn.iocoder.yudao.module.pms.service.iotdevicerunlog.IotDeviceRunLogService;
|
|
import cn.iocoder.yudao.module.pms.service.iotdevicerunlog.IotDeviceRunLogService;
|
|
import cn.iocoder.yudao.module.pms.service.iotmaintenancebom.IotMaintenanceBomService;
|
|
import cn.iocoder.yudao.module.pms.service.iotmaintenancebom.IotMaintenanceBomService;
|
|
|
|
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
|
|
|
|
+import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
|
|
import cn.iocoder.yudao.module.system.service.dept.DeptService;
|
|
import cn.iocoder.yudao.module.system.service.dept.DeptService;
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
@@ -98,6 +98,8 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
|
|
private DeptService deptService;
|
|
private DeptService deptService;
|
|
@Resource
|
|
@Resource
|
|
private IotOutboundMapper iotOutboundMapper;
|
|
private IotOutboundMapper iotOutboundMapper;
|
|
|
|
+ @Resource
|
|
|
|
+ private DeptMapper deptMapper;
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public Long createIotMainWorkOrder(IotMainWorkOrderSaveReqVO createReqVO) {
|
|
public Long createIotMainWorkOrder(IotMainWorkOrderSaveReqVO createReqVO) {
|
|
@@ -660,6 +662,530 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
+ public List<IotDeviceRespVO> deviceMainTimeoutList(IotMainWorkOrderPageReqVO pageReqVO) {
|
|
|
|
+ // 所有保养计划 + 保养工单 明细中待保养的最近距离 里程/时间/自然日
|
|
|
|
+ List<IotMainWorkOrderBomDO> workOrderBomS = new ArrayList<>();
|
|
|
|
+ Set<Long> deviceIds = CollUtil.isEmpty(workOrderBomS)
|
|
|
|
+ ? new HashSet<>()
|
|
|
|
+ : workOrderBomS.stream()
|
|
|
|
+ .map(IotMainWorkOrderBomDO::getDeviceId) // 获取 deviceId
|
|
|
|
+ .filter(Objects::nonNull) // 过滤非空值
|
|
|
|
+ .collect(Collectors.toSet()); // 收集到 Set 中
|
|
|
|
+ Set<Long> orderDeviceIds = new HashSet<>();
|
|
|
|
+ orderDeviceIds.addAll(deviceIds);
|
|
|
|
+ // 查询保养计划明细中不包含 deviceIds 的设备id集合
|
|
|
|
+ List<IotMaintenanceBomDO> mainBomS = new ArrayList<>();
|
|
|
|
+ Set<Long> mainBomDeviceIds = new HashSet<>();
|
|
|
|
+ IotMaintenanceBomPageReqVO mainBomReqVO = new IotMaintenanceBomPageReqVO();
|
|
|
|
+ if (CollUtil.isNotEmpty(deviceIds)) {
|
|
|
|
+ mainBomReqVO.setDeviceIds(new ArrayList<>(deviceIds));
|
|
|
|
+ mainBomS = iotMaintenanceBomMapper.selectAlarmList(mainBomReqVO);
|
|
|
|
+ } else {
|
|
|
|
+ mainBomS = iotMaintenanceBomMapper.selectList(mainBomReqVO);
|
|
|
|
+ }
|
|
|
|
+ Set<String> boundedMultiAttrNames = new HashSet<>();
|
|
|
|
+ Set<Long> deviceCategoryIds = new HashSet<>();
|
|
|
|
+ Map<Long, Long> deviceCategoryPair = new HashMap<>();
|
|
|
|
+ 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());
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ // 查询所有设备类别id
|
|
|
|
+ // 组装bom关联的设备信息
|
|
|
|
+ Map<Long, IotDeviceRespVO> deviceMap = iotDeviceService.getDeviceMap(convertListByFlatMap(mainBomS,
|
|
|
|
+ bom -> Stream.of(bom.getDeviceId())));
|
|
|
|
+ if (CollUtil.isNotEmpty(deviceMap)) {
|
|
|
|
+ deviceMap.forEach((k,v) -> {
|
|
|
|
+ deviceCategoryIds.add(v.getAssetClass());
|
|
|
|
+ deviceCategoryPair.put(k, v.getAssetClass());
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ deviceIds.addAll(mainBomDeviceIds);
|
|
|
|
+ if (CollUtil.isEmpty(deviceIds)){
|
|
|
|
+ // 没有设备信息,返回空列表
|
|
|
|
+ return new ArrayList<>();
|
|
|
|
+ }
|
|
|
|
+ // 查询 运行记录模板中包含多个累计 时长 公里数 属性的集合
|
|
|
|
+ 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));
|
|
|
|
+ Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap =
|
|
|
|
+ iotDeviceRunLogService.getDeviceRunLogMapAlone(new ArrayList<>(deviceIds), new ArrayList<>(deviceCategoryIds), deviceCategoryPair);
|
|
|
|
+ // 以设备为维度统计每个设备相关的保养项的最近保养距离 key设备id value设备下每个保养项的的最小保养距离集合
|
|
|
|
+ Map<Long, List<Map<String, Object>>> orderDistancePair = new HashMap<>();
|
|
|
|
+ // 设备保养明细 key设备id value设备保养工单明细下所有保养规则数据最小值
|
|
|
|
+ Map<Long, String> resultMap = new HashMap<>();
|
|
|
|
+ // 记录保养项的 提前量 key设备id-保养项id-距离保养值 value提前量
|
|
|
|
+ Map<String, BigDecimal> bomLeadPair = new HashMap<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(mainBomS)) {
|
|
|
|
+ // 遍历保养计划明细 计算 保养计划中的设备 的最近的保养时间
|
|
|
|
+ for (IotMaintenanceBomDO bom : mainBomS) {
|
|
|
|
+ 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));
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), runningTimeDistance);
|
|
|
|
+ bomLeadPair.put(uniqueKey, timePeriodLead);
|
|
|
|
+ }
|
|
|
|
+ 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));
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), runningKiloDistance);
|
|
|
|
+ bomLeadPair.put(uniqueKey, kiloCycleLead);
|
|
|
|
+ }
|
|
|
|
+ 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));
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), naturalDateDistance);
|
|
|
|
+ bomLeadPair.put(uniqueKey, natualDateLead);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 找出距离0最近的数,作为工单的最近保养距离数据
|
|
|
|
+ Object closet = chooseNearestDistance(runningTimeDistance, runningKiloDistance, naturalDateDistance);
|
|
|
|
+ Map<String, Object> tempDistance = new HashMap<>();
|
|
|
|
+ if (closet == runningTimeDistance) {
|
|
|
|
+ tempDistance.put("H", closet);
|
|
|
|
+ } else if (closet == runningKiloDistance) {
|
|
|
|
+ tempDistance.put("KM", closet);
|
|
|
|
+ } else if (closet == naturalDateDistance) {
|
|
|
|
+ tempDistance.put("D", closet);
|
|
|
|
+ }
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 以设备id 为维度 统计每个保养工单明细中 距离最近的保养数据
|
|
|
|
+ resultMap = findClosestToZero(orderDistancePair);
|
|
|
|
+ // 根据保养项规则应该生成保养工单的设备id集合
|
|
|
|
+ Set<Long> shouldWorkOrderFlags = new HashSet<>();
|
|
|
|
+ // 找出设备保养项距离保养最小值对应的 提前量
|
|
|
|
+ if (CollUtil.isNotEmpty(resultMap)) {
|
|
|
|
+ resultMap.forEach((k,v) -> {
|
|
|
|
+ // k设备id v距离保养最小值(带单位)
|
|
|
|
+ // 去掉v中带的单位 310 D -61.00 H
|
|
|
|
+ String[] distanceStrs = v.split(" ");
|
|
|
|
+ BigDecimal tempDistance = new BigDecimal(distanceStrs[0]);
|
|
|
|
+ if (tempDistance.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
+ shouldWorkOrderFlags.add(k);
|
|
|
|
+ }
|
|
|
|
+ if (CollUtil.isNotEmpty(bomLeadPair)) {
|
|
|
|
+ bomLeadPair.forEach((key,value) -> {
|
|
|
|
+ // key设备id-保养项id-距离保养值 value提前量
|
|
|
|
+ String[] uniqueKeyStrs = key.split("-");
|
|
|
|
+ if (uniqueKeyStrs.length == 3) {
|
|
|
|
+ if (String.valueOf(k).equals(uniqueKeyStrs[0]) && distanceStrs[0].equals(uniqueKeyStrs[2])
|
|
|
|
+ && tempDistance.compareTo(BigDecimal.ZERO)>=0 && tempDistance.compareTo(value)<=0 ) {
|
|
|
|
+ shouldWorkOrderFlags.add(k);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ // 对集合 resultMap 中所有数据进行排序 按照 map 的value值 去除后面的 字符后 升序排列
|
|
|
|
+ // 排序后输出一个 List<Long> 类型的集合,排序对应上面的排序规则
|
|
|
|
+ List<Long> sortedDeviceIds = sortByNumericTimeoutValue(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, sortedDeviceIds);
|
|
|
|
+ // 处理当前分页数据 拼接上已经排序的 筛选出的设备保养项 最小保养距离
|
|
|
|
+ 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 字段
|
|
|
|
+ List<IotDeviceRespVO> page = iotDeviceMapper.timeoutDeviceMaintenances(pageReqVO, alarmDeviceIds, ids);
|
|
|
|
+ if (CollUtil.isNotEmpty(page)) {
|
|
|
|
+ page.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 (shouldWorkOrderFlags.contains(device.getId())) {
|
|
|
|
+ device.setShouldWorkOrder(true);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ return page;
|
|
|
|
+ } catch (Exception exception) {
|
|
|
|
+ if (exception.getMessage().contains("Table does not exist")) {
|
|
|
|
+ return new ArrayList<>();
|
|
|
|
+ }
|
|
|
|
+ throw exception;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public List<IotDeviceMainTimeoutVO> timeoutDeviceMainDistances(IotMainWorkOrderPageReqVO pageReqVO) {
|
|
|
|
+ // key公司级部门名称 value公司下所有保养超时的设备数量
|
|
|
|
+ Map<String, Integer> companyNameTimeoutDevices = new HashMap<>();
|
|
|
|
+ List<IotDeviceMainTimeoutVO> companyMainTimeoutDevices = new ArrayList<>();
|
|
|
|
+ // 所有保养计划 明细中待保养的最近距离 里程/时间/自然日
|
|
|
|
+ DataPermissionUtils.executeIgnore(() -> {
|
|
|
|
+ List<IotMainWorkOrderBomDO> workOrderBomS = new ArrayList<>();
|
|
|
|
+ Set<Long> deviceIds = CollUtil.isEmpty(workOrderBomS)
|
|
|
|
+ ? new HashSet<>()
|
|
|
|
+ : workOrderBomS.stream()
|
|
|
|
+ .map(IotMainWorkOrderBomDO::getDeviceId) // 获取 deviceId
|
|
|
|
+ .filter(Objects::nonNull) // 过滤非空值
|
|
|
|
+ .collect(Collectors.toSet()); // 收集到 Set 中
|
|
|
|
+ Set<Long> orderDeviceIds = new HashSet<>();
|
|
|
|
+ orderDeviceIds.addAll(deviceIds);
|
|
|
|
+ // 查询保养计划明细中不包含 deviceIds 的设备id集合
|
|
|
|
+ List<IotMaintenanceBomDO> mainBomS = new ArrayList<>();
|
|
|
|
+ Set<Long> mainBomDeviceIds = new HashSet<>();
|
|
|
|
+ IotMaintenanceBomPageReqVO mainBomReqVO = new IotMaintenanceBomPageReqVO();
|
|
|
|
+ if (CollUtil.isNotEmpty(deviceIds)) {
|
|
|
|
+ mainBomReqVO.setDeviceIds(new ArrayList<>(deviceIds));
|
|
|
|
+ mainBomS = iotMaintenanceBomMapper.selectAlarmList(mainBomReqVO);
|
|
|
|
+ } else {
|
|
|
|
+ mainBomS = iotMaintenanceBomMapper.selectList(mainBomReqVO);
|
|
|
|
+ }
|
|
|
|
+ Set<String> boundedMultiAttrNames = new HashSet<>();
|
|
|
|
+ Set<Long> deviceCategoryIds = new HashSet<>();
|
|
|
|
+ Map<Long, Long> deviceCategoryPair = new HashMap<>();
|
|
|
|
+ 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());
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ // 查询所有设备类别id
|
|
|
|
+ // 组装bom关联的设备信息
|
|
|
|
+ Map<Long, IotDeviceRespVO> deviceMap = iotDeviceService.getDeviceMap(convertListByFlatMap(mainBomS,
|
|
|
|
+ bom -> Stream.of(bom.getDeviceId())));
|
|
|
|
+ if (CollUtil.isNotEmpty(deviceMap)) {
|
|
|
|
+ deviceMap.forEach((k,v) -> {
|
|
|
|
+ deviceCategoryIds.add(v.getAssetClass());
|
|
|
|
+ deviceCategoryPair.put(k, v.getAssetClass());
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ deviceIds.addAll(mainBomDeviceIds);
|
|
|
|
+ if (CollUtil.isEmpty(deviceIds)){
|
|
|
|
+ // 没有设备信息,返回空列表
|
|
|
|
+ return companyMainTimeoutDevices;
|
|
|
|
+ }
|
|
|
|
+ // 查询 运行记录模板中包含多个累计 时长 公里数 属性的集合
|
|
|
|
+ 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));
|
|
|
|
+ Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap =
|
|
|
|
+ iotDeviceRunLogService.getDeviceRunLogMapAlone(new ArrayList<>(deviceIds), new ArrayList<>(deviceCategoryIds), deviceCategoryPair);
|
|
|
|
+ // 以设备为维度统计每个设备相关的保养项的最近保养距离 key设备id value设备下每个保养项的的最小保养距离集合
|
|
|
|
+ Map<Long, List<Map<String, Object>>> orderDistancePair = new HashMap<>();
|
|
|
|
+ // 设备保养明细 key设备id value设备保养工单明细下所有保养规则数据最小值
|
|
|
|
+ Map<Long, String> resultMap = new HashMap<>();
|
|
|
|
+ // 记录保养项的 提前量 key设备id-保养项id-距离保养值 value提前量
|
|
|
|
+ Map<String, BigDecimal> bomLeadPair = new HashMap<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(mainBomS)) {
|
|
|
|
+ // 遍历保养计划明细 计算 保养计划中的设备 的最近的保养时间
|
|
|
|
+ for (IotMaintenanceBomDO bom : mainBomS) {
|
|
|
|
+ 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));
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), runningTimeDistance);
|
|
|
|
+ bomLeadPair.put(uniqueKey, timePeriodLead);
|
|
|
|
+ }
|
|
|
|
+ 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));
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), runningKiloDistance);
|
|
|
|
+ bomLeadPair.put(uniqueKey, kiloCycleLead);
|
|
|
|
+ }
|
|
|
|
+ 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));
|
|
|
|
+ String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId(), naturalDateDistance);
|
|
|
|
+ bomLeadPair.put(uniqueKey, natualDateLead);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 找出距离0最近的数,作为工单的最近保养距离数据
|
|
|
|
+ Object closet = chooseNearestDistance(runningTimeDistance, runningKiloDistance, naturalDateDistance);
|
|
|
|
+ Map<String, Object> tempDistance = new HashMap<>();
|
|
|
|
+ if (closet == runningTimeDistance) {
|
|
|
|
+ tempDistance.put("H", closet);
|
|
|
|
+ } else if (closet == runningKiloDistance) {
|
|
|
|
+ tempDistance.put("KM", closet);
|
|
|
|
+ } else if (closet == naturalDateDistance) {
|
|
|
|
+ tempDistance.put("D", closet);
|
|
|
|
+ }
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 以设备id 为维度 统计每个保养工单明细中 距离最近的保养数据
|
|
|
|
+ resultMap = findClosestToZero(orderDistancePair);
|
|
|
|
+ // 根据保养项规则应该生成保养工单的设备id集合
|
|
|
|
+ Set<Long> shouldWorkOrderFlags = new HashSet<>();
|
|
|
|
+ // 找出设备保养项距离保养最小值对应的 提前量
|
|
|
|
+ if (CollUtil.isNotEmpty(resultMap)) {
|
|
|
|
+ resultMap.forEach((k,v) -> {
|
|
|
|
+ // k设备id v距离保养最小值(带单位)
|
|
|
|
+ // 去掉v中带的单位 310 D -61.00 H
|
|
|
|
+ String[] distanceStrs = v.split(" ");
|
|
|
|
+ BigDecimal tempDistance = new BigDecimal(distanceStrs[0]);
|
|
|
|
+ if (tempDistance.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
+ shouldWorkOrderFlags.add(k);
|
|
|
|
+ }
|
|
|
|
+ if (CollUtil.isNotEmpty(bomLeadPair)) {
|
|
|
|
+ bomLeadPair.forEach((key,value) -> {
|
|
|
|
+ // key设备id-保养项id-距离保养值 value提前量
|
|
|
|
+ String[] uniqueKeyStrs = key.split("-");
|
|
|
|
+ if (uniqueKeyStrs.length == 3) {
|
|
|
|
+ if (String.valueOf(k).equals(uniqueKeyStrs[0]) && distanceStrs[0].equals(uniqueKeyStrs[2])
|
|
|
|
+ && tempDistance.compareTo(BigDecimal.ZERO)>=0 && tempDistance.compareTo(value)<=0 ) {
|
|
|
|
+ shouldWorkOrderFlags.add(k);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ // 对集合 resultMap 中所有数据进行排序 按照 map 的value值 去除后面的 字符后 升序排列
|
|
|
|
+ // 排序后输出一个 List<Long> 类型的集合,排序对应上面的排序规则
|
|
|
|
+ // 筛选出所有 保养距离 小于0 的设备
|
|
|
|
+ List<Long> sortedDeviceIds = sortByNumericTimeoutValue(resultMap);
|
|
|
|
+ try {
|
|
|
|
+ // 查询所有公司级别的组织部门
|
|
|
|
+ Set<Long> parentIds = new HashSet<>();
|
|
|
|
+ parentIds.add(DeptDO.PARENT_ID_ROOT);
|
|
|
|
+ // 公司级部门
|
|
|
|
+ List<DeptDO> theFirstLevelDepts = deptMapper.selectListByParentId(parentIds);
|
|
|
|
+ AtomicReference<List<DeptDO>> theSecondLevelDepts = new AtomicReference<>(new ArrayList<>());
|
|
|
|
+ if (CollUtil.isNotEmpty(theFirstLevelDepts)) {
|
|
|
|
+ theFirstLevelDepts.forEach(dept -> {
|
|
|
|
+ parentIds.clear();
|
|
|
|
+ parentIds.add(dept.getId());
|
|
|
|
+ theSecondLevelDepts.set(deptMapper.selectListByParentId(parentIds));
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ Map<Long, String> firstLevelDeptNamePair = new HashMap<>();
|
|
|
|
+ // key子部门id value公司级部门id
|
|
|
|
+ Map<Long, Long> deptCompanyPair = new HashMap<>();
|
|
|
|
+ if (CollUtil.isNotEmpty(theSecondLevelDepts.get())) {
|
|
|
|
+ AtomicReference<Set<Long>> ids = new AtomicReference<>(new HashSet<>());
|
|
|
|
+ theSecondLevelDepts.get().forEach(dept -> {
|
|
|
|
+ // 对部门名称进行 处理 去掉多语言部分
|
|
|
|
+ String deptName = dept.getName();
|
|
|
|
+ deptName = StrUtil.subBefore(deptName, "~~", false);
|
|
|
|
+ firstLevelDeptNamePair.put(dept.getId(), deptName);
|
|
|
|
+ // 查询每个公司下所有子部门 将子部门与公司建立对应关系
|
|
|
|
+ ids.set(deptService.getChildDeptIdListFromCache(dept.getId()));
|
|
|
|
+ ids.get().add(dept.getId());
|
|
|
|
+ if (CollUtil.isNotEmpty(ids.get())) {
|
|
|
|
+ ids.get().forEach(deptId -> {
|
|
|
|
+ deptCompanyPair.put(deptId, dept.getId());
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ ids.get().clear();;
|
|
|
|
+ });
|
|
|
|
+ // 查询 排序后的保养距离超时的 sortedDeviceIds 集合中 每个设备 对应的部门
|
|
|
|
+ IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
|
|
|
|
+ deviceReqVO.setDeviceIds(sortedDeviceIds);
|
|
|
|
+ List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
|
|
|
|
+ // key公司级部门id value公司下所有保养超时的设备数量
|
|
|
|
+ Map<Long, Integer> companyTimeoutDevices = new HashMap<>();
|
|
|
|
+
|
|
|
|
+ if (CollUtil.isNotEmpty(devices)) {
|
|
|
|
+ devices.forEach(device -> {
|
|
|
|
+ if (deptCompanyPair.containsKey(device.getDeptId())) {
|
|
|
|
+ Long tempCompanyDeptId = deptCompanyPair.get(device.getDeptId());
|
|
|
|
+ if (companyTimeoutDevices.containsKey(tempCompanyDeptId)) {
|
|
|
|
+ Integer tempCount = companyTimeoutDevices.get(tempCompanyDeptId);
|
|
|
|
+ companyTimeoutDevices.put(tempCompanyDeptId, ++tempCount);
|
|
|
|
+ } else {
|
|
|
|
+ companyTimeoutDevices.put(tempCompanyDeptId, 1);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ if (CollUtil.isNotEmpty(companyTimeoutDevices)) {
|
|
|
|
+ companyTimeoutDevices.forEach((k,v) -> {
|
|
|
|
+ // key公司级部门id value公司下所有保养超时的设备数量
|
|
|
|
+ if (firstLevelDeptNamePair.containsKey(k)) {
|
|
|
|
+ String companyName = firstLevelDeptNamePair.get(k);
|
|
|
|
+ companyNameTimeoutDevices.put(companyName, v);
|
|
|
|
+ IotDeviceMainTimeoutVO timeoutDevice = new IotDeviceMainTimeoutVO();
|
|
|
|
+ timeoutDevice.setDeptName(companyName);
|
|
|
|
+ timeoutDevice.setDeptId(k);
|
|
|
|
+ timeoutDevice.setCount(v);
|
|
|
|
+ companyMainTimeoutDevices.add(timeoutDevice);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return companyMainTimeoutDevices;
|
|
|
|
+ } catch (Exception exception) {
|
|
|
|
+ return new HashMap<>();
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ return companyMainTimeoutDevices;
|
|
|
|
+ }
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public PageResult<IotDeviceRespVO> maintenanceSearch(IotMainWorkOrderPageReqVO pageReqVO) {
|
|
public PageResult<IotDeviceRespVO> maintenanceSearch(IotMainWorkOrderPageReqVO pageReqVO) {
|
|
// 所有保养计划 明细中待保养的最近距离 里程/时间/自然日
|
|
// 所有保养计划 明细中待保养的最近距离 里程/时间/自然日
|
|
@@ -1064,6 +1590,41 @@ public class IotMainWorkOrderServiceImpl implements IotMainWorkOrderService {
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 筛选出 保养距离 超时的所有设备
|
|
|
|
+ * 排序 Map<Long, String> 中的元素 删除 类似 D、 H、 KM 后进行升序排列
|
|
|
|
+ * @param map
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private List<Long> sortByNumericTimeoutValue(Map<Long, String> map) {
|
|
|
|
+ return map.entrySet().stream()
|
|
|
|
+ .map(entry -> {
|
|
|
|
+ String[] parts = entry.getValue().split("\\s+");
|
|
|
|
+ if (parts.length < 2) {
|
|
|
|
+ return new AbstractMap.SimpleEntry<>(entry.getKey(), Double.MAX_VALUE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ BigDecimal value = new BigDecimal(parts[0]);
|
|
|
|
+ // 单位转换:H→天,KM/D保持不变
|
|
|
|
+ if ("H".equals(parts[1])) {
|
|
|
|
+ value = value.divide(BigDecimal.valueOf(24), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
|
+ }
|
|
|
|
+ return new AbstractMap.SimpleEntry<>(entry.getKey(), value.doubleValue());
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
+ return new AbstractMap.SimpleEntry<>(entry.getKey(), Double.MAX_VALUE);
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ // 2. 过滤出转换后数值小于0的数据
|
|
|
|
+ .filter(entry -> entry.getValue() < 0)
|
|
|
|
+ .sorted(Comparator
|
|
|
|
+ .<AbstractMap.SimpleEntry<Long, Double>>comparingDouble(AbstractMap.SimpleEntry::getValue) // 按转换值升序
|
|
|
|
+ .thenComparingLong(AbstractMap.SimpleEntry::getKey) // 值相同时按键升序
|
|
|
|
+ )
|
|
|
|
+ .map(AbstractMap.SimpleEntry::getKey)
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 找出每个设备对应的bom保养项集合中 距离保养最短的 数据
|
|
* 找出每个设备对应的bom保养项集合中 距离保养最短的 数据
|
|
* @param orderDistancePair
|
|
* @param orderDistancePair
|