#
lsh
2024-06-22 a64aaeecc264176a60c6bb0e4e348c63f929d459
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java
@@ -8,10 +8,10 @@
import com.core.common.DateUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.*;
import com.zy.asrs.mapper.BasCrnErrorMapper;
import com.zy.asrs.mapper.WaitPakinMapper;
import com.zy.asrs.mapper.WrkMastMapper;
import com.zy.asrs.mapper.*;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.CodeDetectionUtil;
import com.zy.asrs.utils.RouteUtils;
import com.zy.asrs.utils.Utils;
import com.zy.asrs.utils.VersionUtils;
import com.zy.common.model.LocTypeDto;
@@ -21,35 +21,34 @@
import com.zy.common.service.CommonService;
import com.zy.common.utils.CollectionUtils;
import com.zy.common.utils.HttpHandler;
import com.zy.common.utils.RedisUtil;
import com.zy.common.utils.RgvUtils;
import com.zy.core.CrnThread;
import com.zy.core.DevpThread;
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.*;
import com.zy.core.model.CrnSlave;
import com.zy.core.model.DevpSlave;
import com.zy.core.model.LedSlave;
import com.zy.core.model.Task;
import com.zy.core.model.*;
import com.zy.core.model.command.CrnCommand;
import com.zy.core.model.command.LedCommand;
import com.zy.core.model.command.RgvCommand;
import com.zy.core.model.cpmmandParam.CrnCommandParam;
import com.zy.core.model.protocol.CrnProtocol;
import com.zy.core.model.protocol.JarProtocol;
import com.zy.core.model.protocol.RgvProtocol;
import com.zy.core.model.protocol.StaProtocol;
import com.zy.core.properties.SlaveProperties;
import com.zy.core.thread.BarcodeThread;
import com.zy.core.thread.LedThread;
import com.zy.core.thread.SiemensDevpThread;
import com.zy.core.thread.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import springfox.documentation.spring.web.json.Json;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -80,6 +79,8 @@
    @Autowired
    private BasCrnpService basCrnpService;
    @Autowired
    private BasRgvService basRgvService;
    @Autowired
    private BasDevpService basDevpService;
    @Autowired
    private LocDetlService locDetlService;
