| | |
| | | import com.zy.core.enums.WrkStsType; |
| | | import com.zy.core.model.StationObjModel; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | import com.zy.core.move.StationMoveCoordinator; |
| | | import com.zy.core.move.StationMoveSession; |
| | | import com.zy.core.thread.StationThread; |
| | | import com.zy.core.utils.CrnOperateProcessUtils; |
| | | import com.zy.common.utils.RedisUtil; |
| | | import com.zy.core.enums.RedisKeyType; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.Comparator; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @Component |
| | | public class InboundCrnMoveDispatchScheduler { |
| | |
| | | private final CommonService commonService; |
| | | private final BasCrnpService basCrnpService; |
| | | private final CrnOperateProcessUtils crnOperateProcessUtils; |
| | | private final StationMoveCoordinator stationMoveCoordinator; |
| | | private final RedisUtil redisUtil; |
| | | |
| | | public InboundCrnMoveDispatchScheduler(WrkMastService wrkMastService, |
| | | BasStationService basStationService, |
| | | CommonService commonService, |
| | | BasCrnpService basCrnpService, |
| | | CrnOperateProcessUtils crnOperateProcessUtils, |
| | | StationMoveCoordinator stationMoveCoordinator, |
| | | RedisUtil redisUtil) { |
| | | CrnOperateProcessUtils crnOperateProcessUtils) { |
| | | this.wrkMastService = wrkMastService; |
| | | this.basStationService = basStationService; |
| | | this.commonService = commonService; |
| | | this.basCrnpService = basCrnpService; |
| | | this.crnOperateProcessUtils = crnOperateProcessUtils; |
| | | this.stationMoveCoordinator = stationMoveCoordinator; |
| | | this.redisUtil = redisUtil; |
| | | } |
| | | |
| | | @Scheduled(fixedDelay = 1000L) |
| | |
| | | |
| | | // 同堆垛机没有需要参与当前调度判断的出库任务时,优先直接到当前入库任务取货位等待。 |
| | | if (!hasBlockingOutboundTask(crnNo)) { |
| | | boolean dispatched = crnOperateProcessUtils.dispatchCrnMove(crnNo, inboundPickupLocNo); |
| | | boolean dispatched = crnOperateProcessUtils.dispatchCrnMove(crnNo, inboundPickupLocNo, true); |
| | | if (dispatched) { |
| | | News.info("检测到仅有入库任务,已触发堆垛机直接移动到入库任务取货位等待,工作号={},堆垛机号={},取货位={}", |
| | | wrkMast.getWrkNo(), crnNo, inboundPickupLocNo); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | StationMoveSession session = stationMoveCoordinator == null ? null : stationMoveCoordinator.loadSession(wrkMast.getWrkNo()); |
| | | if (!isInboundCrnMoveDispatchWindow(wrkMast, session)) { |
| | | return; |
| | | } |
| | | |
| | | boolean dispatched = crnOperateProcessUtils.dispatchCrnMove(crnNo, inboundPickupLocNo); |
| | | if (dispatched) { |
| | | News.info("入库任务即将到达取货位,已触发堆垛机预移车,工作号={},堆垛机号={},取货位={}", |
| | | wrkMast.getWrkNo(), crnNo, inboundPickupLocNo); |
| | | } else { |
| | | News.taskInfo(wrkMast.getWrkNo(), "当前存在阻塞入库预移车的出库任务,暂不触发堆垛机预移车"); |
| | | } |
| | | } |
| | | |
| | |
| | | return true; |
| | | } |
| | | |
| | | String activeBatch = resolveActiveOutboundBatch(pendingOutboundTasks); |
| | | if (Cools.isEmpty(activeBatch)) { |
| | | return true; |
| | | } |
| | | |
| | | return pendingOutboundTasks.stream() |
| | | .filter(this::isBatchTaskWithSeq) |
| | | .filter(task -> isWithinCurrentBatchExecuteWindow(task, pendingOutboundTasks)) |
| | | .filter(this::isCrnMoveBlockingOutboundTask) |
| | | .anyMatch(task -> Objects.equals(activeBatch, task.getBatch())); |
| | | } |
| | | |
| | | private String resolveActiveOutboundBatch(List<WrkMast> pendingOutboundTasks) { |
| | | if (pendingOutboundTasks == null || pendingOutboundTasks.isEmpty()) { |
| | | return null; |
| | | } |
| | | Set<String> activeBatchSet = pendingOutboundTasks.stream() |
| | | .filter(this::isBatchTaskWithSeq) |
| | | .filter(task -> !Objects.equals(task.getWrkSts(), WrkStsType.NEW_OUTBOUND.sts)) |
| | | .map(WrkMast::getBatch) |
| | | .filter(batch -> !Cools.isEmpty(batch)) |
| | | .collect(Collectors.toSet()); |
| | | if (activeBatchSet.size() != 1) { |
| | | return null; |
| | | } |
| | | return activeBatchSet.iterator().next(); |
| | | .filter(crnOperateProcessUtils::canOutboundTaskExecuteInCurrentBatchWindow) |
| | | .findAny() |
| | | .isPresent(); |
| | | } |
| | | |
| | | private boolean isBatchTaskWithSeq(WrkMast wrkMast) { |
| | |
| | | return Objects.equals(wrkMast.getWrkSts(), WrkStsType.NEW_OUTBOUND.sts) |
| | | || Objects.equals(wrkMast.getWrkSts(), WrkStsType.OUTBOUND_RUN.sts) |
| | | || Objects.equals(wrkMast.getWrkSts(), WrkStsType.OUTBOUND_MANUAL.sts); |
| | | } |
| | | |
| | | private boolean isWithinCurrentBatchExecuteWindow(WrkMast wrkMast, List<WrkMast> pendingOutboundTasks) { |
| | | if (!isBatchTaskWithSeq(wrkMast) || pendingOutboundTasks == null || pendingOutboundTasks.isEmpty()) { |
| | | return false; |
| | | } |
| | | int batchRunningLimit = getSystemConfigInt("crnOutBatchRunningLimit", 5); |
| | | if (batchRunningLimit <= 0) { |
| | | return true; |
| | | } |
| | | List<WrkMast> sameBatchTasks = pendingOutboundTasks.stream() |
| | | .filter(this::isBatchTaskWithSeq) |
| | | .filter(task -> Objects.equals(task.getBatch(), wrkMast.getBatch())) |
| | | .sorted(Comparator.comparing(WrkMast::getBatchSeq).thenComparing(WrkMast::getWrkNo)) |
| | | .collect(Collectors.toList()); |
| | | if (sameBatchTasks.isEmpty()) { |
| | | return false; |
| | | } |
| | | int windowSize = Math.min(batchRunningLimit, sameBatchTasks.size()); |
| | | for (int i = 0; i < windowSize; i++) { |
| | | WrkMast current = sameBatchTasks.get(i); |
| | | if (current != null && Objects.equals(current.getWrkNo(), wrkMast.getWrkNo())) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private int getSystemConfigInt(String code, int defaultValue) { |
| | | Object systemConfigMapObj = redisUtil == null ? null : redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); |
| | | if (!(systemConfigMapObj instanceof HashMap)) { |
| | | return defaultValue; |
| | | } |
| | | try { |
| | | HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj; |
| | | return Integer.parseInt(systemConfigMap.getOrDefault(code, String.valueOf(defaultValue))); |
| | | } catch (Exception ignore) { |
| | | return defaultValue; |
| | | } |
| | | } |
| | | |
| | | private boolean isInboundCrnMoveDispatchWindow(WrkMast wrkMast, StationMoveSession session) { |
| | | if (wrkMast == null || session == null || !session.isActive() || wrkMast.getStaNo() == null) { |
| | | return false; |
| | | } |
| | | List<Integer> fullPathStationIds = session.getFullPathStationIds(); |
| | | Integer currentStationId = session.getCurrentStationId(); |
| | | if (fullPathStationIds == null || fullPathStationIds.isEmpty() || currentStationId == null) { |
| | | return false; |
| | | } |
| | | int currentIndex = fullPathStationIds.lastIndexOf(currentStationId); |
| | | if (currentIndex < 0 || currentIndex >= fullPathStationIds.size() - 1) { |
| | | return false; |
| | | } |
| | | int remainingStationCount = fullPathStationIds.size() - currentIndex - 1; |
| | | if (remainingStationCount != 1) { |
| | | return false; |
| | | } |
| | | Integer nextStationId = fullPathStationIds.get(currentIndex + 1); |
| | | return Objects.equals(nextStationId, wrkMast.getStaNo()); |
| | | } |
| | | } |