*
lsh
2 天以前 cc53aa90eaf44db5f474af473285187486da8370
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java
@@ -11,6 +11,7 @@
import com.zy.asrs.domain.enums.WorkNoType;
import com.zy.asrs.domain.param.CrnOperatorParam;
import com.zy.asrs.entity.*;
import com.zy.asrs.entity.param.TaskCreateParam;
import com.zy.asrs.mapper.*;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.*;
@@ -81,6 +82,8 @@
    private CrnController crnController;
    @Autowired
    private BasDevpPositionService basDevpPositionService;
    @Autowired
    private OpenService openService;
    @Value("${wms.url}")
    private String wmsUrl;
@@ -670,6 +673,7 @@
            CrnSlave crnSlave = new CrnSlave(crn);
            if (Cools.isEmpty(crnProtocol.getLaneNo()) || crnProtocol.getLaneNo()==0){
                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机巷道号异常!");
                continue;
            }
@@ -761,19 +765,25 @@
                        if (!taskWrks.isEmpty()) {
                            continue;
                        }
                        List<TaskWrkLog> taskWrkLogs = taskWrkLogService.selectList(new EntityWrapper<TaskWrkLog>().eq("CRN_NO",crnProtocol.getLaneNo()).orderBy("COMPLETE_TIME",true));
                        List<TaskWrkLog> taskWrkLogs = taskWrkLogService.selectList(new EntityWrapper<TaskWrkLog>().eq("CRN_NO",crnProtocol.getLaneNo()).orderBy("COMPLETE_TIME",false));
                        if (!taskWrkLogs.isEmpty()) {
                            TaskWrkLog taskWrkLog = taskWrkLogs.get(0);
                            Date completeTime = taskWrkLog.getCompleteTime();
                            if (completeTime==null){
                                completeTime = taskWrkLog.getCancelTime();
                            boolean signT = false;
                            for (TaskWrkLog taskWrkLog : taskWrkLogs){
                                Date completeTime = taskWrkLog.getCompleteTime();
                                if (completeTime==null){
                                    completeTime = taskWrkLog.getModiTime();
                                    continue;
                                }
                                long differenceInSeconds = TimeCalculatorUtils.differenceInMilliseconds(completeTime, new Date());
                                if (differenceInSeconds <= 60*2*1000) {
                                    signT = true;
                                    break;
                                } else {
                                    signT = false;
                                    break;
                                }
                            }
                            long differenceInSeconds = TimeCalculatorUtils.differenceInMilliseconds(completeTime, new Date());
                            if (differenceInSeconds <= 60*10*1000) {
                                return;
                            if (signT){
                                continue;
                            }
                        }
                        // 命令下发区 --------------------------------------------------------------------------
@@ -783,10 +793,10 @@
                        crnCommand.setTaskNo((short)999); // 工作号
                        crnCommand.setAckFinish((short) 0);  // 任务完成确认位
                        crnCommand.setTaskMode(CrnTaskModeType.SITE_MOVE); // 任务模式:  站位移转4
                        crnCommand.setSourcePosX((short) 0);     // 源库位排
                        crnCommand.setSourcePosY(crnProtocol.getBay());     // 源库位列
                        crnCommand.setSourcePosZ(crnProtocol.getLevel());   // 源库位层
                        int row = crnProtocol.getLaneNo() * 2;
                        crnCommand.setSourcePosX((short) row);     // 源库位排
                        crnCommand.setSourcePosY((short) 1);     // 源库位列
                        crnCommand.setSourcePosZ((short) 1);   // 源库位层
                        crnCommand.setDestinationPosX((short) row);     // 目标库位排
                        crnCommand.setDestinationPosY((short) 1);     // 目标库位层
                        crnCommand.setDestinationPosZ((short) 1);     // 目标库位列
@@ -809,7 +819,7 @@
                    }
                }
            } catch (Exception e){
                log.error("堆垛机5分钟无任务则回到源点失败");
                log.error("堆垛机10分钟无任务则回到源点失败");
            }
        }
    }
@@ -833,6 +843,7 @@
            CrnSlave crn = new CrnSlave(crnSlave);
            if (Cools.isEmpty(crnProtocol.getLaneNo()) || crnProtocol.getLaneNo()==0){
                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机巷道号异常!");
                continue;
            }
