自动化立体仓库 - WMS系统
#
pang.jiabao
2024-08-12 de8e16542594e01210aba8a72d18f2d2874681c2
#
12个文件已修改
2个文件已添加
672 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/LocDetlController.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OpenController.java 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/importexcle/LocMat.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/importexcle/LocMatListener.java 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/LocDetlMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/OpenService.java 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/BasCrnpServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 177 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/LocDetlMapper.xml 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/locDetl/locDetl.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/index.html 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/locDetl/locDetl.html 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/login.html 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/LocDetlController.java
@@ -13,16 +13,20 @@
import com.core.common.DateUtils;
import com.core.common.R;
import com.zy.asrs.entity.LocDetl;
import com.zy.asrs.entity.ManLocDetl;
import com.zy.asrs.entity.Mat;
import com.zy.asrs.importexcle.LocMat;
import com.zy.asrs.importexcle.LocMatListener;
import com.zy.asrs.mapper.LocDetlMapper;
import com.zy.asrs.service.LocDetlService;
import com.zy.asrs.service.ManLocDetlService;
import com.zy.asrs.service.LocMastService;
import com.zy.asrs.service.MatService;
import com.zy.common.web.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
@@ -39,6 +43,26 @@
    @Autowired
    private MatService matService;
    @Resource
    private LocMastService locMastService;
    @PostMapping("/importLocData")
    @ManagerAuth(memo = "导入立库已有库存")
    public R importLocData(@RequestParam("file") MultipartFile multipartFile) {
        try {
            importLocData1(multipartFile);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error(e.getMessage());
        }
        return R.ok("导入成功");
    }
    @Transactional(rollbackFor = Exception.class)
    public void importLocData1(MultipartFile multipartFile) throws IOException {
        EasyExcel.read(multipartFile.getInputStream(), LocMat.class,
                new LocMatListener(locMastService,locDetlMapper,getUserId())).sheet().doReadSync();
    }
    @RequestMapping(value = "/locDetl/update")
    public R update1() {
        if (!locDetlService.updateLocNo("0402805", "0402804")) {
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -31,6 +31,69 @@
    @Autowired
    private OpenService openService;
    @PostMapping("/scrk")
    @AppAuth(memo = "GWMS调用生成入库工作档")
    public synchronized R gwmsGenerateInventory(@RequestHeader(required = false) String appkey,
                                                @RequestBody GwmsGenerateInventoryDto param,
                                                HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.gwmsGenerateInventory(param));
    }
    @PostMapping("/zxrk")
    @AppAuth(memo = "GWCS到达堆垛机入库站点请求ZWCS执行")
    public synchronized R crnExecute(@RequestHeader(required = false) String appkey,
                                     @RequestBody CrnExecuteParam param,
                                     HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.crnExecute(param));
    }
    @PostMapping("/ckrw")
    @AppAuth(memo = "ZWMS接收MES下发出库任务")
    public synchronized R zwmsOutLocWork(@RequestHeader(required = false) String appkey,
                                         @RequestBody ZwmsOutLocWorkDto param,
                                         HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.zwmsOutLocWork(param));
    }
    @PostMapping("/ckjgsb")
    @AppAuth(memo = "货物到达出库口以后,上报出库结果")
    public synchronized R outLocResultReport(@RequestHeader(required = false) String appkey,
                                             @RequestBody GhjtApiParam param,
                                             HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.outLocResultReport(param));
    }
    @PostMapping("/cpjck")
    @AppAuth(memo = "拆盘机出库接口")
    public synchronized R emptyOutLoc(@RequestHeader(required = false) String appkey,
                                      @RequestBody GhjtApiParam param,
                                      HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.emptyOutLoc(param));
    }
    @PostMapping("/zpckdw")
    @AppAuth(memo = "组盘桁架gwcs告诉zwms货物到位,zmws告诉gwcs怎么拆")
    public synchronized R zphjDw(@RequestHeader(required = false) String appkey,
                                 @RequestBody ZphjckdwParam param,
                                 HttpServletRequest request) {
        auth(appkey, param, request);
        return openService.zphjDw(param);
    }
    @PostMapping("/cdwc")
    @AppAuth(memo = "组盘桁架拆垛完成gwcs请求zwms")
    public synchronized R zphjCdwc(@RequestHeader(required = false) String appkey,
                                   @RequestBody ZphjcdwcParam param,
                                   HttpServletRequest request) {
        auth(appkey, param, request);
        return openService.zphjCdwc(param);
    }
    /*@PostMapping("/order/matSync/default/v1")
    @AppAuth(memo = "商品信息同步接口")
    public synchronized R syncMatInfo(@RequestHeader(required = false) String appkey,
@@ -147,68 +210,7 @@
        }
    }
    @PostMapping("/scrk")
    @AppAuth(memo = "GWMS调用生成入库工作档")
    public synchronized R gwmsGenerateInventory(@RequestHeader(required = false) String appkey,
                                      @RequestBody GwmsGenerateInventoryDto param,
                                      HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.gwmsGenerateInventory(param));
    }
    @PostMapping("/zxrk")
    @AppAuth(memo = "GWCS到达堆垛机入库站点请求ZWCS执行")
    public synchronized R crnExecute(@RequestHeader(required = false) String appkey,
                                                @RequestBody CrnExecuteParam param,
                                                HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.crnExecute(param));
    }
    @PostMapping("/ckrw")
    @AppAuth(memo = "ZWMS接收MES下发出库任务")
    public synchronized R zwmsOutLocWork(@RequestHeader(required = false) String appkey,
                                     @RequestBody ZwmsOutLocWorkDto param,
                                     HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.zwmsOutLocWork(param));
    }
    @PostMapping("/ckjgsb")
    @AppAuth(memo = "货物到达出库口以后,上报出库结果")
    public synchronized R outLocResultReport(@RequestHeader(required = false) String appkey,
                                         @RequestBody GhjtApiParam param,
                                         HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.outLocResultReport(param));
    }
    @PostMapping("/cpjck")
    @AppAuth(memo = "拆盘机出库接口")
    public synchronized R emptyOutLoc(@RequestHeader(required = false) String appkey,
                                             @RequestBody GhjtApiParam param,
                                             HttpServletRequest request) {
        auth(appkey, param, request);
        return R.ok(openService.emptyOutLoc(param));
    }
    @PostMapping("/zpckdw")
    @AppAuth(memo = "组盘桁架gwcs告诉zwms货物到位,zmws告诉gwcs怎么拆")
    public synchronized R zphjDw(@RequestHeader(required = false) String appkey,
                                      @RequestBody ZphjckdwParam param,
                                      HttpServletRequest request) {
        auth(appkey, param, request);
        return openService.zphjDw(param);
    }
    @PostMapping("/cdwc")
    @AppAuth(memo = "组盘桁架拆垛完成gwcs请求zwms")
    public synchronized R zphjCdwc(@RequestHeader(required = false) String appkey,
                                      @RequestBody ZphjcdwcParam param,
                                      HttpServletRequest request) {
        auth(appkey, param, request);
        return openService.zphjCdwc(param);
    }
//    @PostMapping("/cpjck")
//    @AppAuth(memo = "物料信息获取")
//    public synchronized R emptyOutLoc(@RequestHeader(required = false) String appkey,
src/main/java/com/zy/asrs/importexcle/LocMat.java
New file
@@ -0,0 +1,28 @@
package com.zy.asrs.importexcle;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.io.Serializable;
/**
 * 同步立库已有物料
 *
 * @author pang.jiabao
 * @since 2023-09-25 16:59:21
 */
