#
Junjie
2026-01-05 f375928943ad4b9fe6d8508e151971dcdc23e982
#
2个文件已添加
20个文件已修改
2287 ■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/DualCrnController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OpenController.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/domain/param/GetAllLocInformationParam.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/domain/vo/DualCrnStateTableVo.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/utils/Utils.java 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/RedisKeyType.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/DualCrnCommand.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/network/entity/ZyDualCrnStatusEntity.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/network/fake/ZyDualCrnFakeConnect.java 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/network/real/ZyDualCrnRealConnect.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/plugin/FakeProcess.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZyRgvThread.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZySiemensCrnThread.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZySiemensDualCrnThread.java 385 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/ZyStationThread.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/utils/CrnOperateProcessUtils.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/utils/DualCrnOperateProcessUtils.java 591 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/utils/StationOperateProcessUtils.java 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/docs/WCS外部HTTP API接口V1.2.docx 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/components/WatchDualCrnCard.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/locMap/locMap.html 451 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/DualCrnController.java
@@ -56,15 +56,11 @@
            vo.setLoading(p.getLoaded() != null && p.getLoaded() == 1 ? "有物" : "无物");
            vo.setLoadingTwo(p.getLoadedTwo() != null && p.getLoadedTwo() == 1 ? "有物" : "无物");
            vo.setBay(p.getBay());
            vo.setBayTwo(p.getBayTwo());
            vo.setLev(p.getLevel());
            vo.setLevTwo(p.getLevelTwo());
            vo.setForkOffset(p.getForkPosType() == null ? "-" : p.getForkPosType().desc);
            vo.setForkOffsetTwo(p.getForkPosTypeTwo() == null ? "-" : p.getForkPosTypeTwo().desc);
            vo.setLiftPos(p.getLiftPosType() == null ? "-" : p.getLiftPosType().desc);
            vo.setLiftPosTwo(p.getLiftPosTypeTwo() == null ? "-" : p.getLiftPosTypeTwo().desc);
            vo.setWalkPos(p.getWalkPos() != null && p.getWalkPos() == 0 ? "在定位" : "不在定位");
            vo.setWalkPosTwo(p.getWalkPosTwo() != null && p.getWalkPosTwo() == 0 ? "在定位" : "不在定位");
            vo.setTaskReceive(p.getTaskReceive() != null && p.getTaskReceive() == 1 ? "接收" : "无任务");
            vo.setTaskReceiveTwo(p.getTaskReceiveTwo() != null && p.getTaskReceiveTwo() == 1 ? "接收" : "无任务");
            vo.setXspeed(p.getXSpeed());
