#
Junjie
3 天以前 6daf900a09adcca981f620744bf89851654d88e0
#
15个文件已修改
14个文件已添加
1个文件已删除
1 文件已重命名
4633 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/ForkLiftController.java 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/LiftController.java 361 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/domain/vo/ForkLiftMsgTableVo.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/domain/vo/LiftMsgTableVo.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/BasLift.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/ForkMainServiceImpl.java 2023 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java 263 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/ws/ConsoleWebSocket.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/model/LiftPointModel.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/utils/LiftUtils.java 247 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/MainProcess.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/ServerBootstrap.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/action/ForkLiftAction.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/action/LiftAction.java 184 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/ForkLiftConfirmType.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/LiftIoModeType.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/LiftProtocolStatusType.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/LiftTaskModeType.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/enums/RedisKeyType.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/ForkLiftAssignCommand.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/ForkLiftRedisCommand.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/LiftAssignCommand.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/LiftCommand.java 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/command/LiftRedisCommand.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/protocol/ForkLiftStaProtocol.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/model/protocol/LiftProtocol.java 252 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/LiftThread.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/thread/impl/NyLiftThread.java 695 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/core/utils/DeviceMsgUtils.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/index.html 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/lift_old.html 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/ForkLiftController.java
@@ -81,12 +81,12 @@
    @PostMapping("/table/lift/msg")
    @ManagerAuth(memo = "提升机数据表")
    public R liftMsgTable(){
        List<LiftMsgTableVo> list = new ArrayList<>();
        List<ForkLiftMsgTableVo> list = new ArrayList<>();
        List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.ForkLift)));
        for (DeviceConfig device : forkliftList) {
            // 表格行
            LiftMsgTableVo vo = new LiftMsgTableVo();
            ForkLiftMsgTableVo vo = new ForkLiftMsgTableVo();
            vo.setLiftNo(device.getDeviceNo());   //  提升机号
            list.add(vo);
            // 获取提升机信息
@@ -186,7 +186,7 @@
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        ForkLiftRedisCommand redisCommand = JSON.parseObject(o.toString(), ForkLiftRedisCommand.class);
        return R.ok().add(redisCommand);
    }
@@ -198,7 +198,7 @@
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        ForkLiftRedisCommand redisCommand = JSON.parseObject(o.toString(), ForkLiftRedisCommand.class);
        redisCommand.setCommandStep(commandStep);
        redisUtil.set(RedisKeyType.FORK_LIFT_WORK_FLAG.key + wrkNo, JSON.toJSONString(redisCommand));
        return R.ok();
@@ -213,8 +213,8 @@
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        LiftAssignCommand assignCommand = redisCommand.getAssignCommand();
        ForkLiftRedisCommand redisCommand = JSON.parseObject(o.toString(), ForkLiftRedisCommand.class);
        ForkLiftAssignCommand assignCommand = redisCommand.getAssignCommand();
        List<ForkLiftCommand> commands = assignCommand.getCommands();
        ForkLiftCommand command = commands.get(commandStep);
        command.setComplete(complete != 0);
@@ -229,9 +229,9 @@
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        Short liftNo = redisCommand.getLiftNo();
        ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo.intValue());
        ForkLiftRedisCommand redisCommand = JSON.parseObject(o.toString(), ForkLiftRedisCommand.class);
        Integer liftNo = redisCommand.getLiftNo();
        ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
        if (forkLiftThread == null) {
            return R.error();
        }
@@ -243,7 +243,7 @@
            return R.error();
        }
        //提升机处于空闲状态,进行任务的恢复
        forkLiftThread.setSyncTaskNo(redisCommand.getWrkNo().intValue());//将提升机线程分配任务号
        forkLiftThread.setSyncTaskNo(redisCommand.getWrkNo());//将提升机线程分配任务号
        return R.ok();
    }
@@ -291,12 +291,12 @@
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            ForkLiftAssignCommand assignCommand = new ForkLiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo().shortValue());
            assignCommand.setTaskNo((short) workNo);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo());
            assignCommand.setTaskNo(workNo);
            assignCommand.setAuto(false);//手动模式
            assignCommand.setTaskMode(ForkLiftTaskModeType.SHUTTLE_SWITCH.id.shortValue());
            assignCommand.setTaskMode(ForkLiftTaskModeType.SHUTTLE_SWITCH.id);
            forkLiftAction.assignWork(forkLiftProtocol.getLiftNo(), assignCommand);
            return R.ok();
@@ -313,12 +313,12 @@
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            ForkLiftAssignCommand assignCommand = new ForkLiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo().shortValue());
            assignCommand.setTaskNo((short) workNo);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo());
            assignCommand.setTaskNo(workNo);
            assignCommand.setAuto(false);//手动模式
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id.shortValue());
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id);
            forkLiftAction.assignWork(forkLiftProtocol.getLiftNo(), assignCommand);
            return R.ok();
@@ -335,12 +335,12 @@
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            ForkLiftAssignCommand assignCommand = new ForkLiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo().shortValue());
            assignCommand.setTaskNo((short) workNo);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo());
            assignCommand.setTaskNo(workNo);
            assignCommand.setAuto(false);//手动模式
            assignCommand.setTaskMode(ForkLiftTaskModeType.MOVE.id.shortValue());
            assignCommand.setTaskMode(ForkLiftTaskModeType.MOVE.id);
            forkLiftAction.assignWork(forkLiftProtocol.getLiftNo(), assignCommand);
            return R.ok();
src/main/java/com/zy/asrs/controller/LiftController.java
New file
@@ -0,0 +1,361 @@
package com.zy.asrs.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.annotations.ManagerAuth;
import com.core.common.BaseRes;
import com.core.common.Cools;
import com.core.common.R;
import com.core.exception.CoolException;
import com.zy.asrs.domain.param.LiftOperatorParam;
import com.zy.asrs.domain.vo.LiftDataVo;
import com.zy.asrs.domain.vo.LiftMsgTableVo;
import com.zy.asrs.domain.vo.LiftSensorDataVo;
import com.zy.asrs.entity.BasLift;
import com.zy.asrs.entity.DeviceConfig;
import com.zy.asrs.service.BasLiftService;
import com.zy.asrs.service.DeviceConfigService;
import com.zy.common.service.CommonService;
import com.zy.common.utils.RedisUtil;
import com.zy.core.action.LiftAction;
import com.zy.core.cache.OutputQueue;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.*;
import com.zy.core.model.command.LiftAssignCommand;
import com.zy.core.model.command.LiftCommand;
import com.zy.core.model.command.LiftRedisCommand;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.model.protocol.LiftStaProtocol;
import com.zy.core.thread.LiftThread;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
 * 提升机接口
 */
@Slf4j
@RestController
@RequestMapping("/lift")
public class LiftController {
    @Autowired
    private CommonService commonService;
    @Autowired
    private BasLiftService basLiftService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private LiftAction liftAction;
    @Autowired
    private DeviceConfigService deviceConfigService;
    @PostMapping("/table/lift/state")
    @ManagerAuth(memo = "提升机信息表")
    public R liftStateTable(){
        ArrayList<JSONObject> list = new ArrayList<>();
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        for (DeviceConfig device : liftList) {
            // 表格行
            JSONObject baseObj = new JSONObject();
            baseObj.put("liftNo", device.getDeviceNo());
            list.add(baseObj);
            // 获取提升机信息
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getDeviceNo());
            if (liftThread == null) {
                continue;
            }
            LiftProtocol liftProtocol = liftThread.getStatus();
            if (liftProtocol == null) {
                continue;
            }
            JSONObject data = JSON.parseObject(JSON.toJSONString(liftProtocol));
            List<LiftStaProtocol> liftStaProtocols = liftThread.getLiftStaProtocols();
            data.put("liftStaProtocols", liftStaProtocols);
            baseObj.putAll(data);
        }
        return R.ok().add(list);
    }
    @PostMapping("/table/lift/msg")
    @ManagerAuth(memo = "提升机数据表")
    public R liftMsgTable(){
        List<LiftMsgTableVo> list = new ArrayList<>();
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        for (DeviceConfig device : liftList) {
            // 表格行
            LiftMsgTableVo vo = new LiftMsgTableVo();
            vo.setLiftNo(device.getDeviceNo());   //  提升机号
            list.add(vo);
            // 获取提升机信息
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getDeviceNo());
            if (liftThread == null) {
                continue;
            }
            LiftProtocol liftProtocol = liftThread.getStatus();
            if (liftProtocol == null) {
                continue;
            }
            vo.setWorkNo(liftProtocol.getTaskNo());//任务号
            vo.setPakMk(liftProtocol.getPakMk()?"Y" : "N");    // 作业标记
            vo.setLiftStaProtocols(liftThread.getLiftStaProtocols());
        }
        return R.ok().add(list);
    }
    @PostMapping("/output/lift")
    @ManagerAuth
    public R liftOutput(){
        StringBuilder str = new StringBuilder();
        String s;
        int i = 0;
        while((s = OutputQueue.LIFT.poll()) != null && i <=10) {
            str.append("\n").append(s);
            i++;
        }
        return R.ok().add(str.toString());
    }
    @GetMapping("/detl/{liftNo}")
    public R liftDetl(@PathVariable("liftNo") Integer liftNo){
        LiftDataVo vo = new LiftDataVo();
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        for (DeviceConfig device : liftList) {
            if (liftNo.equals(device.getDeviceNo())) {
                vo.setLiftNo(device.getDeviceNo());
                BasLift basLift = basLiftService.selectById(device.getDeviceNo());
                if (!Cools.isEmpty(basLift)) {
                    vo.setWorkNo(basLift.getWrkNo());
                    vo.setPakMk(basLift.getPakMk());
                }
                break;
            }
        }
        return R.ok().add(vo);
    }
    @GetMapping("/sensor/detl/{liftNo}")
    public R liftSensorDetl(@PathVariable("liftNo") Integer liftNo){
        LiftSensorDataVo vo = new LiftSensorDataVo();
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        for (DeviceConfig device : liftList) {
            if (liftNo.equals(device.getDeviceNo())) {
                vo.setLiftNo(device.getDeviceNo());
                // 获取提升机信息
                LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getDeviceNo());
                if (liftThread == null) {
                    return R.error("设备不在线");
                }
                LiftProtocol liftProtocol = liftThread.getStatus();
                if (liftProtocol == null) {
                    return R.error("设备不在线");
                }
                break;
            }
        }
        return R.ok().add(vo);
    }
    @PostMapping("/detl/update")
    @ManagerAuth(memo = "修改数据")
    public R liftUpdate(@RequestParam Integer liftNo,
                        @RequestParam Integer workNo) {
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return R.error("plc已掉线");
        }
        LiftProtocol liftProtocol = liftThread.getStatus();
        if (liftProtocol == null) {
            return R.error("plc已掉线");
        }
        if (workNo != null) {
            liftThread.setSyncTaskNo(workNo);
        }
        return R.ok();
    }
    @RequestMapping(value = "/command/query")
    public R liftCommandQuery(@RequestParam("wrkNo") Integer wrkNo) {
        Object o = redisUtil.get(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo);
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        return R.ok().add(redisCommand);
    }
    //回退命令
    @RequestMapping(value = "/command/rollback")
    public R liftCommandRollback(@RequestParam("wrkNo") Integer wrkNo
            , @RequestParam("commandStep") Integer commandStep) {
        Object o = redisUtil.get(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo);
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        redisCommand.setCommandStep(commandStep);
        redisUtil.set(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo, JSON.toJSONString(redisCommand));
        return R.ok();
    }
    //命令完成状态切换
    @RequestMapping(value = "/command/completeSwitch")
    public R liftCommandCompleteSwitch(@RequestParam("wrkNo") Integer wrkNo
            , @RequestParam("commandStep") Integer commandStep
            , @RequestParam("complete") Integer complete) {
        Object o = redisUtil.get(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo);
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        LiftAssignCommand assignCommand = redisCommand.getAssignCommand();
        List<LiftCommand> commands = assignCommand.getCommands();
        LiftCommand command = commands.get(commandStep);
        command.setComplete(complete != 0);
        redisUtil.set(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo, JSON.toJSONString(redisCommand));
        return R.ok();
    }
    //重启任务(命令)
    @RequestMapping(value = "/command/restart")
    public R liftCommandCompleteSwitch(@RequestParam("wrkNo") Integer wrkNo) {
        Object o = redisUtil.get(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo);
        if (o == null) {
            return R.error();
        }
        LiftRedisCommand redisCommand = JSON.parseObject(o.toString(), LiftRedisCommand.class);
        Integer liftNo = redisCommand.getLiftNo();
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return R.error();
        }
        LiftProtocol liftProtocol = liftThread.getStatus();
        if (liftProtocol == null) {
            return R.error();
        }
        if (!liftThread.isIdle()) {
            return R.error();
        }
        //提升机处于空闲状态,进行任务的恢复
        liftThread.setSyncTaskNo(redisCommand.getWrkNo());//将提升机线程分配任务号
        return R.ok();
    }
    //删除任务(命令)
    @RequestMapping(value = "/command/del")
    public R liftCommandDel(@RequestParam("wrkNo") Integer wrkNo) {
        Object o = redisUtil.get(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo);
        if (o == null) {
            return R.error();
        }
        redisUtil.del(RedisKeyType.LIFT_WORK_FLAG.key + wrkNo);
        return R.ok();
    }
    /****************************************************************/
    /************************** 手动操作 ******************************/
    /****************************************************************/
    @ManagerAuth(memo = "手动操作")
    @PostMapping("/operator/lift")
    public R liftOperator(LiftOperatorParam param){
        if (Cools.isEmpty(param.getLiftNo())) {
            return R.parse(BaseRes.PARAM);
        }
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, param.getLiftNo());
        if (liftThread == null) {
            throw new CoolException("提升机不在线");
        }
        LiftProtocol liftProtocol = liftThread.getStatus();
        if (liftProtocol == null) {
            throw new CoolException("提升机不在线");
        }
        if (param.getLiftTaskMode().equals(LiftTaskModeType.SHUTTLE_SWITCH.id)) {
            //小车换层
            int workNo = commonService.getWorkNo(WrkIoType.MANUAL.id);//获取任务号
            Integer startSta = param.getSourceStaNo();
            Integer targetSta = param.getStaNo();
            //获取提升机命令
            LiftCommand liftCommand = liftThread.getShuttleSwitchCommand(workNo, startSta, targetSta);
            ArrayList<LiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(liftProtocol.getLiftNo());
            assignCommand.setTaskNo(workNo);
            assignCommand.setAuto(false);//手动模式
            assignCommand.setTaskMode(LiftTaskModeType.SHUTTLE_SWITCH.id);
            liftAction.assignWork(liftProtocol.getLiftNo(), assignCommand);
            return R.ok();
        } else if (param.getLiftTaskMode().equals(LiftTaskModeType.PICK_PUT.id)) {
            //移动托盘
            int workNo = commonService.getWorkNo(WrkIoType.MANUAL.id);//获取任务号
            Integer startSta = param.getSourceStaNo();
            Integer targetSta = param.getStaNo();
            //获取提升机命令
            LiftCommand liftCommand = liftThread.getPickAndPutCommand(workNo, startSta, targetSta);
            ArrayList<LiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(liftProtocol.getLiftNo());
            assignCommand.setTaskNo(workNo);
            assignCommand.setAuto(false);//手动模式
            assignCommand.setTaskMode(LiftTaskModeType.PICK_PUT.id);
            liftAction.assignWork(liftProtocol.getLiftNo(), assignCommand);
            return R.ok();
        } else if (param.getLiftTaskMode().equals(LiftTaskModeType.MOVE.id)) {
            //移动
            int workNo = commonService.getWorkNo(WrkIoType.MANUAL.id);//获取任务号
            Integer startSta = param.getSourceStaNo();
            Integer targetSta = param.getStaNo();
            //获取提升机命令
            LiftCommand liftCommand = liftThread.getMoveCommand(workNo, startSta, targetSta);
            ArrayList<LiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(liftProtocol.getLiftNo());
            assignCommand.setTaskNo(workNo);
            assignCommand.setAuto(false);//手动模式
            assignCommand.setTaskMode(LiftTaskModeType.MOVE.id);
            liftAction.assignWork(liftProtocol.getLiftNo(), assignCommand);
            return R.ok();
        } else if (param.getLiftTaskMode().equals(LiftTaskModeType.RESET.id)) {
            //提升机复位
            liftThread.setSyncTaskNo(0);
            liftThread.setProtocolStatus(LiftProtocolStatusType.IDLE);
            return R.ok();
        } else {
            throw new CoolException("未知命令");
        }
    }
}
src/main/java/com/zy/asrs/domain/vo/ForkLiftMsgTableVo.java
New file
@@ -0,0 +1,30 @@
package com.zy.asrs.domain.vo;
import com.zy.core.model.protocol.ForkLiftStaProtocol;
import lombok.Data;
import java.util.List;
@Data
public class ForkLiftMsgTableVo {
    // 提升机号
    private Integer liftNo;
    // 工作号
    private Integer workNo = 0;
    // 作业标记
    private String pakMk = "-";
    /**
     * 站点信息
     */
    private List<ForkLiftStaProtocol> forkLiftStaProtocols;
    /**
     * 穿梭车号
     */
    private Integer shuttleNo;
}
src/main/java/com/zy/asrs/domain/vo/LiftMsgTableVo.java
@@ -1,6 +1,6 @@
package com.zy.asrs.domain.vo;
import com.zy.core.model.protocol.ForkLiftStaProtocol;
import com.zy.core.model.protocol.LiftStaProtocol;
import lombok.Data;
import java.util.List;
@@ -20,7 +20,7 @@
    /**
     * 站点信息
     */
    private List<ForkLiftStaProtocol> forkLiftStaProtocols;
    private List<LiftStaProtocol> liftStaProtocols;
    /**
     * 穿梭车号
src/main/java/com/zy/asrs/entity/BasLift.java
@@ -8,6 +8,7 @@
import java.util.ArrayList;
import java.util.Date;
import com.zy.common.model.LiftPointModel;
import com.zy.core.model.LiftStation;
import org.springframework.format.annotation.DateTimeFormat;
import com.core.common.SpringUtils;
@@ -137,4 +138,13 @@
        return list;
    }
    public LiftPointModel getPoint$(){
        if (Cools.isEmpty(this.point)){
            return null;
        }
        LiftPointModel liftPointModel = JSON.parseObject(point, LiftPointModel.class);
        return liftPointModel;
    }
}
src/main/java/com/zy/asrs/service/impl/ForkMainServiceImpl.java
New file
@@ -0,0 +1,2023 @@
package com.zy.asrs.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zy.asrs.domain.enums.NotifyMsgType;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.NotifyUtils;
import com.zy.asrs.utils.Utils;
import com.zy.common.model.MapNode;
import com.zy.common.model.enums.NavigationMapType;
import com.zy.common.service.CommonService;
import com.zy.common.utils.*;
import com.zy.core.News;
import com.zy.core.action.ForkLiftAction;
import com.zy.core.action.ShuttleAction;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.dispatcher.ShuttleDispatchUtils;
import com.zy.core.enums.*;
import com.zy.core.model.command.*;
import com.zy.core.model.protocol.ForkLiftProtocol;
import com.zy.core.model.protocol.ForkLiftStaProtocol;
import com.zy.core.model.protocol.ShuttleProtocol;
import com.zy.core.thread.ForkLiftThread;
import com.zy.core.thread.ShuttleThread;
import com.zy.system.entity.Config;
import com.zy.system.service.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * 立体仓库WCS系统主流程业务
 * Created by vincent on 2020/8/6
 */
