package com.zy.asrs.wcs.core.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.zy.asrs.framework.common.Cools; import com.zy.asrs.framework.common.SnowflakeIdWorker; import com.zy.asrs.wcs.core.entity.*; import com.zy.asrs.wcs.core.kernel.AnalyzeService; 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.*; 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.rcs.cache.SlaveConnection; import com.zy.asrs.wcs.rcs.entity.Device; import com.zy.asrs.wcs.rcs.entity.DeviceType; 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.service.DeviceTypeService; 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.ArrayList; import java.util.Date; import java.util.List; /** * 立体仓库WCS系统主流程业务 * Created by vincent on 2020/8/6 */ @Slf4j @Service("mainService") @Transactional public class MainServiceImpl { @Autowired private TaskService taskService; @Autowired private AnalyzeService analyzeService; @Autowired private MotionService motionService; @Autowired private DeviceService deviceService; @Autowired private DeviceTypeService deviceTypeService; @Autowired private LocCtgService locCtgService; @Autowired private LocService locService; @Autowired private SnowflakeIdWorker snowflakeIdWorker; @Autowired private TaskCtgService taskCtgService; @Autowired private DictService dictService; @Autowired private ShuttleDispatcher shuttleDispatcher; /** * 组托 * 入库站,根据条码扫描生成入库工作档,工作状态 2 */ public synchronized void generateInboundWrk() { } // 解析入库工作档 public synchronized void analyzeInBoundTask() { for (Task task : taskService.selectWaitAnalyzeInBoundTask()) { // generate motion list List motionList = analyzeService.generateMotion(task); if (motionList.isEmpty()) { continue; } motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo())); // 更新工作主档 task.setTaskSts(TaskStsType.ANALYZE_INBOUND.sts); // 工作状态 task.setUpdateTime(new Date()); if (!taskService.updateById(task)) { News.error("更新工作档失败!!! [工作号:{}]", task.getTaskNo()); } } } /** * 出库 ====>> 同一时间一台穿梭车只能有一个出库任务 */ public synchronized void generateOutboundWrkMast() { List tasks = taskService.selectPakOut(); if (tasks.isEmpty()) { return; } for (Task task : tasks) { DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, 1); StaProtocol staProtocol = devpThread.getStation().get(Integer.parseInt(task.getOriginSite()));//源站 StaProtocol staProtocol1 = devpThread.getStation().get(Integer.parseInt(task.getDestSite()));//目标站 if (staProtocol == null || staProtocol1 == null) { continue; } else { staProtocol = staProtocol.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; } // //同库位组校验 // List outerLoc = Utils.getGroupOuterLoc(wrkMast.getSourceLocNo()); // List outerLocMasts = locMastService.selectNotEmptyLocNos(outerLoc); // if (!outerLocMasts.isEmpty()) { // News.info("{}任务,浅库位存在货物,系统等待中", wrkMast.getWrkNo()); // continue;//浅库位存在未执行任务 // } // generate motion list List motionList = analyzeService.generateMotion(task); if (Cools.isEmpty(motionList)) { log.error("出库 ===>> 暂时没有空闲小车, 任务号={}", task.getTaskNo()); continue; } motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo())); // 更新工作主档 task.setTaskSts(TaskStsType.ANALYZE_OUTBOUND.sts); // 工作状态 task.setUpdateTime(new Date()); if (!taskService.updateById(task)) { News.error("更新工作档失败!!! [工作号:{}]", task.getTaskNo()); } } } } /** * 四向穿梭车电量检测 ===>> 发起充电 */ public synchronized void loopShuttleCharge() { // 获取充电桩库位类型 LocCtg locCtg = locCtgService.getOne(new LambdaQueryWrapper() .eq(LocCtg::getFlag, "CHARGE") .eq(LocCtg::getStatus, 1)); if (locCtg == null) { return; } //获取充电任务类型 TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper() .eq(TaskCtg::getFlag, "CHARGE") .eq(TaskCtg::getStatus, 1)); if (taskCtg == null) { return; } DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper() .eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle)) .eq(DeviceType::getStatus, 1)); if (deviceType == null) { return; } List list = deviceService.list(new LambdaQueryWrapper() .eq(Device::getDeviceType, deviceType.getId()) .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; } String currentLocNo = shuttleProtocol.getCurrentLocNo(); int lev = Utils.getLev(currentLocNo);//获取小车楼层 //搜索小车当前楼层充电桩 ArrayList allChargeLoc = new ArrayList<>(); List list1 = locService.list(new LambdaQueryWrapper() .eq(Loc::getLocCtg, locCtg.getId()) .eq(Loc::getStatus, 1) .eq(Loc::getLev, lev)); if (!list1.isEmpty()) { allChargeLoc.addAll(list1); } //搜索其他楼层充电桩 List list2 = locService.list(new LambdaQueryWrapper() .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 tasks = taskService.hasChargeInLoc(loc.getLocNo()); if (!tasks.isEmpty()) { continue; } chargeLoc = loc; break; } if (chargeLoc == null) { continue;//未找到充电桩 } if (motionService.count(new LambdaQueryWrapper() .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.getId()); 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 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() { Integer enoughPower = 90; Dict dict = dictService.getOne(new LambdaQueryWrapper() .eq(Dict::getFlag, "chargeMaxValue") .eq(Dict::getStatus, 1)); if (dict != null) { enoughPower = Integer.parseInt(dict.getValue()); } //获取迁移任务类型 TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper() .eq(TaskCtg::getFlag, "MOVE") .eq(TaskCtg::getStatus, 1)); if (taskCtg == null) { return; } DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper() .eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle)) .eq(DeviceType::getStatus, 1)); if (deviceType == null) { return; } List list = deviceService.list(new LambdaQueryWrapper() .eq(Device::getDeviceType, deviceType.getId()) .eq(Device::getStatus, 1)); for (Device device : list) { //获取四向穿梭车线程 ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue()); if (shuttleThread == null) { continue; } if (!shuttleThread.isCharging()) { continue; } if (!shuttleThread.isChargingCompleted()) { continue; } //查找充电任务 Task chargeTask = taskService.getOne(new LambdaQueryWrapper() .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.getId()); 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 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); } } }