Junjie
1 天以前 ccab5f516f055c5e8d8015442d9860a18072f508
src/main/java/com/zy/common/service/CommonService.java
@@ -20,6 +20,7 @@
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.Comparator;
@@ -31,7 +32,12 @@
@Service
public class CommonService {
    private static final long OUT_STATION_ROUTE_CACHE_SECONDS = 300L;
    private static final long OUT_STATION_ROUTE_CACHE_SECONDS = 60 * 60 * 24 * 7;
    /**
     * 入库目标站的拓扑变化频率很低,允许使用 24h 缓存减少重复可达路径搜索。
     */
    private static final long IN_STATION_ROUTE_CACHE_SECONDS = 60 * 60 * 24;
    private static final long IN_STATION_ROUTE_SLOW_LOG_THRESHOLD_MS = 200L;
    @Autowired
    private WrkMastService wrkMastService;
@@ -58,36 +64,10 @@
     * 生成工作号
     * @return workNo(工作号)
     */
    public synchronized int getWorkNo(Integer wrkMk) {
        WrkLastno wrkLastno = wrkLastnoService.getById(wrkMk);
        if (Cools.isEmpty(wrkLastno)) {
            throw new CoolException("数据异常,请联系管理员");
        }
        int workNo = wrkLastno.getWrkNo();
        int sNo = wrkLastno.getsNo();
        int eNo = wrkLastno.geteNo();
        workNo = workNo>=eNo ? sNo : workNo+1;
        while (true) {
            WrkMast wrkMast = wrkMastService.selectByWorkNo(workNo);
            if (null != wrkMast) {
                workNo = workNo>=eNo ? sNo : workNo+1;
            } else {
                break;
            }
        }
        // 修改序号记录
        if (workNo > 0){
            wrkLastno.setWrkNo(workNo);
            wrkLastnoService.updateById(wrkLastno);
        }
        // 检验
        if (workNo == 0) {
    public int getWorkNo(Integer wrkMk) {
        int workNo = wrkLastnoService.allocateNextWorkNo(wrkMk);
        if (workNo <= 0) {
            throw new CoolException("生成工作号失败,请联系管理员");
        } else {
            if (wrkMastService.selectByWorkNo(workNo)!=null) {
                throw new CoolException("生成工作号" + workNo + "在工作档中已存在");
            }
        }
        return workNo;
    }
@@ -109,21 +89,33 @@
            throw new CoolException("任务不存在");
        }
        Long currentWrkSts = wrkMast.getWrkSts();
        Long targetWrkSts;
        if (wrkMast.getIoType() == WrkIoType.IN.id) {
            wrkMast.setWrkSts(WrkStsType.COMPLETE_INBOUND.sts);
            targetWrkSts = WrkStsType.COMPLETE_INBOUND.sts;
        }else if (wrkMast.getIoType() == WrkIoType.OUT.id) {
            wrkMast.setWrkSts(WrkStsType.COMPLETE_OUTBOUND.sts);
            targetWrkSts = WrkStsType.COMPLETE_OUTBOUND.sts;
        } else if (wrkMast.getIoType() == WrkIoType.LOC_MOVE.id) {
            wrkMast.setWrkSts(WrkStsType.COMPLETE_LOC_MOVE.sts);
            targetWrkSts = WrkStsType.COMPLETE_LOC_MOVE.sts;
        } else if (wrkMast.getIoType() == WrkIoType.CRN_MOVE.id) {
            wrkMast.setWrkSts(WrkStsType.COMPLETE_CRN_MOVE.sts);
            targetWrkSts = WrkStsType.COMPLETE_CRN_MOVE.sts;
        } else {
            throw new CoolException("任务类型不支持完成");
        }
        wrkMast.setModiTime(new Date());
        wrkMastService.updateById(wrkMast);
        boolean updated = wrkMastService.update(null, new UpdateWrapper<WrkMast>()
                .set("wrk_sts", targetWrkSts)
                .set("modi_time", new Date())
                .set("memo", "手动完成")
                .eq("wrk_no", wrkMast.getWrkNo())
                .eq("wrk_sts", currentWrkSts));
        if (!updated) {
            throw new CoolException("任务状态已变化,完成失败");
        }
        return true;
    }
    @Transactional
    public boolean cancelTask(CancelTaskParam param) {
        WrkMast wrkMast = null;
        Integer wrkNo = param.getWrkNo();
@@ -141,24 +133,61 @@
            throw new CoolException("任务不存在");
        }
        boolean cancelSuccess = false;
        if (wrkMast.getIoType().equals(WrkIoType.IN.id) && !wrkMast.getWrkSts().equals(WrkStsType.NEW_INBOUND.sts)) {
            cancelSuccess = true;
        } else if (wrkMast.getIoType().equals(WrkIoType.OUT.id) && !wrkMast.getWrkSts().equals(WrkStsType.NEW_OUTBOUND.sts)) {
            cancelSuccess = true;
        } else if (wrkMast.getIoType().equals(WrkIoType.LOC_MOVE.id) && !wrkMast.getWrkSts().equals(WrkStsType.NEW_LOC_MOVE.sts)) {
            cancelSuccess = true;
        } else if (wrkMast.getIoType().equals(WrkIoType.CRN_MOVE.id) && !wrkMast.getWrkSts().equals(WrkStsType.NEW_CRN_MOVE.sts)) {
            cancelSuccess = true;
        Long expectedWrkSts;
        if (wrkMast.getIoType().equals(WrkIoType.IN.id)) {
            expectedWrkSts = WrkStsType.NEW_INBOUND.sts;
        } else if (wrkMast.getIoType().equals(WrkIoType.OUT.id)) {
            expectedWrkSts = WrkStsType.NEW_OUTBOUND.sts;
        } else if (wrkMast.getIoType().equals(WrkIoType.LOC_MOVE.id)) {
            expectedWrkSts = WrkStsType.NEW_LOC_MOVE.sts;
        } else if (wrkMast.getIoType().equals(WrkIoType.CRN_MOVE.id)) {
            expectedWrkSts = WrkStsType.NEW_CRN_MOVE.sts;
        } else {
            throw new CoolException("任务类型不支持取消");
        }
        if (cancelSuccess) {
        if (!expectedWrkSts.equals(wrkMast.getWrkSts())) {
            throw new CoolException("任务已执行,取消失败");
        }
        wrkMast.setMk("taskCancel");
        wrkMast.setModiTime(new Date());
        wrkMastService.updateById(wrkMast);
        boolean updated = wrkMastService.update(null, new UpdateWrapper<WrkMast>()
                .eq("wrk_no", wrkMast.getWrkNo())
                .eq("wrk_sts", expectedWrkSts)
                .set("mk", "taskCancel")
                .set("memo", "手动取消")
                .set("modi_time", new Date()));
        if (!updated) {
            throw new CoolException("任务状态已变化,取消失败");
        }
        return true;
    }
    @Transactional
    public boolean forceCancelTask(CancelTaskParam param) {
        WrkMast wrkMast = null;
        Integer wrkNo = param.getWrkNo();
        String taskNo = param.getTaskNo();//wms任务号
        if (wrkNo == null) {
            if (!Cools.isEmpty(taskNo)) {
                wrkMast = wrkMastService.getOne(new QueryWrapper<WrkMast>().eq("wms_wrk_no", taskNo));
            }
        } else {
            wrkMast = wrkMastService.selectByWorkNo(wrkNo);
        }
        if (wrkMast == null) {
            throw new CoolException("任务不存在");
        }
        boolean updated = wrkMastService.update(null, new UpdateWrapper<WrkMast>()
                .eq("wrk_no", wrkMast.getWrkNo())
                .set("mk", "taskForceCancel")
                .set("memo", "手动完成")
                .set("modi_time", new Date()));
        if (!updated) {
            throw new CoolException("任务强制取消失败");
        }
        return true;
    }
@@ -384,6 +413,86 @@
        locMastService.updateById(locMast);
        return true;
    }
    //移库任务(返回WrkMast,供跑库等场景获取工作号)
    public WrkMast createLocMoveTaskReturnMast(CreateLocMoveTaskParam param) {
        Date now = new Date();
        LocMast sourceLocMast = locMastService.queryByLoc(param.getSourceLocNo());
        if (null == sourceLocMast) {
            throw new CoolException(param.getSourceLocNo() + "源库位不存在");
        }
        if (!sourceLocMast.getLocSts().equals("F")) {
            throw new CoolException(sourceLocMast.getLocNo() + "源库位不处于在库状态");
        }
        LocMast locMast = locMastService.queryByLoc(param.getLocNo());
        if (null == locMast) {
            throw new CoolException(param.getLocNo() + "目标库位不存在");
        }
        if (!locMast.getLocSts().equals("O")) {
            throw new CoolException(locMast.getLocNo() + "目标库位不处于空库状态");
        }
        double ioPri = 800D;
        if (param.getTaskPri() != null) {
            ioPri = param.getTaskPri().doubleValue();
        }
        FindCrnNoResult sourceCrnResult = this.findCrnNoByLocNo(sourceLocMast.getLocNo());
        if (sourceCrnResult == null) {
            throw new CoolException("未找到对应堆垛机");
        }
        FindCrnNoResult targetCrnResult = this.findCrnNoByLocNo(locMast.getLocNo());
        if (targetCrnResult == null) {
            throw new CoolException("未找到对应堆垛机");
        }
        if (!sourceCrnResult.getCrnNo().equals(targetCrnResult.getCrnNo())) {
            throw new CoolException("源库位和目标库位不在同一巷道");
        }
        int workNo = getWorkNo(WrkIoType.LOC_MOVE.id);
        WrkMast wrkMast = new WrkMast();
        wrkMast.setWrkNo(workNo);
        wrkMast.setIoTime(now);
        wrkMast.setWrkSts(WrkStsType.NEW_LOC_MOVE.sts);
        wrkMast.setIoType(WrkIoType.LOC_MOVE.id);
        wrkMast.setIoPri(ioPri);
        wrkMast.setSourceLocNo(param.getSourceLocNo());
        wrkMast.setLocNo(param.getLocNo());
        wrkMast.setWmsWrkNo(param.getTaskNo());
        wrkMast.setBarcode(sourceLocMast.getBarcode());
        wrkMast.setAppeTime(now);
        wrkMast.setModiTime(now);
        if (targetCrnResult.getCrnType().equals(SlaveType.Crn)) {
            wrkMast.setCrnNo(targetCrnResult.getCrnNo());
        } else if (targetCrnResult.getCrnType().equals(SlaveType.DualCrn)) {
            wrkMast.setDualCrnNo(targetCrnResult.getCrnNo());
        } else {
            throw new CoolException("未知设备类型");
        }
        boolean res = wrkMastService.save(wrkMast);
        if (!res) {
            News.error("移库任务 --- 保存工作档失败!");
            throw new CoolException("保存工作档失败");
        }
        wrkAnalysisService.initForTask(wrkMast);
        sourceLocMast.setLocSts("R");
        sourceLocMast.setModiTime(new Date());
        locMastService.updateById(sourceLocMast);
        locMast.setLocSts("S");
        locMast.setModiTime(new Date());
        locMastService.updateById(locMast);
        return wrkMast;
    }
    //入库任务
@@ -640,27 +749,42 @@
    }
    public Integer findInStationId(FindCrnNoResult findCrnNoResult, Integer sourceStationId) {
        return resolveInStationId(findCrnNoResult, sourceStationId).getTargetStationId();
    }
    public InStationResolveResult resolveInStationId(FindCrnNoResult findCrnNoResult, Integer sourceStationId) {
        long resolveStartNs = System.nanoTime();
        if (findCrnNoResult == null || findCrnNoResult.getCrnType() == null
                || findCrnNoResult.getCrnNo() == null || sourceStationId == null) {
            return InStationResolveResult.empty(false, nanosToMillis(resolveStartNs));
        }
        List<StationObjModel> stationList = new ArrayList<>();
        Integer crnNo = findCrnNoResult.getCrnNo();
        if (findCrnNoResult.getCrnType().equals(SlaveType.Crn)) {
            BasCrnp basCrnp = basCrnpService.getOne(new QueryWrapper<BasCrnp>().eq("crn_no", crnNo));
            if(basCrnp == null) {
                return null;
                return InStationResolveResult.empty(false, nanosToMillis(resolveStartNs));
            }
            stationList = basCrnp.getInStationList$();
        } else if (findCrnNoResult.getCrnType().equals(SlaveType.DualCrn)) {
            BasDualCrnp basDualCrnp = basDualCrnpService.getOne(new QueryWrapper<BasDualCrnp>().eq("crn_no", crnNo));
            if(basDualCrnp == null) {
                return null;
                return InStationResolveResult.empty(false, nanosToMillis(resolveStartNs));
            }
            stationList = basDualCrnp.getInStationList$();
        }
        Integer cachedTargetStationId = resolveCachedInStationId(findCrnNoResult, sourceStationId, stationList);
        if (cachedTargetStationId != null) {
            return cachedTargetStationId;
            long totalCostMs = nanosToMillis(resolveStartNs);
            if (totalCostMs >= IN_STATION_ROUTE_SLOW_LOG_THRESHOLD_MS) {
                log.info("入库目标站缓存命中耗时较长,sourceStationId={},crnNo={},targetStationId={},totalCost={}ms",
                        sourceStationId, crnNo, cachedTargetStationId, totalCostMs);
            }
            return InStationResolveResult.cacheHit(cachedTargetStationId, totalCostMs);
        }
        long searchStartNs = System.nanoTime();
        Integer targetStationId = null;
        for (StationObjModel stationObjModel : stationList) {
            try {
@@ -674,7 +798,11 @@
//                e.printStackTrace();
            }
        }
        return targetStationId;
        long searchCostMs = nanosToMillis(searchStartNs);
        long totalCostMs = nanosToMillis(resolveStartNs);
        log.info("入库目标站缓存未命中,sourceStationId={},crnNo={},targetStationId={},searchCost={}ms,totalCost={}ms",
                sourceStationId, crnNo, targetStationId, searchCostMs, totalCostMs);
        return InStationResolveResult.searchResult(targetStationId, totalCostMs, searchCostMs);
    }
    public Integer findOutStationId(FindCrnNoResult findCrnNoResult, Integer targetStationId) {
@@ -755,7 +883,7 @@
        }
        redisUtil.set(buildInStationRouteCacheKey(findCrnNoResult, sourceStationId),
                targetStationId,
                OUT_STATION_ROUTE_CACHE_SECONDS);
                IN_STATION_ROUTE_CACHE_SECONDS);
    }
    private String buildInStationRouteCacheKey(FindCrnNoResult findCrnNoResult, Integer sourceStationId) {
@@ -836,4 +964,54 @@
        }
    }
    private long nanosToMillis(long startNs) {
        long elapsedNs = System.nanoTime() - startNs;
        return elapsedNs <= 0L ? 0L : elapsedNs / 1_000_000L;
    }
    public static class InStationResolveResult {
        private final Integer targetStationId;
        private final boolean cacheHit;
        private final long totalCostMs;
        private final long searchCostMs;
        private InStationResolveResult(Integer targetStationId,
                                       boolean cacheHit,
                                       long totalCostMs,
                                       long searchCostMs) {
            this.targetStationId = targetStationId;
            this.cacheHit = cacheHit;
            this.totalCostMs = totalCostMs;
            this.searchCostMs = searchCostMs;
        }
        public static InStationResolveResult cacheHit(Integer targetStationId, long totalCostMs) {
            return new InStationResolveResult(targetStationId, true, totalCostMs, 0L);
        }
        public static InStationResolveResult searchResult(Integer targetStationId, long totalCostMs, long searchCostMs) {
            return new InStationResolveResult(targetStationId, false, totalCostMs, searchCostMs);
        }
        public static InStationResolveResult empty(boolean cacheHit, long totalCostMs) {
            return new InStationResolveResult(null, cacheHit, totalCostMs, 0L);
        }
        public Integer getTargetStationId() {
            return targetStationId;
        }
        public boolean isCacheHit() {
            return cacheHit;
        }
        public long getTotalCostMs() {
            return totalCostMs;
        }
        public long getSearchCostMs() {
            return searchCostMs;
        }
    }
}