@@ -87,15 +88,45 @@
    private BasErrLogService basErrLogService;
    @Autowired
    private BasCrnErrorMapper basCrnErrorMapper;
    @Autowired
    private BasRgvErrMapper basRgvErrMapper;
    @Autowired
    private BasRgvErrLogService basRgvErrLogService;
    @Autowired
    private BasRgvPathService basRgvPathService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private WrkMastStaMapper wrkMastStaMapper;
    @Autowired
    private BasRgvMapMapper basRgvMapMapper;
    @Autowired
    private RgvOneSignMapper rgvOneSignMapper;
    @Autowired
    private WrkMastCrnMapper wrkMastCrnMapper;
    @Autowired
    private WrkMastSplitTwinMapper wrkMastSplitTwinMapper;
    @Autowired
    private WrkMastSplitTwinService wrkMastSplitTwinService;
    @Autowired
    private BasJarMastService basJarMastService;
    @Autowired
    private WrkMastExecuteService wrkMastExecuteService;
    @Autowired
    private BasJarService basJarService;
    @Autowired
    private BasJarMapper basJarMapper;
    @Value("${wms.url}")
    private String wmsUrl;
    /**
     * 组托
     * 入库站,根据条码扫描生成入库工作档,工作状态 2
     */
    public void generateStoreWrkFile() {
    public synchronized void generateStoreWrkFile() {
        // 根据输送线plc遍历
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历入库口
@@ -106,9 +137,10 @@
                    continue;
                }
                String barcode = barcodeThread.getBarcode();
                if (!Cools.isEmpty(barcode)) {
                    log.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode);
                    if ("NG".endsWith(barcode) || "NoRead".equals(barcode)) {
//                    log.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode);
                    if ("NG".endsWith(barcode) || "NoRead".equals(barcode) || !CodeDetectionUtil.barcodeDetection(barcode)) {
                        continue;
                    }
                } else {
@@ -116,6 +148,7 @@
                }
                // 获取入库站信息
//                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(inSta.getStaNo());
                if (staProtocol == null) {
@@ -124,22 +157,65 @@
                    staProtocol = staProtocol.clone();
                }
                // 入出库模式判断
//                if ( inSta.getStaNo()==203 && devpThread.ioModeOf2F != IoModeType.PAKIN_MODE) { continue; }
                if (inSta.getStaNo() == 203 && devpThread.ioModeOf2F == IoModeType.PAKOUT_MODE) {
                // 尺寸检测异常
                boolean back = false;
                String errMsg = "异常:";
                if (staProtocol.isFrontErr()) {
                    errMsg = errMsg+"前超限;";
                    back = true;
                }
                if (staProtocol.isBackErr()) {
                    errMsg = errMsg+"后超限";
                    back = true;
                }
                if (staProtocol.isHighErr()) {
                    errMsg = errMsg+"高超限";
                    back = true;
                }
                if (staProtocol.isLeftErr()) {
                    errMsg = errMsg+"左超限";
                    back = true;
                }
                if (staProtocol.isRightErr()) {
                    errMsg = errMsg+"右超限";
                    back = true;
                }
                if (staProtocol.isWeightErr()) {
                    errMsg = errMsg+"超重";
                    back = true;
                }
                if (staProtocol.isBarcodeErr()) {
                    errMsg = errMsg+"扫码失败";
                    back = true;
                }
                // 退回
                if (back) {
                    // led 异常显示
                    LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                    if (ledThread != null) {
                        MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(5, errMsg));
                    }
                    continue;
                }
                // 入出库模式判断
//                if ( inSta.getStaNo()==203 && devpThread.ioModeOf2F != IoModeType.PAKIN_MODE) { continue; }
//                if (inSta.getStaNo() == 203 && devpThread.ioModeOf2F == IoModeType.PAKOUT_MODE) {
//                    continue;
//                }
                // 判断是否满足入库条件
                if (staProtocol.isAutoing() && staProtocol.isLoading()
                if (staProtocol.isAutoing()
                        && staProtocol.isLoading()
                        && staProtocol.isInEnable()
                        && !staProtocol.isEmptyMk() && (staProtocol.getWorkNo() == 0 || staProtocol.getWorkNo() > 9990)
                        && !staProtocol.isEmptyMk()
                        && staProtocol.getWorkNo() == 0
                        && staProtocol.isPakMk()) {// && !Cools.isEmpty(barcode)) {
//                    if(Cools.isEmpty(barcode) || "NG".endsWith(barcode) || "NoRead".equals(barcode)) {
//                        log.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode);
//                        //条码为空或者不符合,退库到172站点
//                        staProtocol.setWorkNo((short)9999);
//                        staProtocol.setWorkNo((short)32222);
//                        staProtocol.setStaNo((short)172);
//                        devpThread.setPakMk(staProtocol.getSiteId(), false);
//                        boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
@@ -181,9 +257,18 @@
                        if (jsonObject.getInteger("code").equals(200)) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                            barcodeThread.setBarcode("");
                            staProtocol.setWorkNo(dto.getWorkNo().shortValue());
                            staProtocol.setStaNo(dto.getStaNo().shortValue());
                            staProtocol.setWorkNo(dto.getWorkNo());
                            if(Cools.isEmpty(dto.getRgvNo()) || dto.getRgvNo() <= 0) {
                                staProtocol.setStaNo(dto.getStaNo());
                            } else {//如果存在RGV编号,说明需要RGV接驳,先下发任务到RGV源站
                                staProtocol.setStaNo(dto.getRgvSstaNo());
                            }
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                            if (!result) {
@@ -192,64 +277,6 @@
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin/loc/v1", JSON.toJSONString(param), response);
                        }
//                        // 检索库位
//                        LocTypeDto locTypeDto = new LocTypeDto(staProtocol);
//                        List<String> matNos = waitPakins.stream().map(WaitPakin::getMatnr).distinct().collect(Collectors.toList());
//                        StartupDto startupDto = commonService.getLocNo(1, 1, inSta.getStaNo(), matNos, locTypeDto, 0);
//                        // 工作号
//                        int workNo = startupDto.getWorkNo();
//                        // 插入工作明细档
//                        wrkDetlService.createWorkDetail(workNo, waitPakins, barcode);
//
//                        // 插入工作主档
//                        wrkMast = new WrkMast();
//                        wrkMast.setWrkNo(workNo);
//                        wrkMast.setIoTime(new Date());
//                        wrkMast.setWrkSts(2L); // 工作状态:2.设备上走
//                        wrkMast.setIoType(1); // 入出库状态:1.入库
//                        wrkMast.setIoPri(10D); // 优先级:10
//                        wrkMast.setCrnNo(startupDto.getCrnNo());
//                        wrkMast.setSourceStaNo(startupDto.getSourceStaNo());
//                        wrkMast.setStaNo(startupDto.getStaNo());
//                        wrkMast.setLocNo(startupDto.getLocNo());
//                        wrkMast.setBarcode(barcode); // 托盘码
//                        wrkMast.setFullPlt("Y"); // 满板:Y
//                        wrkMast.setPicking("N"); // 拣料
//                        wrkMast.setExitMk("N"); // 退出
//                        wrkMast.setEmptyMk("N"); // 空板
//                        wrkMast.setLinkMis("N");
//                        // 操作人员数据
//                        wrkMast.setAppeTime(new Date());
//                        wrkMast.setModiTime(new Date());
//                        Integer insert = wrkMastMapper.insert(wrkMast);
//                        if (insert == 0) {
//                            throw new CoolException("保存工作档失败");
//                        }
//                        // 更新目标库位状态
//                        LocMast locMast = locMastService.selectById(startupDto.getLocNo());
//                        locMast.setLocSts("S"); // S.入库预约
//                        locMast.setModiTime(new Date());
//                        if (!locMastService.updateById(locMast)){
//                            throw new CoolException("改变库位状态失败");
//                        }
//                        // 将入库通知档修改为已启动
//                        if (wrkMastMapper.updateWaitPakInStep1(barcode) == 0) {
//                            throw new CoolException("修改入库通知档状态为已启动失败");
//                        }
//
//                        // 命令下发区 --------------------------------------------------------------------------
//
//                        // 更新站点信息 且 下发plc命令
//                        barcodeThread.setBarcode("");
//                        staProtocol.setWorkNo((short) workNo);
//                        staProtocol.setStaNo(startupDto.getStaNo().shortValue());
//                        devpThread.setPakMk(staProtocol.getSiteId(), false);
//                        boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
//                        if (!result) {
//                            throw new CoolException("更新plc站点信息失败");
//                        }
                    } catch (Exception e) {
                        e.printStackTrace();
@@ -265,14 +292,351 @@
    }
    /**
     * wms入库
     * 入库站,根据条码扫描生成入库工作档,工作状态 1 ==>> 2
     * 组托
     * 入库站,根据条码扫描生成入库工作档,工作状态 2
     */
    public void generateStoreWrkFile0() {
    public synchronized void generateStoreWrkFileSingle() {
        // 根据输送线plc遍历
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历入库口
            for (DevpSlave.Sta inSta : devp.getInSta()) {
            for (DevpSlave.Sta inSta : devp.getInSingleSta()) {
                // 获取条码扫描仪信息
                BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, inSta.getBarcode());
                if (barcodeThread == null) {
                    continue;
                }
                String barcode = barcodeThread.getBarcode();
                if (!Cools.isEmpty(barcode)) {
//                    log.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode);
                    if ("NG".endsWith(barcode) || "NoRead".equals(barcode) || !CodeDetectionUtil.barcodeDetection(barcode)) {
                        continue;
                    }
                } else {
                    continue;
                }
                // 获取入库站信息
//                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(inSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                // 尺寸检测异常
                boolean back = false;
                String errMsg = "异常:";
                if (staProtocol.isFrontErr()) {
                    errMsg = errMsg+"前超限;";
                    back = true;
                }
                if (staProtocol.isBackErr()) {
                    errMsg = errMsg+"后超限";
                    back = true;
                }
                if (staProtocol.isHighErr()) {
                    errMsg = errMsg+"高超限";
                    back = true;
                }
                if (staProtocol.isLeftErr()) {
                    errMsg = errMsg+"左超限";
                    back = true;
                }
                if (staProtocol.isRightErr()) {
                    errMsg = errMsg+"右超限";
                    back = true;
                }
                if (staProtocol.isWeightErr()) {
                    errMsg = errMsg+"超重";
                    back = true;
                }
                if (staProtocol.isBarcodeErr()) {
                    errMsg = errMsg+"扫码失败";
                    back = true;
                }
                // 退回
                if (back) {
                    // led 异常显示
                    LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                    if (ledThread != null) {
                        MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(5, errMsg));
                    }
                    continue;
                }
                // 入出库模式判断
//                if ( inSta.getStaNo()==203 && devpThread.ioModeOf2F != IoModeType.PAKIN_MODE) { continue; }
//                if (inSta.getStaNo() == 203 && devpThread.ioModeOf2F == IoModeType.PAKOUT_MODE) {
//                    continue;
//                }
                // 判断是否满足入库条件
                if (staProtocol.isAutoing()
                        && staProtocol.isLoading()
                        && staProtocol.isInEnable()
                        && !staProtocol.isEmptyMk()
                        && staProtocol.getWorkNo() == 0
                        && staProtocol.isPakMk()) {// && !Cools.isEmpty(barcode)) {
                    if(Cools.isEmpty(barcode) || "NG".endsWith(barcode) || !CodeDetectionUtil.barcodeDetection(barcode)) {
                        log.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode);
//                        //条码为空或者不符合,退库到172站点
//                        staProtocol.setWorkNo((short)32222);
//                        staProtocol.setStaNo((short)172);
//                        devpThread.setPakMk(staProtocol.getSiteId(), false);
//                        boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
//                        if (!result) {
//                            throw new CoolException("更新plc站点信息失败");
//                        }
                        continue;
                    }
                    // 判断重复工作档
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep1(inSta.getStaNo(), barcode);
                    if (wrkMast != null) {
                        log.error("工作档中已存在该站状态为( 2.设备上走 )的数据,工作号={}", wrkMast.getWrkNo());
                        continue;
                    }
//                    // 获取入库通知档
//                    List<WaitPakin> waitPakins = waitPakinMapper.selectList(new EntityWrapper<WaitPakin>().eq("zpallet", barcode).eq("io_status", "N"));
//                    if (waitPakins.isEmpty()) {
//                        log.error("无此入库条码数据。条码号={}", barcode);
//                        continue;
//                    }
                    try {
                        LocTypeDto locTypeDto = new LocTypeDto(staProtocol);
                        SearchLocParam param = new SearchLocParam();
                        param.setBarcode(barcode);
                        param.setIoType(1);
                        param.setSourceStaNo(inSta.getStaNo());
                        param.setLocType1(locTypeDto.getLocType1());
                        String response = new HttpHandler.Builder()
                                .setUri(wmsUrl)
                                .setPath("/rpc/pakin/pair/station/single/loc/v1")
                                .setJson(JSON.toJSONString(param))
                                .build()
                                .doPost();
                        JSONObject jsonObject = JSON.parseObject(response);
                        if (jsonObject.getInteger("code").equals(200)) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                            barcodeThread.setBarcode("");
                            staProtocol.setWorkNo(dto.getWorkNo());
                            if(Cools.isEmpty(dto.getRgvNo()) || dto.getRgvNo() <= 0) {
                                staProtocol.setStaNo(dto.getStaNo());
                            } else {//如果存在RGV编号,说明需要RGV接驳,先下发任务到RGV源站
                                staProtocol.setStaNo(dto.getRgvSstaNo());
                            }
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                            if (!result) {
                                throw new CoolException("更新plc站点信息失败");
                            }
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin/pair/station/single/loc/v1", JSON.toJSONString(param), response);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }
    }
    /**
     * 组托
     * 入库站,根据条码扫描生成入库工作档,工作状态 2
     */
    public synchronized void generateStoreWrkFileLarge() {
        // 根据输送线plc遍历
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历入库口
            for (DevpSlave.Sta inSta : devp.getInLargeSta()) {
                // 获取条码扫描仪信息
                BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, inSta.getBarcode());
                if (barcodeThread == null) {
                    continue;
                }
                String barcode = barcodeThread.getBarcode();
                if (!Cools.isEmpty(barcode)) {
//                    log.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode);
                    if ("NG".endsWith(barcode) || "NoRead".equals(barcode) || !CodeDetectionUtil.barcodeDetection(barcode)) {
                        continue;
                    }
                } else {
                    continue;
                }
                // 获取入库站信息
//                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(inSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                // 尺寸检测异常
                boolean back = false;
                String errMsg = "异常:";
                if (staProtocol.isFrontErr()) {
                    errMsg = errMsg+"前超限;";
                    back = true;
                }
                if (staProtocol.isBackErr()) {
                    errMsg = errMsg+"后超限";
                    back = true;
                }
                if (staProtocol.isHighErr()) {
                    errMsg = errMsg+"高超限";
                    back = true;
                }
                if (staProtocol.isLeftErr()) {
                    errMsg = errMsg+"左超限";
                    back = true;
                }
                if (staProtocol.isRightErr()) {
                    errMsg = errMsg+"右超限";
                    back = true;
                }
                if (staProtocol.isWeightErr()) {
                    errMsg = errMsg+"超重";
                    back = true;
                }
                if (staProtocol.isBarcodeErr()) {
                    errMsg = errMsg+"扫码失败";
                    back = true;
                }
                // 退回
                if (back) {
                    // led 异常显示
                    LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                    if (ledThread != null) {
                        MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(5, errMsg));
                    }
                    continue;
                }
                // 入出库模式判断
//                if ( inSta.getStaNo()==203 && devpThread.ioModeOf2F != IoModeType.PAKIN_MODE) { continue; }
//                if (inSta.getStaNo() == 203 && devpThread.ioModeOf2F == IoModeType.PAKOUT_MODE) {
//                    continue;
//                }
                // 判断是否满足入库条件
                if (staProtocol.isAutoing()
                        && staProtocol.isLoading()
                        && staProtocol.isInEnable()
                        && !staProtocol.isEmptyMk()
                        && staProtocol.getWorkNo() == 0
                        && staProtocol.isPakMk()) {// && !Cools.isEmpty(barcode)) {
                    if(Cools.isEmpty(barcode) || "NG".endsWith(barcode) || !CodeDetectionUtil.barcodeDetection(barcode)) {
                        log.info("{}号条码扫描器检测条码信息:{}", inSta.getBarcode(), barcode);
//                        //条码为空或者不符合,退库到172站点
//                        staProtocol.setWorkNo((short)32222);
//                        staProtocol.setStaNo((short)172);
//                        devpThread.setPakMk(staProtocol.getSiteId(), false);
//                        boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
//                        if (!result) {
//                            throw new CoolException("更新plc站点信息失败");
//                        }
                        continue;
                    }
                    // 判断重复工作档
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep1(inSta.getStaNo(), barcode);
                    if (wrkMast != null) {
                        log.error("工作档中已存在该站状态为( 2.设备上走 )的数据,工作号={}", wrkMast.getWrkNo());
                        continue;
                    }
//                    // 获取入库通知档
//                    List<WaitPakin> waitPakins = waitPakinMapper.selectList(new EntityWrapper<WaitPakin>().eq("zpallet", barcode).eq("io_status", "N"));
//                    if (waitPakins.isEmpty()) {
//                        log.error("无此入库条码数据。条码号={}", barcode);
//                        continue;
//                    }
                    try {
                        LocTypeDto locTypeDto = new LocTypeDto(staProtocol);
                        SearchLocParam param = new SearchLocParam();
                        param.setBarcode(barcode);
                        param.setIoType(1);
                        param.setSourceStaNo(inSta.getStaNo());
                        param.setLocType1(locTypeDto.getLocType1());
                        String response = new HttpHandler.Builder()
                                .setUri(wmsUrl)
                                .setPath("/rpc/pakin/loc/v1")
                                .setJson(JSON.toJSONString(param))
                                .build()
                                .doPost();
                        JSONObject jsonObject = JSON.parseObject(response);
                        if (jsonObject.getInteger("code").equals(200)) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            barcodeThread.setBarcode("");
                            staProtocol.setWorkNo(dto.getWorkNo());
                            if(Cools.isEmpty(dto.getRgvNo()) || dto.getRgvNo() <= 0) {
                                staProtocol.setStaNo(dto.getStaNo());
                            } else {//如果存在RGV编号,说明需要RGV接驳,先下发任务到RGV源站
                                staProtocol.setStaNo(dto.getRgvSstaNo());
                            }
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                            if (!result) {
                                throw new CoolException("更新plc站点信息失败");
                            }
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin/loc/v1", JSON.toJSONString(param), response);
                            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                            if (ledThread != null) {
                                MessageQueue.offer(SlaveType.Led, inSta.getLed(), new Task(5, "入库失败!"));
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }
    }
    /**
     * wms入库
     * 入库站,根据条码扫描生成入库工作档,工作状态 1 ==>> 2
     */
    public synchronized void generateStoreWrkFile0() {
        // 根据输送线plc遍历
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历入库口
            for (DevpSlave.Sta inSta : devp.getInWmsSta()) {
                // 获取入库站信息
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(inSta.getStaNo());
@@ -283,13 +647,13 @@
                }
//                // 入出库模式判断
                if (inSta.getStaNo() == 203 && devpThread.ioModeOf2F != IoModeType.PAKIN_MODE) {
                    continue;
                }
//                if (inSta.getStaNo() == 203 && devpThread.ioModeOf2F != IoModeType.PAKIN_MODE) {
//                    continue;
//                }
                // 判断是否满足入库条件
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isInEnable()
                        && !staProtocol.isEmptyMk() && (staProtocol.getWorkNo() == 0 || staProtocol.getWorkNo() == 9999)
                        && !staProtocol.isEmptyMk() && staProtocol.getWorkNo() == 0
                        && staProtocol.isPakMk()) {
                    // 判断重复工作档
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep11(inSta.getStaNo());
@@ -300,8 +664,12 @@
                    // 命令下发区 --------------------------------------------------------------------------
                    // 更新站点信息 且 下发plc命令
                    staProtocol.setWorkNo(wrkMast.getWrkNo().shortValue());
                    staProtocol.setStaNo(wrkMast.getStaNo().shortValue());
                    staProtocol.setWorkNo(wrkMast.getWrkNo());
                    Integer staNo = wrkMast.getStaNo();
                    if (wrkMast.getSourceStaNo()==145){
                        staNo = 147;
                    }
                    staProtocol.setStaNo(staNo);
                    devpThread.setPakMk(staProtocol.getSiteId(), false);
                    boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                    if (result) {
@@ -359,7 +727,7 @@
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isInEnable() && staProtocol.isPakMk()) {
//                    WrkMast wrkMast = wrkMastMapper.selectPickStep(barcode);
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep3(staProtocol.getWorkNo().intValue());
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep5(staProtocol.getSiteId(),"7");
                    if (wrkMast == null) {
                        // 无拣料数据
                        continue;
@@ -369,73 +737,67 @@
                        continue;
                    }
                    // 拣、盘、并 作业站转换
//                    int stnNo = 0;
//                    if (wrkMast.getStaNo() == 109) {
//                        stnNo = 127;
//                    } else if (wrkMast.getStaNo() == 113) {
//                        stnNo = 128;
//                    } else {
//                        log.error("{}号任务数据异常!", wrkMast.getWrkNo());
//                    }
                    // 获取目标站
                    Wrapper<StaDesc> wrapper = new EntityWrapper<StaDesc>()
                            .eq("type_no", wrkMast.getIoType() - 50)
                            .eq("stn_no", pickSta.getStaNo()) // 作业站点 = 拣料出库的目标站
                            .eq("crn_no", wrkMast.getCrnNo()); // 堆垛机号
                    StaDesc staDesc = staDescService.selectOne(wrapper);
                    if (Cools.isEmpty(staDesc)) {
                        log.error("入库路径不存在!type_no={},stn_no={},crn_no={}", wrkMast.getIoType(), pickSta.getStaNo(), wrkMast.getCrnNo());
                        continue;
                    }
                    //   获取库位号
                    try {
                        // 保存工作明细档历史档
                        if (wrkMastMapper.saveWrkDetlLog(wrkMast.getWrkNo()) == 0) {
                            throw new CoolException("保存工作明细档历史档失败");
                        SearchLocParam param = new SearchLocParam();
                        param.setBarcode(wrkMast.getBarcode());
                        param.setIoType(wrkMast.getIoType());
                        param.setSourceStaNo(pickSta.getStaNo()); //作业站点
                        param.setLocType1((short)1);
                        String response = "";
                        log.info("入库作业站"+pickSta.getStaNo()+"盘点再入库任务请求WMS===>>参数:" + param);
                        try {
                            response = new HttpHandler.Builder()
                                    .setUri(wmsUrl)
                                    .setPath("/rpc/pakin2/loc/v1")
                                    .setJson(JSON.toJSONString(param))
                                    .setTimeout(15, TimeUnit.SECONDS)
                                    .build()
                                    .doPost();
                        } catch(Exception e){
                            log.error("入库作业站"+pickSta.getStaNo()+"盘点再入库任务请求WMS===>>参数:" + param);
                            log.error("stnToCrnStnPick2===>>盘点查库位入库接口失败", e);
                            e.printStackTrace();
                            continue;
                        }
                        // 保存工作主档历史档
                        if (wrkMastMapper.saveWrkMastLog(wrkMast.getWrkNo()) == 0) {
                            throw new CoolException("保存工作主档历史档失败");
                        log.info("入库作业站"+pickSta.getStaNo()+"盘点再入库任务请求WMS===>>参数:" + param);
                        log.info("入库作业站"+pickSta.getStaNo()+"下发盘点再入库任务请求WMS返回结果===>>" + response);
                        if(response.equals("")) {
                            continue;
                        }
                        Date now = new Date();
                        // 堆垛机站点(目标站)
                        Integer staNo = staDesc.getCrnStn();
                        // 更新工作档数据状态
                        wrkMast.setIoTime(now);
                        wrkMast.setIoType(wrkMast.getIoType() - 50); // 入出库类型: 103->53,104->54,107->57
                        wrkMast.setWrkSts(2L); // 工作状态: 2.设备上走
                        wrkMast.setSourceStaNo(wrkMast.getStaNo()); // 源站
                        wrkMast.setStaNo(staNo); // 目标站
                        wrkMast.setLocNo(wrkMast.getSourceLocNo()); // 目标库位 = 出库时的源库位
                        wrkMast.setSourceLocNo(""); // 源库位清空
                        wrkMast.setModiTime(now);
                        if (wrkMastMapper.updateById(wrkMast) == 0) {
                            throw new CoolException("更新工作档数据状态失败");
                        }
                        // 更新明细档io_time (历史档关联使用)
                        wrkDetlService.updateIoTime(wrkMast.getWrkNo(), now);
                        // 修改库位状态 Q.拣料/盘点/并板再入库
                        LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
                        locMast.setLocSts("Q");
                        locMast.setModiTime(new Date());
                        if (!locMastService.updateById(locMast)) {
                            throw new CoolException("修改库位状态失败");
                        JSONObject jsonObject = JSON.parseObject(response);
//                        LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, pickSta.getLed());
                        Integer code = jsonObject.getInteger("code");
                        if (code == 200) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            if (Cools.isEmpty(dto) || Cools.isEmpty(dto.getStaNo())) {
                                log.error("任务号"+wrkMast.getWrkNo()+"盘点再入库查询库位失败===>>" + jsonObject.toJSONString());
                            } else {
                                log.info("任务号"+wrkMast.getWrkNo()+"盘点再入库查询库位成功===>>" + jsonObject.toJSONString());
                                try {
                                    // 更新站点信息 且 下发plc命令
                                    staProtocol.setWorkNo(wrkMast.getWrkNo());
                                    staProtocol.setStaNo(dto.getStaNo());
                                    devpThread.setPakMk(staProtocol.getSiteId(), false);
//                                    ledThread.errorReset();
                                    boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                                    if (!result) {
                                        log.error("发布命令至输送线队列失败!!! [plc编号:{}]", devp.getId());
                                    }
                                    log.info("任务号"+wrkMast.getWrkNo()+"盘点/拣料再入库任务下发成功===>>" + staProtocol);
                                } catch (Exception e) {
                                    log.error("盘点再入库失败===>>" + e);
                                    e.printStackTrace();
                                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                }
                            }
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin2/loc/v1", JSON.toJSONString(param), response);
                        }
                    } catch (Exception e) {
                        log.error("stnToCrnStnPick2===>>fail", e);
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        continue;
                    }
                    // 更新站点信息 且 下发plc命令
                    staProtocol.setWorkNo(wrkMast.getWrkNo().shortValue());
                    staProtocol.setStaNo(wrkMast.getStaNo().shortValue());
                    devpThread.setPakMk(staProtocol.getSiteId(), false);
                    boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                    if (!result) {
                        log.error("发布命令至输送线队列失败!!! [plc编号:{}]", devp.getId());
                    }
                }
@@ -446,64 +808,560 @@
    }
    /**
     * 堆垛机站出库到出库站
     * 拣料、并板、盘点再入库  拆垛位置
     */
    @Async
    public void crnStnToOutStn() {
        for (CrnSlave crnSlave : slaveProperties.getCrn()) {
            // 遍历堆垛机出库站
            for (CrnSlave.CrnStn crnStn : crnSlave.getCrnOutStn()) {
                // 获取堆垛机出库站信息
                DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
                StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
    public synchronized void stnToCrnStnPick2() {
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历拣料入库口
            for (DevpSlave.Sta pickSta : devp.getPickSta2()) {
                // 获取拣料入库站信息
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(pickSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                if (staProtocol.isAutoing() && staProtocol.isLoading() && (staProtocol.getWorkNo() == 0 || staProtocol.getStaNo() == null)) {
                    // 查询工作档
                    WrkMast wrkMast = wrkMastMapper.selectPakOutStep2(staProtocol.getSiteId());
                BasDevp basDevp = basDevpService.selectById(staProtocol.getSiteId());
                if (Cools.isEmpty(basDevp) || basDevp.getReportSign()!=1){
                    continue;
                }
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isPakMk() && staProtocol.getWorkNo()==0 && !staProtocol.isOutEnable() && staProtocol.isInEnable()) {
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep4(staProtocol.getSiteId(),"3");
                    if (wrkMast == null) {
                        continue;
                    }
                    // 判断工作档条件
                    if (wrkMast.getIoType() < 100 || wrkMast.getStaNo() == null || wrkMast.getSourceStaNo() == null) {
                    if (staProtocol.isEmptyMk()){
                        log.error("站点号"+staProtocol.getSiteId()+"空板信号异常!");
                        continue;
                    }
                    // 判断吊车是否实际已完成,且电脑状态在move中,以备电脑进行更新工作档
                    CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, wrkMast.getCrnNo());
                    CrnProtocol crnProtocol = crnThread.getCrnProtocol();
                    if ((wrkMast.getIoType() != 103 && wrkMast.getIoType() != 104 && wrkMast.getIoType() != 107)
                            || Cools.isEmpty(wrkMast.getStaNo()) || Cools.isEmpty(wrkMast.getSourceStaNo())) {
                        continue;
                    }
                    String barcode = wrkMast.getBarcode();
                    if(!Cools.isEmpty(barcode)) {
                        if("NG".endsWith(barcode) || "NoRead".equals(barcode) || "empty".equals(barcode)) {
                            continue;
                        }
                    } else {
                        continue;
                    }
                    //   获取库位号
                    try {
                        SearchLocParam param = new SearchLocParam();
                        param.setBarcode(barcode);
                        param.setIoType(wrkMast.getIoType());
                        param.setSourceStaNo(pickSta.getStaNo()); //作业站点
                        param.setLocType1((short)1);
                        String response = "";
                        log.info("入库作业站"+pickSta.getStaNo()+"盘点再入库任务请求WMS===>>参数:" + param);
                        try {
                            response = new HttpHandler.Builder()
                                    .setUri(wmsUrl)
                                    .setPath("/rpc/pakin2/loc/v1")
                                    .setJson(JSON.toJSONString(param))
                                    .setTimeout(15, TimeUnit.SECONDS)
                                    .build()
                                    .doPost();
                        } catch(Exception e){
                            log.error("入库作业站"+pickSta.getStaNo()+"盘点再入库任务请求WMS===>>参数:" + param);
                            log.error("stnToCrnStnPick2===>>盘点查库位入库接口失败", e);
                            e.printStackTrace();
                            continue;
                        }
                        log.info("入库作业站"+pickSta.getStaNo()+"盘点再入库任务请求WMS===>>参数:" + param);
                        log.info("入库作业站"+pickSta.getStaNo()+"下发盘点再入库任务请求WMS返回结果===>>" + response);
                        if(response.equals("")) {
                            continue;
                        }
                        JSONObject jsonObject = JSON.parseObject(response);
//                        LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, pickSta.getLed());
                        Integer code = jsonObject.getInteger("code");
                        if (code == 200) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            if (Cools.isEmpty(dto) || Cools.isEmpty(dto.getStaNo())) {
                                log.error("任务号"+wrkMast.getWrkNo()+"盘点再入库查询库位失败===>>" + jsonObject.toJSONString());
                            } else {
                                log.info("任务号"+wrkMast.getWrkNo()+"盘点再入库查询库位成功===>>" + jsonObject.toJSONString());
                                try {
                                    // 更新站点信息 且 下发plc命令
                                    staProtocol.setWorkNo(wrkMast.getWrkNo());
                                    staProtocol.setStaNo(dto.getStaNo());
                                    devpThread.setPakMk(staProtocol.getSiteId(), false);
//                                    ledThread.errorReset();
                                    boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                                    if (!result) {
                                        log.error("发布命令至输送线队列失败!!! [plc编号:{}]", devp.getId());
                                    }
                                    log.info("任务号"+wrkMast.getWrkNo()+"盘点/拣料再入库任务下发成功===>>" + staProtocol);
                                } catch (Exception e) {
                                    log.error("盘点再入库失败===>>" + e);
                                    e.printStackTrace();
                                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                }
                            }
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin2/loc/v1", JSON.toJSONString(param), response);
                        }
                    } catch (Exception e) {
                        log.error("stnToCrnStnPick2===>>fail", e);
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
//                    // 获取目标站
//                    Wrapper<StaDesc> wrapper = new EntityWrapper<StaDesc>()
//                            .eq("type_no", wrkMast.getIoType() - 50)
//                            .eq("stn_no", pickSta.getStaNo()) // 作业站点 = 拣料出库的目标站
//                            .eq("crn_no", wrkMast.getCrnNo()); // 堆垛机号
//                    StaDesc staDesc = staDescService.selectOne(wrapper);
//                    if (Cools.isEmpty(staDesc)) {
//                        log.error("入库路径不存在!type_no={},stn_no={},crn_no={}", wrkMast.getIoType(), pickSta.getStaNo(), wrkMast.getCrnNo());
//                        continue;
//                    }
//
//                    try {
//                        // 保存工作明细档历史档
//                        if (wrkMastMapper.saveWrkDetlLog(wrkMast.getWrkNo()) == 0) {
//                            throw new CoolException("保存工作明细档历史档失败");
//                        }
//                        // 保存工作主档历史档
//                        if (wrkMastMapper.saveWrkMastLog(wrkMast.getWrkNo()) == 0) {
//                            throw new CoolException("保存工作主档历史档失败");
//                        }
//
//                        Date now = new Date();
//                        // 堆垛机站点(目标站)
//                        Integer staNo = staDesc.getCrnStn();
//                        // 更新工作档数据状态
//                        wrkMast.setIoTime(now);
//                        wrkMast.setIoType(wrkMast.getIoType() - 50); // 入出库类型: 103->53,104->54,107->57
//                        wrkMast.setWrkSts(2L); // 工作状态: 2.设备上走
//                        wrkMast.setSourceStaNo(wrkMast.getStaNo()); // 源站
//                        wrkMast.setStaNo(staNo); // 目标站
//                        wrkMast.setLocNo(wrkMast.getSourceLocNo()); // 目标库位 = 出库时的源库位
//                        wrkMast.setSourceLocNo(""); // 源库位清空
//                        wrkMast.setModiTime(now);
//                        if (wrkMastMapper.updateById(wrkMast) == 0) {
//                            throw new CoolException("更新工作档数据状态失败");
//                        }
//                        // 更新明细档io_time (历史档关联使用)
//                        wrkDetlService.updateIoTime(wrkMast.getWrkNo(), now);
//                        // 修改库位状态 Q.拣料/盘点/并板再入库
//                        LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
//                        locMast.setLocSts("Q");
//                        locMast.setModiTime(new Date());
//                        if (!locMastService.updateById(locMast)) {
//                            throw new CoolException("修改库位状态失败");
//                        }
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                        continue;
//                    }
//
//                    // 更新站点信息 且 下发plc命令
//                    staProtocol.setWorkNo(wrkMast.getWrkNo());
//                    staProtocol.setStaNo(wrkMast.getStaNo());
//                    devpThread.setPakMk(staProtocol.getSiteId(), false);
//                    boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
//                    if (!result) {
//                        log.error("发布命令至输送线队列失败!!! [plc编号:{}]", devp.getId());
//                    }
                }
            }
        }
    }
    /**
     * 拣料、并板、盘点再入库  拆垛位置
     */
    public synchronized void storeEmptyPlt4() {
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历叠盘入库口
            for (DevpSlave.Sta pickSta : devp.getEmptyInSta2()) {
                // 获取入库站信息
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(pickSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                BasDevp basDevp = basDevpService.selectById(staProtocol.getSiteId());
                if (Cools.isEmpty(basDevp) || basDevp.getReportSign()!=1){
                    continue;
                }
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isPakMk() && staProtocol.getWorkNo()==0 && !staProtocol.isOutEnable() && staProtocol.isInEnable()) {
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep4(staProtocol.getSiteId(),"3");
                    if (wrkMast == null) {
                        WrkMast wrkMast1 = wrkMastMapper.selectPakInStep5(staProtocol.getSiteId(),"3");
                        if (Cools.isEmpty(wrkMast1) && staProtocol.isEmptyMk()){
                            WrkMastSta wrkMastSta = wrkMastStaMapper.selectByWrkNo(staProtocol.getSiteId() + 19999L);
                            if (Cools.isEmpty(wrkMastSta)){
                                WrkMastSta wrkMastSta1 = new WrkMastSta(new Date(),staProtocol.getSiteId());
                                wrkMastSta1.setType(2);
                                wrkMastSta1.setWrkType(1);
                                wrkMastStaMapper.insert(wrkMastSta1);
                            }
                        }
                    }
                }
            }
        }
    }
    /**
     * 堆垛机站出库到出库站
     */
    public synchronized void crnStnToOutStn() {
        for (CrnSlave crnSlave : slaveProperties.getCrn()) {
            // 遍历堆垛机出库站
            for (CrnSlave.CrnStn crnStn : crnSlave.getCrnOutStn()) {
                switch (crnSlave.getId()){
                    case 1:
                    case 2:
                        crnStnToOutStnOne(crnStn);
                        continue;
                    case 3:
                    case 4:
                    case 5:
                        crnStnToOutStnTwo(crnStn,1);
                        continue;
                    case 6:
                    case 7:
                        crnStnToOutStnThree(crnStn);
                        continue;
                    default:
                        break;
                }
            }
        }
    }
    /**
     * 堆垛机站出库到出库站
     */
    public synchronized boolean crnStnToOutStnOne(CrnSlave.CrnStn crnStn ) {
        try{
            // 获取堆垛机出库站信息
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                return false;
            } else {
                staProtocol = staProtocol.clone();
            }
            if (staProtocol.isAutoing() && staProtocol.isLoading() && (staProtocol.getWorkNo() == 0 || staProtocol.getStaNo() == null)) {
                // 查询工作档
                WrkMast wrkMast = wrkMastMapper.selectPakOutStep2(staProtocol.getSiteId());
                if (wrkMast == null) {
                    return false;
                }
                // 判断工作档条件
                if (wrkMast.getIoType() < 100 || wrkMast.getStaNo() == null || wrkMast.getSourceStaNo() == null) {
                    return false;
                }
                // 判断吊车是否实际已完成,且电脑状态在move中,以备电脑进行更新工作档
                CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, wrkMast.getCrnNo());
                CrnProtocol crnProtocol = crnThread.getCrnProtocol();
                if (crnProtocol.statusType == CrnStatusType.FETCHING || crnProtocol.statusType == CrnStatusType.PUTTING) {
                    // 移动中
                    return false;
                }
                WrkMastCrn wrkMastCrn = wrkMastCrnMapper.selectWrkNoOneAndTwo(crnProtocol.getTaskNo().intValue());
                if (!Cools.isEmpty(wrkMastCrn) && wrkMastCrn.getWrkSts().equals(12L)){
                    wrkMast = wrkMastMapper.selectPakInStep3(wrkMastCrn.getWrkNo().intValue());
                } else {
                    return false;
                }
                //  判断堆垛机状态等待确认
                if (crnProtocol.modeType == CrnModeType.AUTO && crnProtocol.getTaskNo().equals(wrkMast.getWrkNo().shortValue())
                        && crnProtocol.statusType == CrnStatusType.WAITING
                        && crnProtocol.forkPosType == CrnForkPosType.HOME) {
                    // 命令下发区 --------------------------------------------------------------------------
                    StaProtocol staProtocolOther = devpThread.getStation().get(crnStn.getStaNoOther());
                    if (staProtocolOther == null) {
                        return false;
                    } else {
                        staProtocolOther = staProtocolOther.clone();
                    }
                    if (staProtocolOther.isAutoing() && staProtocolOther.isLoading() && (staProtocolOther.getWorkNo() == 0 || staProtocolOther.getStaNo() == null)) {
//                        WrkMastCrn wrkMastCrn = wrkMastCrnMapper.selectWrkNoOneAndTwo(wrkMast.getWrkNo());
                        WrkMast wrkMastOne = wrkMastMapper.selectPakInStep3(wrkMastCrn.getWrkNoOne().intValue());
                        WrkMast wrkMastTwo = wrkMastMapper.selectPakInStep3(wrkMastCrn.getWrkNoTwo().intValue());
                        WrkMast wrkMast1 = null;
                        WrkMast wrkMast2 = null;
                        if (Utils.getRow(wrkMastOne.getSourceLocNo()) == wrkMast.getCrnNo()*4){
                            wrkMast1 = wrkMastTwo;
                            wrkMast2 = wrkMastOne;
                        }else {
                            wrkMast2 = wrkMastTwo;
                            wrkMast1 = wrkMastOne;
                        }
                        // 下发站点信息
                        staProtocolOther.setWorkNo(Cools.isEmpty(wrkMast1.getWorkNoOther())? wrkMast1.getWrkNo():wrkMast1.getWorkNoOther());
                        staProtocolOther.setStaNo(wrkMast1.getStaNo());
                        if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocolOther))) {
                            return false;
                        }
                        // 下发站点信息
                        staProtocol.setWorkNo(Cools.isEmpty(wrkMast2.getWorkNoOther())? wrkMast2.getWrkNo():wrkMast2.getWorkNoOther());
//                                    staProtocol.setStaNo(RouteUtils.CrnStaEnd(wrkMast.getStaNo(),wrkMast.getSourceStaNo()));
                        staProtocol.setStaNo(wrkMast2.getStaNo());
                        if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocol))) {
                            return false;
                        }
                        boolean sign = true;
                        // 更新工作档状态为14失败
                        wrkMastCrn.setWrkSts(14L);
                        if (wrkMastCrnMapper.updateById(wrkMastCrn) != 0) {
                        } else {
                            sign = false;
                            log.error("更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo());
                        }
                        // 更新工作档状态为14失败
                        wrkMastOne.setWrkSts(14L);
                        wrkMastOne.setCrnEndTime(new Date());
                        if (wrkMastMapper.updateById(wrkMastOne) != 0) {
                        } else {
                            sign = false;
                            log.error("更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo());
                        }
                        // 更新工作档状态为14失败
                        wrkMastTwo.setWrkSts(14L);
                        wrkMastTwo.setCrnEndTime(new Date());
                        if (wrkMastMapper.updateById(wrkMastTwo) != 0) {
                        } else {
                            sign = false;
                            log.error("更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo());
                        }
                        if (sign){
                            // 复位堆垛机
                            crnThread.setResetFlag(true);
                            return true;
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("更新工作档的工作状态为14失败!!! [出库站:{}]", crnStn.getStaNo());
        }
        return false;
    }
    public synchronized boolean crnStnToOutStnTwo(CrnSlave.CrnStn crnStn ,Integer conStation) {
        try{
            Date now = new Date();
            // 获取堆垛机出库站信息
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                return false;
            } else {
                staProtocol = staProtocol.clone();
            }
            if (staProtocol.isAutoing() && staProtocol.isLoading() && (staProtocol.getWorkNo() == 0 || staProtocol.getStaNo() == null)) {
                // 查询工作档
                WrkMast wrkMast = wrkMastMapper.selectPakOutStep2(staProtocol.getSiteId());
                if (wrkMast == null) {
                    return false;
                }
                // 判断工作档条件
                if (wrkMast.getIoType() < 100 || wrkMast.getStaNo() == null || wrkMast.getSourceStaNo() == null) {
                    return false;
                }
                // 判断吊车是否实际已完成,且电脑状态在move中,以备电脑进行更新工作档
                CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, wrkMast.getCrnNo());
                CrnProtocol crnProtocol = crnThread.getCrnProtocol();
                if (conStation==1){
                    if (crnProtocol.statusType == CrnStatusType.FETCHING || crnProtocol.statusType == CrnStatusType.PUTTING) {
                        // 移动中
                        continue;
                        return false;
                    }
                    //  判断堆垛机状态等待确认
                    if (crnProtocol.modeType == CrnModeType.AUTO && crnProtocol.getTaskNo().equals(wrkMast.getWrkNo().shortValue())
                            && crnProtocol.statusType == CrnStatusType.WAITING
                            && crnProtocol.forkPosType == CrnForkPosType.HOME) {
                        // 命令下发区 --------------------------------------------------------------------------
                        // 下发站点信息
                        staProtocol.setWorkNo(wrkMast.getWrkNo().shortValue());
                        staProtocol.setStaNo(wrkMast.getStaNo().shortValue());
                        if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocol))) {
                            continue;
                            && crnProtocol.forkPosType == CrnForkPosType.HOME
                            && crnProtocol.getLoaded()==0) {
                        List<WrkMastSplitTwin> wrkMastSplitTwinList = wrkMastSplitTwinMapper.getWrkMastSplitTwin(wrkMast.getCrnNo(), conStation, null, 2, 3);
                        if (wrkMastSplitTwinList.size()!=1){
                            log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",wrkMast.getCrnNo(),"不存在或者存在多笔可执行作业,请删除无效作业!!!",conStation,2,3);
                        }
                        // 更新工作档状态为14失败
                        wrkMast.setWrkSts(14L);
                        wrkMast.setCrnEndTime(new Date());
                        if (wrkMastMapper.updateById(wrkMast) != 0) {
                            // 复位堆垛机
                            crnThread.setResetFlag(true);
                        } else {
                            log.error("更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo());
                        for (WrkMastSplitTwin wrkMastSplitTwin:wrkMastSplitTwinList){
                            if (wrkMastSplitTwin.getWrkNo()!=wrkMast.getWrkNo().longValue()){
                                log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={},工作任务号={},执行任务号={}",wrkMast.getCrnNo(),"工作任务与执行任务不匹配",conStation,2,3,wrkMast.getWrkNo(),wrkMastSplitTwin.getWrkNo());
                                return false;
                            }
                            // 命令下发区 --------------------------------------------------------------------------
                            // 下发站点信息
                            staProtocol.setWorkNo(wrkMast.getWrkNo());
                            staProtocol.setStaNo(RouteUtils.CrnStaEnd(wrkMast.getStaNo(),wrkMast.getSourceStaNo()));
                            if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocol))) {
                                return false;
                            }
                            // 更新工作档状态为14失败
                            wrkMast.setWrkSts(14L);
                            wrkMast.setCrnEndTime(now);
                            if (wrkMastMapper.updateById(wrkMast) != 0) {
                                wrkMastSplitTwin.setWrkSts(wrkMastSplitTwin.getWrkSts()+1);
                                wrkMastSplitTwin.setUpdateTime(now);
                                // 修改成功后复位堆垛机
                                if (wrkMastSplitTwinService.updateById(wrkMastSplitTwin)) {
                                    // 堆垛机复位
                                    crnThread.setResetFlag(true);
                                    return true;
                                }else {
                                    log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",wrkMast.getCrnNo(),"修改执行档案失败",conStation,2,3);
                                }
                            } else {
                                log.error("更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo());
                            }
                        }
                    }
                }else if (conStation==2){
                    if (crnProtocol.statusTypeTwo == CrnStatusType.FETCHING || crnProtocol.statusTypeTwo == CrnStatusType.PUTTING) {
                        // 移动中
                        return false;
                    }
                    //  判断堆垛机状态等待确认
                    if (crnProtocol.modeType == CrnModeType.AUTO && crnProtocol.getTaskNoTwo().equals(wrkMast.getWrkNo().shortValue())
                            && crnProtocol.statusTypeTwo == CrnStatusType.WAITING
                            && crnProtocol.forkPosTypeTwo == CrnForkPosType.HOME
                            && crnProtocol.getLoadedTwo()==0) {
                        List<WrkMastSplitTwin> wrkMastSplitTwinList = wrkMastSplitTwinMapper.getWrkMastSplitTwin(wrkMast.getCrnNo(), conStation, null, 2, 3);
                        if (wrkMastSplitTwinList.size()!=1){
                            log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",wrkMast.getCrnNo(),"不存在或者存在多笔可执行作业,请删除无效作业!!!",conStation,2,3);
                        }
                        for (WrkMastSplitTwin wrkMastSplitTwin:wrkMastSplitTwinList){
                            if (wrkMastSplitTwin.getWrkNo()!=wrkMast.getWrkNo().longValue()){
                                log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={},工作任务号={},执行任务号={}",wrkMast.getCrnNo(),"工作任务与执行任务不匹配",conStation,2,3,wrkMast.getWrkNo(),wrkMastSplitTwin.getWrkNo());
                                return false;
                            }
                            // 命令下发区 --------------------------------------------------------------------------
                            // 下发站点信息
                            staProtocol.setWorkNo(wrkMast.getWrkNo());
                            staProtocol.setStaNo(RouteUtils.CrnStaEnd(wrkMast.getStaNo(),wrkMast.getSourceStaNo()));
                            if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocol))) {
                                return false;
                            }
                            // 更新工作档状态为14失败
                            wrkMast.setWrkSts(14L);
                            wrkMast.setCrnEndTime(now);
                            if (wrkMastMapper.updateById(wrkMast) != 0) {
                                wrkMastSplitTwin.setWrkSts(wrkMastSplitTwin.getWrkSts()+1);
                                wrkMastSplitTwin.setUpdateTime(now);
                                // 修改成功后复位堆垛机
                                if (wrkMastSplitTwinService.updateById(wrkMastSplitTwin)) {
                                    // 堆垛机复位
                                    crnThread.setResetFlagTwo(true);
                                    return true;
                                }else {
                                    log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",wrkMast.getCrnNo(),"修改执行档案失败",conStation,2,3);
                                }
                            } else {
                                log.error("更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo());
                            }
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("更新工作档的工作状态为14失败!!! [出库站:{}]", crnStn.getStaNo());
        }
        return false;
    }
    public synchronized boolean crnStnToOutStnThree(CrnSlave.CrnStn crnStn ) {
        try{
            // 获取堆垛机出库站信息
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                return false;
            } else {
                staProtocol = staProtocol.clone();
            }
            if (staProtocol.isAutoing() && staProtocol.isLoading() && (staProtocol.getWorkNo() == 0 || staProtocol.getStaNo() == null)) {
                // 查询工作档
                WrkMast wrkMast = wrkMastMapper.selectPakOutStep2(staProtocol.getSiteId());
                if (wrkMast == null) {
                    return false;
                }
                // 判断工作档条件
                if (wrkMast.getIoType() < 100 || wrkMast.getStaNo() == null || wrkMast.getSourceStaNo() == null) {
                    return false;
                }
                // 判断吊车是否实际已完成,且电脑状态在move中,以备电脑进行更新工作档
                CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, wrkMast.getCrnNo());
                CrnProtocol crnProtocol = crnThread.getCrnProtocol();
                if (crnProtocol.statusType == CrnStatusType.FETCHING || crnProtocol.statusType == CrnStatusType.PUTTING) {
                    // 移动中
                    return false;
                }
                //  判断堆垛机状态等待确认
                if (crnProtocol.modeType == CrnModeType.AUTO && crnProtocol.getTaskNo().equals(wrkMast.getWrkNo().shortValue())
                        && crnProtocol.statusType == CrnStatusType.WAITING
                        && crnProtocol.forkPosType == CrnForkPosType.HOME) {
                    // 命令下发区 --------------------------------------------------------------------------
                    // 下发站点信息
                    staProtocol.setWorkNo(wrkMast.getWrkNo());
                    staProtocol.setStaNo(RouteUtils.CrnStaEnd(wrkMast.getStaNo(),wrkMast.getSourceStaNo()));
                    if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocol))) {
                        return false;
                    }
                    // 更新工作档状态为14失败
                    wrkMast.setWrkSts(14L);
                    wrkMast.setCrnEndTime(new Date());
                    if (wrkMastMapper.updateById(wrkMast) != 0) {
                        // 复位堆垛机
                        crnThread.setResetFlag(true);
                        return true;
                    } else {
                        log.error("更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo());
                    }
                }
            }
        }catch (Exception e){
            log.error("更新工作档的工作状态为14失败!!! [出库站:{}]", crnStn.getStaNo());
        }
        return false;
    }
    /**
     * 堆垛机站出库到出库站
     */
    public synchronized void crnStnToOutStnTwo() {
        for (CrnSlave crnSlave : slaveProperties.getCrn()) {
            // 遍历堆垛机出库站
            for (CrnSlave.CrnStn crnStn : crnSlave.getCrnOutStn()) {
                switch (crnSlave.getId()){
                    case 3:
                    case 4:
                    case 5:
                        crnStnToOutStnTwo(crnStn,2);
                        continue;
                    default:
                        break;
                }
            }
        }
@@ -513,115 +1371,211 @@
     * 入出库  ===>>  堆垛机入出库作业下发
     */
    public synchronized void crnIoExecute() {
        for (CrnSlave crn : slaveProperties.getCrn()) {
            // 获取堆垛机信息
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
            if (crnProtocol == null) {
                continue;
            }
            BasCrnp basCrnp = basCrnpService.selectById(crn.getId());
            if (basCrnp == null) {
                log.error("{}号堆垛机尚未在数据库进行维护!", crn.getId());
                continue;
            }
        try{
            for (CrnSlave crn : slaveProperties.getCrn()) {
                // 获取堆垛机信息
                CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
                CrnProtocol crnProtocol = crnThread.getCrnProtocol();
                if (crnProtocol == null) {
                    continue;
                }
                BasCrnp basCrnp = basCrnpService.selectById(crn.getId());
                if (basCrnp == null) {
                    log.error("{}号堆垛机尚未在数据库进行维护!", crn.getId());
                    continue;
                }
//            //堆垛机回原点任务中
//            if(crnThread.isBackHpFlag()){
//                continue;
//            }
            // 只有当堆垛机空闲 并且 无任务时才继续执行
            if (crnProtocol.getStatusType() == CrnStatusType.IDLE && crnProtocol.getTaskNo() == 0 && crnProtocol.getModeType() == CrnModeType.AUTO
                    && crnProtocol.getLoaded() == 0 && crnProtocol.getForkPos() == 0) {
                // 如果最近一次是入库模式
                if (crnProtocol.getLastIo().equals("I")) {
                    if (basCrnp.getInEnable().equals("Y")) {
                        this.crnStnToLoc(crn, crnProtocol); //  入库
                        crnProtocol.setLastIo("O");
                    } else if (basCrnp.getOutEnable().equals("Y")) {
                        this.locToCrnStn(crn, crnProtocol); //  出库
                        crnProtocol.setLastIo("I");
                // 只有当堆垛机空闲 并且 无任务时才继续执行
                if (crnProtocol.getStatusType() == CrnStatusType.IDLE
                        && crnProtocol.getTaskNo() == 0
                        && crnProtocol.getModeType() == CrnModeType.AUTO
                        && crnProtocol.getLoaded() == 0
                        && crnProtocol.getForkPos() == 0) {
                    // 如果最近一次是入库模式
                    if (crnProtocol.getLastIo().equals("I")) {
                        if (basCrnp.getInEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 1:
                                case 2:
                                    this.crnStnToLoc1Single(crn, crnProtocol); //  入库
                                    break;
                                case 3:
                                case 4:
                                case 5:
                                    continue;
                                default:
                                    this.crnStnToLoc1(crn, crnProtocol,1); //  入库
                            }
                            crnProtocol.setLastIo("O");
                        } else if (basCrnp.getOutEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 1:
                                case 2:
                                    this.locToCrnStn1Single(crn, crnProtocol); //  出库
                                    break;
                                case 3:
                                case 4:
                                case 5:
                                    continue;
                                default:
                                    this.locToCrnStn1(crn, crnProtocol,1); //  出库
                            }
                            crnProtocol.setLastIo("I");
                        }
                    }
                    // 如果最近一次是出库模式
                    else if (crnProtocol.getLastIo().equals("O")) {
                        if (basCrnp.getOutEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 1:
                                case 2:
                                    this.locToCrnStn1Single(crn, crnProtocol); //  出库
                                    break;
                                case 3:
                                case 4:
                                case 5:
                                    continue;
                                default:
                                    this.locToCrnStn1(crn, crnProtocol,1); //  出库
                            }
                            crnProtocol.setLastIo("I");
                        } else if (basCrnp.getInEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 1:
                                case 2:
                                    this.crnStnToLoc1Single(crn, crnProtocol); //  入库
                                    break;
                                case 3:
                                case 4:
                                case 5:
                                    continue;
                                default:
                                    this.crnStnToLoc1(crn, crnProtocol,1); //  入库
                            }
                            crnProtocol.setLastIo("O");
                        }
                    }
                }
                // 如果最近一次是出库模式
                else if (crnProtocol.getLastIo().equals("O")) {
                    if (basCrnp.getOutEnable().equals("Y")) {
                        this.locToCrnStn(crn, crnProtocol); //  出库
                        crnProtocol.setLastIo("I");
                    } else if (basCrnp.getInEnable().equals("Y")) {
                        this.crnStnToLoc(crn, crnProtocol); //  入库
                        crnProtocol.setLastIo("O");
                    }
                }
            }
            // 库位移转
            this.locToLoc(crn, crnProtocol);
                // 库位移转
                this.locToLoc(crn, crnProtocol);
//            this.crnRebackHp(crnProtocol, crnThread);
            }
        }catch (Exception e){
            log.error("堆垛机出入库下发报错"+e);
        }
    }
    /**
     * 回原点,堆垛机没有执行中任务,设备存在入库任务时叫回原点
     * 入出库  ===>>  堆垛机入出库作业下发
     */
    public synchronized void crnRebackHp(CrnProtocol crnProtocol, CrnThread crnThread) {
//        for (CrnSlave crn : slaveProperties.getCrn()) {
//            // 获取堆垛机信息
//            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
//            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
//            if (crnProtocol == null) {
//                continue;
//            }
//            BasCrnp basCrnp = basCrnpService.selectById(crn.getId());
//            if (basCrnp == null) {
//                log.error("{}号堆垛机尚未在数据库进行维护!", crn.getId());
//                continue;
//            }
        if (crnProtocol.getStatusType() == CrnStatusType.IDLE && crnProtocol.getTaskNo() == 0 && crnProtocol.getModeType() == CrnModeType.AUTO) {
            if (crnProtocol.getBay() == 1 && crnProtocol.getLevel() == 1) {
                return;
            }
    public synchronized void crnIoExecuteTwo() {
        try{
            for (CrnSlave crn : slaveProperties.getCrn()) {
                // 获取堆垛机信息
                CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
                CrnProtocol crnProtocol = crnThread.getCrnProtocol();
                if (crnProtocol == null) {
                    continue;
                }
                BasCrnp basCrnp = basCrnpService.selectById(crn.getId());
                if (basCrnp == null) {
                    log.error("{}号堆垛机尚未在数据库进行维护!", crn.getId());
                    continue;
                }
            // 已经存在吊车执行任务时,则过滤3,12
            if (wrkMastMapper.selectWorking(crnProtocol.getCrnNo()) != null) {
                return;
            }
            //堆垛机有执行中任务,过滤3,4,11,12
            if (wrkMastMapper.selectCrnWorking(crnProtocol.getCrnNo()) != null) {
                return;
            }
                int[] sign = new int[]{0,0};
                // 只有当堆垛机空闲 并且 无任务时才继续执行
                if (crnProtocol.getModeType() == CrnModeType.AUTO) {
                    // 只有当堆垛机工位空闲 并且 无任务时才继续执行
                    if (crnProtocol.getStatusType() == CrnStatusType.IDLE
                            && crnProtocol.getTaskNo() == 0
                            && crnProtocol.getLoaded() == 0
                            && crnProtocol.getForkPos() == 0) {
                        /*
                        * 任务拆分特殊处理
                        * */
                        if (crnProtocol.getStatusTypeTwo() == CrnStatusType.IDLE
                                && crnProtocol.getTaskNoTwo() == 0
                                && crnProtocol.getLoadedTwo() == 0
                                && crnProtocol.getForkPosTwo() == 0){
                            sign[0] = 1;
                            sign[1] = 1;
                        }
                    }
                }
            //输送线没有入库任务,过滤2
            if (wrkMastMapper.selectDevWorking(crnProtocol.getCrnNo()) == null) {
                return;
                if (sign[0]==1){
                    // 如果最近一次是入库模式
                    if (crnProtocol.getLastIo().equals("I")) {
                        if (basCrnp.getInEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 3:
                                case 4:
                                case 5:
                                    this.crnStnToLoc1Big(crn, crnProtocol, sign[1]); //  入库
                                    break;
                                default:
                                    continue;
                            }
                            crnProtocol.setLastIo("O");
                        } else if (basCrnp.getOutEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 3:
                                case 4:
                                case 5:
                                    this.locToCrnStn1Big(crn, crnProtocol, sign[1]); //  出库
                                    break;
                                default:
                                    continue;
                            }
                            crnProtocol.setLastIo("I");
                        }
                    }
                    // 如果最近一次是出库模式
                    else if (crnProtocol.getLastIo().equals("O")) {
                        if (basCrnp.getOutEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 3:
                                case 4:
                                case 5:
                                    this.locToCrnStn1Big(crn, crnProtocol, sign[1]); //  出库
                                    break;
                                default:
                                    continue;
                            }
                            crnProtocol.setLastIo("I");
                        } else if (basCrnp.getInEnable().equals("Y")) {
                            switch (crn.getId()){
                                case 3:
                                case 4:
                                case 5:
                                    this.crnStnToLoc1Big(crn, crnProtocol, sign[1]); //  入库
                                    break;
                                default:
                                    continue;
                            }
                            crnProtocol.setLastIo("O");
                        }
                    }
                }
                // 库位移转
                this.locToLoc(crn, crnProtocol);
//            this.crnRebackHp(crnProtocol, crnThread);
            }
            log.info("堆垛机召回原点==>>" + crnProtocol.getCrnNo() + "号堆垛机有入库任务,召回原点");
            // 命令下发区 --------------------------------------------------------------------------
            CrnCommand crnCommand = new CrnCommand();
            crnCommand.setCrnNo(crnProtocol.getCrnNo()); // 堆垛机编号
            crnCommand.setTaskNo((short) 9999); // 工作号
            crnCommand.setAckFinish((short) 0);  // 任务完成确认位
            crnCommand.setTaskMode(CrnTaskModeType.GO_ORIGIN); // 任务模式:  回原点
            crnCommand.setSourcePosX((short) 0);     // 源库位排
            crnCommand.setSourcePosY((short) 0);     // 源库位列
            crnCommand.setSourcePosZ((short) 0);     // 源库位层
            crnCommand.setDestinationPosX((short) 0);     // 目标库位排
            crnCommand.setDestinationPosY((short) 0);     // 目标库位列
            crnCommand.setDestinationPosZ((short) 0);     // 目标库位层
            if (!MessageQueue.offer(SlaveType.Crn, crnProtocol.getCrnNo(), new Task(2, crnCommand))) {
                log.error("堆垛机回原点命令下发失败,堆垛机号={},任务数据={}", crnProtocol.getCrnNo(), JSON.toJSON(crnCommand));
            }
            crnThread.setBackHpFlag(true);
        }catch (Exception e){
            log.error("堆垛机出入库下发报错"+e);
        }
//        }
    }
    /**
     * 入库  ===>>  堆垛机站到库位
     */
    public void crnStnToLoc(CrnSlave slave, CrnProtocol crnProtocol) {
    public synchronized void crnStnToLoc(CrnSlave slave, CrnProtocol crnProtocol) {
        for (CrnSlave.CrnStn crnStn : slave.getCrnInStn()) {
            boolean flag = false;
            // 获取堆垛机入库站信息
@@ -703,7 +1657,7 @@
                    }
                    continue;
                } else if (shallowLoc.getLocSts().equals("Q")) {
                    WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                    WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                    if (null != waitWrkMast && waitWrkMast.getWrkSts() == 4) {
                        continue;
                    }
@@ -751,10 +1705,467 @@
    }
    /**
     * 入库  ===>>  堆垛机站到库位
     * 2024-06-05
     */
    public synchronized void crnStnToLoc1Big(CrnSlave slave, CrnProtocol crnProtocol, Integer crnStation) {
        List<WrkMast> wrkMasts = wrkMastMapper.selectPakInStep12(slave.getId());
        Integer crnStation1 = crnStation;//记录
        for(WrkMast wrkMast : wrkMasts){
            if (wrkMast == null) {
                continue;
            }
            crnStation=crnStation1;//刷新
            CrnSlave.CrnStn crnStn = null;
            for (CrnSlave.CrnStn crnStn1 : slave.getCrnInStn()){
                if(crnStn1.getStaNo().equals(wrkMast.getStaNo())){
                    crnStn = crnStn1;
                    break;
                }
            }
            if(Cools.isEmpty(crnStn)){
                continue;
            }
            boolean flag = false;
            // 获取堆垛机入库站信息
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                continue;
            } else {
                staProtocol = staProtocol.clone();
            }
            // 查询站点详细信息
            BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
            if (staDetl == null) {
                log.error("入库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
                continue;
            }
            if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.getWorkNo().equals(wrkMast.getWrkNo())
                    && staProtocol.isInEnable() && staDetl.getCanining() != null && staDetl.getCanining().equals("Y")) {
                flag = true;
            }
            if (!flag) {
                continue;
            }
            // 获取库位信息
            LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
            if (locMast == null) {
                log.error("查询库存无数据--库位号{}", wrkMast.getLocNo());
                continue;
            }
            if (!locMast.getLocSts().equals("S") && !locMast.getLocSts().equals("Q")) {
                log.error("入库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMast.getLocNo(), locMast.getLocSts());
                continue;
            }
            //工位
            if (crnStation == 1){
                // 堆垛机控制过滤
                if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) {
                    break;
                }
                // 堆垛机控制过滤
                if (!crnProtocol.getStatusTypeTwo().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNoTwo() != 0) {
                    break;
                }
            }else if(crnStation == 2){
                // 堆垛机控制过滤
                if (!crnProtocol.getStatusTypeTwo().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNoTwo() != 0) {
                    break;
                }
            }else {
                break;
            }
            if (locMast.getBay1()==81){
                crnStation=2;
            }
            // 已经存在吊车执行任务时,则过滤
            if (wrkMastMapper.selectWorking(slave.getId()) != null) {
                continue;
            }
            // 已经存在吊车执行任务时,则过滤
            if (wrkMastSplitTwinMapper.selectCount(new EntityWrapper<WrkMastSplitTwin>().eq("wrk_no", wrkMast.getWrkNo().longValue())) != 0) {
                break;
//                        return;
            }
            // 双深库位且浅库位有货,则需先对浅库位进行库位移转
            if (Utils.isDeepLoc(slaveProperties, wrkMast.getLocNo())) {
                String shallowLocNo = Utils.getShallowLoc(slaveProperties, wrkMast.getLocNo());
                LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                // O.空库位、Q.拣料/盘点/并板再入库、S.入库预约、X.禁用 直接搬!
                if (shallowLoc.getLocSts().equals("P") || shallowLoc.getLocSts().equals("R")) {
                    WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                    if (null == waitWrkMast) {
                        log.error("{}库位异常,未检索到相应工作档!", shallowLocNo);
                    } else {
                        waitWrkMast.setIoPri(15D);
                        waitWrkMast.setModiTime(new Date());
                        if (wrkMastMapper.updateById(waitWrkMast) == 0) {
                            log.error("调整工作档优先级失败!工作号={}", waitWrkMast.getWrkNo());
                        }
                        continue;
                    }
                } else if (shallowLoc.getLocSts().equals("F") || shallowLoc.getLocSts().equals("D")) {
                    // 此标记避免多次执行移库任务
                    if (Cools.isEmpty(wrkMast.getUpdMk()) || "N".equals(wrkMast.getUpdMk())) {
                        wrkMast.setUpdMk("Y");
                        wrkMast.setIoPri(14D);
                        wrkMastMapper.updateById(wrkMast);
                        // 生成工作档,将浅库位移转到新的库位中
                        moveLocForDeepLoc(slave, shallowLoc);
                        // 生成工作档、改变浅库位的源库/目标库 库位状态、下发堆垛机命令(立马执行)
//                        moveLocForDeepLocPakin(slave, shallowLoc, wrkMast);
                    }
                    continue;
                } else if (shallowLoc.getLocSts().equals("Q")) {
                    WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                    if (null != waitWrkMast && waitWrkMast.getWrkSts() == 4) {
                        continue;
                    }
                }
            }
            // 命令下发区 --------------------------------------------------------------------------
            CrnCommand crnCommand = new CrnCommand();
            crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
            crnCommand.setTaskNo(wrkMast.getWrkNo().shortValue()); // 工作号
            crnCommand.setAckFinish((short) 0);  // 任务完成确认位
            crnCommand.setTaskMode(CrnTaskModeType.SEPARATE_TAKE); // 任务模式:  单取货
            crnCommand.setSourcePosX(crnStn.getRow().shortValue());     // 源库位排
            crnCommand.setSourcePosY(crnStn.getBay().shortValue());     // 源库位列
            crnCommand.setSourcePosZ(crnStn.getLev().shortValue());     // 源库位层
            crnCommand.setDestinationPosX((short)0);     // 目标库位排
            crnCommand.setDestinationPosY((short)0);     // 目标库位列
            crnCommand.setDestinationPosZ((short)0);     // 目标库位层
            if (!MessageQueue.offer(SlaveType.Crn, wrkMast.getCrnNo(), new Task(crnStation==1? 2:5, crnCommand))) {
                log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMast.getCrnNo(), JSON.toJSON(crnCommand));
            } else {
                // 修改工作档状态 2.设备上走 => 3.吊车入库中
                Date now = new Date();
                wrkMast.setWrkSts(3L);
                wrkMast.setCrnStrTime(now);
                wrkMast.setModiTime(now);
                WrkMastSplitTwin wrkMastSplitTwin = new WrkMastSplitTwin(wrkMast,crnStation,now);
                wrkMastSplitTwin.setWrkSts(1);
                wrkMastSplitTwin.setWrkStart(wrkMast.getStaNo().toString());
                wrkMastSplitTwin.setWrkEnd(wrkMast.getLocNo());
                wrkMastSplitTwin.setStartRow(crnStn.getRow());
                wrkMastSplitTwin.setStartBay(crnStn.getBay());
                wrkMastSplitTwin.setStartLev(crnStn.getLev());
                wrkMastSplitTwin.setEndRow(locMast.getRow1());
                wrkMastSplitTwin.setEndBay(locMast.getBay1());
                wrkMastSplitTwin.setEndLev(locMast.getLev1());
                wrkMastSplitTwin.setWrkType(1);
                wrkMastSplitTwin.setIoType(1);
                if (wrkMastMapper.updateById(wrkMast) == 0) {
                    log.error("修改工作档状态 2.设备上走 => 3.吊车入库中 失败!!,工作号={}", wrkMast.getWrkNo());
                }
                if (wrkMastSplitTwinMapper.insert(wrkMastSplitTwin)==0){
                    log.error("创建 堆垛机执行任务 失败!!,工作号={},堆垛机号={}", wrkMast.getWrkNo(),wrkMast.getCrnNo());
                }
                break;
            }
        }
    }
    /**
     * 入库  ===>>  堆垛机站到库位
     * 2024-01-15 煜星小料箱
     */
    public synchronized void crnStnToLoc1Single(CrnSlave slave, CrnProtocol crnProtocol) {
        List<WrkMast> wrkMasts = wrkMastMapper.selectPakInStep12(slave.getId());
        for(WrkMast wrkMast : wrkMasts){
            if (wrkMast == null) {
                continue;
            }
            CrnSlave.CrnStn crnStn = null;
            for (CrnSlave.CrnStn crnStn1 : slave.getCrnInStn()){
                if(crnStn1.getStaNo().equals(wrkMast.getStaNo())){
                    crnStn = crnStn1;
                    break;
                }
            }
            if(Cools.isEmpty(crnStn)){
                continue;
            }
            boolean flag = false;
            boolean flagOther = false;
            // 获取堆垛机入库站信息
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                continue;
            } else {
                staProtocol = staProtocol.clone();
            }
            StaProtocol staProtocolOther = devpThread.getStation().get(crnStn.getStaNoOther());
            if (staProtocolOther == null) {
                continue;
            } else {
                staProtocolOther = staProtocolOther.clone();
            }
            // 查询站点详细信息
            BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
            if (staDetl == null) {
                log.error("入库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
                continue;
            }
            if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.getWorkNo().equals(wrkMast.getWrkNo())
                    && staProtocol.isInEnable() && staDetl.getCanining() != null && staDetl.getCanining().equals("Y")) {
                flag = true;
            }
            if (staProtocol.getWorkNo().equals(staProtocolOther.getWorkNo())){
                continue;
            }
            // 查询站点详细信息
            BasDevp staDetlOther = basDevpService.selectById(crnStn.getStaNoOther());
            if (staDetlOther == null) {
                log.error("入库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNoOther());
                continue;
            }
            if (staProtocolOther.isAutoing() && staProtocolOther.isLoading() && staProtocolOther.getWorkNo() > 0 && staProtocolOther.isInEnable()
                    && staDetlOther.getCanining() != null && staDetlOther.getCanining().equals("Y")) {
                flagOther = true;
            }
            if (!flag || !flagOther) {
                continue;
            }
            //查询堆垛机任务
            WrkMastCrn wrkMastCrn = wrkMastCrnMapper.selectWrkNoOneAndTwo(wrkMast.getWrkNo());
            if (Cools.isEmpty(wrkMastCrn)){
                continue;
            }
            WrkMast wrkMastOther = wrkMastMapper.selectPakInStep3(wrkMastCrn.getWrkNoTwo().intValue());
            // 获取库位信息
            LocMast locMast = locMastService.selectById(Utils.getRow(wrkMastCrn.getLocNo())%4>2? wrkMastCrn.getLocNoTwo():wrkMastCrn.getLocNoOne());
            if (locMast == null) {
                log.error("查询库存无数据--库位号{}", wrkMastCrn.getLocNo());
                continue;
            }
            if (!locMast.getLocSts().equals("S") && !locMast.getLocSts().equals("Q")) {
                log.error("入库操作库位状态不符合--状态, 库位号={},库位状态={}", locMast.getLocNo(), locMast.getLocSts());
                continue;
            }
            // 堆垛机控制过滤
            if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) {
                continue;
            }
            // 已经存在吊车执行任务时,则过滤
            if (wrkMastMapper.selectWorking(slave.getId()) != null) {
                continue;
            }
            // 命令下发区 --------------------------------------------------------------------------
            CrnCommand crnCommand = new CrnCommand();
            crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
            crnCommand.setTaskNo(wrkMast.getWrkNo().shortValue()); // 工作号
            crnCommand.setAckFinish((short) 0);  // 任务完成确认位
            crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE); // 任务模式:  库位移转
            crnCommand.setSourcePosX(crnStn.getRow().shortValue());     // 源库位排
            crnCommand.setSourcePosY(crnStn.getBay().shortValue());     // 源库位列
            crnCommand.setSourcePosZ(crnStn.getLev().shortValue());     // 源库位层
            crnCommand.setDestinationPosX(locMast.getRow1().shortValue());     // 目标库位排
            crnCommand.setDestinationPosY(locMast.getBay1().shortValue());     // 目标库位列
            crnCommand.setDestinationPosZ(locMast.getLev1().shortValue());     // 目标库位层
            if (!MessageQueue.offer(SlaveType.Crn, wrkMast.getCrnNo(), new Task(2, crnCommand))) {
                log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMast.getCrnNo(), JSON.toJSON(crnCommand));
            } else {
                // 修改工作档状态 2.设备上走 => 3.吊车入库中
                Date now = new Date();
                wrkMast.setWrkSts(3L);
                wrkMast.setCrnStrTime(now);
                wrkMast.setModiTime(now);
                if (wrkMastMapper.updateById(wrkMast) == 0) {
                    log.error("修改工作档状态 2.设备上走 => 3.吊车入库中 失败!!,工作号={}", wrkMast.getWrkNo());
                }
                // 修改工作档状态 2.设备上走 => 3.吊车入库中
                wrkMastOther.setWrkSts(3L);
                wrkMastOther.setCrnStrTime(now);
                wrkMastOther.setModiTime(now);
                if (wrkMastMapper.updateById(wrkMastOther) == 0) {
                    log.error("修改工作档状态 2.设备上走 => 3.吊车入库中 失败!!,工作号={}", wrkMastOther.getWrkNo());
                }
                wrkMastCrn.setWrkSts(3L);
                wrkMastCrn.setModiTime(now);
                if (wrkMastCrnMapper.updateById(wrkMastCrn) == 0) {
                    log.error("修改堆垛机工作档状态 2.设备上走 => 3.吊车入库中 失败!!,工作号={}", wrkMastCrn.getWrkNo());
                }
            }
        }
    }
    /**
     * 入库  ===>>  堆垛机站到库位
     * 2024-01-15 优化双工位
     */
    public synchronized void crnStnToLoc1(CrnSlave slave, CrnProtocol crnProtocol, Integer crnStation) {
        List<WrkMast> wrkMasts = wrkMastMapper.selectPakInStep12(slave.getId());
        for(WrkMast wrkMast : wrkMasts){
            if (wrkMast == null) {
                continue;
            }
            CrnSlave.CrnStn crnStn = null;
            for (CrnSlave.CrnStn crnStn1 : slave.getCrnInStn()){
                if(crnStn1.getStaNo().equals(wrkMast.getStaNo())){
                    crnStn = crnStn1;
                    break;
                }
            }
            if(Cools.isEmpty(crnStn)){
                continue;
            }
            boolean flag = false;
            // 获取堆垛机入库站信息
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                continue;
            } else {
                staProtocol = staProtocol.clone();
            }
            // 查询站点详细信息
            BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
            if (staDetl == null) {
                log.error("入库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
                continue;
            }
            if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.getWorkNo().equals(wrkMast.getWrkNo())
                    && staProtocol.isInEnable() && staDetl.getCanining() != null && staDetl.getCanining().equals("Y")) {
                flag = true;
            }
            if (!flag) {
                continue;
            }
            // 获取库位信息
            LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
            if (locMast == null) {
                log.error("查询库存无数据--库位号{}", wrkMast.getLocNo());
                continue;
            }
            if (!locMast.getLocSts().equals("S") && !locMast.getLocSts().equals("Q")) {
                log.error("入库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMast.getLocNo(), locMast.getLocSts());
                continue;
            }
            //工位
            if (crnStation == 1){
                // 堆垛机控制过滤
                if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) {
                    break;
                }
            }else if(crnStation == 2){
                // 堆垛机控制过滤
                if (!crnProtocol.getStatusTypeTwo().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNoTwo() != 0) {
                    break;
                }
            }else {
                break;
            }
            // 已经存在吊车执行任务时,则过滤
            if (wrkMastMapper.selectWorking(slave.getId()) != null) {
                continue;
            }
            // 双深库位且浅库位有货,则需先对浅库位进行库位移转
            if (Utils.isDeepLoc(slaveProperties, wrkMast.getLocNo())) {
                String shallowLocNo = Utils.getShallowLoc(slaveProperties, wrkMast.getLocNo());
                LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                // O.空库位、Q.拣料/盘点/并板再入库、S.入库预约、X.禁用 直接搬!
                if (shallowLoc.getLocSts().equals("P") || shallowLoc.getLocSts().equals("R")) {
                    WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                    if (null == waitWrkMast) {
                        log.error("{}库位异常,未检索到相应工作档!", shallowLocNo);
                    } else {
                        waitWrkMast.setIoPri(15D);
                        waitWrkMast.setModiTime(new Date());
                        if (wrkMastMapper.updateById(waitWrkMast) == 0) {
                            log.error("调整工作档优先级失败!工作号={}", waitWrkMast.getWrkNo());
                        }
                        continue;
                    }
                } else if (shallowLoc.getLocSts().equals("F") || shallowLoc.getLocSts().equals("D")) {
                    // 此标记避免多次执行移库任务
                    if (Cools.isEmpty(wrkMast.getUpdMk()) || "N".equals(wrkMast.getUpdMk())) {
                        wrkMast.setUpdMk("Y");
                        wrkMast.setIoPri(14D);
                        wrkMastMapper.updateById(wrkMast);
                        // 生成工作档,将浅库位移转到新的库位中
                        moveLocForDeepLoc(slave, shallowLoc);
                        // 生成工作档、改变浅库位的源库/目标库 库位状态、下发堆垛机命令(立马执行)
//                        moveLocForDeepLocPakin(slave, shallowLoc, wrkMast);
                    }
                    continue;
                } else if (shallowLoc.getLocSts().equals("Q")) {
                    WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                    if (null != waitWrkMast && waitWrkMast.getWrkSts() == 4) {
                        continue;
                    }
                }
            }
            // 命令下发区 --------------------------------------------------------------------------
            CrnCommand crnCommand = new CrnCommand();
            crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
            crnCommand.setTaskNo(wrkMast.getWrkNo().shortValue()); // 工作号
            crnCommand.setAckFinish((short) 0);  // 任务完成确认位
            crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE); // 任务模式:  库位移转
            crnCommand.setSourcePosX(crnStn.getRow().shortValue());     // 源库位排
            crnCommand.setSourcePosY(crnStn.getBay().shortValue());     // 源库位列
            crnCommand.setSourcePosZ(crnStn.getLev().shortValue());     // 源库位层
            crnCommand.setDestinationPosX(locMast.getRow1().shortValue());     // 目标库位排
            crnCommand.setDestinationPosY(locMast.getBay1().shortValue());     // 目标库位列
            crnCommand.setDestinationPosZ(locMast.getLev1().shortValue());     // 目标库位层
            if (!MessageQueue.offer(SlaveType.Crn, wrkMast.getCrnNo(), new Task(crnStation==1? 2:5, crnCommand))) {
                log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMast.getCrnNo(), JSON.toJSON(crnCommand));
            } else {
                // 修改工作档状态 2.设备上走 => 3.吊车入库中
                Date now = new Date();
                wrkMast.setWrkSts(3L);
                wrkMast.setCrnStrTime(now);
                wrkMast.setModiTime(now);
                if (wrkMastMapper.updateById(wrkMast) == 0) {
                    log.error("修改工作档状态 2.设备上走 => 3.吊车入库中 失败!!,工作号={}", wrkMast.getWrkNo());
                }
            }
        }
    }
    /**
     * 出库  ===>>  库位到堆垛机站
     * 2022-06-09 TQS修改,查询工作档LIST,遍历下发,防止第一个任务堵塞出库
     */
    public void locToCrnStn(CrnSlave slave, CrnProtocol crnProtocol) {
    public synchronized void locToCrnStn(CrnSlave slave, CrnProtocol crnProtocol) {
        for (CrnSlave.CrnStn crnStn : slave.getCrnOutStn()) {
            // 获取工作状态为11(生成出库ID)的出库工作档
//            WrkMast wrkMast = wrkMastMapper.selectPakOutStep1(slave.getId(), crnStn.getStaNo());
@@ -771,7 +2182,7 @@
                // 获取源库位信息
                LocMast sourceSta = locMastService.selectById(wrkMast.getSourceLocNo());
                if (!sourceSta.getLocSts().equals("R") && !sourceSta.getLocSts().equals("P")) {
                    log.error("出库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMast.getLocNo(), sourceSta.getLocSts());
                    log.error("出库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMast.getSourceLocNo(), sourceSta.getLocSts());
                    continue;
                }
                // 获取堆垛机出库站信息
@@ -845,7 +2256,7 @@
                            log.error("{}任务出库失败,浅库位堵塞!浅库位号:{}", wrkMast.getWrkNo(), shallowLocNo);
                            continue;
                        } else if (shallowLoc.getLocSts().equals("Q") || shallowLoc.getLocSts().equals("S")) {
                            WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                            WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                            if (null != waitWrkMast && waitWrkMast.getWrkSts() == 4) {
                                continue;
                            }
@@ -888,127 +2299,558 @@
        }
    }
//    /**
//     * 出库  ===>>  库位到堆垛机站
//     */
//    public void locToCrnStn(CrnSlave slave, CrnProtocol crnProtocol){
//        for (CrnSlave.CrnStn crnStn : slave.getCrnOutStn()) {
//            // 获取工作状态为11(生成出库ID)的出库工作档
//            WrkMast wrkMast = wrkMastMapper.selectPakOutStep1(slave.getId(), crnStn.getStaNo());
//            if (wrkMast == null) {
//                continue;
//            }
//            // 工作档状态判断
//            if (wrkMast.getIoType() < 100 || wrkMast.getSourceStaNo() == null){
//                log.error("查询工作档数据不符合条件--入出类型/站点, 工作号={},源库位={},入出类型={}", wrkMast.getWrkNo(), wrkMast.getSourceLocNo(), wrkMast.getIoType());
//                continue;
//            }
//            // 获取源库位信息
//            LocMast sourceSta = locMastService.selectById(wrkMast.getSourceLocNo());
//            if (!sourceSta.getLocSts().equals("R") &&!sourceSta.getLocSts().equals("P")) {
//                log.error("出库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMast.getLocNo(), sourceSta.getLocSts());
//                continue;
//            }
//            // 获取堆垛机出库站信息
//            SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
//            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
//            if (staProtocol == null) {
//                continue;
//            } else {
//                staProtocol = staProtocol.clone();
//            }
//
////            // 入出库模式判断
////            if (devpThread.ioMode != IoModeType.PAKOUT_MODE) { continue; }
//
//
//            // 查询站点详细信息
//            BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
//            if (staDetl == null) {
//                log.error("出库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
//                continue;
//            }
//            // 判断堆垛机出库站状态
//            if (staProtocol.isAutoing() && !staProtocol.isLoading() && staDetl.getCanouting() !=null && staDetl.getCanouting().equals("Y")
//                    && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) {
//                // 命令下发区 --------------------------------------------------------------------------
//
//                // 堆垛机控制过滤
//                if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) {
    /**
     * 出库  ===>>  库位到堆垛机站
     * 2024-01-15 优化双工位
     */
    public synchronized void locToCrnStn1(CrnSlave slave, CrnProtocol crnProtocol, Integer crnStation) {
        List<WrkMast> wrkMasts = wrkMastMapper.selectPakOutStep12(slave.getId());
        for (WrkMast wrkMast : wrkMasts) {
            if (wrkMast == null) {
                continue;
            }
            CrnSlave.CrnStn crnStn = null;
            for (CrnSlave.CrnStn crnStn1 : slave.getCrnOutStn()){
                if(crnStn1.getStaNo().equals(wrkMast.getSourceStaNo())){
                    crnStn = crnStn1;
                    break;
                }
            }
            if(Cools.isEmpty(crnStn)){
                continue;
            }
            // 工作档状态判断
            if (wrkMast.getIoType() < 100 || wrkMast.getSourceStaNo() == null) {
                log.error("查询工作档数据不符合条件--入出类型/站点, 工作号={},源库位={},入出类型={}", wrkMast.getWrkNo(), wrkMast.getSourceLocNo(), wrkMast.getIoType());
                continue;
            }
            //退库模式跳过118、119出库任务
            if (wrkMast.getStaNo()==118 || wrkMast.getStaNo()==119){
                RgvOneSign rgvOneSign = rgvOneSignMapper.selectOneSign();
                if (Cools.isEmpty(rgvOneSign) || rgvOneSign.getRgvOneSign()==1){
                    continue;
                }
            }
            // 获取源库位信息
            LocMast sourceSta = locMastService.selectById(wrkMast.getSourceLocNo());
            if (!sourceSta.getLocSts().equals("R") && !sourceSta.getLocSts().equals("P")) {
                log.error("出库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMast.getSourceLocNo(), sourceSta.getLocSts());
                continue;
            }
            // 获取堆垛机出库站信息
            SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                break;
//                    continue;
//                }
//
//                // 双深库位且浅库位有货,则需先对浅库位进行库位移转
//                if (Utils.isDeepLoc(slaveProperties, wrkMast.getSourceLocNo())) {
//                    String shallowLocNo = Utils.getShallowLoc(slaveProperties, wrkMast.getSourceLocNo());
//                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
//                    // O.空库位、Q.拣料/盘点/并板再入库、S.入库预约、X.禁用 直接搬!
//                    if (shallowLoc.getLocSts().equals("P") || shallowLoc.getLocSts().equals("R")) {
//                        WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
//                        if (null == waitWrkMast) {
//                            log.error("{}库位异常,未检索到相应工作档!", shallowLocNo);
//                        } else {
//                            if(waitWrkMast.getWrkSts() == 11) {
//                                waitWrkMast.setIoPri(15D);
//                                waitWrkMast.setModiTime(new Date());
//                                if (wrkMastMapper.updateById(waitWrkMast) == 0) {
//                                    log.error("调整工作档优先级失败!工作号={}", waitWrkMast.getWrkNo());
//                                }
//                                continue;
//                            } else {
//
//                            }
//                        }
//                    } else if (shallowLoc.getLocSts().equals("F") || shallowLoc.getLocSts().equals("D")) {
//                        // 此标记避免多次执行移库任务
//                        if (Cools.isEmpty(wrkMast.getUpdMk()) || "N".equals(wrkMast.getUpdMk())) {
//                            wrkMast.setUpdMk("Y");
//                            wrkMastMapper.updateById(wrkMast);
//                            // 生成工作档、改变浅库位的源库/目标库 库位状态、下发堆垛机命令(立马执行)
//                            moveLocForDeepLoc(slave, shallowLoc);
//                        }
//                        log.error("{}任务出库失败,浅库位堵塞!", wrkMast.getWrkNo());
            } else {
                staProtocol = staProtocol.clone();
            }
//            // 入出库模式判断
//            if (devpThread.ioMode != IoModeType.PAKOUT_MODE) { continue; }
            if (wrkMast.getStaNo() == 204 && devpThread.ioModeOf2F != IoModeType.PAKOUT_MODE) {
                continue;
            }
            // 查询站点详细信息
            BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
            if (staDetl == null) {
                log.error("出库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
                break;
//                    continue;
            }
            // 判断堆垛机出库站状态
            if (staProtocol.isAutoing() && !staProtocol.isLoading() && staDetl.getCanouting() != null && staDetl.getCanouting().equals("Y")
                    && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) {
                // 命令下发区 --------------------------------------------------------------------------
                //工位
                if (crnStation == 1){
                    // 堆垛机控制过滤
                    if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) {
//                        continue;
//                    }
//                }
//
//                // 已经存在吊车执行任务时,则过滤
//                if (wrkMastMapper.selectWorking(slave.getId()) != null) {
//                    return;
//                }
//
//                // 1.堆垛机开始移动
//                CrnCommand crnCommand = new CrnCommand();
//                crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
//                crnCommand.setTaskNo(wrkMast.getWrkNo().shortValue()); // 工作号
//                crnCommand.setAckFinish((short) 0);  // 任务完成确认位
//                crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE); // 任务模式:  库位移转
//                crnCommand.setSourcePosX(sourceSta.getRow1().shortValue());     // 源库位排
//                crnCommand.setSourcePosY(sourceSta.getBay1().shortValue());     // 源库位列
//                crnCommand.setSourcePosZ(sourceSta.getLev1().shortValue());     // 源库位层
//                crnCommand.setDestinationPosX(crnStn.getRow().shortValue());     // 目标库位排
//                crnCommand.setDestinationPosY(crnStn.getBay().shortValue());     // 目标库位列
//                crnCommand.setDestinationPosZ(crnStn.getLev().shortValue());     // 目标库位层
//                if (!MessageQueue.offer(SlaveType.Crn, wrkMast.getCrnNo(), new Task(2, crnCommand))) {
//                    log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMast.getCrnNo(), JSON.toJSON(crnCommand));
//                } else {
//                    // 修改工作档状态 11.生成出库ID => 12.吊车出库中
//                    Date now = new Date();
//                    wrkMast.setWrkSts(12L);
//                    wrkMast.setCrnStrTime(now);
//                    wrkMast.setModiTime(now);
//                    if (wrkMastMapper.updateById(wrkMast) == 0) {
//                        log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMast.getWrkNo());
//                    }
//                }
                        break;
                    }
                }else if(crnStation == 2){
                    // 堆垛机控制过滤
                    if (!crnProtocol.getStatusTypeTwo().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNoTwo() != 0) {
//                        continue;
                        break;
                    }
                }else {
                    break;
                }
                // 双深库位且浅库位有货,则需先对浅库位进行库位移转
                if (Utils.isDeepLoc(slaveProperties, wrkMast.getSourceLocNo())) {
                    String shallowLocNo = Utils.getShallowLoc(slaveProperties, wrkMast.getSourceLocNo());
                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                    // O.空库位、Q.拣料/盘点/并板再入库、S.入库预约、X.禁用 直接搬!
                    if (shallowLoc.getLocSts().equals("P") || shallowLoc.getLocSts().equals("R")) {
                        WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                        if (null == waitWrkMast) {
                            log.error("{}库位异常,未检索到相应工作档!", shallowLocNo);
                        } else {
                            if (waitWrkMast.getWrkSts() == 11) {
                                waitWrkMast.setIoPri(15D);
                                waitWrkMast.setModiTime(new Date());
                                if (wrkMastMapper.updateById(waitWrkMast) == 0) {
                                    log.error("调整工作档优先级失败!工作号={}", waitWrkMast.getWrkNo());
                                }
                                continue;
                            } else {
                            }
                        }
                    } else if (shallowLoc.getLocSts().equals("F") || shallowLoc.getLocSts().equals("D")) {
//                            WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                        //2022-08-16 modify,不根据updmk标记移库任务(容易被取消导致堵塞),查询工作档是否存在任务
                        WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                        // 此标记避免多次执行移库任务
//                            if (Cools.isEmpty(wrkMast.getUpdMk()) || "N".equals(wrkMast.getUpdMk())
//                                || Cools.isEmpty(waitWrkMast)) {
                        if (Cools.isEmpty(waitWrkMast)) {
                            wrkMast.setUpdMk("Y");
                            wrkMastMapper.updateById(wrkMast);
                            // 生成工作档,将浅库位移转到新的库位中
                            moveLocForDeepLoc(slave, shallowLoc);
                        }
                        log.error("{}任务出库失败,浅库位堵塞!浅库位号:{}", wrkMast.getWrkNo(), shallowLocNo);
                        continue;
                    } else if (shallowLoc.getLocSts().equals("Q") || shallowLoc.getLocSts().equals("S")) {
                        WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                        if (null != waitWrkMast && waitWrkMast.getWrkSts() == 4) {
                            continue;
                        }
                    }
                }
                // 已经存在吊车执行任务时,则过滤
                if (wrkMastMapper.selectWorking(slave.getId()) != null) {
                    break;
//                        return;
                }
                // 1.堆垛机开始移动
                CrnCommand crnCommand = new CrnCommand();
                crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
                crnCommand.setTaskNo(wrkMast.getWrkNo().shortValue()); // 工作号
                crnCommand.setAckFinish((short) 0);  // 任务完成确认位
                crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE); // 任务模式:  库位移转
                crnCommand.setSourcePosX(sourceSta.getRow1().shortValue());     // 源库位排
                crnCommand.setSourcePosY(sourceSta.getBay1().shortValue());     // 源库位列
                crnCommand.setSourcePosZ(sourceSta.getLev1().shortValue());     // 源库位层
                crnCommand.setDestinationPosX(crnStn.getRow().shortValue());     // 目标库位排
                crnCommand.setDestinationPosY(crnStn.getBay().shortValue());     // 目标库位列
                crnCommand.setDestinationPosZ(crnStn.getLev().shortValue());     // 目标库位层
                if (!MessageQueue.offer(SlaveType.Crn, wrkMast.getCrnNo(), new Task(crnStation==1? 2:5, crnCommand))) {
                    log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMast.getCrnNo(), JSON.toJSON(crnCommand));
                } else {
                    // 修改工作档状态 11.生成出库ID => 12.吊车出库中
                    Date now = new Date();
                    wrkMast.setWrkSts(12L);
                    wrkMast.setCrnStrTime(now);
                    wrkMast.setModiTime(now);
                    if (wrkMastMapper.updateById(wrkMast) == 0) {
                        log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMast.getWrkNo());
                    }
                    break;
                }
            }
        }
    }
    /**
     * 出库  ===>>  库位到堆垛机站
     * 2024-01-15 煜星小料箱
     */
    public synchronized void locToCrnStn1Single(CrnSlave slave, CrnProtocol crnProtocol) {
        List<WrkMastCrn> wrkMastCrnList = wrkMastCrnMapper.selectList(new EntityWrapper<WrkMastCrn>()
                .eq("crn_no", crnProtocol.getCrnNo()).eq("wrk_sts", 11L));
        for (WrkMastCrn wrkMastCrn : wrkMastCrnList) {
            if (wrkMastCrn == null) {
                continue;
            }
            CrnSlave.CrnStn crnStn = null;
            for (CrnSlave.CrnStn crnStn1 : slave.getCrnOutStn()){
                if(crnStn1.getStaNo().equals(wrkMastCrn.getSourceStaNo())){
                    crnStn = crnStn1;
                    break;
                }
            }
            if(Cools.isEmpty(crnStn)){
                continue;
            }
            // 工作档状态判断
            if (wrkMastCrn.getIoType() < 100 || wrkMastCrn.getSourceStaNo() == null) {
                log.error("查询工作档数据不符合条件--入出类型/站点, 工作号={},源库位={},入出类型={}", wrkMastCrn.getWrkNo(), wrkMastCrn.getSourceLocNo(), wrkMastCrn.getIoType());
                continue;
            }
            // 获取源库位信息
            LocMast sourceSta = locMastService.selectById(wrkMastCrn.getSourceLocNo());
            if (!sourceSta.getLocSts().equals("R") && !sourceSta.getLocSts().equals("P")) {
                log.error("出库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMastCrn.getSourceLocNo(), sourceSta.getLocSts());
                continue;
            }
            // 获取堆垛机出库站信息
            SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                break;
//                    continue;
            } else {
                staProtocol = staProtocol.clone();
            }
            StaProtocol staProtocolOther = devpThread.getStation().get(crnStn.getStaNoOther());
            if (staProtocolOther == null) {
                continue;
            } else {
                staProtocolOther = staProtocolOther.clone();
            }
//            // 入出库模式判断
//            if (devpThread.ioMode != IoModeType.PAKOUT_MODE) { continue; }
//            if (wrkMast.getStaNo() == 204 && devpThread.ioModeOf2F != IoModeType.PAKOUT_MODE) {
//                continue;
//            }
//        }
//    }
            // 查询站点详细信息
            BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
            if (staDetl == null) {
                log.error("出库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
                break;
//                    continue;
            }
            // 查询站点详细信息
            BasDevp staDetlOther = basDevpService.selectById(crnStn.getStaNoOther());
            if (staDetlOther == null) {
                log.error("出库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNoOther());
                break;
//                    continue;
            }
            // 判断堆垛机出库站状态
            if (staProtocol.isAutoing() && !staProtocol.isLoading() && staDetl.getCanouting() != null && staDetl.getCanouting().equals("Y")
                    && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) {
                if (staProtocolOther.isAutoing() && !staProtocolOther.isLoading() && staDetlOther.getCanouting() != null && staDetlOther.getCanouting().equals("Y")
                        && staProtocolOther.getWorkNo() == 0 && staProtocolOther.isOutEnable()){
                    // 命令下发区 --------------------------------------------------------------------------
                    // 堆垛机控制过滤
                    if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) {
//                        continue;
                        break;
                    }
                    // 已经存在吊车执行任务时,则过滤
                    if (wrkMastMapper.selectWorking(slave.getId()) != null) {
                        break;
//                        return;
                    }
                    // 1.堆垛机开始移动
                    CrnCommand crnCommand = new CrnCommand();
                    crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
                    crnCommand.setTaskNo(wrkMastCrn.getWrkNo().shortValue()); // 工作号
                    crnCommand.setAckFinish((short) 0);  // 任务完成确认位
                    crnCommand.setTaskMode(CrnTaskModeType.LOC_MOVE); // 任务模式:  库位移转
                    crnCommand.setSourcePosX(sourceSta.getRow1().shortValue());     // 源库位排
                    crnCommand.setSourcePosY(sourceSta.getBay1().shortValue());     // 源库位列
                    crnCommand.setSourcePosZ(sourceSta.getLev1().shortValue());     // 源库位层
                    crnCommand.setDestinationPosX(crnStn.getRow().shortValue());     // 目标库位排
                    crnCommand.setDestinationPosY(crnStn.getBay().shortValue());     // 目标库位列
                    crnCommand.setDestinationPosZ(crnStn.getLev().shortValue());     // 目标库位层
                    if (!MessageQueue.offer(SlaveType.Crn, wrkMastCrn.getCrnNo(), new Task(2, crnCommand))) {
                        log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMastCrn.getCrnNo(), JSON.toJSON(crnCommand));
                    } else {
                        // 修改工作档状态 11.生成出库ID => 12.吊车出库中
                        Date now = new Date();
                        wrkMastCrn.setWrkSts(12L);
                        wrkMastCrn.setModiTime(now);
                        if (wrkMastCrnMapper.updateById(wrkMastCrn) == 0) {
                            log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMastCrn.getWrkNo());
                        }
                        WrkMast wrkMastOne = wrkMastMapper.selectPakInStep3(wrkMastCrn.getWrkNoOne().intValue());
                        wrkMastOne.setWrkSts(12L);
                        wrkMastOne.setCrnStrTime(now);
                        wrkMastOne.setModiTime(now);
                        if (wrkMastMapper.updateById(wrkMastOne) == 0) {
                            log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMastOne.getWrkNo());
                        }
                        WrkMast wrkMastTwo = wrkMastMapper.selectPakInStep3(wrkMastCrn.getWrkNoTwo().intValue());
                        wrkMastTwo.setWrkSts(12L);
                        wrkMastTwo.setCrnStrTime(now);
                        wrkMastTwo.setModiTime(now);
                        if (wrkMastMapper.updateById(wrkMastTwo) == 0) {
                            log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMastTwo.getWrkNo());
                        }
                        break;
                    }
                }
            }
        }
    }
    /**
     * 出库  ===>>  库位到堆垛机站
     * 2024-06-05  煜星大料箱
     */
    public synchronized void locToCrnStn1Big(CrnSlave slave, CrnProtocol crnProtocol, Integer crnStation) {
        List<WrkMast> wrkMasts = wrkMastMapper.selectPakOutStep12(slave.getId());
        Integer crnStation1 = crnStation;
        for (WrkMast wrkMast : wrkMasts) {
            if (wrkMast == null) {
                continue;
            }
            crnStation = crnStation1;
            CrnSlave.CrnStn crnStn = null;
            for (CrnSlave.CrnStn crnStn1 : slave.getCrnOutStn()){
                if(crnStn1.getStaNo().equals(wrkMast.getSourceStaNo())){
                    crnStn = crnStn1;
                    break;
                }
            }
            if(Cools.isEmpty(crnStn)){
                continue;
            }
            // 工作档状态判断
            if (wrkMast.getIoType() < 100 || wrkMast.getSourceStaNo() == null) {
                log.error("查询工作档数据不符合条件--入出类型/站点, 工作号={},源库位={},入出类型={}", wrkMast.getWrkNo(), wrkMast.getSourceLocNo(), wrkMast.getIoType());
                continue;
            }
            //退库模式跳过118、119出库任务
            if (wrkMast.getStaNo()==118 || wrkMast.getStaNo()==119){
                RgvOneSign rgvOneSign = rgvOneSignMapper.selectOneSign();
                if (Cools.isEmpty(rgvOneSign) || rgvOneSign.getRgvOneSign()==1){
                    continue;
                }
            }
            // 获取源库位信息
            LocMast sourceSta = locMastService.selectById(wrkMast.getSourceLocNo());
            if (!sourceSta.getLocSts().equals("R") && !sourceSta.getLocSts().equals("P")) {
                log.error("出库操作库位状态不符合--状态, 库位号={},库位状态={}", wrkMast.getSourceLocNo(), sourceSta.getLocSts());
                continue;
            }
            // 获取堆垛机出库站信息
            SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
            StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
            if (staProtocol == null) {
                break;
//                    continue;
            } else {
                staProtocol = staProtocol.clone();
            }
//            // 入出库模式判断
//            if (devpThread.ioMode != IoModeType.PAKOUT_MODE) { continue; }
            if (wrkMast.getStaNo() == 204 && devpThread.ioModeOf2F != IoModeType.PAKOUT_MODE) {
                continue;
            }
            // 查询站点详细信息
            BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
            if (staDetl == null) {
                log.error("出库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
                break;
//                    continue;
            }
            // 判断堆垛机出库站状态
            if (staProtocol.isAutoing() && !staProtocol.isLoading() && staDetl.getCanouting() != null && staDetl.getCanouting().equals("Y")
                    && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) {
                // 命令下发区 --------------------------------------------------------------------------
                //工位
                if (crnStation == 1){
                    // 堆垛机控制过滤
                    if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) {
//                        continue;
                        break;
                    }
                    // 堆垛机控制过滤
                    if (!crnProtocol.getStatusTypeTwo().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNoTwo() != 0) {
//                        continue;
                        break;
                    }
                }else if(crnStation == 2){
                    // 堆垛机控制过滤
                    if (!crnProtocol.getStatusTypeTwo().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNoTwo() != 0) {
//                        continue;
                        break;
                    }
                }else {
                    break;
                }
                if (sourceSta.getBay1().shortValue()==81){
                    crnStation = 2;
                }
                // 双深库位且浅库位有货,则需先对浅库位进行库位移转
                if (Utils.isDeepLoc(slaveProperties, wrkMast.getSourceLocNo())) {
                    String shallowLocNo = Utils.getShallowLoc(slaveProperties, wrkMast.getSourceLocNo());
                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                    // O.空库位、Q.拣料/盘点/并板再入库、S.入库预约、X.禁用 直接搬!
                    if (shallowLoc.getLocSts().equals("P") || shallowLoc.getLocSts().equals("R")) {
                        WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                        if (null == waitWrkMast) {
                            log.error("{}库位异常,未检索到相应工作档!", shallowLocNo);
                        } else {
                            if (waitWrkMast.getWrkSts() == 11) {
                                waitWrkMast.setIoPri(15D);
                                waitWrkMast.setModiTime(new Date());
                                if (wrkMastMapper.updateById(waitWrkMast) == 0) {
                                    log.error("调整工作档优先级失败!工作号={}", waitWrkMast.getWrkNo());
                                }
                                continue;
                            } else {
                            }
                        }
                    } else if (shallowLoc.getLocSts().equals("F") || shallowLoc.getLocSts().equals("D")) {
//                            WrkMast waitWrkMast = wrkMastMapper.selectByLocNo(shallowLocNo);
                        //2022-08-16 modify,不根据updmk标记移库任务(容易被取消导致堵塞),查询工作档是否存在任务
                        WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                        // 此标记避免多次执行移库任务
//                            if (Cools.isEmpty(wrkMast.getUpdMk()) || "N".equals(wrkMast.getUpdMk())
//                                || Cools.isEmpty(waitWrkMast)) {
                        if (Cools.isEmpty(waitWrkMast)) {
                            wrkMast.setUpdMk("Y");
                            wrkMastMapper.updateById(wrkMast);
                            // 生成工作档,将浅库位移转到新的库位中
                            moveLocForDeepLoc(slave, shallowLoc);
                        }
                        log.error("{}任务出库失败,浅库位堵塞!浅库位号:{}", wrkMast.getWrkNo(), shallowLocNo);
                        continue;
                    } else if (shallowLoc.getLocSts().equals("Q") || shallowLoc.getLocSts().equals("S")) {
                        WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo);
                        if (null != waitWrkMast && waitWrkMast.getWrkSts() == 4) {
                            continue;
                        }
                    }
                }
                // 已经存在吊车执行任务时,则过滤
                if (wrkMastMapper.selectWorking(slave.getId()) != null) {
                    break;
//                        return;
                }
                // 已经存在吊车执行任务时,则过滤
                if (wrkMastSplitTwinMapper.selectCount(new EntityWrapper<WrkMastSplitTwin>().eq("wrk_no", wrkMast.getWrkNo().longValue())) != 0) {
                    break;
//                        return;
                }
                if (true){
                    // 1.堆垛机开始移动
                    CrnCommand crnCommand = new CrnCommand();
                    crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
                    crnCommand.setTaskNo(wrkMast.getWrkNo().shortValue()); // 工作号
                    crnCommand.setAckFinish((short) 0);  // 任务完成确认位
                    crnCommand.setTaskMode(CrnTaskModeType.SEPARATE_TAKE); // 任务模式:  单取货
                    crnCommand.setSourcePosX(sourceSta.getRow1().shortValue());     // 源库位排
                    crnCommand.setSourcePosY(sourceSta.getBay1().shortValue());     // 源库位列
                    crnCommand.setSourcePosZ(sourceSta.getLev1().shortValue());     // 源库位层
                    crnCommand.setDestinationPosX((short)0);     // 目标库位排
                    crnCommand.setDestinationPosY((short)0);     // 目标库位列
                    crnCommand.setDestinationPosZ((short)0);     // 目标库位层
                    if (!MessageQueue.offer(SlaveType.Crn, wrkMast.getCrnNo(), new Task(crnStation==1? 2:5, crnCommand))) {
                        log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMast.getCrnNo(), JSON.toJSON(crnCommand));
                    } else {
                        // 修改工作档状态 11.生成出库ID => 12.吊车出库中
                        Date now = new Date();
                        wrkMast.setWrkSts(12L);
                        wrkMast.setCrnStrTime(now);
                        wrkMast.setModiTime(now);
                        WrkMastSplitTwin wrkMastSplitTwin = new WrkMastSplitTwin(wrkMast,crnStation,now);
                        wrkMastSplitTwin.setWrkSts(1);
                        wrkMastSplitTwin.setWrkStart(wrkMast.getSourceLocNo());
                        wrkMastSplitTwin.setWrkEnd(wrkMast.getSourceStaNo().toString());
                        wrkMastSplitTwin.setStartRow(sourceSta.getRow1());
                        wrkMastSplitTwin.setStartBay(sourceSta.getBay1());
                        wrkMastSplitTwin.setStartLev(sourceSta.getLev1());
                        wrkMastSplitTwin.setEndRow(crnStn.getRow());
                        wrkMastSplitTwin.setEndBay(crnStn.getBay());
                        wrkMastSplitTwin.setEndLev(crnStn.getLev());
                        wrkMastSplitTwin.setWrkType(1);
                        wrkMastSplitTwin.setIoType(2);
                        if (wrkMastMapper.updateById(wrkMast) == 0) {
                            log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMast.getWrkNo());
                        }
                        if (wrkMastSplitTwinMapper.insert(wrkMastSplitTwin)==0){
                            log.error("创建 堆垛机执行任务 失败!!,工作号={},堆垛机号={}", wrkMast.getWrkNo(),wrkMast.getCrnNo());
                        }
                        break;
                    }
                }