@@ -941,41 +952,6 @@
                // 已经存在吊车执行任务时,则过滤
                if (taskWrkMapper.selectCrnWorking(crnProtocol.getLaneNo()) != null) {
                    TaskWrk taskWrkNow3 = taskWrkMapper.selectCrnWorking(crnProtocol.getLaneNo());
                    if (taskWrkNow3.getWrkSts() == 3){
                        try{
                            // 命令下发区 --------------------------------------------------------------------------
                            CrnCommand crnCommand = new CrnCommand();
                            crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
                            crnCommand.setLaneNo(crnProtocol.getLaneNo()); // 堆垛机巷道编号
                            crnCommand.setTaskNo(taskWrkNow3.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(Utils.getRowShort(taskWrkNow3.getTargetPoint()));     // 目标库位列
                            int bay1 = Utils.getBayShort(taskWrkNow3.getTargetPoint()) + 1;
                            crnCommand.setDestinationPosY((short)bay1);     // 目标库位层
                            crnCommand.setDestinationPosZ(Utils.getLevShort(taskWrkNow3.getTargetPoint()));     // 目标库位排
//                crnCommand.setCommand((short) 1);
                            try{
                                DeviceErrorService deviceErrorService = SpringUtils.getBean(DeviceErrorService.class);
                                deviceErrorService.addDeviceError("CrnErr", slave.getId(), "巷道号"+crnCommand.getLaneNo()+";堆垛机命令地址补丁重新写入:"+JSON.toJSONString(crnCommand.getNowTask()));
                            } catch (Exception e2){
                            }
                            if (!MessageQueue.offer(SlaveType.Crn, slave.getId(), new Task(2, crnCommand))) {
                                log.error("堆垛机命令生成失败,堆垛机号={},任务数据={}", taskWrk.getCrnNo(), JSON.toJSON(crnCommand));
                                devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机命令生成失败");
                                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "运行命令下发失败");
                                throw new CoolException("堆垛机命令生成失败");
                            }
                        } catch (Exception eNow3){
                        }
                    }
                    devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机存在吊车任务");
                    CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机存在执行中吊车任务");
                    continue;
@@ -1024,22 +1000,22 @@
//                }
                // 命令下发区 --------------------------------------------------------------------------
                CrnCommand crnCommand = new CrnCommand();
                crnCommand.setCrnNo(slave.getId()); // 堆垛机编号
                crnCommand.setLaneNo(crnProtocol.getLaneNo()); // 堆垛机巷道编号
                crnCommand.setTaskNo(taskWrk.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(Utils.getRowShort(taskWrk.getTargetPoint()));     // 目标库位列
                CrnCommand crnCommand1 = new CrnCommand();
                crnCommand1.setCrnNo(slave.getId()); // 堆垛机编号
                crnCommand1.setLaneNo(crnProtocol.getLaneNo()); // 堆垛机巷道编号
                crnCommand1.setTaskNo(taskWrk.getWrkNo().shortValue()); // 工作号
                crnCommand1.setAckFinish((short) 0);  // 任务完成确认位
                crnCommand1.setTaskMode(CrnTaskModeType.LOC_MOVE); // 任务模式:  库位移转
                crnCommand1.setSourcePosX(crnStn.getRow().shortValue());     // 源库位排
                crnCommand1.setSourcePosY(crnStn.getBay().shortValue());     // 源库位列
                crnCommand1.setSourcePosZ(crnStn.getLev().shortValue());   // 源库位层
                crnCommand1.setDestinationPosX(Utils.getRowShort(taskWrk.getTargetPoint()));     // 目标库位列
                int bay1 = Utils.getBayShort(taskWrk.getTargetPoint()) + 1;
                crnCommand.setDestinationPosY((short)bay1);     // 目标库位层
                crnCommand.setDestinationPosZ(Utils.getLevShort(taskWrk.getTargetPoint()));     // 目标库位排
                crnCommand1.setDestinationPosY((short)bay1);     // 目标库位层
                crnCommand1.setDestinationPosZ(Utils.getLevShort(taskWrk.getTargetPoint()));     // 目标库位排
//                crnCommand.setCommand((short) 1);
                if (!MessageQueue.offer(SlaveType.Crn, slave.getId(), new Task(2, crnCommand))) {
                    log.error("堆垛机命令生成失败,堆垛机号={},任务数据={}", taskWrk.getCrnNo(), JSON.toJSON(crnCommand));
                if (!MessageQueue.offer(SlaveType.Crn, slave.getId(), new Task(2, crnCommand1))) {
                    log.error("堆垛机命令生成失败,堆垛机号={},任务数据={}", taskWrk.getCrnNo(), JSON.toJSON(crnCommand1));
                    devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机命令生成失败");
                    CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "运行命令下发失败");
@@ -1153,39 +1129,6 @@
                        // 已经存在吊车执行任务时,则过滤
                        if (taskWrkMapper.selectCrnWorking(crnProtocol.getLaneNo()) != null) {
                            TaskWrk taskWrkNow3 = taskWrkMapper.selectCrnWorking(crnProtocol.getLaneNo());
                            if (taskWrkNow3.getWrkSts() == 12){
                                try{
                                    CrnCommand command = new CrnCommand();
                                    command.setCrnNo(slave.getId()); // 堆垛机编号
                                    command.setLaneNo(crnProtocol.getLaneNo()); // 堆垛机编号
                                    command.setTaskNo(taskWrkNow3.getWrkNo().shortValue()); // 工作号
                                    command.setAckFinish((short) 0);  // 任务完成确认位
                                    command.setTaskMode(CrnTaskModeType.PAKIN); // 任务模式
                                    command.setSourcePosX(Utils.getRowShort(taskWrkNow3.getStartPoint()));     // 源库位排
                                    int bayS = Utils.getBayShort(taskWrkNow3.getStartPoint()) + 1;
                                    command.setSourcePosY((short)bayS);     // 源库位列
                                    command.setSourcePosZ(Utils.getLevShort(taskWrkNow3.getStartPoint()));     // 源库位层
                                    command.setDestinationPosX(crnStn.getRow().shortValue());     // 目标库位排
                                    command.setDestinationPosY(crnStn.getBay().shortValue());     // 目标库位列
                                    command.setDestinationPosZ(crnStn.getLev().shortValue());     // 目标库位层
//                        command.setCommand((short) 1);
                                    try{
                                        DeviceErrorService deviceErrorService = SpringUtils.getBean(DeviceErrorService.class);
                                        deviceErrorService.addDeviceError("CrnErr", slave.getId(), "巷道号"+command.getLaneNo()+";堆垛机命令地址补丁重新写入:"+JSON.toJSONString(command.getNowTask()));
                                    } catch (Exception e2){
                                    }
                                    if (!MessageQueue.offer(SlaveType.Crn, slave.getId(), new Task(2, command))) {
                                        log.error("堆垛机命令生成失败,堆垛机号={},巷道={},任务数据={}", slave.getId(), taskWrk.getCrnNo(), JSON.toJSON(command));
                                        devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机命令生成失败");
                                        CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "运行命令下发失败");
                                        throw new CoolException("堆垛机命令生成失败");
                                    }
                                } catch (Exception eNow3){
                                }
                            }
                            devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机存在吊车任务");
                            CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机存在执行中吊车任务");
                            break;
@@ -1312,6 +1255,7 @@
                // 已经存在吊车执行任务时,则过滤
                if (taskWrkMapper.selectCrnWorking(crnProtocol.getLaneNo()) != null) {
                    CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机存在执行中吊车任务");
                    continue;
                }
@@ -1408,6 +1352,7 @@
                CrnSlave crn = new CrnSlave(crnSlave);
                if (Cools.isEmpty(crnProtocol.getLaneNo()) || crnProtocol.getLaneNo()==0){
                    CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机巷道号异常!");
                    continue;
                }
@@ -2738,4 +2683,599 @@
    }
    /**
     * 堆垛机站出库到出库站
     */
    public boolean crnStnDEMOStop2() {
        int signHpMk = 0;
        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 (Cools.isEmpty(basCrnp.getHpMk()) || !basCrnp.getHpMk().equals("Y")){
                signHpMk++;
            }
        }
        if (signHpMk == slaveProperties.getCrn().size()){
            return true;
        }
        return false;
    }
    /**
     * 堆垛机站出库到出库站
     */
    public boolean crnStnDEMOStop3() {
        int selectCount = taskWrkService.selectCount(new EntityWrapper<TaskWrk>().eq("io_type",4));
        if (selectCount>0) {
            return false;
        }
        return true;
    }
    /**
     * 演示模式启动
     */
    public boolean crnStnDEMOOpen0() {
        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 (Cools.isEmpty(basCrnp.getHpMk()) || !basCrnp.getHpMk().equals("Y")){
                continue;
            }
            return true;
        }
        return false;
    }
    /**
     * 演示模式启动
     */
    public boolean crnStnDEMOOpen1() {
        int selectCount = taskWrkService.selectCount(new EntityWrapper<TaskWrk>());
        if (selectCount>0) {
            return false;
        }
        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 (Cools.isEmpty(basCrnp.getHpMk()) || !basCrnp.getHpMk().equals("Y")){
                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "存在其它堆垛机开启演示模式!");
                continue;
            }
            CrnSlave crnSlave = new CrnSlave(crn);
            if (Cools.isEmpty(crnProtocol.getLaneNo()) || crnProtocol.getLaneNo()==0){
                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机巷道号异常!");
                continue;
            }
            if (!crn.getId().equals(crnProtocol.getLaneNo())) {
                for (CrnSlave crnOther : slaveProperties.getCrn()) {
                    if (crnOther.getId().equals(crnProtocol.getLaneNo())) {
                        crnSlave.updateCrnInStn(crnOther);
                    }
                }
            }
            for (String locNo : crnProtocol.getLocMastDemoList()){
                LocMast locMast = locMastService.selectByLocNo(locNo);
                TaskCreateParam taskCreateParam = new TaskCreateParam(crnSlave,locMast);
                taskCreateParam.setStartPointSta(crnProtocol.getStaIntDemo());
                taskCreateParam.setTargetPointSta(crnProtocol.getStaOutDemo());
                openService.taskCreate(taskCreateParam);
            }
            return true;
        }
        return false;
    }
    /**
     * 入出库  ===>>  堆垛机入出库作业下发  演示
     */
    public synchronized void crnIoExecuteDemo() throws IOException {
        for (CrnSlave crnSlave : slaveProperties.getCrn()) {
            // 获取堆垛机信息
            CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crnSlave.getId());
            CrnProtocol crnProtocol = crnThread.getCrnProtocol();
            if (crnProtocol == null) {
                continue;
            }
            BasCrnp basCrnp = basCrnpService.selectById(crnSlave.getId());
            if (basCrnp == null) {
                log.error("{}号堆垛机尚未在数据库进行维护!", crnSlave.getId());
                continue;
            }
            CrnSlave crn = new CrnSlave(crnSlave);
            if (Cools.isEmpty(crnProtocol.getLaneNo()) || crnProtocol.getLaneNo()==0){
                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机巷道号异常!");
                continue;
            }
            if (!crnSlave.getId().equals(crnProtocol.getLaneNo())) {
                for (CrnSlave crnOther : slaveProperties.getCrn()) {
                    if (crnOther.getId().equals(crnProtocol.getLaneNo())) {
                        crn.updateCrnInStn(crnOther);
                    }
                }
            }
//            try{
//                // 库位移转
//                this.locToLoc(crn, crnProtocol);
//            } catch (Exception e) {
//                log.error("库位移转失败");
//            }
            // 只有当堆垛机空闲 并且 无任务时才继续执行
            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.crnStnToLocDemo(crn, crnProtocol); //  入库
                        crnProtocol.setLastIo("O");
                    } else if (basCrnp.getOutEnable().equals("Y")) {
                        this.locToCrnStnDemo(crn, crnProtocol); //  出库
                        crnProtocol.setLastIo("I");
                    }
                }
                // 如果最近一次是出库模式
                else if (crnProtocol.getLastIo().equals("O")) {
                    if (basCrnp.getOutEnable().equals("Y")) {
                        this.locToCrnStnDemo(crn, crnProtocol); //  出库
                        crnProtocol.setLastIo("I");
                    } else if (basCrnp.getInEnable().equals("Y")) {
                        this.crnStnToLocDemo(crn, crnProtocol); //  入库
                        crnProtocol.setLastIo("O");
                    }
                }
            }  else {
                if (crnProtocol.getModeType() == CrnModeType.AUTO && crnProtocol.getStatusType() == CrnStatusType.IDLE){
                    if (crnProtocol.getTaskNo() != 0){
                        CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "工作号不为0");
                    }
                    if (crnProtocol.getLoaded() != 0){
                        CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "载货台有物");
                    }
                    if (crnProtocol.getForkPos() != 0){
                        CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "货叉位置不在中位");
                    }
                }
            }
        }
    }
    /**
     * 入库  ===>>  堆垛机站到库位
     */
    public void crnStnToLocDemo(CrnSlave slave, CrnProtocol crnProtocol) {
        for (CrnSlave.CrnStn crnStn : slave.getCrnInStn()) {
            List<StaDesc> staDescs = staDescMapper.selectList(new EntityWrapper<StaDesc>().eq("CRN_NO", crnProtocol.getLaneNo()).eq("CRN_STN", crnStn.getStaNo()));
            for (StaDesc staDesc : staDescs) {
                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.getWorkNo() > 0
//                        && staProtocol.isInEnable()
                        && staDetl.getCanining() != null && staDetl.getCanining().equals("Y")) {
                    flag = true;
                }
                if (!flag) {
                    continue;
                }
                // 获取工作状态为2(设备上走)的入库工作档
                TaskWrk taskWrk = taskWrkMapper.selectPakInDemo(crnProtocol.getLaneNo(), staProtocol.getWorkNo().intValue(), staDesc.getStnNo().toString());
                if (null == taskWrk) {
                    continue;
                }
                // 堆垛机控制过滤
                if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE)) {
                    devpThread.setErrorDev(staProtocol.getSiteId(), "堆垛机非空闲");
                    continue;
                }
                if (crnProtocol.getTaskNo() != 0) {
                    devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机工作号不为0");
                    CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "工作号不为0");
                    continue;
                }
                // 已经存在吊车执行任务时,则过滤
                if (taskWrkMapper.selectCrnWorking(crnProtocol.getLaneNo()) != null) {
                    devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机存在吊车任务");
                    CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机存在执行中吊车任务");
                    continue;
                }
