zjj
2024-11-18 f11ebf31a302d2a8a755625cec83294c67a9088c
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/service/impl/MainServiceImpl.java
@@ -4,15 +4,22 @@
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zy.asrs.common.domain.dto.StartupDto;
import com.zy.asrs.common.domain.param.SearchLocParam;
import com.zy.asrs.common.utils.HttpHandler;
import com.zy.asrs.framework.common.Cools;
import com.zy.asrs.framework.common.R;
import com.zy.asrs.framework.common.SnowflakeIdWorker;
import com.zy.asrs.wcs.core.domain.dto.MatDto;
import com.zy.asrs.wcs.core.domain.dto.RedisMapDto;
import com.zy.asrs.wcs.core.domain.dto.StaDto;
import com.zy.asrs.wcs.core.domain.param.CreateInTaskParam;
import com.zy.asrs.wcs.core.entity.*;
import com.zy.asrs.wcs.core.kernel.AnalyzeService;
import com.zy.asrs.wcs.core.model.MapNode;
import com.zy.asrs.wcs.core.model.enums.DeviceCtgType;
import com.zy.asrs.wcs.core.model.enums.MotionStsType;
import com.zy.asrs.wcs.core.model.enums.TaskStsType;
import com.zy.asrs.wcs.core.model.enums.*;
import com.zy.asrs.wcs.core.service.*;
import com.zy.asrs.wcs.core.utils.OpenUtils;
import com.zy.asrs.wcs.core.utils.RedisUtil;
import com.zy.asrs.wcs.core.utils.ShuttleDispatcher;
import com.zy.asrs.wcs.core.utils.Utils;
@@ -20,12 +27,15 @@
import com.zy.asrs.wcs.rcs.cache.SlaveConnection;
import com.zy.asrs.wcs.rcs.constant.DeviceRedisConstant;
import com.zy.asrs.wcs.rcs.entity.Device;
import com.zy.asrs.wcs.rcs.model.command.LedCommand;
import com.zy.asrs.wcs.rcs.model.enums.ShuttleProtocolStatusType;
import com.zy.asrs.wcs.rcs.model.enums.SlaveType;
import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol;
import com.zy.asrs.wcs.rcs.model.protocol.StaProtocol;
import com.zy.asrs.wcs.rcs.service.DeviceService;
import com.zy.asrs.wcs.rcs.thread.BarcodeThread;
import com.zy.asrs.wcs.rcs.thread.DevpThread;
import com.zy.asrs.wcs.rcs.thread.LedThread;
import com.zy.asrs.wcs.rcs.thread.ShuttleThread;
import com.zy.asrs.wcs.system.entity.Dict;
import com.zy.asrs.wcs.system.service.DictService;
@@ -33,7 +43,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.*;
/**
@@ -67,13 +77,196 @@
    private ShuttleDispatcher shuttleDispatcher;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private BasConveyorService basConveyorService;
    @Autowired
    private BasConveyorStaService basConveyorStaService;
    @Autowired
    private BasConveyorPathService basConveyorPathService;
    @Autowired
    private BasLedService basLedService;
    @Autowired
    private DeviceBarcodeService deviceBarcodeService;
    @Autowired
    private ShuttleChargeStaService shuttleChargeStaService;
    @Autowired
    private OpenUtils openUtils;
    /**
     * 组托
     * 入库站,根据条码扫描生成入库工作档,工作状态 2
     */
    public synchronized void generateInboundWrk() {
        try {
            // 根据输送线plc遍历
            List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>()
                    .eq(Device::getDeviceType, DeviceCtgType.CONVEYOR.val())
                    .eq(Device::getStatus, 1));
            for (Device devp : list) {
                BasConveyor basConveyor = basConveyorService.getOne(new LambdaQueryWrapper<BasConveyor>().eq(BasConveyor::getDeviceId, devp.getId()).eq(BasConveyor::getHostId, devp.getHostId()));
                // 遍历入库口
                for (StaDto inSta : JSON.parseArray(basConveyor.getInSta(), StaDto.class)) {
                    BasConveyorSta basConveyorSta = basConveyorStaService.selectBySiteNo(inSta.getStaNo().toString());
                    if(basConveyorSta == null) {
                        continue;
                    }
                    // 获取入库站信息
                    DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Conveyor, devp.getId().intValue());
                    StaProtocol staProtocol = devpThread.getStation().get(inSta.getStaNo());
                    if (staProtocol == null) {
                        continue;
                    } else {
                        staProtocol = staProtocol.clone();
                    }
                    Short workNo = staProtocol.getWorkNo();
                    // 尺寸检测异常
                    boolean back = false;
                    String errMsg = "异常:";
                    if (staProtocol.isFrontErr()) {
                        errMsg = errMsg + "前超限;";
                        back = true;
                    }
                    if (staProtocol.isBackErr()) {
                        errMsg = errMsg + "后超限";
                        back = true;
                    }
                    if (staProtocol.isHighErr()) {
                        errMsg = errMsg + "高超限";
                        back = true;
                    }
                    if (staProtocol.isLeftErr()) {
                        errMsg = errMsg + "左超限";
                        back = true;
                    }
                    if (staProtocol.isRightErr()) {
                        errMsg = errMsg + "右超限";
                        back = true;
                    }
                    if (staProtocol.isWeightErr()) {
                        errMsg = errMsg + "超重";
                        back = true;
                    }
                    if (staProtocol.isBarcodeErr()) {
                        errMsg = errMsg + "扫码失败";
                        back = true;
                    }
                    // 退回
                    if (back) {
                        // led 异常显示
                        LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                        if (ledThread != null) {
                            ledThread.error(errMsg);
                        }
                        continue;
                    }
                    // 判断是否满足入库条件
                    if (staProtocol.isAutoing() && staProtocol.isLoading()
                            && staProtocol.isInEnable()
                            && !staProtocol.isEmptyMk() && (workNo == 0 || (workNo >= 9990 && workNo <= 9999))
                            && staProtocol.isPakMk()
                    ) {
                        // 获取条码扫描仪信息
                        DeviceBarcode deviceBarcode = deviceBarcodeService.getById(basConveyorSta.getBarcodeId());
                        if(deviceBarcode == null) {
                            continue;
                        }
                        BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, Integer.parseInt(deviceBarcode.getDeviceId()));
                        if (barcodeThread == null) {
                            continue;
                        }
                        String barcode = barcodeThread.getBarcode();
                        if (!Cools.isEmpty(barcode)) {
                            News.info("{}号条码扫描器检测条码信息:{}", deviceBarcode.getId(), barcode);
                            if ("NG".endsWith(barcode) || "NoRead".equals(barcode) || "empty".equals(barcode) || "00000000".equals(barcode)) {
                                staProtocol.setWorkNo((short) 32002);
                                staProtocol.setStaNo(inSta.getBackSta().shortValue());
                                devpThread.setPakMk(staProtocol.getSiteId(), false);
                                devpThread.writeWorkSta(staProtocol.getSiteId(), (short) 32002, inSta.getBackSta().shortValue());
                                // led 异常显示
                                LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                                if (ledThread != null) {
                                    String errorMsg = "扫码失败,请重试";
                                    ledThread.error(errorMsg);
                                }
                                continue;
                            }
                        }
                        // 判断重复工作档
                        Task task1 = taskService.getOne(new LambdaQueryWrapper<Task>()
                                .eq(Task::getOriginSite, inSta.getStaNo())
                                .in(Task::getTaskSts, TaskStsType.NEW_INBOUND.sts, TaskStsType.ANALYZE_INBOUND.sts, TaskStsType.EXECUTE_INBOUND.sts)
                                .eq(Task::getZpallet, barcode));
                        if (task1 != null) {
                            News.error("工作档已存在,工作号={}", task1.getTaskNo());
                            if (staProtocol.getWorkNo().intValue() != Integer.parseInt(task1.getTaskNo())) {
                                devpThread.writeWorkSta(staProtocol.getSiteId(), Short.parseShort(task1.getTaskNo()), Short.parseShort(task1.getDestSite()));
                                devpThread.setPakMk(staProtocol.getSiteId(), false);
                                News.info("输送线入库命令下发,任务数据={}", JSON.toJSON(task1));
                            }
                            continue;
                        }
                        try {
                            //获取WMS地址
                            Dict dict = dictService.getOne(new LambdaQueryWrapper<Dict>().eq(Dict::getFlag, "WMS_URL").eq(Dict::getStatus, 1));
                            if (dict == null) {
                                News.error("WMS地址未配置");
                                continue;
                            }
                            String wmsUrl = dict.getValue();
                            SearchLocParam param = new SearchLocParam();
                            param.setBarcode(barcode);
                            param.setIoType(1);
                            param.setSourceStaNo(inSta.getStaNo());
                            param.setLocType1(staProtocol.getLocType1().shortValue());
                            String response = new HttpHandler.Builder()
                                    .setUri(wmsUrl)
                                    .setPath("/rpc/pakin/loc/v1")
                                    .setJson(JSON.toJSONString(param))
                                    .build()
                                    .doPost();
                            JSONObject jsonObject = JSON.parseObject(response);
                            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, inSta.getLed());
                            Integer code = jsonObject.getInteger("code");
                            if (code.equals(200)) {
                                StartupDto dto = jsonObject.getObject("data", StartupDto.class);
                                String wmsLocNo = dto.getLocNo();
                                int row = Integer.parseInt(wmsLocNo.substring(0, 2));
                                int bay = Integer.parseInt(wmsLocNo.substring(2, 5));
                                int lev = Integer.parseInt(wmsLocNo.substring(5, 7));
                                row -= 16;
                                String wcsLocNo = Utils.getLocNo(row, bay, lev);
                                CreateInTaskParam createInTaskParam = new CreateInTaskParam();
                                createInTaskParam.setTaskNo(String.valueOf(dto.getWorkNo()));
                                createInTaskParam.setDestLoc(wcsLocNo);
                                createInTaskParam.setOriginSite("31002");
                                createInTaskParam.setDestSite("31004");
                                createInTaskParam.setPriority(11);
                                createInTaskParam.setBarcode(barcode);
                                R result = openUtils.createInTask(createInTaskParam);
                                News.info("创建入库任务,任务数据={},WMS响应={},请求响应={}", JSON.toJSON(param), JSON.toJSON(jsonObject), JSON.toJSON(result));
                            }else {
                                News.error("入库申请失败,任务数据={},请求响应={}", JSON.toJSON(param), JSON.toJSON(jsonObject));
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
@@ -82,13 +275,18 @@
    public synchronized void initRealtimeBasMap() {
        try {
            List<Dict> dicts = dictService.list(new LambdaQueryWrapper<Dict>()
                    .like(Dict::getFlag, "map")
                    .like(Dict::getFlag, "map-")
                    .eq(Dict::getStatus, 1));
            TreeMap<Integer, ArrayList<ArrayList<MapNode>>> levData = new TreeMap<>();
            for (Dict dict : dicts) {
                String[] split = dict.getFlag().split("-");
                int lev = Integer.parseInt(split[1]);
                Object data = redisUtil.get(DeviceRedisConstant.MAP + lev);
                if (data != null) {
                    continue;
                }
                TreeMap<Integer, List<JSONObject>> rows = new TreeMap<>();
                //排序Row
@@ -121,6 +319,19 @@
                        mapNode.setRow(object.getInteger("row"));
                        mapNode.setBay(object.getInteger("bay"));
                        mapNode.setNo(object.getString("row") + "-" + object.getString("bay"));
                        mapNode.setXBase(object.getInteger("refx"));
                        mapNode.setYBase(object.getInteger("refy"));
                        if(mapNode.getValue() == MapNodeType.CONVEYOR.id) {
                            //输送线,判断小车是否可走
                            if (object.containsKey("conveyorHasGo")) {
                                if(object.getBoolean("conveyorHasGo")) {
                                    //小车可走
                                    mapNode.setValue(MapNodeType.CONVEYOR_CAR_GO.id);
                                }
                            }
                        }
                        nodes.add(mapNode);
                    }
@@ -131,7 +342,36 @@
                        }
                    });
                    list.add(nodes);
                    ArrayList<MapNode> sortNodes = new ArrayList<>();
                    int defaultBay = 1;//默认从1列开始
                    for (MapNode node : nodes) {
                        if (node.getBay() == defaultBay) {
                            defaultBay++;
                            sortNodes.add(node);
                            continue;
                        }
                        //存在空缺节点,自动补足
                        for (int i = defaultBay; i < node.getBay(); i++) {
                            MapNode mapNode = new MapNode();
                            mapNode.setValue(MapNodeType.DISABLE.id);
                            mapNode.setTop(1000);
                            mapNode.setBottom(1000);
                            mapNode.setLeft(1000);
                            mapNode.setRight(1000);
                            mapNode.setRow(node.getRow());
                            mapNode.setBay(i);
                            mapNode.setNo(node.getRow() + "-" + i);
                            mapNode.setXBase(0);
                            mapNode.setYBase(0);
                            sortNodes.add(mapNode);
                        }
                        defaultBay = node.getBay() + 1;
                        sortNodes.add(node);
                    }
                    list.add(sortNodes);
                }
                levData.put(lev, list);
@@ -141,7 +381,7 @@
                ArrayList<ArrayList<MapNode>> lists = entry.getValue();//获取地图
                MapNode mapNode = new MapNode();
                mapNode.setValue(-1);
                mapNode.setValue(MapNodeType.DISABLE.id);
                mapNode.setTop(1000);
                mapNode.setBottom(1000);
                mapNode.setLeft(1000);
@@ -149,6 +389,8 @@
                mapNode.setRow(0);
                mapNode.setBay(0);
                mapNode.setNo("0-0");
                mapNode.setXBase(0);
                mapNode.setYBase(0);
                //获取最长row
                int row = 0;
@@ -162,6 +404,19 @@
                    list.add(mapNode.clone());
                }
                //最后一次检测地图节点是否完整,地图矩阵row均要达到最长row
                for (ArrayList<MapNode> list : lists) {
                    int len = (row + 2);//row+2是因为头节点和尾节点存在人为添加的-1节点
                    if (list.size() == len) {
                        continue;
                    }
                    //节点长度不满足,进行补足
                    for (int i = list.size(); i < len; i++) {
                        list.add(mapNode.clone());
                    }
                }
                ArrayList<MapNode> headNodes = new ArrayList<>();
                ArrayList<MapNode> footerNodes = new ArrayList<>();
                for (int i = 0; i < row+2; i++) {
@@ -174,11 +429,11 @@
                Integer lev = entry.getKey();
                Date now = new Date();
                HashMap<String, Object> map = new HashMap<>();
                map.put("data", JSON.toJSONString(lists));
                map.put("create_time", now);
                map.put("update_time", now);
                map.put("lev", lev);
                RedisMapDto map = new RedisMapDto();
                map.setData(JSON.toJSONString(lists));
                map.setCreateTime(now);
                map.setUpdateTime(now);
                map.setLev(lev);
                //将地图数据存入redis
                redisUtil.set(DeviceRedisConstant.MAP + lev, JSON.toJSONString(map));
@@ -191,12 +446,77 @@
    // 解析入库工作档
    public synchronized void analyzeInBoundTask() {
        for (Task task : taskService.selectWaitAnalyzeInBoundTask()) {
            BasConveyorSta basConveyorSta = basConveyorStaService.getOne(new LambdaQueryWrapper<BasConveyorSta>().eq(BasConveyorSta::getSiteNo, task.getDestSite()));
            if (basConveyorSta == null) {
                continue;
            }
            BasConveyor basConveyor = basConveyorService.getById(basConveyorSta.getConveyorId());
            if (basConveyor == null) {
                continue;
            }
//            DeviceBarcode deviceBarcode = deviceBarcodeService.getById(basConveyorSta.getBarcodeId());
//            if (deviceBarcode == null) {
//                continue;
//            }
//            BarcodeThread barcodeThread = (BarcodeThread) SlaveConnection.get(SlaveType.Barcode, Integer.parseInt(deviceBarcode.getDeviceId()));
//            if (barcodeThread == null) {
//                continue;
//            }
//            if (!barcodeThread.getBarcode().equals(task.getZpallet())) {
//                continue;
//            }
            if (Cools.isEmpty(basConveyorSta.getTaskNo())){
                continue;
            }
            if (!basConveyorSta.getTaskNo().toString().equals(task.getTaskNo())){
                continue;
            }
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Conveyor, basConveyor.getDeviceId().intValue());
            if (devpThread == null) {
                continue;
            }
            StaProtocol staProtocol = devpThread.getStation().get(basConveyorSta.getSiteNo());
            if (staProtocol == null) {
                continue;
            }
            if (!(staProtocol.isAutoing()
                    && staProtocol.isLoading()
                    && staProtocol.isInEnable())) {
                continue;
            }
            //解析前判断内部目标值是否有物 有工作号
            StaProtocol staProtocolInside = devpThread.getStation().get(Utils.getStaByLev(Utils.getLev(task.getDestLoc())));
            if (staProtocolInside == null) {
                continue;
            }
            if (staProtocolInside.isLoading() || staProtocolInside.getWorkNo() !=0) {
                continue;
            }
            if (Cools.isEmpty(task.getShuttleNo())) {
                //分配小车
                //搜索空闲车
                ShuttleThread shuttleThread = shuttleDispatcher.searchIdleShuttle(task);
                if (shuttleThread == null) {
                    News.info("{}任务未找到空闲穿梭车", task.getTaskNo());
                    continue;
                }
                task.setShuttleNo(Integer.valueOf(shuttleThread.getDevice().getDeviceNo()));//保存穿梭车号
                task.setUpdateTime(new Date());
                if (!taskService.updateById(task)) {
                    News.info("{}任务更新穿梭车号失败", task.getTaskNo());
                }
                continue;
            }
            // generate motion list
            List<Motion> motionList = analyzeService.generateMotion(task);
            if (motionList.isEmpty()) {
                continue;
            }
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), task.getHostId());
            // 更新工作主档
            task.setTaskSts(TaskStsType.ANALYZE_INBOUND.sts); // 工作状态
