package com.zy.asrs.task; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zy.asrs.domain.enums.NotifyMsgType; import com.zy.asrs.entity.BasStation; import com.zy.asrs.entity.LocMast; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.entity.WrkMastLog; import com.zy.asrs.service.BasStationService; import com.zy.asrs.service.LocMastService; import com.zy.asrs.service.WrkAnalysisService; import com.zy.asrs.service.WrkMastLogService; import com.zy.asrs.service.WrkMastService; import com.zy.asrs.utils.NotifyUtils; import com.zy.common.utils.RedisUtil; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.LocStsType; import com.zy.core.enums.RedisKeyType; import com.zy.core.enums.SlaveType; import com.zy.core.enums.WrkIoType; import com.zy.core.enums.WrkStsType; import com.zy.core.thread.StationThread; import com.zy.core.utils.StationOperateProcessUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.UUID; @Component @Slf4j public class WrkMastFinalizeProcessor { private static final int WRK_LOCK_SECONDS = 30; private static final List CANCEL_MKS = Arrays.asList("taskCancel", "taskForceCancel"); private final WrkMastService wrkMastService; private final WrkMastLogService wrkMastLogService; private final WrkAnalysisService wrkAnalysisService; private final LocMastService locMastService; private final NotifyUtils notifyUtils; private final StationOperateProcessUtils stationOperateProcessUtils; private final BasStationService basStationService; private final RedisUtil redisUtil; public WrkMastFinalizeProcessor(WrkMastService wrkMastService, WrkMastLogService wrkMastLogService, WrkAnalysisService wrkAnalysisService, LocMastService locMastService, NotifyUtils notifyUtils, StationOperateProcessUtils stationOperateProcessUtils, BasStationService basStationService, RedisUtil redisUtil) { this.wrkMastService = wrkMastService; this.wrkMastLogService = wrkMastLogService; this.wrkAnalysisService = wrkAnalysisService; this.locMastService = locMastService; this.notifyUtils = notifyUtils; this.stationOperateProcessUtils = stationOperateProcessUtils; this.basStationService = basStationService; this.redisUtil = redisUtil; } @Transactional(rollbackFor = Exception.class) public void processCompleteInbound(Integer wrkNo) { processWithLock(wrkNo, () -> { WrkMast wrkMast = wrkMastService.selectByWorkNo(wrkNo); if (wrkMast == null) { log.error("入库完成清理跳过,未找到工作档。wrkNo={}", wrkNo); return; } if (!Objects.equals(wrkMast.getWrkSts(), WrkStsType.COMPLETE_INBOUND.sts)) { log.error("入库完成清理跳过,工作状态不匹配。wrkNo={}, wrkSts={}", wrkNo, wrkMast.getWrkSts()); return; } Integer taskNo = wrkMast.getWrkNo(); Integer sourceStaNo = wrkMast.getSourceStaNo(); Integer staNo = wrkMast.getStaNo(); LocMast locMast = locMastService.queryByLoc(wrkMast.getLocNo()); if (locMast == null) { log.error("入库完成清理跳过,目标库位不存在。wrkNo={}, locNo={}", wrkNo, wrkMast.getLocNo()); return; } if (!"S".equals(locMast.getLocSts())) { log.error("入库完成清理跳过,目标库位状态不为S。wrkNo={}, locNo={}, locSts={}", wrkNo, wrkMast.getLocNo(), locMast.getLocSts()); return; } locMast.setLocSts("F"); locMast.setBarcode(wrkMast.getBarcode()); locMast.setModiTime(new Date()); if (!locMastService.updateById(locMast)) { log.error("入库完成清理失败,目标库位更新失败。wrkNo={}, locNo={}", wrkNo, wrkMast.getLocNo()); return; } archiveAndFinish(wrkMast); if (wrkMastService.deleteByWrkNoAndCurrentWrkSts(wrkMast.getWrkNo(), WrkStsType.COMPLETE_INBOUND.sts) <= 0) { log.error("入库完成清理失败,删除工作档失败或状态已变化。wrkNo={}", wrkNo); return; } notifyUtils.notify("task", 1, String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.TASK_COMPLETE, JSON.toJSONString(wrkMast)); clearTaskPath(taskNo, sourceStaNo, staNo); }); } @Transactional(rollbackFor = Exception.class) public void processCompleteOutbound(Integer wrkNo) { processWithLock(wrkNo, () -> { WrkMast wrkMast = wrkMastService.selectByWorkNo(wrkNo); if (wrkMast == null) { log.error("出库完成清理跳过,未找到工作档。wrkNo={}", wrkNo); return; } if (!Objects.equals(wrkMast.getWrkSts(), WrkStsType.COMPLETE_OUTBOUND.sts)) { log.error("出库完成清理跳过,工作状态不匹配。wrkNo={}, wrkSts={}", wrkNo, wrkMast.getWrkSts()); return; } Integer taskNo = wrkMast.getWrkNo(); Integer sourceStaNo = wrkMast.getSourceStaNo(); Integer staNo = wrkMast.getStaNo(); LocMast locMast = locMastService.queryByLoc(wrkMast.getSourceLocNo()); if (locMast == null) { log.error("出库完成清理跳过,源库位不存在。wrkNo={}, sourceLocNo={}", wrkNo, wrkMast.getSourceLocNo()); return; } if (!("R".equals(locMast.getLocSts()) || "O".equals(locMast.getLocSts()))) { log.error("出库完成清理跳过,源库位状态异常。wrkNo={}, sourceLocNo={}, locSts={}", wrkNo, wrkMast.getSourceLocNo(), locMast.getLocSts()); return; } locMast.setLocSts("O"); locMast.setBarcode(""); locMast.setModiTime(new Date()); if (!locMastService.updateById(locMast)) { log.error("出库完成清理失败,源库位更新失败。wrkNo={}, sourceLocNo={}", wrkNo, wrkMast.getSourceLocNo()); return; } archiveAndFinish(wrkMast); if (wrkMastService.deleteByWrkNoAndCurrentWrkSts(wrkMast.getWrkNo(), WrkStsType.COMPLETE_OUTBOUND.sts) <= 0) { log.error("出库完成清理失败,删除工作档失败或状态已变化。wrkNo={}", wrkNo); return; } notifyUtils.notify("task", 1, String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.TASK_COMPLETE, JSON.toJSONString(wrkMast)); clearTaskPath(taskNo, sourceStaNo, staNo); }); } @Transactional(rollbackFor = Exception.class) public void processCompleteLocMove(Integer wrkNo) { processWithLock(wrkNo, () -> { WrkMast wrkMast = wrkMastService.selectByWorkNo(wrkNo); if (wrkMast == null) { log.error("移库完成清理跳过,未找到工作档。wrkNo={}", wrkNo); return; } if (!Objects.equals(wrkMast.getWrkSts(), WrkStsType.COMPLETE_LOC_MOVE.sts)) { log.error("移库完成清理跳过,工作状态不匹配。wrkNo={}, wrkSts={}", wrkNo, wrkMast.getWrkSts()); return; } LocMast locMast = locMastService.queryByLoc(wrkMast.getLocNo()); LocMast sourceLocMast = locMastService.queryByLoc(wrkMast.getSourceLocNo()); if (locMast == null || sourceLocMast == null) { log.error("移库完成清理跳过,源库位或目标库位不存在。wrkNo={}, sourceLocNo={}, locNo={}", wrkNo, wrkMast.getSourceLocNo(), wrkMast.getLocNo()); return; } if (!"S".equals(locMast.getLocSts()) || !"R".equals(sourceLocMast.getLocSts())) { log.error("移库完成清理跳过,库位状态异常。wrkNo={}, sourceLocNo={}, sourceLocSts={}, locNo={}, locSts={}", wrkNo, wrkMast.getSourceLocNo(), sourceLocMast.getLocSts(), wrkMast.getLocNo(), locMast.getLocSts()); return; } locMast.setLocSts("F"); locMast.setBarcode(wrkMast.getBarcode()); locMast.setModiTime(new Date()); if (!locMastService.updateById(locMast)) { log.error("移库完成清理失败,目标库位更新失败。wrkNo={}, locNo={}", wrkNo, wrkMast.getLocNo()); return; } sourceLocMast.setLocSts("O"); sourceLocMast.setBarcode(""); sourceLocMast.setModiTime(new Date()); if (!locMastService.updateById(sourceLocMast)) { log.error("移库完成清理失败,源库位更新失败。wrkNo={}, sourceLocNo={}", wrkNo, wrkMast.getSourceLocNo()); return; } archiveAndFinish(wrkMast); if (wrkMastService.deleteByWrkNoAndCurrentWrkSts(wrkMast.getWrkNo(), WrkStsType.COMPLETE_LOC_MOVE.sts) <= 0) { log.error("移库完成清理失败,删除工作档失败或状态已变化。wrkNo={}", wrkNo); return; } notifyUtils.notify("task", 1, String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.TASK_COMPLETE, JSON.toJSONString(wrkMast)); }); } @Transactional(rollbackFor = Exception.class) public void processCompleteCrnMove(Integer wrkNo) { processWithLock(wrkNo, () -> { WrkMast wrkMast = wrkMastService.selectByWorkNo(wrkNo); if (wrkMast == null) { log.error("堆垛机移位完成清理跳过,未找到工作档。wrkNo={}", wrkNo); return; } if (!Objects.equals(wrkMast.getWrkSts(), WrkStsType.COMPLETE_CRN_MOVE.sts)) { log.error("堆垛机移位完成清理跳过,工作状态不匹配。wrkNo={}, wrkSts={}", wrkNo, wrkMast.getWrkSts()); return; } archiveAndFinish(wrkMast); if (wrkMastService.deleteByWrkNoAndCurrentWrkSts(wrkMast.getWrkNo(), WrkStsType.COMPLETE_CRN_MOVE.sts) <= 0) { log.error("堆垛机移位完成清理失败,删除工作档失败或状态已变化。wrkNo={}", wrkNo); } }); } @Transactional(rollbackFor = Exception.class) public void processCancelTask(Integer wrkNo) { processWithLock(wrkNo, () -> { WrkMast wrkMast = wrkMastService.selectByWorkNo(wrkNo); if (wrkMast == null) { log.error("取消任务清理跳过,未找到工作档。wrkNo={}", wrkNo); return; } if (wrkMast.getMk() == null || !CANCEL_MKS.contains(wrkMast.getMk())) { log.error("取消任务清理跳过,取消标记不匹配。wrkNo={}, mk={}", wrkNo, wrkMast.getMk()); return; } archiveAndFinish(wrkMast); if (wrkMastService.deleteByWrkNoAndMkIn(wrkMast.getWrkNo(), CANCEL_MKS) <= 0) { log.error("取消任务清理失败,删除工作档失败或标记已变化。wrkNo={}, mk={}", wrkNo, wrkMast.getMk()); return; } if (Objects.equals(wrkMast.getIoType(), WrkIoType.IN.id)) { LocMast locMast = locMastService.queryByLoc(wrkMast.getLocNo()); if (locMast != null) { locMast.setLocSts(String.valueOf(LocStsType.O)); locMast.setModiTime(new Date()); locMastService.updateById(locMast); } } else if (Objects.equals(wrkMast.getIoType(), WrkIoType.OUT.id)) { LocMast locMast = locMastService.queryByLoc(wrkMast.getSourceLocNo()); if (locMast != null) { locMast.setLocSts(String.valueOf(LocStsType.F)); locMast.setModiTime(new Date()); locMastService.updateById(locMast); } } else if (Objects.equals(wrkMast.getIoType(), WrkIoType.LOC_MOVE.id)) { LocMast sourceLocMast = locMastService.queryByLoc(wrkMast.getSourceLocNo()); LocMast locMast = locMastService.queryByLoc(wrkMast.getLocNo()); if (sourceLocMast != null && String.valueOf(LocStsType.R).equals(sourceLocMast.getLocSts())) { sourceLocMast.setLocSts(String.valueOf(LocStsType.F)); sourceLocMast.setModiTime(new Date()); locMastService.updateById(sourceLocMast); } if (locMast != null && String.valueOf(LocStsType.S).equals(locMast.getLocSts())) { locMast.setLocSts(String.valueOf(LocStsType.O)); locMast.setModiTime(new Date()); locMastService.updateById(locMast); } } notifyUtils.notify("task", 1, String.valueOf(wrkMast.getWrkNo()), wrkMast.getWmsWrkNo(), NotifyMsgType.TASK_CANCEL, JSON.toJSONString(wrkMast)); }); } private void processWithLock(Integer wrkNo, Runnable action) { if (wrkNo == null || wrkNo <= 0 || action == null) { log.error("WrkMastFinalizeProcessor处理跳过,参数非法。wrkNo={}, actionNull={}", wrkNo, action == null); return; } String lockKey = RedisKeyType.WRK_MAST_SCHEDULER_LOCK.key + wrkNo; String lockValue = UUID.randomUUID().toString(); if (!redisUtil.trySetStringIfAbsent(lockKey, lockValue, WRK_LOCK_SECONDS)) { log.error("WrkMastFinalizeProcessor获取工作档处理锁失败。wrkNo={}, lockKey={}", wrkNo, lockKey); return; } try { action.run(); } catch (Exception e) { log.error("WrkMastFinalizeProcessor处理工作档异常。wrkNo={}", wrkNo, e); throw e; } finally { if (!redisUtil.compareAndDelete(lockKey, lockValue)) { log.error("WrkMastFinalizeProcessor释放工作档处理锁失败。wrkNo={}, lockKey={}", wrkNo, lockKey); } } } private void archiveAndFinish(WrkMast wrkMast) { WrkMastLog wrkMastLog = wrkMastLogService.saveRecord(wrkMast.getWrkNo()); if (wrkMastLog != null) { wrkAnalysisService.finishTask(wrkMast, resolveFinishTime(wrkMast), wrkMastLog.getId()); } } private void clearTaskPath(Integer taskNo, Integer sourceStaNo, Integer staNo) { List basStations = basStationService.list(new QueryWrapper().in("station_id", sourceStaNo, staNo)); for (BasStation basStation : basStations) { StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, basStation.getDeviceNo()); if (stationThread != null) { stationOperateProcessUtils.attemptClearTaskPath(stationThread, taskNo); } } } private Date resolveFinishTime(WrkMast wrkMast) { if (wrkMast == null) { return new Date(); } if (wrkMast.getModiTime() != null) { return wrkMast.getModiTime(); } if (wrkMast.getIoTime() != null) { return wrkMast.getIoTime(); } return new Date(); } }