自动化立体仓库 - WMS系统
pang.jiabao
2024-04-20 529c963c32dd81947a573d8ebe3524278aa2cbcf
新增补料功能
6个文件已修改
3个文件已添加
508 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/LocDetlController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/WorkController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/ReplenishmentParam.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/WorkService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/WrkDetlService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/WrkDetlServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/pakStore/pakComb.js 250 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/pakStore/pakComb.html 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/LocDetlController.java
@@ -13,11 +13,9 @@
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.mapper.LocDetlMapper;
import com.zy.asrs.service.LocDetlService;
import com.zy.asrs.service.ManLocDetlService;
import com.zy.asrs.service.MatService;
import com.zy.common.web.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
@@ -69,6 +67,18 @@
        return R.parse(BaseRes.EMPTY);
    }
    @GetMapping (value = "/locDetl/pageList/auth")
    @ManagerAuth(memo = "分页查询库存明细")
    public R pageList(@RequestParam Map<String,Object> param){
        if (Cools.isEmpty(param.get("locNo"))){
            return new R(201,"");
        }
        Page<LocDetl> locDetlPage = locDetlService.selectPage(new Page<>(Integer.parseInt((String) param.get("curr"))
                , Integer.parseInt((String) param.get("limit"))), new EntityWrapper<LocDetl>().eq("loc_no", param.get("locNo")));
        return R.ok(locDetlPage);
    }
    @RequestMapping(value = "/stock/out/list/auth")
    @ManagerAuth
    public R stockOutList(@RequestParam(defaultValue = "1")Integer curr,
src/main/java/com/zy/asrs/controller/WorkController.java
@@ -3,10 +3,7 @@
import com.core.annotations.ManagerAuth;
import com.core.common.R;
import com.zy.asrs.entity.WaitPakin;
import com.zy.asrs.entity.param.EmptyPlateOutParam;
import com.zy.asrs.entity.param.FullStoreParam;
import com.zy.asrs.entity.param.LocDetlAdjustParam;
import com.zy.asrs.entity.param.StockOutParam;
import com.zy.asrs.entity.param.*;
import com.zy.asrs.service.BasDevpService;
import com.zy.asrs.service.WorkService;
import com.zy.common.model.StartupDto;
@@ -119,7 +116,17 @@
        workService.locMove(sourceLocNo, targetLocNo, getUserId());
        return R.ok("移库启动成功");
    }
    @RequestMapping("/locCombOutStartCheckSite/site")
    @ManagerAuth(memo = "并板出库站点查询")
    public R locCombOutStartCheckSite(){
        return R.ok().add(basDevpService.getAvailableOutSite(104));
    }
    @RequestMapping("/locComb/out/start")
    @ManagerAuth(memo = "并板出库")
    public R locCombOutStart(@RequestBody ReplenishmentParam param) {
        workService.locCombOut(param,getUserId());
        return R.ok("补料出库启动成功");
    }
    @RequestMapping("/locDdetl/adjust/start")
    @ManagerAuth(memo = "库存调整")
    public R locDetlAdjustStart(@RequestBody LocDetlAdjustParam param) {
src/main/java/com/zy/asrs/entity/param/ReplenishmentParam.java
New file
@@ -0,0 +1,38 @@
package com.zy.asrs.entity.param;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
 * @author pang.jiabao
 * @description 补料入库dto
 * @createDate 2024/4/19 17:06
 */
@Data
public class ReplenishmentParam {
    // 站点编号
    private Integer devpNo;
    // 库位号
    private String locNo;
    // 产品列表数据
    private List<MatCodeStore> list;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class MatCodeStore {
        // 产品编号
        private String matnr;
        // 产品名称
        private String  maktx;
        // 产品批次
        private String batch;
        // 产品数量
        private Double count;
    }
}
src/main/java/com/zy/asrs/service/WorkService.java
@@ -3,10 +3,7 @@
import com.zy.asrs.entity.BasDevp;
import com.zy.asrs.entity.WaitPakin;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.entity.param.EmptyPlateOutParam;
import com.zy.asrs.entity.param.FullStoreParam;
import com.zy.asrs.entity.param.LocDetlAdjustParam;
import com.zy.asrs.entity.param.StockOutParam;
import com.zy.asrs.entity.param.*;
import com.zy.common.model.LocDetlDto;
import com.zy.common.model.StartupDto;
import com.zy.common.model.TaskDto;
@@ -66,6 +63,11 @@
    void locMove(String sourceLocNo, String locNo, Long userId);
    /**
     * 补料出库
     */
    void locCombOut(ReplenishmentParam param, Long userId);
    /**
     * 手动完成工作档
     */
    void completeWrkMast(String workNo, Long userId);
src/main/java/com/zy/asrs/service/WrkDetlService.java
@@ -1,6 +1,7 @@
package com.zy.asrs.service;
import com.baomidou.mybatisplus.service.IService;
import com.zy.asrs.entity.MatCodeCountDto;
import com.zy.asrs.entity.WrkDetl;
import com.zy.common.model.DetlDto;
@@ -10,6 +11,7 @@
public interface WrkDetlService extends IService<WrkDetl> {
    void createWorkDetail(Integer workNo, List<DetlDto> detlDtos, String barcode, Long userId, Date now);
    void createWorkDetail2(Integer workNo, List<MatCodeCountDto> detlDtos, String barcode, Long userId);
    List<WrkDetl> selectByWrkNo(Integer wrkNo);
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
@@ -8,10 +8,7 @@
import com.core.common.SnowflakeIdWorker;
import com.core.exception.CoolException;
import com.zy.asrs.entity.*;
import com.zy.asrs.entity.param.EmptyPlateOutParam;
import com.zy.asrs.entity.param.FullStoreParam;
import com.zy.asrs.entity.param.LocDetlAdjustParam;
import com.zy.asrs.entity.param.StockOutParam;
import com.zy.asrs.entity.param.*;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.Utils;
import com.zy.common.model.*;
@@ -643,6 +640,87 @@
    @Override
    @Transactional
    public void locCombOut(ReplenishmentParam param, Long userId) {
        // 参数非空判断
        if (Cools.isEmpty(param.getDevpNo(), param.getList())) {
            throw new CoolException(BaseRes.PARAM);
        }
        //判断库位号、库位状态
        LocMast locMast;
        if (Cools.isEmpty(param.getLocNo())){
            throw new CoolException("并板出库库位参数错误");
        }else {
            locMast = locMastService.selectById(param.getLocNo());
            if(!Cools.isEmpty(locMast)){
                if (!locMast.getLocSts().equals("F")){
                    throw new CoolException("并板库位非在库状态");
                }
            }else{
                throw new CoolException("库存中库位号不存在");
            }
        }
        // 源站点状态检测
//        BasDevp sourceStaNo = basDevpService.checkSiteStatus(param.getDevpNo(), true);
        // 生成工作号
        int workNo = commonService.getWorkNo(DEFAULT_WORK_NO_TYPE);
        // 获取路径
        Wrapper<StaDesc> wrapper = new EntityWrapper<StaDesc>()
                .eq("type_no", 104)
                .eq("stn_no", param.getDevpNo())
                .eq("crn_no", locMast.getCrnNo());
        StaDesc staDesc = staDescService.selectOne(wrapper);
        if (Cools.isEmpty(staDesc)) {
            throw new CoolException("出库路径不存在");
        }
        // 生成工作档
        WrkMast wrkMast = new WrkMast();
        wrkMast.setWrkNo(workNo);
        wrkMast.setIoTime(new Date());
        wrkMast.setWrkSts(11L); // 工作状态:生成入库ID
        wrkMast.setIoType(104); // 入出库状态:1.入库
        wrkMast.setIoPri(13D); // 优先级:10
        wrkMast.setCrnNo(locMast.getCrnNo());
        wrkMast.setSourceStaNo(staDesc.getCrnStn());
        wrkMast.setStaNo(param.getDevpNo());
        wrkMast.setSourceLocNo(param.getLocNo());
        wrkMast.setBarcode(locMast.getBarcode()); // 托盘码
        wrkMast.setFullPlt("Y"); // 满板:Y
        wrkMast.setPicking("N"); // 拣料
        wrkMast.setExitMk("N"); // 退出
        wrkMast.setEmptyMk("N"); // 空板
        wrkMast.setLinkMis("N");
        wrkMast.setCtnType(locMast.getCtnType()); // 容器类型
        // 操作人员数据
        wrkMast.setAppeUser(userId);
        wrkMast.setAppeTime(new Date());
        wrkMast.setModiUser(userId);
        wrkMast.setModiTime(new Date());
        boolean res = wrkMastService.insert(wrkMast);
        if (!res) {
            throw new CoolException("保存工作档失败");
        }
        // 生成工作档明细
        List<MatCodeCountDto> matDtos = new ArrayList<>();
        param.getList().forEach(elem -> {
            matDtos.add(new MatCodeCountDto(elem.getMatnr(), elem.getBatch(), elem.getCount()));
        });
        wrkDetlService.createWorkDetail2(workNo, matDtos, locMast.getBarcode(), userId);
        // 更新库位状态
//        LocMast locMast = locMastService.selectById(dto.getLocNo());
        if (locMast.getLocSts().equals("F")){
            locMast.setLocSts("P"); // P.并板出库预约
            locMast.setModiUser(userId);
            locMast.setModiTime(new Date());
            if (!locMastService.updateById(locMast)){
                throw new CoolException("改变库位状态失败");
            }
        } else {
            throw new CoolException(locMast.getLocNo()+"目标库位已被占用");
        }
    }
    @Override
    @Transactional
    public void completeWrkMast(String workNo, Long userId) {
        WrkMast wrkMast = wrkMastService.selectById(workNo);
        if (Cools.isEmpty(wrkMast)){
src/main/java/com/zy/asrs/service/impl/WrkDetlServiceImpl.java
@@ -4,6 +4,7 @@
import com.core.common.Cools;
import com.core.exception.CoolException;
import com.zy.asrs.entity.Mat;
import com.zy.asrs.entity.MatCodeCountDto;
import com.zy.asrs.entity.WrkDetl;
import com.zy.asrs.mapper.WrkDetlMapper;
import com.zy.asrs.service.MatService;
@@ -52,6 +53,37 @@
    }
    @Override
    public void createWorkDetail2(Integer workNo, List<MatCodeCountDto> matCodeCountDtos, String barcode, Long userId) {
        if (matCodeCountDtos.isEmpty()){
            return;
        }
        for (MatCodeCountDto dto : matCodeCountDtos) {
            Mat mat = matService.selectByMatnr(dto.getMatNo());
            if (Cools.isEmpty(mat)){
                throw new CoolException(dto.getMatNo() + "商品维护失败");
            }
            // 保持工作档明细
            WrkDetl wrkDetl = new WrkDetl();
            wrkDetl.sync(mat);
            wrkDetl.setWrkNo(workNo);
            wrkDetl.setIoTime(new Date());
            wrkDetl.setAnfme(dto.getCount()); // 数量
            wrkDetl.setMemo("");
            wrkDetl.setBatch(dto.getBatch());
//            VersionUtils.setWrkDetl(wrkDetl, matCode); // 版本控制
//            wrkDetl.setBname(dto.getStr4());
            wrkDetl.setZpallet(barcode); // 托盘条码
            wrkDetl.setAppeUser(userId);
            wrkDetl.setAppeTime(new Date());
            wrkDetl.setModiUser(userId);
            wrkDetl.setModiTime(new Date());
            if (!this.insert(wrkDetl)) {
                throw new CoolException("保存工作明细失败");
            }
        }
    }
    @Override
    public List<WrkDetl> selectByWrkNo(Integer wrkNo) {
        return this.baseMapper.selectByWrkNo(wrkNo);
    }
src/main/webapp/static/js/pakStore/pakComb.js
New file
@@ -0,0 +1,250 @@
var matCodeData = []
var tableIns, tableInsLoc;
// 搜索条件-库位号
var locNo = ''
// 库存明细
var locData = []
var form = null
layui.use(['table', 'form'], function () {
    var table = layui.table
    var $ = layui.jquery
    form = layui.form;
    // 获取出库口
    function fetchSelect() {
        $.ajax({
            url: baseUrl + "/locCombOutStartCheckSite/site",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            success: function (res) {
                if (res.code === 200) {
                    var html = res.data.map((item) => {
                        return `<option value="${item}">${item}</option>`
                    })
                    $('#putSiteSelect').append(html);
                    form.render('select');
                } else if (res.code === 403) {
                    top.location.href = baseUrl + "/";
                } else {
                    layer.msg(res.msg)
                }
            }
        })
    }
    // 加载出库口信息
    fetchSelect()
    // 库位物料
    tableInsLoc = table.render({
        elem: '#locDetail'
        , headers: {token: localStorage.getItem('token')}
        , url: baseUrl + '/locDetl/pageList/auth'
        , cols: [[ //标题栏
            {field: 'locNo', title: '库位', width: 120}
            , {field: 'maktx', title: '商品名', width: 300}
            , {field: 'matnr', title: '商品号', width: 200}
            , {field: 'specs', title: '规格', width: 300}
            , {field: 'anfme', title: '数量', width: 100}
        ]]
        , page: true //是否显示分页
        , request: {
            pageName: 'curr',
            pageSize: 'limit',
        },
        where: {'locNo': locNo}
        , limits: [5]
        , limit: 5, //每页默认显示的数量
        parseData: function (res) {
            if (res.code === 201) {
                return ''
            }
            locData = res.data.records
            return {
                'code': res.code,
                'msg': res.msg,
                'count': res.data.total,
                'data': res.data.records
            }
        },
        response: {
            statusCode: 200
        },
        done: function (res, curr, count) {
            if (res.code === 403) {
                top.location.href = baseUrl + "/";
            }
        }
    })
    // 新增物料
    tableIns = table.render({
        elem: '#chooseData',
        id: 'chooseData',
        data: [],
        limit: 500,
        cellMinWidth: 50,
        cols: [[
            {
                fixed: 'left',
                align: 'center',
                field: 'count',
                title: '数量',
                style: 'color: blue',
                width: 100,
                edit: 'text',
                width: 120,
                style: 'color: blue;font-weight: bold'
            },
            {field: 'matnr', align: 'center', title: '商品编号'},
            {field: 'maktx', align: 'center', title: '商品名称'},
            {field: 'specs', align: 'center', title: '规格'},
            {fixed: 'right', title: '操作', align: 'center', toolbar: '#operate', width: 200}
        ]]
    });
    // 监听table的移除事件
    table.on('tool(chooseData)', function (obj) {
        var data = obj.data;
        switch (obj.event) {
            case 'remove':
                const findIndex = matCodeData.findIndex(item => item.id === data.id)
                matCodeData.splice(findIndex, 1)
                tableIns.reload({data: matCodeData, limit: matCodeData.length});
                break;
        }
    });
    table.on('edit(chooseData)', function (obj) {
        matCodeData = matCodeData.map(item => {
            if (item.id === obj.data.id) {
                return {
                    ...item,
                    count: obj.value
                }
            }
            return item
        })
    });
    // 搜索按钮
    $("#searchFor").click(function () {
        table.reload('locDetail', {
            where: {'locNo': locNo},
            page: { // 分页参数
                curr: 1 // 重新从第一页开始
            },
            // 其他参数
        })
    })
})
// 获取输入框值
$("#locNo").on("input", function (e) {
    //获取input输入的值
    locNo = e.delegateTarget.value;
});
// 补料出库
$("#outbound").click(function () {
    if (locNo === "" || locNo.length != 7) {
        layer.msg("库位号错误");
        return;
    }
    //判断库位数据
    if (locData == null || locData.length === 0) {
        layer.msg("并板库位没有库存数据");
        return;
    }
    // 判断是否存在产品
    if (matCodeData.length === 0) {
        layer.msg("请先添加产品");
        return;
    }
    // 判断产品数量是否存在异常
    for (var i = 0; i < matCodeData.length; i++) {
        if (isNaN(matCodeData[i].count)) {
            layer.msg("请输入数字");
            return;
        }
        if (matCodeData[i].count === 0) {
            layer.msg("数量不能为零");
            return;
        }
    }
    // 判断出站口
    var outNo = $('#putSiteSelect').val()
    if (outNo.length === 0) {
        layer.msg("请选择出库口");
        return;
    }
    $.ajax({
        url: baseUrl + "/locComb/out/start",
        headers: {'token': localStorage.getItem('token')},
        data: JSON.stringify({
            locNo: locNo,
            devpNo: Number(outNo),
            list: matCodeData
        }),
        contentType: 'application/json;charset=UTF-8',
        method: 'POST',
        async: false,
        success: function (res) {
            if (res.code === 200) {
                layer.msg(res.msg);
                // 清空出库口选择
                $("#putSiteSelect").val('');
                form.render();
                // 清空输入的库位
                $("#locNo").val("");
                locNo = ''
                // 清空增加的明细数据
                matCodeData = [];
                tableIns.reload({data: []});
                // 清空库位明细数据
                tableInsLoc.reload({data: [], where: {'locNo': ''}});
                locData = []
            } else if (res.code === 403) {
                top.location.href = baseUrl + "/";
            } else {
                layer.msg(res.msg)
            }
        }
    })
})
// 提取物料
var matCodeLayerIdx;
// 打开商品弹窗
function getMat() {
    matCodeLayerIdx = layer.open({
        type: 2,
        title: '物料',
        shade: [0.3, '#000'],
        area: ['90%', '80%'],
        content: 'matQuery.html',
        success: function (layero, index) {
            $('.layui-layer-title').css('font-size', '16px');
        },
        end: function () {
            $('#addmatnr').focus();
        }
    });
}
// 添加表格数据
var matData = [];
// 获取弹窗返回的值
function addTableData(data) {
    for (var i = 0; i < data.length; i++) {
        data[i]["count"] = 0
    }
    matCodeData = data
    // 对于options的各项参数有点迷惑,但是试了好多方法,发现加一条limit属性,取数据源长度即可
    tableIns.reload({data: matCodeData, limit: matCodeData.length});
    layer.close(matCodeLayerIdx);
}
src/main/webapp/views/pakStore/pakComb.html
New file
@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title></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, maximum-scale=1">
    <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all">
    <link rel="stylesheet" href="../../static/css/cool.css" media="all">
    <link rel="stylesheet" href="../../static/css/common.css" media="all">
    <style>
    </style>
</head>
<body>
<div style="padding: 15px">
    <div class="layui-row">
        <div class="layui-col-md1">
            <input type="text" id="locNo" placeholder="库位号" class="layui-input">
        </div>
        <div class="layui-col-md1">
            <button class="layui-btn layui-btn-normal" id="searchFor" style="margin-left: 25px">搜索</button>
        </div>
    </div>
    <div class="layui-row">
        <table class="layui-hide" id="locDetail" lay-filter="locDetail"></table>
    </div>
    <div class="layui-form layui-row layui-col-space16">
        <div class="layui-col-md2">
            <select id="putSiteSelect">
                <option value="">请选择补料出库站点</option>
            </select>
        </div>
        <div class="layui-col-md1">
            <button class="layui-btn layui-btn-normal" id="outbound">补料出库</button>
        </div>
        <div class="layui-col-md1">
            <button class="layui-btn layui-btn-primary layui-border" id="addmatnr" onclick="getMat()">新增物料</button>
        </div>
    </div>
    <div class="layui-row">
        <script type="text/html" id="operate">
            <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="remove">移除</a>
        </script>
        <table class="layui-table" id="chooseData" lay-filter="chooseData"></table>
    </div>
</div>
<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>
<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
<script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script>
<script type="text/javascript" src="../../static/js/handlebars/handlebars-v4.5.3.js"></script>
<script type="text/javascript" src="../../static/js/pakStore/pakComb.js" charset="utf-8"></script>
</body>
</html>