@@ -210,35 +530,38 @@
    /**
     * 出库 ====>> 同一时间一台穿梭车只能有一个出库任务
     */
    public synchronized void generateOutboundWrkMast() {
    public synchronized void analyzeOutBoundTask() {
        List<Task> tasks = taskService.selectPakOut();
        if (tasks.isEmpty()) {
            return;
        }
        for (Task task : tasks) {
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, 1);
            BasConveyorSta originStaObj = basConveyorStaService.selectBySiteNo(task.getOriginSite());//获取源站
            if (originStaObj == null) {
                continue;
            }
            BasConveyor basConveyor = basConveyorService.getById(originStaObj.getConveyorId());
            if(basConveyor == null) {
                continue;
            }
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Conveyor, basConveyor.getDeviceId().intValue());
            StaProtocol staProtocol = devpThread.getStation().get(Integer.parseInt(task.getOriginSite()));//源站
            StaProtocol staProtocol1 = devpThread.getStation().get(Integer.parseInt(task.getDestSite()));//目标站
            if (staProtocol == null || staProtocol1 == null) {
//            StaProtocol staProtocol1 = devpThread.getStation().get(Integer.parseInt(task.getDestSite()));//目标站
            if (staProtocol == null) {
                continue;
            } else {
                staProtocol = staProtocol.clone();
                staProtocol1 = staProtocol1.clone();
//                staProtocol1 = staProtocol1.clone();
            }
//            // 查询站点详细信息
//            BasDevp staDetl = basDevpService.selectById(outSta.getStaNo());
//            if (staDetl == null) {
//                log.error("出库 ===>> 站点在数据库不存在, 站点编号={}", outSta.getStaNo());
//                continue;
//            }
            // 判断堆垛机出库站状态
            // 判断出库站状态
            if (staProtocol.isAutoing() && !staProtocol.isLoading() && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) {
                if (!(staProtocol1.isAutoing() && !staProtocol1.isLoading() && staProtocol1.getWorkNo() == 0 && staProtocol1.isOutEnable())) {
                    continue;
                }
//                if (!(staProtocol1.isAutoing() && !staProtocol1.isLoading() && staProtocol1.getWorkNo() == 0 && staProtocol1.isOutEnable())) {
//                    continue;
//                }
//                //同库位组校验
//                List<String> outerLoc = Utils.getGroupOuterLoc(wrkMast.getSourceLocNo());
@@ -248,13 +571,30 @@
//                    continue;//浅库位存在未执行任务
//                }
                if (Cools.isEmpty(task.getShuttleNo())) {
                    //分配小车
                    //搜索空闲车
                    ShuttleThread shuttleThread = shuttleDispatcher.searchIdleShuttle(task);
                    if (shuttleThread == null) {
                        News.info("{}任务未找到空闲穿梭车", task.getTaskNo());
                        continue;
                    }
                    task.setShuttleNo(Integer.valueOf(shuttleThread.getDevice().getDeviceNo()));//保存穿梭车号
                    task.setUpdateTime(new Date());
                    if (!taskService.updateById(task)) {
                        News.info("{}任务更新穿梭车号失败", task.getTaskNo());
                    }
                    continue;
                }
                // generate motion list
                List<Motion> motionList = analyzeService.generateMotion(task);
                if (Cools.isEmpty(motionList)) {
                    log.error("出库 ===>> 暂时没有空闲小车, 任务号={}", task.getTaskNo());
                    continue;
                }
                motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
                motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), task.getHostId());
                // 更新工作主档
                task.setTaskSts(TaskStsType.ANALYZE_OUTBOUND.sts); // 工作状态
@@ -267,21 +607,49 @@
        }
    }
    // 解析小车移动工作档
    public synchronized void analyzeMoveTask() {
        for (Task task : taskService.selectWaitAnalyzeMoveTask()) {
            if (Cools.isEmpty(task.getShuttleNo())) {
                //分配小车
                //搜索空闲车
                ShuttleThread shuttleThread = shuttleDispatcher.searchIdleShuttle(task);
                if (shuttleThread == null) {
                    News.info("{}任务未找到空闲穿梭车", task.getTaskNo());
                    continue;
                }
                task.setShuttleNo(Integer.valueOf(shuttleThread.getDevice().getDeviceNo()));//保存穿梭车号
                task.setUpdateTime(new Date());
                if (!taskService.updateById(task)) {
                    News.info("{}任务更新穿梭车号失败", task.getTaskNo());
                }
                continue;
            }
            // generate motion list
            List<Motion> motionList = analyzeService.generateShuttleMoveMotion(task);
            if (motionList.isEmpty()) {
                continue;
            }
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), task.getHostId());
            // 更新工作主档
            task.setTaskSts(TaskStsType.ANALYZE_MOVE.sts); // 工作状态
            task.setUpdateTime(new Date());
            if (!taskService.updateById(task)) {
                News.error("更新工作档失败!!! [工作号:{}]", task.getTaskNo());
            }
        }
    }
    /**
     * 四向穿梭车电量检测 ===>> 发起充电
     */
    public synchronized void loopShuttleCharge() {
        // 获取充电桩库位类型
        LocCtg locCtg = locCtgService.getOne(new LambdaQueryWrapper<LocCtg>()
                .eq(LocCtg::getFlag, "CHARGE")
                .eq(LocCtg::getStatus, 1));
        if (locCtg == null) {
            return;
        }
        //获取充电任务类型
        TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>()
                .eq(TaskCtg::getFlag, "CHARGE")
                .eq(TaskCtg::getFlag, String.valueOf(TaskCtgType.CHARGE))
                .eq(TaskCtg::getStatus, 1));
        if (taskCtg == null) {
            return;
@@ -313,20 +681,19 @@
            String currentLocNo = shuttleProtocol.getCurrentLocNo();
            int lev = Utils.getLev(currentLocNo);//获取小车楼层
            //搜索小车当前楼层充电桩
            ArrayList<Loc> allChargeLoc = new ArrayList<>();
            List<Loc> list1 = locService.list(new LambdaQueryWrapper<Loc>()
                    .eq(Loc::getLocCtg, locCtg.getId())
                    .eq(Loc::getStatus, 1)
                    .eq(Loc::getLev, lev));
            ArrayList<ShuttleChargeSta> allChargeLoc = new ArrayList<>();
            List<ShuttleChargeSta> list1 = shuttleChargeStaService.list(new LambdaQueryWrapper<ShuttleChargeSta>()
                    .eq(ShuttleChargeSta::getDeviceLev, lev)
                    .eq(ShuttleChargeSta::getStatus, 1));
            if (!list1.isEmpty()) {
                allChargeLoc.addAll(list1);
            }
            //搜索其他楼层充电桩
            List<Loc> list2 = locService.list(new LambdaQueryWrapper<Loc>()
                    .eq(Loc::getLocCtg, locCtg.getId())
                    .eq(Loc::getStatus, 1)
                    .notIn(Loc::getLev, lev));
            List<ShuttleChargeSta> list2 = shuttleChargeStaService.list(new LambdaQueryWrapper<ShuttleChargeSta>()
                    .notIn(ShuttleChargeSta::getDeviceLev, lev)
                    .eq(ShuttleChargeSta::getStatus, 1));
            if (!list2.isEmpty()) {
                allChargeLoc.addAll(list2);
            }
@@ -337,24 +704,34 @@
            }
            //选择空闲充电桩
            Loc chargeLoc = null;
            for (Loc loc : allChargeLoc) {
            ShuttleChargeSta chargeSta = null;
            for (ShuttleChargeSta shuttleChargeSta : allChargeLoc) {
                // 判断充电位是否被占用(车辆位置)
                if (Utils.hasShuttleInLoc(loc.getLocNo(), device.getId())) {
                if (Utils.hasShuttleInLoc(shuttleChargeSta.getDeviceLoc(), device.getId())) {
                    continue;
                }
                // 盘点充电位是否存在任务档
                List<Task> tasks = taskService.hasChargeInLoc(loc.getLocNo());
                List<Task> tasks = taskService.hasChargeInLoc(shuttleChargeSta.getDeviceLoc());
                if (!tasks.isEmpty()) {
                    continue;
                }
                chargeLoc = loc;
                Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>()
                        .eq(Loc::getLocNo, shuttleChargeSta.getDeviceLoc()));
                if (loc == null) {
                    continue;
                }
                if (!loc.getLocSts().equals(LocStsType.C.val())) {
                    continue;//库位不是充电桩
                }
                chargeSta = shuttleChargeSta;
                break;
            }
            if (chargeLoc == null) {
            if (chargeSta == null) {
                continue;//未找到充电桩
            }
@@ -375,7 +752,7 @@
                continue;
            }
            String chargeLocNo = chargeLoc.getLocNo();
            String chargeLocNo = chargeSta.getDeviceLoc();
            Task task = new Task();
            task.setUuid(String.valueOf(snowflakeIdWorker.nextId()));
            task.setTaskNo(String.valueOf(Utils.getTaskNo("CHARGE")));
@@ -399,7 +776,7 @@
                News.error("保存{}号四向穿梭车充电任务失败!!!", device.getDeviceNo());
                continue;
            }
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), task.getHostId());
            task.setTaskSts(TaskStsType.ANALYZE_CHARGE.sts);
            if (!taskService.save(task)) {
@@ -415,17 +792,9 @@
     * 四向穿梭车电量检测 ===>> 满电后回到待机位
     */
    public synchronized void loopShuttleToStandbyCauseCharge() {
        Integer enoughPower = 90;
        Dict dict = dictService.getOne(new LambdaQueryWrapper<Dict>()
                .eq(Dict::getFlag, "chargeMaxValue")
                .eq(Dict::getStatus, 1));
        if (dict != null) {
            enoughPower = Integer.parseInt(dict.getValue());
        }
        //获取迁移任务类型
        TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>()
                .eq(TaskCtg::getFlag, "MOVE")
                .eq(TaskCtg::getFlag, String.valueOf(TaskCtgType.MOVE))
                .eq(TaskCtg::getStatus, 1));
        if (taskCtg == null) {
            return;
@@ -438,6 +807,11 @@
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue());
            if (shuttleThread == null) {
                continue;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                continue;
            }
@@ -463,8 +837,21 @@
                continue;
            }
            ShuttleChargeSta chargeSta = shuttleChargeStaService.getOne(new LambdaQueryWrapper<ShuttleChargeSta>()
                    .eq(ShuttleChargeSta::getDeviceLoc, chargeTask.getDestLoc())
                    .eq(ShuttleChargeSta::getStatus, 1));
            if (chargeSta == null) {
                continue;//充电桩不存在,异常
            }
            String standbyLoc = chargeSta.getStandbyLoc();
            if (standbyLoc == null) {
                continue;//避让位置数据不存在
            }
            List<String> availableLoc = JSON.parseArray(standbyLoc, String.class);
            //获取避让位置
            String standByLocNo = shuttleDispatcher.searchStandByLocNo(Integer.valueOf(device.getDeviceNo()), device.getHostId(), shuttleThread.getStatus().getCurrentLocNo());
            String standByLocNo = shuttleDispatcher.searchAvailableLocNo(Integer.valueOf(device.getDeviceNo()), device.getHostId(), shuttleThread.getStatus().getCurrentLocNo(), availableLoc);
            Task task = new Task();
            task.setUuid(String.valueOf(snowflakeIdWorker.nextId()));