@Slf4j
@Service("forkMainService")
public class ForkMainServiceImpl {
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
    private BasShuttleErrLogService basShuttleErrLogService;
    @Autowired
    private BasLiftErrLogService basLiftErrLogService;
    @Autowired
    private BasShuttleErrService basShuttleErrService;
    @Autowired
    private BasLiftErrService basLiftErrService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private BasMapService basMapService;
    @Autowired
    private ShuttleDispatchUtils shuttleDispatchUtils;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ConfigService configService;
    @Autowired
    private NavigateMapUtils navigateMapUtils;
    @Autowired
    private NavigateMapData navigateMapData;
    @Autowired
    private NavigateUtils navigateUtils;
    @Autowired
    private ShuttleOperaUtils shuttleOperaUtils;
    @Autowired
    private ShuttleAction shuttleAction;
    @Autowired
    private ForkLiftAction forkLiftAction;
    @Autowired
    private NotifyUtils notifyUtils;
    @Autowired
    private BasShuttleChargeService basShuttleChargeService;
    @Autowired
    private DeviceConfigService deviceConfigService;
    /**
     * 初始化实时地图
     */
    public synchronized void initRealtimeBasMap() {
        try {
            List<BasMap> basMaps = basMapService.selectList(new EntityWrapper<BasMap>().orderBy("lev", true));
            for (BasMap basMap : basMaps) {
                Integer lev = basMap.getLev();
                Object data = redisUtil.get(RedisKeyType.MAP.key + lev);
                if (data == null) {//redis地图数据为空
                    //载入地图
                    List<List<MapNode>> lists = navigateMapData.getJsonOriginData(lev, NavigationMapType.getMapTypes(NavigationMapType.NONE), null, null);//获取完整地图(包括入库出库)
                    //存入数据库
                    basMap.setData(JSON.toJSONString(lists));
                    basMap.setCreateTime(new Date());
                    basMap.setUpdateTime(new Date());
                    if (!basMapService.updateById(basMap)) {
                        log.info("地图数据存储失败");
                    }
                    //将数据库地图数据存入redis
                    redisUtil.set(RedisKeyType.MAP.key + lev, JSON.toJSONString(basMap));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 入库  ===>>  四向穿梭车入库作业下发
     */
    public synchronized void shuttleInExecute() {
        try {
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .in("wrk_sts"
                            , WrkStsType.INBOUND_LIFT_RUN_COMPLETE.sts
                    )
                    .orderBy("io_pri", false)
                    .orderBy("appe_time", true)
            );
            for (WrkMast wrkMast : wrkMasts) {
                boolean step1 = this.shuttleInExecuteStep1(wrkMast);//小车搬入库中
                Thread.sleep(100);
                if (!step1) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 入库-小车搬入库中
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    public synchronized boolean shuttleInExecuteStep1(WrkMast wrkMast) {
        if (wrkMast.getWrkSts() == WrkStsType.INBOUND_LIFT_RUN_COMPLETE.sts) {
            //获取目标站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (liftSta == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,缺少站点信息,禁止派发", wrkMast.getWrkNo());
                return false;
            }
            if (wrkMast.getShuttleNo() == null) {//没有绑定小车,进行调度
                boolean result = shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), liftSta.getLocNo());//调度小车到货物所在输送站点进行取货
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,调度小车{}系统等待中", wrkMast.getWrkNo(), result ? "成功" : "失败");
                return false;
            }
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            if (!shuttleThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车忙碌中", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            //判断小车是否存在移动任务
            WrkMast hasMoveWorking = wrkMastService.selectShuttleHasMoveWorking(wrkMast.getShuttleNo());
            if (hasMoveWorking != null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}号小车,存在移动任务,禁止派发任务", wrkMast.getShuttleNo());
                return false;//存在移动任务,禁止执行入库任务
            }
            //判断小车是否到达输送站点库位
            if (!shuttleProtocol.getCurrentLocNo().equals(liftSta.getLocNo())) {
                //小车不在输送站点位置
                shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), liftSta.getLocNo(), wrkMast.getShuttleNo());//调度小车到货物所在输送站点进行取货
                News.info("{}任务,{}小车,未到达输送站点,系统等待中", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            //检测障碍物车
            boolean checkObstacle = shuttleOperaUtils.checkObstacle(wrkMast.getLocNo(), new ArrayList<Integer>() {{
                add(shuttleProtocol.getShuttleNo());
            }}, new ArrayList<>());
            if (checkObstacle) {
                News.info("{}任务,避障范围有小车,等待障碍小车调离中", wrkMast.getWrkNo());
                return false;
            }
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo()); // 四向穿梭车编号
            assignCommand.setTaskMode(ShuttleTaskModeType.TRANSPORT.id);//小车移库任务
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setAuto(true);//自动模式
            //获取小车到输送站点行走命令
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(liftSta.getLocNo(), wrkMast.getLocNo(), NavigationMapType.getDfxWithDevice(), assignCommand, shuttleThread);
            if (commands == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,路径计算失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            List<ShuttleCommand> liftCommand = shuttleOperaUtils.getShuttleLiftCommand(assignCommand, shuttleThread, true);
            if (liftCommand == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车获取顶升命令失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            List<ShuttleCommand> liftCommand2 = shuttleOperaUtils.getShuttleLiftCommand(assignCommand, shuttleThread, false);
            if (liftCommand2 == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车获取下降命令失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            commands.add(0, liftCommand.get(0));
            commands.add(liftCommand2.get(0));
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.INBOUND_SHUTTLE_RUN.sts);//小车搬运中  4.提升机搬运完成 ==> 5.小车搬运中
            wrkMast.setModiTime(new Date());
            wrkMast.setSystemMsg("");//清空消息
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
                //触发通知
                notifyUtils.notify(String.valueOf(SlaveType.Shuttle), shuttleProtocol.getShuttleNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.SHUTTLE_TRANSPORT);
                return false;
            }
            return false;
        }
        return true;
    }
    /**
     * 出库  ===>>  四向穿梭车出库作业下发
     */
    public synchronized void shuttleOutExecute() {
        try {
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .in("wrk_sts"
                            , WrkStsType.NEW_OUTBOUND.sts
                    )
                    .orderBy("io_pri", false)
                    .orderBy("appe_time", true)
            );
            for (WrkMast wrkMast : wrkMasts) {
                boolean step1 = this.shuttleOutExecuteStep1(wrkMast);//小车搬出库中
                Thread.sleep(100);
                if (!step1) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 出库-小车搬出库中
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    public synchronized boolean shuttleOutExecuteStep1(WrkMast wrkMast) {
        //101.生成出库任务 => 102.小车搬运中
        if (wrkMast.getWrkSts() == WrkStsType.NEW_OUTBOUND.sts) {
            Integer liftNo = wrkMast.getLiftNo();
            if (liftNo == null) {
                //通过输送线站号获取提升机号
                liftNo = ForkLiftUtils.getConveyorBindLiftNo(wrkMast.getStaNo());
                if (liftNo == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,未找到匹配的提升机", wrkMast.getWrkNo());
                    return false;
                }
            }
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
            if (forkLiftThread == null) {
                return false;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                return false;
            }
            //判断提升机是否处于出库模式
            if (!forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.OUT)) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,提升机不处于出库模式,禁止出库", wrkMast.getWrkNo());
                return false;
            }
            //获取源站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByLev(liftNo, Utils.getLev(wrkMast.getSourceLocNo()));
            if (liftSta == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,缺少站点信息,禁止派发", wrkMast.getWrkNo());
                return false;
            }
            if (liftSta.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}站点存在小车,禁止派发", wrkMast.getWrkNo(), liftSta.getStaNo());
                return false;
            }
            if (liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}站点有托盘,禁止派发", wrkMast.getWrkNo(), liftSta.getStaNo());
                return false;
            }
            List<WrkMast> shuttleMoveList = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .eq("io_type", 200)
            );
            for (WrkMast moveWrkMast : shuttleMoveList) {
                if(Utils.getLev(moveWrkMast.getLocNo()) != Utils.getLev(wrkMast.getSourceLocNo())) {
                    continue;
                }
                if(Utils.getLev(moveWrkMast.getLocNo()) == Utils.getLev(moveWrkMast.getSourceLocNo())) {
                    continue;
                }
                //存在换层任务,出库任务暂时不执行
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,存在换层任务,出库任务等待中", wrkMast.getWrkNo());
                return false;
            }
            boolean checkLocPathIsAvailable = navigateUtils.checkLocPathIsAvailable(wrkMast.getSourceLocNo(), liftSta.getLocNo());
            if(!checkLocPathIsAvailable) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,未计算到可执行路径,等待中", wrkMast.getWrkNo());
                return false;
            }
            if (wrkMast.getShuttleNo() == null) {//没有绑定小车,进行调度
                //强制预留一台小车给入库任务
                int lev = Utils.getLev(wrkMast.getSourceLocNo());
                //获取当前楼层有几台可用小车
                int shuttleCount = shuttleDispatchUtils.getShuttleEnableUseCountByLev(lev);
                if (shuttleCount >= 2) {//只有可用小车数量大于2,才进行入库任务预留小车
                    int shuttleWrkInObligateCount = 1;//预留小车数量
                    Config config = configService.selectOne(new EntityWrapper<Config>().eq("code", "shuttleWrkInObligateCount").eq("status", 1));
                    if (config != null) {
                        shuttleWrkInObligateCount = Integer.parseInt(config.getValue());
                    }
                    //可用出库小车数量(给入库任务预留一台车)
                    int useShuttleCount = shuttleCount - shuttleWrkInObligateCount;
                    //查询楼层已分配车辆的出库任务数量
                    List<WrkMast> wrkMasts = wrkMastService.selectShuttleOutWrkByLev(lev);
                    if (wrkMasts.size() >= useShuttleCount) {
                        News.taskInfo(wrkMast.getWrkNo(), "{}任务,当前楼层可用小车{}台,出库任务已分配{}台,系统等待中。", wrkMast.getWrkNo(), useShuttleCount, wrkMasts.size());
                        return false;
                    }
                }
                boolean result = shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), wrkMast.getSourceLocNo());//调度小车到货物所在库位进行取货
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,调度小车{}系统等待中。", wrkMast.getWrkNo(), result ? "成功" : "失败");
                return false;
            }
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            if (!shuttleThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,忙碌中", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            //判断小车是否到达货物库位
            if (!shuttleProtocol.getCurrentLocNo().equals(wrkMast.getSourceLocNo())) {
                //检测障碍物车
                boolean checkObstacle = shuttleOperaUtils.checkObstacle(wrkMast.getSourceLocNo(), new ArrayList<Integer>() {{
                    add(shuttleProtocol.getShuttleNo());
                }}, new ArrayList<>());
                if (checkObstacle) {
                    News.info("{}任务,避障范围有小车,等待障碍小车调离中", wrkMast.getWrkNo());
                    return false;
                }
                //小车不在输送站点位置
                shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), wrkMast.getSourceLocNo(), wrkMast.getShuttleNo());//调度小车到货物所在库位进行取货
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,未到达输送站点,系统等待中", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            //检测是否存在移动任务
            WrkMast moveWorking = wrkMastService.selectShuttleHasMoveWorking(wrkMast.getShuttleNo());
            if (moveWorking != null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车存在移动任务", wrkMast.getWrkNo());
                return false;
            }
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo()); // 四向穿梭车编号
            assignCommand.setTaskMode(ShuttleTaskModeType.TRANSPORT.id);//小车移库任务
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setAuto(true);//自动模式
            //获取小车到输送站点行走命令
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(wrkMast.getSourceLocNo(), liftSta.getLocNo(), NavigationMapType.getDfxWithDevice(), assignCommand, shuttleThread);
            if (commands == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,路径计算失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            List<ShuttleCommand> liftCommand = shuttleOperaUtils.getShuttleLiftCommand(assignCommand, shuttleThread, true);
            if (liftCommand == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车获取顶升命令失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            List<ShuttleCommand> liftCommand2 = shuttleOperaUtils.getShuttleLiftCommand(assignCommand, shuttleThread, false);
            if (liftCommand2 == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车获取下降命令失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            commands.add(0, liftCommand.get(0));
            commands.add(liftCommand2.get(0));
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.OUTBOUND_SHUTTLE_RUN.sts);//小车搬运中  101.生成出库任务 ==> 102.小车搬运中
            wrkMast.setSourceStaNo(liftSta.getStaNo());
            wrkMast.setModiTime(new Date());
            wrkMast.setSystemMsg("");//清空消息
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
                //触发通知
                notifyUtils.notify(String.valueOf(SlaveType.Shuttle), shuttleProtocol.getShuttleNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.SHUTTLE_TRANSPORT);
                return false;
            }
            return false;
        }
        return true;
    }
    /**
     * 执行移库任务
     */
    public synchronized void shuttleLocMoveExecute() {
        try {
            //查询移库任务
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .in("wrk_sts", WrkStsType.NEW_LOC_MOVE.sts)
                    .orderBy("io_pri", false)
                    .orderBy("appe_time", true)
            );
            for (WrkMast wrkMast : wrkMasts) {
                boolean stepToTarget = this.shuttleLocMoveExecuteToTarget(wrkMast);//移库任务-小车去目标点
                if (!stepToTarget) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 移库任务-小车去目标点
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean shuttleLocMoveExecuteToTarget(WrkMast wrkMast) {
        //--------------------------------------小车移动至站点-----------------------------------------//
        Date now = new Date();
        //小车移动至站点  501.生成移库任务 ==> 502.小车搬运中
        if (wrkMast.getWrkSts() == WrkStsType.NEW_LOC_MOVE.sts) {
            boolean checkLocPathIsAvailable = navigateUtils.checkLocPathIsAvailable(wrkMast.getSourceLocNo(), wrkMast.getLocNo());
            if(!checkLocPathIsAvailable) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,未计算到可执行路径,等待中", wrkMast.getWrkNo());
                return false;
            }
            if (wrkMast.getShuttleNo() == null) {//没有绑定小车,进行调度
                boolean result = shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), wrkMast.getSourceLocNo());//调度小车到货物点进行取货
                News.info("{}任务,调度小车{}系统等待中", wrkMast.getWrkNo(), result ? "成功" : "失败");
                return false;
            }
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            if (shuttleProtocol.getCurrentLocNo() == null) {
                return false;
            }
            //判断小车是否到达货物库位
            if (!shuttleProtocol.getCurrentLocNo().equals(wrkMast.getSourceLocNo())) {
                //小车未到达取货位置
                shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), wrkMast.getSourceLocNo(), wrkMast.getShuttleNo());//调度小车到货物所在库位进行取货
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车未到达取货位置", wrkMast.getWrkNo(), wrkMast.getSourceLocNo());
                return false;
            }
            //检测是否存在移动任务
            WrkMast moveWorking = wrkMastService.selectShuttleHasMoveWorking(wrkMast.getShuttleNo());
            if (moveWorking != null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车存在移动任务", wrkMast.getWrkNo());
                return false;
            }
            //检测障碍物车
            boolean checkObstacle = shuttleOperaUtils.checkObstacle(wrkMast.getLocNo(), new ArrayList<Integer>() {{
                add(shuttleProtocol.getShuttleNo());
            }}, new ArrayList<>());
            if (checkObstacle) {
                News.info("{}任务,避障范围有小车,等待障碍小车调离中", wrkMast.getWrkNo());
                return false;
            }
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo()); // 四向穿梭车编号
            assignCommand.setTaskMode(ShuttleTaskModeType.TRANSPORT.id);//小车移库任务
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setAuto(true);//自动模式
            assignCommand.setLocNo(wrkMast.getLocNo());
            //获取小车到输送站点行走命令
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(wrkMast.getSourceLocNo(), wrkMast.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.DFX), assignCommand, shuttleThread);
            if (commands == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,路径计算失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            List<ShuttleCommand> liftCommand = shuttleOperaUtils.getShuttleLiftCommand(assignCommand, shuttleThread, true);
            if (liftCommand == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车获取顶升命令失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            List<ShuttleCommand> liftCommand2 = shuttleOperaUtils.getShuttleLiftCommand(assignCommand, shuttleThread, false);
            if (liftCommand2 == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车获取下降命令失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            commands.add(0, liftCommand.get(0));
            commands.add(liftCommand2.get(0));
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.LOC_MOVE_SHUTTLE_RUN.sts);//小车搬运中  501.生成移库任务 ==> 502.小车搬运中
            wrkMast.setModiTime(now);
            wrkMast.setSystemMsg("");//清空消息
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
                //触发通知
                notifyUtils.notify(String.valueOf(SlaveType.Shuttle), shuttleProtocol.getShuttleNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.SHUTTLE_MOVING);
                return false;
            }
            return false;
        }
        return true;
    }
    /**
     * 货叉提升机任务
     */
    public synchronized void forkLiftIoExecute() {
        try {
            //搜索是否有待处理的任务
            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .in("wrk_sts", WrkStsType.NEW_INBOUND.sts, WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts));
            if (wrkMasts.isEmpty()) {
                return;
            }
            for (WrkMast wrkMast : wrkMasts) {
                boolean stepIn = this.liftIoExecuteStepIn(wrkMast);//提升机入库
                if (!stepIn) {
                    continue;
                }
                boolean stepOut = this.liftIoExecuteStepOut(wrkMast);//提升机出库
                if (!stepOut) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 提升机入库
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean liftIoExecuteStepIn(WrkMast wrkMast) {
        //--------------------------------------提升机入库-----------------------------------------//
        Date now = new Date();
        //1.生成入库任务 ==> 3.提升机搬运中
        if (wrkMast.getWrkSts() == WrkStsType.NEW_INBOUND.sts) {
            //获取目标输送站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (liftSta == null) {
                return false;//找不到站点
            }
            if (liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftSta.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在小车", wrkMast.getWrkNo());
                return false;
            }
            //检测楼层是否有可用穿梭车
            boolean checkLevHasShuttle = Utils.checkLevHasShuttle(liftSta.getLev());
            if (!checkLevHasShuttle) {
                if (wrkMast.getShuttleNo() != null) {
                    return false;
                }
                //获取小车待机位
                String standbyLocNo = Utils.getShuttleStandbyLocNo(liftSta.getLocNo());
                if (standbyLocNo == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,获取小车待机位失败", wrkMast.getWrkNo());
                    return false;
                }
                //调度小车去待机位
                boolean dispatchShuttle = shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), standbyLocNo);
                if (!dispatchShuttle) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,调度小车失败", wrkMast.getWrkNo());
                    return false;
                }
                return false;
            }
            Integer liftNo = wrkMast.getLiftNo();
            if (liftNo == null) {
                //未分配提升机
                Integer staNo = wrkMast.getSourceStaNo();
                liftNo = ForkLiftUtils.getConveyorBindLiftNo(staNo);
                if(liftNo == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,未找到匹配的提升机", wrkMast.getWrkNo());
                    return false;
                }
                //申请提升机资源
                boolean applyForkLift = forkLiftAction.applyForkLift(liftNo, wrkMast.getWrkNo());
                if(!applyForkLift) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,申请提升机资源失败,禁止入库", wrkMast.getWrkNo());
                    return false;
                }
                return false;
            }
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
            if (forkLiftThread == null) {
                return false;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                return false;
            }
            if (!forkLiftThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机,忙碌中", wrkMast.getWrkNo(), liftSta.getLiftNo());
                return false;
            }
            //判断提升机是否处于入库模式
            if (!forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.IN)) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,提升机不处于入库模式,禁止入库", wrkMast.getWrkNo());
                return false;
            }
            //请求上级系统,是否允许入库
            boolean inMission = ForkLiftUtils.queryInMission(wrkMast.getSourceStaNo(), liftSta.getLiftNo(), wrkMast.getWmsWrkNo());
            if (!inMission) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,上级系统不允许入库", wrkMast.getWrkNo());
                return false;
            }
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getPickAndPutCommand(wrkMast.getWrkNo(), wrkMast.getSourceStaNo(), liftSta.getLev());
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            ForkLiftAssignCommand assignCommand = new ForkLiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(liftNo);
            assignCommand.setTaskNo(wrkMast.getWrkNo());
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id);
            wrkMast.setWrkSts(WrkStsType.INBOUND_LIFT_RUN.sts);//提升机搬运中  1.生成入库任务 ==> 3.提升机搬运中
            wrkMast.setSystemMsg("");//清空消息
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                forkLiftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
            }
            return false;
        }
        return true;
    }
    /**
     * 提升机出库
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean liftIoExecuteStepOut(WrkMast wrkMast) {
        //--------------------------------------提升机出库-----------------------------------------//
        //103.小车搬运完成 ==> 104.提升机搬运中
        if (wrkMast.getWrkSts() == WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts) {
            //获取源站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,找不到站点,禁止派发", wrkMast.getWrkNo());
                return false;//找不到站点
            }
            if(wrkMast.getShuttleNo() != null) {
                ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
                if (shuttleThread == null) {
                    return false;
                }
                ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
                if(shuttleProtocol == null) {
                    return false;
                }
                if (shuttleProtocol.getCurrentLocNo().equals(liftSta.getLocNo())) {
                    //小车还在输送站点
                    //获取小车待机位
                    String standbyLocNo = Utils.getShuttleStandbyLocNo(liftSta.getLocNo());
                    if (standbyLocNo == null) {
                        News.taskInfo(wrkMast.getWrkNo(), "{}任务,获取小车待机位失败", wrkMast.getWrkNo());
                        return false;
                    }
                    //调度小车去待机位
                    boolean dispatchShuttle = shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), standbyLocNo, wrkMast.getShuttleNo());
                    if (!dispatchShuttle) {
                        News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车在输送站点调度小车避让失败", wrkMast.getWrkNo());
                        return false;
                    }
                } else {
                    //小车已不在输送站点位置,释放小车
                    wrkMast.setShuttleNo(null);//释放小车
                    wrkMast.setModiTime(new Date());
                    wrkMastService.updateById(wrkMast);
                    return false;
                }
                return false;
            }
            if (liftSta.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}站点存在小车,禁止派发", wrkMast.getWrkNo(), liftSta.getStaNo());
                return false;
            }
            if (!liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}站点无托盘,禁止派发", wrkMast.getWrkNo(), liftSta.getStaNo());
                return false;
            }
            Integer liftNo = wrkMast.getLiftNo();
            if (liftNo == null) {
                //未分配提升机
                Integer staNo = wrkMast.getStaNo();
                liftNo = ForkLiftUtils.getConveyorBindLiftNo(staNo);
                if(liftNo == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,未找到匹配的提升机", wrkMast.getWrkNo());
                    return false;
                }
                //申请提升机资源
                boolean applyForkLift = forkLiftAction.applyForkLift(liftSta.getLiftNo(), wrkMast.getWrkNo());
                if(!applyForkLift) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,申请提升机资源失败,禁止执行出库", wrkMast.getWrkNo());
                    return false;
                }
                return false;
            }
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
            if (forkLiftThread == null) {
                return false;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                return false;
            }
            if (!forkLiftThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机,忙碌中", wrkMast.getWrkNo(), liftSta.getLiftNo());
                return false;
            }
            //判断提升机是否处于出库模式
            if (!forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.OUT)) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,提升机不处于出库模式,禁止出库", wrkMast.getWrkNo());
                return false;
            }
            //请求上级系统,是否允许出库
            boolean outMission = ForkLiftUtils.queryOutMission(wrkMast.getStaNo());
            if (!outMission) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,上级系统不允许出库", wrkMast.getWrkNo());
                return false;
            }
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getPickAndPutCommand(wrkMast.getWrkNo(), liftSta.getLev(), wrkMast.getStaNo());
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            ForkLiftAssignCommand assignCommand = new ForkLiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(liftNo);
            assignCommand.setTaskNo(wrkMast.getWrkNo());
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id);
            wrkMast.setWrkSts(WrkStsType.OUTBOUND_LIFT_RUN.sts);//提升机搬运中  103.生成入库任务 ==> 104.提升机搬运中
            wrkMast.setShuttleNo(null);//释放小车
            wrkMast.setSystemMsg("");//清空消息
            wrkMast.setModiTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                forkLiftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
            }
            return false;
        }
        return true;
    }
    /**
     * 货叉提升机任务完成
     */
    public synchronized void forkLiftFinished() {
        try {
            List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                    .eq("device_type", String.valueOf(SlaveType.ForkLift)));
            for (DeviceConfig device : forkliftList) {
                //获取提升机信息
                ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, device.getDeviceNo());
                if(forkLiftThread == null) {
                    continue;
                }
                ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
                if (forkLiftProtocol == null) {
                    continue;
                }
                //提升机为等待确认且空闲
                if (forkLiftProtocol.getProtocolStatus() == ForkLiftProtocolStatusType.WAITING.id
                        && forkLiftProtocol.getWrkNo() != 0
                ) {
                    //将任务档标记为完成
                    WrkMast wrkMast = wrkMastService.selectByWorkNo(forkLiftProtocol.getWrkNo());
                    if (wrkMast != null) {
                        if (wrkMast.getWrkSts() == WrkStsType.INBOUND_LIFT_RUN.sts) {
                            //3.提升机搬运中 ==> 4.提升机搬运完成
                            wrkMast.setWrkSts(WrkStsType.INBOUND_LIFT_RUN_COMPLETE.sts);
                            wrkMast.setLiftNo(null);//释放提升机
                            forkLiftThread.setSyncTaskNo(0);
                        } else if (wrkMast.getWrkSts() == WrkStsType.OUTBOUND_LIFT_RUN.sts) {
                            //104.提升机搬运中 ==> 109.出库完成
                            wrkMast.setWrkSts(WrkStsType.COMPLETE_OUTBOUND.sts);
                            wrkMast.setLiftNo(null);//释放提升机
                            forkLiftThread.setSyncTaskNo(0);
                            redisUtil.set(RedisKeyType.FORK_LIFT_PUT_COMPLETE.key + forkLiftProtocol.getLiftNo(), wrkMast.getWmsWrkNo(), 60 * 3);
                        } else if (wrkMast.getWrkSts() == WrkStsType.MOVE_LIFT_RUN.sts) {
                            //306.提升机搬运中 ==> 307.提升机搬运完成
                            wrkMast.setWrkSts(WrkStsType.MOVE_LIFT_RUN_COMPLETE.sts);
                            forkLiftThread.setSyncTaskNo(0);
                        }
                        wrkMast.setModiTime(new Date());
                        if (wrkMastService.updateById(wrkMast)) {
                            forkLiftThread.reset();
                            News.info("提升机已确认且任务完成状态。提升机号={}", forkLiftProtocol.getLiftNo());
                        } else {
                            News.error("提升机已确认且任务完成状态,复位失败,但未找到工作档。提升机号={},工作号={}", forkLiftProtocol.getLiftNo(), forkLiftProtocol.getWrkNo());
                        }
                    }else {
                        boolean checkPreviewDispatchForkLift = commonService.checkWorkNoContainMk(forkLiftProtocol.getWrkNo(), WrkIoType.FORKLIFT_MOVE.id);
                        if (checkPreviewDispatchForkLift) {
                            //属于提升机预调度移动任务
                            //无工作档支撑,直接确认完成
                            forkLiftThread.setSyncTaskNo(0);
                            forkLiftThread.reset();
                            News.info("已确认提升机预调度移动任务。提升机号={}", forkLiftProtocol.getLiftNo());
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 异常信息记录
     */
    public void recErr() {
        try {
            this.recShuttleErr();
            this.recLiftErr();
        } catch (Exception e) {
            News.error("recErr fail", e);
        }
    }
    /**
     * 四向穿梭车异常信息记录
     */
    private void recShuttleErr() {
        Date now = new Date();
        List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Shuttle)));
        for (DeviceConfig device : shuttleList) {
            // 获取四向穿梭车信息
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getDeviceNo());
            if (shuttleThread == null) {
                continue;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                continue;
            }
            if (shuttleProtocol.getTaskNo() != 0) {
                //有任务
                BasShuttleErrLog latest = basShuttleErrLogService.findLatestByTaskNo(device.getDeviceNo(), shuttleProtocol.getTaskNo());
                // 有异常
                if (latest == null) {
                    if (shuttleProtocol.getErrorCode() != null && Integer.parseInt(shuttleProtocol.getErrorCode()) != 0) {
                        WrkMast wrkMast = wrkMastService.selectByWorkNo(shuttleProtocol.getTaskNo());
                        if (wrkMast == null) {
                            continue;
                        }
                        int errorCode = Integer.parseInt(shuttleProtocol.getErrorCode());
                        BasShuttleErr basShuttleErr = basShuttleErrService.queryByCode(errorCode);
                        String errName = basShuttleErr==null? "未知异常":basShuttleErr.getErrName();
                        BasShuttleErrLog basShuttleErrLog = new BasShuttleErrLog(
                                null,    // 编号
                                wrkMast.getWrkNo(),    // 工作号
                                now,    // 发生时间
                                null,    // 结束时间
                                wrkMast.getWrkSts(),    // 工作状态
                                wrkMast.getIoType(),    // 入出库类型
                                device.getDeviceNo(),    // 四向穿梭车
                                null,    // plc
                                wrkMast.getLocNo(),    // 目标库位
                                wrkMast.getStaNo(),    // 目标站
                                wrkMast.getSourceStaNo(),    // 源站
                                wrkMast.getSourceLocNo(),    // 源库位
                                wrkMast.getBarcode(),    // 条码
                                errorCode,    // 异常码
                                errName,    // 异常
                                1,    // 异常情况
                                now,    // 添加时间
                                null,    // 添加人员
                                now,    // 修改时间
                                null,    // 修改人员
                                "任务中异常",    // 备注
                                JSON.toJSONString(shuttleProtocol)    // 系统状态数据
                        );
                        if (!basShuttleErrLogService.insert(basShuttleErrLog)) {
                            News.error("四向穿梭车plc异常记录失败 ===>> [id:{}] [error:{}]", device.getDeviceNo(), errName);
                        }
                    }
                } else {
                    // 异常修复
                    if (shuttleProtocol.getErrorCode() == null || Integer.parseInt(shuttleProtocol.getErrorCode()) == 0) {
                        latest.setEndTime(now);
                        latest.setUpdateTime(now);
                        latest.setStatus(2);
                        if (!basShuttleErrLogService.updateById(latest)) {
                            News.error("四向穿梭车plc异常记录修复失败 ===>> [id:{}] [errLogId:{}]", device.getDeviceNo(), latest.getId());
                        }
                    }
                }
            }
        }
    }
    /**
     * 提升机异常信息记录
     */
    private void recLiftErr() {
        Date now = new Date();
        List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.ForkLift)));
        for (DeviceConfig device : forkliftList) {
            // 获取提升机信息
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, device.getDeviceNo());
            if (forkLiftThread == null) {
                continue;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                continue;
            }
            if (forkLiftProtocol.getTaskNo() != 0) {
                //有任务
                BasLiftErrLog latest = basLiftErrLogService.findLatestByTaskNo(device.getDeviceNo(), forkLiftProtocol.getTaskNo());
                // 有异常
                if (latest == null) {
                    if (forkLiftProtocol.getErrorCode() != null && forkLiftProtocol.getErrorCode() != 0) {
                        WrkMast wrkMast = wrkMastService.selectByWorkNo(forkLiftProtocol.getWrkNo());
                        if (wrkMast == null) {
                            continue;
                        }
                        BasLiftErr basLiftErr = basLiftErrService.queryByCode(forkLiftProtocol.getErrorCode());
                        String errName = basLiftErr==null? "未知异常":basLiftErr.getErrName();
                        BasLiftErrLog basLiftErrLog = new BasLiftErrLog(
                                null,    // 编号
                                wrkMast.getWrkNo(),    // 工作号
                                now,    // 发生时间
                                null,    // 结束时间
                                wrkMast.getWrkSts(),    // 工作状态
                                wrkMast.getIoType(),    // 入出库类型
                                device.getDeviceNo(),    // 提升机
                                null,    // plc
                                wrkMast.getLocNo(),    // 目标库位
                                wrkMast.getStaNo(),    // 目标站
                                wrkMast.getSourceStaNo(),    // 源站
                                wrkMast.getSourceLocNo(),    // 源库位
                                wrkMast.getBarcode(),    // 条码
                                null,    // 异常码
                                errName,    // 异常
                                1,    // 异常情况
                                now,    // 添加时间
                                null,    // 添加人员
                                now,    // 修改时间
                                null,    // 修改人员
                                "任务中异常",    // 备注
                                JSON.toJSONString(forkLiftProtocol)    // 系统状态数据
                        );
                        if (!basLiftErrLogService.insert(basLiftErrLog)) {
                            News.error("提升机plc异常记录失败 ===>> [id:{}] [error:{}]", device.getDeviceNo(), errName);
                        }
                    }
                } else {
                    // 异常修复
                    if (forkLiftProtocol.getErrorCode() == null || forkLiftProtocol.getErrorCode() == 0) {
                        latest.setEndTime(now);
                        latest.setUpdateTime(now);
                        latest.setStatus(2);
                        if (!basLiftErrLogService.updateById(latest)) {
                            News.error("提升机plc异常记录修复失败 ===>> [id:{}] [errLogId:{}]", device.getDeviceNo(), latest.getId());
                        }
                    }
                }
            }
        }
    }
    /**
     * 四向穿梭车电量检测 ===>> 发起充电
     */
    public synchronized void loopShuttleCharge() {
        try {
            List<BasShuttleCharge> charges = basShuttleChargeService.selectList(new EntityWrapper<BasShuttleCharge>().orderBy("charge_id", true));
            if (charges.isEmpty()) {
                return;//无充电桩
            }
            List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                    .eq("device_type", String.valueOf(SlaveType.Shuttle)));
            for (DeviceConfig device : shuttleList) {
                //获取四向穿梭车线程
                ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getDeviceNo());
                ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
                if (shuttleProtocol == null) {
                    continue;
                }
                //判断当前小车是否满足需要充电要求
                if (!shuttleThread.isRequireCharge()) {
                    continue;
                }
                WrkMast wrkMast1 = wrkMastService.selectShuttleWorking(shuttleProtocol.getShuttleNo());
                if (wrkMast1 != null) {
                    continue;
                }
                WrkMast wrkMast2 = wrkMastService.selectShuttleHasMoveWorking(shuttleProtocol.getShuttleNo());
                if (wrkMast2 != null) {
                    continue;
                }
                WrkMast wrkMast = wrkMastService.selectChargeWorking(shuttleProtocol.getShuttleNo());
                if (wrkMast != null) {//已有充电任务
                    continue;
                }
                //小车所在楼层
                int lev = Utils.getLev(shuttleProtocol.getCurrentLocNo());
                BasShuttleCharge shuttleCharge = null;
                //搜索小车所在楼层有没有充电桩
                for (BasShuttleCharge charge : charges) {
                    if (lev != Utils.getLev(charge.getLocNo())) {
                        continue;//小车和充电桩不在同一层
                    }
                    if (charge.getStatus() == 0) {
                        continue;//充电桩被禁用
                    }
                    //小车和充电桩在同一层
                    if (wrkMastService.selectChargeWorkingByChargeSta(charge.getChargeId()) == null) {
                        shuttleCharge = charge;
                        break;
                    }
                }
                if (shuttleCharge == null) {
                    //同楼层没有找到充电桩,找可用充电桩
                    //小车同楼层没有充电桩,只要充电桩可用就生成充电任务
                    for (BasShuttleCharge charge : charges) {
                        if (wrkMastService.selectChargeWorkingByChargeSta(charge.getChargeId()) == null) {
                            //判断当前充电桩是否有小车,如有小车,不分配该充电桩
                            ArrayList<String> locs = new ArrayList<>();
                            locs.add(charge.getLocNo());
                            Integer checkHasShuttle = Utils.checkGroupLocHasShuttle(locs);
                            if(checkHasShuttle != null) {
                                //当前充电桩有穿梭车,不分配该充电桩
                                continue;
                            }
                            if (charge.getStatus() == 0) {
                                continue;//充电桩被禁用
                            }
                            shuttleCharge = charge;
                            break;
                        }
                    }
                }
                if (shuttleCharge == null) {
                    continue;
                }
                String chargeLocNo = shuttleCharge.getLocNo();
                wrkMast = new WrkMast();
                wrkMast.setMk(String.valueOf(shuttleCharge.getChargeId()));
                wrkMast.setWrkNo(commonService.getWorkNo(WrkIoType.SHUTTLE_CHARGE.id));
                wrkMast.setWrkSts(WrkStsType.NEW_CHARGE.sts);
                wrkMast.setIoType(WrkIoType.SHUTTLE_CHARGE.id);//300.充电
                wrkMast.setIoPri((double) 999);
                wrkMast.setLocNo(chargeLocNo);
                wrkMast.setShuttleNo(device.getDeviceNo());
                wrkMast.setMemo("charge");
                wrkMast.setAppeTime(new Date());
                if (!wrkMastService.insert(wrkMast)) {
                    News.error("保存{}号四向穿梭车充电任务失败!!!", device.getDeviceNo());
                    continue;
                }
                News.info("保存{}号四向穿梭车充电任务成功!!!", device.getDeviceNo());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 执行四向穿梭车充电任务
     */
    public synchronized void executeShuttleCharge() {
        try {
            //查询小车充电任务
            List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                    .eq("device_type", String.valueOf(SlaveType.Shuttle)));
            for (DeviceConfig device : shuttleList) {
                WrkMast wrkMast = wrkMastService.selectChargeWorking(device.getDeviceNo());
                if(wrkMast == null) {
                    continue;
                }
                boolean result1 = this.executeShuttleChargeStepGoToChargeSta(wrkMast);//小车等待充电桩
                if (!result1) {
                    continue;
                }
                boolean result2 = this.executeShuttleChargeStepArrivalChargeSta(wrkMast);//小车到达充电桩
                if (!result2) {
                    continue;
                }
                boolean result3 = this.executeShuttleChargeStepStartCharge(wrkMast);//小车开始充电
                if (!result3) {
                    continue;
                }
                boolean result4 = this.executeShuttleChargeStepStopCharge(wrkMast);//小车停止充电
                if (!result4) {
                    continue;
                }
                boolean result5 = this.executeShuttleChargeStepLeaveCharge(wrkMast);//小车离开充电桩
                if (!result5) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 小车前往充电桩
     */
    private synchronized boolean executeShuttleChargeStepGoToChargeSta(WrkMast wrkMast) {
        if (wrkMast.getWrkSts() == WrkStsType.NEW_CHARGE.sts) {
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            if (wrkMast.getLocNo().equals(shuttleProtocol.getCurrentLocNo())) {
                //小车在充电桩位置
                wrkMast.setWrkSts(WrkStsType.CHARGE_SHUTTLE_RUN_COMPLETE.sts);
                wrkMast.setModiTime(new Date());
                wrkMastService.updateById(wrkMast);
                return false;
            }
            //调度小车去充电桩
            boolean dispatched = shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), wrkMast.getLocNo(), wrkMast.getShuttleNo());
            if (!dispatched) {
                return false;
            }
            wrkMast.setWrkSts(WrkStsType.CHARGE_SHUTTLE_RUN.sts);//小车前往充电桩
            wrkMast.setModiTime(new Date());
            wrkMastService.updateById(wrkMast);
            return false;
        }
        return true;
    }
    /**
     * 小车到达充电桩
     */
    private synchronized boolean executeShuttleChargeStepArrivalChargeSta(WrkMast wrkMast) {
        if (wrkMast.getWrkSts() == WrkStsType.CHARGE_SHUTTLE_RUN.sts) {
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            //判断是否存在未完成的移动任务
            WrkMast moveWrk = wrkMastService.selectShuttleHasMoveWorking(wrkMast.getShuttleNo());
            if(moveWrk != null) {
                return false;
            }
            if (!wrkMast.getLocNo().equals(shuttleProtocol.getCurrentLocNo())) {
                return false;
            }
            //小车在充电桩位置
            wrkMast.setWrkSts(WrkStsType.CHARGE_SHUTTLE_RUN_COMPLETE.sts);//小车到达充电桩
            wrkMast.setModiTime(new Date());
            wrkMastService.updateById(wrkMast);
            return false;
        }
        return true;
    }
    //小车开始充电
    private synchronized boolean executeShuttleChargeStepStartCharge(WrkMast wrkMast) {
        if (wrkMast.getWrkSts() == WrkStsType.CHARGE_SHUTTLE_RUN_COMPLETE.sts) {
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            //小车已经在充电桩位置,下发充电命令
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo());//四向穿梭车号
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setTaskMode(ShuttleTaskModeType.CHARGE_ON.id);//充电开
            assignCommand.setSourceLocNo(shuttleProtocol.getCurrentLocNo());//源库位(小车当前位置)
            List<ShuttleCommand> commands = shuttleOperaUtils.getShuttleChargeCommand(assignCommand, shuttleThread, true);
            assignCommand.setCommands(commands);//运行命令
            wrkMast.setWrkSts(WrkStsType.CHARGE_SHUTTLE_WORKING.sts);
            wrkMast.setModiTime(new Date());
            if (!wrkMastService.updateById(wrkMast)) {
                return false;
            }
            //下发任务
            shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
            notifyUtils.notify(String.valueOf(SlaveType.Shuttle), shuttleProtocol.getShuttleNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.SHUTTLE_POWER_START);//触发通知
            return false;
        }
        return true;
    }
    //小车停止充电
    private synchronized boolean executeShuttleChargeStepStopCharge(WrkMast wrkMast) {
        if (wrkMast.getWrkSts() == WrkStsType.CHARGE_SHUTTLE_WORKING.sts) {
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            if (!shuttleThread.isChargingCompleted()) {
                return false;
            }
            //小车已经在充电桩位置,下发停止充电命令
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo());//四向穿梭车号
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setTaskMode(ShuttleTaskModeType.CHARGE_OFF.id);//充电关
            assignCommand.setSourceLocNo(shuttleProtocol.getCurrentLocNo());//源库位(小车当前位置)
            List<ShuttleCommand> commands = shuttleOperaUtils.getShuttleChargeCommand(assignCommand, shuttleThread, false);
            assignCommand.setCommands(commands);//运行命令
            //下发任务
            shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
            return false;
        }
        return true;
    }
    //小车离开充电桩
    private synchronized boolean executeShuttleChargeStepLeaveCharge(WrkMast wrkMast) {
        if (wrkMast.getWrkSts() == WrkStsType.CHARGE_SHUTTLE_COMPLETE.sts) {
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            BasShuttleCharge basShuttleCharge = basShuttleChargeService.selectOne(new EntityWrapper<BasShuttleCharge>().eq("charge_id", wrkMast.getMk()));
            if(basShuttleCharge == null) {
                return false;
            }
            //检测障碍物车
            boolean checkObstacle = shuttleOperaUtils.checkObstacle(basShuttleCharge.getWaitLocNo(), new ArrayList<Integer>() {{
                add(shuttleProtocol.getShuttleNo());
            }}, new ArrayList<>());
            if (checkObstacle) {
                News.info("{}任务,避障范围有小车,等待障碍小车调离中", wrkMast.getWrkNo());
                return false;
            }
            //调度小车去待机位
            boolean dispatched = shuttleDispatchUtils.dispatchShuttle(wrkMast.getWrkNo(), basShuttleCharge.getWaitLocNo(), wrkMast.getShuttleNo());
            if (!dispatched) {
                return false;
            }
            wrkMast.setWrkSts(WrkStsType.COMPLETE_CHARGE.sts);
            wrkMast.setModiTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                return false;
            }
            return false;
        }
        return true;
    }
    /**
     * 执行小车移库任务
     */
    public synchronized void shuttleMoveExecute() {
        try {
            //查询小车移库任务
            List<WrkMast> wrkMasts = wrkMastService.selectShuttleMoveWrk();
            for (WrkMast wrkMast : wrkMasts) {
                boolean stepMoveNearby = this.shuttleMoveExecuteStepMoveNearby(wrkMast);//小车移动到近点
                if (!stepMoveNearby) {
                    continue;
                }
                boolean stepMoveInLift = this.shuttleMoveExecuteStepMoveInLift(wrkMast);//小车迁入提升机中
                if (!stepMoveInLift) {
                    continue;
                }
                boolean stepLiftMove = this.shuttleMoveExecuteStepLiftMove(wrkMast);//提升机搬运中
                if (!stepLiftMove) {
                    continue;
                }
                boolean updateShuttleLocation = this.shuttleMoveExecuteStepUpdateShuttleLocation(wrkMast);//提升机搬运完成更新小车坐标
                if (!updateShuttleLocation) {
                    continue;
                }
                boolean stepMoveLoc = this.shuttleMoveExecuteStepMoveLoc(wrkMast);//小车移动到目标库位中
                if (!stepMoveLoc) {
                    continue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 小车迁移-小车移动到近点中
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean shuttleMoveExecuteStepMoveNearby(WrkMast wrkMast) {
        //--------------------------------------小车移动到近点中-----------------------------------------//
        Date now = new Date();
        //小车移动到近点  301.生成小车移库任务 ==> 302.小车移动至站点中
        if (wrkMast.getWrkSts() == WrkStsType.NEW_MOVE.sts) {
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            //小车处于空闲状态
            if (!shuttleThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,小车忙碌中", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            if (Utils.getLev(wrkMast.getLocNo()) == Utils.getLev(shuttleProtocol.getCurrentLocNo())) {
                //目标库位和小车库位处于同一楼层,不需要通过提升机调度
                wrkMast.setWrkSts(WrkStsType.MOVE_OUT_LIFT_COMPLETE.sts);// 309.小车迁出提升机完成 ==> 310.小车移动中
                wrkMast.setModiTime(now);
                if (wrkMastService.updateById(wrkMast)) {
                    //下发任务
                    return true;//直接进入309.小车迁出提升机完成 ==> 310.小车移动中
                }
                return false;
            }
            //获取源输送站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                return false;//找不到站点
            }
            if (liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftSta.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在小车", wrkMast.getWrkNo());
                return false;
            }
            //获取目标输送站
            ForkLiftStaProtocol liftStaTarget = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (liftStaTarget == null) {
                return false;//找不到站点
            }
            if (liftStaTarget.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftStaTarget.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在小车", wrkMast.getWrkNo());
                return false;
            }
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo()); // 四向穿梭车编号
            assignCommand.setTaskMode(ShuttleTaskModeType.MOVE_LOC_NO.id);//小车移库任务
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setAuto(true);//自动模式
            //计算近点位置
            String endLocation = navigateUtils.calcEndLocation(shuttleProtocol.getCurrentLocNo(), liftSta.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL), null, null, 1);
            if (endLocation == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车近点位置计算失败", wrkMast.getWrkNo());
                return false;
            }
            //小车已在近点位置无需前往
            if (shuttleProtocol.getCurrentLocNo().equals(endLocation)) {
                wrkMast.setWrkSts(WrkStsType.MOVE_NEARBY_COMPLETE.sts);//小车移动到提升机中  301.生成小车移库任务 ==> 303.小车移动至近点完成
                wrkMast.setModiTime(now);
                wrkMast.setSystemMsg("");//清空消息
                wrkMastService.updateById(wrkMast);
                return true;
            }
            //获取小车到近点行走命令
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(shuttleProtocol.getCurrentLocNo(), endLocation, NavigationMapType.getMapTypes(NavigationMapType.NORMAL, NavigationMapType.SHUTTLE), assignCommand, shuttleThread);
            if (commands == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,路径计算失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;//路径解锁失败
            }
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.MOVE_NEARBY.sts);//小车移动到提升机中  301.生成小车移库任务 ==> 302.小车移动至近点中
            wrkMast.setModiTime(now);
            wrkMast.setSystemMsg("");//清空消息
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
                notifyUtils.notify(String.valueOf(SlaveType.Shuttle), shuttleProtocol.getShuttleNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.SHUTTLE_MOVING);
                //触发通知
                return false;
            }
            return false;
        }
        return true;
    }
    /**
     * 小车迁移-小车迁入提升机中
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean shuttleMoveExecuteStepMoveInLift(WrkMast wrkMast) {
        //--------------------------------------小车迁入提升机中-----------------------------------------//
        Date now = new Date();
        //小车迁入提升机  303.小车移动至近点完成 ==> 304.小车迁入提升机中
        if (wrkMast.getWrkSts() == WrkStsType.MOVE_NEARBY_COMPLETE.sts) {
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            //小车处于空闲状态
            if (!shuttleThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,小车忙碌中", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            //获取源输送站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                return false;//找不到站点
            }
            if (liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftSta.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在小车", wrkMast.getWrkNo());
                return false;
            }
            //获取目标输送站
            ForkLiftStaProtocol liftStaTarget = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (liftStaTarget == null) {
                return false;//找不到站点
            }
            if (liftStaTarget.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftStaTarget.getHasCar()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在小车", wrkMast.getWrkNo());
                return false;
            }
            List<WrkMast> outWrkMastList = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .eq("io_type", 101)
                    .in("wrk_sts"
                            , WrkStsType.OUTBOUND_SHUTTLE_RUN.sts
                            , WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts
                            , WrkStsType.OUTBOUND_LIFT_RUN.sts
                            , WrkStsType.OUTBOUND_LIFT_RUN_COMPLETE.sts
                    )
            );
            for (WrkMast outWrkMast : outWrkMastList) {
                if(Utils.getLev(outWrkMast.getSourceLocNo()) == Utils.getLev(wrkMast.getLocNo())) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,存在正在执行的小车出库任务,禁止移动至站点", wrkMast.getWrkNo());
                    return false;
                }
            }
            if (wrkMast.getLiftNo() == null) {
                //申请提升机资源(该任务需要换层必须提前独占提升机)
                boolean applyForkLift = forkLiftAction.applyForkLift(liftSta.getLiftNo(), wrkMast.getWrkNo());
                if(!applyForkLift) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,申请提升机资源失败,禁止移动至站点", wrkMast.getWrkNo());
                    return false;
                }
                return false;
            }
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo()); // 四向穿梭车编号
            assignCommand.setTaskMode(ShuttleTaskModeType.MOVE_LOC_NO.id);//小车移库任务
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setAuto(true);//自动模式
            //获取小车到提升机行走命令
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(shuttleProtocol.getCurrentLocNo(), liftSta.getLocNo(), NavigationMapType.getNormalWithDevice(), assignCommand, shuttleThread);
            if (commands == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,路径计算失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;//路径解锁失败
            }
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.MOVE_IN_LIFT.sts);//303.小车移动至近点完成 ==> 304.小车迁入提升机中
            wrkMast.setModiTime(now);
            wrkMast.setSystemMsg("");//清空消息
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
                notifyUtils.notify(String.valueOf(SlaveType.Shuttle), shuttleProtocol.getShuttleNo(), String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.SHUTTLE_MOVING);
                //触发通知
                return false;
            }
            return false;
        }
        return true;
    }
    /**
     * 小车迁移-提升机搬运中
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean shuttleMoveExecuteStepLiftMove(WrkMast wrkMast) {
        //--------------------------------------提升机搬运中-----------------------------------------//
        Date now = new Date();
        //提升机搬运中  305.小车迁入提升机完成 ==> 306.提升机搬运中
        if (wrkMast.getWrkSts() == WrkStsType.MOVE_IN_LIFT_COMPLETE.sts) {
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, wrkMast.getLiftNo());
            if (forkLiftThread == null) {
                return false;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                return false;
            }
            if (!forkLiftThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机,提升机忙碌中,禁止派发", wrkMast.getWrkNo(), wrkMast.getLiftNo());
                return false;
            }
            //获取源站
            ForkLiftStaProtocol sourceLiftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            //获取目标站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (sourceLiftSta == null || liftSta == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,缺少站点信息,禁止派发", wrkMast.getWrkNo());
                return false;//缺少站点信息
            }
            if (liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在托盘,禁止派发", wrkMast.getWrkNo());
                return false;//有托盘跳过
            }
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getShuttleSwitchCommand(wrkMast.getWrkNo(), sourceLiftSta.getLev(), liftSta.getLev());
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            ForkLiftAssignCommand assignCommand = new ForkLiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(wrkMast.getLiftNo());
            assignCommand.setTaskNo(wrkMast.getWrkNo());
            assignCommand.setTaskMode(ForkLiftTaskModeType.SHUTTLE_SWITCH.id);
            wrkMast.setWrkSts(WrkStsType.MOVE_LIFT_RUN.sts);//提升机搬运中  305.小车迁入提升机完成 ==> 306.提升机搬运中
            wrkMast.setSystemMsg("");//清空消息
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                forkLiftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
            }
        }
        return true;
    }
    /**
     * 小车迁移-提升机搬运完成更新小车坐标
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean shuttleMoveExecuteStepUpdateShuttleLocation(WrkMast wrkMast) {
        //--------------------------------------提升机搬运中-----------------------------------------//
        Date now = new Date();
        //提升机搬运中  307.提升机搬运完成 ==> 308.小车迁出提升机中
        if (wrkMast.getWrkSts() == WrkStsType.MOVE_LIFT_RUN_COMPLETE.sts) {
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            //小车处于空闲状态
            if (!shuttleThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,小车忙碌中,禁止派发", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo()); // 四向穿梭车编号
            assignCommand.setTaskMode(ShuttleTaskModeType.UPDATE_LOCATION.id);//更新坐标
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setAuto(true);//自动模式
            assignCommand.setSourceLocNo(shuttleProtocol.getCurrentLocNo());//源库位
            assignCommand.setLocNo(wrkMast.getLocNo());//目标库位
            //更新小车坐标
            ShuttleCommand command = shuttleThread.getUpdateLocationCommand(wrkMast.getWrkNo(), wrkMast.getLocNo());
            ArrayList<ShuttleCommand> commands = new ArrayList<>();
            commands.add(command);
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.MOVE_OUT_LIFT.sts);//小车迁出提升机中
            wrkMast.setSystemMsg("");//清空消息
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
            }
        }
        return true;
    }
    /**
     * 小车迁移-小车移动到目标库位中
     * 如需主方法执行continue,请返回false
     * ps:返回值true并不代表该方法执行成功,返回值仅做标记用于主方法是否执行continue
     */
    private boolean shuttleMoveExecuteStepMoveLoc(WrkMast wrkMast) {
        //--------------------------------------小车移动到目标库位中-----------------------------------------//
        Date now = new Date();
        //小车移动到目标库位中  309.小车迁出提升机完成 ==> 310.小车移动中
        if (wrkMast.getWrkSts() == WrkStsType.MOVE_OUT_LIFT_COMPLETE.sts) {
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                return false;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                return false;
            }
            //小车处于空闲状态
            if (!shuttleThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,小车忙碌中,禁止派发", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;
            }
            //小车已经在目标库位,直接认定小车移动任务完成
            if (shuttleProtocol.getCurrentLocNo().equals(wrkMast.getLocNo())) {
                wrkMast.setWrkSts(WrkStsType.COMPLETE_MOVE.sts);//311.小车移动完成
                wrkMast.setLiftNo(null);//释放提升机
                wrkMast.setModiTime(now);
                wrkMastService.updateById(wrkMast);
                return false;
            }
            ShuttleAssignCommand assignCommand = new ShuttleAssignCommand();
            assignCommand.setShuttleNo(shuttleProtocol.getShuttleNo()); // 四向穿梭车编号
            assignCommand.setTaskMode(ShuttleTaskModeType.MOVE_LOC_NO.id);//小车移库任务
            assignCommand.setTaskNo(wrkMast.getWrkNo());//任务号
            assignCommand.setAuto(true);//自动模式
            assignCommand.setSourceLocNo(shuttleProtocol.getCurrentLocNo());//源库位
            assignCommand.setLocNo(wrkMast.getLocNo());//目标库位
            //获取小车到目标库位命令
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(shuttleProtocol.getCurrentLocNo(), wrkMast.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL), assignCommand, shuttleThread);
            if (commands == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,路径计算失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;//路径计算失败
            }
            assignCommand.setCommands(commands);
            wrkMast.setWrkSts(WrkStsType.MOVE_SHUTTLE.sts);//小车移动到目标库位中  309.小车迁出提升机完成 ==> 310.小车移动中
            wrkMast.setLiftNo(null);//释放提升机
            wrkMast.setSystemMsg("");//清空消息
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                shuttleAction.assignWork(shuttleProtocol.getShuttleNo(), assignCommand);
            }
        }
        return true;
    }
    //自动切换出入库模式
    public void autoSwitchForkLiftIOMode() {
//        List<DeviceConfig> forkliftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
//                .eq("device_type", String.valueOf(SlaveType.ForkLift)));
//        for (DeviceConfig device : forkliftList) {
//            Integer liftNo = device.getDeviceNo();
//            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
//            if (forkLiftThread == null) {
//                continue;
//            }
//            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
//            if (forkLiftProtocol == null) {
//                continue;
//            }
//
//            List<Integer> liftAllStaNo = ForkLiftUtils.getLiftAllStaNo(liftNo);
//            if (liftAllStaNo.isEmpty()) {
//                continue;
//            }
//
//            List<Integer> conveyorBindLiftAllStaNo = ForkLiftUtils.getConveyorBindLiftAllStaNo(liftNo);
//            if (conveyorBindLiftAllStaNo.isEmpty()) {
//                continue;
//            }
//
//            //获取入库任务
//            List<WrkMast> inWrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
//                    .in("sta_no", liftAllStaNo)
//                    .in("wrk_sts"
//                            , WrkStsType.NEW_INBOUND.sts
//                            , WrkStsType.INBOUND_DEVICE_RUN.sts
//                            , WrkStsType.INBOUND_LIFT_RUN.sts
//                            , WrkStsType.INBOUND_LIFT_RUN_COMPLETE.sts
//                            , WrkStsType.INBOUND_SHUTTLE_RUN.sts
//                            , WrkStsType.INBOUND_SHUTTLE_RUN_COMPLETE.sts
//                    ));
//
//            //获取出库任务
//            List<WrkMast> outWrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
//                    .in("sta_no", conveyorBindLiftAllStaNo)
//                    .in("wrk_sts"
//                            , WrkStsType.NEW_OUTBOUND.sts
//                            , WrkStsType.OUTBOUND_SHUTTLE_RUN.sts
//                            , WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts
//                            , WrkStsType.OUTBOUND_LIFT_RUN.sts
//                            , WrkStsType.OUTBOUND_LIFT_RUN_COMPLETE.sts
//                    ));
//
//            if (forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.NONE)) {
//                //未知模式
//                if (!inWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.IN);
//                } else if (!outWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.OUT);
//                }else {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.IN);
//                }
//            } else if (forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.IN)) {
//                //入库模式
//                if (inWrkMasts.isEmpty() && !outWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.OUT);
//                }
//            } else if (forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.OUT)) {
//                //出库模式
//                if (outWrkMasts.isEmpty() && !inWrkMasts.isEmpty()) {
//                    forkLiftThread.switchIOMode(ForkLiftIoModeType.IN);
//                }
//            }
//        }
    }
    //出库任务预调度提升机
    public void outTaskPreviewDispatchForkLift() {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .in("wrk_sts"
                        , WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts
                ));
        for (WrkMast wrkMast : wrkMasts) {
            if(wrkMast.getShuttleNo() == null){
                continue;
            }
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                continue;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                continue;
            }
            if(shuttleProtocol.getCurrentLocNo() == null){
                continue;
            }
            //通过输送线站号获取提升机号
            Integer liftNo = ForkLiftUtils.getConveyorBindLiftNo(wrkMast.getStaNo());
            if (liftNo == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,未找到匹配的提升机", wrkMast.getWrkNo());
                continue;
            }
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
            if (forkLiftThread == null) {
                continue;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                continue;
            }
            //存在调度锁
            Object object = redisUtil.get(RedisKeyType.OUT_TASK_PREVIEW_DISPATCH_FORKLIFT.key + forkLiftProtocol.getLiftNo());
            if (object != null) {
                continue;
            }
            //申请提升机资源
            boolean applyForkLift = forkLiftAction.applyForkLift(liftNo, null);
            if(!applyForkLift) {
                continue;//提升机已被绑定,不再执行预调度任务
            }
            if (!forkLiftThread.isIdle()) {
                continue;
            }
            //提升机不在出库层
            if (forkLiftProtocol.getLev().equals(Utils.getLev(wrkMast.getSourceLocNo()))) {
                continue;
            }
            //移动
            int workNo = commonService.getWorkNo(WrkIoType.FORKLIFT_MOVE.id);//获取任务号
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getMoveCommand(workNo, forkLiftProtocol.getLev(), Utils.getLev(wrkMast.getSourceLocNo()));
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            ForkLiftAssignCommand assignCommand = new ForkLiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo());
            assignCommand.setTaskNo(workNo);
            assignCommand.setTaskMode(ForkLiftTaskModeType.MOVE.id);
            forkLiftAction.assignWork(forkLiftProtocol.getLiftNo(), assignCommand);
            redisUtil.set(RedisKeyType.OUT_TASK_PREVIEW_DISPATCH_FORKLIFT.key + forkLiftProtocol.getLiftNo(), "lock", 30);//30秒不再调度
        }
    }
}
src/main/java/com/zy/asrs/service/impl/MainServiceImpl.java
@@ -12,7 +12,7 @@
import com.zy.common.service.CommonService;
import com.zy.common.utils.*;
import com.zy.core.News;
import com.zy.core.action.ForkLiftAction;
import com.zy.core.action.LiftAction;
import com.zy.core.action.ShuttleAction;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.dispatcher.ShuttleDispatchUtils;
@@ -67,7 +67,7 @@
    @Autowired
    private ShuttleAction shuttleAction;
    @Autowired
    private ForkLiftAction forkLiftAction;
    private LiftAction liftAction;
    @Autowired
    private NotifyUtils notifyUtils;
    @Autowired