//                int workNo = commonService.getWorkNo(WorkNoType.PAKIN.type);//获取入库工作号
//                taskWrk.setWrkNo(workNo);//工作号
                Date now = new Date();
                taskWrk.setStatus(TaskStatusType.DISTRIBUTE.id);//派发状态
//                taskWrk.setAssignTime(now);//派发时间
                taskWrk.setExecuteTime(now);
                taskWrk.setWrkSts(3);//工作状态 3.吊车入库
                taskWrk.setCrnNo(staDesc.getCrnNo());//堆垛机号
                taskWrk.setModiTime(now);
                taskWrk.setModiUser(9988L);
                // 命令下发区 --------------------------------------------------------------------------
                CrnCommand crnCommand1 = new CrnCommand();
                crnCommand1.setCrnNo(slave.getId()); // 堆垛机编号
                crnCommand1.setLaneNo(crnProtocol.getLaneNo()); // 堆垛机巷道编号
                crnCommand1.setTaskNo(taskWrk.getWrkNo().shortValue()); // 工作号
                crnCommand1.setAckFinish((short) 0);  // 任务完成确认位
                crnCommand1.setTaskMode(CrnTaskModeType.LOC_MOVE); // 任务模式:  库位移转
                crnCommand1.setSourcePosX(crnStn.getRow().shortValue());     // 源库位排
                crnCommand1.setSourcePosY(crnStn.getBay().shortValue());     // 源库位列
                crnCommand1.setSourcePosZ(crnStn.getLev().shortValue());   // 源库位层
                crnCommand1.setDestinationPosX(Utils.getRowShort(taskWrk.getTargetPoint()));     // 目标库位列
                int bay1 = Utils.getBayShort(taskWrk.getTargetPoint()) + 1;
                crnCommand1.setDestinationPosY((short)bay1);     // 目标库位层
                crnCommand1.setDestinationPosZ(Utils.getLevShort(taskWrk.getTargetPoint()));     // 目标库位排
                crnCommand1.setCommand((short) 0);
                if (!MessageQueue.offer(SlaveType.Crn, slave.getId(), new Task(2, crnCommand1))) {
                    log.error("堆垛机命令生成失败,堆垛机号={},任务数据={}", taskWrk.getCrnNo(), JSON.toJSON(crnCommand1));
                    devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机命令生成失败");
                    CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "运行命令下发失败");
                    throw new CoolException("堆垛机命令生成失败");
                } else {
                    try {
                        devpThread.setErrorDev(staProtocol.getSiteId(), "-");
                        CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "-");
                        taskWrkService.updateById(taskWrk);
                    } catch (Exception e) {
                        log.error("修改工作档状态 2.设备上走 => 3.吊车入库中 失败!!,工作号={}", taskWrk.getWrkNo());
                        log.error("修改工作档状态 2.设备上走 => 3.吊车入库中 失败!!,异常:" + e);
                    }
                }
            }
            // return;
        }
    }
    /**
     * 出库  ===>>  库位到堆垛机站
     * 2022-06-09 TQS修改,查询工作档LIST,遍历下发,防止第一个任务堵塞出库
     */
    public void locToCrnStnDemo(CrnSlave slave, CrnProtocol crnProtocol) {
        List<TaskWrk> taskWrksInitial = taskWrkMapper.selectPakOut(crnProtocol.getLaneNo(), null);
        if (taskWrksInitial.size() == 0) {
            return;
        }
        for (CrnSlave.CrnStn crnStn : slave.getCrnOutStn()) {
            List<StaDesc> staDescs = staDescMapper.selectList(new EntityWrapper<StaDesc>().eq("CRN_NO", crnProtocol.getLaneNo()).eq("CRN_STN", crnStn.getStaNo()));
            for (StaDesc staDesc : staDescs) {
                // 获取工作状态为11(生成出库ID)的出库工作档
                List<TaskWrk> taskWrks = taskWrkMapper.selectPakOutDemo(crnProtocol.getLaneNo(), staDesc.getStnNo().toString());
                for (TaskWrk taskWrk : taskWrks) {
                    if (taskWrk == null) {
                        continue;
                    }
                    // 工作档状态判断
                    if (taskWrk.getIoType() != 4 || taskWrk.getTargetPoint() == null || taskWrk.getStartPoint() == null) {
                        log.error("查询工作档数据不符合条件--入出类型/站点, 工作号={},源库位={},入出类型={}", taskWrk.getWrkNo(), taskWrk.getStartPoint(), taskWrk.getIoType());
                        continue;
                    }
                    // 获取堆垛机出库站信息
                    SiemensDevpThread devpThread = (SiemensDevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
                    StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
                    if (staProtocol == null) {
                        break;
                    } else {
                        staProtocol = staProtocol.clone();
                    }
                    // 查询站点详细信息
                    BasDevp staDetl = basDevpService.selectById(crnStn.getStaNo());
                    if (staDetl == null) {
                        log.error("出库 ===>> 堆垛机站点在数据库不存在, 站点编号={}", crnStn.getStaNo());
                        break;
                    }
                    // 判断堆垛机出库站状态
                    if (staProtocol.isAutoing() && staDetl.getCanouting() != null && staDetl.getCanouting().equals("Y")) {
//                    // 判断堆垛机出库站状态
//                    if (staProtocol.isAutoing() && !staProtocol.isLoading() && staDetl.getCanouting() != null && staDetl.getCanouting().equals("Y")
//                            && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) {
                        // 命令下发区 --------------------------------------------------------------------------
                        // 堆垛机控制过滤
                        if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE)) {
                            devpThread.setErrorDev(staProtocol.getSiteId(), "堆垛机非空闲");
                            continue;
                        }
                        if (crnProtocol.getTaskNo() != 0) {
                            devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机工作号不为0");
                            CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "工作号不为0");
                            continue;
                        }
                        // 已经存在吊车执行任务时,则过滤
                        if (taskWrkMapper.selectCrnWorking(crnProtocol.getLaneNo()) != null) {
                            devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机存在吊车任务");
                            CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机存在执行中吊车任务");
                            break;
                        }
                        CrnCommand command = new CrnCommand();
                        command.setCrnNo(slave.getId()); // 堆垛机编号
                        command.setLaneNo(crnProtocol.getLaneNo()); // 堆垛机编号
                        command.setTaskNo(taskWrk.getWrkNo().shortValue()); // 工作号
                        command.setAckFinish((short) 0);  // 任务完成确认位
                        command.setTaskMode(CrnTaskModeType.PAKIN); // 任务模式
                        command.setSourcePosX(Utils.getRowShort(taskWrk.getStartPoint()));     // 源库位排
                        int bayS = Utils.getBayShort(taskWrk.getStartPoint()) + 1;
                        command.setSourcePosY((short)bayS);     // 源库位列
                        command.setSourcePosZ(Utils.getLevShort(taskWrk.getStartPoint()));     // 源库位层
                        command.setDestinationPosX(crnStn.getRow().shortValue());     // 目标库位排
                        command.setDestinationPosY(crnStn.getBay().shortValue());     // 目标库位列
                        command.setDestinationPosZ(crnStn.getLev().shortValue());     // 目标库位层
//                        command.setCommand((short) 1);
                        if (!MessageQueue.offer(SlaveType.Crn, slave.getId(), new Task(2, command))) {
                            log.error("堆垛机命令生成失败,堆垛机号={},巷道={},任务数据={}", slave.getId(), taskWrk.getCrnNo(), JSON.toJSON(command));
                            devpThread.setErrorDev(staProtocol.getSiteId(), crnProtocol.getLaneNo()+"巷道堆垛机命令生成失败");
                            CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "运行命令下发失败");
                            throw new CoolException("堆垛机命令生成失败");
                        } else {
                            try {
                                // 修改工作档状态 11.生成出库ID => 12.吊车出库中
                                Date now = new Date();
                                taskWrk.setWrkSts(12);
                                taskWrk.setStatus(TaskStatusType.DISTRIBUTE.id);
                                taskWrk.setModiTime(now);
                                taskWrk.setExecuteTime(now);
                                devpThread.setErrorDev(staProtocol.getSiteId(), "-");
                                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "-");
                                if (taskWrkMapper.updateById(taskWrk) == 0) {
                                    log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", taskWrk.getWrkNo());
                                }
                            } catch (Exception e) {
                                log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,工作号={}", taskWrk.getWrkNo());
                                log.error("修改工作档状态 11.生成出库ID => 12.吊车出库中 失败!!,异常:" + e);
                            }
                        }
                    } else {
                        CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "-");
                        if (staProtocol.isAutoing()){
                            if (staDetl.getCanouting() != null && staDetl.getCanouting().equals("Y")){
                                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "能出:未打开");
                            }
                            if (staProtocol.getWorkNo() == 0){
                                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "工作号不为0");
                            }
                            if (staProtocol.isOutEnable()){
                                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "没有可出");
                            }
                            if (staProtocol.isLoading()){
                                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "出库站有物");
                            }
                        } else {
                            CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "出库站点:非自动");
                        }
                    }
                }
            }
        }
    }
    /**
     * 堆垛机站出库到出库站
     */
    public void crnStnToOutStnDemo() {
        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;
            }
            CrnSlave crnSlave = new CrnSlave(crn);
            if (Cools.isEmpty(crnProtocol.getLaneNo()) || crnProtocol.getLaneNo()==0){
                CrnErrCache.updateCrnErr(crnProtocol.getCrnNo(), "堆垛机巷道号异常!");
                continue;
            }
            if (!crn.getId().equals(crnProtocol.getLaneNo())) {
                for (CrnSlave crnOther : slaveProperties.getCrn()) {
                    if (crnOther.getId().equals(crnProtocol.getLaneNo())) {
                        crnSlave.updateCrnInStn(crnOther);
                    }
                }
            }
            // 遍历堆垛机出库站
            for (CrnSlave.CrnStn crnStn : crnSlave.getCrnOutStn()) {
                List<StaDesc> staDescs = staDescMapper.selectList(new EntityWrapper<StaDesc>().eq("CRN_NO", crnProtocol.getLaneNo()).eq("CRN_STN", crnStn.getStaNo()));
                for (StaDesc staDesc : staDescs) {
                    try {
                        // 获取堆垛机出库站信息
                        DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId());
                        StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo());
                        if (staProtocol == null) {
                            continue;
                        } else {
                            staProtocol = staProtocol.clone();
                        }
                        if (staProtocol.isAutoing() && staProtocol.isLoading() && (staProtocol.getWorkNo() == 0 || staProtocol.getStaNo() == 0)) {
                            // 查询工作档
                            TaskWrk taskWrk = taskWrkMapper.selectCrnStaWorkingDemo(crnProtocol.getLaneNo(), staDesc.getStnNo().toString());
                            if (taskWrk == null) {
                                continue;
                            }
                            log.info("下发输送线任务:taskWrk:" + JSON.toJSONString(taskWrk));
//                            R r = siteController.siteDetlUpdate(Integer.valueOf(taskWrk.getTargetPoint()), taskWrk.getWrkNo().shortValue(), (short) 0, "Y", false, false);
                            staProtocol.setWorkNo(taskWrk.getWrkNo());
                            staProtocol.setStaNo(BarcodeUtils.getStaNo(staProtocol.getSiteId()));
                            boolean offer = false;
                            try {
                                offer = MessageQueue.offer(SlaveType.Devp, 1, new Task(2, staProtocol));
                            } catch (Exception e) {
                                log.error("下发输送线任务失败:异常:" + e);
                                log.error("下发输送线任务失败:异常:offer:" + offer);
                            }
//                            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(r));
                            if (offer) {
                                log.info("下发输送线任务成功:taskWrk:" + JSON.toJSONString(taskWrk));
                                Date now = new Date();
//                                taskWrk.setStatus(TaskStatusType.OVER3.id);
                                taskWrk.setWrkSts(2);
                                taskWrk.setModiTime(now);
                                taskWrk.setCompleteTime(now);
                                taskWrkService.updateById(taskWrk);
                            } else {
                                log.error("下发输送线任务失败:taskWrk:" + JSON.toJSONString(taskWrk));
//                                log.error("下发输送线任务失败:异常信息:"+JSON.toJSONString(r));
                            }
                        }
                    } catch (Exception e) {
                        log.error("出库到出库站异常:异常信息:" + e);
                    }
                }
            }
        }
    }
    public synchronized void taskStartDemo() {
        for (RgvSlave rgvSlave : slaveProperties.getRgv()) {
            try {
                if (rgvDetection(rgvSlave)) {
                    String taskNoNow = rgvOtherTaskWrk(rgvSlave);
                    List<BasDevpPosition> basDevpPositions = basDevpPositionService.selectList(new EntityWrapper<BasDevpPosition>().orderBy("PLC_POSITION", true));
                    boolean itSmall = new TrackRangeUtils().IsItSmall(rgvSlave);
                    if (basDevpPositions.isEmpty()) {
                        log.error("获取所有站点信息异常");
                        try{
                            DeviceErrorService deviceErrorService = SpringUtils.getBean(DeviceErrorService.class);
                            deviceErrorService.addDeviceError("rgvErr", rgvSlave.getId(), "指令生成:获取所有站点信息异常");
                        } catch (Exception e2){
                        }
                        continue;
                    }
                    List<TaskWrk> taskWrkList = new ArrayList<>();
                    List<Integer> staList = new ArrayList<>();
                    for (RgvSlave.RgvStn inSta : rgvSlave.getRgvInSta()) {
                        TaskWrk taskWrk = deviceDetection(inSta);
                        if (taskWrk != null) {
                            if (taskWrk.getWrkNo().toString().equals(taskNoNow)) continue;
                            taskWrkList.add(taskWrk);
                            staList.add(inSta.getStaNo());
                        }
                    }
                    if (taskWrkList.isEmpty() || staList.isEmpty()) continue;
                    boolean sign = false;
                    if (!sign){
                        //可用区域就近取货
                        //就近排序
                        RgvProtocol rgvProtocol = RgvStatusCache.getRgvStatus(rgvSlave.getId());
                        List<Integer> rangeList = RouteUtils.SortNearby(staList, rgvProtocol.RgvPos, basDevpPositions);
                        //  半边区域内取货任务
                        for (Integer staNoNow : rangeList) {
                            for (RgvSlave.RgvStn rgvStn : rgvSlave.getRgvInSta()) {
                                if (rgvStn.getStaNo().equals(staNoNow)) {
                                    TaskWrk taskWrk = deviceDetection(rgvStn);
                                    if (taskWrk != null) {
                                        Integer outStaNo = BarcodeUtils.getOutStaNo(taskWrk.getOriginTargetPoint());
                                        for (RgvSlave.RgvStn rgvStnOut : rgvSlave.getRgvOutSta()) {
                                            if (rgvStnOut.getStaNo().equals(outStaNo)) {
                                                sign = taskGenerate(rgvSlave, rgvStn, 0);
                                                break;
                                            }
                                        }
                                    }
                                    break;
                                }
                            }
                            if (sign) {
                                break;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("任务生成失败===》异常信息:{}", e.getMessage());
                try{
                    DeviceErrorService deviceErrorService = SpringUtils.getBean(DeviceErrorService.class);
                    deviceErrorService.addDeviceError("rgvErr", rgvSlave.getId(), "指令生成失败");
                } catch (Exception e2){
                }
            }
        }
    }
}