#
Junjie
2024-05-05 ecf8ba7c1bd6fc6a719c62a888327109795a3fda
zy-asrs-wcs/src/main/java/com/zy/asrs/wcs/core/service/impl/MainServiceImpl.java
@@ -1,24 +1,41 @@
package com.zy.asrs.wcs.core.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zy.asrs.framework.common.Cools;
import com.zy.asrs.wcs.core.entity.Task;
import com.zy.asrs.framework.common.SnowflakeIdWorker;
import com.zy.asrs.wcs.core.domain.dto.RedisMapDto;
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.service.TaskService;
import com.zy.asrs.wcs.core.service.*;
import com.zy.asrs.wcs.core.utils.RedisUtil;
import com.zy.asrs.wcs.core.utils.ShuttleDispatcher;
import com.zy.asrs.wcs.core.utils.Utils;
import com.zy.asrs.wcs.rcs.News;
import com.zy.asrs.wcs.core.entity.Motion;
import com.zy.asrs.wcs.core.service.MotionService;
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.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.DevpThread;
import com.zy.asrs.wcs.rcs.thread.ShuttleThread;
import com.zy.asrs.wcs.system.entity.Dict;
import com.zy.asrs.wcs.system.service.DictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.*;
/**
 * 立体仓库WCS系统主流程业务
@@ -35,6 +52,22 @@
    private AnalyzeService analyzeService;
    @Autowired
    private MotionService motionService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private LocCtgService locCtgService;
    @Autowired
    private LocService locService;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private TaskCtgService taskCtgService;
    @Autowired
    private DictService dictService;
    @Autowired
    private ShuttleDispatcher shuttleDispatcher;
    @Autowired
    private RedisUtil redisUtil;
    /**
     * 组托
@@ -42,6 +75,122 @@
     */
    public synchronized void generateInboundWrk() {
    }
    /**
     * 初始化实时地图
     */
    public synchronized void initRealtimeBasMap() {
        try {
            List<Dict> dicts = dictService.list(new LambdaQueryWrapper<Dict>()
                    .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]);
                TreeMap<Integer, List<JSONObject>> rows = new TreeMap<>();
                //排序Row
                JSONArray value = JSON.parseArray(dict.getValue());
                for (Object o : value) {
                    JSONObject item = JSON.parseObject(o.toString());
                    if (item.getString("type").equals("SHELF")) {
                        JSONObject property = JSON.parseObject(item.getString("property"));
                        Integer row1 = property.getInteger("row");
                        ArrayList<JSONObject> bays = new ArrayList<>();
                        if (rows.containsKey(row1)) {
                            bays.addAll(rows.get(row1));
                        }
                        bays.add(property);
                        rows.put(row1, bays);
                    }
                }
                ArrayList<ArrayList<MapNode>> list = new ArrayList<>();
                //排序Bay
                for (Map.Entry<Integer, List<JSONObject>> entry : rows.entrySet()) {
                    ArrayList<MapNode> nodes = new ArrayList<>();
                    for (JSONObject object : entry.getValue()) {
                        MapNode mapNode = new MapNode();
                        mapNode.setValue(object.getInteger("shelfType"));
                        mapNode.setTop(object.getInteger("top"));
                        mapNode.setBottom(object.getInteger("bottom"));
                        mapNode.setLeft(object.getInteger("left"));
                        mapNode.setRight(object.getInteger("right"));
                        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"));
                        nodes.add(mapNode);
                    }
                    Collections.sort(nodes, new Comparator<MapNode>() {
                        @Override
                        public int compare(MapNode o1, MapNode o2) {
                            return Integer.compare(o1.getBay(), o2.getBay());
                        }
                    });
                    list.add(nodes);
                }
                levData.put(lev, list);
            }
            for (Map.Entry<Integer, ArrayList<ArrayList<MapNode>>> entry : levData.entrySet()) {
                ArrayList<ArrayList<MapNode>> lists = entry.getValue();//获取地图
                MapNode mapNode = new MapNode();
                mapNode.setValue(-1);
                mapNode.setTop(1000);
                mapNode.setBottom(1000);
                mapNode.setLeft(1000);
                mapNode.setRight(1000);
                mapNode.setRow(0);
                mapNode.setBay(0);
                mapNode.setNo("0-0");
                mapNode.setXBase(0);
                mapNode.setYBase(0);
                //获取最长row
                int row = 0;
                //给每个row首尾增加-1节点
                for (ArrayList<MapNode> list : lists) {
                    if (list.size() > row) {
                        row = list.size();
                    }
                    list.add(0, mapNode.clone());
                    list.add(mapNode.clone());
                }
                ArrayList<MapNode> headNodes = new ArrayList<>();
                ArrayList<MapNode> footerNodes = new ArrayList<>();
                for (int i = 0; i < row+2; i++) {
                    headNodes.add(mapNode.clone());
                    footerNodes.add(mapNode.clone());
                }
                lists.add(0, headNodes);
                lists.add(footerNodes);
                Integer lev = entry.getKey();
                Date now = new Date();
                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));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 解析入库工作档