@@ -649,65 +649,65 @@
            if (liftNo == null) {
                //未分配提升机
                Integer staNo = wrkMast.getSourceStaNo();
                liftNo = ForkLiftUtils.getConveyorBindLiftNo(staNo);
                liftNo = LiftUtils.getConveyorBindLiftNo(staNo);
                if(liftNo == null) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,未找到匹配的提升机", wrkMast.getWrkNo());
                    return false;
                }
                //申请提升机资源
                boolean applyForkLift = forkLiftAction.applyForkLift(liftNo, wrkMast.getWrkNo());
                if(!applyForkLift) {
                boolean applyLift = liftAction.applyLift(liftNo, wrkMast.getWrkNo());
                if(!applyLift) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,申请提升机资源失败,禁止入库", wrkMast.getWrkNo());
                    return false;
                }
                return false;
            }
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
            if (forkLiftThread == null) {
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
            if (liftThread == null) {
                return false;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
            LiftProtocol liftProtocol = liftThread.getStatus();
            if (liftProtocol == null) {
                return false;
            }
            if (!forkLiftThread.isIdle()) {
            if (!liftThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机,忙碌中", wrkMast.getWrkNo(), liftSta.getLiftNo());
                return false;
            }
            //判断提升机是否处于入库模式
            if (!forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.IN)) {
            if (!liftProtocol.getIOModeType().equals(LiftIoModeType.IN)) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,提升机不处于入库模式,禁止入库", wrkMast.getWrkNo());
                return false;
            }
            //请求上级系统,是否允许入库
            boolean inMission = ForkLiftUtils.queryInMission(wrkMast.getSourceStaNo(), liftSta.getLiftNo(), wrkMast.getWmsWrkNo());
            boolean inMission = LiftUtils.queryInMission(wrkMast.getSourceStaNo(), liftSta.getLiftNo(), wrkMast.getWmsWrkNo());
            if (!inMission) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,上级系统不允许入库", wrkMast.getWrkNo());
                return false;
            }
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getPickAndPutCommand(wrkMast.getWrkNo(), wrkMast.getSourceStaNo(), liftSta.getLev());
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            LiftCommand liftCommand = liftThread.getPickAndPutCommand(wrkMast.getWrkNo(), wrkMast.getSourceStaNo(), liftSta.getLev());
            ArrayList<LiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(liftNo.shortValue());
            assignCommand.setTaskNo(wrkMast.getWrkNo().shortValue());
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id.shortValue());
            assignCommand.setLiftNo(liftNo);
            assignCommand.setTaskNo(wrkMast.getWrkNo());
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id);
            wrkMast.setWrkSts(WrkStsType.INBOUND_LIFT_RUN.sts);//提升机搬运中  1.生成入库任务 ==> 3.提升机搬运中
            wrkMast.setSystemMsg("");//清空消息
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                forkLiftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
                liftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
            }
            return false;
        }
