自动化立体仓库 - WMS系统
pang.jiabao
2025-11-10 11a590bda370ddad398b2c3ae68a218ee8d5a5d2
src/main/java/com/zy/common/service/CommonService.java
@@ -18,7 +18,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
 * 货架核心功能
@@ -50,6 +51,9 @@
    private SlaveProperties slaveProperties;
    @Autowired
    private WrkDetlService wrkDetlService;
    // 深库位排
    private static final List<Integer> deepLocRowList = Arrays.asList(1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32);
    /**
     * 生成工作号
@@ -91,6 +95,102 @@
        return workNo;
    }
    /**
     * 获取库位---山东宜和纺织
     *
     * @param sourceSiteNo 入库源站点
     */
    public StartupDto getLocNoBySdyhfz(Integer sourceSiteNo,int ioType) {
        // 获取可用,可入,无报警堆垛机
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<BasCrnp>().eq("crn_sts", 3).eq("crn_err", 0).eq("in_enable", "Y"));
        if (basCrnps.size() == 0) {
            log.error(sourceSiteNo + "入库请求库位失败:堆垛机报警/无可用/无可入");
            throw new CoolException(sourceSiteNo + "入库请求库位失败:堆垛机报警/无可用/无可入");
        }
        // 计算负载均衡
        List<CraneLoadInfo> craneInfos = new ArrayList<>();
        // 负载均衡权重(可调整)任务少,库位占用少的先分配
        double w1 = 0.6; // 任务数权重
        double w2 = 0.4; // 仓位权重
        for (BasCrnp basCrnp : basCrnps) {
            // 挂载任务数
            int taskCount = locMastService.selectCount(new EntityWrapper<LocMast>().eq("crn_no", basCrnp.getCrnNo()).in("loc_sts", "S", "R"));
            // 空库位数量
            int emptyCount = locMastService.selectCount(new EntityWrapper<LocMast>().eq("crn_no", basCrnp.getCrnNo()).eq("loc_sts", "O"));
            // 库位占用率
            double emptyLocOccupancy = (double) (800 - emptyCount) / 800;
            CraneLoadInfo craneLoadInfo = new CraneLoadInfo();
            craneLoadInfo.setCrnNo(basCrnp.getCrnNo());
            craneLoadInfo.setTaskCount(taskCount);
            craneLoadInfo.setOccupancy(emptyLocOccupancy);
            craneInfos.add(craneLoadInfo);
        }
        // 获取最值
        int taskMax = craneInfos.stream().mapToInt(CraneLoadInfo::getTaskCount).max().orElse(0);
        int taskMin = craneInfos.stream().mapToInt(CraneLoadInfo::getTaskCount).min().orElse(0);
        double occMax = craneInfos.stream().mapToDouble(CraneLoadInfo::getOccupancy).max().orElse(0);
        double occMin = craneInfos.stream().mapToDouble(CraneLoadInfo::getOccupancy).min().orElse(0);
        // 避免分母为0的情况
        double taskRange = (taskMax - taskMin) == 0 ? 1 : (taskMax - taskMin);
        double occRange = (occMax - occMin) == 0 ? 1 : (occMax - occMin);
        // 计算 α
        for (CraneLoadInfo info : craneInfos) {
            double taskNorm = (info.getTaskCount() - taskMin) / taskRange;
            double occNorm = (info.getOccupancy() - occMin) / occRange;
            double alpha = w1 * taskNorm + w2 * occNorm;
            info.setAlpha(alpha);
        }
        // 排序:α 越小越空闲
        craneInfos.sort(Comparator.comparingDouble(CraneLoadInfo::getAlpha));
        // 寻找库位
        LocMast locMast = null;
        // 根据入库类型和源站点获取工作路径
        StaDesc staDesc = null;
        for (CraneLoadInfo craneLoadInfo : craneInfos) {
            List<LocMast> locMastList = locMastService.selectList(new EntityWrapper<LocMast>().eq("crn_no", craneLoadInfo.getCrnNo()).eq("loc_sts", "O").orderBy("lev1").orderBy("bay1").orderBy("row1"));
            if (locMastList.size() <= 4) {
                continue;
            }
            // 先取深库位
            Optional<LocMast> first = locMastList.stream().filter(o -> deepLocRowList.contains(o.getRow1())).findFirst();
            // 深库位里面没有从浅库位里面取
            locMast = first.orElseGet(() -> locMastList.get(0));
            if (locMast != null) {
                staDesc = staDescService.selectOne(new EntityWrapper<StaDesc>().eq("type_no", ioType).eq("crn_no", locMast.getCrnNo()).eq("stn_no", sourceSiteNo));
                if (staDesc == null) {
                    log.error("获取工作路径异常,类型:{},堆垛机:{},源站:{}", ioType, locMast.getCrnNo(), sourceSiteNo);
                    throw new CoolException("获取工作路径异常,类型:" + ioType + ",堆垛机:" + locMast.getCrnNo() + ",源站:" + sourceSiteNo);
                }
                break;
            }
        }
        if (locMast == null) {
            log.error("堆垛机剩余库位不足:{}", craneInfos);
            throw new CoolException("堆垛机不可用/库位不足,请检查");
        }
        // 生成工作号
        int workNo = getWorkNo(0);
        // 返回dto
        StartupDto startupDto = new StartupDto();
        startupDto.setWorkNo(workNo);
        startupDto.setCrnNo(locMast.getCrnNo());
        startupDto.setSourceStaNo(sourceSiteNo);
        startupDto.setStaNo(staDesc.getCrnStn());
        startupDto.setLocNo(locMast.getLocNo());
        return startupDto;
    }
    //拆盘机处空板扫码,驱动托盘向码垛位,不入库
    @Transactional
    public StartupDto getScanBarcodeEmptyBoard() {