@@ -127,126 +276,242 @@
     * 四向穿梭车电量检测 ===>> 发起充电
     */
    public synchronized void loopShuttleCharge() {
//        ShuttleChargeType shuttleCharge = ShuttleChargeType.CHARGE_1;
//        for (ShuttleSlave shuttle : slaveProperties.getShuttle()) {
//            // 判断充电位是否被占用
//            if (wrkChargeService.hasShuttleInChargeLoc(shuttleCharge.locNo, shuttle.getId())) {
//                continue;
//            }
//
//            //获取四向穿梭车线程
//            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttle.getId());
//            ShuttleProtocol shuttleProtocol = shuttleThread.getShuttleProtocol();
//            if (shuttleProtocol == null) {
//                continue;
//            }
//            if (motionService.selectCount(new EntityWrapper<Motion>()
//                    .eq("device_ctg", DeviceCtgType.SHUTTLE.val())
//                    .eq("device", shuttle.getId())
//                    .eq("motion_sts", MotionStsType.EXECUTING.val())) > 0) {
//                continue;
//            }
//
//            //判断当前小车是否满足需要充电要求
//            if (!shuttleProtocol.isRequireCharge()) {
//                continue;
//            }
//
//            WrkCharge wrkCharge = wrkChargeService.selectWorking(null);
//            if (wrkCharge != null) {//已有充电任务
//                continue;
//            }
//
//            String chargeLocNo = shuttleCharge.locNo;
//            wrkCharge = new WrkCharge();
//            wrkCharge.setShuttleNo(shuttle.getId());
//            wrkCharge.setCharge(shuttleCharge.id);
//            wrkCharge.setWrkNo(commonService.getChargeWorkNo(4));
//            wrkCharge.setUuid(String.valueOf(snowflakeIdWorker.nextId()));
//            wrkCharge.setWrkSts(WrkMastStsType.NEW_CHARGE.sts);   // 充电任务
//            wrkCharge.setIoType(WrkIoTypeType.CHARGE.sts);
//            wrkCharge.setIoPri((double) 10);
//            wrkCharge.setLocNo(chargeLocNo);
//            wrkCharge.setMemo("charge");
//            wrkCharge.setAppeTime(new Date());
//
//            // generate motion list
//            List<Motion> motionList = analyzeService.generateChargeMotion(wrkCharge);
//            if (Cools.isEmpty(motionList)) {
//                News.error("保存{}号四向穿梭车充电任务失败!!!", shuttle.getId());
//                continue;
//            }
//            motionService.batchInsert(motionList, wrkCharge.getUuid(), wrkCharge.getWrkNo());
//
//            wrkCharge.setWrkSts(WrkMastStsType.ANALYZE_CHARGE.sts);
//
//            if (!wrkChargeService.insert(wrkCharge)) {
//                News.error("保存{}号四向穿梭车充电任务失败!!!", shuttle.getId());
//                continue;
//            }
//
//            News.info("保存{}号四向穿梭车充电任务成功!!!", shuttle.getId());
//        }
        // 获取充电桩库位类型
        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::getStatus, 1));
        if (taskCtg == null) {
            return;
        }
        List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val())
                .eq(Device::getStatus, 1));
        for (Device device : list) {
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue());
            if (shuttleThread == null) {
                continue;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                continue;
            }
            if (!shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.IDLE)) {
                continue;
            }
            if (!shuttleThread.isRequireCharge()) {
                continue;
            }
            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));
            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));
            if (!list2.isEmpty()) {
                allChargeLoc.addAll(list2);
            }
            //没有找到充电桩
            if (allChargeLoc.isEmpty()) {
                continue;
            }
            //选择空闲充电桩
            Loc chargeLoc = null;
            for (Loc loc : allChargeLoc) {
                // 判断充电位是否被占用(车辆位置)
                if (Utils.hasShuttleInLoc(loc.getLocNo(), device.getId())) {
                    continue;
                }
                // 盘点充电位是否存在任务档
                List<Task> tasks = taskService.hasChargeInLoc(loc.getLocNo());
                if (!tasks.isEmpty()) {
                    continue;
                }
                chargeLoc = loc;
                break;
            }
            if (chargeLoc == null) {
                continue;//未找到充电桩
            }
            if (motionService.count(new LambdaQueryWrapper<Motion>()
                    .eq(Motion::getDeviceCtg, DeviceCtgType.SHUTTLE.val())
                    .eq(Motion::getDevice, device.getDeviceNo())
                    .eq(Motion::getMotionSts, MotionStsType.EXECUTING.val())) > 0) {
                continue;
            }
            //判断当前小车是否满足需要充电要求
            if (!shuttleThread.isRequireCharge()) {
                continue;
            }
            Task taskCharge = taskService.selectChargeWorking(Integer.valueOf(device.getDeviceNo()));
            if (taskCharge != null) {//已有充电任务
                continue;
            }
            String chargeLocNo = chargeLoc.getLocNo();
            Task task = new Task();
            task.setUuid(String.valueOf(snowflakeIdWorker.nextId()));
            task.setTaskNo(String.valueOf(Utils.getTaskNo("CHARGE")));
            task.setTaskSts(TaskStsType.NEW_CHARGE.sts);
            task.setTaskCtg(taskCtg.getId());
            task.setPriority(10);
            task.setOriginSite(null);
            task.setOriginLoc(null);
            task.setDestSite(null);
            task.setDestLoc(chargeLocNo);
            task.setIoTime(new Date());
            task.setStartTime(new Date());
            task.setHostId(device.getHostId());
            task.setStatus(1);
            task.setMemo("charge");
            task.setShuttleNo(Integer.valueOf(device.getDeviceNo()));
            // generate motion list
            List<Motion> motionList = analyzeService.generateChargeMotion(task);
            if (Cools.isEmpty(motionList)) {
                News.error("保存{}号四向穿梭车充电任务失败!!!", device.getDeviceNo());
                continue;
            }
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
            task.setTaskSts(TaskStsType.ANALYZE_CHARGE.sts);
            if (!taskService.save(task)) {
                News.error("保存{}号四向穿梭车充电任务失败!!!", device.getDeviceNo());
                continue;
            }
            News.info("保存{}号四向穿梭车充电任务成功!!!", device.getDeviceNo());
        }
    }
    /**
     * 四向穿梭车电量检测 ===>> 满电后回到待机位
     */
    public synchronized void loopShuttleToStandbyCauseCharge() {
//        ShuttleChargeType shuttleCharge = ShuttleChargeType.CHARGE_1;
//        Integer enoughPower = 90;
//        Config config = configService.selectOne(new EntityWrapper<Config>()
//                .eq("code", "chargeMaxValue")
//                .eq("status", 1));
//        if (config != null) {
//            enoughPower = Integer.parseInt(config.getValue());
//        }
//
//        for (ShuttleSlave shuttle : slaveProperties.getShuttle()) {
//            //获取四向穿梭车线程
//            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, shuttle.getId());
//            ShuttleProtocol shuttleProtocol = shuttleThread.getShuttleProtocol();
//            if (shuttleProtocol == null) {
//                continue;
//            }
//            // 是否存在充电任务
//            WrkCharge wrkCharge = wrkChargeService.selectWorking(shuttle.getId());
//            if (wrkCharge == null) {
//                continue;
//            }
//
//            if (motionService.selectCount(new EntityWrapper<Motion>()
//                    .eq("device_ctg", DeviceCtgType.SHUTTLE.val())
//                    .eq("device", shuttle.getId())
//                    .eq("motion_sts", MotionStsType.EXECUTING.val())) > 0) {
//                continue;
//            }
//            // 不处于充电中
//            if (!shuttleProtocol.getPlcOutputCharge()) {
//                continue;
//            }
//            // 在充电位
//            if (!shuttleProtocol.getCurrentLocNo().equals(shuttleCharge.locNo)) {
//                continue;
//            }
//            // 电量是否达到满电要求
//            if (shuttleProtocol.getBatteryPower$().intValue() < enoughPower) {
//                continue;
//            }
//            // 已有迁移任务
//            if (wrkChargeService.selectMoveWorking(shuttle.getId()) != null) {
//                continue;
//            }
//
//            // 待机位
//            String standByLocNo = ShuttleTempLocType.query(shuttleProtocol.getShuttleNo().intValue(), 2, Utils.getLev(shuttleCharge.locNo)).locNo;
//
//            shuttleDispatcher.generateShuttleChargeWrkComplete(shuttleProtocol.getShuttleNo().intValue(), standByLocNo);
//
//            wrkCharge.setWrkSts(WrkMastStsType.COMPLETE_CHARGE.sts);
//            wrkCharge.setIoTime(new Date());
//            wrkChargeMapper.updateById(wrkCharge);
//        }
        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::getStatus, 1));
        if (taskCtg == null) {
            return;
        }
        List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, DeviceCtgType.SHUTTLE.val())
                .eq(Device::getStatus, 1));
        for (Device device : list) {
            //获取四向穿梭车线程
            ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue());
            if (shuttleThread == null) {
                continue;
            }
            ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
            if (shuttleProtocol == null) {
                continue;
            }
            if (!shuttleThread.isCharging()) {
                continue;
            }
            if (!shuttleThread.isChargingCompleted()) {
                continue;
            }
            //查找充电任务
            Task chargeTask = taskService.getOne(new LambdaQueryWrapper<Task>()
                    .eq(Task::getTaskSts, TaskStsType.CHARGE_WORKING.sts)
                    .eq(Task::getShuttleNo, device.getDeviceNo()));
            if (chargeTask == null) {
                continue;
            }
            //充电完成
            // 已有迁移任务
            if (taskService.selectMoveWorking(Integer.valueOf(device.getDeviceNo())) != null) {
                continue;
            }
            //获取避让位置
            String standByLocNo = shuttleDispatcher.searchStandByLocNo(Integer.valueOf(device.getDeviceNo()), device.getHostId(), shuttleThread.getStatus().getCurrentLocNo());
            Task task = new Task();
            task.setUuid(String.valueOf(snowflakeIdWorker.nextId()));
            task.setTaskNo(String.valueOf(Utils.getTaskNo("MOVE")));
            task.setTaskSts(TaskStsType.NEW_MOVE.sts);
            task.setTaskCtg(taskCtg.getId());
            task.setPriority(10);
            task.setOriginSite(null);
            task.setOriginLoc(null);
            task.setDestSite(null);
            task.setDestLoc(standByLocNo); // 避让位置
            task.setIoTime(new Date());
            task.setStartTime(new Date());
            task.setHostId(device.getHostId());
            task.setStatus(1);
            task.setMemo("charge");
            task.setShuttleNo(Integer.valueOf(device.getDeviceNo()));
            // generate motion list
            List<Motion> motionList = analyzeService.generateShuttleChargeWrkComplete(task);
            if (Cools.isEmpty(motionList)) {
                News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo());
                continue;
            }
            motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
            task.setTaskSts(TaskStsType.ANALYZE_MOVE.sts);
            if (!taskService.save(task)) {
                News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo());
                continue;
            }
            chargeTask.setTaskSts(TaskStsType.COMPLETE_CHARGE.sts);
            chargeTask.setIoTime(new Date());
            taskService.updateById(chargeTask);
        }
    }
}