//                else {
//                    // 1.堆垛机开始移动
//                    CrnCommandParam crnCommandParam = new CrnCommandParam();
//                    CrnCommand crnCommand = new CrnCommand();
//                    crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
//                    crnCommand.setTaskNo(wrkMast.getWrkNo().shortValue()); // 工作号
//                    crnCommand.setAckFinish((short) 0);  // 任务完成确认位
//                    crnCommand.setTaskMode(CrnTaskModeType.SEPARATE_TAKE); // 任务模式:  单取货
//                    crnCommand.setSourcePosX(sourceSta.getRow1().shortValue());     // 源库位排
//                    crnCommand.setSourcePosY(sourceSta.getBay1().shortValue());     // 源库位列
//                    crnCommand.setSourcePosZ(sourceSta.getLev1().shortValue());     // 源库位层
//                    crnCommand.setDestinationPosX((short)0);     // 目标库位排
//                    crnCommand.setDestinationPosY((short)0);     // 目标库位列
//                    crnCommand.setDestinationPosZ((short)0);     // 目标库位层
//                    if (!MessageQueue.offer(SlaveType.Crn, wrkMast.getCrnNo(), new Task(crnStation==1? 2:5, crnCommand))) {
//                        log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMast.getCrnNo(), JSON.toJSON(crnCommand));
//                    } else {
//                        // 修改工作档状态 11.生成出库ID => 12.吊车出库中
//                        Date now = new Date();
//                        wrkMast.setWrkSts(12L);
//                        wrkMast.setCrnStrTime(now);
//                        wrkMast.setModiTime(now);
//                        WrkMastSplitTwin wrkMastSplitTwin = new WrkMastSplitTwin(wrkMast,crnStation,now);
//                        wrkMastSplitTwin.setWrkSts(1);
//                        wrkMastSplitTwin.setWrkStart(wrkMast.getSourceLocNo());
//                        wrkMastSplitTwin.setWrkEnd(wrkMast.getSourceStaNo().toString());
//                        wrkMastSplitTwin.setStartRow(sourceSta.getRow1());
//                        wrkMastSplitTwin.setStartBay(sourceSta.getBay1());
//                        wrkMastSplitTwin.setStartLev(sourceSta.getLev1());
//                        wrkMastSplitTwin.setEndRow(crnStn.getRow());
//                        wrkMastSplitTwin.setEndBay(crnStn.getBay());
//                        wrkMastSplitTwin.setEndLev(crnStn.getLev());
//                        wrkMastSplitTwin.setWrkType(1);
//                        wrkMastSplitTwin.setIoType(2);
//                        if (wrkMastMapper.updateById(wrkMast) == 0) {
//                            log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMast.getWrkNo());
//                        }
//
//                        if (wrkMastSplitTwinMapper.insert(wrkMastSplitTwin)==0){
//                            log.error("创建 堆垛机执行任务 失败!!,工作号={},堆垛机号={}", wrkMast.getWrkNo(),wrkMast.getCrnNo());
//                        }
//                        break;
//                    }
//                }
            }
        }
    }
    /**
     * 库位移转
     */
    public void locToLoc(CrnSlave slave, CrnProtocol crnProtocol) {
    public synchronized void locToLoc(CrnSlave slave, CrnProtocol crnProtocol) {
        // 获取工作档信息
        WrkMast wrkMast = wrkMastMapper.selectLocMove(slave.getId());
        if (null == wrkMast) {
@@ -1076,18 +2918,198 @@
    /**
     * 执行对工作档的完成操作
     */
    @Async
    public void storeFinished() {
    public synchronized void storeFinished() {
        for (CrnSlave crn : slaveProperties.getCrn()) {
            switch (crn.getId()){
                case 1:
                case 2:
                    storeFinishedExecuteOne(crn);
                    continue;
                case 3:
                case 4:
                case 5:
                    storeFinishedExecuteTwo(crn);
                    continue;
                case 6:
                case 7:
                    storeFinishedExecuteThree(crn);
                    continue;
                default:
                    continue;
            }
        }
    }
    public synchronized boolean storeFinishedExecuteOne(CrnSlave crn) {
        try{
            // 获取堆垛机信息
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
            if (crnProtocol == null) {
                continue;
                return false;
            }
            if (crnProtocol.modeType != CrnModeType.AUTO){
                return false;
            }
            //  状态:等待确认 并且  任务完成位 = 1
            if (crnProtocol.statusType == CrnStatusType.WAITING && crnProtocol.getTaskNo() != 0) {
                if (crnProtocol.getTaskNo() == 9999) {
                if (crnProtocol.getTaskNo() == 32222) {
                    // 堆垛机复位
                    crnThread.setResetFlag(true);
                } else {
                    // 获取入库待确认工作档
                    WrkMastCrn wrkMastCrn = wrkMastCrnMapper.selectWrkNoOneAndTwo(crnProtocol.getTaskNo().intValue());
                    if (wrkMastCrn == null) {
                        log.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", crn.getId(), crnProtocol.getTaskNo());
                        return false;
                    }
                    // 获取入库待确认工作档
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep3(crnProtocol.getTaskNo().intValue());
                    if (wrkMast == null) {
                        log.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", crn.getId(), crnProtocol.getTaskNo());
                        return false;
                    }
                    // 获取入库待确认工作档
                    WrkMast wrkMastOther = wrkMastMapper.selectPakInStep3(wrkMastCrn.getWrkNoTwo().intValue());
                    if (wrkMastOther == null) {
                        log.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", crn.getId(), crnProtocol.getTaskNo());
                        return false;
                    }
                    // 入库 + 库位转移  ==> 4.入库完成
                    if (wrkMastCrn.getWrkSts() == 3 || (wrkMastCrn.getWrkSts() == 12 && wrkMastCrn.getIoType() == 11)) {
                        wrkMastCrn.setWrkSts(4L);
                    } else {
                        return false;
                    }
                    Date now = new Date();
                    wrkMastCrn.setModiTime(now);
                    wrkMast.setCrnEndTime(now);
                    wrkMast.setWrkSts(4L);
                    wrkMast.setModiTime(now);
                    wrkMastOther.setCrnEndTime(now);
                    wrkMastOther.setWrkSts(4L);
                    wrkMastOther.setModiTime(now);
                    // 修改成功后复位堆垛机
                    if (wrkMastCrnMapper.updateById(wrkMastCrn) > 0 && wrkMastMapper.updateById(wrkMast) > 0 && wrkMastMapper.updateById(wrkMastOther) > 0 ) {
                        // 堆垛机复位
                        crnThread.setResetFlag(true);
                        return true;
                    }
                }
            }
        }catch (Exception e){
            log.error("堆垛机工位一完成等待确认异常,堆垛机号={},异常信息={},工位号={}",crn.getId(),e.getMessage(),1);
        }
        return false;
    }
    public synchronized boolean storeFinishedExecuteTwo(CrnSlave crn) {
        try{
            // 获取堆垛机信息
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
            if (crnProtocol == null) {
                return false;
            }
            if (crnProtocol.modeType != CrnModeType.AUTO){
                return false;
            }
            //  状态:等待确认 并且  任务完成位 = 1
            if (crnProtocol.statusType == CrnStatusType.WAITING && crnProtocol.getTaskNo() != 0) {
                if (crnProtocol.getTaskNo() == 32222) {
                    // 堆垛机复位
                    crnThread.setResetFlag(true);
                    return true;
                } else {
                    // 获取入库待确认工作档
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep3(crnProtocol.getTaskNo().intValue());
                    if (wrkMast == null) {
                        log.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", crn.getId(), crnProtocol.getTaskNo());
                        return false;
                    }
                    // 入库 + 库位转移  ==> 4.入库完成
                    if (wrkMast.getWrkSts() == 3 || (wrkMast.getWrkSts() == 12 && wrkMast.getIoType() == 11)) {
                        wrkMast.setWrkSts(4L);
                    } else {
                        return false;
                    }
                    Date now = new Date();
                    wrkMast.setCrnEndTime(now);
                    wrkMast.setModiTime(now);
                    // 堆垛机复位
                    List<WrkMastSplitTwin> wrkMastSplitTwinList = wrkMastSplitTwinMapper.getWrkMastSplitTwin(crn.getId(), 1, null, 2, 3);
                    if (wrkMastSplitTwinList.size()!=1){
                        log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"不存在或者存在多笔可执行作业,请删除无效作业!!!",1,2,3);
                    }
                    for (WrkMastSplitTwin wrkMastSplitTwin:wrkMastSplitTwinList){
                        if (wrkMastSplitTwin.getWrkNo()!=wrkMast.getWrkNo().longValue()){
                            log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={},工作任务号={},执行任务号={}",crn.getId(),"工作任务与执行任务不匹配",1,2,3,wrkMast.getWrkNo(),wrkMastSplitTwin.getWrkNo());
                            return false;
                        }
                        wrkMastSplitTwin.setWrkSts(wrkMastSplitTwin.getWrkSts()+1);
                        wrkMastSplitTwin.setUpdateTime(now);
                        // 修改成功后复位堆垛机
                        if (wrkMastMapper.updateById(wrkMast) > 0) {
                            // 修改成功后复位堆垛机
                            if (wrkMastSplitTwinService.updateById(wrkMastSplitTwin)) {
                                // 堆垛机复位
                                crnThread.setResetFlag(true);
                                return true;
                            }else {
                                log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"修改执行档案失败",1,2,3);
                            }
                        }else {
                            log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"修改工作档案失败!",1,2,3);
                        }
                    }
                    return false;
                }
            }else if (crnProtocol.statusType == CrnStatusType.SEPARATE_WAITING && crnProtocol.getTaskNo() != 0  && crnProtocol.getLoaded()==1){
                if (crnProtocol.getTaskNo() == 32222) {
                    // 堆垛机复位
                    crnThread.setResetFlag(true);
                    return true;
                } else {
                    List<WrkMastSplitTwin> wrkMastSplitTwinList = wrkMastSplitTwinMapper.getWrkMastSplitTwin(crn.getId(), 1, null, 1, 1);
                    if (wrkMastSplitTwinList.size()!=1){
                        log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"不存在或者存在多笔可执行作业,请删除无效作业!!!",1,1,1);
                    }
                    for (WrkMastSplitTwin wrkMastSplitTwin:wrkMastSplitTwinList){
                        Date now = new Date();
                        wrkMastSplitTwin.setWrkSts(wrkMastSplitTwin.getWrkSts()+1);
                        wrkMastSplitTwin.setUpdateTime(now);
                        // 修改成功后复位堆垛机
                        if (wrkMastSplitTwinService.updateById(wrkMastSplitTwin)) {
                            // 堆垛机复位
                            crnThread.setResetFlag(true);
                            return true;
                        }else {
                            log.error("堆垛机放货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"修改执行档案失败",1,2,3);
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("堆垛机工位一完成等待确认异常,堆垛机号={},异常信息={},工位号={}",crn.getId(),e.getMessage(),1);
        }
        return false;
    }
    public synchronized boolean storeFinishedExecuteThree(CrnSlave crn) {
        try{
            // 获取堆垛机信息
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
            if (crnProtocol == null) {
                return false;
            }
            if (crnProtocol.modeType != CrnModeType.AUTO){
                return false;
            }
            //  状态:等待确认 并且  任务完成位 = 1
            if (crnProtocol.statusType == CrnStatusType.WAITING && crnProtocol.getTaskNo() != 0) {
                if (crnProtocol.getTaskNo() == 32222) {
                    // 堆垛机复位
                    crnThread.setResetFlag(true);
                } else {
@@ -1095,13 +3117,13 @@
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep3(crnProtocol.getTaskNo().intValue());
                    if (wrkMast == null) {
                        log.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", crn.getId(), crnProtocol.getTaskNo());
                        continue;
                        return false;
                    }
                    // 入库 + 库位转移  ==> 4.入库完成
                    if (wrkMast.getWrkSts() == 3 || (wrkMast.getWrkSts() == 12 && wrkMast.getIoType() == 11)) {
                        wrkMast.setWrkSts(4L);
                    } else {
                        continue;
                        return false;
                    }
                    Date now = new Date();
                    wrkMast.setCrnEndTime(now);
@@ -1110,18 +3132,259 @@
                    if (wrkMastMapper.updateById(wrkMast) > 0) {
                        // 堆垛机复位
                        crnThread.setResetFlag(true);
                        return true;
                    }
                }
            }
        }catch (Exception e){
            log.error("堆垛机工位一完成等待确认异常,堆垛机号={},异常信息={},工位号={}",crn.getId(),e.getMessage(),1);
        }
        return false;
    }
    /**
     * 执行对工作档的完成操作
     */
    public synchronized void storeFinishedTwo() {
        for (CrnSlave crn : slaveProperties.getCrn()) {
            switch (crn.getId()){
                case 3:
                case 4:
                case 5:
                    storeFinishedTwoExecute(crn);
                    continue;
                default:
                    continue;
            }
        }
    }
    public synchronized boolean storeFinishedTwoExecute(CrnSlave crn) {
        try{
            // 获取堆垛机信息
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
            if (crnProtocol == null) {
                return false;
            }
            if (crnProtocol.modeType != CrnModeType.AUTO){
                return false;
            }
            //  状态:等待确认 并且  任务完成位 = 1
            if (crnProtocol.statusTypeTwo == CrnStatusType.WAITING && crnProtocol.getTaskNoTwo() != 0) {
                if (crnProtocol.getTaskNoTwo() == 32222) {
                    // 堆垛机复位
                    crnThread.setResetFlagTwo(true);
                } else {
                    // 获取入库待确认工作档
                    WrkMast wrkMast = wrkMastMapper.selectPakInStep3(crnProtocol.getTaskNoTwo().intValue());
                    if (wrkMast == null) {
                        log.error("堆垛机处于等待确认且任务完成状态,但未找到工作档。堆垛机号={},工作号={}", crn.getId(), crnProtocol.getTaskNoTwo());
                        return false;
                    }
                    // 入库 + 库位转移  ==> 4.入库完成
                    if (wrkMast.getWrkSts() == 3 || (wrkMast.getWrkSts() == 12 && wrkMast.getIoType() == 11)) {
                        wrkMast.setWrkSts(4L);
                    } else {
                        return false;
                    }
                    Date now = new Date();
                    wrkMast.setCrnEndTime(now);
                    wrkMast.setModiTime(now);
                    // 堆垛机复位
                    List<WrkMastSplitTwin> wrkMastSplitTwinList = wrkMastSplitTwinMapper.getWrkMastSplitTwin(crn.getId(), 2, null, 2, 3);
                    if (wrkMastSplitTwinList.size()!=1){
                        log.error("堆垛机取货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"不存在或者存在多笔可执行作业,请删除无效作业!!!",2,2,3);
                    }
                    for (WrkMastSplitTwin wrkMastSplitTwin:wrkMastSplitTwinList){
                        if (wrkMastSplitTwin.getWrkNo()!=wrkMast.getWrkNo().longValue()){
                            log.error("堆垛机取货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={},工作任务号={},执行任务号={}",crn.getId(),"工作任务与执行任务不匹配",1,2,3,wrkMast.getWrkNo(),wrkMastSplitTwin.getWrkNo());
                            return false;
                        }
                        wrkMastSplitTwin.setWrkSts(wrkMastSplitTwin.getWrkSts()+1);
                        wrkMastSplitTwin.setUpdateTime(now);
                        // 修改成功后复位堆垛机
                        if (wrkMastMapper.updateById(wrkMast) > 0) {
                            // 修改成功后复位堆垛机
                            if (wrkMastSplitTwinService.updateById(wrkMastSplitTwin)) {
                                // 堆垛机复位
                                crnThread.setResetFlagTwo(true);
                                return true;
                            }else {
                                log.error("堆垛机取货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"修改执行档案失败",2,2,3);
                            }
                        }else {
                            log.error("堆垛机取货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"修改工作档案失败!",2,2,3);
                        }
                    }
                    return false;
                }
            }else if (crnProtocol.statusTypeTwo == CrnStatusType.SEPARATE_WAITING && crnProtocol.getTaskNoTwo() != 0  && crnProtocol.getLoadedTwo()==1){
                if (crnProtocol.getTaskNoTwo() == 32222) {
                    // 堆垛机复位
                    crnThread.setResetFlagTwo(true);
                } else {
                    List<WrkMastSplitTwin> wrkMastSplitTwinList = wrkMastSplitTwinMapper.getWrkMastSplitTwin(crn.getId(), 2, null, 1, 1);
                    if (wrkMastSplitTwinList.size()!=1){
                        log.error("堆垛机取货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"不存在或者存在多笔可执行作业,请删除无效作业!!!",2,1,1);
                    }
                    for (WrkMastSplitTwin wrkMastSplitTwin:wrkMastSplitTwinList){
                        Date now = new Date();
                        wrkMastSplitTwin.setWrkSts(wrkMastSplitTwin.getWrkSts()+1);
                        wrkMastSplitTwin.setUpdateTime(now);
                        // 修改成功后复位堆垛机
                        if (wrkMastSplitTwinService.updateById(wrkMastSplitTwin)) {
                            // 堆垛机复位
                            crnThread.setResetFlagTwo(true);
                            return true;
                        }else {
                            log.error("堆垛机取货完成等待确认异常,堆垛机号={},异常信息={},工位号={},工作类型={},工作状态={}",crn.getId(),"修改执行档案失败",2,2,3);
                        }
                    }
                }
            }
        }catch (Exception e){
            log.error("堆垛机工位二完成等待确认异常,堆垛机号={},异常信息={},工位号={}",crn.getId(),e.getMessage(),2);
        }
        return false;
    }
    /**
     * 异常信息记录
     */
    public synchronized void recErr() {
        try {
            this.recCrnErr();
            this.recRgvErr();
        } catch (Exception e) {
            log.error("recErr fail", e);
        }
    }
    /**
     * RGV异常信息记录
     */
    public synchronized void recRgvErr() {
        Date now = new Date();
        for (RgvSlave rgv : slaveProperties.getRgv()) {
            // 获取RGV信息
            RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgv.getId());
            RgvProtocol rgvProtocol = rgvThread.getRgvProtocol();
            if (rgvProtocol == null) {
                continue;
            }
            if (true) {
                // 有任务
                if (rgvProtocol.getTaskNo1() != 0 || rgvProtocol.getTaskNo2() != 0) {
                    Integer taskNo = rgvProtocol.getTaskNo1() > 0 ? rgvProtocol.getTaskNo1().intValue() : rgvProtocol.getTaskNo2().intValue();
                    BasRgvErrLog latest = basRgvErrLogService.findLatestByTaskNo(rgv.getId(), taskNo);
                    // 有异常
                    if (latest == null) {
                        if (rgvProtocol.getAlarm() != null && rgvProtocol.getAlarm() > 0) {
                            WrkMast wrkMast = wrkMastMapper.selectById(taskNo);
                            if (wrkMast == null) {
                                continue;
                            }
                            BasRgvErr rgvErr = basRgvErrMapper.selectById(rgvProtocol.getAlarm());
                            String errName = rgvErr == null ? String.valueOf(rgvProtocol.getAlarm()) : rgvErr.getErrName();
                            BasRgvErrLog basRgvErrLog = new BasRgvErrLog(
                                    null,    // 编号
                                    wrkMast.getWrkNo(),    // 工作号
                                    now,    // 发生时间
                                    null,    // 结束时间
                                    wrkMast.getWrkSts(),    // 工作状态
                                    wrkMast.getIoType(),    // 入出库类型
                                    rgv.getId(),    // 堆垛机
                                    null,    // plc
                                    wrkMast.getLocNo(),    // 目标库位
                                    wrkMast.getStaNo(),    // 目标站
                                    wrkMast.getSourceStaNo(),    // 源站
                                    wrkMast.getSourceLocNo(),    // 源库位
                                    wrkMast.getBarcode(),    // 条码
                                    (int) rgvProtocol.getAlarm(),    // 异常码
                                    errName,    // 异常
                                    1,    // 异常情况
                                    now,    // 添加时间
                                    null,    // 添加人员
                                    now,    // 修改时间
                                    null,    // 修改人员
                                    "任务中异常"    // 备注
                            );
                            if (!basRgvErrLogService.insert(basRgvErrLog)) {
                                log.error("RGV异常记录失败 ===>> [id:{}] [error:{}]", rgv.getId(), errName);
                            }
                        }
                    } else {
                        // 异常修复
                        if (rgvProtocol.getAlarm() == null || rgvProtocol.getAlarm() == 0) {
                            latest.setEndTime(now);
                            latest.setUpdateTime(now);
                            latest.setStatus(2);
                            if (!basRgvErrLogService.updateById(latest)) {
                                log.error("堆垛机plc异常记录修复失败 ===>> [id:{}] [errLogId:{}]", rgv.getId(), latest.getId());
                            }
                        }
                    }
                    // 无任务
                } else {
                    BasRgvErrLog latest = basRgvErrLogService.findLatest(rgv.getId());
                    // 有异常
                    if (rgvProtocol.getAlarm() != null && rgvProtocol.getAlarm() > 0) {
                        // 记录新异常
                        if (latest == null || (latest.getErrCode() != rgvProtocol.getAlarm().intValue())) {
                            BasRgvErr rgvErr = basRgvErrMapper.selectById(rgvProtocol.getAlarm());
                            String errName = rgvErr == null ? String.valueOf(rgvProtocol.getAlarm()) : rgvErr.getErrName();
                            BasRgvErrLog basRgvErrLog = new BasRgvErrLog(
                                    null,    // 编号
                                    null,    // 工作号
                                    now,    // 发生时间
                                    null,    // 结束时间
                                    null,    // 工作状态
                                    null,    // 入出库类型
                                    rgv.getId(),    // 堆垛机
                                    null,    // plc
                                    null,    // 目标库位
                                    null,    // 目标站
                                    null,    // 源站
                                    null,    // 源库位
                                    null,    // 条码
                                    (int) rgvProtocol.getAlarm(),    // 异常码
                                    errName,    // 异常
                                    1,    // 异常情况
                                    now,    // 添加时间
                                    null,    // 添加人员
                                    now,    // 修改时间
                                    null,    // 修改人员
                                    "无任务异常"    // 备注
                            );
                            if (!basRgvErrLogService.insert(basRgvErrLog)) {
                                log.error("RGV异常记录失败 ===>> [id:{}] [error:{}]", rgv.getId(), errName);
                            }
                        }
                        // 无异常
                    } else {
                        // 异常修复
                        if (latest != null && latest.getStatus() == 1) {
                            latest.setEndTime(now);
                            latest.setUpdateTime(now);
                            latest.setStatus(2);
                            if (!basRgvErrLogService.updateById(latest)) {
                                log.error("RGV异常记录修复失败 ===>> [id:{}] [errLogId:{}]", rgv.getId(), latest.getId());
                            }
                        }
                    }
                }
            }
        }
    }
    /**
     * 堆垛机异常信息记录
     */
    @Async
    public void recCrnErr() {
    public synchronized void recCrnErr() {
        Date now = new Date();
        for (CrnSlave crn : slaveProperties.getCrn()) {
            // 获取堆垛机信息
@@ -1236,15 +3499,14 @@
        }
    }
    // -------------------------------------------------------------------------------
    /**
     * 空栈板初始化入库,叉车入库站放货
     */
    @Async
    public void storeEmptyPlt() {
    public synchronized void storeEmptyPlt() {
        for (DevpSlave devp : slaveProperties.getDevp()) {
            if (devp.getId()==1) continue;
            // 遍历空板入库口
            for (DevpSlave.Sta emptyInSta : devp.getEmptyInSta()) {
                // 获取空板入库站信息
@@ -1256,15 +3518,9 @@
                    staProtocol = staProtocol.clone();
                }
//                // 入出库模式判断
//                if ( emptyInSta.getStaNo()==203 && devpThread.ioModeOf2F != IoModeType.PAKIN_MODE) { continue; }
                if (emptyInSta.getStaNo() == 203 && devpThread.ioModeOf2F == IoModeType.PAKOUT_MODE) {
                    continue;
                }
                // 站点条件判断
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isInEnable()
                        && staProtocol.isEmptyMk() && (staProtocol.getWorkNo() > 9990 && staProtocol.getWorkNo() <= 9999) && staProtocol.isPakMk()) {
                        && staProtocol.isEmptyMk() && ((staProtocol.getWorkNo() > 32222 && staProtocol.getWorkNo() <= 63333) || staProtocol.getWorkNo()==0)  && staProtocol.isPakMk()) {
                    try {
                        LocTypeDto locTypeDto = new LocTypeDto(staProtocol);
@@ -1284,8 +3540,8 @@
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            // 更新站点信息 且 下发plc命令
                            staProtocol.setWorkNo(dto.getWorkNo().shortValue());
                            staProtocol.setStaNo(dto.getStaNo().shortValue());
                            staProtocol.setWorkNo(dto.getWorkNo());
                            staProtocol.setStaNo(dto.getStaNo());
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                            if (!result) {
@@ -1298,73 +3554,242 @@
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }
    }
//                    // 检索库位
//                    LocTypeDto locTypeDto = new LocTypeDto(staProtocol);
//                    StartupDto startupDto = commonService.getLocNo(1, 10, emptyInSta.getStaNo(), null, locTypeDto, 0);
//                    // 工作号
//                    int workNo = startupDto.getWorkNo();
//
//                    try {
//                        // 插入工作主档
//                        WrkMast wrkMast = new WrkMast();
//                        wrkMast.setWrkNo(workNo);
//                        wrkMast.setIoTime(new Date());
//                        wrkMast.setWrkSts(2L); // 工作状态:2.设备上走
//                        wrkMast.setIoType(10); // 入出库状态:10.空板入库
//                        wrkMast.setIoPri(10D); // 优先级:10
//                        wrkMast.setCrnNo(startupDto.getCrnNo());
//                        wrkMast.setSourceStaNo(startupDto.getSourceStaNo());
//                        wrkMast.setStaNo(startupDto.getStaNo());
//                        wrkMast.setLocNo(startupDto.getLocNo());
//                        wrkMast.setFullPlt("N"); // 满板
//                        wrkMast.setPicking("N"); // 拣料
//                        wrkMast.setExitMk("N"); // 退出
//                        wrkMast.setEmptyMk("Y"); // 空板
//                        wrkMast.setLinkMis("N");
////                    wrkMast.setCtnType(sourceStaNo.getCtnType()); // 容器类型
//                        // 操作人员数据
//                        wrkMast.setAppeTime(new Date());
//                        wrkMast.setModiTime(new Date());
//                        Integer insert = wrkMastMapper.insert(wrkMast);
//                        if (insert == 0) {
//                            throw new CoolException("保存工作档失败");
//                        }
//                        // 更新目标库位状态
//                        LocMast locMast = locMastService.selectById(startupDto.getLocNo());
//                        locMast.setLocSts("S"); // S.入库预约
//                        locMast.setModiTime(new Date());
//                        if (!locMastService.updateById(locMast)){
//                            throw new CoolException("改变库位状态失败");
//                        }
//                        // 命令下发区 --------------------------------------------------------------------------
//
//                        // 更新站点信息 且 下发plc命令
//                        staProtocol.setWorkNo((short) workNo);
//                        staProtocol.setStaNo(startupDto.getStaNo().shortValue());
//                        devpThread.setPakMk(staProtocol.getSiteId(), false);
//                        boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
//                        if (!result) {
//                            throw new CoolException("更新plc站点信息失败");
//                        }
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//                    }
    /**
     * 空栈板初始化入库,叉车入库站放货
     */
    public synchronized void storeEmptyPltSingle() {
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历空板入库口
            for (DevpSlave.Sta emptyInSta : devp.getEmptyInSingleSta()) {
                // 获取空板入库站信息
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(emptyInSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                // 站点条件判断
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isInEnable()
                        && staProtocol.isEmptyMk() && ((staProtocol.getWorkNo() > 32222 && staProtocol.getWorkNo() <= 63333) || staProtocol.getWorkNo()==0)  && staProtocol.isPakMk()) {
                    try {
                        LocTypeDto locTypeDto = new LocTypeDto(staProtocol);
                        SearchLocParam param = new SearchLocParam();
                        param.setIoType(10);
                        param.setSourceStaNo(emptyInSta.getStaNo());
                        param.setLocType1(locTypeDto.getLocType1());
                        String response = new HttpHandler.Builder()
                                .setUri(wmsUrl)
                                .setPath("/rpc/pakin/pair/station/single/loc/v1")
                                .setJson(JSON.toJSONString(param))
                                .build()
                                .doPost();
                        JSONObject jsonObject = JSON.parseObject(response);
                        if (jsonObject.getInteger("code").equals(200)) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            // 更新站点信息 且 下发plc命令
                            staProtocol.setWorkNo(dto.getWorkNo());
                            staProtocol.setStaNo(dto.getStaNo());
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                            if (!result) {
                                throw new CoolException("更新plc站点信息失败");
                            }
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin/pair/station/single/loc/v1", JSON.toJSONString(param), response);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }
    }
    /**
     * 空栈板初始化入库,叉车入库站放货
     */
    public synchronized void storeEmptyPltLarge() {
        for (DevpSlave devp : slaveProperties.getDevp()) {
            // 遍历空板入库口
            for (DevpSlave.Sta emptyInSta : devp.getEmptyInLargeSta()) {
                // 获取空板入库站信息
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(emptyInSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                // 站点条件判断
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isInEnable()
                        && staProtocol.isEmptyMk() && ((staProtocol.getWorkNo() > 32222 && staProtocol.getWorkNo() <= 63333) || staProtocol.getWorkNo()==0)  && staProtocol.isPakMk()) {
                    try {
                        LocTypeDto locTypeDto = new LocTypeDto(staProtocol);
                        SearchLocParam param = new SearchLocParam();
                        param.setIoType(10);
                        param.setSourceStaNo(emptyInSta.getStaNo());
                        param.setLocType1(locTypeDto.getLocType1());
                        String response = new HttpHandler.Builder()
                                .setUri(wmsUrl)
                                .setPath("/rpc/pakin/loc/v1")
                                .setJson(JSON.toJSONString(param))
                                .build()
                                .doPost();
                        JSONObject jsonObject = JSON.parseObject(response);
                        if (jsonObject.getInteger("code").equals(200)) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            // 更新站点信息 且 下发plc命令
                            staProtocol.setWorkNo(dto.getWorkNo());
                            staProtocol.setStaNo(dto.getStaNo());
                            devpThread.setPakMk(staProtocol.getSiteId(), false);
                            boolean result = MessageQueue.offer(SlaveType.Devp, devp.getId(), new Task(2, staProtocol));
                            if (!result) {
                                throw new CoolException("更新plc站点信息失败");
                            }
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin/loc/v1", JSON.toJSONString(param), response);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }
    }
    /**
     * 入库  ===>> 空栈板初始化入库,1楼叠盘机叠盘
     */
    public synchronized void storeEmptyPlt2() {
        for (DevpSlave devp : slaveProperties.getDevp()) {
            if (devp.getId()==2) continue;
            // 遍历空板入库口
            for (DevpSlave.Sta emptyInSta : devp.getEmptyInSta()) {
                // 获取空板入库站信息
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                StaProtocol staProtocol = devpThread.getStation().get(emptyInSta.getStaNo());
                if (staProtocol == null) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                // 站点条件判断
                if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.isInEnable()
                        && staProtocol.isEmptyMk() && ((staProtocol.getWorkNo() > 32222 && staProtocol.getWorkNo() <= 63333) || staProtocol.getWorkNo()==0) && staProtocol.isPakMk()) {
                    try {
                        WrkMastSta wrkMastSta = wrkMastStaMapper.selectByWrkNo(staProtocol.getSiteId() + 19999L);
                        if (Cools.isEmpty(wrkMastSta)){
                            WrkMastSta wrkMastSta1 = new WrkMastSta(new Date(),staProtocol.getSiteId());
                            wrkMastSta1.setType(2);
                            wrkMastSta1.setWrkType(1);//工作类型  1:取(叠盘)  2:拆盘  3:取放 5:满取  6:满放
                            wrkMastStaMapper.insert(wrkMastSta1);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }
    }
    /**
     * 空栈板初始化入库,叉车入库站放货
     */
    public synchronized void storeEmptyPlt3() {
        try{
            RgvOneSign rgvOneSign = rgvOneSignMapper.selectOneSign();
            if (Cools.isEmpty(rgvOneSign) || rgvOneSign.getRgvOneSign()==1){
                return;
            }
            for (RgvSlave rgvSlave:slaveProperties.getRgv()) {
                RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, rgvSlave.getId());
                RgvProtocol rgvProtocol = rgvThread.getRgvProtocol();
                if (rgvProtocol == null) {
                    continue;
                }
                BasRgv basRgv = basRgvService.selectById(rgvSlave.getId());
                if (basRgv == null) {
                    log.error("{}号RGV尚未在数据库进行维护!", rgvSlave.getId());
                    continue;
                }
                // 只有当RGV空闲、自动,工位二有物//rgv可用
                if (rgvProtocol.getStatusType() == RgvStatusType.IDLE
                        && rgvProtocol.getModeType() == RgvModeType.AUTO
                        && rgvProtocol.getStatusType1() == RgvStatusType.IDLE
                        && rgvProtocol.getStatusType2() == RgvStatusType.IDLE
                        && rgvProtocol.getTaskNo1()==0 && rgvProtocol.getTaskNo2()==0
//                        &&  (rgvProtocol.getLoaded2()==2  || rgvProtocol.getLoaded2()==3 ) ////0 无物;1 一层无物二层有物  ;2一层有物二层无物 (只能满放);3  1、2层都有物  4:()只允许拆盘
                        &&  rgvProtocol.getLoaded2()==3 ////0 无物;1 一层无物二层有物  ;2一层有物二层无物 (只能满放);3  1、2层都有物  4:()只允许拆盘
                ) {
                    try {
                        WrkMast wrkMast1 = wrkMastMapper.selectPakOutStep3(122);
                        if (!Cools.isEmpty(wrkMast1)){
                            continue;
                        }
                        // 获取空板入库站信息
                        SearchLocParam param = new SearchLocParam();
                        param.setIoType(10);
                        param.setSourceStaNo(122);
                        param.setLocType1((short)1);
                        String response = new HttpHandler.Builder()
                                .setUri(wmsUrl)
                                .setPath("/rpc/pakin/empty/loc/v1")
                                .setJson(JSON.toJSONString(param))
                                .build()
                                .doPost();
                        JSONObject jsonObject = JSON.parseObject(response);
                        if (jsonObject.getInteger("code").equals(200)) {
                            StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                            // 更新站点信息 且 下发plc命令
                            WrkMast wrkMast = wrkMastMapper.selectPakInStep3(dto.getWorkNo());
                            if (!Cools.isEmpty(wrkMast) && wrkMast.getIoType()==10 && wrkMast.getWrkSts()==2){
                                WrkMastSta wrkMastSta = wrkMastStaMapper.selectByWrkNo(wrkMast.getWrkNo().longValue());
                                if (Cools.isEmpty(wrkMastSta)){
                                    WrkMastSta wrkMastSta1 = new WrkMastSta(new Date(),wrkMast.getStaNo());
                                    wrkMastSta1.setWrkNo(wrkMast.getWrkNo().longValue());
                                    wrkMastSta1.setType(2);
                                    wrkMastSta1.setWrkType(6);//工作类型  1:取(叠盘)  2:拆盘  3:取放 5:满取  6:满放
                                    wrkMastStaMapper.insert(wrkMastSta1);
                                }
                            }
                        } else {
                            log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/pakin/empty/loc/v1", JSON.toJSONString(param), response);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    }
                }
            }
        }catch (Exception e){
            log.error("3933行执行小车放空板任务下发失败");
            log.error("3933行"+e);
        }
    }
    /**
     * 出库  ===>> 工作档信息写入led显示器
     */
    @Async
    public void ledExecute() {
    public synchronized void ledExecute() {
        for (LedSlave led : slaveProperties.getLed()) {
            // 获取输送线plc线程
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, led.getDevpPlcId());
@@ -1394,6 +3819,7 @@
                // 出库模式
                switch (wrkMast.getIoType()) {
                    case 1:
                    case 202:
                        ledCommand.setTitle("全板入库");
                        break;
                    case 10:
@@ -1415,6 +3841,10 @@
                        ledCommand.setTitle("空板出库");
                        ledCommand.setEmptyMk(true);
                        break;
                    case 212:
                        ledCommand.setTitle("空板出库");
                        ledCommand.setEmptyMk(true);
                        break;
                    default:
                        log.error("任务入出库类型错误!!![工作号:{}] [入出库类型:{}]", wrkMast.getWrkNo(), wrkMast.getIoType());
                        break;
@@ -1425,7 +3855,7 @@
//                ledCommand.setSourceStaNo(wrkMast.getSourceStaNo());
                if (wrkMast.getIoType() != 110 && wrkMast.getIoType() != 10) {
                    List<WrkDetl> wrkDetls = wrkDetlService.findByWorkNo(wrkMast.getWrkNo());
                    wrkDetls.forEach(wrkDetl -> ledCommand.getMatDtos().add(new MatDto(wrkDetl.getMatnr(), wrkDetl.getMaktx(), wrkDetl.getAnfme())));
                    wrkDetls.forEach(wrkDetl -> ledCommand.getMatDtos().add(new MatDto(wrkDetl)));
                }
                commands.add(ledCommand);
            }
@@ -1438,21 +3868,22 @@
            }
            // 命令下发 -------------------------------------------------------------------------------
            if (!commands.isEmpty()) {
                if (led.getId() == 7) {
//                if (led.getId() == 7) {
                    if (!MessageQueue.offer(SlaveType.Led, led.getId(), new Task(3, commands))) {
                        log.error("{}号LED命令下发失败!!![ip:{}] [port:{}]", led.getId(), led.getIp(), led.getPort());
                        continue;
                    } else {
                        ledThread.setLedMk(false);
                    }
                } else {
                    if (!MessageQueue.offer(SlaveType.Led, led.getId(), new Task(1, commands))) {
                        log.error("{}号LED命令下发失败!!![ip:{}] [port:{}]", led.getId(), led.getIp(), led.getPort());
                        continue;
                    } else {
                        ledThread.setLedMk(false);
                    }
                }
//                }
//                else {
//                    if (!MessageQueue.offer(SlaveType.Led, led.getId(), new Task(1, commands))) {
//                        log.error("{}号LED命令下发失败!!![ip:{}] [port:{}]", led.getId(), led.getIp(), led.getPort());
//                        continue;
//                    } else {
//                        ledThread.setLedMk(false);
//                    }
//                }
            }
@@ -1480,35 +3911,7 @@
    /**
     * 其他  ===>> LED显示器复位,显示默认信息
     */
    @Async
    public void ledReset() {
//        for (LedSlave led : slaveProperties.getLed()) {
//            // 获取输送线plc线程
//            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, led.getDevpPlcId());
//            // 命令集合
//            boolean reset = true;
//            for (Integer staNo : led.getStaArr()) {
//                // 获取叉车站点
//                StaProtocol staProtocol = devpThread.getStation().get(staNo);
//                if (staProtocol == null) {
//                    continue;
//                } else {
//                    staProtocol = staProtocol.clone();
//                }
//                if (staProtocol.getWorkNo() != 0) {
//                    reset = false;
//                    break;
//                }
//            }
//            // 获取led线程
//            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, led.getDevpPlcId());
//            // led显示默认内容
//            if (reset) {
//                if (!MessageQueue.offer(SlaveType.Led, led.getId(), new Task(2, new ArrayList<>()))) {
//                    log.error("{}号LED命令下发失败!!![ip:{}] [port:{}]", led.getId(), led.getIp(), led.getPort());
//                }
//            }
//        }
    public synchronized void ledReset() {
        for (LedSlave led : slaveProperties.getLed()) {
            // 获取输送线plc线程
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, led.getDevpPlcId());
@@ -1628,7 +4031,7 @@
     * 因双深库位阻塞,对浅库位进行移转(立即执行版)
     * tip:同步
     */
    private void moveLocForDeepLoc(CrnSlave crn, LocMast shallowLoc) {
    private synchronized void moveLocForDeepLoc(CrnSlave crn, LocMast shallowLoc) {
        try {
            List<Integer> rows = locMastService.queryDistinctRow(crn.getId());
            LocMast loc = null;
@@ -1844,206 +4247,491 @@
    }
    /**
     * 堆垛机命令下发后,异步修改工作档状态
     * 入出库  ===>>  小车作业下发
     */
    public synchronized void crnIoWrkMast() {
    public synchronized boolean steIoExecute(Integer sign) {
        return false;
    }
    /**
     * 入出库  ===>>  堆垛机入出库作业下发
     */
    public synchronized void crnIoExecuteTwoExecute(Integer i) {
        for (CrnSlave crn : slaveProperties.getCrn()) {
            try{
                switch (crn.getId()){
                    case 3:
                    case 4:
                    case 5:
                        crnWrkMastSplitTwinExecute(crn,i);
                        continue;
                    default:
                        continue;
                }
            }catch (Exception e){
                log.error("堆垛机出入库执行任务下发报错,堆垛机号={},异常信息={}",crn.getId(),e.getMessage());
            }
        }
    }
    public synchronized boolean crnWrkMastSplitTwinExecute(CrnSlave crn,Integer i){
        try{
            // 获取堆垛机信息
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId());
            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
            if (crnProtocol == null) {
                continue;
                return false;
            }
            Date now = new Date();
            // 堆垛机正在运行
            if (crnProtocol.getStatusType() != CrnStatusType.IDLE && crnProtocol.getTaskNo() != 0 && crnProtocol.getModeType() == CrnModeType.AUTO) {
                // 获取工作档
                WrkMast wrkMast = wrkMastMapper.selectById(crnProtocol.getTaskNo());
                if (wrkMast == null) {
                    continue;
                }
                // 入库
                if (wrkMast.getWrkSts() == 1 || wrkMast.getWrkSts() == 2) {
                    log.warn("堆垛机非空闲情况下,开始修改工作档状态。[id:{},时间:{}] >>>>> 堆垛机当前状态为:{}。任务号:{}", crn.getId(), DateUtils.convert(now, DateUtils.yyyyMMddHHmmsssss_F), crnProtocol.getStatusType().desc, crnProtocol.getTaskNo());
                    // 修改工作档状态 2.设备上走 => 3.吊车入库中
                    wrkMast.setWrkSts(3L);
                    wrkMast.setCrnStrTime(now);
                    wrkMast.setModiTime(now);
                    if (wrkMastMapper.updateById(wrkMast) == 0) {
                        log.error("修改工作档状态 2.设备上走 => 3.吊车入库中 失败!!,工作号={}", wrkMast.getWrkNo());
                    }
                    log.warn("修改工作档状态成功。[时间:{}] >>>>> 任务号:{}", DateUtils.convert(now, DateUtils.yyyyMMddHHmmsssss_F), wrkMast.getWrkNo());
                }
                // 出库、移库
                if (wrkMast.getWrkSts() == 11) {
                    log.warn("堆垛机非空闲情况下,开始修改工作档状态。[id:{},时间:{}] >>>>> 堆垛机当前状态为:{}。任务号:{}", crn.getId(), DateUtils.convert(now, DateUtils.yyyyMMddHHmmsssss_F), crnProtocol.getStatusType().desc, crnProtocol.getTaskNo());
                    // 修改工作档状态 11.生成出库ID => 12.吊车出库中
                    wrkMast.setWrkSts(12L);
                    wrkMast.setCrnStrTime(now);
                    wrkMast.setModiTime(now);
                    if (wrkMastMapper.updateById(wrkMast) == 0) {
                        log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", wrkMast.getWrkNo());
                    }
                    log.warn("修改工作档状态成功。[时间:{}] >>>>> 任务号:{}", DateUtils.convert(now, DateUtils.yyyyMMddHHmmsssss_F), wrkMast.getWrkNo());
                }
            BasCrnp basCrnp = basCrnpService.selectById(crn.getId());
            if (basCrnp == null) {
                log.error("{}号堆垛机尚未在数据库进行维护!", crn.getId());
                return false;
            }
            int[] sign = new int[]{0,0};
            // 只有当堆垛机自动时才继续执行
            if (crnProtocol.getModeType() == CrnModeType.AUTO) {
                // 只有当堆垛机工位1取货或者有物 并且 工位2无任务时才继续执行
                switch (i){
                    case 1:
                        if (crnProtocol.getStatusType() == CrnStatusType.IDLE
                                && crnProtocol.getTaskNo() == 0
                                && crnProtocol.getLoaded() == 0
                                && crnProtocol.getForkPos() == 0) {
                            sign[0] = 1;
                            sign[1] = 1;
                        }
                        break;
                    case 2:
                        if (crnProtocol.getStatusType() == CrnStatusType.SEPARATE_IDLE
                                && crnProtocol.getTaskNo() == 0
                                && crnProtocol.getLoaded() == 1
                                && crnProtocol.getForkPos() == 0) {
                            sign[0] = 2;
                            sign[1] = 1;
                        }
                        break;
                    case 3:
                        if (crnProtocol.getStatusTypeTwo() == CrnStatusType.IDLE
                                && crnProtocol.getTaskNoTwo() == 0
                                && crnProtocol.getLoadedTwo() == 0
                                && crnProtocol.getForkPosTwo() == 0){
                            sign[0] = 1;
                            sign[1] = 2;
                        }
                        break;
                    case 4:
                        if (crnProtocol.getStatusTypeTwo() == CrnStatusType.SEPARATE_IDLE
                                && crnProtocol.getTaskNoTwo() == 0
                                && crnProtocol.getLoadedTwo() == 1
                                && crnProtocol.getForkPosTwo() == 0){
                            sign[0] = 2;
                            sign[1] = 2;
                        }
                        break;
                    default:
                }
            }
            if (sign[0]!=0){
                List<WrkMastSplitTwin> wrkMastSplitTwinList = wrkMastSplitTwinService.getWrkMastSplitTwin(crn.getId(),sign[1],null,sign[0],0);
                if (wrkMastSplitTwinList.size()>1){
                    log.error("堆垛机出入库下发异常,堆垛机号={},异常信息={},工位号={},工作类型={}",crn.getId(),"存在多笔可执行作业,请删除无效作业!!!",sign[1],sign[0]);
                    return false;
                }
                for (WrkMastSplitTwin wrkMastSplitTwin:wrkMastSplitTwinList){
                    boolean ack = sign[0] == 1 ? crnExecuteTakeFull(crn.getId(), wrkMastSplitTwin, sign[1]) : crnExecutePutFull(crn.getId(), wrkMastSplitTwin, sign[1]);
                    if (ack){
                        wrkMastSplitTwin.setWrkSts(wrkMastSplitTwin.getWrkType()==1? 1:3);
                        wrkMastSplitTwinService.updateById(wrkMastSplitTwin);
                    }else {
                        log.error("堆垛机出入库下发报错,堆垛机号={},异常信息={}",crn.getId(),"下发任务返回值为:"+ack);
                    }
                }
            }
        }catch (Exception e){
            log.error("堆垛机出入库下发报错,堆垛机号={},异常信息={}",crn.getId(),e.getMessage());
        }
        return false;
    }
    /*
     * 堆垛机取货至工位任务
     * */
    public synchronized boolean crnExecuteTakeFull(Integer crnNo,WrkMastSplitTwin wrkMastSplitTwin, Integer crnStation){
        try{
            //  命令下发区 --------------------------------------------------------------------------
            // 1.堆垛机开始移动
            CrnCommand crnCommand = new CrnCommand();
            crnCommand.setCrnNo(crnNo); // 堆垛机编号
            crnCommand.setTaskNo(wrkMastSplitTwin.getWrkNo().shortValue()); // 工作号
            crnCommand.setAckFinish((short) 0);  // 任务完成确认位
            crnCommand.setTaskMode(CrnTaskModeType.SEPARATE_TAKE); // 任务模式:  单取货
            crnCommand.setSourcePosX(wrkMastSplitTwin.getStartRow().shortValue());     // 源库位排
            crnCommand.setSourcePosY(wrkMastSplitTwin.getStartBay().shortValue());     // 源库位列
            crnCommand.setSourcePosZ(wrkMastSplitTwin.getStartLev().shortValue());     // 源库位层
            crnCommand.setDestinationPosX((short)0);     // 目标库位排
            crnCommand.setDestinationPosY((short)0);     // 目标库位列
            crnCommand.setDestinationPosZ((short)0);     // 目标库位层
            if (!MessageQueue.offer(SlaveType.Crn, wrkMastSplitTwin.getCrnNo(), new Task(crnStation==1? 2:5, crnCommand))) {
                log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMastSplitTwin.getCrnNo(), JSON.toJSON(crnCommand));
                return false;
            } else {
                return true;
            }
        }catch (Exception e){
            return false;
        }
    }
    /*
     * 堆垛机放货货至出库站点任务
     * */
    public synchronized boolean crnExecutePutFull(Integer crnNo,WrkMastSplitTwin wrkMastSplitTwin, Integer crnStation){
        try{
            //  命令下发区 --------------------------------------------------------------------------
            // 1.堆垛机开始移动
            CrnCommand crnCommand = new CrnCommand();
            crnCommand.setCrnNo(crnNo); // 堆垛机编号
            crnCommand.setTaskNo(wrkMastSplitTwin.getWrkNo().shortValue()); // 工作号
            crnCommand.setAckFinish((short) 0);  // 任务完成确认位
            crnCommand.setTaskMode(CrnTaskModeType.SEPARATE_PUT); // 任务模式:  单放货
            crnCommand.setSourcePosX((short)0);     // 源库位排
            crnCommand.setSourcePosY((short)0);     // 源库位列
            crnCommand.setSourcePosZ((short)0);     // 源库位层
            crnCommand.setDestinationPosX(wrkMastSplitTwin.getEndRow().shortValue());     // 目标库位排
            crnCommand.setDestinationPosY(wrkMastSplitTwin.getEndBay().shortValue());     // 目标库位列
            crnCommand.setDestinationPosZ(wrkMastSplitTwin.getEndLev().shortValue());     // 目标库位层
            if (!MessageQueue.offer(SlaveType.Crn, wrkMastSplitTwin.getCrnNo(), new Task(crnStation==1? 2:5, crnCommand))) {
                log.error("堆垛机命令下发失败,堆垛机号={},任务数据={}", wrkMastSplitTwin.getCrnNo(), JSON.toJSON(crnCommand));
                return false;
            } else {
                return true;
            }
        }catch (Exception e){
            return false;
        }
    }
    /**
     * 入出库模式切换函数
     *  Jar任务创建  //完成
     */
    public void ioConvert() {
        try {
            // 根据输送线plc遍历
            for (DevpSlave devp : slaveProperties.getDevp()) {
                SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, devp.getId());
                for (DevpSlave.Sta inSta : devp.getInSta()) {
                    if (inSta.getStaNo() == 2) {
    public synchronized void jarMastGenerate() {
        for (JarSlave jarSlave : slaveProperties.getJar()) {
            try{
                if (wrkMastExecuteService.getWrkMastByJarIdCount(jarSlave.getId())!=0){
                    continue;
                }
                for(JarSlave.StaStn staStn : jarSlave.getJarInSta()){
                    // 获取硫化罐入库站信息
                    DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, staStn.getDevpPlcId());
                    StaProtocol staProtocol = devpThread.getStation().get(staStn.getStaNo());
                    if (staProtocol == null) {
                        continue;
                    } else {
                        staProtocol = staProtocol.clone();
                    }
                    WrkMast pakout = wrkMastMapper.selectWorkingPakout(inSta.getStaNo());
                    switch (inSta.getStaNo()) {
                        case 203://1F
                            if (pakout != null) {
                                if (devpThread.ioModeOf2F != IoModeType.PAKOUT_MODE) {
                                    // 出库切换中
                                    devpThread.ioModeOf2F = IoModeType.PAKOUT_BOOTING;
                                    WrkMast pakin = wrkMastMapper.selectWorkingPakin(inSta.getStaNo());
                                    if (pakin == null && !devpThread.getStation().get(inSta.getStaNo()).isLoading()
                                            && !devpThread.getStation().get(inSta.getStaNo() + 1).isLoading()
                                            && devpThread.getStation().get(inSta.getStaNo() + 1).getWorkNo() == 0) {
                                        // 出库模式
                                        devpThread.ioModeOf2F = IoModeType.PAKOUT_MODE;
                                    }
                                }
                            } else {
                                // 入库模式
                                devpThread.ioModeOf2F = IoModeType.PAKIN_MODE;
                    if (staProtocol.isAutoing() && staProtocol.isLoading() && staProtocol.getWorkNo()!=0){
                        try{
                            if (basJarMastService.selectJarMastOperation(jarSlave.getId(),2)!=0){
                                break;
                            }
                            break;
                        case 401://1F
                            if (pakout != null) {
                                if (devpThread.ioModeOf4F != IoModeType.PAKOUT_MODE) {
                                    // 出库切换中
                                    devpThread.ioModeOf4F = IoModeType.PAKOUT_BOOTING;
                                    WrkMast pakin = wrkMastMapper.selectWorkingPakin(inSta.getStaNo());
                                    if (pakin == null && !devpThread.getStation().get(inSta.getStaNo()).isLoading()
                                            && !devpThread.getStation().get(inSta.getStaNo() + 1).isLoading()
                                            && devpThread.getStation().get(inSta.getStaNo() + 1).getWorkNo() == 0) {
                                        // 出库模式
                                        devpThread.ioModeOf4F = IoModeType.PAKOUT_MODE;
                                    }
                                }
                            } else {
                                // 入库模式
                                devpThread.ioModeOf4F = IoModeType.PAKIN_MODE;
                            if (basJarMastService.selectJarMastOperation(jarSlave.getJarOtherId(),3)!=0){
//                            log.error("{}号小车",jarSlave.getJarOtherId());
                                break;
                            }
                            break;
                            if (basJarMastService.getJarMastByJarIdCount(jarSlave.getId())>=14){
                                break;
                            }
                            if (basJarMastService.selectJarMastOperation(jarSlave.getId(),0,9)>=7){
                                break;
                            }
                            if (!Objects.equals
                                    (
                                    basJarMastService.selectJarMastOperation(jarSlave.getId(), 0, 4)
                                    ,
                                    basJarMastService.selectJarMastOperation(jarSlave.getId(), 0, 9)
                                    )
                            ){
                                break;
                            }
                            BasJarMast jarMastByJarIdMax = basJarMastService.getJarMastByJarIdMax(jarSlave.getId(),0,4);
                            int jarLocDigit = 0;
                            if (Cools.isEmpty(jarMastByJarIdMax)){
                                if (basJarMastService.selectJarMastOperation(jarSlave.getId(),0,4)!=0){
                                    break;
                                }
                                jarLocDigit = 1;
                            } else if (jarMastByJarIdMax.getJarLocDigit()<7){
                                jarLocDigit = jarMastByJarIdMax.getJarLocDigit()+1;
                            } else {
                                continue;
                            }
                            WrkMast wrkMast = wrkMastMapper.selectById(staProtocol.getWorkNo());
                            if (Cools.isEmpty(wrkMast) || wrkMast.getWrkSts()!=2){
                                continue;
                            }
                            BasJarMast basJarMast = basJarMastService.getJarMastByWrkNo(wrkMast.getWrkNo().longValue());
                            if (!Cools.isEmpty(basJarMast)){
                                continue;
                            }
                            WrkMastExecute wrkMastExecute = wrkMastExecuteService.getWrkMastByWrkNo(wrkMast.getWrkNo().longValue());
                            if (!Cools.isEmpty(wrkMastExecute)){
                                continue;
                            }
                            if (jarMastGenerateExecute(jarSlave,wrkMast,jarLocDigit,staStn.getStaNo())){
                                return;
                            }
                        }catch (Exception e){
                            log.error(jarSlave.getId()+"号小车复位线程报错!"+e);
                        }
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void outOfDevp() {
        List<WrkMast> wrkMasts = wrkMastMapper.selectPick();
        for (WrkMast wrkMast : wrkMasts) {
            if (basDevpService.selectCount(new EntityWrapper<BasDevp>().eq("wrk_no", wrkMast.getWrkNo())) == 0) {
                wrkMast.setCtnNo("Y");
                if (wrkMastMapper.updateById(wrkMast) == 0) {
                    log.error("修改{}工作档失败,ctn_no", wrkMast.getWrkNo());
                }
            }
        }
    }
    public void autoEmptyOut() {
        DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, 1);
        Integer autoOutSite = 12;
        //如果站点可出禁用,则不生成空盘出库任务
        StaProtocol staProtocol = devpThread.getStation().get(autoOutSite);
        if (staProtocol == null) {
            return;
        } else {
            staProtocol = staProtocol.clone();
        }
        if (staProtocol.isAutoing()  //自动
                && !staProtocol.isLoading()  //无物
                && staProtocol.isOutEnable()  //可出信号
                && staProtocol.getWorkNo() == 0
        ) {
            WrkMast pakoutEmpty = wrkMastMapper.selectPakoutEmpty(autoOutSite);
            if (null != pakoutEmpty) {
                return;
            }
            try {
                String response = new HttpHandler.Builder()
                        .setUri(wmsUrl)
                        .setPath("/rpc/auto/emptyOut/v1")
                        .build()
                        .doPost();
                JSONObject jsonObject = JSON.parseObject(response);
                if (jsonObject.getInteger("code").equals(200)) {
                    JSONObject data = (JSONObject) jsonObject.get("data");
                    log.info((String) data.get("msg"));
                } else {
                    log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/auto/emptyOut/v1","", response);
                }
            } catch (Exception e) {
                e.printStackTrace();
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            } catch (Exception e){
                log.error("{}号硫化罐Jar任务创建异常,异常原因={}",jarSlave.getId(),e.getMessage());
            }
        }
    }
    public void autoEmptyIn() {
        DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, 1);
        Integer autoInSite = 12;
        StaProtocol staProtocol = devpThread.getStation().get(autoInSite);
        if (staProtocol == null) {
            return;
        } else {
            staProtocol = staProtocol.clone();
        }
        if (staProtocol.isAutoing()  //自动
                && staProtocol.isLoading()  //有物
                && staProtocol.isInEnable()  //可入信号
                && (staProtocol.getWorkNo() == 0 || staProtocol.getWorkNo() > 9990) //工作号为0或者工作号是9991~9999(输送机留用)
        ) {
    /**
     *  Jar任务创建===》执行  //完成
     */
    public synchronized boolean jarMastGenerateExecute(JarSlave jarSlave,WrkMast wrkMast,Integer jarLocDigit,Integer staNo) {
        try{
            // 获取硫化罐信息
            JarThread jarThread = (JarThread) SlaveConnection.get(SlaveType.Jar, jarSlave.getId());
            JarProtocol jarProtocol = jarThread.getJarProtocol();
            if (jarProtocol == null) {
                return false;
            }
            if (jarProtocol.modeType != JarModeType.AUTO){
                return false;
            }
            try {
                LocTypeDto locTypeDto = new LocTypeDto((short) 1, (short) 1, (short) 1);
            JarThread jarOtherThread = (JarThread) SlaveConnection.get(SlaveType.Jar, jarSlave.getJarOtherId());
            JarProtocol jarOtherProtocol = jarOtherThread.getJarProtocol();
            if (jarOtherProtocol == null) {
                return false;
            }
//            if (jarOtherProtocol.modeType != JarModeType.AUTO){
//                return false;
//            }
            BasJar basJar = basJarMapper.selectById(jarProtocol.getJarNo());
            if (Cools.isEmpty(basJar)){
                log.error("{}号硫化罐查询设备档案无信息!!!",jarProtocol.getJarNo());
                return false;
            }
                String response = new HttpHandler.Builder()
                        .setUri(wmsUrl)
                        .setPath("/rpc/auto/emptyIn/v1")
                        .setJson(JSON.toJSONString(locTypeDto))
                        .build()
                        .doPost();
                JSONObject jsonObject = JSON.parseObject(response);
                if (jsonObject.getInteger("code").equals(200)) {
                    log.info((String) jsonObject.get("msg"));
                } else {
                    log.error("请求接口失败!!!url:{};request:{};response:{}", wmsUrl + "/rpc/auto/emptyIn/v1", JSON.toJSONString(locTypeDto), response);
            if (basJar.getJarMode()!=1 && basJar.getJarMode()!=0){
                return false;
            }
            //自动、空闲、右门关闭、   Other左门关闭
            if (jarProtocol.isAutoing() && !jarProtocol.isRightDoor() && jarProtocol.jarErr==0
                    && jarProtocol.leftDoorOpen==0  && jarProtocol.leftDoorClose==0 && jarProtocol.rightDoorOpen==0  && jarProtocol.rightDoorClose==0
                    && !jarOtherProtocol.isLeftDoor() && jarOtherProtocol.leftDoorOpen==0  && jarOtherProtocol.leftDoorClose==0){
                if (jarProtocol.statusType == JarStatusType.IDLE || jarProtocol.statusType == JarStatusType.MOVING){
                    BasJarMast basJarMast = new BasJarMast(basJar, wrkMast, jarLocDigit);
                    basJarMast.setJarEnterStaNo(staNo);//入硫化罐站点
                    basJarMastService.insert(basJarMast);
                    return true;
                }
            } catch (Exception e) {
                e.printStackTrace();
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        } catch (Exception e){
            log.error("{}号硫化罐生成BasJarMast初始任务失败,异常原因={},工作号={},硫化库位={}",jarSlave.getId(),e.getMessage(),wrkMast,jarLocDigit);
        }
        return false;
    }
    /**
     *  Jar任务完成   //未完成
     */
    public synchronized boolean jarMastGenerateComplete(JarSlave jarSlave) {
        try{
            // 获取堆垛机信息
            JarThread jarThread = (JarThread) SlaveConnection.get(SlaveType.Jar, jarSlave.getId());
            JarProtocol jarProtocol = jarThread.getJarProtocol();
            if (jarProtocol == null) {
                return false;
            }
            if (jarProtocol.modeType != JarModeType.AUTO){
                return false;
            }
            JarThread jarOtherThread = (JarThread) SlaveConnection.get(SlaveType.Jar, jarSlave.getJarOtherId());
            JarProtocol jarOtherProtocol = jarOtherThread.getJarProtocol();
            if (jarOtherProtocol == null) {
                return false;
            }
            if (jarOtherProtocol.modeType != JarModeType.AUTO){
                return false;
            }
            //自动、空闲、右门关闭、
            if (jarProtocol.isAutoing() && !jarProtocol.isRightDoor() && jarProtocol.jarErr==0 && !jarOtherProtocol.isLeftDoor() && jarOtherProtocol.jarErr==0){
            }
        } catch (Exception e){
//            log.error("堆垛机工位二完成等待确认异常,堆垛机号={},异常信息={},工位号={}",crn.getId(),e.getMessage(),2);
        }
        return false;
    }
    /**
     *  JarWrkMastExecute任务创建   //未完成
     *  开门、入硫化罐
     */
    public synchronized void jarWrkMastExecuteGenerate() {
        for (JarSlave jarSlave : slaveProperties.getJar()) {
            try{
                if (wrkMastExecuteService.getWrkMastByJarIdCount(jarSlave.getId())!=0){
                    continue;
                }
                List<BasJarMast> basJarMastList = basJarMastService.getJarMastByJarIdAndStatusList(jarSlave.getId(), new ArrayList<Integer>() {{
                    add(0);
                    add(2);
                }});
                for (BasJarMast basJarMast : basJarMastList){
                    // 获取硫化罐信息
                    JarThread jarThread = (JarThread) SlaveConnection.get(SlaveType.Jar, jarSlave.getId());
                    JarProtocol jarProtocol = jarThread.getJarProtocol();
                    if (jarProtocol == null) {
                        break;
                    }
                    if (jarProtocol.modeType != JarModeType.AUTO){
                        break;
                    }
                    JarThread jarOtherThread = (JarThread) SlaveConnection.get(SlaveType.Jar, jarSlave.getJarOtherId());
                    JarProtocol jarOtherProtocol = jarOtherThread.getJarProtocol();
                    if (jarOtherProtocol == null) {
                        break;
                    }
//                    if (jarOtherProtocol.modeType != JarModeType.AUTO){
//                        continue;
//                    }
                    BasJar basJar = basJarMapper.selectById(jarProtocol.getJarNo());
                    if (Cools.isEmpty(basJar)){
                        log.error("{}号硫化罐查询设备档案无信息!!!",jarProtocol.getJarNo());
                        break;
                    }
                    //门作业  无
                    //自动、空闲、右门关闭、   Other左门关闭
                    if (jarProtocol.isAutoing() && !jarProtocol.isRightDoor() && jarProtocol.jarErr==0
                            && jarProtocol.leftDoorOpen==0  && jarProtocol.leftDoorClose==0 && jarProtocol.rightDoorOpen==0  && jarProtocol.rightDoorClose==0
                            && !jarOtherProtocol.isLeftDoor() && jarOtherProtocol.leftDoorOpen==0  && jarOtherProtocol.leftDoorClose==0){
                        if (jarProtocol.statusType == JarStatusType.IDLE && !jarProtocol.isLeftDoor() && basJarMast.getStatus()==0){
                            //生成开门任务 OpenTheDoor
                            if (!jarWrkMastExecuteGenerateExecute(basJar,basJarMast,new int[]{basJar.getEnterSteNo(),basJar.getEnterRgvId(),1,1})){
                                log.error("JarWrkMastExecute任务创建===>执行异常===》异常数据:BasJar:"+ JSON.toJSONString(basJar)+";BasJarMast:"+JSON.toJSONString(basJarMast));
                            }
                            return;
                        } else if (jarProtocol.statusType == JarStatusType.MOVING && jarProtocol.isLeftDoor()){
                            //生成入硫化罐任务
                            if (!jarWrkMastExecuteGenerateExecute(basJar,basJarMast,new int[]{basJar.getEnterSteNo(),basJar.getEnterRgvId(),5,1})){
                                log.error("JarWrkMastExecute任务创建===>执行异常===》异常数据:BasJar:"+ JSON.toJSONString(basJar)+";BasJarMast:"+JSON.toJSONString(basJarMast));
                            }
                            return;
                        } else if (jarProtocol.statusType == JarStatusType.IDLE && jarProtocol.isLeftDoor()){
                            log.error("JarWrkMastExecute任务创建===>执行异常===》硫化罐空闲但是门未关===》异常数据:BasJar:"+ JSON.toJSONString(basJar)+";BasJarMast:"+JSON.toJSONString(basJarMast));
                        }
                    }
                    break;
                }
            } catch (Exception e){
                log.error("{}号硫化罐JarWrkMastExecute任务创建异常,异常原因={}",jarSlave.getId(),e.getMessage());
            }
        }
    }
    /**
     *  JarWrkMastExecute任务创建===>执行   //未完成
     */
    public synchronized boolean jarWrkMastExecuteGenerateExecute(BasJar basJar,BasJarMast basJarMast,int[] digit) {
        try{
            WrkMastExecute wrkMastExecute = new WrkMastExecute(basJarMast);
            wrkMastExecute.setJarId(digit[3]==2? basJar.getBurial():basJar.getJarNo());
            wrkMastExecute.setSteId(digit[0]);//穿梭板ID
            wrkMastExecute.setRgvId(digit[1]);//RGV ID
            wrkMastExecute.setIoType(digit[2]);//任务类型 0: 未知  1: 开进料门  2: 关进料门  3: 开出料门  4: 关出料门  5: 入硫化罐  6: 入冷却槽  7: 穿梭车进冷却槽  8: 穿梭车离开冷却槽  9: 出冷却槽
            wrkMastExecute.setType(digit[3]);//设备  0: 未知  1: 硫化罐  2: 冷却槽  3: 硫化罐==>冷却槽
            return wrkMastExecuteService.insert(wrkMastExecute);
        }catch (Exception e){
            log.error("JarWrkMastExecute任务创建===>执行异常===》异常原因:"+e.getMessage());
        }
        return false;
    }
    /*
     * 开门任务创建
     * */
    public synchronized boolean jarWrkMastExecuteGenerate2(){
        try{
        } catch (Exception e){
            log.error("{}号硫化罐OpenTheDoorGenerate==》JarWrkMastExecute任务创建异常,异常原因={}",null,e.getMessage());
        }
        return false;
    }
    /**
     *  JarWrkMastExecute任务完成   //未完成
     */
    public synchronized void jarWrkMastExecuteGenerateComplete() {
        try{
        }catch (Exception e){
            log.error("小车复位线程报错!"+e);
        }
    }
    /*
     * Rgv  移动
     * */
    public synchronized boolean jarRgvTake2(Integer rgvId,BasJarMast basJarMast){
        return false;
    }
    /*
     * 小车取空板至工位任务  满取
     * */
    public synchronized boolean jarRgvTake3(Integer rgvId,BasJarMast basJarMast){
        return false;
    }
    /*
     * 小车取空板至工位任务  满取
     * */
    public synchronized boolean jarRgvTake4(Integer rgvId,BasJarMast basJarMast){
        return false;
    }
    /*
     * 小车取空板至工位任务  满取
     * */
    public synchronized boolean jarRgvTake5(Integer rgvId,BasJarMast basJarMast){
        return false;
    }
    /*
     * 小车取空板至工位任务  满取
     * */
    public synchronized boolean jarRgvTake6(Integer rgvId,BasJarMast basJarMast){
        return false;
    }
    /*
     * 小车取空板至工位任务  满取
     * */
    public synchronized boolean jarRgvTake7(Integer rgvId,BasJarMast basJarMast){
        return false;
    }
    /*
     * 穿梭板移动
     * */
    public synchronized boolean jarRgvTake8(Integer rgvId,BasJarMast basJarMast){
        return false;
    }
}