@Data
public class LocMat implements Serializable {
    // index从0开始
    @ExcelProperty(value = "库位号",index = 0)
    private String a;
    @ExcelProperty(value = "空箱子F,空托盘D",index = 1)
    private String b;
    @ExcelProperty(value = "木箱类型",index = 2)
    private String c;
}
src/main/java/com/zy/asrs/importexcle/LocMatListener.java
New file
@@ -0,0 +1,140 @@
package com.zy.asrs.importexcle;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.core.exception.CoolException;
import com.zy.asrs.entity.LocDetl;
import com.zy.asrs.entity.LocMast;
import com.zy.asrs.mapper.LocDetlMapper;
import com.zy.asrs.service.LocMastService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * @author pang.jiabao
 * @description 监听立库已有物料excel数据导入
 * @createDate 2023/10/9 11:13
 */
@Slf4j
public class LocMatListener extends AnalysisEventListener<LocMat> {
    /**
     * 每隔1000条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 400;
    private static int num = 1;
    private int count = 0;
    List<LocMat> list = new ArrayList<>();
    /**
     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private final LocMastService locMastService;
    private final LocDetlMapper locDetlMapper;
    private final Long userId;
    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     */
    public LocMatListener(LocMastService locMastService,LocDetlMapper locDetlMapper, Long userId) {
        this.locMastService = locMastService;
        this.locDetlMapper = locDetlMapper;
        this.userId = userId;
    }
    /**
     * 这个每一条数据解析都会来调用
     */
    @SneakyThrows
    @Override
    public void invoke(LocMat data, AnalysisContext context) {
        log.info("解析到第 {} 条数据:{}", ++count, JSON.toJSONString(data));
        list.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (list.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            list.clear();
        }
    }
    /**
     * 所有数据解析完成了 都会来调用
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        if (list.size() > 0) {
            saveData();
        }
        log.info("所有数据解析完成!");
    }
    /**
     * 加上存储数据库
     */
    private void saveData() {
        log.info("{}条数据,开始存储数据库!", list.size());
        List<LocDetl> locDetls = new ArrayList<>();
            list.forEach(locMat -> {
                LocMast locMast = locMastService.selectById(locMat.getA());
                if (!locMast.getLocSts().equals("O")) {
                    throw new CoolException(locMat.getA() + ":库位不为空!");
                }
                Date now = new Date();
                if ("F".equals(locMat.getB())) {
                    LocDetl locDetl = new LocDetl();
                    locDetl.setLocNo(locMat.getA());
                    locDetl.setZpallet("test" + num);
                    locDetl.setAnfme(1.0);
                    locDetl.setMatnr("3μm×10mm");
                    locDetl.setMaktx("3μm×10mm");
                    locDetl.setBatch("t" + num);
                    locDetl.setSpecs("1");
                    locDetl.setModel("t" + num);
                    locDetl.setColor(locMat.getC()); // 木箱类型
                    locDetl.setBrand("t" + num);
                    locDetl.setPrice(800.0);
                    locDetl.setOrigin("中");
                    locDetl.setWeight(900.0);
                    locDetl.setVolume(1000.0);
                    locDetl.setModiTime(now);
                    locDetl.setModiUser(userId);
                    locDetl.setAppeTime(now);
                    locDetl.setAppeUser(userId);
                    // 添加进库存明细列表
                    locDetls.add(locDetl);
                    num ++;
                }
                // 更新库位状态
                locMast.setLocSts(locMat.getB());
                locMastService.updateById(locMast);
            });
            // 批量插入库存明细
            if (!locDetls.isEmpty()) {
                locDetlMapper.batchDetls(locDetls);
            }
        log.info("存储数据库成功!");
    }
    /**
     *解析出现错误会进入该方法 具体看源代码或文档
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        log.error("处理异常:" + exception.getMessage());
        throw exception;
    }
}
src/main/java/com/zy/asrs/mapper/LocDetlMapper.java
@@ -76,4 +76,8 @@
    void updateMatTurn(@Param("matnrOld")String matnrOld,@Param("matnr")String matnr);
    /**
     * 批量插入库存明细
     */
    int batchDetls(@Param("locDetls") List<LocDetl> locDetls);
}
src/main/java/com/zy/asrs/service/OpenService.java
@@ -10,6 +10,42 @@
public interface OpenService {
    /**
     * GWMS请求ZWMS生成入库任务
     * @return 目标信息
     */
    R gwmsGenerateInventory(GwmsGenerateInventoryDto param);
    /**
     *GWMS到达目标站点请求ZWCS执行入库
     */
    String crnExecute(CrnExecuteParam param);
    /**
     * ZWMS接收MES下发出库任务
     */
    String zwmsOutLocWork(ZwmsOutLocWorkDto param);
    /**
     * 货物到达出库口以后,上报出库结果
     */
    String outLocResultReport(GhjtApiParam param);
    /**
     * 拆盘机出库接口(空托盘出库)
     */
    String emptyOutLoc(GhjtApiParam param);
    /**
     * 组盘桁架gwcs告诉zwms货物到位,zmws告诉gwcs怎么拆
     */
    R zphjDw(ZphjckdwParam param);
    /**
     * 组盘桁架拆垛完成gwcs请求zwms
     */
    R zphjCdwc(ZphjcdwcParam param);
    /**
     * 添加入库单
     */
    void pakinOrderCreate(OpenOrderPakinParam param);
@@ -60,39 +96,5 @@
    void cs2();
    /**
     * GWMS请求ZWMS生成入库任务
     * @return 目标信息
     */
    R gwmsGenerateInventory(GwmsGenerateInventoryDto param);
    /**
     *GWMS到达目标站点请求ZWCS执行入库
     */
    String crnExecute(CrnExecuteParam param);
    /**
     * ZWMS接收MES下发出库任务
     */
    String zwmsOutLocWork(ZwmsOutLocWorkDto param);
    /**
     * 货物到达出库口以后,上报出库结果
     */
    String outLocResultReport(GhjtApiParam param);
    /**
     * 拆盘机出库接口(空托盘出库)
     */
    String emptyOutLoc(GhjtApiParam param);
    /**
     * 组盘桁架gwcs告诉zwms货物到位,zmws告诉gwcs怎么拆
     */
    R zphjDw(ZphjckdwParam param);
    /**
     * 组盘桁架拆垛完成gwcs请求zwms
     */
    R zphjCdwc(ZphjcdwcParam param);
}
src/main/java/com/zy/asrs/service/impl/BasCrnpServiceImpl.java
@@ -1,12 +1,9 @@
package com.zy.asrs.service.impl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.core.common.Cools;
import com.core.exception.CoolException;
import com.zy.asrs.entity.BasCrnp;
import com.zy.asrs.entity.BasDevp;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.mapper.BasCrnpMapper;
import com.zy.asrs.service.BasCrnpService;
import com.zy.asrs.service.BasDevpService;
@@ -43,7 +40,7 @@
    public boolean checkSiteError(Integer crnNo, boolean pakin) {
        BasCrnp crnp = this.selectById(crnNo);
        if (Cools.isEmpty(crnp)) {
            log.error("{}号堆垛机不存在", crnNo);
//            log.error("{}号堆垛机不存在", crnNo);
            return false;
        }
        if (crnp.getCrnErr() != null && crnp.getCrnSts() != 3){
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -30,7 +30,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.net.CookieStore;
import java.util.*;
import java.util.stream.Collectors;
@@ -993,16 +992,17 @@
        if (Cools.isEmpty(param)) {
            throw new CoolException("请求参数有误:" + param);
        }
        int zpalletCount = locDetlService.selectCount(new EntityWrapper<LocDetl>().eq("zpallet", param.getBarcode()));
        if (zpalletCount > 0) {
            throw new CoolException("库存托盘码已存在:" + param.getBarcode());
        }
        if (!Cools.isEmpty(param.getBarcode())) {
            int zpalletCount = locDetlService.selectCount(new EntityWrapper<LocDetl>().eq("zpallet", param.getBarcode()));
            if (zpalletCount > 0) {
                throw new CoolException("库存托盘码已存在:" + param.getBarcode());
            }
        int barcodeCount = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("barcode", param.getBarcode()));
        if (barcodeCount > 0) {
            throw new CoolException("工作档已存在该托盘码:" + param.getBarcode());
            int barcodeCount = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("barcode", param.getBarcode()));
            if (barcodeCount > 0) {
                throw new CoolException("工作档已存在该托盘码:" + param.getBarcode());
            }
        }
        LocTypeDto locTypeDto = new LocTypeDto();
        locTypeDto.setLocType1((short)1);
        int iotype = 1;
src/main/java/com/zy/common/service/CommonService.java
@@ -3,7 +3,6 @@
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.core.common.Arith;
import com.core.common.Cools;
import com.core.exception.CoolException;
import com.zy.asrs.entity.*;
@@ -11,7 +10,6 @@
import com.zy.asrs.utils.Utils;
import com.zy.asrs.utils.VersionUtils;
import com.zy.common.model.LocTypeDto;
import com.zy.common.model.Shelves;
import com.zy.common.model.StartupDto;
import com.zy.common.properties.SlaveProperties;
import lombok.extern.slf4j.Slf4j;
@@ -19,7 +17,10 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * 货架核心功能
@@ -122,115 +123,9 @@
     */
    @Transactional
    public StartupDto getLocNo(Integer staDescId, Integer sourceStaNo,LocTypeDto locTypeDto,int times) {
        LocMast locMast;
        // 初始化参数
        int crnNo = 0;      //堆垛机号
        int nearRow = 0;    //最浅库位排
        int curRow = 0;     //最深库位排
        LocMast locMast = null;     // 目标库位
        StartupDto startupDto = new StartupDto();
        RowLastno rowLastno = rowLastnoService.selectById(1);
        int sRow = rowLastno.getsRow();
        int eRow = rowLastno.geteRow();
        int crn_qty = rowLastno.getCrnQty();
        int rowCount = eRow - sRow + 1;
        if (Cools.isEmpty(rowLastno)) {
            throw new CoolException("数据异常,请联系管理员");
        }
        // ===============>>>> 开始执行
        curRow = rowLastno.getCurrentRow();
        // 如果没有相近物料,则按规则轮询货架
        if (Cools.isEmpty(locMast)) {
            Shelves shelves = new Shelves(rowCount, crn_qty);
            int divides = (int) Arith.divides(1, curRow - 1, 4);
            curRow = (int) Arith.remainder(curRow, 4);
            if (curRow == 0) {
                curRow = 4;
            }
            for (int i = 0; i < shelves.group; i ++) {
                curRow = shelves.start(curRow);
                if (curRow < 0) {
                    throw new CoolException("检索库位失败,请联系管理员");
                }
                Integer crnNo1 = shelves.get(curRow);
                crnNo1 = crnNo1 + divides*1;
                if (basCrnpService.checkSiteError(crnNo1, true)) {
                    crnNo = crnNo1;
                    curRow = curRow + divides*4;
                    break;
                }
            }
        }
        if (crnNo == 0) {
            throw new CoolException("没有可用的堆垛机");
        }
        // 1.当检索库排为浅库位排时,优先寻找当前库排的深库位排
        if (locMast == null) {
            if (Utils.isShallowLoc(slaveProperties, curRow)) {
                Integer deepRow = Utils.getDeepRow(slaveProperties, curRow);
                locMast = locMastService.queryFreeLocMast(deepRow, locTypeDto.getLocType1());
                // todo:luxiaotao 如果用浅排找到的深库位,那么则需要判断这个深库位对应的浅库位是否有货(F、X、D)
                // 因库位移转、需预留空库位
                if (!locMastService.checkEmptyCount(locMast)) {
                    locMast = null;
                }
            }
            if (Cools.isEmpty(locMast)) {
                locMast = locMastService.queryFreeLocMast(curRow, locTypeDto.getLocType1());
                // 因库位移转、需预留空库位
                if (!locMastService.checkEmptyCount(locMast)) {
                    locMast = null;
                }
                // 目标库位 ===>> 浅库位, 则校验其深库位是否为 F D X
                if (null != locMast && Utils.isShallowLoc(slaveProperties, locMast.getLocNo())) {
                    LocMast deepLoc = locMastService.selectById(Utils.getDeepLoc(slaveProperties, locMast.getLocNo()));
                    if (!deepLoc.getLocSts().equals("F") && !deepLoc.getLocSts().equals("D") && !deepLoc.getLocSts().equals("X")) {
                        locMast = null;
                    }
                }
                // 目标库位 ===>> 深库位, 则校验其浅库位是否为 O
                if (null != locMast && Utils.isDeepLoc(slaveProperties, locMast.getLocNo())) {
                    LocMast shallowLoc = locMastService.selectById(Utils.getShallowLoc(slaveProperties, locMast.getLocNo()));
                    if (!Cools.isEmpty(shallowLoc)) {
                        if (!shallowLoc.getLocSts().equals("O")) {
                            locMast = null;
                        }
                    }
                }
            }
        }
        // 更新库位排号
        rowLastno.setCurrentRow(curRow);
        rowLastnoService.updateById(rowLastno);
        // 2.库位当前所属尺寸无空库位时,调整尺寸参数,向上兼容检索库位
        if (Cools.isEmpty(locMast)) {
            // 当前巷道无空库位时,递归调整至下一巷道,检索全部巷道无果后,跳出递归
            if (times < rowCount) {
                times = times + 1;
                return getLocNo(staDescId, sourceStaNo, locTypeDto, times);
            }
            log.error("系统没有空库位!!! 尺寸规格: {}, 轮询次数:{}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("没有空库位");
        }
//        // 搜索空托
//        locMast = getLocNoStep4(staDescId, sourceStaNo);
//        if (locMast != null) {
//            //找到库位,返回dto
//            return getLocNoStep6(staDescId, sourceStaNo, locMast);//返回dto
//        }
        if (locMast == null) {
            //搜索整个空库位组
            locMast = getLocNoStepSingle(locTypeDto);
        }
        locMast = getLocNoStepSingle(locTypeDto);
        if (locMast != null) {
            //找到库位,返回dto
@@ -240,37 +135,49 @@
       //找不到库位,抛出异常
        throw new CoolException("没有空库位");
    }
    // 搜索单品(整个库位组)
    private LocMast getLocNoStepSingle(LocTypeDto locTypeDto) {
        LocMast locMast = null;
        //单品
        List<LocMast> locMasts = locMastService.selectAreaEmpty(locTypeDto.getLocType1());//搜索货物
        // 获取模式为电脑模式,无任务的堆垛机列表:防止分配到堆垛机不可用
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<BasCrnp>().eq("crn_sts",3)
                .eq("wrk_no",0));
        if (basCrnps.isEmpty()) {
            // 都有任务则获取电脑模式的堆垛机列表
            basCrnps = basCrnpService.selectList(new EntityWrapper<BasCrnp>().eq("crn_sts",3));
        }
        if (basCrnps.isEmpty()) {
            throw new CoolException("没有可用堆垛机,堆垛机停止或异常");
        }
        // 可用堆垛机列表
        List<Integer> crnNoList = basCrnps.stream().map(BasCrnp::getCrnNo).collect(Collectors.toList());
        // 搜索深库位
        List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                .eq("loc_sts","O").in("crn_no",crnNoList).in("row1","1,4,5,8,9,12,13,16,17,20,21,24").orderBy("lev1,bay1,row1"));
        // 深库位没有则搜索浅库位
        if (locMasts.isEmpty()) {
            locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                    .eq("loc_sts","O").in("crn_no",crnNoList).in("row1","2,3,6,7,10,11,14,15,18,19,22,23").orderBy("lev1,bay1,row1"));
        }
        if (locMasts.isEmpty()) {
            throw new CoolException("没有可用库位");
        }
        // 记录堆垛机是否查询过,避免重复查询
        Map<Integer,Boolean> crnMap = new HashMap<>();
        for (LocMast mast : locMasts) {
            List<String> groupLoc = Utils.getGroupLocNo(mast.getLocNo(), true);
//            if (!locMastService.checkAllLocEmpty(groupLoc)) {
//                continue;
//            }
            LocMast tmp = null;
            for (String loc : groupLoc) {
                LocMast locMast1 = locMastService.selectByLoc(loc);
                if (locMast1 == null) {
                    continue;
            if (crnMap.get(mast.getCrnNo()) == null) {
                //预留空库位
                if (locMastService.checkEmptyCount(mast, 10)) {
                    locMast = mast;
                    break;
                } else {
                    crnMap.put(mast.getCrnNo(),true);
                }
                if (!locMast1.getLocSts().equals("O")) {
                    continue;
                }
                tmp = locMast1;
                break;
            }
            //预留空库位
            if (tmp != null && locMastService.checkEmptyCount(mast, 10)) {
                locMast = tmp;
                break;
            }
        }
src/main/resources/mapper/LocDetlMapper.xml
@@ -57,6 +57,33 @@
            </otherwise>
        </choose>
    </sql>
    <insert id="batchDetls">
        INSERT INTO
        asr_loc_detl(loc_no,zpallet,anfme,matnr,maktx,batch,specs,model,color,brand,price
        ,origin,weight,volume,modi_time,modi_user,appe_time,appe_user)
        VALUES
        <foreach collection="locDetls" item="item" index="index" separator=",">
            (
            #{item.locNo},
            #{item.zpallet},
            #{item.anfme},
            #{item.matnr},
            #{item.maktx},
            #{item.batch},
            #{item.specs},
            #{item.model},
            #{item.color},
            #{item.brand},
            #{item.price},
            #{item.origin},
            #{item.weight},
            #{item.volume},
            #{item.modiTime},
            #{item.modiUser},
            #{item.appeTime},
            #{item.appeUser}
            )</foreach>
    </insert>
    <select id="selectItem" resultMap="BaseResultMap">
        select top 1 *
src/main/webapp/static/js/locDetl/locDetl.js
@@ -2,17 +2,17 @@
function getCol() {
    var cols = [
        {field: 'locNo$', align: 'center',title: '库位号'},
        {field: 'matnr', align: 'center',title: '规格', sort:true}
        ,{field: 'maktx', align: 'center',title: '商品名称', sort:true}
        {field: 'matnr', align: 'center',title: '规格', sort:true,width: 120}
        ,{field: 'maktx', align: 'center',title: '商品名称', sort:true,hide: true}
        ,{field: 'orderNo', align: 'center',title: '单据编号', hide: true}
        ,{field: 'batch', align: 'center',title: '箱号', width: 300, sort:true}
        ,{field: 'batch', align: 'center',title: '箱号', width: 250, sort:true}
        ,{field: 'anfme', align: 'center',title: '数量'}
        ,{field: 'zpallet', align: 'center',title: '托盘条码'}
        ,{field: 'specs', align: 'center',title: '接头'}
        ,{field: 'model', align: 'center',title: '卷号', hide: false}
        ,{field: 'color', align: 'center',title: '颜色', hide: true}
        ,{field: 'brand', align: 'center',title: '木箱类型', hide: true}
        ,{field: 'brand$', align: 'center',title: '木箱类型', hide: false}
        ,{field: 'color', align: 'center',title: '木箱类型', hide: false,width: 250}
        ,{field: 'brand', align: 'center',title: '包装组号', hide: false}
        ,{field: 'brand$', align: 'center',title: '木箱类型', hide: true}
        ,{field: 'unit', align: 'center',title: '单位', hide: true}
        ,{field: 'price', align: 'center',title: '长度', hide: false}
        ,{field: 'sku', align: 'center',title: 'sku', hide: true}
@@ -40,7 +40,7 @@
    // cols.push.apply(cols, detlCols);
    cols.push({field: 'modiUser$', align: 'center',title: '修改人员',hide: true}
        ,{field: 'modiTime$', align: 'center',title: '修改时间'}
        ,{field: 'modiTime$', align: 'center',title: '修改时间',width: 200}
    )
    return cols;
}
src/main/webapp/views/index.html
@@ -2,7 +2,7 @@
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>冠鸿江铜 - 自动化立体仓库 - AS / RS</title>
  <title>冠鸿江铜WMS</title>
  <meta name="renderer" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
@@ -26,7 +26,7 @@
  <!-- 头部 -->
  <div class="layui-header">
    <div class="layui-logo">
      <img src="../static/image/logo.png" style="display: inline-block; width: 40%;height: auto">
<!--      <img src="../static/image/logo.png" style="display: inline-block; width: 40%;height: auto">-->
      <!--          <span style="margin-top: 0; letter-spacing: 10px">中扬立库</span>-->
<!--                <img src="../static/image/favicon.ico"/>-->
<!--                <cite>冠鸿江铜</cite>-->
src/main/webapp/views/locDetl/locDetl.html
@@ -73,11 +73,38 @@
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-primary layui-btn-sm" id="btn-export" lay-event="exportData" style="margin-top: 10px">导出</button>
    </div>
    <input type="file" id="fileInput" accept=".xlsx, .xls">
    <button class="layui-btn layui-btn-primary layui-btn-sm" id="btn-import" onclick="exportExc()" style="margin-top: 10px">导入</button>
</script>
<script type="text/html" id="operate">
    <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">详情</a>
</script>
<script>
    function exportExc() {
        var fileInput = document.getElementById('fileInput');
        var file = fileInput.files[0];
        if (file === undefined) {
            alert('请先选择文件')
            return
        }
        var formData = new FormData();
        formData.append('file', file);
        fetch(baseUrl+'/importLocData', {
            method: 'POST',
            headers: {'token': localStorage.getItem('token')},
            body: formData
        }).then(response => {
            response.text().then(data => {
                var res = JSON.parse(data)
                alert(res.msg)
            })
        }).catch(error => {
            alert('导入异常');
        });
    }
</script>
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script>
src/main/webapp/views/login.html
@@ -3,7 +3,7 @@
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>冠鸿江铜 │ login of zoneyung wms</title>
    <title>冠鸿江铜WMS</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1">
    <meta name="description" content="study of Instancing with three.js">
    <meta name="keywords" content="undefined, Yoichi Kobayashi, WebGL, three.js">
@@ -53,7 +53,7 @@
                    z-index: 100;
                    top: 22px;
                    left: 20px;">
        <img src="../static/image/logo.png" alt="" style="width: 20%">
<!--        <img src="../static/image/logo.png" alt="" style="width: 20%">-->
      </div>
      <div class="p-sketch-outline">
        <h2 class="p-sketch-outline__title">Automatic Storage and Retrieval System</h2>
@@ -67,7 +67,7 @@
    <div id="sidebar">
      <div class="login-contain">
        <div class="login-box">
          <img src="../static/image/logo.png" alt="" style="width: 80%">
<!--          <img src="../static/image/logo.png" alt="" style="width: 80%">-->
<!--          <span class="login100-form-title p-t-20 p-b-45">中扬立库</span>-->
<!--          <span class="login100-form-title p-t-20 p-b-45" style="margin: 15px 0;color: #868686;font-size: 24px">WMS</span>-->
          <div class="wrap-input100 validate-input m-b-10" data-validate="请输入用户名">