#
Junjie
昨天 707f8db2227a6031f230e35895ea1c5f7ff03bd6
src/main/java/com/zy/core/network/fake/ZyStationFakeConnect.java
@@ -1,33 +1,43 @@
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.model.NavigateNode;
import com.zy.common.utils.NavigateUtils;
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.core.enums.RedisKeyType;
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.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;
/**
 * 输送站假连接(模拟)
 */
public class ZyStationFakeConnect implements ZyStationConnectApi {
    private ZyStationStatusEntity status;
    private final List<ZyStationStatusEntity> statusList = new CopyOnWriteArrayList<>();
    private static int LOCK_STATION = 0;
    private final DeviceConfig deviceConfig;
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private RedisUtil redisUtil;
    // 允许并行执行多个命令任务(固定线程池)。如需更高并发可调整大小。
    private final ExecutorService executor = Executors
            .newFixedThreadPool(9999);
    public ZyStationFakeConnect(DeviceConfig deviceConfig) {
    public ZyStationFakeConnect(DeviceConfig deviceConfig, RedisUtil redisUtil) {
        this.deviceConfig = deviceConfig;
        this.status = JSON.parseObject(deviceConfig.getFakeInitStatus(), ZyStationStatusEntity.class);
        if (this.status == null) {
            this.status = new ZyStationStatusEntity();
            this.status.setStationId(deviceConfig.getDeviceNo());
        }
        this.redisUtil = redisUtil;
    }
    @Override
@@ -37,50 +47,541 @@
    @Override
    public boolean disconnect() {
        executor.shutdownNow();
        return true;
    }
    @Override
    public List<ZyStationStatusEntity> getStatus() {
        return Collections.singletonList(status);
        if (this.statusList.isEmpty()) {
            List<ZyStationStatusEntity> init = JSON.parseArray(deviceConfig.getFakeInitStatus(), ZyStationStatusEntity.class);
            if (init != null) {
                statusList.addAll(init);
                for (ZyStationStatusEntity status : this.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);// 模拟托盘高度为0
                    status.setError(0);// 模拟无报警
                    status.setBarcode("");// 模拟无条码
                }
            }
        }
        return this.statusList;
    }
    @Override
    public CommandResponse sendCommand(StationCommand command) {
        CommandResponse response = new CommandResponse(false);
        executor.submit(() -> handleCommand(command));
        response.setResult(true);
        return response;
        executor.submit(() -> {
            try {
                handleCommand(command);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return new CommandResponse(true, "命令已受理(异步执行)");
    }
    private void handleCommand(StationCommand command) {
        // 简单的模拟:设置工作号和目标站,并模拟有物/可入/可出状态切换
        this.status.setTaskNo(command.getTaskNo());
        this.status.setTargetStaNo(command.getTargetStaNo());
        News.info("[WCS Debug] 站点仿真模拟已启动,命令数据={}", JSON.toJSONString(command));
        Integer taskNo = command.getTaskNo();
        Integer stationId = command.getStationId();
        Integer targetStationId = command.getTargetStaNo();
        boolean generateBarcode = false;
        // 模拟到站过程
        this.status.setAutoing(true);
        this.status.setLoading(true);
        sleep(1000);
        if(taskNo == 0 && targetStationId == 0){
            //清空站点
            resetStation(stationId);
            return;
        }
        // 模拟放下托盘
        this.status.setInEnable(true);
        this.status.setOutEnable(false);
        sleep(1000);
        //任务号属于仿真入库任务号
        if (checkTaskNoInArea(taskNo)) {
            //生成仿真数据
            generateBarcode = true;
        }
        // 完成任务,复位状态
        this.status.setLoading(false);
        this.status.setAutoing(false);
        this.status.setTaskNo(0);
        this.status.setInEnable(false);
        this.status.setOutEnable(true);
        if (taskNo == 9998 && targetStationId == 0) {
            //生成出库站点仿真数据
            generateFakeOutStationData(stationId);
            return;
        }
        if (taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId == targetStationId) {
            //下发任务数据-不允许只是下发数据
            generateStationData(taskNo, stationId, targetStationId);
        }
        String startLev = String.valueOf(stationId).substring(0, 1);
        String endLev = String.valueOf(targetStationId).substring(0, 1);
        if (startLev.equals(endLev)) {
            currentLevCommand(command, generateBarcode);
        }else {
            diffLevCommand(command, generateBarcode);
        }
    }
    private void generateFakeOutStationData(Integer stationId) {
        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 taskNo, Integer stationId, Integer targetStationId) {
        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 stationId) {
        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 currentLevCommand(StationCommand command, boolean generateBarcode) {
        NavigateUtils navigateUtils = SpringUtils.getBean(NavigateUtils.class);
        if (navigateUtils == null) {
            return;
        }
        Integer taskNo = command.getTaskNo();
        Integer stationId = command.getStationId();
        Integer targetStationId = command.getTargetStaNo();
        String startLev = String.valueOf(stationId).substring(0, 1);
        List<NavigateNode> navigateNodes = null;
        try {
            navigateNodes = navigateUtils.calcByStationId(Integer.parseInt(startLev), stationId, targetStationId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (navigateNodes == null) {
            return;
        }
        stationMove(navigateNodes, taskNo, targetStationId, false, generateBarcode);
    }
    private void diffLevCommand(StationCommand command, boolean generateBarcode) {
        NavigateUtils navigateUtils = SpringUtils.getBean(NavigateUtils.class);
        if (navigateUtils == null) {
            return;
        }
        Integer taskNo = command.getTaskNo();
        Integer stationId = command.getStationId();
        Integer targetStationId = command.getTargetStaNo();
        String startLev = String.valueOf(stationId).substring(0, 1);
        String endLev = String.valueOf(targetStationId).substring(0, 1);
        List<NavigateNode> navigateNodes = null;
        List<NavigateNode> targetNavigateNodes = null;
        try {
            List<NavigateNode> liftStationList = navigateUtils.findLiftStationList(Integer.parseInt(startLev));
            if(liftStationList.isEmpty()){
                //未找到提升机节点
                return;
            }
            List<NavigateNode> targetLiftStationList = navigateUtils.findLiftStationList(Integer.parseInt(endLev));
            if(targetLiftStationList.isEmpty()){
                //未找到提升机节点
                return;
            }
            for (NavigateNode liftStation : liftStationList) {
                JSONObject valuObject = JSON.parseObject(liftStation.getNodeValue());
                if(valuObject == null){
                    continue;
                }
                Integer liftStationId = valuObject.getInteger("stationId");
                Integer liftNo = valuObject.getInteger("liftNo");
                Integer targetLiftStationId = null;
                for (NavigateNode targetLiftStation : targetLiftStationList) {
                    JSONObject targetValuObject = JSON.parseObject(targetLiftStation.getNodeValue());
                    if(targetValuObject == null){
                        continue;
                    }
                    Integer targetLiftNo = targetValuObject.getInteger("liftNo");
                    if(liftNo.equals(targetLiftNo)){
                        targetLiftStationId = targetValuObject.getInteger("stationId");
                        break;
                    }
                }
                if(targetLiftStationId == null){
                    continue;
                }
                navigateNodes = navigateUtils.calcByStationId(Integer.parseInt(startLev), stationId, liftStationId);
                if(navigateNodes == null){
                    continue;
                }
                //计算提升机到目标站的路径
                targetNavigateNodes = navigateUtils.calcByStationId(Integer.parseInt(endLev), targetLiftStationId, targetStationId);
                if(targetNavigateNodes == null) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (navigateNodes == null || targetNavigateNodes == null) {
            return;
        }
        boolean result = stationMove(navigateNodes, taskNo, stationId, true, generateBarcode);
        if(result) {
            stationMove(targetNavigateNodes, taskNo, targetStationId, false, generateBarcode);
        }
    }
    private boolean stationMove(List<NavigateNode> navigateNodes, Integer taskNo, Integer targetStationId, boolean clearData, boolean generateBarcode) {
        Integer lastStationId = null;
        long executeTime = System.currentTimeMillis();
        int i = 0;
        while (i < navigateNodes.size()) {
            if (Thread.currentThread().isInterrupted()) {
                return false;
            }
            NavigateNode navigateNode = navigateNodes.get(i);
            JSONObject valueObject = JSON.parseObject(navigateNode.getNodeValue());
            Integer currentStationId = valueObject.getInteger("stationId");
            Integer nextStationId = null;
            try {
                NavigateNode nextNode = navigateNodes.get(i + 1);
                JSONObject nextValueObject = JSON.parseObject(nextNode.getNodeValue());
                nextStationId = nextValueObject.getInteger("stationId");
            } catch (Exception e) {
            }
            if (!checkTaskNoInArea(taskNo)) {
                boolean fakeAllowCheckBlock = true;
                Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
                if (systemConfigMapObj != null) {
                    HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
                    if (!systemConfigMap.get("fakeAllowCheckBlock").equals("Y")) {
                        fakeAllowCheckBlock = false;
                    }
                }
                if (fakeAllowCheckBlock && System.currentTimeMillis() - executeTime > 1000 * 10) {
                    //认定堵塞
                    boolean result = runBlockStation(taskNo, currentStationId, taskNo, currentStationId);
                    if(!result) {
                        continue;
                    }
                    return false;
                }
            }
            if (i == 0) {
                boolean result = initStationMove(taskNo, currentStationId, taskNo, targetStationId, true, null);
                if (!result) {
                    continue;
                }
                sleep(1000);
                if (Thread.currentThread().isInterrupted()) {
                    return false;
                }
            }
            if(nextStationId != null) {
                boolean result = stationMoveToNext(taskNo, currentStationId, nextStationId, taskNo, targetStationId);
                if (!result) {
                    continue;
                }
                lastStationId = currentStationId;
            }
            i++;
            executeTime = System.currentTimeMillis();
            sleep(1000);
            if (Thread.currentThread().isInterrupted()) {
                return false;
            }
        }
        if (generateBarcode) {
            if (lastStationId != null) {
                while (true) {
                    if (Thread.currentThread().isInterrupted()) {
                        break;
                    }
                    boolean result = generateStationBarcode(taskNo, targetStationId);
                    sleep(1000);
                    if (!result) {
                        continue;
                    }
                    break;
                }
            }
        }
        if (clearData) {
            sleep(10000);
            if (Thread.currentThread().isInterrupted()) {
                return true;
            }
            if (lastStationId != null) {
                while (true) {
                    if (Thread.currentThread().isInterrupted()) {
                        break;
                    }
                    boolean result = clearStation(taskNo, targetStationId);
                    sleep(1000);
                    if (!result) {
                        continue;
                    }
                    break;
                }
            }
        }
        return true;
    }
    private void sleep(long ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
    }
}
    public synchronized boolean setLockStation(Integer uuid) {
        if (LOCK_STATION == 0) {
            LOCK_STATION = uuid;
            return true;
        }else {
            if(LOCK_STATION == uuid) {
                return true;
            }
        }
        return false;
    }
    public synchronized boolean releaseLockStation(Integer uuid) {
        if (LOCK_STATION != uuid) {
            return false;
        }
        LOCK_STATION = 0;
        return true;
    }
    public synchronized boolean updateStationData(Integer lockTaskNo, Integer stationId, Integer taskNo, Integer targetStaNo, Boolean isLoading, String barcode, Boolean runBlock) {
        if (LOCK_STATION != lockTaskNo) {
            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 synchronized boolean initStationMove(Integer lockTaskNo, Integer currentStationId, Integer taskNo, Integer targetStationId, Boolean isLoading, String barcode) {
        boolean executeResult = lockExecute(lockTaskNo, () -> {
            ZyStationStatusEntity currentStatus = statusList.stream()
                .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
            if (currentStatus == null) {
                return false;
            }
            if (currentStatus.getTaskNo() > 0) {
                if (!currentStatus.getTaskNo().equals(taskNo) && currentStatus.isLoading()) {
                    return false;
                }
            }
            boolean result = updateStationData(taskNo, currentStationId, taskNo, targetStationId, isLoading, barcode, false);
            if (!result) {
                return false;
            }
            return true;
        });
        return executeResult;
    }
    public synchronized boolean stationMoveToNext(Integer lockTaskNo, Integer currentStationId, Integer nextStationId, Integer taskNo, Integer targetStaNo) {
        boolean executeResult = lockExecute(lockTaskNo, () -> {
            ZyStationStatusEntity currentStatus = statusList.stream()
                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
            ZyStationStatusEntity nextStatus = statusList.stream()
                    .filter(item -> item.getStationId().equals(nextStationId)).findFirst().orElse(null);
            if (currentStatus == null || nextStatus == null) {
                return false;
            }
            if (nextStatus.getTaskNo() > 0 || nextStatus.isLoading()) {
                return false;
            }
            boolean result = updateStationData(lockTaskNo, nextStationId, taskNo, targetStaNo, true, null, false);
            if (!result) {
                return false;
            }
            boolean result2 = updateStationData(lockTaskNo, currentStationId, 0, 0, false, null, false);
            if (!result2) {
                return false;
            }
            return true;
        });
        return executeResult;
    }
    public synchronized boolean generateStationBarcode(Integer lockTaskNo, Integer currentStationId) {
        boolean executeResult = lockExecute(lockTaskNo, () -> {
            ZyStationStatusEntity currentStatus = statusList.stream()
                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
            if (currentStatus == null) {
                return false;
            }
            String barcodeTime = String.valueOf(System.currentTimeMillis());
            String barcode = barcodeTime.substring(5);
            boolean result = updateStationData(lockTaskNo, currentStationId, null, null, null, barcode, null);
            if (!result) {
                return false;
            }
            return true;
        });
        return executeResult;
    }
    public synchronized boolean clearStation(Integer lockTaskNo, Integer currentStationId) {
        boolean executeResult = lockExecute(lockTaskNo, () -> {
            ZyStationStatusEntity currentStatus = statusList.stream()
                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
            if (currentStatus == null) {
                return false;
            }
            boolean result = updateStationData(lockTaskNo, currentStationId, 0, 0, false, "", false);
            if (!result) {
                return false;
            }
            return true;
        });
        return executeResult;
    }
    public synchronized boolean runBlockStation(Integer lockTaskNo, Integer currentStationId, Integer taskNo, Integer blockStationId) {
        boolean executeResult = lockExecute(lockTaskNo, () -> {
            ZyStationStatusEntity currentStatus = statusList.stream()
                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
            if (currentStatus == null) {
                return false;
            }
            boolean result = updateStationData(lockTaskNo, currentStationId, taskNo, blockStationId, true, "", true);
            if (!result) {
                return false;
            }
            return true;
        });
        return executeResult;
    }
    public synchronized boolean lockExecute(Integer taskNo, Supplier<Boolean> function) {
        if (!setLockStation(taskNo)) {
            return false;
        }
        boolean result = function.get();
        releaseLockStation(taskNo);
        return result;
    }
    private synchronized boolean checkTaskNoInArea(Integer taskNo) {
        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(taskNo >= start && taskNo <= end) {
            return true;
        }
        return false;
    }
}