package com.zy.core.network.fake; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.core.common.SpringUtils; import com.zy.asrs.entity.DeviceConfig; import com.zy.common.utils.RedisUtil; import com.zy.core.News; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.StationCommandType; import com.zy.core.model.CommandResponse; import com.zy.core.model.command.StationCommand; import com.zy.core.network.api.ZyStationConnectApi; import com.zy.core.network.entity.ZyStationStatusEntity; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class ZyStationFakeSegConnect implements ZyStationConnectApi { private static final long DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS = 10000L; private static final long WAIT_SEGMENT_TIMEOUT_MS = 30000L; private static final String STATUS_WAITING = "WAITING"; private static final String STATUS_RUNNING = "RUNNING"; private static final String STATUS_BLOCKED = "BLOCKED"; private static final String STATUS_CANCELLED = "CANCELLED"; private static final String STATUS_TIMEOUT = "TIMEOUT"; private static final String STATUS_FINISHED = "FINISHED"; private final Map stationLocks = new ConcurrentHashMap(); private final Map> deviceStatusMap = new ConcurrentHashMap>(); private final Map deviceConfigMap = new ConcurrentHashMap(); private final Map> taskQueues = new ConcurrentHashMap>(); private final Map taskLastUpdateTime = new ConcurrentHashMap(); private final Map taskRunning = new ConcurrentHashMap(); private final ExecutorService executor = Executors.newCachedThreadPool(); private RedisUtil redisUtil; public void addFakeConnect(DeviceConfig deviceConfig, RedisUtil redisUtil) { this.redisUtil = redisUtil; if (deviceConfigMap.containsKey(deviceConfig.getDeviceNo())) { return; } deviceConfigMap.put(deviceConfig.getDeviceNo(), deviceConfig); deviceStatusMap.put(deviceConfig.getDeviceNo(), new CopyOnWriteArrayList()); } @Override public boolean connect() { return true; } @Override public boolean disconnect() { executor.shutdownNow(); return true; } @Override public List getStatus(Integer deviceNo) { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return new ArrayList(); } DeviceConfig deviceConfig = deviceConfigMap.get(deviceNo); if (statusList.isEmpty() && deviceConfig != null) { List init = JSON.parseArray(deviceConfig.getFakeInitStatus(), ZyStationStatusEntity.class); if (init != null) { statusList.addAll(init); for (ZyStationStatusEntity status : statusList) { status.setAutoing(true); status.setLoading(false); status.setInEnable(true); status.setOutEnable(true); status.setEmptyMk(false); status.setFullPlt(false); status.setRunBlock(false); status.setPalletHeight(0); status.setError(0); status.setBarcode(""); } } } return statusList; } @Override public CommandResponse sendCommand(Integer deviceNo, StationCommand command) { Integer taskNo = command.getTaskNo(); if (taskNo == null) { return new CommandResponse(false, "任务号为空"); } if (command.getCommandType() != StationCommandType.MOVE) { handleCommand(deviceNo, command); return new CommandResponse(true, "命令已受理(异步执行)"); } if (isDirectMoveCommand(command)) { handleDirectMoveCommand(deviceNo, command); return new CommandResponse(true, "命令已受理(异步执行)"); } taskQueues.computeIfAbsent(taskNo, key -> new LinkedBlockingQueue()).offer(command); taskLastUpdateTime.put(taskNo, System.currentTimeMillis()); if (taskRunning.putIfAbsent(taskNo, true) == null) { executor.submit(new Runnable() { @Override public void run() { runTaskLoop(deviceNo, taskNo); } }); } return new CommandResponse(true, "命令已受理(异步执行)"); } @Override public CommandResponse sendOriginCommand(String address, short[] data) { return new CommandResponse(true, "原始命令已受理(异步执行)"); } @Override public byte[] readOriginCommand(String address, int length) { return new byte[0]; } private boolean isDirectMoveCommand(StationCommand command) { if (command == null || command.getCommandType() != StationCommandType.MOVE) { return false; } List path = command.getNavigatePath(); return (path == null || path.isEmpty()) && command.getStationId() != null && command.getStationId().equals(command.getTargetStaNo()); } private void handleDirectMoveCommand(Integer deviceNo, StationCommand command) { Integer taskNo = command.getTaskNo(); Integer stationId = command.getStationId(); Integer targetStationId = command.getTargetStaNo(); if (taskNo != null && taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId != null && stationId.equals(targetStationId)) { generateStationData(deviceNo, taskNo, stationId, targetStationId); } TaskRuntimeContext context = new TaskRuntimeContext(taskNo, getThreadImpl(deviceNo)); context.startStationId = stationId; context.currentStationId = stationId; context.finalTargetStationId = targetStationId; context.initialized = true; context.status = STATUS_RUNNING; context.appendStitchedPath(Arrays.asList(stationId)); context.addPassedStation(stationId); context.generateBarcode = checkTaskNoInArea(taskNo); traceEvent(deviceNo, context, "MOVE_INIT", "同站点任务直接到位", buildDetails("stationId", stationId), false); if (context.generateBarcode) { generateStationBarcode(taskNo, stationId, deviceNo); } traceEvent(deviceNo, context, "ARRIVED", "任务已在起点站点完成", buildDetails("barcodeGenerated", context.generateBarcode, "stationId", stationId), false); context.status = STATUS_FINISHED; traceEvent(deviceNo, context, "TASK_END", "任务执行完成", buildDetails("reason", STATUS_FINISHED), true); } private void runTaskLoop(Integer deviceNo, Integer taskNo) { TaskRuntimeContext context = new TaskRuntimeContext(taskNo, getThreadImpl(deviceNo)); try { while (true) { if (Thread.currentThread().isInterrupted()) { if (!isTerminalStatus(context.status)) { context.status = STATUS_CANCELLED; } break; } if (hasTaskReset(taskNo)) { context.status = STATUS_CANCELLED; break; } BlockingQueue commandQueue = taskQueues.get(taskNo); if (commandQueue == null) { break; } StationCommand command = commandQueue.poll(100, TimeUnit.MILLISECONDS); if (command != null) { taskLastUpdateTime.put(taskNo, System.currentTimeMillis()); context.lastCommandAt = System.currentTimeMillis(); handleIncomingSegment(deviceNo, context, command); } if (!context.pendingPathQueue.isEmpty()) { if (!context.initialized || context.currentStationId == null) { initializeTaskPosition(deviceNo, context); continue; } if (!executeNextMove(deviceNo, context)) { break; } continue; } if (handleIdleState(deviceNo, context)) { break; } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); if (!isTerminalStatus(context.status)) { context.status = STATUS_CANCELLED; } } finally { taskQueues.remove(taskNo); taskLastUpdateTime.remove(taskNo); taskRunning.remove(taskNo); if (!isTerminalStatus(context.status)) { context.status = STATUS_FINISHED; } traceEvent(deviceNo, context, "TASK_END", "任务执行结束并清理资源", buildDetails("reason", context.status), true); News.info("[WCS Debug] 任务{}执行结束并清理资源,状态={}", taskNo, context.status); } } private void handleIncomingSegment(Integer deviceNo, TaskRuntimeContext context, StationCommand command) { List newPath = normalizePath(command.getNavigatePath()); Integer lastInQueue = getLastInQueue(context.pendingPathQueue); int startIndex = getPathAppendStartIndex(newPath, context.currentStationId, lastInQueue); context.setStartStationIdIfAbsent(command.getStationId()); if (!context.generateBarcode && checkTaskNoInArea(context.taskNo)) { context.generateBarcode = true; } traceEvent(deviceNo, context, "SEGMENT_RECEIVED", "收到新的路径分段命令", buildDetails("segmentPath", newPath, "appendStartIndex", startIndex, "currentStationId", context.currentStationId, "queueTailStationId", lastInQueue, "commandStationId", command.getStationId(), "commandTargetStationId", command.getTargetStaNo()), false); Integer commandTargetStationId = command.getTargetStaNo(); if (commandTargetStationId != null) { if (!commandTargetStationId.equals(context.finalTargetStationId)) { traceEvent(deviceNo, context, "TARGET_SWITCHED", "任务目标站发生切换: " + context.finalTargetStationId + " -> " + commandTargetStationId, buildDetails("fromTargetStationId", context.finalTargetStationId, "toTargetStationId", commandTargetStationId), false); context.arrivalHandled = false; } context.finalTargetStationId = commandTargetStationId; syncCurrentStationTarget(context.taskNo, context.currentStationId, context.finalTargetStationId); } if (!newPath.isEmpty() && startIndex < 0) { traceEvent(deviceNo, context, "SEGMENT_IGNORED", "路径分段无法与当前运行上下文衔接,已忽略", buildDetails("segmentPath", newPath, "currentStationId", context.currentStationId, "queueTailStationId", lastInQueue, "ignoreReason", "PATH_NOT_CONNECTED"), false); context.latestAppendedPath.clear(); return; } List appendedPath = new ArrayList(); for (int i = startIndex; i < newPath.size(); i++) { Integer stationId = newPath.get(i); context.pendingPathQueue.offer(stationId); appendedPath.add(stationId); } context.appendStitchedPath(appendedPath); if (!appendedPath.isEmpty()) { traceEvent(deviceNo, context, "SEGMENT_APPENDED", "路径分段已追加到待执行队列,队列长度=" + context.pendingPathQueue.size(), buildDetails("segmentPath", newPath, "appendedPath", appendedPath, "appendStartIndex", startIndex, "queueSize", context.pendingPathQueue.size()), false); } } private void initializeTaskPosition(Integer deviceNo, TaskRuntimeContext context) { Integer nextStationId = context.pendingPathQueue.peek(); if (nextStationId == null) { return; } if (context.currentStationId == null) { Integer actualCurrentStationId = findCurrentStationIdByTask(context.taskNo); if (actualCurrentStationId != null) { context.currentStationId = actualCurrentStationId; context.initialized = true; context.status = STATUS_RUNNING; context.blockedStationId = null; Integer actualDeviceNo = getDeviceNoByStationId(actualCurrentStationId); if (actualDeviceNo != null) { clearRunBlock(actualCurrentStationId, actualDeviceNo); } trimPendingPathToCurrent(context.pendingPathQueue, actualCurrentStationId); if (actualCurrentStationId.equals(context.pendingPathQueue.peek())) { context.pendingPathQueue.poll(); } context.addPassedStation(actualCurrentStationId); context.lastStepAt = System.currentTimeMillis(); traceEvent(deviceNo, context, "MOVE_INIT", "任务从当前实际站点恢复执行", buildDetails("stationId", actualCurrentStationId, "recovered", true), false); return; } } context.currentStationId = nextStationId; Integer currentDeviceNo = getDeviceNoByStationId(context.currentStationId); if (currentDeviceNo == null) { context.pendingPathQueue.poll(); return; } boolean result = initStationMove(context.taskNo, context.currentStationId, currentDeviceNo, context.taskNo, context.finalTargetStationId, true, null); if (!result) { sleep(200); return; } context.initialized = true; context.status = STATUS_RUNNING; context.pendingPathQueue.poll(); context.addPassedStation(context.currentStationId); context.lastStepAt = System.currentTimeMillis(); traceEvent(deviceNo, context, "MOVE_INIT", "任务初始化起点站点", buildDetails("stationId", context.currentStationId, "recovered", false), false); sleep(500); } private boolean executeNextMove(Integer deviceNo, TaskRuntimeContext context) { Integer nextStationId = context.pendingPathQueue.peek(); if (nextStationId == null || context.currentStationId == null) { return true; } Integer currentDeviceNo = getDeviceNoByStationId(context.currentStationId); Integer nextDeviceNo = getDeviceNoByStationId(nextStationId); if (currentDeviceNo == null || nextDeviceNo == null) { context.pendingPathQueue.poll(); return true; } boolean moveSuccess = stationMoveToNext(context.taskNo, context.currentStationId, currentDeviceNo, nextStationId, nextDeviceNo, context.taskNo, context.finalTargetStationId); if (moveSuccess) { Integer previousStationId = context.currentStationId; context.currentStationId = nextStationId; context.pendingPathQueue.poll(); context.addPassedStation(nextStationId); context.arrivalHandled = false; context.blockedStationId = null; context.status = STATUS_RUNNING; context.lastStepAt = System.currentTimeMillis(); traceEvent(deviceNo, context, "MOVE_STEP_OK", "任务完成一步站点移动", buildDetails("fromStationId", previousStationId, "toStationId", nextStationId, "remainingPendingPath", context.getPendingStationIds()), false); sleep(1000); return true; } if (!checkTaskNoInArea(context.taskNo) && getFakeAllowCheckBlock() && System.currentTimeMillis() - context.lastStepAt > getFakeRunBlockTimeoutMs()) { boolean blocked = runBlockStation(context.taskNo, context.currentStationId, currentDeviceNo, context.taskNo, context.currentStationId); if (blocked) { context.blockedStationId = context.currentStationId; context.status = STATUS_BLOCKED; context.pendingPathQueue.clear(); traceEvent(deviceNo, context, "RUN_BLOCKED", "任务在当前站点被标记为堵塞", buildDetails("blockedStationId", context.currentStationId), false); return false; } } sleep(500); return true; } private boolean handleIdleState(Integer deviceNo, TaskRuntimeContext context) { if (context.currentStationId != null && context.finalTargetStationId != null && context.currentStationId.equals(context.finalTargetStationId)) { if (!context.arrivalHandled) { boolean barcodeGenerated = false; if (context.generateBarcode) { Integer targetDeviceNo = getDeviceNoByStationId(context.finalTargetStationId); if (targetDeviceNo != null) { barcodeGenerated = generateStationBarcode(context.taskNo, context.finalTargetStationId, targetDeviceNo); } } context.arrivalHandled = true; traceEvent(deviceNo, context, "ARRIVED", "任务到达最终目标站点", buildDetails("stationId", context.currentStationId, "barcodeGenerated", barcodeGenerated), false); } context.status = STATUS_FINISHED; return true; } Long lastTime = taskLastUpdateTime.get(context.taskNo); if (lastTime != null && System.currentTimeMillis() - lastTime > WAIT_SEGMENT_TIMEOUT_MS) { context.status = STATUS_TIMEOUT; traceEvent(deviceNo, context, "WAIT_TIMEOUT", "等待新的路径分段超时", buildDetails("timeoutMs", WAIT_SEGMENT_TIMEOUT_MS, "currentStationId", context.currentStationId, "targetStationId", context.finalTargetStationId), false); return true; } return false; } private List normalizePath(List path) { List result = new ArrayList(); if (path == null) { return result; } for (Integer stationId : path) { if (stationId != null) { result.add(stationId); } } return result; } private void trimPendingPathToCurrent(LinkedBlockingQueue queue, Integer currentStationId) { if (queue == null || currentStationId == null || queue.isEmpty()) { return; } List snapshot = new ArrayList(queue); int index = snapshot.indexOf(currentStationId); if (index <= 0) { return; } for (int i = 0; i < index; i++) { queue.poll(); } } private boolean hasTaskReset(Integer taskNo) { if (redisUtil == null || taskNo == null) { return false; } Object cancel = redisUtil.get(RedisKeyType.DEVICE_STATION_MOVE_RESET.key + taskNo); return cancel != null; } private Integer getLastInQueue(LinkedBlockingQueue queue) { Integer last = null; for (Integer item : queue) { last = item; } return last; } private int getPathAppendStartIndex(List newPath, Integer currentStationId, Integer lastInQueue) { if (newPath == null || newPath.isEmpty()) { return 0; } if (lastInQueue != null) { int idx = newPath.lastIndexOf(lastInQueue); if (idx >= 0) { return idx + 1; } } if (currentStationId != null) { int idx = newPath.lastIndexOf(currentStationId); if (idx >= 0) { return idx + 1; } return -1; } if (lastInQueue != null) { return -1; } return 0; } private void syncCurrentStationTarget(Integer taskNo, Integer currentStationId, Integer targetStationId) { if (currentStationId == null || targetStationId == null) { return; } Integer currentDeviceNo = getDeviceNoByStationId(currentStationId); if (currentDeviceNo == null) { return; } lockStations(currentStationId); try { List statusList = deviceStatusMap.get(currentDeviceNo); if (statusList == null) { return; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); if (currentStatus == null) { return; } if (currentStatus.getTaskNo() != null && currentStatus.getTaskNo() > 0 && !currentStatus.getTaskNo().equals(taskNo) && currentStatus.isLoading()) { return; } updateStationDataInternal(currentStationId, currentDeviceNo, taskNo, targetStationId, null, null, null); } finally { unlockStations(currentStationId); } } @SuppressWarnings("unchecked") private boolean getFakeAllowCheckBlock() { boolean fakeAllowCheckBlock = true; Object systemConfigMapObj = redisUtil == null ? null : redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); if (systemConfigMapObj instanceof Map) { Map systemConfigMap = (Map) systemConfigMapObj; String value = systemConfigMap.get("fakeAllowCheckBlock"); if (value != null && !"Y".equals(value)) { fakeAllowCheckBlock = false; } } return fakeAllowCheckBlock; } private long getFakeRunBlockTimeoutMs() { long timeoutMs = DEFAULT_FAKE_RUN_BLOCK_TIMEOUT_MS; Object systemConfigMapObj = redisUtil == null ? null : redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); if (systemConfigMapObj instanceof Map) { Map systemConfigMap = (Map) systemConfigMapObj; Object value = systemConfigMap.get("fakeRunBlockTimeoutMs"); if (value != null) { try { long parsed = Long.parseLong(String.valueOf(value).trim()); if (parsed > 0) { timeoutMs = parsed; } } catch (Exception ignore) { } } } return timeoutMs; } private void handleCommand(Integer deviceNo, StationCommand command) { News.info("[WCS Debug] 站点仿真模拟(V3)已启动,命令数据={}", JSON.toJSONString(command)); Integer taskNo = command.getTaskNo(); Integer stationId = command.getStationId(); Integer targetStationId = command.getTargetStaNo(); if (command.getCommandType() == StationCommandType.RESET) { resetStation(deviceNo, stationId); return; } if (command.getCommandType() == StationCommandType.WRITE_INFO) { if (command.getBarcode() != null) { updateStationBarcode(deviceNo, stationId, command.getBarcode()); return; } if (taskNo == 9998 && targetStationId == 0) { generateFakeOutStationData(deviceNo, stationId); return; } } if (taskNo != null && taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId != null && stationId.equals(targetStationId)) { generateStationData(deviceNo, taskNo, stationId, targetStationId); } } private void generateFakeOutStationData(Integer deviceNo, Integer stationId) { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return; } ZyStationStatusEntity status = statusList.stream() .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null); if (status == null) { return; } synchronized (status) { status.setLoading(true); } } private void generateStationData(Integer deviceNo, Integer taskNo, Integer stationId, Integer targetStationId) { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return; } ZyStationStatusEntity status = statusList.stream() .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null); if (status == null) { return; } synchronized (status) { status.setTaskNo(taskNo); status.setTargetStaNo(targetStationId); } } private void resetStation(Integer deviceNo, Integer stationId) { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return; } ZyStationStatusEntity status = statusList.stream() .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null); if (status == null) { return; } synchronized (status) { status.setTaskNo(0); status.setLoading(false); status.setBarcode(""); } } private void updateStationBarcode(Integer deviceNo, Integer stationId, String barcode) { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return; } ZyStationStatusEntity status = statusList.stream() .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null); if (status == null) { return; } synchronized (status) { status.setBarcode(barcode); } } private Integer getDeviceNoByStationId(Integer stationId) { for (Map.Entry> entry : deviceStatusMap.entrySet()) { List list = entry.getValue(); if (list == null) { continue; } for (ZyStationStatusEntity entity : list) { if (entity.getStationId() != null && entity.getStationId().equals(stationId)) { return entry.getKey(); } } } return null; } private Integer findCurrentStationIdByTask(Integer taskNo) { for (List list : deviceStatusMap.values()) { if (list == null) { continue; } for (ZyStationStatusEntity entity : list) { if (entity.getTaskNo() != null && entity.getTaskNo().equals(taskNo) && entity.isLoading()) { return entity.getStationId(); } } } return null; } private void sleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } private ReentrantLock getStationLock(Integer stationId) { return stationLocks.computeIfAbsent(stationId, key -> new ReentrantLock()); } private void lockStations(Integer... stationIds) { Integer[] sorted = Arrays.copyOf(stationIds, stationIds.length); Arrays.sort(sorted); for (Integer stationId : sorted) { getStationLock(stationId).lock(); } } private void unlockStations(Integer... stationIds) { Integer[] sorted = Arrays.copyOf(stationIds, stationIds.length); Arrays.sort(sorted); for (int i = sorted.length - 1; i >= 0; i--) { getStationLock(sorted[i]).unlock(); } } private boolean updateStationDataInternal(Integer stationId, Integer deviceNo, Integer taskNo, Integer targetStaNo, Boolean isLoading, String barcode, Boolean runBlock) { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return false; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null); if (currentStatus == null) { return false; } if (taskNo != null) { currentStatus.setTaskNo(taskNo); } if (targetStaNo != null) { currentStatus.setTargetStaNo(targetStaNo); } if (isLoading != null) { currentStatus.setLoading(isLoading); } if (barcode != null) { currentStatus.setBarcode(barcode); } if (runBlock != null) { currentStatus.setRunBlock(runBlock); } return true; } public boolean initStationMove(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo, Integer taskNo, Integer targetStationId, Boolean isLoading, String barcode) { lockStations(currentStationId); try { List statusList = deviceStatusMap.get(currentStationDeviceNo); if (statusList == null) { return false; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); if (currentStatus == null) { return false; } if (currentStatus.getTaskNo() != null && currentStatus.getTaskNo() > 0 && !currentStatus.getTaskNo().equals(taskNo) && currentStatus.isLoading()) { return false; } return updateStationDataInternal(currentStationId, currentStationDeviceNo, taskNo, targetStationId, isLoading, barcode, false); } finally { unlockStations(currentStationId); } } public boolean stationMoveToNext(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo, Integer nextStationId, Integer nextStationDeviceNo, Integer taskNo, Integer targetStaNo) { lockStations(currentStationId, nextStationId); try { List statusList = deviceStatusMap.get(currentStationDeviceNo); List nextStatusList = deviceStatusMap.get(nextStationDeviceNo); if (statusList == null || nextStatusList == null) { return false; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); ZyStationStatusEntity nextStatus = nextStatusList.stream() .filter(item -> item.getStationId().equals(nextStationId)).findFirst().orElse(null); if (currentStatus == null || nextStatus == null) { return false; } if (nextStatus.getTaskNo() != null && nextStatus.getTaskNo() > 0 || nextStatus.isLoading()) { return false; } boolean result = updateStationDataInternal(nextStationId, nextStationDeviceNo, taskNo, targetStaNo, true, null, false); if (!result) { return false; } return updateStationDataInternal(currentStationId, currentStationDeviceNo, 0, 0, false, "", false); } finally { unlockStations(currentStationId, nextStationId); } } public boolean generateStationBarcode(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo) { lockStations(currentStationId); try { List statusList = deviceStatusMap.get(currentStationDeviceNo); if (statusList == null) { return false; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); if (currentStatus == null) { return false; } Random random = new Random(); String barcodeTime = String.valueOf(System.currentTimeMillis()); String barcode = String.valueOf(random.nextInt(10)) + String.valueOf(random.nextInt(10)) + barcodeTime.substring(7); return updateStationDataInternal(currentStationId, currentStationDeviceNo, null, null, null, barcode, null); } finally { unlockStations(currentStationId); } } public boolean clearStation(Integer deviceNo, Integer lockTaskNo, Integer currentStationId) { lockStations(currentStationId); try { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return false; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); if (currentStatus == null) { return false; } return updateStationDataInternal(currentStationId, deviceNo, 0, 0, false, "", false); } finally { unlockStations(currentStationId); } } public boolean runBlockStation(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo, Integer taskNo, Integer blockStationId) { lockStations(currentStationId); try { List statusList = deviceStatusMap.get(currentStationDeviceNo); if (statusList == null) { return false; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null); if (currentStatus == null) { return false; } return updateStationDataInternal(currentStationId, currentStationDeviceNo, taskNo, blockStationId, true, "", true); } finally { unlockStations(currentStationId); } } public void clearRunBlock(Integer stationId, Integer deviceNo) { lockStations(stationId); try { List statusList = deviceStatusMap.get(deviceNo); if (statusList == null) { return; } ZyStationStatusEntity currentStatus = statusList.stream() .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null); if (currentStatus == null) { return; } if (currentStatus.isRunBlock()) { currentStatus.setRunBlock(false); News.info("[WCS Debug] 站点{}堵塞标记已清除", stationId); } } finally { unlockStations(stationId); } } private boolean checkTaskNoInArea(Integer taskNo) { if (taskNo == null || redisUtil == null) { return false; } Object fakeTaskNoAreaObj = redisUtil.get(RedisKeyType.FAKE_TASK_NO_AREA.key); if (fakeTaskNoAreaObj == null) { return false; } JSONObject data = JSON.parseObject(String.valueOf(fakeTaskNoAreaObj)); Integer start = data.getInteger("start"); Integer end = data.getInteger("end"); if (start == null || end == null) { return false; } return taskNo >= start && taskNo <= end; } private Map buildDetails(Object... keyValues) { Map details = new LinkedHashMap(); if (keyValues == null) { return details; } for (int i = 0; i + 1 < keyValues.length; i += 2) { Object key = keyValues[i]; if (key != null) { details.put(String.valueOf(key), keyValues[i + 1]); } } return details; } private void traceEvent(Integer deviceNo, TaskRuntimeContext context, String eventType, String message, Map details, boolean terminal) { if (context == null || context.taskNo == null) { return; } try { FakeTaskTraceRegistry registry = SpringUtils.getBean(FakeTaskTraceRegistry.class); if (registry == null) { return; } registry.record(context.taskNo, context.threadImpl != null ? context.threadImpl : getThreadImpl(deviceNo), context.status, context.startStationId, context.currentStationId, context.finalTargetStationId, context.blockedStationId, context.getStitchedPathStationIds(), context.getPassedStationIds(), context.getPendingStationIds(), context.getLatestAppendedPath(), eventType, message, details, terminal); } catch (Exception ignore) { } } private String getThreadImpl(Integer deviceNo) { DeviceConfig deviceConfig = deviceConfigMap.get(deviceNo); return deviceConfig == null ? "" : deviceConfig.getThreadImpl(); } private boolean isTerminalStatus(String status) { return STATUS_BLOCKED.equals(status) || STATUS_CANCELLED.equals(status) || STATUS_TIMEOUT.equals(status) || STATUS_FINISHED.equals(status); } private static class TaskRuntimeContext { private final Integer taskNo; private final String threadImpl; private final LinkedBlockingQueue pendingPathQueue = new LinkedBlockingQueue(); private final List stitchedPathStationIds = new ArrayList(); private final List passedStationIds = new ArrayList(); private final List latestAppendedPath = new ArrayList(); private Integer startStationId; private Integer currentStationId; private Integer finalTargetStationId; private Integer blockedStationId; private boolean generateBarcode; private boolean initialized; private boolean arrivalHandled; private long lastStepAt = System.currentTimeMillis(); private long lastCommandAt = System.currentTimeMillis(); private String status = STATUS_WAITING; private TaskRuntimeContext(Integer taskNo, String threadImpl) { this.taskNo = taskNo; this.threadImpl = threadImpl; } private void setStartStationIdIfAbsent(Integer stationId) { if (startStationId == null && stationId != null) { startStationId = stationId; } } private void appendStitchedPath(List path) { latestAppendedPath.clear(); if (path == null) { return; } for (Integer stationId : path) { if (stationId == null) { continue; } latestAppendedPath.add(stationId); if (stitchedPathStationIds.isEmpty() || !stationId.equals(stitchedPathStationIds.get(stitchedPathStationIds.size() - 1))) { stitchedPathStationIds.add(stationId); } } } private void addPassedStation(Integer stationId) { if (stationId == null) { return; } if (passedStationIds.isEmpty() || !stationId.equals(passedStationIds.get(passedStationIds.size() - 1))) { passedStationIds.add(stationId); } } private List getPendingStationIds() { return new ArrayList(pendingPathQueue); } private List getPassedStationIds() { return new ArrayList(passedStationIds); } private List getStitchedPathStationIds() { return new ArrayList(stitchedPathStationIds); } private List getLatestAppendedPath() { return new ArrayList(latestAppendedPath); } } }