@@ -159,7 +155,7 @@
        }
        DualCrnCommand command = crnThread.getMoveCommand(targetLocNo, 9999, crnNo);
        if (station != null) {
            command.setStation(station.shortValue());
            command.setStation(station);
        }
        MessageQueue.offer(SlaveType.DualCrn, crnNo, new Task(3, command));
        return R.ok();
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -1,6 +1,7 @@
package com.zy.asrs.controller;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.core.common.R;
import com.zy.asrs.domain.param.*;
import com.zy.asrs.entity.DeviceConfig;
@@ -179,18 +180,31 @@
    @PostMapping("/getAllLocInformation")
    @OpenApiLog(memo = "获取全部库位信息")
    public R getAllLocInformation() {
        List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>());
        if (locMasts.isEmpty()) {
            return R.error("库位信息不存在");
    public R getAllLocInformation(@RequestBody GetAllLocInformationParam param) {
        List<HashMap<String, Object>> list = new ArrayList<>();
        EntityWrapper<LocMast> wrapper = new EntityWrapper<>();
        if (!Cools.isEmpty(param.getRow())) {
            wrapper.eq("row1", param.getRow());
        }
        ArrayList<HashMap<String, Object>> list = new ArrayList<>();
        if (!Cools.isEmpty(param.getLev())) {
            wrapper.eq("lev1", param.getLev());
        }
        List<LocMast> locMasts = locMastService.selectList(wrapper);
        if (locMasts.isEmpty()) {
            return R.ok().add(list);
        }
        for (LocMast locMast : locMasts) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("locNo", locMast.getLocNo());
            map.put("locSts", locMast.getLocSts());
            map.put("barcode", locMast.getBarcode());
            map.put("row", locMast.getRow1());
            map.put("bay", locMast.getBay1());
            map.put("lev", locMast.getLev1());
            list.add(map);
        }
@@ -224,7 +238,7 @@
    @GetMapping("/getFakeSystemRunStatus")
    public R getFakeSystemRunStatus() {
        HashMap<String, Object> map = new HashMap<>();
        if(mainProcessPlugin.equals("FakeProcess")) {
        if(mainProcessPlugin.contains("Fake")) {
            map.put("running", false);
            map.put("isFake", true);
            Config config = configService.selectOne(new EntityWrapper<Config>().eq("code", "enableFake"));
src/main/java/com/zy/asrs/domain/param/GetAllLocInformationParam.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.domain.param;
import lombok.Data;
@Data
public class GetAllLocInformationParam {
    private Integer row;
    private Integer lev;
}
src/main/java/com/zy/asrs/domain/vo/DualCrnStateTableVo.java
@@ -23,30 +23,22 @@
    private String loadingTwo = "-";
    private Integer bay;
    private Integer bayTwo;
    private Integer lev;
    private Integer levTwo;
    private String forkOffset = "-";
    private String forkOffsetTwo = "-";
    private String liftPos = "-";
    private String liftPosTwo = "-";
    private String walkPos = "-";
    private String walkPosTwo = "-";
    private String taskReceive = "-";
    private String taskReceiveTwo = "-";
    private Integer bay;
    private Integer lev;
    private String liftPos = "-";
    private String walkPos = "-";
    private Integer xspeed = 0;
    private Integer yspeed = 0;
src/main/java/com/zy/asrs/utils/Utils.java
@@ -198,13 +198,24 @@
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<>());
            List<BasCrnp> basCrnps = basCrnpService.selectList(wrapper);
            List<BasCrnp> baseList = new ArrayList<>();
            List<BasCrnp> extraList = new ArrayList<>();
            for (BasCrnp basCrnp : basCrnps) {
                if (excludeCrnList.contains(basCrnp.getCrnNo())) {
                    extraList.add(basCrnp);
                }else {
                    baseList.add(basCrnp);
                }
            }
            baseList.addAll(extraList);
            for (WrkMast wrkMast : wrkMasts) {
                Integer crnNo = wrkMast.getCrnNo();
                map.put(crnNo, map.getOrDefault(crnNo, 0) + 1);
            }
            List<BasCrnp> enabledCrnps = new ArrayList<>();
            for (BasCrnp basCrnp : basCrnps) {
            for (BasCrnp basCrnp : baseList) {
                CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, basCrnp.getCrnNo());
                if (crnThread == null) {
                    continue;
@@ -221,9 +232,6 @@
                // æ£€æŸ¥æ˜¯å¦è¶…过最大入库任务数
                if (maxInTaskControl && inWrkMasts.size() >= basCrnp.getMaxInTask()) {
                    News.info("堆垛机:{} å·²è¾¾æœ€å¤§å…¥åº“任务数,当前任务数:{}", basCrnp.getCrnNo(), inWrkMasts.size());
                    continue;
                }
                if (excludeCrnList.contains(basCrnp.getCrnNo())) {
                    continue;
                }
@@ -278,13 +286,24 @@
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<>());
            List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(wrapper);
            List<BasDualCrnp> baseList = new ArrayList<>();
            List<BasDualCrnp> extraList = new ArrayList<>();
            for (BasDualCrnp basDualCrnp : basDualCrnps) {
                if (excludeCrnList.contains(basDualCrnp.getCrnNo())) {
                    extraList.add(basDualCrnp);
                }else {
                    baseList.add(basDualCrnp);
                }
            }
            baseList.addAll(extraList);
            for (WrkMast wrkMast : wrkMasts) {
                Integer dualCrnNo = wrkMast.getDualCrnNo();
                map.put(dualCrnNo, map.getOrDefault(dualCrnNo, 0) + 1);
            }
            List<BasDualCrnp> enabledCrnps = new ArrayList<>();
            for (BasDualCrnp basDualCrnp : basDualCrnps) {
            for (BasDualCrnp basDualCrnp : baseList) {
                DualCrnThread dualCrnThread = (DualCrnThread) SlaveConnection.get(SlaveType.DualCrn, basDualCrnp.getCrnNo());
                if (dualCrnThread == null) {
                    continue;
@@ -300,10 +319,7 @@
                );
                // æ£€æŸ¥æ˜¯å¦è¶…过最大入库任务数
                if (maxInTaskControl && inWrkMasts.size() >= basDualCrnp.getMaxInTask()) {
                    News.info("堆垛机:{} å·²è¾¾æœ€å¤§å…¥åº“任务数,当前任务数:{}", basDualCrnp.getCrnNo(), inWrkMasts.size());
                    continue;
                }
                if (excludeCrnList.contains(basDualCrnp.getCrnNo())) {
                    News.info("双工位堆垛机:{} å·²è¾¾æœ€å¤§å…¥åº“任务数,当前任务数:{}", basDualCrnp.getCrnNo(), inWrkMasts.size());
                    continue;
                }
@@ -364,9 +380,23 @@
            return rowList;
        }
        BasDualCrnpService basDualCrnpService = SpringUtils.getBean(BasDualCrnpService.class);
        if (basDualCrnpService == null) {
            return rowList;
        }
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<BasCrnp>());
        for (BasCrnp basCrnp : basCrnps) {
            String deepRowsStr = basCrnp.getDeepRows();
            if(!Cools.isEmpty(deepRowsStr)){
                List<Integer> rows = JSON.parseArray(deepRowsStr, Integer.class);
                rowList.addAll(rows);
            }
        }
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<BasDualCrnp>());
        for (BasDualCrnp basDualCrnp : basDualCrnps) {
            String deepRowsStr = basDualCrnp.getDeepRows();
            if(!Cools.isEmpty(deepRowsStr)){
                List<Integer> rows = JSON.parseArray(deepRowsStr, Integer.class);
                rowList.addAll(rows);
@@ -377,6 +407,22 @@
    //获取浅库位排号
    public static Integer getShallowRowByDeepRow(Integer deepRow) {
        SlaveType slaveType = checkRowDeviceType(deepRow);
        if (slaveType == null) {
            return null;
        }
        if (slaveType.equals(SlaveType.Crn)) {
            return getShallowRowByCrnDeepRow(deepRow);
        } else if (slaveType.equals(SlaveType.DualCrn)) {
            return getShallowRowByDualCrnDeepRow(deepRow);
        }
        return null;
    }
    //获取堆垛机浅库位排号
    public static Integer getShallowRowByCrnDeepRow(Integer deepRow) {
        BasCrnpService basCrnpService = SpringUtils.getBean(BasCrnpService.class);
        if (basCrnpService == null) {
            return null;
@@ -403,6 +449,52 @@
            }
        }
        if (controlRowList == null) {
            return null;
        }
        for (Integer row : controlRowList) {
            if (deepRow.equals(row)) {
                continue;
            }
            return row;
        }
        return null;
    }
    //获取双工位堆垛机浅库位排号
    public static Integer getShallowRowByDualCrnDeepRow(Integer deepRow) {
        BasDualCrnpService basDualCrnpService = SpringUtils.getBean(BasDualCrnpService.class);
        if (basDualCrnpService == null) {
            return null;
        }
        List<Integer> deepRowList = getDeepRowList();
        if (!deepRowList.contains(deepRow)) {
            return null;
        }
        List<Integer> controlRowList = null;
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (BasDualCrnp basDualCrnp : basDualCrnps) {
            List<List<Integer>> rowList = basDualCrnp.getControlRows$();
            for (List<Integer> rows : rowList) {
                if (rows.contains(deepRow)) {
                    controlRowList = rows;
                    break;
                }
            }
            if (controlRowList != null) {
                break;
            }
        }
        if (controlRowList == null) {
            return null;
        }
        for (Integer row : controlRowList) {
            if (deepRow.equals(row)) {
                continue;
@@ -415,6 +507,19 @@
    //获取深库位排号
    public static Integer getDeepRowByShallowRow(Integer shallowRow) {
        SlaveType slaveType = checkRowDeviceType(shallowRow);
        if (slaveType.equals(SlaveType.Crn)) {
            return getDeepRowByCrnShallowRow(shallowRow);
        } else if (slaveType.equals(SlaveType.DualCrn)) {
            return getDeepRowByDualCrnShallowRow(shallowRow);
        }
        return null;
    }
    //获取堆垛机深库位排号
    public static Integer getDeepRowByCrnShallowRow(Integer shallowRow) {
        BasCrnpService basCrnpService = SpringUtils.getBean(BasCrnpService.class);
        if (basCrnpService == null) {
            return null;
@@ -451,4 +556,78 @@
        }
        return null;
    }
    //获取双工位堆垛机深库位排号
    public static Integer getDeepRowByDualCrnShallowRow(Integer shallowRow) {
        BasDualCrnpService basDualCrnpService = SpringUtils.getBean(BasDualCrnpService.class);
        if (basDualCrnpService == null) {
            return null;
        }
        List<Integer> controlRowList = null;
        List<Integer> deepRowList = null;
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (BasDualCrnp basDualCrnp : basDualCrnps) {
            List<List<Integer>> rowList = basDualCrnp.getControlRows$();
            for (List<Integer> rows : rowList) {
                if (rows.contains(shallowRow)) {
                    controlRowList = rows;
                    deepRowList = JSON.parseArray(basDualCrnp.getDeepRows(), Integer.class);
                    break;
                }
            }
            if (controlRowList != null) {
                break;
            }
        }
        if (deepRowList == null) {
            return null;
        }
        for (Integer row : controlRowList) {
            if (!deepRowList.contains(row)) {
                continue;
            }
            return row;
        }
        return null;
    }
    //检测排号设备类型
    public static SlaveType checkRowDeviceType(Integer row) {
        BasCrnpService basCrnpService = SpringUtils.getBean(BasCrnpService.class);
        if (basCrnpService == null) {
            return null;
        }
        BasDualCrnpService basDualCrnpService = SpringUtils.getBean(BasDualCrnpService.class);
        if (basDualCrnpService == null) {
            return null;
        }
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<>());
        for (BasCrnp basCrnp : basCrnps) {
            List<List<Integer>> controlRows = basCrnp.getControlRows$();
            for (List<Integer> list : controlRows) {
                if (list.contains(row)) {
                    return SlaveType.Crn;
                }
            }
        }
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (BasDualCrnp basDualCrnp : basDualCrnps) {
            List<List<Integer>> controlRows = basDualCrnp.getControlRows$();
            for (List<Integer> list : controlRows) {
                if (list.contains(row)) {
                    return SlaveType.DualCrn;
                }
            }
        }
        return null;
    }
}
src/main/java/com/zy/common/service/CommonService.java
@@ -1,7 +1,5 @@
package com.zy.common.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.core.exception.CoolException;
@@ -156,7 +154,6 @@
        if (!sourceCrnResult.getCrnNo().equals(targetCrnResult.getCrnNo())) {
            throw new CoolException("源库位和目标库位不在同一巷道");
        }
        Integer crnNo = targetCrnResult.getCrnNo();
        // èŽ·å–å·¥ä½œå·
        int workNo = getWorkNo(WrkIoType.LOC_MOVE.id);
@@ -169,11 +166,19 @@
        wrkMast.setIoPri(ioPri);
        wrkMast.setSourceLocNo(param.getSourceLocNo());
        wrkMast.setLocNo(param.getLocNo()); // ç›®æ ‡åº“位
        wrkMast.setCrnNo(crnNo);
        wrkMast.setWmsWrkNo(param.getTaskNo());
        wrkMast.setBarcode(sourceLocMast.getBarcode());
        wrkMast.setAppeTime(now);
        wrkMast.setModiTime(now);
        if (targetCrnResult.getCrnType().equals(SlaveType.Crn)) {
            wrkMast.setCrnNo(targetCrnResult.getCrnNo());
        } else if (targetCrnResult.getCrnType().equals(SlaveType.DualCrn)) {
            wrkMast.setDualCrnNo(targetCrnResult.getCrnNo());
        }else {
            throw new CoolException("未知设备类型");
        }
        boolean res = wrkMastService.insert(wrkMast);
        if (!res) {
            News.error("移库任务 --- ä¿å­˜å·¥ä½œæ¡£å¤±è´¥ï¼");
src/main/java/com/zy/core/enums/RedisKeyType.java
@@ -36,10 +36,12 @@
    DUAL_CRN_IO_EXECUTE_FINISH_LIMIT("dual_crn_io_execute_finish_limit_"),
    STATION_IN_EXECUTE_LIMIT("station_in_execute_limit_"),
    STATION_OUT_EXECUTE_LIMIT("station_out_execute_limit_"),
    STATION_OUT_EXECUTE_COMPLETE_LIMIT("station_out_execute_complete_limit_"),
    CHECK_STATION_RUN_BLOCK_LIMIT_("check_station_run_block_limit_"),
    CHECK_SHALLOW_LOC_STATUS_LIMIT("check_shallow_loc_status_limit_"),
    DUAL_CRN_PICK_WAIT_NEXT_TASK("dual_crn_pick_wait_next_task_"),
    DUAL_CRN_OUT_TASK_STATION_INFO("dual_crn_out_task_station_info_"),
    CURRENT_CIRCLE_TASK_CRN_NO("current_circle_task_crn_no_"),
    AI_CHAT_HISTORY("ai_chat_history_"),
src/main/java/com/zy/core/model/command/DualCrnCommand.java
@@ -12,35 +12,35 @@
    private Integer crnNo = 0;
    // ä»»åŠ¡å·
    private Short taskNo = 0;
    private Integer taskNo = 0;
    /**
     * ä»»åŠ¡æ¨¡å¼ï¼š
     */
    private Short taskMode = 0;
    private Integer taskMode = 0;
    // æºä½ç½®æŽ’号
    private Short sourcePosX = 0;
    private Integer sourcePosX = 0;
    // æºä½ç½®åˆ—号
    private Short sourcePosY = 0;
    private Integer sourcePosY = 0;
    // æºä½ç½®å±‚号
    private Short sourcePosZ = 0;
    private Integer sourcePosZ = 0;
    // ç›®æ ‡ä½ç½®æŽ’号
    private Short destinationPosX = 0;
    private Integer destinationPosX = 0;
    // ç›®æ ‡ä½ç½®åˆ—号
    private Short destinationPosY = 0;
    private Integer destinationPosY = 0;
    // ç›®æ ‡ä½ç½®å±‚号
    private Short destinationPosZ = 0;
    private Integer destinationPosZ = 0;
    // ä»»åŠ¡ç¡®è®¤ 0:未确认 1:已确认
    private Short command = 0;
    private Integer command = 0;
    //工位
    private Short station;
    private Integer station;
}
src/main/java/com/zy/core/network/entity/ZyDualCrnStatusEntity.java
@@ -47,20 +47,6 @@
    public Integer statusTwo;
    /**
     * å †åž›æœºå½“前列号
     */
    public Integer bay;
    public Integer bayTwo;
    /**
     * å †åž›æœºå½“前层号
     */
    public Integer level;
    public Integer levelTwo;
    /**
     * å½“前货叉位置
     * 0 = è´§å‰åŽŸä½
     * 1 = è´§å‰åœ¨å·¦ä¾§
@@ -69,24 +55,6 @@
    public Integer forkPos;
    public Integer forkPosTwo;
    /**
     * å½“前载货台位置
     * 0 = ä¸‹å®šä½
     * 1 = ä¸Šå®šä½
     */
    public Integer liftPos;
    public Integer liftPosTwo;
    /**
     * èµ°è¡Œåœ¨å®šä½
     * 0 = åœ¨å®šä½
     * 1 = ä¸åœ¨å®šä½
     */
    public Integer walkPos;
    public Integer walkPosTwo;
    /**
     * è½½è´§å°æœ‰ç‰©
@@ -105,6 +73,30 @@
    public Integer taskReceiveTwo;
    /**
     * å †åž›æœºå½“前列号
     */
    public Integer bay;
    /**
     * å †åž›æœºå½“前层号
     */
    public Integer level;
    /**
     * å½“前载货台位置
     * 0 = ä¸‹å®šä½
     * 1 = ä¸Šå®šä½
     */
    public Integer liftPos;
    /**
     * èµ°è¡Œåœ¨å®šä½
     * 0 = åœ¨å®šä½
     * 1 = ä¸åœ¨å®šä½
     */
    public Integer walkPos;
    /**
     * X行走线速度m/min
     */
    private Integer xSpeed;
src/main/java/com/zy/core/network/fake/ZyDualCrnFakeConnect.java
@@ -16,7 +16,10 @@
    private ZyDualCrnStatusEntity crnStatus;
    private DeviceConfig deviceConfig;
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    // å…è®¸å¹¶è¡Œæ‰§è¡Œå¤šä¸ªå‘½ä»¤ä»»åŠ¡ï¼ˆå›ºå®šçº¿ç¨‹æ± ï¼‰ã€‚å¦‚éœ€æ›´é«˜å¹¶å‘å¯è°ƒæ•´å¤§å°ã€‚
    private final ExecutorService executor = Executors
            .newFixedThreadPool(9999);
    private int taskExecuteStation = 0;
    public ZyDualCrnFakeConnect(DeviceConfig deviceConfig) {
        this.deviceConfig = deviceConfig;
@@ -79,46 +82,71 @@
    }
    private void commandMove(DualCrnCommand command) {
        int destinationPosX = command.getDestinationPosX().intValue();
        int destinationPosY = command.getDestinationPosY().intValue();
        int destinationPosZ = command.getDestinationPosZ().intValue();
        int taskMode = command.getTaskMode().intValue();
        int taskNo = command.getTaskNo().intValue();
        int destinationPosX = command.getDestinationPosX();
        int destinationPosY = command.getDestinationPosY();
        int destinationPosZ = command.getDestinationPosZ();
        int taskMode = command.getTaskMode();
        int taskNo = command.getTaskNo();
        int station = command.getStation();
        while (true) {
            if (taskExecuteStation == 0) {
                taskExecuteStation = station;
            }
            if (taskExecuteStation == station) {
                break;
            }
            sleep(200);
        }
        if(command.getStation() == 1) {
            this.crnStatus.setTaskNo(taskNo);
            this.crnStatus.setStatus(CrnStatusType.MOVING.id);
            this.crnStatus.setTaskReceive(1);
            moveY(this.crnStatus.getBay(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevel(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY, this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatus(CrnStatusType.WAITING.id);
        }else {
            this.crnStatus.setTaskNoTwo(taskNo);
            this.crnStatus.setStatusTwo(CrnStatusType.MOVING.id);
            this.crnStatus.setTaskReceive(1);
            moveY(this.crnStatus.getBayTwo(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevelTwo(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY, this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatusTwo(CrnStatusType.WAITING.id);
        }
        taskExecuteStation = 0;
    }
    private void commandTake(DualCrnCommand command) {
        int sourcePosX = command.getSourcePosX().intValue();
        int sourcePosY = command.getSourcePosY().intValue();
        int sourcePosZ = command.getSourcePosZ().intValue();
        int destinationPosX = command.getDestinationPosX().intValue();
        int destinationPosY = command.getDestinationPosY().intValue();
        int destinationPosZ = command.getDestinationPosZ().intValue();
        int taskMode = command.getTaskMode().intValue();
        int taskNo = command.getTaskNo().intValue();
        int sourcePosX = command.getSourcePosX();
        int sourcePosY = command.getSourcePosY();
        int sourcePosZ = command.getSourcePosZ();
        int destinationPosX = command.getDestinationPosX();
        int destinationPosY = command.getDestinationPosY();
        int destinationPosZ = command.getDestinationPosZ();
        int taskMode = command.getTaskMode();
        int taskNo = command.getTaskNo();
        int station = command.getStation();
        while (true) {
            if (taskExecuteStation == 0) {
                taskExecuteStation = station;
            }
            if (taskExecuteStation == station) {
                break;
            }
            sleep(200);
        }
        if(command.getStation() == 1) {
            this.crnStatus.setTaskNo(taskNo);
            this.crnStatus.setStatus(CrnStatusType.FETCH_MOVING.id);
            this.crnStatus.setTaskReceive(1);
            moveY(this.crnStatus.getBay(), sourcePosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevel(), sourcePosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), sourcePosY,this.crnStatus.getLevel(), sourcePosZ,command.getStation());
            this.crnStatus.setStatus(CrnStatusType.FETCHING.id);
            sleep(2000);
            if (Thread.currentThread().isInterrupted()) {
@@ -127,8 +155,7 @@
            this.crnStatus.setLoaded(1);
            this.crnStatus.setStatus(CrnStatusType.PUT_MOVING.id);
            moveY(this.crnStatus.getBay(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevel(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY,this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatus(CrnStatusType.PUTTING.id);
            sleep(2000);
            if (Thread.currentThread().isInterrupted()) {
@@ -141,8 +168,7 @@
            this.crnStatus.setStatusTwo(CrnStatusType.FETCH_MOVING.id);
            this.crnStatus.setTaskReceiveTwo(1);
            moveY(this.crnStatus.getBayTwo(), sourcePosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevelTwo(), sourcePosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), sourcePosY,this.crnStatus.getLevel(), sourcePosZ, command.getStation());
            this.crnStatus.setStatusTwo(CrnStatusType.FETCHING.id);
            sleep(2000);
            if (Thread.currentThread().isInterrupted()) {
@@ -151,8 +177,7 @@
            this.crnStatus.setLoadedTwo(1);
            this.crnStatus.setStatusTwo(CrnStatusType.PUT_MOVING.id);
            moveY(this.crnStatus.getBayTwo(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevelTwo(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY,this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatusTwo(CrnStatusType.PUTTING.id);
            sleep(2000);
            if (Thread.currentThread().isInterrupted()) {
@@ -161,24 +186,38 @@
            this.crnStatus.setLoadedTwo(0);
            this.crnStatus.setStatusTwo(CrnStatusType.WAITING.id);
        }
        taskExecuteStation = 0;
    }
    private void commandPick(DualCrnCommand command) {
        int destinationPosX = command.getDestinationPosX().intValue();
        int destinationPosY = command.getDestinationPosY().intValue();
        int destinationPosZ = command.getDestinationPosZ().intValue();
        int taskMode = command.getTaskMode().intValue();
        int taskNo = command.getTaskNo().intValue();
        int destinationPosX = command.getDestinationPosX();
        int destinationPosY = command.getDestinationPosY();
        int destinationPosZ = command.getDestinationPosZ();
        int taskMode = command.getTaskMode();
        int taskNo = command.getTaskNo();
        int station = command.getStation();
        while (true) {
            if (taskExecuteStation == 0) {
                taskExecuteStation = station;
            }
            if (taskExecuteStation == station) {
                break;
            }
            sleep(200);
        }
        if(command.getStation() == 1) {
            this.crnStatus.setTaskNo(taskNo);
            this.crnStatus.setStatus(CrnStatusType.FETCH_MOVING.id);
            this.crnStatus.setTaskReceive(1);
            moveY(this.crnStatus.getBay(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevel(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY,this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatus(CrnStatusType.FETCHING.id);
            sleep(2000);
            sleep(3000);
            if (Thread.currentThread().isInterrupted()) {
                return;
            }
@@ -189,34 +228,47 @@
            this.crnStatus.setStatusTwo(CrnStatusType.FETCH_MOVING.id);
            this.crnStatus.setTaskReceiveTwo(1);
            moveY(this.crnStatus.getBayTwo(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevelTwo(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY,this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatusTwo(CrnStatusType.FETCHING.id);
            sleep(2000);
            sleep(3000);
            if (Thread.currentThread().isInterrupted()) {
                return;
            }
            this.crnStatus.setLoadedTwo(1);
            this.crnStatus.setStatusTwo(CrnStatusType.WAITING.id);
        }
        taskExecuteStation = 0;
    }
    private void commandPut(DualCrnCommand command) {
        int destinationPosX = command.getDestinationPosX().intValue();
        int destinationPosY = command.getDestinationPosY().intValue();
        int destinationPosZ = command.getDestinationPosZ().intValue();
        int taskMode = command.getTaskMode().intValue();
        int taskNo = command.getTaskNo().intValue();
        int destinationPosX = command.getDestinationPosX();
        int destinationPosY = command.getDestinationPosY();
        int destinationPosZ = command.getDestinationPosZ();
        int taskMode = command.getTaskMode();
        int taskNo = command.getTaskNo();
        int station = command.getStation();
        while (true) {
            if (taskExecuteStation == 0) {
                taskExecuteStation = station;
            }
            if (taskExecuteStation == station) {
                break;
            }
            sleep(200);
        }
        if(command.getStation() == 1) {
            this.crnStatus.setTaskNo(taskNo);
            this.crnStatus.setStatus(CrnStatusType.PUT_MOVING.id);
            this.crnStatus.setTaskReceive(1);
            moveY(this.crnStatus.getBay(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevel(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY,this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatus(CrnStatusType.PUTTING.id);
            sleep(2000);
            sleep(3000);
            if (Thread.currentThread().isInterrupted()) {
                return;
            }
@@ -227,16 +279,17 @@
            this.crnStatus.setStatusTwo(CrnStatusType.PUT_MOVING.id);
            this.crnStatus.setTaskReceiveTwo(1);
            moveY(this.crnStatus.getBayTwo(), destinationPosY, command.getStation().intValue());
            moveZ(this.crnStatus.getLevelTwo(), destinationPosZ, command.getStation().intValue());
            moveYZ(this.crnStatus.getBay(), destinationPosY,this.crnStatus.getLevel(), destinationPosZ, command.getStation());
            this.crnStatus.setStatusTwo(CrnStatusType.PUTTING.id);
            sleep(2000);
            sleep(3000);
            if (Thread.currentThread().isInterrupted()) {
                return;
            }
            this.crnStatus.setLoadedTwo(0);
            this.crnStatus.setStatusTwo(CrnStatusType.WAITING.id);
        }
        taskExecuteStation = 0;
    }
    private void moveZ(int sourcePosZ, int destinationPosZ, int station) {
@@ -245,11 +298,7 @@
            int initSourcePosZ = sourcePosZ;
            for(int i = 0; i < moveLength; i++) {
                initSourcePosZ++;
                if(station == 1) {
                    this.crnStatus.setLevel(initSourcePosZ);
                }else {
                    this.crnStatus.setLevelTwo(initSourcePosZ);
                }
                this.crnStatus.setLevel(initSourcePosZ);
                sleep(1000);
                if (Thread.currentThread().isInterrupted()) {
                    return;
@@ -260,11 +309,7 @@
            int initSourcePosZ = sourcePosZ;
            for(int i = 0; i < moveLength; i++) {
                initSourcePosZ--;
                if(station == 1) {
                    this.crnStatus.setLevel(initSourcePosZ);
                }else {
                    this.crnStatus.setLevelTwo(initSourcePosZ);
                }
                this.crnStatus.setLevel(initSourcePosZ);
                this.crnStatus.setLevel(initSourcePosZ);
                sleep(1000);
                if (Thread.currentThread().isInterrupted()) {
@@ -280,12 +325,8 @@
            int initSourcePosY = sourcePosY;
            for(int i = 0; i < moveLength; i++) {
                initSourcePosY++;
                if(station == 1) {
                    this.crnStatus.setBay(initSourcePosY);
                }else {
                    this.crnStatus.setBayTwo(initSourcePosY);
                }
                sleep(1000);
                this.crnStatus.setBay(initSourcePosY);
                sleep(500);
                if (Thread.currentThread().isInterrupted()) {
                    return;
                }
@@ -295,12 +336,8 @@
            int initSourcePosY = sourcePosY;
            for(int i = 0; i < moveLength; i++) {
                initSourcePosY--;
                if(station == 1) {
                    this.crnStatus.setBay(initSourcePosY);
                }else {
                    this.crnStatus.setBayTwo(initSourcePosY);
                }
                sleep(1000);
                this.crnStatus.setBay(initSourcePosY);
                sleep(500);
                if (Thread.currentThread().isInterrupted()) {
                    return;
                }
@@ -308,6 +345,11 @@
        }
    }
    private void moveYZ(int sourcePosY, int destinationPosY, int sourcePosZ, int destinationPosZ, int station) {
        moveY(sourcePosY, destinationPosY, station);
        moveZ(sourcePosZ, destinationPosZ, station);
    }
    private void sleep(long ms) {
        try {
            Thread.sleep(ms);
src/main/java/com/zy/core/network/real/ZyDualCrnRealConnect.java
@@ -64,21 +64,18 @@
                //工位1
                crnStatus.setTaskNo((int) siemensNet.getByteTransform().TransInt16(result.Content, 2));
                crnStatus.setStatus((int) siemensNet.getByteTransform().TransInt16(result.Content, 4));
                crnStatus.setBay((int) siemensNet.getByteTransform().TransInt16(result.Content, 6));
                crnStatus.setLevel((int) siemensNet.getByteTransform().TransInt16(result.Content, 8));
                crnStatus.setForkPos((int) siemensNet.getByteTransform().TransInt16(result.Content, 10));
                crnStatus.setLoaded((int) siemensNet.getByteTransform().TransInt16(result.Content, 12));
                crnStatus.setWalkPos((int) siemensNet.getByteTransform().TransInt16(result.Content, 26));
                //工位2
                crnStatus.setTaskNoTwo((int) siemensNet.getByteTransform().TransInt16(result.Content, 14));
                crnStatus.setStatusTwo((int) siemensNet.getByteTransform().TransInt16(result.Content, 16));
                crnStatus.setBayTwo((int) siemensNet.getByteTransform().TransInt16(result.Content, 18));
                crnStatus.setLevelTwo((int) siemensNet.getByteTransform().TransInt16(result.Content, 20));
                crnStatus.setForkPosTwo((int) siemensNet.getByteTransform().TransInt16(result.Content, 22));
                crnStatus.setLoadedTwo((int) siemensNet.getByteTransform().TransInt16(result.Content, 24));
                crnStatus.setWalkPosTwo((int) siemensNet.getByteTransform().TransInt16(result.Content, 28));
                crnStatus.setBay((int) siemensNet.getByteTransform().TransInt16(result.Content, 6));
                crnStatus.setLevel((int) siemensNet.getByteTransform().TransInt16(result.Content, 8));
                crnStatus.setWalkPos((int) siemensNet.getByteTransform().TransInt16(result.Content, 26));
                crnStatus.setAlarm((int) siemensNet.getByteTransform().TransInt16(result.Content, 18));
                crnStatus.setTemp1((int) siemensNet.getByteTransform().TransInt16(result.Content, 20));
                crnStatus.setTemp2((int) siemensNet.getByteTransform().TransInt16(result.Content, 22));
src/main/java/com/zy/core/plugin/FakeProcess.java
@@ -94,7 +94,7 @@
        stationOperateProcessUtils.stationOutExecuteFinish();
        //执行双工位堆垛机任务
        dualCrnOperateProcessUtils.dualRrnIoExecute();
        dualCrnOperateProcessUtils.dualCrnIoExecute();
        //双工位堆垛机任务执行完成
        dualCrnOperateProcessUtils.dualCrnIoExecuteFinish();
    }
@@ -615,7 +615,17 @@
                                continue;
                            }
                            DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
                            if (!dualCrnProtocol.getStatusType().equals(DualCrnStatusType.PUT_MOVING) && !dualCrnProtocol.getStatusType().equals(DualCrnStatusType.PUTTING)) {
                            boolean reset = false;
                            if (dualCrnProtocol.getTaskNo() > 0 && dualCrnProtocol.getLoaded() == 1) {
                                reset = true;
                            }
                            if (dualCrnProtocol.getTaskNoTwo() > 0 && dualCrnProtocol.getLoadedTwo() == 1) {
                                reset = true;
                            }
                            if (!reset) {
                                continue;
                            }
src/main/java/com/zy/core/thread/impl/ZyRgvThread.java
@@ -30,10 +30,6 @@
import java.text.MessageFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
@Data
@Slf4j
@@ -44,9 +40,6 @@
    private ZyRgvConnectDriver zyRgvConnectDriver;
    private RgvProtocol rgvProtocol;
    private int deviceLogCollectTime = 200;
    private volatile boolean closed = false;
    private ScheduledExecutorService readExecutor;
    private ScheduledExecutorService processExecutor;
    public ZyRgvThread(DeviceConfig deviceConfig, RedisUtil redisUtil) {
        this.deviceConfig = deviceConfig;
@@ -58,53 +51,39 @@
    public void run() {
        connect();
        initRgv();
        readExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("RgvReader-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
            }
        });
        readExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                readStatus();
            } catch (Exception e) {
                log.error("RgvThread Fail", e);
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        processExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("RgvWriter-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
        Thread readThread = new Thread(() -> {
            while (true) {
                try {
                    deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                    readStatus();
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("RgvThread Fail", e);
                }
            }
        });
        processExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                int step = 1;
                Task task = MessageQueue.poll(SlaveType.Rgv, deviceConfig.getDeviceNo());
                if (task != null) {
                    step = task.getStep();
        readThread.start();
        Thread processThread = new Thread(() -> {
            while (true) {
                try {
                    int step = 1;
                    Task task = MessageQueue.poll(SlaveType.Rgv, deviceConfig.getDeviceNo());
                    if (task != null) {
                        step = task.getStep();
                    }
                    if (step == 2) {
                        sendCommand((RgvCommand) task.getData());
                    }
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("RgvProcess Fail", e);
                }
                if (step == 2 && task != null) {
                    sendCommand((RgvCommand) task.getData());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        });
        processThread.start();
    }
    private void initRgv() {
@@ -182,17 +161,8 @@
    @Override
    public void close() {
        closed = true;
        if (zyRgvConnectDriver != null) {
            zyRgvConnectDriver.close();
        }
        ScheduledExecutorService ex = readExecutor;
        if (ex != null) {
            try { ex.shutdownNow(); } catch (Exception ignore) {}
        }
        ScheduledExecutorService px = processExecutor;
        if (px != null) {
            try { px.shutdownNow(); } catch (Exception ignore) {}
        }
    }
src/main/java/com/zy/core/thread/impl/ZySiemensCrnThread.java
@@ -30,10 +30,6 @@
import java.text.MessageFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
 * å †åž›æœºçº¿ç¨‹
@@ -47,10 +43,6 @@
    private ZyCrnConnectDriver zyCrnConnectDriver;
    private CrnProtocol crnProtocol;
    private int deviceLogCollectTime = 200;
    private boolean resetFlag = false;
    private volatile boolean closed = false;
    private ScheduledExecutorService readExecutor;
    private ScheduledExecutorService processExecutor;
    public ZySiemensCrnThread(DeviceConfig deviceConfig, RedisUtil redisUtil) {
        this.deviceConfig = deviceConfig;
@@ -62,53 +54,39 @@
    public void run() {
        this.connect();
        this.initCrn();
        readExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("CrnReader-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
            }
        });
        readExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                readStatus();
            } catch (Exception e) {
                log.error("CrnThread Fail", e);
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        processExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("CrnWriter-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
        Thread readThread = new Thread(() -> {
            while (true) {
                try {
                    deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                    readStatus();
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("CrnThread Fail", e);
                }
            }
        });
        processExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                int step = 1;
                Task task = MessageQueue.poll(SlaveType.Crn, deviceConfig.getDeviceNo());
                if (task != null) {
                    step = task.getStep();
        readThread.start();
        Thread processThread = new Thread(() -> {
            while (true) {
                try {
                    int step = 1;
                    Task task = MessageQueue.poll(SlaveType.Crn, deviceConfig.getDeviceNo());
                    if (task != null) {
                        step = task.getStep();
                    }
                    if (step == 2) {
                        sendCommand((CrnCommand) task.getData());
                    }
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("CrnProcess Fail", e);
                }
                if (step == 2 && task != null) {
                    sendCommand((CrnCommand) task.getData());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        });
        processThread.start();
    }
    /**
@@ -240,15 +218,6 @@
    @Override
    public void close() {
        closed = true;
        ScheduledExecutorService ex = readExecutor;
        if (ex != null) {
            try { ex.shutdownNow(); } catch (Exception ignore) {}
        }
        ScheduledExecutorService px = processExecutor;
        if (px != null) {
            try { px.shutdownNow(); } catch (Exception ignore) {}
        }
        if (zyCrnConnectDriver != null) {
            zyCrnConnectDriver.close();
        }
src/main/java/com/zy/core/thread/impl/ZySiemensDualCrnThread.java
@@ -6,26 +6,28 @@
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.DateUtils;
import com.core.common.SpringUtils;
import com.zy.asrs.entity.BasDualCrnp;
import com.zy.asrs.entity.BasDualCrnpOpt;
import com.zy.asrs.entity.DeviceConfig;
import com.zy.asrs.entity.DeviceDataLog;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.BasDualCrnpOptService;
import com.zy.asrs.service.BasDualCrnpService;
import com.zy.asrs.service.WrkMastService;
import com.zy.asrs.utils.Utils;
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.core.cache.MessageQueue;
import com.zy.core.cache.OutputQueue;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.*;
import com.zy.core.model.CommandResponse;
import com.zy.core.model.StationObjModel;
import com.zy.core.model.Task;
import com.zy.core.model.command.DualCrnCommand;
import com.zy.core.model.protocol.DualCrnProtocol;
import com.zy.core.model.protocol.StationProtocol;
import com.zy.core.network.DeviceConnectPool;
import com.zy.core.network.ZyDualCrnConnectDriver;
import com.zy.core.network.entity.ZyDualCrnStatusEntity;
import com.zy.core.thread.DualCrnThread;
import com.zy.core.thread.StationThread;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@@ -33,10 +35,7 @@
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.Map;
/**
 * åŒå·¥ä½å †åž›æœºçº¿ç¨‹
@@ -50,11 +49,6 @@
    private ZyDualCrnConnectDriver zyDualCrnConnectDriver;
    private DualCrnProtocol crnProtocol;
    private int deviceLogCollectTime = 200;
    private boolean resetFlag = false;
    private volatile boolean closed = false;
    private ScheduledExecutorService readExecutor;
    private ScheduledExecutorService processExecutor;
    private ScheduledExecutorService commandExecutor;
    public ZySiemensDualCrnThread(DeviceConfig deviceConfig, RedisUtil redisUtil) {
        this.deviceConfig = deviceConfig;
@@ -66,133 +60,163 @@
    public void run() {
        this.connect();
        this.initCrn();
        readExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("DualCrnReader-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
        Thread readThread = new Thread(() -> {
            while (true) {
                try {
                    deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                    readStatus();
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("DualCrnThread Fail", e);
                }
            }
        });
        readExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                readStatus();
            } catch (Exception e) {
                log.error("DualCrnThread Fail", e);
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        readThread.start();
        processExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("DualCrnWriter-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
            }
        });
        processExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                int step = 1;
                Task task = MessageQueue.poll(SlaveType.DualCrn, deviceConfig.getDeviceNo());
                if (task != null) {
                    step = task.getStep();
                }
                if (step == 2) {
                    List<DualCrnCommand> commandList = (List<DualCrnCommand>) task.getData();
                    DualCrnCommand command = commandList.get(0);
                    HashMap<String, Object> map = new HashMap<>();
                    map.put("commands", commandList);
                    map.put("idx", 1);
                    redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + command.getTaskNo(), JSON.toJSONString(map, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24);
                    sendCommand(command);
                } else if (step == 3) {
                    sendCommand((DualCrnCommand) task.getData());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        commandExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("DualCrnCommand-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
            }
        });
        commandExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                if(crnProtocol.getMode() != DualCrnModeType.AUTO.id) {
                    return;
                }
                if(crnProtocol.getAlarm() != 0) {
                    return;
                }
                //等待下一个任务
                Object wait = redisUtil.get(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo());
                if (wait != null) {
                    return;
                }
                if(crnProtocol.getTaskNo() > 0 && crnProtocol.getStatus() == DualCrnStatusType.IDLE.id) {
                    Integer taskNo = crnProtocol.getTaskNo();
                    Object commandObj = redisUtil.get(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo);
                    if (commandObj == null) {
                        News.error("双工位堆垛机,工位1空闲等待下发命令,但未找到命令。堆垛机号={},工作号={}", crnProtocol.getCrnNo(), taskNo);
                        return;
        Thread processThread = new Thread(() -> {
            while (true) {
                try {
                    int step = 1;
                    Task task = MessageQueue.poll(SlaveType.DualCrn, deviceConfig.getDeviceNo());
                    if (task != null) {
                        step = task.getStep();
                    }
                    JSONObject commandMap = JSON.parseObject(commandObj.toString());
                    Integer idx = commandMap.getInteger("idx");
                    List<DualCrnCommand> commandList = commandMap.getJSONArray("commands").toJavaList(DualCrnCommand.class);
                    DualCrnCommand dualCommand = commandList.get(idx);
                    idx++;
                    commandMap.put("idx", idx);
                    sendCommand(dualCommand);
                    redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo, commandMap.toJSONString(), 60 * 60 * 24);
                }
                    if (step == 2) {
                        List<DualCrnCommand> commandList = (List<DualCrnCommand>) task.getData();
                        DualCrnCommand command = commandList.get(0);
                if(crnProtocol.getTaskNoTwo() > 0 && crnProtocol.getStatusTwo() == DualCrnStatusType.IDLE.id) {
                    Integer taskNo = crnProtocol.getTaskNoTwo();
                    Object commandObj = redisUtil.get(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo);
                    if (commandObj == null) {
                        News.error("双工位堆垛机,工位2空闲等待下发命令,但未找到命令。堆垛机号={},工作号={}", crnProtocol.getCrnNo(), taskNo);
                        return;
                        HashMap<String, Object> map = new HashMap<>();
                        map.put("commands", commandList);
                        map.put("idx", 1);
                        redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + command.getTaskNo(), JSON.toJSONString(map, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24);
                        sendCommand(command);
                    } else if (step == 3) {
                        sendCommand((DualCrnCommand) task.getData());
                    }
                    JSONObject commandMap = JSON.parseObject(commandObj.toString());
                    Integer idx = commandMap.getInteger("idx");
                    List<DualCrnCommand> commandList = commandMap.getJSONArray("commands").toJavaList(DualCrnCommand.class);
                    DualCrnCommand dualCommand = commandList.get(idx);
                    idx++;
                    commandMap.put("idx", idx);
                    sendCommand(dualCommand);
                    redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo, commandMap.toJSONString(), 60 * 60 * 24);
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("DualCrnProcess Fail", e);
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("DualCrnCommandThread Fail", e);
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        });
        processThread.start();
        Thread commandThread = new Thread(() -> {
            while (true) {
                try {
                    if(crnProtocol.getMode() != DualCrnModeType.AUTO.id) {
                        continue;
                    }
                    if(crnProtocol.getAlarm() != 0) {
                        continue;
                    }
                    if (crnProtocol.getLoaded() == 1 && crnProtocol.getLoadedTwo() == 1) {
                        Object wait = redisUtil.get(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo());
                        if (wait != null) {
                            redisUtil.del(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo());
                        }
                    }
                    if(crnProtocol.getTaskNo() > 0 && crnProtocol.getStatus() == DualCrnStatusType.IDLE.id) {
                        Integer taskNo = crnProtocol.getTaskNo();
                        Object commandObj = redisUtil.get(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo);
                        if (commandObj == null) {
                            News.error("双工位堆垛机,工位1空闲等待下发命令,但未找到命令。堆垛机号={},工作号={}", crnProtocol.getCrnNo(), taskNo);
                            continue;
                        }
                        JSONObject commandMap = JSON.parseObject(commandObj.toString());
                        Integer idx = commandMap.getInteger("idx");
                        List<DualCrnCommand> commandList = commandMap.getJSONArray("commands").toJavaList(DualCrnCommand.class);
                        if (idx >= commandList.size()) {
                            continue;
                        }
                        DualCrnCommand dualCommand = commandList.get(idx);
                        if (dualCommand.getTaskMode() == DualCrnTaskModeType.PUT.id.shortValue()) {
                            //等待下一个任务
                            Object wait = redisUtil.get(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo());
                            if (wait != null) {
                                continue;
                            }
                            Object outTaskStationInfoObj = redisUtil.get(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + taskNo);
                            if (outTaskStationInfoObj != null) {
                                //检测出口站是否可执行放货动作
                                StationObjModel stationObjModel = JSON.parseObject(outTaskStationInfoObj.toString(), StationObjModel.class);
                                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
                                if (stationThread == null) {
                                    continue;
                                }
                                Map<Integer, StationProtocol> statusMap = stationThread.getStatusMap();
                                StationProtocol stationProtocol = statusMap.get(stationObjModel.getStationId());
                                if (stationProtocol == null) {
                                    continue;
                                }
                                if (!stationProtocol.isAutoing()) {
                                    continue;
                                }
                                if (stationProtocol.isLoading()) {
                                    continue;
                                }
                                if (stationProtocol.getTaskNo() > 0) {
                                    continue;
                                }
                            }
                        }
                        idx++;
                        commandMap.put("idx", idx);
                        sendCommand(dualCommand);
                        redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo, commandMap.toJSONString(), 60 * 60 * 24);
                    }
                    if(crnProtocol.getTaskNoTwo() > 0 && crnProtocol.getStatusTwo() == DualCrnStatusType.IDLE.id) {
                        Integer taskNo = crnProtocol.getTaskNoTwo();
                        Object commandObj = redisUtil.get(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo);
                        if (commandObj == null) {
                            News.error("双工位堆垛机,工位2空闲等待下发命令,但未找到命令。堆垛机号={},工作号={}", crnProtocol.getCrnNo(), taskNo);
                            continue;
                        }
                        JSONObject commandMap = JSON.parseObject(commandObj.toString());
                        Integer idx = commandMap.getInteger("idx");
                        List<DualCrnCommand> commandList = commandMap.getJSONArray("commands").toJavaList(DualCrnCommand.class);
                        if (idx >= commandList.size()) {
                            continue;
                        }
                        DualCrnCommand dualCommand = commandList.get(idx);
                        if (dualCommand.getTaskMode() == DualCrnTaskModeType.PUT.id.shortValue()) {
                            //等待下一个任务
                            Object wait = redisUtil.get(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnProtocol.getCrnNo());
                            if (wait != null) {
                                continue;
                            }
                        }
                        idx++;
                        commandMap.put("idx", idx);
                        sendCommand(dualCommand);
                        redisUtil.set(RedisKeyType.DUAL_CRN_COMMAND_.key + taskNo, commandMap.toJSONString(), 60 * 60 * 24);
                    }
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("DualCrnCommand Fail", e);
                }
            }
        });
        commandThread.start();
    }
    /**
@@ -257,25 +281,21 @@
        //工位1
        crnProtocol.setTaskNo(crnStatus.getTaskNo());
        crnProtocol.setStatus(crnStatus.getStatus());
        crnProtocol.setBay(crnStatus.getBay());
        crnProtocol.setLevel(crnStatus.getLevel());
        crnProtocol.setForkPos(crnStatus.getForkPos());
        crnProtocol.setLoaded(crnStatus.getLoaded());
        crnProtocol.setWalkPos(crnStatus.getWalkPos());
        crnProtocol.setLiftPos(crnStatus.getLiftPos());
        crnProtocol.setTaskReceive(crnStatus.getTaskReceive());
        //工位2
        crnProtocol.setTaskNoTwo(crnStatus.getTaskNoTwo());
        crnProtocol.setStatusTwo(crnStatus.getStatusTwo());
        crnProtocol.setBayTwo(crnStatus.getBayTwo());
        crnProtocol.setLevelTwo(crnStatus.getLevelTwo());
        crnProtocol.setForkPosTwo(crnStatus.getForkPosTwo());
        crnProtocol.setLoadedTwo(crnStatus.getLoadedTwo());
        crnProtocol.setWalkPosTwo(crnStatus.getWalkPosTwo());
        crnProtocol.setLiftPosTwo(crnStatus.getLiftPosTwo());
        crnProtocol.setTaskReceiveTwo(crnStatus.getTaskReceiveTwo());
        crnProtocol.setBay(crnStatus.getBay());
        crnProtocol.setLevel(crnStatus.getLevel());
        crnProtocol.setWalkPos(crnStatus.getWalkPos());
        crnProtocol.setLiftPos(crnStatus.getLiftPos());
        crnProtocol.setAlarm(crnStatus.getAlarm());
        crnProtocol.setTemp1(crnStatus.getTemp1());
        crnProtocol.setTemp2(crnStatus.getTemp2());
@@ -337,15 +357,6 @@
    @Override
    public void close() {
        closed = true;
        ScheduledExecutorService ex = readExecutor;
        if (ex != null) {
            try { ex.shutdownNow(); } catch (Exception ignore) {}
        }
        ScheduledExecutorService px = processExecutor;
        if (px != null) {
            try { px.shutdownNow(); } catch (Exception ignore) {}
        }
        if (zyDualCrnConnectDriver != null) {
            zyDualCrnConnectDriver.close();
        }
@@ -360,16 +371,16 @@
    public DualCrnCommand getPickAndPutCommand(String sourceLocNo, String targetLocNo, Integer taskNo, Integer crnNo, Integer station) {
        DualCrnCommand crnCommand = new DualCrnCommand();
        crnCommand.setCrnNo(crnNo); // å †åž›æœºç¼–号
        crnCommand.setTaskNo(taskNo.shortValue()); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.TRANSFER.id.shortValue()); // ä»»åŠ¡æ¨¡å¼:  å–放货
        crnCommand.setSourcePosX((short) Utils.getRow(sourceLocNo));     // æºåº“位排
        crnCommand.setSourcePosY((short) Utils.getBay(sourceLocNo));     // æºåº“位列
        crnCommand.setSourcePosZ((short) Utils.getLev(sourceLocNo));     // æºåº“位层
        crnCommand.setDestinationPosX((short) Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY((short) Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ((short) Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setStation(station.shortValue());//工位
        crnCommand.setCommand((short) 1);     // ä»»åŠ¡ç¡®è®¤
        crnCommand.setTaskNo(taskNo); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.TRANSFER.id); // ä»»åŠ¡æ¨¡å¼:  å–放货
        crnCommand.setSourcePosX(Utils.getRow(sourceLocNo));     // æºåº“位排
        crnCommand.setSourcePosY(Utils.getBay(sourceLocNo));     // æºåº“位列
        crnCommand.setSourcePosZ(Utils.getLev(sourceLocNo));     // æºåº“位层
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setStation(station);//工位
        crnCommand.setCommand(1);     // ä»»åŠ¡ç¡®è®¤
        return crnCommand;
    }
@@ -377,13 +388,13 @@
    public DualCrnCommand getPickCommand(String targetLocNo, Integer taskNo, Integer crnNo, Integer station) {
        DualCrnCommand crnCommand = new DualCrnCommand();
        crnCommand.setCrnNo(crnNo); // å †åž›æœºç¼–号
        crnCommand.setTaskNo(taskNo.shortValue()); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.PICK.id.shortValue()); // ä»»åŠ¡æ¨¡å¼:  å–è´§
        crnCommand.setDestinationPosX((short) Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY((short) Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ((short) Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setStation(station.shortValue());//工位
        crnCommand.setCommand((short) 1);     // ä»»åŠ¡ç¡®è®¤
        crnCommand.setTaskNo(taskNo); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.PICK.id); // ä»»åŠ¡æ¨¡å¼:  å–è´§
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setStation(station);//工位
        crnCommand.setCommand(1);     // ä»»åŠ¡ç¡®è®¤
        return crnCommand;
    }
@@ -391,13 +402,13 @@
    public DualCrnCommand getPutCommand(String targetLocNo, Integer taskNo, Integer crnNo, Integer station) {
        DualCrnCommand crnCommand = new DualCrnCommand();
        crnCommand.setCrnNo(crnNo); // å †åž›æœºç¼–号
        crnCommand.setTaskNo(taskNo.shortValue()); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.PUT.id.shortValue()); // ä»»åŠ¡æ¨¡å¼:  æ”¾è´§
        crnCommand.setDestinationPosX((short) Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY((short) Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ((short) Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setStation(station.shortValue());//工位
        crnCommand.setCommand((short) 1);     // ä»»åŠ¡ç¡®è®¤
        crnCommand.setTaskNo(taskNo); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.PUT.id); // ä»»åŠ¡æ¨¡å¼:  æ”¾è´§
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setStation(station);//工位
        crnCommand.setCommand(1);     // ä»»åŠ¡ç¡®è®¤
        return crnCommand;
    }
@@ -405,12 +416,12 @@
    public DualCrnCommand getMoveCommand(String targetLocNo, Integer taskNo, Integer crnNo) {
        DualCrnCommand crnCommand = new DualCrnCommand();
        crnCommand.setCrnNo(crnNo); // å †åž›æœºç¼–号
        crnCommand.setTaskNo(taskNo.shortValue()); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.MOVE.id.shortValue()); // ä»»åŠ¡æ¨¡å¼:  å †åž›æœºç§»åЍ
        crnCommand.setDestinationPosX((short) Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY((short) Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ((short) Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setCommand((short) 1);     // ä»»åŠ¡ç¡®è®¤
        crnCommand.setTaskNo(taskNo); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.MOVE.id); // ä»»åŠ¡æ¨¡å¼:  å †åž›æœºç§»åЍ
        crnCommand.setDestinationPosX(Utils.getRow(targetLocNo));     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY(Utils.getBay(targetLocNo));     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ(Utils.getLev(targetLocNo));     // ç›®æ ‡åº“位层
        crnCommand.setCommand(1);     // ä»»åŠ¡ç¡®è®¤
        return crnCommand;
    }
@@ -418,16 +429,16 @@
    public DualCrnCommand getResetCommand(Integer crnNo, Integer station) {
        DualCrnCommand crnCommand = new DualCrnCommand();
        crnCommand.setCrnNo(crnNo); // å †åž›æœºç¼–号
        crnCommand.setTaskNo((short) 0); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.CONFIRM.id.shortValue()); // ä»»åŠ¡æ¨¡å¼:  ç¡®è®¤
        crnCommand.setSourcePosX((short)0);     // æºåº“位排
        crnCommand.setSourcePosY((short)0);     // æºåº“位列
        crnCommand.setSourcePosZ((short)0);     // æºåº“位层
        crnCommand.setDestinationPosX((short)0);     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY((short)0);     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ((short)0);     // ç›®æ ‡åº“位层
        crnCommand.setStation(station.shortValue());//工位
        crnCommand.setCommand((short) 1);     // ä»»åŠ¡ç¡®è®¤
        crnCommand.setTaskNo(0); // å·¥ä½œå·
        crnCommand.setTaskMode(DualCrnTaskModeType.CONFIRM.id); // ä»»åŠ¡æ¨¡å¼:  ç¡®è®¤
        crnCommand.setSourcePosX(0);     // æºåº“位排
        crnCommand.setSourcePosY(0);     // æºåº“位列
        crnCommand.setSourcePosZ(0);     // æºåº“位层
        crnCommand.setDestinationPosX(0);     // ç›®æ ‡åº“位排
        crnCommand.setDestinationPosY(0);     // ç›®æ ‡åº“位列
        crnCommand.setDestinationPosZ(0);     // ç›®æ ‡åº“位层
        crnCommand.setStation(station);//工位
        crnCommand.setCommand(1);     // ä»»åŠ¡ç¡®è®¤
        return crnCommand;
    }
src/main/java/com/zy/core/thread/impl/ZyStationThread.java
@@ -28,10 +28,7 @@
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@@ -49,9 +46,6 @@
    private ZyStationConnectDriver zyStationConnectDriver;
    private int deviceLogCollectTime = 200;
    private long deviceDataLogTime = System.currentTimeMillis();
    private volatile boolean closed = false;
    private ScheduledExecutorService readExecutor;
    private ScheduledExecutorService processExecutor;
    public ZyStationThread(DeviceConfig deviceConfig, RedisUtil redisUtil) {
        this.deviceConfig = deviceConfig;
@@ -64,53 +58,38 @@
        this.connect();
        deviceLogCollectTime = Utils.getDeviceLogCollectTime();
        readExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("DevpReader-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
        Thread readThread = new Thread(() -> {
            while (true) {
                try {
                    deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                    readStatus();
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("StationThread Fail", e);
                }
            }
        });
        readExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                deviceLogCollectTime = Utils.getDeviceLogCollectTime();
                readStatus();
            } catch (Exception e) {
                log.error("StationThread Fail", e);
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        readThread.start();
        processExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("DevpWriter-" + deviceConfig.getDeviceNo());
                t.setDaemon(true);
                return t;
        Thread processThread = new Thread(() -> {
            while (true) {
                try {
                    int step = 1;
                    Task task = MessageQueue.poll(SlaveType.Devp, deviceConfig.getDeviceNo());
                    if (task != null) {
                        step = task.getStep();
                    }
                    if (step == 2) {
                        sendCommand((StationCommand) task.getData());
                    }
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("StationProcess Fail", e);
                }
            }
        });
        processExecutor.scheduleAtFixedRate(() -> {
            if (closed || Thread.currentThread().isInterrupted()) {
                return;
            }
            try {
                int step = 1;
                Task task = MessageQueue.poll(SlaveType.Devp, deviceConfig.getDeviceNo());
                if (task != null) {
                    step = task.getStep();
                }
                if (step == 2) {
                    sendCommand((StationCommand) task.getData());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 0, 200, TimeUnit.MILLISECONDS);
        processThread.start();
    }
    private void readStatus() {
@@ -190,15 +169,6 @@
    @Override
    public void close() {
        closed = true;
        ScheduledExecutorService ex = readExecutor;
        if (ex != null) {
            try { ex.shutdownNow(); } catch (Exception ignore) {}
        }
        ScheduledExecutorService px = processExecutor;
        if (px != null) {
            try { px.shutdownNow(); } catch (Exception ignore) {}
        }
        if (zyStationConnectDriver != null) {
            zyStationConnectDriver.close();
        }
src/main/java/com/zy/core/utils/CrnOperateProcessUtils.java
@@ -163,7 +163,6 @@
            }
            if(wrkMast.getWrkSts() != WrkStsType.INBOUND_DEVICE_RUN.sts){
                News.taskInfo(stationProtocol.getTaskNo(), "工作号:{} ä»»åŠ¡çŠ¶æ€å¼‚å¸¸", stationProtocol.getTaskNo());
                continue;
            }
src/main/java/com/zy/core/utils/DualCrnOperateProcessUtils.java
@@ -2,10 +2,10 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.exception.CoolException;
import com.zy.asrs.domain.param.CreateLocMoveTaskParam;
import com.zy.asrs.entity.BasCrnp;
import com.zy.asrs.entity.BasDualCrnp;
import com.zy.asrs.entity.LocMast;
import com.zy.asrs.entity.WrkMast;
@@ -22,15 +22,14 @@
import com.zy.core.enums.*;
import com.zy.core.model.StationObjModel;
import com.zy.core.model.Task;
import com.zy.core.model.command.CrnCommand;
import com.zy.core.model.command.DualCrnCommand;
import com.zy.core.model.protocol.CrnProtocol;
import com.zy.core.model.command.StationCommand;
import com.zy.core.model.protocol.DualCrnProtocol;
import com.zy.core.model.protocol.StationProtocol;
import com.zy.core.thread.CrnThread;
import com.zy.core.thread.DualCrnThread;
import com.zy.core.thread.StationThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@@ -42,6 +41,8 @@
@Component
public class DualCrnOperateProcessUtils {
    @Value("${mainProcessPlugin}")
    private String mainProcessPlugin;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
@@ -56,7 +57,7 @@
    private CommonService commonService;
    //入出库  ===>>  åŒå·¥ä½å †åž›æœºå…¥å‡ºåº“作业下发
    public synchronized void dualRrnIoExecute() {
    public synchronized void dualCrnIoExecute() {
        List<BasDualCrnp> basDualCrnps = basDualCrnpService.selectList(new EntityWrapper<>());
        for (BasDualCrnp basDualCrnp : basDualCrnps) {
            DualCrnThread dualCrnThread = (DualCrnThread) SlaveConnection.get(SlaveType.DualCrn, basDualCrnp.getCrnNo());
@@ -85,72 +86,67 @@
                continue;
            }
            int executeTaskNo = 0;
            if (dualCrnProtocol.getTaskNo() > 0) {
                executeTaskNo = dualCrnProtocol.getTaskNo();
            }
            if (dualCrnProtocol.getTaskNoTwo() > 0) {
                executeTaskNo = dualCrnProtocol.getTaskNoTwo();
            }
            if (executeTaskNo > 0) {
                WrkMast wrkMast = wrkMastService.selectByWorkNo(executeTaskNo);
                if (wrkMast != null) {
                    if (wrkMast.getIoType().equals(WrkIoType.IN.id)) {
                        this.crnExecuteIn(basDualCrnp, dualCrnThread); //  å…¥åº“
                    } else if (wrkMast.getIoType().equals(WrkIoType.OUT.id)) {
                        this.crnExecuteOut(basDualCrnp, dualCrnThread); //  å‡ºåº“
                    }else {
                        continue;
                    }
                }
            }
            // å¦‚果最近一次是入库模式
            if (dualCrnProtocol.getLastIo().equals("I")) {
                if (basDualCrnp.getInEnable().equals("Y")) {
                    this.crnExecuteIn(basDualCrnp, dualCrnThread); //  å…¥åº“
                    dualCrnProtocol.setLastIo("O");
                } else if (basDualCrnp.getOutEnable().equals("Y")) {
                    this.crnExecuteOut(basDualCrnp, dualCrnThread); //  å‡ºåº“
                    dualCrnProtocol.setLastIo("I");
                }
            }
            // å¦‚果最近一次是出库模式
            else if (dualCrnProtocol.getLastIo().equals("O")) {
                if (basDualCrnp.getOutEnable().equals("Y")) {
                    this.crnExecuteOut(basDualCrnp, dualCrnThread); //  å‡ºåº“
                    dualCrnProtocol.setLastIo("I");
                } else if (basDualCrnp.getInEnable().equals("Y")) {
                    this.crnExecuteIn(basDualCrnp, dualCrnThread); //  å…¥åº“
                    dualCrnProtocol.setLastIo("O");
                }
            }
            this.crnExecute(basDualCrnp, dualCrnThread);
        }
    }
    private synchronized void crnExecuteIn(BasDualCrnp basDualCrnp, DualCrnThread dualCrnThread) {
    private synchronized void crnExecute(BasDualCrnp basDualCrnp, DualCrnThread dualCrnThread) {
        DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
        if(dualCrnProtocol == null){
            return;
        }
        List<WrkMast> allTaskList = new ArrayList<>();
        List<WrkMast> inTaskList = getInTaskList(basDualCrnp);
        List<WrkMast> outTaskList = getOutTaskList(basDualCrnp);
        List<WrkMast> locMoveTaskList = getLocMoveTaskList(basDualCrnp);
        if (!locMoveTaskList.isEmpty()) {
            allTaskList.addAll(locMoveTaskList);
        }
        // å¦‚果最近一次是出库模式
        if (dualCrnProtocol.getLastIo().equals("O")) {
            allTaskList.addAll(inTaskList);
            allTaskList.addAll(outTaskList);
        }
        // å¦‚果最近一次是入库模式
        else if (dualCrnProtocol.getLastIo().equals("I")) {
            allTaskList.addAll(outTaskList);
            allTaskList.addAll(inTaskList);
        }
        for (WrkMast wrkMast : allTaskList) {
            if (wrkMast.getIoType() == WrkIoType.IN.id) {
                boolean result = this.crnExecuteIn(basDualCrnp, dualCrnThread, wrkMast);
                if (result) {
                    break;
                }
            } else if (wrkMast.getIoType() == WrkIoType.OUT.id) {
                boolean result = this.crnExecuteOut(basDualCrnp, dualCrnThread, wrkMast);
                if (result) {
                    break;
                }
            } else if (wrkMast.getIoType() == WrkIoType.LOC_MOVE.id) {
                boolean result = this.crnExecuteLocMove(basDualCrnp, dualCrnThread, wrkMast);
                if (result) {
                    break;
                }
            }
        }
    }
    private List<WrkMast> getInTaskList(BasDualCrnp basDualCrnp) {
        List<WrkMast> list = new ArrayList<>();
        if(!basDualCrnp.getInEnable().equals("Y")){
            News.info("双工位堆垛机:{} å¯å…¥ä¿¡å·ä¸æ»¡è¶³", basDualCrnp.getCrnNo());
            return;
            return list;
        }
        List<StationObjModel> inStationList = basDualCrnp.getInStationList$();
        if(inStationList.isEmpty()){
            News.info("双工位堆垛机:{} å…¥åº“站点未设置", basDualCrnp.getCrnNo());
            return;
        }
        Integer crnNo = basDualCrnp.getCrnNo();
        int station = calcStation(dualCrnProtocol);
        if(station == 0){
            News.info("双工位堆垛机:{} æ— å¯ç”¨å·¥ä½", basDualCrnp.getCrnNo());
            return;
            return list;
        }
        for (StationObjModel stationObjModel : inStationList) {
@@ -190,19 +186,217 @@
            }
            if(wrkMast.getWrkSts() != WrkStsType.INBOUND_DEVICE_RUN.sts){
                News.taskInfo(stationProtocol.getTaskNo(), "工作号:{} ä»»åŠ¡çŠ¶æ€å¼‚å¸¸", stationProtocol.getTaskNo());
                continue;
            }
            list.add(wrkMast);
        }
        return list;
    }
    private List<WrkMast> getOutTaskList(BasDualCrnp basDualCrnp) {
        List<WrkMast> list = new ArrayList<>();
        if(!basDualCrnp.getOutEnable().equals("Y")){
            News.info("双工位堆垛机:{} å¯å‡ºä¿¡å·ä¸æ»¡è¶³", basDualCrnp.getCrnNo());
            return list;
        }
        List<StationObjModel> outStationList = basDualCrnp.getOutStationList$();
        if(outStationList.isEmpty()){
            News.info("双工位堆垛机:{} å‡ºåº“站点未设置", basDualCrnp.getCrnNo());
            return list;
        }
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .eq("dual_crn_no", basDualCrnp.getCrnNo())
                .eq("wrk_sts", WrkStsType.NEW_OUTBOUND.sts)
        );
        list.addAll(wrkMasts);
        return list;
    }
    private List<WrkMast> getLocMoveTaskList(BasDualCrnp basDualCrnp) {
        List<WrkMast> list = new ArrayList<>();
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .eq("dual_crn_no", basDualCrnp.getCrnNo())
                .eq("wrk_sts", WrkStsType.NEW_LOC_MOVE.sts)
        );
        list.addAll(wrkMasts);
        return list;
    }
    private synchronized boolean crnExecuteIn(BasDualCrnp basDualCrnp, DualCrnThread dualCrnThread, WrkMast wrkMast) {
        DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
        if (dualCrnProtocol == null) {
            return false;
        }
        if (!basDualCrnp.getInEnable().equals("Y")) {
            News.info("双工位堆垛机:{} å¯å…¥ä¿¡å·ä¸æ»¡è¶³", basDualCrnp.getCrnNo());
            return false;
        }
        List<StationObjModel> inStationList = basDualCrnp.getInStationList$();
        if(inStationList.isEmpty()){
            News.info("双工位堆垛机:{} å…¥åº“站点未设置", basDualCrnp.getCrnNo());
            return false;
        }
        Integer crnNo = basDualCrnp.getCrnNo();
        int station = calcStation(dualCrnProtocol, "in");
        if (station == 0) {
            News.info("双工位堆垛机:{} æ— å¯ç”¨å·¥ä½", basDualCrnp.getCrnNo());
            return false;
        }
        if (wrkMast.getWrkSts() != WrkStsType.INBOUND_DEVICE_RUN.sts) {
            return false;
        }
        // èŽ·å–åº“ä½ä¿¡æ¯
        LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
        if (locMast == null) {
            News.taskInfo(wrkMast.getWrkNo(), "目标库位:{} ä¿¡æ¯ä¸å­˜åœ¨", wrkMast.getLocNo());
            return false;
        }
        if (!locMast.getLocSts().equals("S")) {
            News.taskInfo(wrkMast.getWrkNo(), "目标库位:{} çŠ¶æ€å¼‚å¸¸", wrkMast.getLocNo());
            return false;
        }
        //检测浅库位状态
        boolean checkStatus = checkShallowLocStatus(locMast.getLocNo(), wrkMast.getWrkNo());
        if (!checkStatus) {
            News.taskInfo(wrkMast.getWrkNo(), "因浅库位堵塞无法执行");
            return false;
        }
        StationObjModel inStationObjModel = null;
        for (StationObjModel stationObjModel : inStationList) {
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
            if (stationThread == null) {
                continue;
            }
            Map<Integer, StationProtocol> stationProtocolMap = stationThread.getStatusMap();
            StationProtocol stationProtocol = stationProtocolMap.get(stationObjModel.getStationId());
            if (stationProtocol == null) {
                continue;
            }
            if (!stationProtocol.isAutoing()) {
                continue;
            }
            if (!stationProtocol.isLoading()) {
                continue;
            }
            if (stationProtocol.getTaskNo() <= 0) {
                continue;
            }
            if (!stationProtocol.isInEnable()) {
                News.taskInfo(stationProtocol.getTaskNo(), "取货站点:{} æ²¡æœ‰å¯å…¥ä¿¡å·", stationObjModel.getStationId());
                continue;
            }
            if (stationProtocol.getTaskNo().equals(wrkMast.getWrkNo())) {
                inStationObjModel = stationObjModel;
                break;
            }
        }
        if (inStationObjModel == null) {
            News.taskInfo(wrkMast.getWrkNo(), "未搜索到取货站点");
            return false;
        }
        String sourceLocNo = Utils.getLocNo(inStationObjModel.getDeviceRow(), inStationObjModel.getDeviceBay(), inStationObjModel.getDeviceLev());
        List<DualCrnCommand> commandList = new ArrayList<>();
        DualCrnCommand pickCommand = dualCrnThread.getPickCommand(sourceLocNo, wrkMast.getWrkNo(), crnNo, station);
        DualCrnCommand putCommand = dualCrnThread.getPutCommand(wrkMast.getLocNo(), wrkMast.getWrkNo(), crnNo, station);
        commandList.add(pickCommand);
        commandList.add(putCommand);
        wrkMast.setWrkSts(WrkStsType.INBOUND_RUN.sts);
        wrkMast.setDualCrnNo(crnNo);
        wrkMast.setSystemMsg("");
        wrkMast.setIoTime(new Date());
        if (wrkMastService.updateById(wrkMast)) {
            MessageQueue.offer(SlaveType.DualCrn, crnNo, new Task(2, commandList));
            News.info("双工位堆垛机命令下发成功,堆垛机号={},任务数据={}", crnNo, JSON.toJSON(commandList));
            dualCrnProtocol.setLastIo("I");
            return true;
        }
        return false;
    }
    private synchronized boolean crnExecuteOut(BasDualCrnp basDualCrnp, DualCrnThread dualCrnThread, WrkMast wrkMast) {
        DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
        if (dualCrnProtocol == null) {
            return false;
        }
        if (!basDualCrnp.getOutEnable().equals("Y")) {
            News.info("双工位堆垛机:{} å¯å‡ºä¿¡å·ä¸æ»¡è¶³", basDualCrnp.getCrnNo());
            return false;
        }
        List<StationObjModel> outStationList = basDualCrnp.getOutStationList$();
        if (outStationList.isEmpty()) {
            News.info("双工位堆垛机:{} å‡ºåº“站点未设置", basDualCrnp.getCrnNo());
            return false;
        }
        Integer crnNo = basDualCrnp.getCrnNo();
        int station = calcStation(dualCrnProtocol, "out");
        if (station == 0) {
            News.info("双工位堆垛机:{} æ— å¯ç”¨å·¥ä½", basDualCrnp.getCrnNo());
            return false;
        }
        for (StationObjModel stationObjModel : outStationList) {
            StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
            if (stationThread == null) {
                continue;
            }
            Map<Integer, StationProtocol> stationProtocolMap = stationThread.getStatusMap();
            StationProtocol stationProtocol = stationProtocolMap.get(stationObjModel.getStationId());
            if (stationProtocol == null) {
                continue;
            }
            if (!stationProtocol.isAutoing()) {
                continue;
            }
            if (stationProtocol.isLoading()) {
                continue;
            }
            if (stationProtocol.getTaskNo() != 0) {
                continue;
            }
            if (!stationProtocol.isOutEnable()) {
                News.info("放货站点:{} æ²¡æœ‰å¯å‡ºä¿¡å·", stationObjModel.getStationId());
                continue;
            }
            // èŽ·å–åº“ä½ä¿¡æ¯
            LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
            LocMast locMast = locMastService.selectById(wrkMast.getSourceLocNo());
            if (locMast == null) {
                News.taskInfo(wrkMast.getWrkNo(), "目标库位:{} ä¿¡æ¯ä¸å­˜åœ¨", wrkMast.getLocNo());
                News.taskInfo(wrkMast.getWrkNo(), "源库位:{} ä¿¡æ¯ä¸å­˜åœ¨", wrkMast.getSourceLocNo());
                continue;
            }
            if (!locMast.getLocSts().equals("S")) {
                News.taskInfo(wrkMast.getWrkNo(), "目标库位:{} çŠ¶æ€å¼‚å¸¸", wrkMast.getLocNo());
            if (!locMast.getLocSts().equals("R")) {
                News.taskInfo(wrkMast.getWrkNo(), "源库位:{} çŠ¶æ€å¼‚å¸¸", wrkMast.getSourceLocNo());
                continue;
            }
@@ -213,124 +407,96 @@
                continue;
            }
            String sourceLocNo = Utils.getLocNo(stationObjModel.getDeviceRow(), stationObjModel.getDeviceBay(), stationObjModel.getDeviceLev());
            String targetLocNo = Utils.getLocNo(stationObjModel.getDeviceRow(), stationObjModel.getDeviceBay(), stationObjModel.getDeviceLev());
            List<DualCrnCommand> commandList = new ArrayList<>();
            DualCrnCommand pickCommand = dualCrnThread.getPickCommand(sourceLocNo, wrkMast.getWrkNo(), crnNo, station);
            DualCrnCommand putCommand = dualCrnThread.getPutCommand(wrkMast.getLocNo(), wrkMast.getWrkNo(), crnNo, station);
            DualCrnCommand pickCommand = dualCrnThread.getPickCommand(wrkMast.getSourceLocNo(), wrkMast.getWrkNo(), crnNo, station);
            DualCrnCommand putCommand = dualCrnThread.getPutCommand(targetLocNo, wrkMast.getWrkNo(), crnNo, station);
            commandList.add(pickCommand);
            commandList.add(putCommand);
            wrkMast.setWrkSts(WrkStsType.INBOUND_RUN.sts);
            wrkMast.setWrkSts(WrkStsType.OUTBOUND_RUN.sts);
            wrkMast.setDualCrnNo(crnNo);
            wrkMast.setSystemMsg("");
            wrkMast.setIoTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                MessageQueue.offer(SlaveType.DualCrn, crnNo, new Task(2, commandList));
                News.info("双工位堆垛机命令下发成功,堆垛机号={},任务数据={}", crnNo, JSON.toJSON(commandList));
                dualCrnProtocol.setLastIo("O");
                redisUtil.set(RedisKeyType.DUAL_CRN_OUT_TASK_STATION_INFO.key + wrkMast.getWrkNo(), JSON.toJSONString(stationObjModel, SerializerFeature.DisableCircularReferenceDetect), 60 * 60 * 24);
                return true;
            }
        }
        return false;
    }
    private synchronized void crnExecuteOut(BasDualCrnp basDualCrnp, DualCrnThread dualCrnThread) {
    private synchronized boolean crnExecuteLocMove(BasDualCrnp basDualCrnp, DualCrnThread dualCrnThread, WrkMast wrkMast) {
        DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus();
        if(dualCrnProtocol == null){
            return;
        }
        if(!basDualCrnp.getOutEnable().equals("Y")){
            News.info("双工位堆垛机:{} å¯å‡ºä¿¡å·ä¸æ»¡è¶³", basDualCrnp.getCrnNo());
            return;
        }
        List<StationObjModel> outStationList = basDualCrnp.getOutStationList$();
        if(outStationList.isEmpty()){
            News.info("双工位堆垛机:{} å‡ºåº“站点未设置", basDualCrnp.getCrnNo());
            return;
        if (dualCrnProtocol == null) {
            return false;
        }
        Integer crnNo = basDualCrnp.getCrnNo();
        int station = calcStation(dualCrnProtocol);
        if(station == 0){
        int station = calcStation(dualCrnProtocol, "locMove");
        if (station == 0) {
            News.info("双工位堆垛机:{} æ— å¯ç”¨å·¥ä½", basDualCrnp.getCrnNo());
            return;
            return false;
        }
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .eq("crn_no", crnNo)
                .eq("wrk_sts", WrkStsType.NEW_OUTBOUND.sts)
                .eq("wrk_sts", WrkStsType.NEW_LOC_MOVE.sts)
        );
        for (WrkMast wrkMast : wrkMasts) {
            for (StationObjModel stationObjModel : outStationList) {
                StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
                if (stationThread == null) {
                    continue;
                }
                Map<Integer, StationProtocol> stationProtocolMap = stationThread.getStatusMap();
                StationProtocol stationProtocol = stationProtocolMap.get(stationObjModel.getStationId());
                if (stationProtocol == null) {
                    continue;
                }
                if (!stationProtocol.isAutoing()) {
                    continue;
                }
                if (stationProtocol.isLoading()) {
                    continue;
                }
                if (stationProtocol.getTaskNo() != 0) {
                    continue;
                }
                if (!stationProtocol.isOutEnable()) {
                    News.info("放货站点:{} æ²¡æœ‰å¯å‡ºä¿¡å·", stationObjModel.getStationId());
                    continue;
                }
                // èŽ·å–åº“ä½ä¿¡æ¯
                LocMast locMast = locMastService.selectById(wrkMast.getSourceLocNo());
                if (locMast == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "源库位:{} ä¿¡æ¯ä¸å­˜åœ¨", wrkMast.getSourceLocNo());
                    continue;
                }
                if (!locMast.getLocSts().equals("R")) {
                    News.taskInfo(wrkMast.getWrkNo(), "源库位:{} çŠ¶æ€å¼‚å¸¸", wrkMast.getSourceLocNo());
                    continue;
                }
                //检测浅库位状态
                boolean checkStatus = checkShallowLocStatus(locMast.getLocNo(), wrkMast.getWrkNo());
                if (!checkStatus) {
                    News.taskInfo(wrkMast.getWrkNo(), "因浅库位堵塞无法执行");
                    continue;
                }
                String targetLocNo = Utils.getLocNo(stationObjModel.getDeviceRow(), stationObjModel.getDeviceBay(), stationObjModel.getDeviceLev());
                List<DualCrnCommand> commandList = new ArrayList<>();
                DualCrnCommand pickCommand = dualCrnThread.getPickCommand(wrkMast.getSourceLocNo(), wrkMast.getWrkNo(), crnNo, station);
                DualCrnCommand putCommand = dualCrnThread.getPutCommand(targetLocNo, wrkMast.getWrkNo(), crnNo, station);
                commandList.add(pickCommand);
                commandList.add(putCommand);
                wrkMast.setWrkSts(WrkStsType.OUTBOUND_RUN.sts);
                wrkMast.setDualCrnNo(crnNo);
                wrkMast.setSystemMsg("");
                wrkMast.setIoTime(new Date());
                if (wrkMastService.updateById(wrkMast)) {
                    MessageQueue.offer(SlaveType.DualCrn, crnNo, new Task(2, commandList));
                    //取货后等待下一个任务时长
                    redisUtil.set(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + crnNo, "wait", 5);
                    News.info("双工位堆垛机命令下发成功,堆垛机号={},任务数据={}", crnNo, JSON.toJSON(commandList));
                    return;
                }
            }
        // èŽ·å–æºåº“ä½ä¿¡æ¯
        LocMast sourceLocMast = locMastService.selectById(wrkMast.getSourceLocNo());
        if (sourceLocMast == null) {
            News.taskInfo(wrkMast.getWrkNo(), "源库位:{} ä¿¡æ¯ä¸å­˜åœ¨", wrkMast.getSourceLocNo());
            return false;
        }
        if(!sourceLocMast.getLocSts().equals("R")){
            News.taskInfo(wrkMast.getWrkNo(), "源库位:{} çŠ¶æ€å¼‚å¸¸ï¼Œä¸å±žäºŽå‡ºåº“é¢„çº¦çŠ¶æ€", wrkMast.getSourceLocNo());
            return false;
        }
        // èŽ·å–åº“ä½ä¿¡æ¯
        LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
        if (locMast == null) {
            News.taskInfo(wrkMast.getWrkNo(), "库位:{} ä¿¡æ¯ä¸å­˜åœ¨", wrkMast.getLocNo());
            return false;
        }
        if (!locMast.getLocSts().equals("S")) {
            News.taskInfo(wrkMast.getWrkNo(), "库位:{} çŠ¶æ€å¼‚å¸¸ï¼Œä¸å±žäºŽå…¥åº“é¢„çº¦çŠ¶æ€", wrkMast.getLocNo());
            return false;
        }
        //检测浅库位状态
        boolean checkStatus = checkShallowLocStatus(locMast.getLocNo(), wrkMast.getWrkNo());
        if (!checkStatus) {
            News.taskInfo(wrkMast.getWrkNo(), "因浅库位堵塞无法执行");
            return false;
        }
        List<DualCrnCommand> commandList = new ArrayList<>();
        DualCrnCommand pickCommand = dualCrnThread.getPickCommand(wrkMast.getSourceLocNo(), wrkMast.getWrkNo(), crnNo, station);
        DualCrnCommand putCommand = dualCrnThread.getPutCommand(wrkMast.getLocNo(), wrkMast.getWrkNo(), crnNo, station);
        commandList.add(pickCommand);
        commandList.add(putCommand);
        wrkMast.setWrkSts(WrkStsType.LOC_MOVE_RUN.sts);
        wrkMast.setDualCrnNo(crnNo);
        wrkMast.setSystemMsg("");
        wrkMast.setIoTime(new Date());
        if (wrkMastService.updateById(wrkMast)) {
            MessageQueue.offer(SlaveType.DualCrn, crnNo, new Task(2, commandList));
            News.info("双工位堆垛机命令下发成功,堆垛机号={},任务数据={}", crnNo, JSON.toJSON(commandList));
            dualCrnProtocol.setLastIo("I");
            return true;
        }
        return false;
    }
    //双工位堆垛机任务执行完成
@@ -357,12 +523,10 @@
            if(dualCrnProtocol.getTaskNo() > 0 && dualCrnProtocol.getStatus() == DualCrnStatusType.WAITING.id) {
                executeFinish(basDualCrnp, dualCrnThread, dualCrnProtocol, dualCrnProtocol.getTaskNo(), 1);
                continue;
            }
            if(dualCrnProtocol.getTaskNoTwo() > 0 && dualCrnProtocol.getStatusTwo() == DualCrnStatusType.WAITING.id) {
                executeFinish(basDualCrnp, dualCrnThread, dualCrnProtocol, dualCrnProtocol.getTaskNoTwo(), 2);
                continue;
            }
        }
    }
@@ -395,6 +559,30 @@
                updateWrkSts = WrkStsType.COMPLETE_INBOUND.sts;
            } else if (wrkMast.getWrkSts() == WrkStsType.OUTBOUND_RUN.sts) {
                updateWrkSts = WrkStsType.OUTBOUND_RUN_COMPLETE.sts;
                if(mainProcessPlugin.contains("Fake")) {
                    //生成仿真站点数据
                    List<StationObjModel> outStationList = basDualCrnp.getOutStationList$();
                    if(outStationList.isEmpty()){
                        News.info("双工位堆垛机:{} å‡ºåº“站点未设置", basDualCrnp.getCrnNo());
                        return;
                    }
                    for (StationObjModel stationObjModel : outStationList) {
                        if (!stationObjModel.getStationId().equals(wrkMast.getSourceStaNo())) {
                            continue;
                        }
                        StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, stationObjModel.getDeviceNo());
                        if (stationThread == null) {
                            continue;
                        }
                        //生成仿真站点数据
                        StationCommand command = stationThread.getMoveCommand(9998, wrkMast.getSourceStaNo(), 0, 0);
                        MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command));
                    }
                }
            } else if (wrkMast.getWrkSts() == WrkStsType.LOC_MOVE_RUN.sts) {
                updateWrkSts = WrkStsType.COMPLETE_LOC_MOVE.sts;
            } else {
@@ -402,16 +590,24 @@
                return;
            }
            wrkMast.setWrkSts(updateWrkSts);
            wrkMast.setSystemMsg("");
            wrkMast.setIoTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                DualCrnCommand resetCommand = dualCrnThread.getResetCommand(dualCrnProtocol.getCrnNo(), station);
                MessageQueue.offer(SlaveType.DualCrn, dualCrnProtocol.getCrnNo(), new Task(3, resetCommand));
                News.info("双工位堆垛机任务状态更新成功,堆垛机号={},工作号={}", basDualCrnp.getCrnNo(), taskNo);
            DualCrnCommand resetCommand = dualCrnThread.getResetCommand(dualCrnProtocol.getCrnNo(), station);
            boolean offer = MessageQueue.offer(SlaveType.DualCrn, dualCrnProtocol.getCrnNo(), new Task(3, resetCommand));
            if (offer) {
                wrkMast.setWrkSts(updateWrkSts);
                wrkMast.setSystemMsg("");
                wrkMast.setIoTime(new Date());
                if (wrkMastService.updateById(wrkMast)) {
                    News.info("双工位堆垛机任务状态更新成功,堆垛机号={},工作号={}", basDualCrnp.getCrnNo(), taskNo);
                }
                redisUtil.set(RedisKeyType.DUAL_CRN_IO_EXECUTE_FINISH_LIMIT.key + basDualCrnp.getCrnNo() + "_" + taskNo, "lock", 10);
            }
            redisUtil.set(RedisKeyType.DUAL_CRN_IO_EXECUTE_FINISH_LIMIT.key + basDualCrnp.getCrnNo() + "_" + taskNo, "lock", 10);
        }else {
            DualCrnCommand command = commandList.get(idx - 1);
            if (command.getTaskMode() == DualCrnTaskModeType.PICK.id.shortValue()) {
                //取货后等待下一个任务时长
                redisUtil.set(RedisKeyType.DUAL_CRN_PICK_WAIT_NEXT_TASK.key + basDualCrnp.getCrnNo(), "wait", 10);
            }
            DualCrnCommand resetCommand = dualCrnThread.getResetCommand(dualCrnProtocol.getCrnNo(), station);
            MessageQueue.offer(SlaveType.DualCrn, dualCrnProtocol.getCrnNo(), new Task(3, resetCommand));
            News.info("双工位堆垛机命令完成确认成功,堆垛机号={},工作号={}", basDualCrnp.getCrnNo(), taskNo);
@@ -481,15 +677,72 @@
        return false;
    }
    private int calcStation(DualCrnProtocol dualCrnProtocol) {
        int station = 0;
        if(dualCrnProtocol.getTaskNo() == 0){
            station = 1;
        }else if (dualCrnProtocol.getTaskNoTwo() == 0){
            station = 2;
    private int calcStation(DualCrnProtocol dualCrnProtocol, String type) {
        List<Integer> idleStationList = new ArrayList<>();
        if (dualCrnProtocol.getTaskNo() == 0
                && dualCrnProtocol.getLoaded() == 0
                && dualCrnProtocol.getStatusType().equals(DualCrnStatusType.IDLE)
        ) {
            idleStationList.add(1);
        }
        return station;
        if (dualCrnProtocol.getTaskNoTwo() == 0
                && dualCrnProtocol.getLoadedTwo() == 0
                && dualCrnProtocol.getStatusTypeTwo().equals(DualCrnStatusType.IDLE)
        ) {
            idleStationList.add(2);
        }
        if (type.equals("locMove")) {
            if (idleStationList.size() != 2) {
                return 0;
            }
            return idleStationList.get(0);
        }
        if (idleStationList.size() == 2) {
            return idleStationList.get(0);
        }
        Integer idleStation = idleStationList.get(0);
        int workingStation = idleStation == 1 ? 2 : 1;
        int executeTaskNo = 0;
        if (workingStation == 1) {
            executeTaskNo = dualCrnProtocol.getTaskNo();
            //检测工位已进入放货阶段,放货阶段不接新任务
            if (dualCrnProtocol.getStatusType().equals(DualCrnStatusType.PUT_MOVING)
                    || dualCrnProtocol.getStatusType().equals(DualCrnStatusType.PUTTING)
                    || dualCrnProtocol.getStatusType().equals(DualCrnStatusType.WAITING)
            ) {
                return 0;
            }
        } else {
            executeTaskNo = dualCrnProtocol.getTaskNoTwo();
            //检测工位已进入放货阶段,放货阶段不接新任务
            if (dualCrnProtocol.getStatusTypeTwo().equals(DualCrnStatusType.PUT_MOVING)
                    || dualCrnProtocol.getStatusTypeTwo().equals(DualCrnStatusType.PUTTING)
                    || dualCrnProtocol.getStatusTypeTwo().equals(DualCrnStatusType.WAITING)
            ) {
                return 0;
            }
        }
        if (executeTaskNo == 0) {
            return 0;
        }
        WrkMast wrkMast = wrkMastService.selectByWorkNo(executeTaskNo);
        if (wrkMast.getIoType().equals(WrkIoType.IN.id) && type.equals("in")) {
            return idleStation;
        }
        if (wrkMast.getIoType().equals(WrkIoType.OUT.id) && type.equals("out")) {
            return idleStation;
        }
        return 0;
    }
}
src/main/java/com/zy/core/utils/StationOperateProcessUtils.java
@@ -38,6 +38,8 @@
    @Autowired
    private BasCrnpService basCrnpService;
    @Autowired
    private BasDualCrnpService basDualCrnpService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private LocMastService locMastService;
@@ -130,15 +132,24 @@
    public synchronized void stationOutExecute() {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("wrk_sts", WrkStsType.OUTBOUND_RUN_COMPLETE.sts));
        for (WrkMast wrkMast : wrkMasts) {
            List<StationObjModel> outStationList = new ArrayList<>();
            BasCrnp basCrnp = basCrnpService.selectOne(new EntityWrapper<BasCrnp>().eq("crn_no", wrkMast.getCrnNo()));
            if (basCrnp == null) {
                continue;
            if (basCrnp != null) {
                outStationList = basCrnp.getOutStationList$();
                if(outStationList.isEmpty()){
                    News.info("堆垛机:{} å‡ºåº“站点未设置", basCrnp.getCrnNo());
                    continue;
                }
            }
            List<StationObjModel> outStationList = basCrnp.getOutStationList$();
            if(outStationList.isEmpty()){
                News.info("堆垛机:{} å‡ºåº“站点未设置", basCrnp.getCrnNo());
                continue;
            BasDualCrnp basDualCrnp = basDualCrnpService.selectOne(new EntityWrapper<BasDualCrnp>().eq("crn_no", wrkMast.getDualCrnNo()));
            if (basDualCrnp != null) {
                outStationList = basDualCrnp.getOutStationList$();
                if(outStationList.isEmpty()){
                    News.info("双工位堆垛机:{} å‡ºåº“站点未设置", basDualCrnp.getCrnNo());
                    continue;
                }
            }
            for (StationObjModel stationObjModel : outStationList) {
@@ -176,6 +187,7 @@
                        MessageQueue.offer(SlaveType.Devp, stationObjModel.getDeviceNo(), new Task(2, command));
                        News.info("输送站点出库命令下发成功,站点号={},工作号={},命令数据={}", stationProtocol.getStationId(), wrkMast.getWrkNo(), JSON.toJSONString(command));
                        redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_LIMIT.key + stationProtocol.getStationId(), "lock", 5);
                        redisUtil.set(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkMast.getWrkNo(), "lock", 60 * 5);
                    }
                }
            }
@@ -188,6 +200,11 @@
        for (WrkMast wrkMast : wrkMasts) {
            Integer wrkNo = wrkMast.getWrkNo();
            Object lock = redisUtil.get(RedisKeyType.STATION_OUT_EXECUTE_COMPLETE_LIMIT.key + wrkNo);
            if (lock != null) {
                continue;
            }
            boolean complete = true;
            List<BasDevp> basDevps = basDevpService.selectList(new EntityWrapper<>());
            for (BasDevp basDevp : basDevps) {
src/main/resources/docs/WCSÍⲿHTTP API½Ó¿ÚV1.2.docx
Binary files differ
src/main/webapp/components/WatchDualCrnCard.js
@@ -53,18 +53,14 @@
                <el-descriptions-item label="工位2状态">{{ item.statusTwo }}</el-descriptions-item>
                <el-descriptions-item label="工位1是否有物">{{ item.loading }}</el-descriptions-item>
                <el-descriptions-item label="工位2是否有物">{{ item.loadingTwo }}</el-descriptions-item>
                <el-descriptions-item label="工位1列">{{ item.bay }}</el-descriptions-item>
                <el-descriptions-item label="工位2列">{{ item.bayTwo }}</el-descriptions-item>
                <el-descriptions-item label="工位1层">{{ item.lev }}</el-descriptions-item>
                <el-descriptions-item label="工位2层">{{ item.levTwo }}</el-descriptions-item>
                <el-descriptions-item label="工位1货叉定位">{{ item.forkOffset }}</el-descriptions-item>
                <el-descriptions-item label="工位2货叉定位">{{ item.forkOffsetTwo }}</el-descriptions-item>
                <el-descriptions-item label="工位1载货台定位">{{ item.liftPos }}</el-descriptions-item>
                <el-descriptions-item label="工位2载货台定位">{{ item.liftPosTwo }}</el-descriptions-item>
                <el-descriptions-item label="工位1走行在定位">{{ item.walkPos }}</el-descriptions-item>
                <el-descriptions-item label="工位2走行在定位">{{ item.walkPosTwo }}</el-descriptions-item>
                <el-descriptions-item label="工位1任务接收">{{ item.taskReceive }}</el-descriptions-item>
                <el-descriptions-item label="工位2任务接收">{{ item.taskReceiveTwo }}</el-descriptions-item>
                <el-descriptions-item label="列">{{ item.bay }}</el-descriptions-item>
                <el-descriptions-item label="层">{{ item.lev }}</el-descriptions-item>
                <el-descriptions-item label="载货台定位">{{ item.liftPos }}</el-descriptions-item>
                <el-descriptions-item label="走行在定位">{{ item.walkPos }}</el-descriptions-item>
                <el-descriptions-item label="走行速度(m/min)">{{ item.xspeed }}</el-descriptions-item>
                <el-descriptions-item label="升降速度(m/min)">{{ item.yspeed }}</el-descriptions-item>
                <el-descriptions-item label="叉牙速度(m/min)">{{ item.zspeed }}</el-descriptions-item>
src/main/webapp/views/locMap/locMap.html
@@ -69,21 +69,6 @@
  </el-drawer>
  <el-drawer
          title="小车信息"
          :visible.sync="drawerShuttle"
          :with-header="true"
          :modal="false"
  >
    <div v-if="drawerShuttleData!=null">
      <div style="margin: 10px;">
        <div style="margin-top: 5px;">小车:{{drawerShuttleData.shuttleNo}}</div>
        <div style="margin-top: 5px;">工作号:{{drawerShuttleData.wrkNo}}</div>
        <div style="margin-top: 5px;">状态:{{drawerShuttleData}}</div>
      </div>
    </div>
  </el-drawer>
  <el-drawer
          title="站点信息"
          :visible.sync="drawerSta"
          :with-header="true"
@@ -108,35 +93,14 @@
    </div>
  </el-drawer>
  <el-drawer
          title="提升机信息"
          :visible.sync="drawerLift"
          :with-header="true"
          :modal="false"
  >
    <div v-if="drawerLiftData!=null">
      <div style="margin: 10px;">
        <div style="margin-top: 5px;">提升机:{{liftList[drawerLiftData-1].liftNo}}</div>
        <div style="margin-top: 5px;">工作号:{{liftList[drawerLiftData-1].taskNo}}</div>
        <div style="margin-top: 5px;">状态:{{liftList[drawerLiftData-1]}}</div>
      </div>
    </div>
  </el-drawer>
</div>
<script>
  let width = 25;
  let height = 25;
  let pixiApp;
  let pixiStageList = [];
  let pixiShuttleMap = new Map();
  let pixiShuttleMoveAdvancePathMap = new Map();
  let pixiShuttleMoveAdvancePathList = [];
  let pixiShuttleLockPathMap = new Map();
  let pixiStaMap = new Map();
  let objectsContainer;
  let objectsContainer2;
  let objectsContainer3;
  let graphics0;
  let graphics3;
  let graphics4;
@@ -152,23 +116,15 @@
      map: [],
      currentLev: 1,
      floorList: [], //当前项目楼层
      currentLevShuttleList: [],//当前楼层四向穿梭车集合
      shuttleColorList: [],//四向穿梭车颜色集合
      drawer: false,
      drawerLocNo: false,
      drawerLocNoData: null,
      drawerLocDetls: [],
      reloadMap: true,
      mapFps: 0,
      drawerShuttle: false,
      drawerShuttleData: null,
      currentLevStaList: [],//当前楼层站点list
      reloadSta: true,
      drawerSta: false,
      drawerStaData: null,
      drawerLift: false,
      drawerLiftData: null,
      liftList: [],
    },
    mounted() {
      this.init()
@@ -205,14 +161,6 @@
        setTimeout(() => {
          that.getMap(this.currentLev)
        }, 1000);
        // this.consoleInterval = setInterval(() => {
        //   this.getMap(this.currentLev) //获取实时地图数据
        //   this.getShuttleStateInfo() //获取四向穿梭车信息
        //   this.getLiftStateInfo() //获取提升机信息
        //   this.getSiteInfo() //获取输送站点数据
        //   // this.getCodeData()//获取条码
        // }, 1000)
      },
      initLev(){
@@ -257,19 +205,8 @@
      },
      changeFloor(lev) {
        this.currentLev = lev
        this.currentLevShuttleList = []
        this.reloadMap = true
        this.reloadSta = true
        this.getMap(lev)
        //清空占用路径
        objectsContainer3.removeChildren();
        pixiShuttleLockPathMap = new Map();
        //清空预计路径
        objectsContainer2.removeChildren();
        pixiShuttleMoveAdvancePathMap = new Map();
        pixiShuttleMoveAdvancePathList = []
      },
      createMap(){
        //Create a Pixi Application
@@ -281,9 +218,6 @@
        });
        //Add the canvas that Pixi automatically created for you to the HTML document
        $("#pixiView").append(pixiApp.view)
        //加载小车资源
        pixiApp.loader.add('shuttle', '../static/images/sxcar.png');
        // ä»ŽGraphics对象创建一个纹理
            graphicsF = pixiApp.renderer.generateTexture(getContainer(1000));
@@ -298,10 +232,6 @@
        // åˆ›å»ºä¸€ä¸ªå®¹å™¨æ¥ç®¡ç†å¤§æ‰¹é‡çš„æ˜¾ç¤ºå¯¹è±¡
        objectsContainer = new PIXI.Container();
        pixiApp.stage.addChild(objectsContainer);
        // åˆ›å»ºä¸€ä¸ªå®¹å™¨æ¥ç®¡ç†å¤§æ‰¹é‡çš„æ˜¾ç¤ºå¯¹è±¡
        objectsContainer2 = new PIXI.Container();
        pixiApp.stage.addChild(objectsContainer2);
        // åˆ›å»ºä¸€ä¸ªå®¹å™¨æ¥ç®¡ç†å¤§æ‰¹é‡çš„æ˜¾ç¤ºå¯¹è±¡
        objectsContainer3 = new PIXI.Container();
@@ -370,13 +300,24 @@
        //*******************缩放画布*******************
        //*******************FPS*******************
        var g_Time=0;
        let g_Time = 0;
        let fpsLastUpdateTs = 0;
        let fpsDeltaSumMs = 0;
        let fpsFrameCount = 0;
        const fpsUpdateInterval = 200;
        pixiApp.ticker.add((delta) => {
          var timeNow = (new Date()).getTime();
          var timeDiff = timeNow - g_Time;
          const timeNow = (new Date()).getTime();
          const timeDiff = timeNow - g_Time;
          g_Time = timeNow;
          var fps = 1000 / timeDiff;
          this.mapFps = parseInt(fps)
          fpsDeltaSumMs += timeDiff;
          fpsFrameCount += 1;
          if (timeNow - fpsLastUpdateTs >= fpsUpdateInterval) {
            const avgFps = fpsDeltaSumMs > 0 ? (fpsFrameCount * 1000 / fpsDeltaSumMs) : 0;
            this.mapFps = Math.round(avgFps);
            fpsDeltaSumMs = 0;
            fpsFrameCount = 0;
            fpsLastUpdateTs = timeNow;
          }
        });
        //*******************FPS*******************
@@ -399,10 +340,7 @@
                if (val.value == 4) {
                  //站点
                  this.openDrawerSta(val)
                } else if (val.value == 67) {
                  //提升机
                  this.openDrawerLift(val)
                } else {
                }else {
                  //库位
                  this.rightEvent(index, idx, e);
                  updateColor(sprite, 0x9900ff);
@@ -450,11 +388,10 @@
          });
          const b1 = objectsContainer.getLocalBounds();
          const b2 = objectsContainer2.getLocalBounds();
          const minX = Math.min(b1.x, b2.x);
          const minY = Math.min(b1.y, b2.y);
          const maxX = Math.max(b1.x + b1.width, b2.x + b2.width);
          const maxY = Math.max(b1.y + b1.height, b2.y + b2.height);
          const minX = Math.min(b1.x);
          const minY = Math.min(b1.y);
          const maxX = Math.max(b1.x + b1.width);
          const maxY = Math.max(b1.y + b1.height);
          const contentW = Math.max(0, maxX - minX);
          const contentH = Math.max(0, maxY - minY);
          const vw = pixiApp.view.width;
@@ -464,141 +401,13 @@
          const posX = (vw - contentW * scale) / 2 - minX * scale;
          const posY = (vh - contentH * scale) / 2 - minY * scale;
          pixiApp.stage.setTransform(posX, posY, scale, scale, 0, 0, 0, 0, 0);
        }else {
          let diff = this.findDiffList(this.map, map);
          diff.forEach((item, index) => {
            //获取old元素
            let oldSprite = pixiStageList[item.x][item.y]
            if (item.originData == -999) {
              //移除old路径元素
              objectsContainer3.removeChild(oldSprite);
            }else {
              //移除old元素
              objectsContainer.removeChild(oldSprite);
            }
            let sprite = getSprite(item.data, item.y * width, item.x * height, item, (e) => {
              this.rightEvent(item.x, item.y, e);
              updateColor(sprite, 0x9900ff);
            });
            if (item.data == -999) {
              //添加路径元素
              objectsContainer3.addChild(sprite);
            }else {
              //添加元素
              objectsContainer.addChild(sprite);
            }
            //保存新元素
            pixiStageList[item.x][item.y] = sprite
          });
        }
        this.map = map;
      },
      rightEvent(x, y, e) {
        this.drawerLocNo = true
        this.drawerLocNoData =  {x:x, y: y, z: this.currentLev, locNo: this.map[x][y].locNo,
            locSts: this.map[x][y].locSts,row:this.map[x][y].row, bay: this.map[x][y].bay, lev: this.currentLev};
      },
      findDiffList(arr1, arr2) {
        let diff = []
        arr1.forEach((item,index) => {
          item.forEach((val,idx) => {
            if(val.value != arr2[index][idx].value){
              diff.push({
                x: index,
                y: idx,
                data: arr2[index][idx].value,
                originData: val.value,
                locSts: val.locSts
              })
            }
          })
        })
        return diff;
      },
      findShuttleDiffList(list1, list2) {
        //检测集合1里面的小车是否在集合2中有变动
        if (list1.length == 0) {
          return false;//集合为空
        }
        if (list1.length != list2.length) {
          return false;//两个集合长度不一致
        }
        let flag = false;
        list1.forEach((item,index) => {
          for (var i = 0; i < list2.length; i++) {
            if (item.shuttleNo == list2[i].shuttleNo) {
              flag = true;
              break;
            }
          }
        });
        return flag;
      },
      findShuttlePathDiffList(list1, list2) {
        //检测集合1里面的小车预计路径是否在集合2中有变动
        if (list1.length == 0) {
          return false;//集合为空
        }
        if (list1.length != list2.length) {
          return false;//两个集合长度不一致
        }
        for (var index = 0; index < list1.length; index++) {
          let item = list1[index];
          for (var i = 0; i < list2.length; i++) {
            if (item.shuttleNo != list2[i].shuttleNo) {
              continue;//找不到小车号
            }
            if (item.moveAdvancePath == null) {
              item.moveAdvancePath = [];
            }
            if (list2[i].moveAdvancePath == null) {
              list2[i].moveAdvancePath = [];
            }
            if (!(item.moveAdvancePath.length == list2[i].moveAdvancePath.length)) {
              return false;//小车预计路径长度不一致
            }
          }
        }
        return true;
      },
      checkStaInListDiff(sta, list) {
        //检测站点是否在集合中有变动
        if (list.length == 0) {
          return false;//集合为空
        }
        let tmp = null;
        for (var i = 0; i < list.length; i++) {
          if (sta.siteId == list[i].siteId) {
            tmp = list[i];//找到相同站点
            break
          }
        }
        if (tmp == null) {
          return false;//没有找到相同站点
        }
        if (sta.siteStatus != tmp.siteStatus) {
          return false;//站点状态不相同
        }
        if (sta.workNo != tmp.workNo) {
          return false;//站点工作号不相同
        }
        return true;//无变化
      },
      webSocketOnOpen(e) {
        console.log("open");
@@ -608,18 +417,10 @@
      },
      webSocketOnMessage(e) {
        const result = JSON.parse(e.data);
        if (result.url == "/shuttle/table/shuttle/state") {
          this.setShuttleStateInfo(JSON.parse(result.data))
        }else if (result.url == "/lift/table/lift/state") {
          this.setLiftStateInfo(JSON.parse(result.data))
        }else if (result.url == "/console/latest/data/site") {
          this.setSiteInfo(JSON.parse(result.data))
        }else if (result.url == "/console/map/auth") {
        if (result.url == "/console/map/auth") {
          this.setMap(JSON.parse(result.data))
        }else if (result.url == "/console/locMap/auth") {
          this.setMap(JSON.parse(result.data))
        }else if (result.url == "/console/barcode/output/site") {
          this.setCodeData(JSON.parse(result.data))
        }
      },
      webSocketClose(e) {
@@ -628,119 +429,6 @@
      sendWs(message) {
        if (ws.readyState == WebSocket.OPEN) {
          ws.send(message)
        }
      },
      colorRGB(){
        //随机颜色
        const r = Math.floor(Math.random()*256);
        const g = Math.floor(Math.random()*256);
        const b = Math.floor(Math.random()*256);
        return `rgb(${r},${g},${b})`;
      },
      updateShuttleXY(item) {
        const shuttle = pixiShuttleMap.get(item.shuttleNo);
        if (shuttle.updateMoveStatus) {//动画执行完成才可继续执行动画
          shuttle.updateMoveStatus = false;//动画执行中
          // è®¡ç®—两点之间的距离1
          const distance = Math.sqrt(Math.pow((item.wcsPoint.x * width) - shuttle.x, 2) + Math.pow((item.wcsPoint.y * height) - shuttle.y, 2));
          gsap.killTweensOf(shuttle); // æ€æ­»æ‰€æœ‰é’ˆå¯¹".class"的动画
          gsap.to(shuttle, {
            x: (item.wcsPoint.y - 0) * width, // ç›®æ ‡ä½ç½®
            y: (item.wcsPoint.x - 1) * height, // ç›®æ ‡ä½ç½®
            duration: 0.2, // åŠ¨ç”»æŒç»­æ—¶é—´ï¼ˆç§’ï¼‰
            ease: "power1.inOut", // ç¼“动类型
            onComplete: () => {
              shuttle.updateMoveStatus = true;//动画执行完成
            }
          });
        }
      },
      getSiteInfo() {
        //获取输送站点数据
        this.sendWs(JSON.stringify({
          "url": "/console/latest/data/site",
          "data": {}
        }))
      },
      setSiteInfo(res) {
        // var test = "{\"msg\":\"操作成功\",\"code\":200,\"data\":[{\"siteId\":\"300\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"301\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"302\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"303\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"304\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"305\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"306\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"307\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"308\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"309\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"310\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"311\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"312\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"313\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"314\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"315\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"316\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"317\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"318\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"319\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"320\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"321\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"322\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"323\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"324\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"325\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"326\",\"siteStatus\":\"site-auto-id\",\"workNo\":5451},{\"siteId\":\"327\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"200\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"328\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"201\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"329\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"202\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"330\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"203\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"331\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"204\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"332\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"205\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"333\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"334\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"335\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"336\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"337\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"338\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"339\",\"siteStatus\":\"site-auto-run-id\",\"workNo\":5447},{\"siteId\":\"340\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"341\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"342\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"343\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"344\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"345\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"346\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"100\",\"siteStatus\":\"site-auto-run-id\",\"workNo\":8851},{\"siteId\":\"101\",\"siteStatus\":\"site-auto-run-id\",\"workNo\":8855},{\"siteId\":\"102\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"103\",\"siteStatus\":\"site-auto\",\"workNo\":0},{\"siteId\":\"104\",\"siteStatus\":\"site-auto-run\",\"workNo\":0},{\"siteId\":\"105\",\"siteStatus\":\"site-auto\",\"workNo\":0}]}";
        // res = JSON.parse(test)
        //获取输送站点数据
        if (res.code === 200){
          var sites = res.data;
          if (this.reloadSta && pixiStaMap.size > 0) {
            //重新渲染所有输送站点
            this.currentLevStaList = sites;
            this.reloadSta = false;
            sites.forEach((item, index) => {
              let sta = pixiStaMap.get(parseInt(item.siteId));
              if (sta != undefined) {
                if (item.workNo > 0) {
                  sta.textObj.text = item.siteId + "(" + item.workNo + ")";
                }
                //创建遮罩层
                if (item.siteStatus == "site-auto") {
                  //自动状态,移除遮罩层
                  if (sta.statusObj != null) {
                    objectsContainer.removeChild(sta.statusObj)
                    sta.statusObj = null;
                  }
                }else if (item.siteStatus == "site-auto-run" || item.siteStatus == "site-auto-run-id") {
                  //自动有物
                  let graphics = getGraphics(0xfa51f6, width, height, sta.x, sta.y);
                  graphics.addChild(sta.textObj);//继承文字信息
                  sta.statusObj = graphics;
                  objectsContainer.addChild(graphics);
                }else if (item.siteStatus == "site-unauto") {
                  //非自动
                  let graphics = getGraphics(0xb8b8b8, width, height, sta.x, sta.y);
                  graphics.addChild(sta.textObj);//继承文字信息
                  sta.statusObj = graphics;
                  objectsContainer.addChild(graphics);
                }
              }
            });
          } else {
            //检测不相同站点进行局部更新
            this.currentLevStaList.forEach((item, index) => {
              let result = this.checkStaInListDiff(item, sites);
              if (!result) {
                //需要更新
                let sta = pixiStaMap.get(parseInt(item.siteId));
                if (item.workNo > 0) {
                  sta.textObj.text = item.siteId + "(" + item.workNo + ")";
                }else {
                  sta.textObj.text = item.siteId;
                }
                //创建遮罩层
                if (item.siteStatus == "site-auto") {
                  //自动状态,移除遮罩层
                  if (sta.statusObj != null) {
                    objectsContainer.removeChild(sta.statusObj)
                    sta.statusObj = null;
                  }
                }else if (item.siteStatus == "site-auto-run") {
                  //自动有物
                  let graphics = getGraphics(0xfa51f6, width, height, sta.x, sta.y);
                  graphics.addChild(sta.textObj);//继承文字信息
                  sta.statusObj = graphics;
                  objectsContainer.addChild(graphics);
                }else if (item.siteStatus == "site-unauto") {
                  //非自动
                  let graphics = getGraphics(0xb8b8b8, width, height, sta.x, sta.y);
                  graphics.addChild(sta.textObj);//继承文字信息
                  sta.statusObj = graphics;
                  objectsContainer.addChild(graphics);
                }
              }
            });
          }
        } else if (res.code === 403){
          parent.location.href = baseUrl+"/login";
        }  else {
          console.log(res.msg);
        }
      },
      openDrawerSta(data) {
@@ -763,101 +451,6 @@
            }
          }
        })
      },
      openDrawerLift(data) {
        this.drawerLift = true;
        this.drawerLiftData = parseInt(data.data)
      },
      getLiftStateInfo() {
        // æå‡æœºä¿¡æ¯è¡¨èŽ·å–
        this.sendWs(JSON.stringify({
          "url": "/lift/table/lift/state",
          "data": {}
        }))
      },
      setLiftStateInfo(res) {
        // æå‡æœºä¿¡æ¯è¡¨èŽ·å–
        if (res.code == 200) {
          this.liftList = res.data
        }
      },
      addMoveAdvancePath(moveAdvancePath, shuttleNo) {//添加预计路径
        let that = this;
        moveAdvancePath.forEach((path, idx) => {
          let locNo = this.map[path.x, path.y];
          if (!pixiShuttleMoveAdvancePathMap.has(locNo)) {
            let graphics = getGraphics(0x9966ff, width, height, path.y * width, (path.x - 1) * height);
            let shuttleNos = [shuttleNo];
            // åˆ›å»ºæ–‡æœ¬å¯¹è±¡
            const style = new PIXI.TextStyle({
              fontFamily: 'Arial',
              fontSize: 10,
              fill: '#000000',
            });
            const text = new PIXI.Text(JSON.stringify(shuttleNos), style);
            text.anchor.set(0.5); // è®¾ç½®æ–‡æœ¬é”šç‚¹ä¸ºä¸­å¿ƒç‚¹
            text.position.set(graphics.width / 2, graphics.height / 2); // å°†æ–‡æœ¬ä½ç½®è®¾ç½®ä¸ºGraphics对象的中心点
            // å°†æ–‡æœ¬å¯¹è±¡æ·»åŠ åˆ°Graphics对象中
            graphics.addChild(text);
            graphics.textObj = text;
            objectsContainer2.addChild(graphics)
            pixiShuttleMoveAdvancePathMap.set(locNo, {
              path: path,
              sprite: graphics,
              textObj: text,
              shuttleNos: shuttleNos
            })
            if (pixiShuttleMoveAdvancePathList[shuttleNo] == null) {
              let locNos = new Set()
              locNos.add(locNo);
              pixiShuttleMoveAdvancePathList[shuttleNo] = locNos;
            }else {
              pixiShuttleMoveAdvancePathList[shuttleNo].add(locNo);
            }
          }else {
            let pathMap = pixiShuttleMoveAdvancePathMap.get(locNo)
            let shuttleNos = pathMap.shuttleNos;
            shuttleNos.push(shuttleNo);
            pathMap.textObj.text = JSON.stringify(shuttleNos);
            pixiShuttleMoveAdvancePathMap.set(locNo, pathMap);
            if (pixiShuttleMoveAdvancePathList[shuttleNo] == null) {
              let locNos = new Set()
              locNos.add(locNo);
              pixiShuttleMoveAdvancePathList[shuttleNo] = locNos;
            }else {
              pixiShuttleMoveAdvancePathList[shuttleNo].add(locNo);
            }
          }
        });
      },
      removeMoveAdvancePath(shuttleNo) {//删除预计路径
        let locNos = pixiShuttleMoveAdvancePathList[shuttleNo];
        if (locNos != null) {
          locNos.forEach((locNo,index) => {
            let pathMap = pixiShuttleMoveAdvancePathMap.get(locNo);
            if (pathMap != null) {
              let shuttleNos = pathMap.shuttleNos;
              let shuttleNosNew = [];
              shuttleNos.forEach((shuttle, idx) => {
                if (shuttle != shuttleNo) {
                  shuttleNosNew.push(shuttle);
                }
              });
              if (shuttleNosNew.length === 0) {
                //预计路径没有小车,直接删除路径
                objectsContainer2.removeChild(pathMap.sprite);
                pixiShuttleMoveAdvancePathMap.delete(locNo)
              }else {
                //预计路径存在其他小车,更新文字信息
                pathMap.textObj.text = JSON.stringify(shuttleNosNew);
                pathMap.shuttleNos = shuttleNosNew;
                pixiShuttleMoveAdvancePathMap.set(locNo, pathMap);
              }
            }
          })
        }
      },
    }
  })