| | |
| | | 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.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) { |
| | | this.wrkMastService = wrkMastService; |
| | | this.basStationService = basStationService; |
| | | this.commonService = commonService; |
| | | this.basCrnpService = basCrnpService; |
| | | this.crnOperateProcessUtils = crnOperateProcessUtils; |
| | | this.stationMoveCoordinator = stationMoveCoordinator; |
| | | this.redisUtil = redisUtil; |
| | | } |
| | | |
| | | @Scheduled(fixedDelay = 1000L) |
| | |
| | | return; |
| | | } |
| | | |
| | | // 同堆垛机没有未完成出库任务时,优先直接到当前入库任务取货位等待。 |
| | | if (!hasPendingOutboundTask(crnNo)) { |
| | | // 同堆垛机没有需要参与当前调度判断的出库任务时,优先直接到当前入库任务取货位等待。 |
| | | if (!hasBlockingOutboundTask(crnNo)) { |
| | | boolean dispatched = crnOperateProcessUtils.dispatchCrnMove(crnNo, inboundPickupLocNo); |
| | | 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 null; |
| | | } |
| | | |
| | | private boolean hasPendingOutboundTask(Integer crnNo) { |
| | | private boolean hasBlockingOutboundTask(Integer crnNo) { |
| | | if (crnNo == null) { |
| | | return false; |
| | | } |
| | | return wrkMastService.count(new QueryWrapper<WrkMast>() |
| | | List<WrkMast> pendingOutboundTasks = wrkMastService.list(new QueryWrapper<WrkMast>() |
| | | .eq("crn_no", crnNo) |
| | | .eq("io_type", WrkIoType.OUT.id) |
| | | .in("wrk_sts", |
| | |
| | | WrkStsType.OUTBOUND_RUN_COMPLETE.sts, |
| | | WrkStsType.STATION_RUN.sts, |
| | | WrkStsType.STATION_RUN_COMPLETE.sts, |
| | | WrkStsType.OUTBOUND_MANUAL.sts)) > 0; |
| | | WrkStsType.OUTBOUND_MANUAL.sts) |
| | | .orderByAsc("wrk_no")); |
| | | if (pendingOutboundTasks == null || pendingOutboundTasks.isEmpty()) { |
| | | return false; |
| | | } |
| | | |
| | | // 非批次任务或缺少批次序号的任务仍按原逻辑处理,避免放宽到无法确认执行顺序的出库任务。 |
| | | boolean hasNonBatchTask = pendingOutboundTasks.stream().anyMatch(task -> !isBatchTaskWithSeq(task)); |
| | | if (hasNonBatchTask) { |
| | | return true; |
| | | } |
| | | |
| | | return pendingOutboundTasks.stream() |
| | | .filter(this::isBatchTaskWithSeq) |
| | | .filter(task -> isWithinCurrentBatchExecuteWindow(task, pendingOutboundTasks)) |
| | | .filter(this::isCrnMoveBlockingOutboundTask) |
| | | .findAny() |
| | | .isPresent(); |
| | | } |
| | | |
| | | private boolean isInboundCrnMoveDispatchWindow(WrkMast wrkMast, StationMoveSession session) { |
| | | if (wrkMast == null || session == null || !session.isActive() || wrkMast.getStaNo() == null) { |
| | | private boolean isBatchTaskWithSeq(WrkMast wrkMast) { |
| | | return wrkMast != null |
| | | && Objects.equals(wrkMast.getIoType(), WrkIoType.OUT.id) |
| | | && !Cools.isEmpty(wrkMast.getBatch()) |
| | | && wrkMast.getBatchSeq() != null; |
| | | } |
| | | |
| | | private boolean isCrnMoveBlockingOutboundTask(WrkMast wrkMast) { |
| | | if (wrkMast == null || wrkMast.getWrkSts() == null) { |
| | | return false; |
| | | } |
| | | List<Integer> fullPathStationIds = session.getFullPathStationIds(); |
| | | Integer currentStationId = session.getCurrentStationId(); |
| | | if (fullPathStationIds == null || fullPathStationIds.isEmpty() || currentStationId == null) { |
| | | 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 currentIndex = fullPathStationIds.lastIndexOf(currentStationId); |
| | | if (currentIndex < 0 || currentIndex >= fullPathStationIds.size() - 1) { |
| | | 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 remainingStationCount = fullPathStationIds.size() - currentIndex - 1; |
| | | if (remainingStationCount != 1) { |
| | | 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; |
| | | } |
| | | } |
| | | Integer nextStationId = fullPathStationIds.get(currentIndex + 1); |
| | | return Objects.equals(nextStationId, wrkMast.getStaNo()); |
| | | 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; |
| | | } |
| | | } |
| | | } |