@@ -724,7 +724,7 @@
        //103.小车搬运完成 ==> 104.提升机搬运中
        if (wrkMast.getWrkSts() == WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts) {
            //获取源站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            LiftStaProtocol liftSta = LiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,找不到站点,禁止派发", wrkMast.getWrkNo());
                return false;//找不到站点
@@ -784,51 +784,51 @@
                    return false;
                }
                //申请提升机资源
                boolean applyForkLift = forkLiftAction.applyForkLift(liftSta.getLiftNo(), wrkMast.getWrkNo());
                if(!applyForkLift) {
                boolean applyLift = liftAction.applyLift(liftSta.getLiftNo(), wrkMast.getWrkNo());
                if(!applyLift) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,申请提升机资源失败,禁止执行出库", wrkMast.getWrkNo());
                    return false;
                }
                return false;
            }
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
            if (forkLiftThread == null) {
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
            if (liftThread == null) {
                return false;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
            LiftProtocol liftProtocol = liftThread.getStatus();
            if (liftProtocol == null) {
                return false;
            }
            if (!forkLiftThread.isIdle()) {
            if (!liftThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机,忙碌中", wrkMast.getWrkNo(), liftSta.getLiftNo());
                return false;
            }
            //判断提升机是否处于出库模式
            if (!forkLiftProtocol.getIOModeType().equals(ForkLiftIoModeType.OUT)) {
            if (!liftProtocol.getIOModeType().equals(LiftIoModeType.OUT)) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,提升机不处于出库模式,禁止出库", wrkMast.getWrkNo());
                return false;
            }
            //请求上级系统,是否允许出库
            boolean outMission = ForkLiftUtils.queryOutMission(wrkMast.getStaNo());
            boolean outMission = LiftUtils.queryOutMission(wrkMast.getStaNo());
            if (!outMission) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,上级系统不允许出库", wrkMast.getWrkNo());
                return false;
            }
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getPickAndPutCommand(wrkMast.getWrkNo(), liftSta.getLev(), wrkMast.getStaNo());
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            LiftCommand liftCommand = liftThread.getPickAndPutCommand(wrkMast.getWrkNo(), liftSta.getLev(), wrkMast.getStaNo());
            ArrayList<LiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(liftNo.shortValue());
            assignCommand.setTaskNo(wrkMast.getWrkNo().shortValue());
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id.shortValue());
            assignCommand.setLiftNo(liftNo);
            assignCommand.setTaskNo(wrkMast.getWrkNo());
            assignCommand.setTaskMode(ForkLiftTaskModeType.PICK_PUT.id);
            wrkMast.setWrkSts(WrkStsType.OUTBOUND_LIFT_RUN.sts);//提升机搬运中  103.生成入库任务 ==> 104.提升机搬运中
            wrkMast.setShuttleNo(null);//释放小车
@@ -836,7 +836,7 @@
            wrkMast.setModiTime(new Date());
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                forkLiftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
                liftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
            }
            return false;
        }
