| | |
| | | */ |
| | | @Slf4j |
| | | @Service("mainService") |
| | | @Transactional |
| | | public class MainServiceImpl { |
| | | |
| | | @Autowired |
| | |
| | | * 组托 |
| | | * 入库站,根据条码扫描生成入库工作档,工作状态 2 |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public synchronized void generateStoreWrkFile() { |
| | | String methodName = Thread.currentThread().getStackTrace()[1].getMethodName(); |
| | | // 根据输送线plc遍历 |
| | |
| | | /** |
| | | * 拣料、并板、盘点再入库 |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public synchronized void stnToCrnStnPick(Integer mark) { |
| | | for (DevpSlave devp : slaveProperties.getDevp()) { |
| | | // 遍历拣料入库口 |
| | |
| | | public synchronized void crnStnToOutStn(Integer mark) { |
| | | |
| | | for (CrnSlave crnSlave : slaveProperties.getCrn()) { |
| | | // 遍历堆垛机出库站 |
| | | for (CrnSlave.CrnStn crnStn : crnSlave.getCrnOutStn()) { |
| | | // 获取堆垛机出库站信息 |
| | | DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId()); |
| | | StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo()); |
| | | if (staProtocol == null) { |
| | | continue; |
| | | } else { |
| | | staProtocol = staProtocol.clone(); |
| | | } |
| | | if (staProtocol.isAutoing() && staProtocol.isLoading() && (staProtocol.getWorkNo() == 0 || staProtocol.getStaNo() == null)) { |
| | | // 查询工作档 |
| | | WrkMast wrkMast = wrkMastMapper.selectPakOutStep2(staProtocol.getSiteId()); |
| | | if (wrkMast == null) { |
| | | continue; |
| | | } |
| | | // 判断工作档条件 |
| | | if (wrkMast.getIoType() < 100 || wrkMast.getStaNo() == null || wrkMast.getSourceStaNo() == null) { |
| | | continue; |
| | | } |
| | | // 判断吊车是否实际已完成,且电脑状态在move中,以备电脑进行更新工作档 |
| | | CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, wrkMast.getCrnNo()); |
| | | CrnProtocol crnProtocol = crnThread.getCrnProtocol(); |
| | | if (crnProtocol.statusType == CrnStatusType.FETCHING || crnProtocol.statusType == CrnStatusType.PUTTING) { |
| | | // 移动中 |
| | | continue; |
| | | } |
| | | // 判断堆垛机状态等待确认 |
| | | if (crnProtocol.modeType == CrnModeType.AUTO && crnProtocol.getTaskNo().equals(wrkMast.getWrkNo().shortValue()) |
| | | && crnProtocol.statusType == CrnStatusType.WAITING |
| | | && crnProtocol.forkPosType == CrnForkPosType.HOME) { |
| | | |
| | | // 命令下发区.更新工作档状态为14 下发站点信息-------------------------------------------------------------------------- |
| | | staProtocol.setStaNo(wrkMast.getStaNo().shortValue()); |
| | | wrkMast.setWrkSts(14L); |
| | | staProtocol.setWorkNo(wrkMast.getWrkNo()); |
| | | |
| | | if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocol))) { |
| | | continue; |
| | | } |
| | | wrkMast.setCrnEndTime(new Date()); |
| | | if (wrkMastMapper.updateById(wrkMast) != 0) { |
| | | // 复位堆垛机 |
| | | News.info("出库任务完成下发堆垛机复位,任务号:{}",wrkMast.getWrkNo()); |
| | | crnThread.setResetFlag(true); |
| | | } else { |
| | | News.error(""+mark+" - 1"+" - 更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo()); |
| | | } |
| | | |
| | | }else { |
| | | News.errorNoLog(""+mark+" - 6"+" - 堆垛机信息不符合入库条件!!!" |
| | | +" 堆垛机状态:"+crnProtocol.modeType+"==自动AUTO:" + CrnModeType.AUTO |
| | | +"、堆垛机任务号:"+crnProtocol.getTaskNo()+"==工作档任务号:" + wrkMast.getWrkNo().shortValue() |
| | | +"、状态枚举:"+crnProtocol.statusType+"==WAITING:10 //任务完成等待WCS确认):" + CrnStatusType.WAITING |
| | | +"、货叉位置:"+crnProtocol.forkPosType+"==HOME:0 // 货叉原位:" + CrnForkPosType.HOME); |
| | | } |
| | | |
| | | } |
| | | try { |
| | | // 每台堆垛机的所有出库站处理在同一个事务中执行,快速提交释放锁 |
| | | processCrnStnToOutStnForCrn(crnSlave, mark); |
| | | } catch (Exception e) { |
| | | News.error(""+mark+" - crnStnToOutStn"+" - 处理堆垛机{}时发生异常", crnSlave.getId(), e); |
| | | // 继续处理下一台堆垛机,不中断整个流程 |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 入出库 ===>> 堆垛机入出库作业下发 |
| | | * 处理单台堆垛机的所有出库站操作(使用独立事务,快速提交释放锁) |
| | | * 注意:必须是public方法,Spring AOP才能代理事务 |
| | | */ |
| | | public synchronized void crnIoExecute(Integer mark) { |
| | | @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) |
| | | public void processCrnStnToOutStnForCrn(CrnSlave crnSlave, Integer mark) { |
| | | // 遍历堆垛机出库站 |
| | | for (CrnSlave.CrnStn crnStn : crnSlave.getCrnOutStn()) { |
| | | processCrnStnToOutStn(crnStn, mark); |
| | | } |
| | | } |
| | | |
| | | for (CrnSlave crn : slaveProperties.getCrn()) { |
| | | // 获取堆垛机信息 |
| | | CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId()); |
| | | /** |
| | | * 处理单个堆垛机出库站的出库操作(无事务,事务由上层方法管理) |
| | | */ |
| | | private void processCrnStnToOutStn(CrnSlave.CrnStn crnStn, Integer mark) { |
| | | // 获取堆垛机出库站信息 |
| | | DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, crnStn.getDevpPlcId()); |
| | | StaProtocol staProtocol = devpThread.getStation().get(crnStn.getStaNo()); |
| | | if (staProtocol == null) { |
| | | return; |
| | | } else { |
| | | staProtocol = staProtocol.clone(); |
| | | } |
| | | if (staProtocol.isAutoing() && staProtocol.isLoading() && (staProtocol.getWorkNo() == 0 || staProtocol.getStaNo() == null)) { |
| | | // 查询工作档 |
| | | WrkMast wrkMast = wrkMastMapper.selectPakOutStep2(staProtocol.getSiteId()); |
| | | if (wrkMast == null) { |
| | | return; |
| | | } |
| | | // 判断工作档条件 |
| | | if (wrkMast.getIoType() < 100 || wrkMast.getStaNo() == null || wrkMast.getSourceStaNo() == null) { |
| | | return; |
| | | } |
| | | // 判断吊车是否实际已完成,且电脑状态在move中,以备电脑进行更新工作档 |
| | | CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, wrkMast.getCrnNo()); |
| | | CrnProtocol crnProtocol = crnThread.getCrnProtocol(); |
| | | if (crnProtocol == null) { |
| | | continue; |
| | | if (crnProtocol.statusType == CrnStatusType.FETCHING || crnProtocol.statusType == CrnStatusType.PUTTING) { |
| | | // 移动中 |
| | | return; |
| | | } |
| | | BasCrnp basCrnp = basCrnpService.selectById(crn.getId()); |
| | | if (basCrnp == null) { |
| | | News.error(""+mark+" - 1"+" - {}号堆垛机尚未在数据库进行维护!", crn.getId()); |
| | | continue; |
| | | } |
| | | // 判断堆垛机状态等待确认 |
| | | if (crnProtocol.modeType == CrnModeType.AUTO && crnProtocol.getTaskNo().equals(wrkMast.getWrkNo().shortValue()) |
| | | && crnProtocol.statusType == CrnStatusType.WAITING |
| | | && crnProtocol.forkPosType == CrnForkPosType.HOME) { |
| | | |
| | | // 只有当堆垛机空闲 并且 无任务时才继续执行 |
| | | if (crnProtocol.getStatusType() == CrnStatusType.IDLE && crnProtocol.getTaskNo() == 0 && crnProtocol.getModeType() == CrnModeType.AUTO |
| | | && crnProtocol.getLoaded() == 0 && crnProtocol.getForkPos() == 0) { |
| | | News.warnNoLog(""+mark+" - 0"+" - 开始执行堆垛机入出库作业下发"); |
| | | // 如果最近一次是入库模式 |
| | | if (crnProtocol.getLastIo().equals("I")) { |
| | | if (basCrnp.getInEnable().equals("Y")) { |
| | | //mark - 1 - .... |
| | | this.crnStnToLoc(crn, crnProtocol,mark); // 入库 |
| | | crnProtocol.setLastIo("O"); |
| | | } else if (basCrnp.getOutEnable().equals("Y")) { |
| | | //mark - 2 - .... |
| | | this.locToCrnStn(crn, crnProtocol,mark); // 出库 |
| | | crnProtocol.setLastIo("I"); |
| | | } |
| | | // 命令下发区.更新工作档状态为14 下发站点信息-------------------------------------------------------------------------- |
| | | staProtocol.setStaNo(wrkMast.getStaNo().shortValue()); |
| | | wrkMast.setWrkSts(14L); |
| | | staProtocol.setWorkNo(wrkMast.getWrkNo()); |
| | | |
| | | if (!MessageQueue.offer(SlaveType.Devp, crnStn.getDevpPlcId(), new Task(2, staProtocol))) { |
| | | return; |
| | | } |
| | | // 如果最近一次是出库模式 |
| | | else if (crnProtocol.getLastIo().equals("O")) { |
| | | if (basCrnp.getOutEnable().equals("Y")) { |
| | | this.locToCrnStn(crn, crnProtocol,mark); // 出库 |
| | | crnProtocol.setLastIo("I"); |
| | | } else if (basCrnp.getInEnable().equals("Y")) { |
| | | this.crnStnToLoc(crn, crnProtocol,mark); // 入库 |
| | | crnProtocol.setLastIo("O"); |
| | | } |
| | | wrkMast.setCrnEndTime(new Date()); |
| | | if (wrkMastMapper.updateById(wrkMast) != 0) { |
| | | // 复位堆垛机 |
| | | News.info("出库任务完成下发堆垛机复位,任务号:{}",wrkMast.getWrkNo()); |
| | | crnThread.setResetFlag(true); |
| | | } else { |
| | | News.error(""+mark+" - 1"+" - 更新工作档的工作状态为14失败!!! [工作号:{}]", wrkMast.getWrkNo()); |
| | | throw new CoolException("更新工作档的工作状态为14失败"); |
| | | } |
| | | |
| | | }else { |
| | | News.errorNoLog(""+mark+" - 6"+" - 堆垛机信息不符合入库条件!!!" |
| | | +" 堆垛机状态:"+crnProtocol.modeType+"==自动AUTO:" + CrnModeType.AUTO |
| | | +"、堆垛机任务号:"+crnProtocol.getTaskNo()+"==工作档任务号:" + wrkMast.getWrkNo().shortValue() |
| | | +"、状态枚举:"+crnProtocol.statusType+"==WAITING:10 //任务完成等待WCS确认):" + CrnStatusType.WAITING |
| | | +"、货叉位置:"+crnProtocol.forkPosType+"==HOME:0 // 货叉原位:" + CrnForkPosType.HOME); |
| | | } |
| | | // 库位移转 |
| | | //mark - 3 - .... |
| | | this.locToLoc(crn, crnProtocol,mark); |
| | | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 入出库 ===>> 堆垛机入出库作业下发 |
| | | * 注意:使用 REQUIRES_NEW 让每个堆垛机的处理在独立事务中执行,避免长时间持有锁导致死锁 |
| | | */ |
| | | public synchronized void crnIoExecute(Integer mark) { |
| | | try { |
| | | for (CrnSlave crn : slaveProperties.getCrn()) { |
| | | try { |
| | | // 每个堆垛机的处理在独立事务中执行,快速提交释放锁 |
| | | processCrnIo(crn, mark); |
| | | } catch (Exception e) { |
| | | News.error(""+mark+" - crnIoExecute"+" - 处理堆垛机{}时发生异常", crn.getId(), e); |
| | | // 继续处理下一个堆垛机,不中断整个流程 |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | News.error(""+mark+" - crnIoExecute"+" - 执行堆垛机入出库作业下发时发生异常", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 处理单个堆垛机的入出库作业(使用独立事务,快速提交释放锁) |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) |
| | | public void processCrnIo(CrnSlave crn, Integer mark) { |
| | | // 获取堆垛机信息 |
| | | CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, crn.getId()); |
| | | if (crnThread == null) { |
| | | return; |
| | | } |
| | | CrnProtocol crnProtocol = crnThread.getCrnProtocol(); |
| | | if (crnProtocol == null) { |
| | | return; |
| | | } |
| | | BasCrnp basCrnp = basCrnpService.selectById(crn.getId()); |
| | | if (basCrnp == null) { |
| | | News.error(""+mark+" - 1"+" - {}号堆垛机尚未在数据库进行维护!", crn.getId()); |
| | | return; |
| | | } |
| | | |
| | | // 只有当堆垛机空闲 并且 无任务时才继续执行 |
| | | if (crnProtocol.getStatusType() == CrnStatusType.IDLE && crnProtocol.getTaskNo() == 0 && crnProtocol.getModeType() == CrnModeType.AUTO |
| | | && crnProtocol.getLoaded() == 0 && crnProtocol.getForkPos() == 0) { |
| | | News.warnNoLog(""+mark+" - 0"+" - 开始执行堆垛机入出库作业下发"); |
| | | // 如果最近一次是入库模式 |
| | | if (crnProtocol.getLastIo().equals("I")) { |
| | | if (basCrnp.getInEnable().equals("Y")) { |
| | | //mark - 1 - .... |
| | | this.crnStnToLoc(crn, crnProtocol,mark); // 入库 |
| | | crnProtocol.setLastIo("O"); |
| | | } else if (basCrnp.getOutEnable().equals("Y")) { |
| | | //mark - 2 - .... |
| | | this.locToCrnStn(crn, crnProtocol,mark); // 出库 |
| | | crnProtocol.setLastIo("I"); |
| | | } |
| | | } |
| | | // 如果最近一次是出库模式 |
| | | else if (crnProtocol.getLastIo().equals("O")) { |
| | | if (basCrnp.getOutEnable().equals("Y")) { |
| | | this.locToCrnStn(crn, crnProtocol,mark); // 出库 |
| | | crnProtocol.setLastIo("I"); |
| | | } else if (basCrnp.getInEnable().equals("Y")) { |
| | | this.crnStnToLoc(crn, crnProtocol,mark); // 入库 |
| | | crnProtocol.setLastIo("O"); |
| | | } |
| | | } |
| | | } |
| | | // 库位移转 |
| | | //mark - 3 - .... |
| | | this.locToLoc(crn, crnProtocol,mark); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | } else if (shallowLoc.getLocSts().equals("F") || shallowLoc.getLocSts().equals("D")) { |
| | | News.warnNoLog(""+mark+" - 1"+" - 12"+" - // F、D 库位状态={}",shallowLoc.getLocSts()); |
| | | // 检查是否已存在移库任务 |
| | | WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo); |
| | | // 此标记避免多次执行移库任务 |
| | | if (Cools.isEmpty(wrkMast.getUpdMk()) || "N".equals(wrkMast.getUpdMk())) { |
| | | if (Cools.isEmpty(waitWrkMast) && (Cools.isEmpty(wrkMast.getUpdMk()) || "N".equals(wrkMast.getUpdMk()))) { |
| | | wrkMast.setUpdMk("Y"); |
| | | wrkMast.setIoPri(14D); |
| | | wrkMastMapper.updateById(wrkMast); |
| | | // 生成工作档,将浅库位移转到新的库位中 |
| | | moveLocForDeepLoc(slave, shallowLoc,mark); |
| | | // 生成工作档、改变浅库位的源库/目标库 库位状态、下发堆垛机命令(立马执行) |
| | | // moveLocForDeepLocPakin(slave, shallowLoc, wrkMast); |
| | | try { |
| | | moveLocForDeepLoc(slave, shallowLoc,mark); |
| | | News.warnNoLog("{}任务已生成浅库位移转任务,浅库位号:{},继续处理下一个任务", wrkMast.getWrkNo(), shallowLocNo); |
| | | } catch (Exception e) { |
| | | News.error("{}任务生成浅库位移转任务失败,浅库位号:{}", wrkMast.getWrkNo(), shallowLocNo, e); |
| | | } |
| | | } else if (!Cools.isEmpty(waitWrkMast)) { |
| | | News.warnNoLog("{}任务入库等待中,浅库位已有移库任务,浅库位号:{},移库任务号:{}", wrkMast.getWrkNo(), shallowLocNo, waitWrkMast.getWrkNo()); |
| | | } |
| | | continue; |
| | | } else if (shallowLoc.getLocSts().equals("Q")) { |
| | |
| | | // continue; |
| | | } |
| | | |
| | | // 判断堆垛机出库站状态 |
| | | if (staProtocol.isAutoing() && !staProtocol.isLoading() && staDetl.getCanouting() != null && staDetl.getCanouting().equals("Y") |
| | | && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) { |
| | | boolean outStationAvailable = true; |
| | | // 是否检查堆垛机出库站状态(true: 检查,false: 不检查) |
| | | if (slaveProperties.isCheckOutStationStatus()) { |
| | | // 检查出库站状态 |
| | | outStationAvailable = |
| | | //自动 |
| | | staProtocol.isAutoing() |
| | | //!有物 |
| | | && !staProtocol.isLoading() |
| | | //能出 |
| | | && staDetl.getCanouting() != null |
| | | && staDetl.getCanouting().equals("Y") |
| | | //工作号 |
| | | && staProtocol.getWorkNo() == 0 |
| | | //可出 |
| | | && staProtocol.isOutEnable(); |
| | | } |
| | | // 出库站可用时继续执行 |
| | | if (outStationAvailable) { |
| | | // 堆垛机控制过滤 |
| | | if (!crnProtocol.getStatusType().equals(CrnStatusType.IDLE) || crnProtocol.getTaskNo() != 0) { |
| | | // continue; |
| | |
| | | wrkMast.setUpdMk("Y"); |
| | | wrkMastMapper.updateById(wrkMast); |
| | | // 生成工作档,将浅库位移转到新的库位中 |
| | | moveLocForDeepLoc(slave, shallowLoc,mark); |
| | | try { |
| | | moveLocForDeepLoc(slave, shallowLoc,mark); |
| | | News.warnNoLog("{}任务已生成浅库位移转任务,浅库位号:{},继续处理下一个任务", wrkMast.getWrkNo(), shallowLocNo); |
| | | continue; // 已生成移库任务,继续处理下一个任务 |
| | | } catch (Exception e) { |
| | | News.error("{}任务生成浅库位移转任务失败,浅库位号:{}", wrkMast.getWrkNo(), shallowLocNo, e); |
| | | continue; // 生成失败,继续处理下一个任务 |
| | | } |
| | | } else { |
| | | // 已存在移库任务,等待移库完成 |
| | | News.warnNoLog("{}任务出库等待中,浅库位已有移库任务,浅库位号:{},移库任务号:{}", wrkMast.getWrkNo(), shallowLocNo, waitWrkMast.getWrkNo()); |
| | | continue; // 继续处理下一个任务,不阻塞当前循环 |
| | | } |
| | | News.error("{}任务出库失败,浅库位堵塞!浅库位号:{}", wrkMast.getWrkNo(), shallowLocNo); |
| | | break; |
| | | } else if (shallowLoc.getLocSts().equals("Q") || shallowLoc.getLocSts().equals("S")) { |
| | | News.warnNoLog(""+mark+" - 2"+" - 10"+" - // Q、S 库位状态={}",shallowLoc.getLocSts()); |
| | | WrkMast waitWrkMast = wrkMastMapper.selectByLocNo1(shallowLocNo); |
| | |
| | | /** |
| | | * 空栈板初始化入库,叉车入库站放货 |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public synchronized void storeEmptyPlt(Integer mark) { |
| | | |
| | | for (DevpSlave devp : slaveProperties.getDevp()) { |
| | |
| | | /** |
| | | * 出库 ===>> 工作档信息写入led显示器 |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public synchronized void ledExecute() { |
| | | for (LedSlave led : slaveProperties.getLed()) { |
| | | // 获取输送线plc线程 |