@@ -489,7 +876,7 @@
                News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo());
                continue;
            }
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()), task.getHostId());
            task.setTaskSts(TaskStsType.ANALYZE_MOVE.sts);
@@ -504,4 +891,168 @@
        }
    }
    /**
     * 出库  ===>> 工作档信息写入led显示器
     */
    public void ledExecute() {
        // 遍历LED
        List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, DeviceCtgType.LED.val())
                .eq(Device::getStatus, 1));
        for (Device ledDevice : list) {
            //获取led数据
            BasLed led = basLedService.getOne(new LambdaQueryWrapper<BasLed>()
                    .eq(BasLed::getDeviceId, ledDevice.getId()));
            List<Integer> staArr = JSON.parseArray(led.getSta(), Integer.class);
            BasConveyor basConveyor = basConveyorService.getById(new LambdaQueryWrapper<BasConveyor>()
                    .eq(BasConveyor::getDeviceId, led.getConveyorId().intValue()));
            if (basConveyor == null) {
                continue;
            }
            // 获取输送线plc线程
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Conveyor, basConveyor.getDeviceId().intValue());
            // 命令集合
            List<LedCommand> commands = new ArrayList<>();
            // 工作档集合
            List<Task> tasks = new ArrayList<>();
            for (Integer staNo : staArr) {
                // 获取叉车站点
                StaProtocol staProtocol = devpThread.getStation().get(staNo);
                if (null == staProtocol || null == staProtocol.getWorkNo() || 0 == staProtocol.getWorkNo() || !staProtocol.isLoading()) {
                    continue;
                } else {
                    staProtocol = staProtocol.clone();
                }
                // 获取工作档数据
                Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskNo, staProtocol.getWorkNo()));
                if (null == task) {
                    continue;
                }
                tasks.add(task);
                // 组装命令
                LedCommand ledCommand = new LedCommand();
                ledCommand.setWorkNo(task.getTaskNo());
                ledCommand.setIoType(task.getTaskCtg().intValue());
                ledCommand.setTitle(task.getTaskCtg$());
                ledCommand.setSourceLocNo(task.getOriginLoc());
                ledCommand.setLocNo(task.getDestLoc());
                ledCommand.setStaNo(Integer.parseInt(task.getDestSite()));
                try {
                    //获取WMS地址
                    Dict dict = dictService.getOne(new LambdaQueryWrapper<Dict>().eq(Dict::getFlag, "WMS_URL").eq(Dict::getStatus, 1));
                    if (dict != null) {
                        String wmsUrl = dict.getValue();
                        HashMap<String, Object> param = new HashMap<>();
                        param.put("taskNo", task.getTaskNo());
                        String response = new HttpHandler.Builder()
                                .setUri(wmsUrl)
                                .setPath("/queryTask")
                                .setJson(JSON.toJSONString(param))
                                .build()
                                .doPost();
                        JSONObject jsonObject = JSON.parseObject(response);
                        Integer code = jsonObject.getInteger("code");
                        if (code.equals(200)) {
                            List<MatDto> matDtos = JSON.parseArray(jsonObject.getString("data"), MatDto.class);
                            ledCommand.setMatDtos(matDtos);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                commands.add(ledCommand);
            }
            // 获取LED线程
            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, ledDevice.getId().intValue());
            // 命令下发 -------------------------------------------------------------------------------
            if (!commands.isEmpty()) {
                ledThread.write(commands);
                ledThread.setLedMk(false);
            }
        }
    }
    /**
     * 其他  ===>> LED显示器复位,显示默认信息
     */
    public void ledReset() {
        // 根据输送线plc遍历
        List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, DeviceCtgType.LED.val())
                .eq(Device::getStatus, 1));
        for (Device ledDevice : list) {
            //获取led数据
            BasLed led = basLedService.getOne(new LambdaQueryWrapper<BasLed>()
                    .eq(BasLed::getDeviceId, ledDevice.getId()));
            List<Integer> staArr = JSON.parseArray(led.getSta(), Integer.class);
            BasConveyor basConveyor = basConveyorService.getById(led.getConveyorId().intValue());
            if (basConveyor == null) {
                continue;
            }
            // 获取输送线plc线程
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Conveyor, basConveyor.getDeviceId().intValue());
            // 命令集合
            boolean reset = true;
            for (Integer staNo : staArr) {
                // 获取叉车站点
                StaProtocol staProtocol = devpThread.getStation().get(staNo);
                if (staProtocol == null) {
                    continue;
                }
                if (staProtocol.getWorkNo() != 0 && staProtocol.isLoading()) {
                    reset = false;
                    break;
                }
            }
            // 获取led线程
            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, ledDevice.getId().intValue());
            // led显示默认内容
            if (reset && !ledThread.isLedMk()) {
                ledThread.errorReset();
                ledThread.setLedMk(true);
            }
        }
        for (Device ledDevice : list) {
            //获取led数据
            BasLed led = basLedService.getOne(new LambdaQueryWrapper<BasLed>()
                    .eq(BasLed::getDeviceId, ledDevice.getId()));
            List<Integer> staArr = JSON.parseArray(led.getSta(), Integer.class);
            BasConveyor basConveyor = basConveyorService.getById(led.getConveyorId());
            if (basConveyor == null) {
                continue;
            }
            // 获取输送线plc线程
            DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Conveyor, basConveyor.getDeviceId().intValue());
            // 命令集合
            boolean reset = true;
            for (Integer staNo : staArr) {
                // 获取叉车站点
                StaProtocol staProtocol = devpThread.getStation().get(staNo);
                if (staProtocol == null) { continue; }
                if (staProtocol.getWorkNo() != 0) {
                    reset = false;
                    break;
                }
            }
            // 获取led线程
            LedThread ledThread = (LedThread) SlaveConnection.get(SlaveType.Led, ledDevice.getId().intValue());
            // led显示默认内容
            if (reset && !ledThread.isLedMk()) {
                ledThread.reset();
                ledThread.setLedMk(true);
            }
        }
    }
}