@@ -1486,14 +1486,9 @@
            }
            //获取源输送站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            LiftStaProtocol liftSta = LiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                return false;//找不到站点
            }
            if (liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftSta.getHasCar()) {
@@ -1502,14 +1497,9 @@
            }
            //获取目标输送站
            ForkLiftStaProtocol liftStaTarget = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            LiftStaProtocol liftStaTarget = LiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (liftStaTarget == null) {
                return false;//找不到站点
            }
            if (liftStaTarget.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftStaTarget.getHasCar()) {
@@ -1524,7 +1514,7 @@
            assignCommand.setAuto(true);//自动模式
            //计算近点位置
            String endLocation = navigateUtils.calcEndLocation(shuttleProtocol.getCurrentLocNo(), liftSta.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL, NavigationMapType.PATH_LOCK), null, null, 1);
            String endLocation = navigateUtils.calcEndLocation(shuttleProtocol.getCurrentLocNo(), liftSta.getLocNo(), NavigationMapType.getMapTypes(NavigationMapType.NORMAL), null, null, 1);
            if (endLocation == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,小车近点位置计算失败", wrkMast.getWrkNo());
                return false;
@@ -1591,14 +1581,9 @@
            }
            //获取源输送站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            LiftStaProtocol liftSta = LiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            if (liftSta == null) {
                return false;//找不到站点
            }
            if (liftSta.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,源站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftSta.getHasCar()) {
@@ -1607,14 +1592,9 @@
            }
            //获取目标输送站
            ForkLiftStaProtocol liftStaTarget = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            LiftStaProtocol liftStaTarget = LiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (liftStaTarget == null) {
                return false;//找不到站点
            }
            if (liftStaTarget.getHasTray()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,目标站存在托盘", wrkMast.getWrkNo());
                return false;
            }
            if (liftStaTarget.getHasCar()) {
@@ -1622,29 +1602,47 @@
                return false;
            }
            List<WrkMast> outWrkMastList = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                    .eq("io_type", 101)
                    .in("wrk_sts"
                            , WrkStsType.OUTBOUND_SHUTTLE_RUN.sts
                            , WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts
                            , WrkStsType.OUTBOUND_LIFT_RUN.sts
                            , WrkStsType.OUTBOUND_LIFT_RUN_COMPLETE.sts
                    )
            );
            for (WrkMast outWrkMast : outWrkMastList) {
                if(Utils.getLev(outWrkMast.getSourceLocNo()) == Utils.getLev(wrkMast.getLocNo())) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,存在正在执行的小车出库任务,禁止移动至站点", wrkMast.getWrkNo());
            if (wrkMast.getLiftNo() == null) {
                //申请提升机资源
                boolean applyLift = liftAction.applyLift(liftSta.getLiftNo(), wrkMast.getWrkNo());
                if(!applyLift) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,申请提升机资源失败,禁止移动", wrkMast.getWrkNo());
                    return false;
                }
                return false;
            }
            if (wrkMast.getLiftNo() == null) {
                //申请提升机资源(该任务需要换层必须提前独占提升机)
                boolean applyForkLift = forkLiftAction.applyForkLift(liftSta.getLiftNo(), wrkMast.getWrkNo());
                if(!applyForkLift) {
                    News.taskInfo(wrkMast.getWrkNo(), "{}任务,申请提升机资源失败,禁止移动至站点", wrkMast.getWrkNo());
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, wrkMast.getLiftNo());
            if (liftThread == null) {
                    return false;
                }
            LiftProtocol liftProtocol = liftThread.getStatus();
            if (liftProtocol == null) {
                return false;
            }
            if (!liftThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机,提升机忙碌中,禁止派发", wrkMast.getWrkNo(), wrkMast.getLiftNo());
                return false;
            }
            int targetLev = Utils.getLev(wrkMast.getLocNo());
            if (liftProtocol.getLev() != targetLev) {
                //获取提升机命令
                LiftCommand liftCommand = liftThread.getMoveCommand(wrkMast.getWrkNo(), liftProtocol.getLev(), targetLev);
                ArrayList<LiftCommand> commands = new ArrayList<>();
                commands.add(liftCommand);
                //提交到线程去工作
                LiftAssignCommand assignCommand = new LiftAssignCommand();
                assignCommand.setCommands(commands);
                assignCommand.setLiftNo(wrkMast.getLiftNo());
                assignCommand.setTaskNo(wrkMast.getWrkNo());
                assignCommand.setTaskMode(ForkLiftTaskModeType.MOVE.id);
                //下发任务
                liftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机在{}层,提升机不在小车层,调度移动中", wrkMast.getWrkNo(), liftProtocol.getLev(), wrkMast.getLiftNo());
                return false;
            }
@@ -1655,7 +1653,7 @@
            assignCommand.setAuto(true);//自动模式
            //获取小车到提升机行走命令
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(shuttleProtocol.getCurrentLocNo(), liftSta.getLocNo(), NavigationMapType.getNormalWithDevice(), assignCommand, shuttleThread);
            List<ShuttleCommand> commands = shuttleOperaUtils.getStartToTargetCommands(shuttleProtocol.getCurrentLocNo(), liftThread.getCurrentLocNo(), NavigationMapType.getNormalWithDevice(), assignCommand, shuttleThread);
            if (commands == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}小车,路径计算失败", wrkMast.getWrkNo(), shuttleProtocol.getShuttleNo());
                return false;//路径解锁失败
@@ -1689,23 +1687,23 @@
        //提升机搬运中  305.小车迁入提升机完成 ==> 306.提升机搬运中
        if (wrkMast.getWrkSts() == WrkStsType.MOVE_IN_LIFT_COMPLETE.sts) {
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, wrkMast.getLiftNo());
            if (forkLiftThread == null) {
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, wrkMast.getLiftNo());
            if (liftThread == null) {
                return false;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
            LiftProtocol liftProtocol = liftThread.getStatus();
            if (liftProtocol == null) {
                return false;
            }
            if (!forkLiftThread.isIdle()) {
            if (!liftThread.isIdle()) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,{}号提升机,提升机忙碌中,禁止派发", wrkMast.getWrkNo(), wrkMast.getLiftNo());
                return false;
            }
            //获取源站
            ForkLiftStaProtocol sourceLiftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            LiftStaProtocol sourceLiftSta = LiftUtils.getLiftStaByStaNo(wrkMast.getSourceStaNo());
            //获取目标站
            ForkLiftStaProtocol liftSta = ForkLiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            LiftStaProtocol liftSta = LiftUtils.getLiftStaByStaNo(wrkMast.getStaNo());
            if (sourceLiftSta == null || liftSta == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,缺少站点信息,禁止派发", wrkMast.getWrkNo());
                return false;//缺少站点信息
@@ -1717,23 +1715,23 @@
            }
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getShuttleSwitchCommand(wrkMast.getWrkNo(), sourceLiftSta.getLev(), liftSta.getLev());
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            LiftCommand liftCommand = liftThread.getShuttleSwitchCommand(wrkMast.getWrkNo(), sourceLiftSta.getLev(), liftSta.getLev());
            ArrayList<LiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(wrkMast.getLiftNo().shortValue());
            assignCommand.setTaskNo(wrkMast.getWrkNo().shortValue());
            assignCommand.setTaskMode(ForkLiftTaskModeType.SHUTTLE_SWITCH.id.shortValue());
            assignCommand.setLiftNo(wrkMast.getLiftNo());
            assignCommand.setTaskNo(wrkMast.getWrkNo());
            assignCommand.setTaskMode(ForkLiftTaskModeType.SHUTTLE_SWITCH.id);
            wrkMast.setWrkSts(WrkStsType.MOVE_LIFT_RUN.sts);//提升机搬运中  305.小车迁入提升机完成 ==> 306.提升机搬运中
            wrkMast.setSystemMsg("");//清空消息
            wrkMast.setModiTime(now);
            if (wrkMastService.updateById(wrkMast)) {
                //下发任务
                forkLiftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
                liftAction.assignWork(wrkMast.getLiftNo(), assignCommand);
            }
        }
        return true;
@@ -1928,91 +1926,6 @@
//                }
//            }
//        }
    }
    //出库任务预调度提升机
    public void outTaskPreviewDispatchForkLift() {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .in("wrk_sts"
                        , WrkStsType.OUTBOUND_SHUTTLE_RUN_COMPLETE.sts
                ));
        for (WrkMast wrkMast : wrkMasts) {
            if(wrkMast.getShuttleNo() == null){
                continue;
            }
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, wrkMast.getShuttleNo());
            if (shuttleThread == null) {
                continue;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                continue;
            }
            if(shuttleProtocol.getCurrentLocNo() == null){
                continue;
            }
            //通过输送线站号获取提升机号
            Integer liftNo = ForkLiftUtils.getConveyorBindLiftNo(wrkMast.getStaNo());
            if (liftNo == null) {
                News.taskInfo(wrkMast.getWrkNo(), "{}任务,未找到匹配的提升机", wrkMast.getWrkNo());
                continue;
            }
            ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
            if (forkLiftThread == null) {
                continue;
            }
            ForkLiftProtocol forkLiftProtocol = forkLiftThread.getStatus();
            if (forkLiftProtocol == null) {
                continue;
            }
            //存在调度锁
            Object object = redisUtil.get(RedisKeyType.OUT_TASK_PREVIEW_DISPATCH_FORKLIFT.key + forkLiftProtocol.getLiftNo());
            if (object != null) {
                continue;
            }
            //申请提升机资源
            boolean applyForkLift = forkLiftAction.applyForkLift(liftNo, null);
            if(!applyForkLift) {
                continue;//提升机已被绑定,不再执行预调度任务
            }
            if (!forkLiftThread.isIdle()) {
                continue;
            }
            //提升机不在出库层
            if (forkLiftProtocol.getLev().equals(Utils.getLev(wrkMast.getSourceLocNo()))) {
                continue;
            }
            //移动
            int workNo = commonService.getWorkNo(WrkIoType.FORKLIFT_MOVE.id);//获取任务号
            //获取提升机命令
            ForkLiftCommand liftCommand = forkLiftThread.getMoveCommand(workNo, forkLiftProtocol.getLev(), Utils.getLev(wrkMast.getSourceLocNo()));
            ArrayList<ForkLiftCommand> commands = new ArrayList<>();
            commands.add(liftCommand);
            //提交到线程去工作
            LiftAssignCommand assignCommand = new LiftAssignCommand();
            assignCommand.setCommands(commands);
            assignCommand.setLiftNo(forkLiftProtocol.getLiftNo().shortValue());
            assignCommand.setTaskNo((short) workNo);
            assignCommand.setTaskMode(ForkLiftTaskModeType.MOVE.id.shortValue());
            forkLiftAction.assignWork(forkLiftProtocol.getLiftNo(), assignCommand);
            redisUtil.set(RedisKeyType.OUT_TASK_PREVIEW_DISPATCH_FORKLIFT.key + forkLiftProtocol.getLiftNo(), "lock", 30);//30秒不再调度
        }
    }
}
src/main/java/com/zy/asrs/ws/ConsoleWebSocket.java
@@ -5,6 +5,7 @@
import com.core.common.SpringUtils;
import com.zy.asrs.controller.ConsoleController;
import com.zy.asrs.controller.ForkLiftController;
import com.zy.asrs.controller.LiftController;
import com.zy.asrs.controller.ShuttleController;
import com.zy.common.model.WebSocketMessage;
import lombok.Data;
@@ -71,13 +72,18 @@
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        ShuttleController shuttleController = SpringUtils.getBean(ShuttleController.class);
        ForkLiftController liftController = SpringUtils.getBean(ForkLiftController.class);
        ForkLiftController forkLiftController = SpringUtils.getBean(ForkLiftController.class);
        LiftController liftController = SpringUtils.getBean(LiftController.class);
        ConsoleController consoleController = SpringUtils.getBean(ConsoleController.class);
        WebSocketMessage socketMessage = JSON.parseObject(message, WebSocketMessage.class);
        if (socketMessage.getUrl().equals("/shuttle/table/shuttle/state")) {
            R result = shuttleController.shuttleStateTable();
            socketMessage.setData(JSON.toJSONString(result));
            this.sendMessage(JSON.toJSONString(socketMessage));
        } else if (socketMessage.getUrl().equals("/forkLift/table/lift/state")) {
            R result = forkLiftController.liftStateTable();
            socketMessage.setData(JSON.toJSONString(result));
            this.sendMessage(JSON.toJSONString(socketMessage));
        } else if (socketMessage.getUrl().equals("/lift/table/lift/state")) {
            R result = liftController.liftStateTable();
            socketMessage.setData(JSON.toJSONString(result));
src/main/java/com/zy/common/model/LiftPointModel.java
New file
@@ -0,0 +1,12 @@
package com.zy.common.model;
import lombok.Data;
@Data
public class LiftPointModel {
    private Integer row;
    private Integer bay;
}
src/main/java/com/zy/common/utils/LiftUtils.java
New file
@@ -0,0 +1,247 @@
package com.zy.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.SpringUtils;
import com.zy.asrs.entity.DeviceConfig;
import com.zy.asrs.service.DeviceConfigService;
import com.zy.asrs.utils.Utils;
import com.zy.common.model.NavigateNode;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.SlaveType;
import com.zy.core.model.protocol.ForkLiftStaProtocol;
import com.zy.core.model.protocol.LiftStaProtocol;
import com.zy.core.thread.ForkLiftThread;
import com.zy.core.thread.LiftThread;
import com.zy.system.entity.Config;
import com.zy.system.service.ConfigService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
 * 提升机工具类
 */
public class LiftUtils {
    //获取提升机所有站点
    public static List<Integer> getLiftAllStaNo(Integer liftNo) {
        List<Integer> list = new ArrayList<>();
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return list;
        }
        for (LiftStaProtocol liftStaProtocol : liftThread.getLiftStaProtocols()) {
            list.add(liftStaProtocol.getStaNo());
        }
        return list;
    }
    //获取提升机所绑定的输送线所有站点
    public static List<Integer> getConveyorBindLiftAllStaNo(Integer liftNo) {
        List<Integer> list = new ArrayList<>();
        ConfigService configService = SpringUtils.getBean(ConfigService.class);
        if (configService == null) {
            return list;
        }
        Config conveyorLiftBindConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "conveyorLiftBind"));
        if(conveyorLiftBindConfig == null) {
            return list;
        }
        List<JSONObject> val = JSON.parseArray(conveyorLiftBindConfig.getValue(), JSONObject.class);
        if (val.isEmpty()) {
            return list;
        }
        for (JSONObject data : val) {
            if(data.getInteger("liftNo").equals(liftNo)) {
                list.add(data.getInteger("staNo"));
            }
        }
        return list;
    }
    //获取提升机站点
    public static LiftStaProtocol getLiftStaByStaNo(Integer staNo) {
        DeviceConfigService deviceConfigService = SpringUtils.getBean(DeviceConfigService.class);
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        for (DeviceConfig device : liftList) {
            LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, device.getDeviceNo());
            if (liftThread == null) {
                return null;
            }
            for (LiftStaProtocol liftStaProtocol : liftThread.getLiftStaProtocols()) {
                if (liftStaProtocol.getStaNo().equals(staNo)) {
                    return liftStaProtocol;
                }
            }
        }
        return null;
    }
    //获取提升机站点
    public static LiftStaProtocol getLiftStaByLev(Integer liftNo, Integer lev) {
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return null;
        }
        for (LiftStaProtocol liftStaProtocol : liftThread.getLiftStaProtocols()) {
            if (liftStaProtocol.getLev().equals(lev)) {
                return liftStaProtocol;
            }
        }
        return null;
    }
    //获取提升机输送站及其前一站节点
    public static List<NavigateNode> getLiftStaNodes(Integer staNo) {
        List<NavigateNode> targetNodes = new ArrayList<>();
        //获取目标站
        LiftStaProtocol targetLiftSta = LiftUtils.getLiftStaByStaNo(staNo);
        if (targetLiftSta == null) {
            return null;//找不到站点
        }
        NavigateNode targetNode = NavigatePositionConvert.locNoToNode(targetLiftSta.getLocNo());//目标节点
        String targetLastLocNo = Utils.getLocNo(Utils.getRow(targetLiftSta.getLocNo()) - 1, Utils.getBay(targetLiftSta.getLocNo()), Utils.getLev(targetLiftSta.getLocNo()));//目标节点前一站
        NavigateNode targetLastNode = NavigatePositionConvert.locNoToNode(targetLastLocNo);//目标节点前一站
        targetNodes.add(targetNode);
        targetNodes.add(targetLastNode);
        return targetNodes;
    }
    //通过输送线站号获取对应提升机号
    public static Integer getConveyorBindLiftNo(Integer staNo) {
        ConfigService configService = SpringUtils.getBean(ConfigService.class);
        if (configService == null) {
            return null;
        }
        Config conveyorLiftBindConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "conveyorLiftBind"));
        if(conveyorLiftBindConfig == null) {
            return null;
        }
        List<JSONObject> list = JSON.parseArray(conveyorLiftBindConfig.getValue(), JSONObject.class);
        if (list.isEmpty()) {
            return null;
        }
        for (JSONObject data : list) {
            if(data.getInteger("staNo").equals(staNo)) {
                return data.getInteger("liftNo");
            }
        }
        return null;
    }
    //请求上级系统,是否允许出库
    //查询是否有出库权限
    public static boolean queryOutMission(Integer staNo) {
        ConfigService configService = SpringUtils.getBean(ConfigService.class);
        if (configService == null) {
            return false;
        }
        Config queryOutMissionPathEnableConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "queryOutMissionPathEnable"));
        if (queryOutMissionPathEnableConfig != null) {
            String queryOutMissionPathEnable = queryOutMissionPathEnableConfig.getValue();
            if (!queryOutMissionPathEnable.equals("Y")) {
                return true;//关闭查询出库权限功能
            }
        }
        Config superSystemUriConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "superSystemUri"));
        if (superSystemUriConfig == null) {
            return false;
        }
        String superSystemUri = superSystemUriConfig.getValue();
        Config queryOutMissionPathConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "queryOutMissionPath"));
        if (queryOutMissionPathConfig == null) {
            return false;
        }
        String missionPath = queryOutMissionPathConfig.getValue();
        try {
            HashMap<String, Object> data = new HashMap<>();
            data.put("staNo", staNo);
            String response = new HttpHandler.Builder()
                    .setUri(superSystemUri)
                    .setPath(missionPath)
                    .setJson(JSON.toJSONString(data))
                    .build()
                    .doPost();
            if (response.equals("ok")) {
                return true;//有出库权限
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }
    //请求上级系统,是否允许入库
    //查询是否有入库权限
    public static boolean queryInMission(Integer sourceStaNo, Integer liftNo, String superTaskNo) {
        ConfigService configService = SpringUtils.getBean(ConfigService.class);
        if (configService == null) {
            return false;
        }
        Config queryInMissionPathEnableConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "queryInMissionPathEnable"));
        if (queryInMissionPathEnableConfig != null) {
            String queryInMissionPathEnable = queryInMissionPathEnableConfig.getValue();
            if (!queryInMissionPathEnable.equals("Y")) {
                return true;//关闭查询入库权限功能
            }
        }
        Config superSystemUriConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "superSystemUri"));
        if (superSystemUriConfig == null) {
            return false;
        }
        String superSystemUri = superSystemUriConfig.getValue();
        Config queryInMissionPathConfig = configService.selectOne(new EntityWrapper<Config>().eq("code", "queryInMissionPath"));
        if (queryInMissionPathConfig == null) {
            return false;
        }
        String missionPath = queryInMissionPathConfig.getValue();
        try {
            HashMap<String, Object> data = new HashMap<>();
            data.put("staNo", sourceStaNo);
            data.put("liftNo", liftNo);
            data.put("superTaskNo", superTaskNo);
            String response = new HttpHandler.Builder()
                    .setUri(superSystemUri)
                    .setPath(missionPath)
                    .setJson(JSON.toJSONString(data))
                    .build()
                    .doPost();
            if (response.equals("ok")) {
                return true;//有入库权限
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
src/main/java/com/zy/core/MainProcess.java
@@ -1,10 +1,12 @@
package com.zy.core;
import com.zy.asrs.service.impl.ForkMainServiceImpl;
import com.zy.asrs.service.impl.MainServiceImpl;
import com.zy.core.properties.SystemProperties;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
@@ -18,8 +20,12 @@
@Component
public class MainProcess {
    @Value("${deviceExecuteConfig.liftType}")
    private String liftType;
    @Autowired
    private MainServiceImpl mainService;
    @Autowired
    private ForkMainServiceImpl forkMainService;
    // 所属线程
    private Thread thread;
    // 频率
@@ -29,6 +35,14 @@
     * =====>>  开始工作
     */
    public void start(){
        if(liftType.equals("ForkLift")){
            initForkMain();
        }else {
            initMain();
        }
    }
    private void initMain() {
        thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
@@ -43,9 +57,6 @@
                    //初始化实时地图
                    mainService.initRealtimeBasMap();
                    //出库任务预调度提升机
                    mainService.outTaskPreviewDispatchForkLift();
                    // 入库  ===>>  四向穿梭车入库作业下发
                    mainService.shuttleInExecute();
@@ -80,6 +91,58 @@
        thread.start();
    }
    private void initForkMain() {
        thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 间隔
                    Thread.sleep(300);
                    // 系统运行状态判断
                    if (!SystemProperties.WCS_RUNNING_STATUS.get()) {
                        continue;
                    }
                    //初始化实时地图
                    forkMainService.initRealtimeBasMap();
                    //出库任务预调度提升机
                    forkMainService.outTaskPreviewDispatchForkLift();
                    // 入库  ===>>  四向穿梭车入库作业下发
                    forkMainService.shuttleInExecute();
                    // 出库  ===>>  四向穿梭车出库作业下发
                    forkMainService.shuttleOutExecute();
//                    //四向穿梭车任务完成
//                    mainService.shuttleFinished();
                    //执行移库任务
                    forkMainService.shuttleLocMoveExecute();
                    //货叉提升机任务
                    forkMainService.forkLiftIoExecute();
                    //货叉提升机任务完成
                    forkMainService.forkLiftFinished();
                    //执行小车移动任务
                    forkMainService.shuttleMoveExecute();
                    // 异常信息记录
                    forkMainService.recErr();
                    // 穿梭车 ===>> 小车电量检测充电
                    forkMainService.loopShuttleCharge();
                    forkMainService.executeShuttleCharge();
                    //自动切换出入库模式
                    forkMainService.autoSwitchForkLiftIOMode();
                    // 间隔
                    Thread.sleep(200);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
    }
    @PreDestroy
    public void shutDown(){
        if (thread != null) thread.interrupt();
src/main/java/com/zy/core/ServerBootstrap.java
@@ -14,6 +14,7 @@
import com.zy.core.enums.SlaveType;
import com.zy.core.task.ShuttleExecuteScheduler;
import com.zy.core.thread.TrafficControlThread;
import com.zy.core.thread.impl.NyLiftThread;
import com.zy.core.thread.impl.NyShuttleThread;
import com.zy.core.thread.impl.TrafficControlImplThread;
import com.zy.core.thread.impl.ZyForkLiftThread;
@@ -73,6 +74,12 @@
        for (DeviceConfig forkLift : forkLiftList) {
            MessageQueue.init(SlaveType.ForkLift, forkLift.getDeviceNo());
        }
        // 初始化提升机mq
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        for (DeviceConfig lift : liftList) {
            MessageQueue.init(SlaveType.Lift, lift.getDeviceNo());
        }
        // 初始化四向穿梭车mq
        List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Shuttle)));
@@ -114,6 +121,33 @@
            }
        }
        // 初始化提升机
        News.info("初始化提升机........................................................");
        List<DeviceConfig> liftList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
                .eq("device_type", String.valueOf(SlaveType.Lift)));
        for (DeviceConfig deviceConfig : liftList) {
            BasLift basLift = basLiftService.selectOne(new EntityWrapper<BasLift>().eq("lift_no", deviceConfig.getDeviceNo()));
            if (basLift == null) {
                throw new CoolException("未配置提升机数据");
            }
            ThreadHandler thread = null;
            if (deviceConfig.getThreadImpl().equals("NyLiftThread")) {
                thread = new NyLiftThread(deviceConfig, basLift.getPoint$(), basLift.getStationList$(), redisUtil);
            } else {
                throw new CoolException("未知的线程实现");
            }
            new Thread(thread).start();
            SlaveConnection.put(SlaveType.Lift, deviceConfig.getDeviceNo(), thread);
            if (deviceConfig.getFake() == 1) {
                fakeDevices.add(deviceConfig);
            }else {
                allDevices.add(deviceConfig);
            }
        }
        // 初始化四向穿梭车
        News.info("初始化四向穿梭车......................................................");
        List<DeviceConfig> shuttleList = deviceConfigService.selectList(new EntityWrapper<DeviceConfig>()
src/main/java/com/zy/core/action/ForkLiftAction.java
@@ -12,9 +12,7 @@
import com.zy.core.enums.RedisKeyType;
import com.zy.core.enums.SlaveType;
import com.zy.core.model.CommandResponse;
import com.zy.core.model.command.ForkLiftCommand;
import com.zy.core.model.command.LiftAssignCommand;
import com.zy.core.model.command.LiftRedisCommand;
import com.zy.core.model.command.*;
import com.zy.core.model.protocol.ForkLiftProtocol;
import com.zy.core.thread.ForkLiftThread;
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,7 +31,7 @@
    @Autowired
    private BasLiftOptService basLiftOptService;
    public synchronized boolean assignWork(Integer liftNo, LiftAssignCommand assignCommand) {
    public synchronized boolean assignWork(Integer liftNo, ForkLiftAssignCommand assignCommand) {
        ForkLiftThread forkLiftThread = (ForkLiftThread) SlaveConnection.get(SlaveType.ForkLift, liftNo);
        if (forkLiftThread == null) {
            return false;
@@ -44,14 +42,14 @@
            return false;
        }
        LiftRedisCommand redisCommand = new LiftRedisCommand();
        ForkLiftRedisCommand redisCommand = new ForkLiftRedisCommand();
        redisCommand.setLiftNo(assignCommand.getLiftNo());//提升机号
        redisCommand.setWrkNo(assignCommand.getTaskNo());//工作号
        redisCommand.setCommandStep(0);//命令执行步序
        redisCommand.setAssignCommand(assignCommand);//命令
        //任务数据保存到redis
        if (redisUtil.set(RedisKeyType.FORK_LIFT_WORK_FLAG.key + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand))) {
            forkLiftThread.setSyncTaskNo(assignCommand.getTaskNo().intValue());
            forkLiftThread.setSyncTaskNo(assignCommand.getTaskNo());
            return true;
        }
        return false;
@@ -68,7 +66,7 @@
//            return false;
//        }
        LiftRedisCommand redisCommand = JSON.parseObject(obj.toString(), LiftRedisCommand.class);
        ForkLiftRedisCommand redisCommand = JSON.parseObject(obj.toString(), ForkLiftRedisCommand.class);
        if (redisCommand == null) {
            return false;
        }
@@ -88,7 +86,7 @@
            return false;
        }
        LiftAssignCommand assignCommand = redisCommand.getAssignCommand();
        ForkLiftAssignCommand assignCommand = redisCommand.getAssignCommand();
        int commandStep = redisCommand.getCommandStep();
        if (commandStep == 0) {
src/main/java/com/zy/core/action/LiftAction.java
New file
@@ -0,0 +1,184 @@
package com.zy.core.action;
import com.alibaba.fastjson.JSON;
import com.zy.asrs.entity.BasLiftOpt;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.service.BasLiftOptService;
import com.zy.asrs.service.WrkMastService;
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.core.cache.SlaveConnection;
import com.zy.core.enums.LiftTaskModeType;
import com.zy.core.enums.RedisKeyType;
import com.zy.core.enums.SlaveType;
import com.zy.core.model.CommandResponse;
import com.zy.core.model.command.LiftAssignCommand;
import com.zy.core.model.command.LiftCommand;
import com.zy.core.model.command.LiftRedisCommand;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.thread.LiftThread;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
@Component
public class LiftAction {
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
    private BasLiftOptService basLiftOptService;
    public synchronized boolean assignWork(Integer liftNo, LiftAssignCommand assignCommand) {
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return false;
        }
        LiftProtocol liftProtocol = liftThread.getStatus();
        if (liftProtocol == null) {
            return false;
        }
        LiftRedisCommand redisCommand = new LiftRedisCommand();
        redisCommand.setLiftNo(assignCommand.getLiftNo());//提升机号
        redisCommand.setWrkNo(assignCommand.getTaskNo());//工作号
        redisCommand.setCommandStep(0);//命令执行步序
        redisCommand.setAssignCommand(assignCommand);//命令
        //任务数据保存到redis
        if (redisUtil.set(RedisKeyType.LIFT_WORK_FLAG.key + assignCommand.getTaskNo(), JSON.toJSONString(redisCommand))) {
            liftThread.setSyncTaskNo(assignCommand.getTaskNo());
            return true;
        }
        return false;
    }
    public synchronized boolean executeWork(Integer liftNo, Integer taskNo) {
        Object obj = redisUtil.get(RedisKeyType.LIFT_WORK_FLAG.key + taskNo);
        if (obj == null) {
            return false;
        }
        LiftRedisCommand redisCommand = JSON.parseObject(obj.toString(), LiftRedisCommand.class);
        if (redisCommand == null) {
            return false;
        }
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return false;
        }
        LiftProtocol liftProtocol = liftThread.getStatus();
        if (liftProtocol == null) {
            return false;
        }
        List<LiftCommand> commands = redisCommand.getAssignCommand().getCommands();
        if (commands.isEmpty()) {
            return false;
        }
        LiftAssignCommand assignCommand = redisCommand.getAssignCommand();
        int commandStep = redisCommand.getCommandStep();
        if (commandStep == 0) {
            //取出命令
            LiftCommand command = commands.get(commandStep);
            //判断提升机是否空闲
            if (!liftThread.isDeviceIdle()) {
                return false;
            }
            // 下发命令
            CommandResponse response = write(command, liftNo);
            //保存命令日志
            BasLiftOpt basLiftOpt = new BasLiftOpt();
            basLiftOpt.setWrkNo(taskNo);
            basLiftOpt.setLiftNo(liftNo);
            basLiftOpt.setCommand(JSON.toJSONString(command));
            basLiftOpt.setSystemStatus(JSON.toJSONString(liftProtocol));
            basLiftOpt.setDeviceWrk(String.valueOf(command.getTaskNo()));
            basLiftOpt.setSendTime(new Date());//指令下发时间
            //保存命令流水
            basLiftOptService.insert(basLiftOpt);
            if (!response.getResult()) {
                News.error("提升机命令下发失败,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
                return false;
            } else {
                News.info("提升机命令下发成功,提升机号={},任务数据={}", command.getLiftNo(), JSON.toJSON(command));
            }
            commandStep++;
            //更新redis数据
            redisCommand.setCommandStep(commandStep);
            // 更新redis数据
            redisUtil.set(RedisKeyType.LIFT_WORK_FLAG.key + taskNo, JSON.toJSONString(redisCommand));
        }
        return true;
    }
    private synchronized CommandResponse write(LiftCommand command, Integer liftNo) {
        CommandResponse response = new CommandResponse(false);
        if (null == command) {
            News.error("提升机写入命令为空");
            response.setMessage("提升机写入命令为空");
            return response;
        }
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return response;
        }
        if (command.getMode() == LiftTaskModeType.PICK_PUT.id) {
            response = liftThread.pickAndPut(command);
        } else if (command.getMode() == LiftTaskModeType.SHUTTLE_SWITCH.id) {
            response = liftThread.shuttleSwitch(command);
        } else if (command.getMode() == LiftTaskModeType.MOVE.id) {
            response = liftThread.move(command);
        }
        return response;
    }
    //申请提升机资源
    public synchronized boolean applyLift(Integer liftNo, Integer waitBindTaskNo) {
        LiftThread liftThread = (LiftThread) SlaveConnection.get(SlaveType.Lift, liftNo);
        if (liftThread == null) {
            return false;
        }
        LiftProtocol liftProtocol = liftThread.getStatus();
        if (liftProtocol == null) {
            return false;
        }
        if (!liftThread.isIdle()) {
            return false;
        }
        List<WrkMast> wrkMasts = wrkMastService.selectLiftWrkMast(liftNo);
        if (!wrkMasts.isEmpty()) {
            return false;
        }
        if (waitBindTaskNo != null) {
            WrkMast wrkMast = wrkMastService.selectByWorkNo(waitBindTaskNo);
            if (wrkMast == null) {
                return false;
            }
            wrkMast.setLiftNo(liftNo);
            wrkMast.setModiTime(new Date());
            wrkMastService.updateById(wrkMast);
        }
        return true;
    }
}
src/main/java/com/zy/core/enums/ForkLiftConfirmType.java
File was deleted
src/main/java/com/zy/core/enums/LiftIoModeType.java
New file
@@ -0,0 +1,41 @@
package com.zy.core.enums;
//提升机出入库模式
public enum LiftIoModeType {
    NONE(0, "未知"),
    IN(1, "入库"),
    OUT(2, "出库"),
    ;
    public Integer id;
    public String desc;
    LiftIoModeType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static LiftIoModeType get(Integer id) {
        if (null == id) {
            return null;
        }
        for (LiftIoModeType type : LiftIoModeType.values()) {
            if (type.id.equals(id)) {
                return type;
            }
        }
        return null;
    }
    public static LiftIoModeType get(LiftIoModeType type) {
        if (null == type) {
            return null;
        }
        for (LiftIoModeType type2 : LiftIoModeType.values()) {
            if (type2 == type) {
                return type2;
            }
        }
        return null;
    }
}
src/main/java/com/zy/core/enums/LiftProtocolStatusType.java
New file
@@ -0,0 +1,42 @@
package com.zy.core.enums;
public enum LiftProtocolStatusType {
    NONE(-1, "离线"),
    IDLE(0, "空闲"),
    WORKING(1, "作业中"),
    WAITING(98, "等待确认"),
    ERROR(99, "故障"),
    ;
    public Integer id;
    public String desc;
    LiftProtocolStatusType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static LiftProtocolStatusType get(Integer id) {
        if (null == id) {
            return NONE;
        }
        for (LiftProtocolStatusType type : LiftProtocolStatusType.values()) {
            if (type.id.equals(id)) {
                return type;
            }
        }
        return NONE;
    }
    public static LiftProtocolStatusType get(LiftProtocolStatusType type) {
        if (null == type) {
            return NONE;
        }
        for (LiftProtocolStatusType type2 : LiftProtocolStatusType.values()) {
            if (type2 == type) {
                return type2;
            }
        }
        return NONE;
    }
}
src/main/java/com/zy/core/enums/LiftTaskModeType.java
New file
@@ -0,0 +1,47 @@
package com.zy.core.enums;
//提升机任务模式
public enum LiftTaskModeType {
    NONE(0, "未知"),
    PICK_PUT(1, "取放货"),
    SHUTTLE_SWITCH(2, "小车换层"),
    MOVE(3, "提升机移动"),
    RESET(9996, "复位"),
    SWITCH_IN(9997, "切换入库模式"),
    SWITCH_OUt(9998, "切换出库模式"),
    READ_STATUS(9999, "读取状态"),
    ;
    public Integer id;
    public String desc;
    LiftTaskModeType(Integer id, String desc) {
        this.id = id;
        this.desc = desc;
    }
    public static LiftTaskModeType get(Integer id) {
        if (null == id) {
            return null;
        }
        for (LiftTaskModeType type : LiftTaskModeType.values()) {
            if (type.id.equals(id)) {
                return type;
            }
        }
        return null;
    }
    public static LiftTaskModeType get(LiftTaskModeType type) {
        if (null == type) {
            return null;
        }
        for (LiftTaskModeType type2 : LiftTaskModeType.values()) {
            if (type2 == type) {
                return type2;
            }
        }
        return null;
    }
}
src/main/java/com/zy/core/enums/RedisKeyType.java
@@ -6,6 +6,9 @@
    SHUTTLE_FLAG("shuttle_"),
    FORK_LIFT_WORK_FLAG("fork_lift_wrk_no_"),
    FORK_LIFT_FLAG("fork_lift_"),
    LIFT_WORK_FLAG("lift_wrk_no_"),
    LIFT_FLAG("lift_"),
    MAP("realtimeBasMap_"),
    BASIC_MAP("basicMap_"),
    QUEUE_SHUTTLE("queue_shuttle_"),
@@ -32,10 +35,12 @@
    //设备消息KEY
    DEVICE_SHUTTLE_MSG_KEY_("deviceShuttleMsgKey_"),
    DEVICE_FORK_LIFT_MSG_KEY_("deviceForkLiftMsgKey_"),
    DEVICE_LIFT_MSG_KEY_("deviceLiftMsgKey_"),
    //设备指令消息KEY
    DEVICE_SHUTTLE_COMMAND_MSG_KEY("deviceShuttleCommandMsgKey_"),
    DEVICE_FORK_LIFT_COMMAND_MSG_KEY("deviceForkLiftCommandMsgKey_"),
    DEVICE_LIFT_COMMAND_MSG_KEY("deviceLiftCommandMsgKey_"),
    //设备配置文件
    DEVICE_CONFIG("deviceConfig"),
src/main/java/com/zy/core/model/command/ForkLiftAssignCommand.java
New file
@@ -0,0 +1,40 @@
package com.zy.core.model.command;
import lombok.Data;
import java.util.List;
@Data
public class ForkLiftAssignCommand {
    /**
     * 提升机号
     */
    private Integer liftNo = 0;
    /**
     * 任务号
     */
    private Integer taskNo = 0;
    /**
     * 命令list
     */
    private List<ForkLiftCommand> commands;
    /**
     * 作业类型
     */
    private Integer taskMode = 0;
    /**
     * 是否自动,true:自动模式,false:手动模式
     */
    private Boolean auto = true;
    /**
     * 提升机楼层
     */
    private Integer lev;
}
src/main/java/com/zy/core/model/command/ForkLiftRedisCommand.java
New file
@@ -0,0 +1,22 @@
package com.zy.core.model.command;
import lombok.Data;
import java.io.Serializable;
@Data
public class ForkLiftRedisCommand implements Serializable {
    //提升机号
    private Integer liftNo;
    //工作号
    private Integer wrkNo;
    //命令执行步序
    private Integer commandStep;
    //命令
    private ForkLiftAssignCommand assignCommand;
}
src/main/java/com/zy/core/model/command/LiftAssignCommand.java
@@ -10,22 +10,22 @@
    /**
     * 提升机号
     */
    private Short liftNo = 0;
    private Integer liftNo = 0;
    /**
     * 任务号
     */
    private Short taskNo = 0;
    private Integer taskNo = 0;
    /**
     * 命令list
     */
    private List<ForkLiftCommand> commands;
    private List<LiftCommand> commands;
    /**
     * 作业类型
     */
    private Short taskMode = 0;
    private Integer taskMode = 0;
    /**
     * 是否自动,true:自动模式,false:手动模式
src/main/java/com/zy/core/model/command/LiftCommand.java
@@ -12,83 +12,31 @@
    /**
     * 提升机号
     */
    private Short liftNo = 0;
    private Integer liftNo;
    /**
     * 任务号
     */
    private Short taskNo = 0;
    private Integer taskNo;
    /**
     * 开始运行
     * 任务模式
     */
    private Short run;
    private Integer mode;
    /**
     * 目标位置
     * 取货数据
     */
    private Short distPosition;
    private Integer pick;
    /**
     * 运行速度
     * 放货数据
     */
    private Short speed;
    /**
     * 二层高度设定(提升机与输送线平层)
     */
    private Short height2;
    /**
     * 三层高度设定(实际的二层)
     */
    private Short height3;
    /**
     * 四层高度设定(实际的三层)
     */
    private Short height4;
    /**
     * 五层高度设定(实际的四层)
     */
    private Short height5;
    /**
     * 提升机锁定
     */
    private Boolean liftLock;
    /**
     * 操作输送站点号
     */
    private Short operaStaNo;
    /**
     * 输送线联动转动方向,0:停止转动,1:正向转动,2:反向转动
     */
    private Integer rotationDire;
    /**
     * 输送线ID
     */
    private Integer devpId;
    /**
     * 目标站
     */
    private Short staNo;
    private Integer put;
    /**
     * 命令是否完成,默认false未完成
     */
    private Boolean complete = false;
    public Short getLiftLockShortValue() {
        if (liftLock == null) {
            return (short) 0;
        }
        return liftLock ? (short) 1 : (short) 0;
    }
}
src/main/java/com/zy/core/model/command/LiftRedisCommand.java
@@ -8,10 +8,10 @@
public class LiftRedisCommand implements Serializable {
    //提升机号
    private Short liftNo;
    private Integer liftNo;
    //工作号
    private Short wrkNo;
    private Integer wrkNo;
    //命令执行步序
    private Integer commandStep;
src/main/java/com/zy/core/model/protocol/ForkLiftStaProtocol.java
@@ -4,7 +4,7 @@
import lombok.extern.slf4j.Slf4j;
/**
 * 提升机站点
 * 货叉提升机站点
 */
@Slf4j
@Data
src/main/java/com/zy/core/model/protocol/LiftProtocol.java
New file
@@ -0,0 +1,252 @@
package com.zy.core.model.protocol;
import com.core.common.Cools;
import com.core.common.SpringUtils;
import com.zy.asrs.entity.BasLiftErr;
import com.zy.asrs.service.BasLiftErrService;
import com.zy.common.utils.RedisUtil;
import com.zy.core.enums.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
 * 提升机
 */
@Slf4j
@Data
public class LiftProtocol implements Cloneable {
    /**
     * 提升机号
     */
    private Integer liftNo;
    /**
     * 模式0手动 1单机 2联机
     */
    private Integer model;
    /**
     * 任务号
     */
    private Integer taskNo = 0;
    /**
     * PLC任务号
     */
    private Integer plcTaskNo;
    /**
     * 任务状态
     */
    private Integer protocolStatus = LiftProtocolStatusType.NONE.id;
    /**
     * 任务状态枚举
     */
    private LiftProtocolStatusType protocolStatusType = LiftProtocolStatusType.NONE;
    /**
     * 任务模式
     */
    private Integer taskMode = LiftTaskModeType.NONE.id;
    /**
     * 任务模式枚举
     */
    private LiftTaskModeType modeType = LiftTaskModeType.NONE;
    /**
     * 取货数据
     */
    private Integer pick;
    /**
     * 放货数据
     */
    private Integer put;
    /**
     * 有托盘
     */
    private Boolean hasTray;
    /**
     * 有小车
     */
    private Boolean hasCar;
    /**
     * 出入库模式
     */
    private Integer iOMode = LiftIoModeType.NONE.id;
    /**
     * 出入库模式枚举
     */
    private LiftIoModeType iOModeType = LiftIoModeType.NONE;
    /**
     * 故障码
     */
    private Integer errorCode;
    /**
     * 当前层
     */
    private Integer lev;
    /**
     * 作业标记
     */
    private Boolean pakMk = false;
    /**
     * 指令下发时间
     */
    private Long sendTime = 0L;
    /**
     * 日志采集时间
     */
    private Long deviceDataLog = System.currentTimeMillis();
    /**
     * 扩展字段
     */
    private Object extend;
    /**
     * 设置任务状态
     */
    public void setProtocolStatus(Integer status) {
        this.protocolStatus = status;
        this.protocolStatusType = LiftProtocolStatusType.get(status);
    }
    /**
     * 设置任务状态
     */
    public void setProtocolStatus(LiftProtocolStatusType status) {
        this.protocolStatus = status.id;
        this.protocolStatusType = status;
    }
    /**
     * 设置任务模式
     */
    public void setTaskMode(Integer taskMode) {
        this.taskMode = taskMode;
        this.modeType = LiftTaskModeType.get(taskMode);
    }
    /**
     * 设置任务模式
     */
    public void setMode(LiftTaskModeType taskMode) {
        this.taskMode = taskMode.id;
        this.modeType = taskMode;
    }
    /**
     * 设置出入库模式
     */
    public void setIOMode(Integer ioMode) {
        this.iOMode = ioMode;
        this.iOModeType = LiftIoModeType.get(ioMode);
    }
    /**
     * 设置出入库模式
     */
    public void setIOMode(LiftIoModeType ioMode) {
        this.iOMode = ioMode.id;
        this.iOModeType = ioMode;
    }
    /**
     * 错误码
     */
    public String getErrCode$() {
        if (this.errorCode == null) {
            return "";
        }
        BasLiftErrService basLiftErrService = SpringUtils.getBean(BasLiftErrService.class);
        BasLiftErr basLiftErr = basLiftErrService.selectById(this.errorCode);
        if (basLiftErr == null) {
            return String.valueOf(this.errorCode);
        }
        return basLiftErr.getErrName();
    }
    public Integer getTaskNo() {
        RedisUtil redisUtil = SpringUtils.getBean(RedisUtil.class);
        if (null != redisUtil) {
            Object o = redisUtil.get(RedisKeyType.LIFT_FLAG.key + this.liftNo);
            if (!Cools.isEmpty(o)) {
                this.taskNo = Integer.parseInt(String.valueOf(o));
            }
        }
        return this.taskNo == null ? 0 : this.taskNo;
    }
    public synchronized void setSyncTaskNo(Integer taskNo) {
        RedisUtil redisUtil = SpringUtils.getBean(RedisUtil.class);
        if (null != redisUtil) {
            redisUtil.set(RedisKeyType.LIFT_FLAG.key + this.liftNo, taskNo);
            this.taskNo = taskNo;
        }
    }
    public String getModel$() {
        if (this.model == null) {
            return "";
        }
        String name = "";
        if (this.model == 0) {
            name = "手动";
        } else if (this.model == 1) {
            name = "单机";
        }else if (this.model == 2) {
            name = "联机";
        }
        return name;
    }
    public String getProtocolStatus$() {
        if (this.protocolStatus == null) {
            return "";
        }
        return LiftProtocolStatusType.get(this.protocolStatus).desc;
    }
    public String getTaskMode$() {
        if (this.taskMode == null) {
            return "";
        }
        return LiftTaskModeType.get(this.taskMode).desc;
    }
    public String getIOMode$() {
        if (this.iOMode == null) {
            return "";
        }
        return LiftIoModeType.get(this.iOMode).desc;
    }
    @Override
    public LiftProtocol clone() {
        try {
            return (LiftProtocol) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
src/main/java/com/zy/core/thread/LiftThread.java
New file
@@ -0,0 +1,57 @@
package com.zy.core.thread;
import com.zy.common.ExecuteSupport;
import com.zy.core.ThreadHandler;
import com.zy.core.enums.*;
import com.zy.core.model.CommandResponse;
import com.zy.core.model.command.LiftCommand;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.model.protocol.LiftStaProtocol;
import java.util.List;
public interface LiftThread extends ThreadHandler {
    LiftProtocol getStatus();//获取提升机状态
    LiftProtocol getStatus(boolean clone);//获取提升机状态
    List<LiftStaProtocol> getLiftStaProtocols();
    CommandResponse pickAndPut(LiftCommand command);//取放货指令
    CommandResponse shuttleSwitch(LiftCommand command);//小车换层
    CommandResponse move(LiftCommand command);//小车移动
    CommandResponse switchIOMode(LiftCommand command);//切换出入库模式
    CommandResponse reset();//复位
    boolean isIdle();//是否空闲
    boolean isDeviceIdle();//设备是否空闲
    boolean isDeviceIdle(ExecuteSupport support);//设备是否空闲
    boolean setProtocolStatus(LiftProtocolStatusType status);//设置工作状态
    boolean setSyncTaskNo(Integer taskNo);//设置工作号
    int generateDeviceTaskNo(int taskNo, LiftTaskModeType type);//生成硬件设备工作号
    String getCurrentLocNo();
    //***************获取命令*****************
    LiftCommand getPickAndPutCommand(Integer taskNo, Integer pick, Integer put);//取放货指令
    LiftCommand getShuttleSwitchCommand(Integer taskNo, Integer pick, Integer put);//小车换层
    LiftCommand getMoveCommand(Integer taskNo, Integer pick, Integer put);//提升机移动
    LiftCommand getSwitchIOCommand(Integer taskNo, LiftIoModeType mode);
    LiftCommand getResetCommand(Integer taskNo);
}
src/main/java/com/zy/core/thread/impl/NyLiftThread.java
New file
@@ -0,0 +1,695 @@
package com.zy.core.thread.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.DateUtils;
import com.core.common.SpringUtils;
import com.zy.asrs.entity.BasLift;
import com.zy.asrs.entity.DeviceConfig;
import com.zy.asrs.entity.DeviceDataLog;
import com.zy.asrs.service.BasLiftService;
import com.zy.asrs.service.DeviceDataLogService;
import com.zy.asrs.utils.Utils;
import com.zy.common.ExecuteSupport;
import com.zy.common.model.LiftPointModel;
import com.zy.common.utils.RedisUtil;
import com.zy.core.News;
import com.zy.core.action.LiftAction;
import com.zy.core.cache.OutputQueue;
import com.zy.core.enums.*;
import com.zy.core.model.CommandResponse;
import com.zy.core.model.DeviceCommandMsgModel;
import com.zy.core.model.DeviceMsgModel;
import com.zy.core.model.LiftStation;
import com.zy.core.model.command.LiftCommand;
import com.zy.core.model.protocol.LiftProtocol;
import com.zy.core.model.protocol.LiftStaProtocol;
import com.zy.core.thread.LiftThread;
import com.zy.core.utils.DeviceMsgUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TreeSet;
@Slf4j
@SuppressWarnings("all")
public class NyLiftThread implements LiftThread {
    private DeviceConfig device;
    private LiftProtocol liftProtocol;
    private RedisUtil redisUtil;
    LiftPointModel liftPointModel;
    private List<LiftStaProtocol> liftStaProtocols = new ArrayList<>();
    private List<DeviceMsgModel> readResultList = new ArrayList<>();
    private List<DeviceMsgModel> resultList = new ArrayList<>();
    public NyLiftThread(DeviceConfig device, LiftPointModel liftPointModel, List<LiftStation> stationList, RedisUtil redisUtil) {
        this.device = device;
        this.redisUtil = redisUtil;
        this.liftPointModel = liftPointModel;
        //初始化站点
        for (LiftStation station : stationList) {
            LiftStaProtocol liftStaProtocol = new LiftStaProtocol();
            liftStaProtocol.setStaNo(station.getStaNo());//站点号
            liftStaProtocol.setLev(station.getLev());//站点楼层
            String locNo = Utils.getLocNo(station.getRow(), station.getBay(), station.getLev());
            liftStaProtocol.setLocNo(locNo);//站点库位号
            liftStaProtocol.setLiftNo(station.getLiftNo());//提升机号
            liftStaProtocols.add(liftStaProtocol);
        }
    }
    @Override
    public boolean connect() {
        return true;
    }
    @Override
    public void close() {
    }
    @Override
    public void run() {
        News.info("{}号提升机线程启动", device.getDeviceNo());
        this.connect();
        //设备读取
        Thread readThread = new Thread(() -> {
            while (true) {
                try {
                    listenMessageFromRedis();
                    readStatus();
                    Thread.sleep(100);
                } catch (Exception e) {
                    log.error("LiftThread Fail", e);
                }
            }
        });
        readThread.start();
        while (true) {
            try {
                execute();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private void execute() {
        LiftAction liftAction = null;
        try {
            liftAction = SpringUtils.getBean(LiftAction.class);
        }catch (Exception e){}
        if (liftAction == null) {
            return;
        }
        Object object = redisUtil.get(RedisKeyType.LIFT_FLAG.key + device.getDeviceNo());
        if (object == null) {
            return;
        }
        Integer taskNo = Integer.valueOf(String.valueOf(object));
        if (taskNo != 0) {
            //存在任务需要执行
            boolean result = liftAction.executeWork(device.getDeviceNo(), taskNo);
        }
    }
    private void readStatus() {
        try {
            //获取提升机数据
            DeviceMsgUtils deviceMsgUtils = null;
            try {
                deviceMsgUtils = SpringUtils.getBean(DeviceMsgUtils.class);
            }catch (Exception e){
            }
            if(deviceMsgUtils == null){
                return;
            }
            LiftCommand readStatusCommand = getReadStatusCommand();
            //指令超过2条,不再下发任务状态请求
            TreeSet<String> deviceCommandMsgListKey = deviceMsgUtils.getDeviceCommandMsgListKey(SlaveType.Lift, device.getDeviceNo());
            if (deviceCommandMsgListKey.size() < 2) {
                requestCommand(readStatusCommand);//请求状态
            }
            if (this.readResultList.isEmpty()) {
                return;
            }
            DeviceMsgModel deviceMsgModel = this.readResultList.get(0);
            this.readResultList.remove(0);
            JSONObject deviceMsg = JSON.parseObject(JSON.toJSONString(deviceMsgModel.getDeviceMsg()));
            if (!deviceMsg.getString("result").equals("success")) {
                return;
            }
            JSONObject data = deviceMsg.getJSONObject("deviceStatus");
            if (null == liftProtocol) {
                liftProtocol = new LiftProtocol();
                liftProtocol.setLiftNo(device.getDeviceNo());
                liftProtocol.setProtocolStatus(LiftProtocolStatusType.NONE);
                InnerLiftExtend innerLiftExtend = new InnerLiftExtend();
                liftProtocol.setExtend(innerLiftExtend);
            }
            //----------读取提升机状态-----------
            //模式
            liftProtocol.setModel(data.getInteger("model"));
            //PLC任务号
            liftProtocol.setPlcTaskNo(data.getInteger("plcTaskNo"));
            //任务状态
            liftProtocol.setProtocolStatus(data.getInteger("protocolStatus"));
            //任务模式
            liftProtocol.setTaskMode(data.getInteger("taskMode"));
            //取货数据
            liftProtocol.setPick(data.getInteger("pick"));
            //放货数据
            liftProtocol.setPut(data.getInteger("put"));
            //有托盘
            liftProtocol.setHasTray(data.getInteger("hasTray") == 1);
            //有小车
            liftProtocol.setHasCar(data.getInteger("hasCar") == 1);
            //出入库模式
            liftProtocol.setIOMode(data.getInteger("iOMode"));
            //故障码
            liftProtocol.setErrorCode(data.getInteger("errorCode"));
            //当前层
            liftProtocol.setLev(data.getInteger("lev"));
            //************补充扩展字段*************
            InnerLiftExtend liftExtend = (InnerLiftExtend) liftProtocol.getExtend();
            liftProtocol.setExtend(liftExtend);
            liftExtend.setFrontOverrun(data.getBoolean("frontOverrun"));
            liftExtend.setBackOverrun(data.getBoolean("backOverrun"));
            liftExtend.setLeftOverrun(data.getBoolean("leftOverrun"));
            liftExtend.setRightOverrun(data.getBoolean("rightOverrun"));
            liftExtend.setOverHeight(data.getBoolean("overHeight"));
            liftExtend.setOverWeight(data.getBoolean("overWeight"));
            JSONArray trayList = data.getJSONArray("trayList");
            for (int i = 0; i < trayList.size(); i++) {
                int hasTray = (int) trayList.get(i);
                LiftStaProtocol liftStaProtocol = liftStaProtocols.get(i);
                liftStaProtocol.setHasTray(hasTray == 1);
            }
            JSONArray carList = data.getJSONArray("carList");
            for (int i = 0; i < carList.size(); i++) {
                int hasCar = (int) carList.get(i);
                LiftStaProtocol liftStaProtocol = liftStaProtocols.get(i);
                liftStaProtocol.setHasCar(hasCar == 1);
            }
            if (System.currentTimeMillis() - liftProtocol.getDeviceDataLog() > 1000 * 5) {
                //采集时间超过5s,保存一次数据记录
                //保存数据记录
                DeviceDataLogService deviceDataLogService = SpringUtils.getBean(DeviceDataLogService.class);
                DeviceDataLog deviceDataLog = new DeviceDataLog();
                deviceDataLog.setOriginData(JSON.toJSONString(data));
                deviceDataLog.setWcsData(JSON.toJSONString(liftProtocol));
                deviceDataLog.setType("lift");
                deviceDataLog.setDeviceNo(liftProtocol.getLiftNo());
                deviceDataLog.setCreateTime(new Date());
                deviceDataLogService.insert(deviceDataLog);
                //更新采集时间
                liftProtocol.setDeviceDataLog(System.currentTimeMillis());
            }
            //将提升机状态保存至数据库
            BasLiftService basLiftService = SpringUtils.getBean(BasLiftService.class);
            BasLift basLift = basLiftService.selectOne(new EntityWrapper<BasLift>()
                    .eq("lift_no", device.getDeviceNo()));
            if (basLift == null) {
                basLift = new BasLift();
                //提升机号
                basLift.setLiftNo(liftProtocol.getLiftNo());
                basLift.setStatus(1);
                basLiftService.insert(basLift);
            }
            //任务号
            basLift.setWrkNo(liftProtocol.getTaskNo());
            //修改时间
            basLift.setUpdateTime(new Date());
            //设备状态
            basLift.setDeviceStatus(JSON.toJSONString(liftProtocol));
            if (basLiftService.updateById(basLift)) {
                OutputQueue.LIFT.offer(MessageFormat.format("【{0}】[id:{1}] <<<<< 实时数据更新成功",DateUtils.convert(new Date()), liftProtocol.getLiftNo()));
            }
        } catch (Exception e) {
            e.printStackTrace();
            OutputQueue.LIFT.offer(MessageFormat.format("【{0}】读取提升机状态信息失败 ===>> [id:{1}] [ip:{2}] [port:{3}]", DateUtils.convert(new Date()), device.getDeviceNo(), device.getIp(), device.getPort()));
        }
    }
    @Override
    public LiftProtocol getStatus(boolean clone) {
        if (this.liftProtocol == null) {
            return null;
        }
        return clone ? this.liftProtocol.clone() : this.liftProtocol;
    }
    @Override
    public List<LiftStaProtocol> getLiftStaProtocols() {
        return this.liftStaProtocols;
    }
    @Override
    public LiftProtocol getStatus() {
        return getStatus(true);
    }
    @Override
    public CommandResponse pickAndPut(LiftCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            String resultKey = requestCommand(command);
            //查询请求结果
            JSONObject result = queryCommandStatus(resultKey);
            if (result == null) {
                return response;//请求失败
            }
            if(!result.getString("result").equals("success")) {
                return response;//请求失败
            }
            this.liftProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            response.setMessage(e.getMessage());
            return response;
        }
    }
    @Override
    public CommandResponse shuttleSwitch(LiftCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            String resultKey = requestCommand(command);
            //查询请求结果
            JSONObject result = queryCommandStatus(resultKey);
            if (result == null) {
                return response;//请求失败
            }
            if(!result.getString("result").equals("success")) {
                return response;//请求失败
            }
            this.liftProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            response.setMessage(e.getMessage());
            return response;
        }
    }
    @Override
    public CommandResponse move(LiftCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            String resultKey = requestCommand(command);
            //查询请求结果
            JSONObject result = queryCommandStatus(resultKey);
            if (result == null) {
                return response;//请求失败
            }
            if(!result.getString("result").equals("success")) {
                return response;//请求失败
            }
            this.liftProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            response.setMessage(e.getMessage());
            return response;
        }
    }
    @Override
    public CommandResponse switchIOMode(LiftCommand command) {
        CommandResponse response = new CommandResponse(false);
        try {
            //发出请求
            String resultKey = requestCommand(command);
            //查询请求结果
            JSONObject result = queryCommandStatus(resultKey);
            if (result == null) {
                return response;//请求失败
            }
            if(!result.getString("result").equals("success")) {
                return response;//请求失败
            }
            this.liftProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            response.setMessage(e.getMessage());
            return response;
        }
    }
    @Override
    public CommandResponse reset() {
        CommandResponse response = new CommandResponse(false);
        try {
            LiftCommand resetCommand = getResetCommand(9999);
            //发出请求
            String resultKey = requestCommand(resetCommand);
            //查询请求结果
            JSONObject result = queryCommandStatus(resultKey);
            if (result == null) {
                return response;//请求失败
            }
            if(!result.getString("result").equals("success")) {
                return response;//请求失败
            }
            this.liftProtocol.setSendTime(System.currentTimeMillis());//指令下发时间
            response.setMessage(JSON.toJSONString(result));
            response.setResult(true);
            return response;
        } catch (Exception e) {
            e.printStackTrace();
            response.setMessage(e.getMessage());
            return response;
        }
    }
    @Override
    public boolean isIdle() {
        if (this.liftProtocol.getTaskNo() == null
                || this.liftProtocol.getPlcTaskNo() == null
                || this.liftProtocol.getProtocolStatus() == null
                || this.liftProtocol.getModel() == null
                || this.liftProtocol.getErrorCode() == null
                || this.liftProtocol.getExtend() == null
        ) {
            return false;
        }
        InnerLiftExtend extend = (InnerLiftExtend) this.liftProtocol.getExtend();
        boolean res = this.liftProtocol.getProtocolStatus() == LiftProtocolStatusType.IDLE.id
                && this.liftProtocol.getPlcTaskNo() == 0
                && this.liftProtocol.getTaskNo() == 0
                && this.liftProtocol.getModel() == 2
                && this.liftProtocol.getErrorCode() == 0
                && !extend.getFrontOverrun()
                && !extend.getBackOverrun()
                && !extend.getLeftOverrun()
                && !extend.getRightOverrun()
                && !extend.getOverHeight()
                && !extend.getOverWeight()
                ;
        return res;
    }
    @Override
    public boolean isDeviceIdle() {
        return isDeviceIdle(null);
    }
    @Override
    public boolean isDeviceIdle(ExecuteSupport support) {
        if (null != support) {
            Boolean judgement = support.judgement();
            if (judgement != null && !judgement) {
                return true;
            }
        }
        if (this.liftProtocol.getProtocolStatus() == null
                || this.liftProtocol.getModel() == null
                || this.liftProtocol.getErrorCode() == null
                || this.liftProtocol.getExtend() == null
        ) {
            return false;
        }
        InnerLiftExtend extend = (InnerLiftExtend) this.liftProtocol.getExtend();
        boolean res = this.liftProtocol.getProtocolStatus() == LiftProtocolStatusType.IDLE.id
                && this.liftProtocol.getModel() == 2
                && this.liftProtocol.getErrorCode() == 0
                && !extend.getFrontOverrun()
                && !extend.getBackOverrun()
                && !extend.getLeftOverrun()
                && !extend.getRightOverrun()
                && !extend.getOverHeight()
                && !extend.getOverWeight()
                ;
        return res;
    }
    @Override
    public boolean setProtocolStatus(LiftProtocolStatusType status) {
        this.liftProtocol.setProtocolStatus(status);
        return true;
    }
    @Override
    public boolean setSyncTaskNo(Integer taskNo) {
        this.liftProtocol.setSyncTaskNo(taskNo);
        return true;
    }
    @Override
    public int generateDeviceTaskNo(int taskNo, LiftTaskModeType type) {
        return taskNo;
    }
    @Override
    public String getCurrentLocNo() {
        if (liftProtocol.getLev() == null) {
            return null;
        }
        return Utils.getLocNo(liftPointModel.getRow(), liftPointModel.getBay(), liftProtocol.getLev());
    }
    @Override
    public LiftCommand getPickAndPutCommand(Integer taskNo, Integer pick, Integer put) {
        LiftCommand command = new LiftCommand();
        command.setLiftNo(device.getDeviceNo());
        command.setTaskNo(taskNo);
        command.setMode(LiftTaskModeType.PICK_PUT.id);
        command.setPick(pick);
        command.setPut(put);
        return command;
    }
    @Override
    public LiftCommand getShuttleSwitchCommand(Integer taskNo, Integer pick, Integer put) {
        LiftCommand command = new LiftCommand();
        command.setLiftNo(device.getDeviceNo());
        command.setTaskNo(taskNo);
        command.setMode(LiftTaskModeType.SHUTTLE_SWITCH.id);
        command.setPick(pick);
        command.setPut(put);
        return command;
    }
    @Override
    public LiftCommand getMoveCommand(Integer taskNo, Integer pick, Integer put) {
        LiftCommand command = new LiftCommand();
        command.setLiftNo(device.getDeviceNo());
        command.setTaskNo(taskNo);
        command.setMode(LiftTaskModeType.MOVE.id);
        command.setPick(pick);
        command.setPut(put);
        return command;
    }
    @Override
    public LiftCommand getSwitchIOCommand(Integer taskNo, LiftIoModeType mode) {
        LiftCommand command = new LiftCommand();
        command.setLiftNo(device.getDeviceNo());
        if (mode.equals(LiftIoModeType.IN)) {
            command.setMode(LiftIoModeType.IN.id);
        } else {
            command.setMode(LiftIoModeType.OUT.id);
        }
        return command;
    }
    @Override
    public LiftCommand getResetCommand(Integer taskNo) {
        LiftCommand command = new LiftCommand();
        command.setLiftNo(device.getDeviceNo());
        command.setMode(LiftTaskModeType.RESET.id);
        return command;
    }
    //获取读状态信息命令
    private LiftCommand getReadStatusCommand() {
        LiftCommand command = new LiftCommand();
        command.setLiftNo(device.getDeviceNo());
        command.setMode(LiftTaskModeType.READ_STATUS.id);
        return command;
    }
    //发出请求
    private String requestCommand(LiftCommand command) throws IOException {
        try {
            DeviceMsgUtils deviceMsgUtils = SpringUtils.getBean(DeviceMsgUtils.class);
            if (deviceMsgUtils == null) {
                return null;
            }
            //压缩数据包
            JSONObject data = JSON.parseObject(JSON.toJSONString(command));
            DeviceCommandMsgModel commandMsgModel = new DeviceCommandMsgModel();
            commandMsgModel.setDeviceId(device.getDeviceNo());
            commandMsgModel.setDeviceType(String.valueOf(SlaveType.Lift));
            commandMsgModel.setCommand(data);
            String key = deviceMsgUtils.sendDeviceCommand(SlaveType.Lift, device.getDeviceNo(), commandMsgModel);
            return key;
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private JSONObject queryCommandStatus(String resultKey) {
        // 获取服务器响应
        // 尝试50次
        JSONObject result = null;
        for (int i = 0; i < 50; i++) {
            result = getRequestBody(resultKey);
            if (result == null) {
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else {
                break;
            }
        }
        return result;
    }
    public JSONObject getRequestBody(String resultKey) {
        try {
            // 获取服务器响应
            JSONObject result = null;
            int idx = -1;
            for (int i = 0; i < resultList.size(); i++) {
                DeviceMsgModel deviceMsgModel = resultList.get(i);
                if(deviceMsgModel.getResultKey().equals(resultKey)){
                    idx = i;
                    result = JSON.parseObject(JSON.toJSONString(deviceMsgModel.getDeviceMsg()));
                    break;
                }
            }
            if (result == null) {
                return null;//无响应结果
            }
            resultList.remove(idx);
            return result;
        } catch (Exception e) {
            return null;
        }
    }
    private void listenMessageFromRedis() {
        try {
            DeviceMsgUtils deviceMsgUtils = null;
            try {
                deviceMsgUtils = SpringUtils.getBean(DeviceMsgUtils.class);
            }catch (Exception e){
            }
            if (deviceMsgUtils == null) {
                return;
            }
            DeviceMsgModel deviceMsg = deviceMsgUtils.getDeviceMsg(SlaveType.Lift, device.getDeviceNo());
            if(deviceMsg == null){
                return;
            }
            if (deviceMsg.getDeviceMsgType().equals("status")) {
                readResultList.add(deviceMsg);
            }else {
                resultList.add(deviceMsg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 扩展字段
     */
    @Data
    private class InnerLiftExtend {
        /**
         * 前超限
         */
        private Boolean frontOverrun;
        /**
         * 后超限
         */
        private Boolean backOverrun;
        /**
         * 左超限
         */
        private Boolean leftOverrun;
        /**
         * 右超限
         */
        private Boolean rightOverrun;
        /**
         * 超高
         */
        private Boolean overHeight;
        /**
         * 超重
         */
        private Boolean overWeight;
    }
}
src/main/java/com/zy/core/utils/DeviceMsgUtils.java
@@ -130,6 +130,8 @@
            return RedisKeyType.DEVICE_SHUTTLE_MSG_KEY_.key + deviceId + "_";
        } else if (deviceType.equals(SlaveType.ForkLift)) {
            return RedisKeyType.DEVICE_FORK_LIFT_MSG_KEY_.key + deviceId + "_";
        } else if (deviceType.equals(SlaveType.Lift)) {
            return RedisKeyType.DEVICE_LIFT_MSG_KEY_.key + deviceId + "_";
        }else {
            throw new CoolException("设备类型未定义");
        }
@@ -144,6 +146,8 @@
            return RedisKeyType.DEVICE_SHUTTLE_COMMAND_MSG_KEY.key + deviceId + "_";
        } else if (deviceType.equals(SlaveType.ForkLift)) {
            return RedisKeyType.DEVICE_FORK_LIFT_COMMAND_MSG_KEY.key + deviceId + "_";
        } else if (deviceType.equals(SlaveType.Lift)) {
            return RedisKeyType.DEVICE_LIFT_COMMAND_MSG_KEY.key + deviceId + "_";
        }else {
            throw new CoolException("设备类型未定义");
        }
src/main/webapp/views/index.html
@@ -19,7 +19,8 @@
    <div class="nav">
        <ul class="cl-effect-4">
            <li><a id="console" onclick="nav(this.id)" class="nav-select" href="#">主控图</a></li>
            <li><a id="forklift" onclick="nav(this.id)" class="nav-unselect" href="#">提升机</a></li>
            <li><a id="forklift" onclick="nav(this.id)" class="nav-unselect" href="#">货叉提升机</a></li>
            <li><a id="lift" onclick="nav(this.id)" class="nav-unselect" href="#">提升机</a></li>
            <li><a id="shuttle" onclick="nav(this.id)" class="nav-unselect" href="#">四向穿梭车</a></li>
            <li><a id="admin" onclick="nav(this.id)" class="nav-unselect" href="#">管理后台</a></li>
        </ul>
src/main/webapp/views/lift_old.html