自动化立体仓库 - WMS系统
zwl
2025-10-22 4ef4e287fe6597543a9628b6dae294c19f2b1d9c
1.新增订单出库挑选功能
2.新增订单明细表
2个文件已添加
8个文件已修改
1027 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/OutController.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/OrderDetl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/OutlocDetlParam.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/third/ExdMaterialMapper.xml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/order/outAll.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/orderDetl/orderDetl.js 172 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/order/outAll.html 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/order/outLocDetlQuery.html 625 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/orderDetl/orderDetl.html 109 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OutController.java
@@ -6,6 +6,7 @@
import com.core.common.R;
import com.zy.asrs.entity.LocDetl;
import com.zy.asrs.entity.OrderDetl;
import com.zy.asrs.entity.param.OutlocDetlParam;
import com.zy.asrs.service.*;
import com.zy.common.model.LocDto;
import com.zy.common.model.TaskDto;
@@ -204,4 +205,44 @@
        return R.ok();
    }
    @PostMapping("/out/pakout/preview/auth1")
    @ManagerAuth
    public R pakoutPreview1(@RequestBody OutlocDetlParam map) {
        if (Cools.isEmpty(map)) {
            return R.parse(BaseRes.PARAM);
        }
        OrderDetl orderDetl = orderDetlService.selectById(map.getId());
        if (Cools.isEmpty(orderDetl)) {
            return R.error("没有找到该订单");
        }
        List<LocDto> locDtos = new ArrayList<>();
        Set<String> exist = new HashSet<>();
        double issued = Optional.of(orderDetl.getAnfme() - orderDetl.getWorkQty()).orElse(0.0D);
        for (LocDetl locDetl : map.getList()) {
            if (issued > 0) {
                LocDto locDto = new LocDto(locDetl.getLocNo(), locDetl.getMatnr(), locDetl.getMaktx(), locDetl.getBatch(), orderDetl.getOrderNo(),
                        locDetl.getAnfme());
                List<String> staNos =  new ArrayList<>();
                staNos.add("C1");
                staNos.add("C2");
                staNos.add("C3");
                locDto.setStaNos(staNos);
                locDtos.add(locDto);
                exist.add(locDetl.getLocNo());
                // 剩余待出数量递减
                issued = issued - locDetl.getAnfme();
            } else {
                break;
            }
        }
        if (issued > 0) {
            LocDto locDto = new LocDto(null, orderDetl.getMatnr(), orderDetl.getMaktx(), orderDetl.getBatch(), orderDetl.getOrderNo(), issued);
            locDto.setLack(Boolean.TRUE);
            locDtos.add(locDto);
        }
        return R.ok().add(locDtos);
    }
}
src/main/java/com/zy/asrs/entity/OrderDetl.java
@@ -17,6 +17,7 @@
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
@Data
@TableName("man_order_detl")
@@ -348,6 +349,19 @@
        return null;
    }
    public String getAnfme$(){
        if(Objects.equals(this.qty, this.anfme)){
            return "已完成";
        }else if(this.workQty==0){
            return "待处理";
        }else if(this.anfme>this.qty){
            return "作业中";
        }else if(this.anfme<this.qty){
            return "异常";
        }
        return "";
    }
    public String getBeBatch$(){
        if (null == this.beBatch){ return null; }
        switch (this.beBatch){
src/main/java/com/zy/asrs/entity/param/OutlocDetlParam.java
New file
@@ -0,0 +1,12 @@
package com.zy.asrs.entity.param;
import com.zy.asrs.entity.LocDetl;
import lombok.Data;
import java.util.List;
@Data
public class OutlocDetlParam {
    long id;
    List<LocDetl> list;
}
src/main/resources/application.yml
@@ -33,12 +33,12 @@
    #    password: root
    #driver-class-name: com.mysql.cj.jdbc.Driver
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    jdbc-url: jdbc:sqlserver://192.168.3.148:1433;databasename=wms_middle
    username: wms
    password: wms@aunde
#    jdbc-url: jdbc:sqlserver://127.0.0.1:1433;databasename=wms_middle
#    username: sa
#    password: sa@123
#    jdbc-url: jdbc:sqlserver://192.168.3.148:1433;databasename=wms_middle
#    username: wms
#    password: wms@aunde
    jdbc-url: jdbc:sqlserver://127.0.0.1:1433;databasename=ycawdasrs
    username: sa
    password: sa@123
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml 
src/main/resources/mapper/third/ExdMaterialMapper.xml
@@ -30,12 +30,12 @@
    </select>
    <select id="getBacode" resultType="com.zy.third.entity.ExdvYanbu" parameterType="string">
            SELECT top 1 *
      FROM [Textile].[trade].[TianfuQcResult]
      where Barcode = #{barcode}
        <!--    SELECT top 1 *
--             SELECT top 1 *
--       FROM [Textile].[trade].[TianfuQcResult]
--       where Barcode = #{barcode}
           SELECT top 1 *
         FROM TianfuQcResult
         where Barcode = #{barcode}-->
         where Barcode = #{barcode}
       </select>
src/main/webapp/static/js/order/outAll.js
@@ -1,5 +1,8 @@
var pageCurr;
var insTb2;
var matnR;
var id;
var anfme;
layui.config({
    base: baseUrl + "/static/layui/lay/modules/"
}).extend({
@@ -54,7 +57,7 @@
            // ,{field: 'updateBy$', align: 'center',title: '修改人员'}
            // ,{field: 'updateTime$', align: 'center',title: '修改时间'}
            // ,{field: 'memo', align: 'center',title: '备注'}
            ,{fixed: 'right', title:'操作', align: 'center', toolbar: '#operate', width: 160}
            ,{fixed: 'right', title:'操作', align: 'center', toolbar: '#operate', width: 200}
        ]],
        request: {
            pageName: 'curr',
@@ -120,12 +123,34 @@
            case 'pakoutPreview':
                pakoutPreview([data.id])
                break;
            case 'outLocDetlQuery' :
                outLocDetlQuery([data.matnr],[data.id],[data.enableQty])
                break;
        }
    });
    // 提取库存
    function outLocDetlQuery(matnr,id,enableQty) {
        let loadIndex = layer.msg('请求中...', {icon: 16, shade: 0.01, time: false});
        matnR=matnr;
        ID=id;
        anfme=enableQty;
        locDetlLayerIdx = layer.open({
            type: 2,
            title: false,
            closeBtn: false,
            maxmin: false,
            area: ['90%', '85%'],
            shadeClose: true,
            content: 'outLocDetlQuery.html',
            success: function(layero, index){
                layer.close(loadIndex);
            }
        });
    }
    function pakoutPreview(ids) {
        let loadIndex = layer.load(2);
        console.log("1111")
        $.ajax({
            url: baseUrl + "/out/pakout2/preview/auth",
            headers: {'token': localStorage.getItem('token')},
src/main/webapp/static/js/orderDetl/orderDetl.js
@@ -9,6 +9,27 @@
    var form = layui.form;
    var admin = layui.admin;
    // 渲染搜索模板
    $.ajax({
        url: baseUrl+"/docType/list/auth",
        headers: {'token': localStorage.getItem('token')},
        data: {
            limit: 9999
        },
        method: 'POST',
        success: function (res) {
            if (res.code === 200){
                let template = Handlebars.compile($('#docTypeTpl').html());
                $('#docType-query').html(template(res.data));
                layui.form.render('select');
            } else if (res.code === 403){
                top.location.href = baseUrl+"/";
            } else {
                layer.msg(res.msg, {icon: 2})
            }
        }
    })
    // 数据渲染
    tableIns = table.render({
        elem: '#orderDetl',
@@ -22,29 +43,33 @@
        height: 'full-120',
        cols: [[
            {type: 'checkbox'}
            ,{field: 'id', align: 'center',title: 'ID'}
            ,{field: 'orderId$', align: 'center',title: '订单内码'}
            ,{field: 'anfme', align: 'center',title: '数量'}
            ,{field: 'matnr', align: 'center',title: '商品编码'}
            ,{field: 'maktx', align: 'center',title: '商品名称'}
            ,{field: 'name', align: 'center',title: '名称'}
            ,{field: 'specs', align: 'center',title: '规格'}
            ,{field: 'model', align: 'center',title: '型号'}
            ,{field: 'batch', align: 'center',title: '批号'}
            ,{field: 'unit', align: 'center',title: '单位'}
            ,{field: 'barcode', align: 'center',title: '商品条码'}
            ,{field: 'supplier', align: 'center',title: '供应商'}
            ,{field: 'unitPrice', align: 'center',title: '单价'}
            ,{field: 'itemNum', align: 'center',title: '品项数'}
            ,{field: 'count', align: 'center',title: '数量'}
            ,{field: 'weight', align: 'center',title: '重量'}
            ,{field: 'status$', align: 'center',title: '状态'}
            ,{field: 'createBy$', align: 'center',title: '添加人员'}
            ,{field: 'createTime$', align: 'center',title: '添加时间'}
            ,{field: 'updateBy$', align: 'center',title: '修改人员'}
            ,{field: 'updateTime$', align: 'center',title: '修改时间'}
            ,{field: 'memo', align: 'center',title: '备注'}
            // ,{field: 'id', align: 'center',title: 'ID'}
            ,{field: 'orderNo', align: 'center',title: '订单编码',sort:true}
            ,{field: 'matnr', align: 'center',title: '商品编码',sort:true}
            ,{field: 'maktx', align: 'center',title: '商品名称',sort:true}
            ,{field: 'anfme', align: 'center',title: '数量',sort:true}
            ,{field: 'workQty', align: 'center',title: '工作数量',sort:true}
            ,{field: 'qty', align: 'center',title: '完成数量',sort:true}
            // ,{field: 'model', align: 'center',title: '型号'}
            ,{field: 'batch', align: 'center',title: '批号',sort:true, hide: true}
            ,{field: 'brand', align: 'center',title: '产线',sort:true, hide: true}
            ,{field: 'sku', align: 'center',title: '等级',sort:true, hide: true}
            ,{field: 'unit', align: 'center',title: '单位', hide: true}
            ,{field: 'danger$', align: 'center',title: '订单类型', hide: true}
            ,{field: 'anfme$', align: 'center', title: '状态', templet: '#settleTpl',  minWidth: 160, width: 160},
            // ,{field: 'unitPrice', align: 'center',title: '单价'}
            // ,{field: 'itemNum', align: 'center',title: '品项数'}
            // ,{field: 'count', align: 'center',title: '数量'}
            // ,{field: 'weight', align: 'center',title: '重量'}
            // ,{field: 'status$', align: 'center',title: '状态'}
            // ,{field: 'createBy$', align: 'center',title: '添加人员'}
            {field: 'createTime$', align: 'center',title: '添加时间'}
            ,{field: 'inspect$', align: 'center',title: '上报次数', width: 100}
            // ,{field: 'updateBy$', align: 'center',title: '修改人员'}
            // ,{field: 'updateTime$', align: 'center',title: '修改时间'}
            // ,{field: 'memo', align: 'center',title: '备注'}
            ,{fixed: 'right', title:'操作', align: 'center', toolbar: '#operate', width:120}
        ]],
        request: {
@@ -93,14 +118,14 @@
                showEditModel();
                break;
            case 'deleteData':
               if (checkStatus.length === 0) {
                   layer.msg('请选择要删除的数据', {icon: 2});
                   return;
               }
               del(checkStatus.map(function (d) {
                   return d.id;
               }));
               break;
                if (checkStatus.length === 0) {
                    layer.msg('请选择要删除的数据', {icon: 2});
                    return;
                }
                del(checkStatus.map(function (d) {
                    return d.id;
                }));
                break;
            case 'exportData':
                admin.confirm('确定导出Excel吗', {shadeClose: true}, function(){
                    var titles=[];
@@ -193,6 +218,61 @@
        });
    }
    // 时间选择器
    layDate.render({
        elem: '#ymd\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#wrkDate\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#ioTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#crnStrTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#crnEndTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#plcStrTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#crnPosTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#refIotime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#modiTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#appeTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#errorTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '#logErrTime\\$',
        type: 'datetime'
    });
    layDate.render({
        elem: '.layui-laydate-range'
        ,type: 'datetime'
        ,range: true
    });
    /* 删除 */
    function del(ids) {
        layer.confirm('确定要删除选中数据吗?', {
@@ -233,6 +313,30 @@
        clearFormVal($('#search-box'));
        tableReload(false);
    });
    // 异常
    form.on('submit(abnormal)', function (data) {
        pageCurr = 1;
        tableReload(true);
        // console.log("abnormal");
        // $.ajax({
        //     url: baseUrl+"/orderDetl/abnormal",
        //     headers: {'token': localStorage.getItem('token')},
        //     method: 'GET',
        //     success: function (res) {
        //         layer.close(loadIndex);
        //         if (res.code === 200){
        //             layer.msg(res.msg, {icon: 1});
        //             tableReload();
        //         } else if (res.code === 403){
        //             top.location.href = baseUrl+"/";
        //         } else {
        //             layer.msg(res.msg, {icon: 2});
        //         }
        //     }
        // })
    });
    // 时间选择器
    function layDateRender(data) {
@@ -264,8 +368,14 @@
    $.each($('#search-box [name]').serializeArray(), function() {
        searchData[this.name] = this.value;
    });
    if(child){
        searchData["abnormal"] = 1;
    }else {
        searchData["abnormal"] = 0;
    }
    tableIns.reload({
        where: searchData,
        page: {curr: pageCurr}
     });
    });
}
src/main/webapp/views/order/outAll.html
@@ -152,8 +152,9 @@
<!-- 行工具栏 -->
<script type="text/html" id="operate">
    {{#if (d.anfme > d.qty){ }}
    {{#if (d.anfme > d.workQty){ }}
    <a class="layui-btn layui-btn-xs layui-btn-danger btn-pakoutPreview" lay-event="pakoutPreview"><i class="layui-icon layui-icon-prev-circle"></i>出库</a>
    <a class="layui-btn layui-btn-xs layui-btn-danger btn-pakoutPreview" lay-event="outLocDetlQuery"><i class="layui-icon layui-icon-prev-circle"></i>提取库存</a>
    {{# } }}
</script>
src/main/webapp/views/order/outLocDetlQuery.html
New file
@@ -0,0 +1,625 @@
<!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/admin.css?v=318" media="all">
    <link rel="stylesheet" href="../../static/css/cool.css" media="all">
    <link rel="stylesheet" href="../../static/css/common.css" media="all">
    <style>
        body {
        }
        .layui-table-box {
            border-right: 1px solid #9F9F9F;
            border-left: 1px solid #9F9F9F;
        }
        #search-box {
            padding: 30px 0 20px 0;
        }
        #search-box .layui-inline:first-child {
            margin-left: 30px;
        }
        #search-box .layui-inline {
            margin-right: 5px;
        }
        #data-search-btn {
            margin-left: 10px;
            display: inline-block;
        }
        #data-search-btn.layui-btn-container .layui-btn {
            margin-right: 20px;
        }
        .fixed-header {
            position: sticky;
            top: 0;
            z-index: 999;
            padding: 25px;
            line-height: 22px;
            background-color: #393D49;
            color: #fff;
            font-weight: 300;
        }
        .total-count {
            display: inline-block;
            margin-left: 20px;
            padding: 5px 15px;
            background: #1E9FFF;
            border-radius: 4px;
            font-weight: bold;
            color: #fff;
        }
        /* 为订单数量单独设置样式 */
        #orderTotal {
            color: #5FB878; /* 绿色表示订单数量 */
            font-weight: bold;
        }
        /* 已选数量正常样式 */
        #selectedTotal {
            color: #fff;
            font-weight: bold;
        }
        /* 已选数量超过订单数量时的警告样式 */
        .over-limit #selectedTotal {
            color: #FF5722 !important; /* 红色警告 */
        }
    </style>
</head>
<body>
<div class="fixed-header">
    <span style="font-size: large; font-weight: bold">提取库存商品</span>
    <!-- 修改:订单数量使用相同样式 -->
    <span class="total-count">订单数量: <span id="orderTotal">0</span></span>
    <span class="total-count">已选数量: <span id="selectedTotal">0</span></span>
</div>
<!-- 搜索栏 -->
<fieldset class="layui-elem-field site-demo-button" style="margin: 20px;">
    <legend>搜索栏</legend>
    <!-- 搜索栏 -->
    <div id="search-box" class="layui-form layui-card-header">
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" id="matnr" type="text" name="matnr" placeholder="商品编号"
                       autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline cool-auto-complete">
                <input id="crnNo" class="layui-input" name="crnNo" type="text" placeholder="请输入" autocomplete="off"
                       style="display: none">
                <input id="crnNo$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text"
                       placeholder="堆垛机号" onfocus=this.blur()>
                <div class="cool-auto-complete-window">
                    <input class="cool-auto-complete-window-input" data-key="basCrnpQueryBycrnNo"
                           onkeyup="autoLoad(this.getAttribute('data-key'))">
                    <select class="cool-auto-complete-window-select" data-key="basCrnpQueryBycrnNoSelect"
                            onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                    </select>
                </div>
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="loc_no" placeholder="库位号" autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="orderNo" placeholder="订单编号" autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="batch" placeholder="批号" autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="brand" placeholder="生产线" autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="sku" placeholder="等级" autocomplete="off">
            </div>
        </div>
        <!-- 日期范围 -->
        <div class="layui-inline" style="width: 300px">
            <div class="layui-input-inline">
                <input class="layui-input layui-laydate-range" name="appe_time" type="text"
                       placeholder="起始时间 - 终止时间" autocomplete="off" style="width: 300px">
            </div>
        </div>
        <!-- 待添加 -->
        <div id="data-search-btn" class="layui-btn-container layui-form-item" style="display: inline-block">
            <button id="search" class="layui-btn layui-btn-primary layui-btn-radius" lay-submit lay-filter="search">
                搜索
            </button>
        </div>
    </div>
</fieldset>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn" id="btn-confirm" lay-event="confirm" style="">提取</button>
    </div>
</script>
<div class="layui-form">
    <table class="layui-hide" id="stockOut" lay-filter="stockOut"></table>
</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>
</body>
<script type="text/html" id="pakoutPreviewBox" style="display: none">
    <div style="padding: 25px; line-height: 22px; background-color: #393D49; color: #fff; font-weight: 300;">
        <span style="font-size: large; font-weight: bold">出库预览</span>
    </div>
    <div class="layui-card">
        <div class="layui-card-body" style="padding: 10px">
            <table id="stoPreTab1" lay-filter="stoPreTab1"></table>
        </div>
        <button class="layui-btn layui-btn-primary layui-border-black layui-btn-sm" lay-filter="batchModifySta"
                lay-submit style="display: block;float: right;margin-right: 1rem">
            批量修改
        </button>
    </div>
</script>
<script type="text/html" id="tbBasicTbStaNos">
    <div class="ew-select-fixed">
        <select class="order-sta-select" lay-filter="tbBasicTbStaNos">
            {{#if (d.staNos!=null) {}}
            {{# for(let i=0; i
            <d.staNos.length
                    ; i++) { }}
            <option value="{{d.staNos[i]}}">{{d.staNos[i]}}</option>
            {{# } }}
            {{# } }}
        </select>
    </div>
</script>
<script>
    function getCol() {
        var cols = [
            {type: 'checkbox', merge: ['locNo']}
            , {field: 'locNo', align: 'center', title: '库位号', merge: true, style: 'font-weight: bold'}
            // ,{field: 'locNo$', align: 'center',title: '库位号'}
        ];
        cols.push.apply(cols, detlCols);
        cols.push({field: 'appeUser$', align: 'center', title: '创建人员', hide: true}
            , {field: 'appeTime$', align: 'center', title: '创建时间'})
        return cols;
    }
    layui.config({
        base: baseUrl + "/static/layui/lay/modules/"
    }).extend({
        notice: 'notice/notice',
    })
        .use(['table', 'notice', 'laydate', 'form', 'admin', 'tableMerge'], function () {
            var table = layui.table;
            var $ = layui.jquery;
            var layer = layui.layer;
            var layDate = layui.laydate;
            var form = layui.form;
            var admin = layui.admin;
            var tableMerge = layui.tableMerge;
            var notice = layui.notice;
            $('#matnr').val(parent.matnR);
            $('#anfme').val(parent.anfme);
            var id = parent.ID[0];
            // 存储当前选中的数量和订单总数
            var selectedTotal = 0;
            var orderTotal = parseFloat(parent.anfme) || 0;
            // 更新显示选中的数量
            function updateSelectedTotal() {
                $('#selectedTotal').text(selectedTotal);
                $('#orderTotal').text(orderTotal); // 更新订单数量显示
                // 如果选中的数量超过订单数量,显示警告样式
                if (selectedTotal > orderTotal) {
                    $('#selectedTotal').parent().addClass('over-limit');
                } else {
                    $('#selectedTotal').parent().removeClass('over-limit');
                }
                // 如果订单数量为0,显示完成状态
                if (orderTotal <= 0) {
                    $('#orderTotal').parent().addClass('order-completed');
                    layer.msg('订单已完成!', {icon: 1, time: 3000});
                } else {
                    $('#orderTotal').parent().removeClass('order-completed');
                }
            }
            // 数据渲染
            locDetlTableIns = table.render({
                elem: '#stockOut',
                headers: {token: localStorage.getItem('token')},
                url: baseUrl + '/stock/out/list/auth',
                where: {matnr: parent.matnR[0]},
                page: true,
                limits: [16, 30, 50, 100, 200, 500],
                limit: 16,
                even: true,
                toolbar: '#toolbar',
                cellMinWidth: 50,
                cols: [getCol()],
                request: {
                    pageName: 'curr',
                    pageSize: 'limit'
                },
                parseData: function (res) {
                    return {
                        'code': res.code,
                        'msg': res.msg,
                        'count': res.data.total,
                        'data': res.data.records
                    }
                },
                response: {
                    statusCode: 200
                },
                done: function (res, curr, count) {
                    tableMerge.render(this);
                    if (res.code === 403) {
                        top.location.href = baseUrl + "/";
                    }
                    // 初始化选中数量
                    selectedTotal = 0;
                    updateSelectedTotal();
                }
            });
            // 监听复选框选择事件
            table.on('checkbox(stockOut)', function(obj){
                var data = obj.data;
                var checked = obj.checked;
                var type = obj.type;
                if (type === 'one') {
                    // 单个选择
                    if (checked) {
                        selectedTotal += parseFloat(data.anfme || 0);
                    } else {
                        selectedTotal -= parseFloat(data.anfme || 0);
                    }
                } else if (type === 'all') {
                    // 全选
                    var checkStatus = table.checkStatus('stockOut');
                    if (checked) {
                        // 计算当前页所有数据的数量总和
                        checkStatus.data.forEach(function(item){
                            selectedTotal += parseFloat(item.anfme || 0);
                        });
                    } else {
                        // 取消全选,减去当前页所有数据的数量总和
                        checkStatus.data.forEach(function(item){
                            selectedTotal -= parseFloat(item.anfme || 0);
                        });
                    }
                }
                updateSelectedTotal();
                // 如果选中的数量超过订单数量,给出提示
                if (selectedTotal > orderTotal) {
                    layer.msg('警告:选中的数量已超过订单数量!', {icon: 2, time: 3000});
                }
            });
            // 监听头工具栏事件
            table.on('toolbar(stockOut)', function (obj) {
                var checkStatus = table.checkStatus(obj.config.id);
                var data = checkStatus.data;
                switch (obj.event) {
                    case 'confirm':
                        if (data.length === 0) {
                            layer.msg("请选择数据");
                            return;
                        }
                        // 检查选中的数量是否超过订单数量
                        if (selectedTotal > orderTotal) {
                            layer.confirm('选中的数量已超过订单数量,是否继续?', {
                                icon: 3,
                                title: '警告'
                            }, function(index){
                                layer.close(index);
                                pakoutPreview(id, data);
                            });
                        } else {
                            pakoutPreview(id, data);
                        }
                        break;
                }
            });
            // 搜索栏搜索事件
            form.on('submit(search)', function (data) {
                tableReload();
            });
            layDate.render({
                elem: '.layui-laydate-range'
                , type: 'datetime'
                , range: true
            });
            function tableReload() {
                var searchData = {};
                $.each($('#search-box [name]').serializeArray(), function () {
                    searchData[this.name] = this.value;
                });
                locDetlTableIns.reload({
                    where: searchData,
                });
                // 重置选中数量
                selectedTotal = 0;
                updateSelectedTotal();
            }
            function pakoutPreview(id, data) {
                console.log("id=" + id)
                let loadIndex = layer.load(2);
                var da = {
                    "id": JSON.stringify(id),
                    "list": data
                }
                $.ajax({
                    url: baseUrl + "/out/pakout/preview/auth1",
                    headers: {'token': localStorage.getItem('token')},
                    contentType: 'application/json;charset=UTF-8',
                    data: JSON.stringify(da),
                    method: 'POST',
                    success: function (res) {
                        layer.close(loadIndex);
                        var tableCache;
                        if (res.code === 200) {
                            layer.open({
                                type: 1
                                , title: false
                                , closeBtn: false
                                , offset: '50px'
                                , area: ['1200px', '700px']
                                , shade: 0.5
                                , shadeClose: false
                                , btn: ['立即出库', '稍后处理']
                                , btnAlign: 'c'
                                , moveType: 1 //拖拽模式,0或者1
                                , content: $('#pakoutPreviewBox').html()
                                , success: function (layero, index) {
                                    res.data.forEach((item, index) => {
                                        console.log(`项 ${index + 1}:`, item);
                                    });
                                    stoPreTabIdx = table.render({
                                        elem: '#stoPreTab1',
                                        data: res.data,
                                        height: 520,
                                        page: false,
                                        limit: Number.MAX_VALUE,
                                        cellMinWidth: 100,
                                        cols: [[
                                            // {type: 'checkbox', merge: ['orderNo']},
                                            {field: 'orderNo', title: '单据编号', merge: true, align: 'center'},
                                            {field: 'title', title: '商品', merge: true, align: 'center', width: 350},
                                            {field: 'batch', title: '批号', align: 'center'},
                                            {
                                                field: 'anfme',
                                                title: '数量',
                                                align: 'center',
                                                width: 90,
                                                style: 'font-weight: bold'
                                            },
                                            {
                                                field: 'locNo',
                                                title: '货位',
                                                align: 'center',
                                                width: 100,
                                                templet: '#locNoTpl'
                                            },
                                            {
                                                field: 'staNos',
                                                align: 'center',
                                                title: '出库站',
                                                merge: ['locNo'],
                                                templet: '#tbBasicTbStaNos'
                                            },
                                            {type: 'checkbox', merge: ['locNo']},
                                        ]],
                                        done: function (res) {
                                            tableMerge.render(this);
                                            $('.layui-table-body.layui-table-main').css("overflow", "auto");
                                            tableCache = tableData = table.cache.stoPreTab1;
                                        }
                                    });
                                    // 修改出库站
                                    form.on('select(tbBasicTbStaNos)', function (obj) {
                                        let index = obj.othis.parents('tr').attr("data-index");
                                        let data = tableCache[index];
                                        for (let i = 0; i < tableCache.length; i++) {
                                            if (tableCache[i].locNo === data.locNo) {
                                                tableCache[i]['staNo'] = Number(obj.elem.value);
                                            }
                                        }
                                        obj.othis.children().find("input").css("color", "blue");
                                        return false;
                                    });
                                    // 批量修改出库站
                                    form.on('submit(batchModifySta)', function () {
                                        let stoPreTabData = layui.table.checkStatus('stoPreTab1').data;
                                        if (stoPreTabData.length < 1) {
                                            layer.msg("请至少选择一条以上合并数据", {icon: 7});
                                            return false;
                                        }
                                        modifySta(stoPreTabData);
                                    });
                                    // 批量修改出库站 - 站点选择
                                    function modifySta(stoPreTabData) {
                                        // 出库站取交集
                                        let staBatchSelectVal = [];
                                        for (let i = 0; i < stoPreTabData.length; i++) {
                                            let staNos = stoPreTabData[i].staNos;
                                            if (staNos !== null) {
                                                if (staBatchSelectVal.length === 0) {
                                                    staBatchSelectVal = staNos;
                                                } else {
                                                    staBatchSelectVal = staBatchSelectVal.filter(val => {
                                                            return new Set(staNos).has(val)
                                                        }
                                                    )
                                                }
                                            }
                                        }
                                        if (staBatchSelectVal.length === 0) {
                                            layer.msg("出库站没有交集,无法批量修改", {icon: 2});
                                            return;
                                        }
                                        admin.open({
                                            type: 1,
                                            area: '300px',
                                            offset: 'auto',
                                            title: '请选择站点',
                                            content: $('#staBatchSelectDialog').html(),
                                            success: function (layero, ddIndex) {
                                                // 渲染下拉框
                                                let template = Handlebars.compile($('#batchStaSelectTpl').html());
                                                $('#batchSelectStaBox').html(template({list: staBatchSelectVal}));
                                                // 确认
                                                form.on('submit(staBatchSelectConfirm)', function (obj) {
                                                    let loadIdx = layer.load(2);
                                                    let batchSta = Number(obj.field.batchSta);
                                                    let arr = [];
                                                    for (let j = 0; j < stoPreTabData.length; j++) {
                                                        for (let i = 0; i < tableCache.length; i++) {
                                                            if (tableCache[i].orderNo === stoPreTabData[j].orderNo
                                                                && tableCache[i].matnr === stoPreTabData[j].matnr
                                                                && tableCache[i].locNo === stoPreTabData[j].locNo) {
                                                                tableCache[i]['staNo'] = batchSta;
                                                                arr.push(i);
                                                            }
                                                        }
                                                    }
                                                    stoPreTabIdx.reload({data: tableCache});
                                                    arr.forEach(item => {
                                                        $('div[lay-id=stoPreTab1] tr[data-index="' + item + '"] .order-sta-select').val(batchSta);
                                                    });
                                                    layui.form.render('select');
                                                    arr.forEach(item => {
                                                        $('div[lay-id=stoPreTab1] tr[data-index="' + item + '"] .layui-select-title').find("input").css("color", "blue");
                                                    });
                                                    layer.close(loadIdx);
                                                    layer.close(ddIndex);
                                                    return false;
                                                });
                                                // 弹窗不出现滚动条
                                                $(layero).children('.layui-layer-content').css('overflow', 'visible');
                                                layui.form.render('select');
                                            },
                                        })
                                    }
                                }
                                , yes: function (index, layero) {
                                    //按钮【立即出库】的回调
                                    pakout(tableCache, index);
                                }
                                , btn2: function (index, layero) {
                                    //按钮【稍后处理】的回调
                                    layer.close(index)
                                    //return false 开启该代码可禁止点击该按钮关闭
                                }
                            });
                        } else if (res.code === 403) {
                            top.location.href = baseUrl + "/";
                        } else {
                            layer.msg(res.msg, {icon: 2})
                        }
                    }
                })
            }
            function pakout(tableCache, layerIndex) {
                // let loadIndex = layer.load(2);
                notice.msg('正在生成出库任务......', {icon: 4});
                $.ajax({
                    url: baseUrl + "/out/pakout/auth",
                    headers: {'token': localStorage.getItem('token')},
                    contentType: 'application/json;charset=UTF-8',
                    data: JSON.stringify(tableCache),
                    method: 'POST',
                    success: function (res) {
                        notice.destroy();
                        if (res.code === 200) {
                            layer.close(layerIndex);
                            console.log("orderTotal="+orderTotal);
                            // 扣减订单数量
                            orderTotal = Math.max(0, orderTotal - selectedTotal);
                            console.log("selectedTotal="+selectedTotal);
                            console.log("orderTotal-selectedTotal="+orderTotal);
                            layer.msg('出库成功!扣减 ' + selectedTotal + ' 数量', {icon: 1, time: 1000}, function(){
                                // 刷新当前页面表格
                                locDetlTableIns.reload({
                                    where: {matnr: parent.matnR[0]},
                                    page: {curr: 1}
                                });
                                // 更新显示
                                updateSelectedTotal();
                                // 如果有父页面表格也需要刷新
                                try {
                                    if (parent.insTb) {
                                        parent.insTb.close();
                                    }
                                    if (parent.insTb2) {
                                        parent.insTb2.reload({page: {curr: 1}});
                                    }
                                    // 更新父页面的订单数量(如果需要)
                                    if (parent.updateOrderTotal) {
                                        parent.updateOrderTotal(orderTotal);
                                    }
                                } catch (e) {
                                    console.log('父页面表格刷新失败:', e);
                                }
                            });
                        } else if (res.code === 403) {
                            top.location.href = baseUrl + "/";
                        } else {
                            layer.msg(res.msg, {icon: 2})
                        }
                    }
                });
            }
            window.pakoutPreview = pakoutPreview;
        })
</script>
</html>
src/main/webapp/views/orderDetl/orderDetl.html
@@ -18,9 +18,33 @@
            <div class="layui-form toolbar" id="search-box">
                <div class="layui-form-item">
                    <div class="layui-inline">
                        <label class="layui-form-label">编号:</label>
                        <div class="layui-input-inline">
                            <input class="layui-input" type="text" name="id" placeholder="编号" autocomplete="off">
                            <input class="layui-input" type="text" name="order_no" placeholder="订单编号"
                                   autocomplete="off">
                        </div>
                    </div>
                    <div class="layui-inline">
                        <div class="layui-input-inline">
                            <input class="layui-input" type="text" name="matnr" placeholder="物料编码"
                                   autocomplete="off">
                        </div>
                    </div>
                    <div class="layui-inline">
                        <div class="layui-input-inline">
                            <input class="layui-input" type="text" name="batch" placeholder="批号" autocomplete="off">
                        </div>
                    </div>
                    <div class="layui-inline">
                        <div class="layui-input-inline">
                            <select name="be_batch" id="docType-query">
                            </select>
                        </div>
                    </div>
                    <div class="layui-inline" style="width: 300px">
                        <div class="layui-input-inline">
                            <input class="layui-input layui-laydate-range" name="create_time" type="text"
                                   placeholder="起始时间 - 终止时间"
                                   autocomplete="off" style="width: 300px">
                        </div>
                    </div>
                    <div class="layui-inline">&emsp;
@@ -30,6 +54,9 @@
                        <button class="layui-btn icon-btn" lay-filter="reset" lay-submit>
                            <i class="layui-icon">&#xe666;</i>重置
                        </button>
                        <button class="layui-btn icon-btn" lay-filter="abnormal" lay-submit>
                            <i class="layui-icon">&#xe615;</i>异常
                        </button>
                    </div>
                </div>
            </div>
@@ -38,11 +65,31 @@
    </div>
</div>
<script type="text/html" id="settleTpl">
    <span name="anfme"
          {{# if( d.qty=== d.anfme){ }}
          class="layui-badge layui-badge-green"
          {{# }else if(d.workQty=== 0){ }}
          class="layui-badge layui-badge-yellow"
          {{# }else if(d.anfme> d.qty){ }}
          class="layui-badge layui-badge-blue"
          {{# }else if(d.anfme < d.qty){ }}
          class="layui-badge layui-badge-red"
          {{# }else if(d.workQty> 0){ }}
          class="layui-badge layui-badge-blue"
          {{# }else if(d.source === 6){ }}
          class="layui-badge layui-badge-gray"
          {{# } }}
    >{{d.anfme$}}</span>
</script>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-sm" id="btn-add" lay-event="addData">新增</button>
        <button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete" lay-event="deleteData">删除</button>
        <button class="layui-btn layui-btn-primary layui-btn-sm" id="btn-export" lay-event="exportData" style="float: right">导出</button>
<!--        <button class="layui-btn layui-btn-sm" id="btn-add" lay-event="addData">新增</button>-->
<!--        <button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete" lay-event="deleteData">删除</button>-->
        <button class="layui-btn layui-btn-primary layui-btn-sm" id="btn-export" lay-event="exportData"
                style="float: right">导出
        </button>
    </div>
</script>
@@ -50,12 +97,19 @@
    <a class="layui-btn layui-btn-primary layui-btn-xs btn-edit" lay-event="edit">修改</a>
    <a class="layui-btn layui-btn-danger layui-btn-xs btn-edit" lay-event="del">删除</a>
</script>
<script type="text/javascript" src="../../static/js/handlebars/handlebars-v4.5.3.js"></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>
<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/orderDetl/orderDetl.js" charset="utf-8"></script>
<script type="text/template" id="docTypeTpl">
    <option value="">选择类型</option>
    {{#each records}}
    <option value="{{docId}}">{{docName}}</option>
    {{/each}}
</script>
</body>
<!-- 表单弹窗 -->
<script type="text/html" id="editDialog">
@@ -67,10 +121,13 @@
                    <label class="layui-form-label">订单内码: </label>
                    <div class="layui-input-block cool-auto-complete">
                        <input class="layui-input" name="orderId" placeholder="请输入订单内码" style="display: none">
                        <input id="orderId$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text" placeholder="请输入订单内码" onfocus=this.blur()>
                        <input id="orderId$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)"
                               type="text" placeholder="请输入订单内码" onfocus=this.blur()>
                        <div class="cool-auto-complete-window">
                            <input class="cool-auto-complete-window-input" data-key="orderQueryByorderId" onkeyup="autoLoad(this.getAttribute('data-key'))">
                            <select class="cool-auto-complete-window-select" data-key="orderQueryByorderIdSelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                            <input class="cool-auto-complete-window-input" data-key="orderQueryByorderId"
                                   onkeyup="autoLoad(this.getAttribute('data-key'))">
                            <select class="cool-auto-complete-window-select" data-key="orderQueryByorderIdSelect"
                                    onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                            </select>
                        </div>
                    </div>
@@ -94,21 +151,21 @@
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">名称: </label>
                    <label class="layui-form-label">订单数量: </label>
                    <div class="layui-input-block">
                        <input class="layui-input" name="name" placeholder="请输入名称">
                        <input class="layui-input" name="anfme" placeholder="请输入名称">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">规格: </label>
                    <label class="layui-form-label">工作数量: </label>
                    <div class="layui-input-block">
                        <input class="layui-input" name="specs" placeholder="请输入规格">
                        <input class="layui-input" name="workQty" placeholder="请输入规格">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">型号: </label>
                    <label class="layui-form-label">完成数量: </label>
                    <div class="layui-input-block">
                        <input class="layui-input" name="model" placeholder="请输入型号">
                        <input class="layui-input" name="qty" placeholder="请输入型号">
                    </div>
                </div>
                <div class="layui-form-item">
@@ -173,10 +230,13 @@
                    <label class="layui-form-label">添加人员: </label>
                    <div class="layui-input-block cool-auto-complete">
                        <input class="layui-input" name="createBy" placeholder="请输入添加人员" style="display: none">
                        <input id="createBy$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text" placeholder="请输入添加人员" onfocus=this.blur()>
                        <input id="createBy$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)"
                               type="text" placeholder="请输入添加人员" onfocus=this.blur()>
                        <div class="cool-auto-complete-window">
                            <input class="cool-auto-complete-window-input" data-key="userQueryBycreateBy" onkeyup="autoLoad(this.getAttribute('data-key'))">
                            <select class="cool-auto-complete-window-select" data-key="userQueryBycreateBySelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                            <input class="cool-auto-complete-window-input" data-key="userQueryBycreateBy"
                                   onkeyup="autoLoad(this.getAttribute('data-key'))">
                            <select class="cool-auto-complete-window-select" data-key="userQueryBycreateBySelect"
                                    onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                            </select>
                        </div>
                    </div>
@@ -191,10 +251,13 @@
                    <label class="layui-form-label">修改人员: </label>
                    <div class="layui-input-block cool-auto-complete">
                        <input class="layui-input" name="updateBy" placeholder="请输入修改人员" style="display: none">
                        <input id="updateBy$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text" placeholder="请输入修改人员" onfocus=this.blur()>
                        <input id="updateBy$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)"
                               type="text" placeholder="请输入修改人员" onfocus=this.blur()>
                        <div class="cool-auto-complete-window">
                            <input class="cool-auto-complete-window-input" data-key="userQueryByupdateBy" onkeyup="autoLoad(this.getAttribute('data-key'))">
                            <select class="cool-auto-complete-window-select" data-key="userQueryByupdateBySelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                            <input class="cool-auto-complete-window-input" data-key="userQueryByupdateBy"
                                   onkeyup="autoLoad(this.getAttribute('data-key'))">
                            <select class="cool-auto-complete-window-select" data-key="userQueryByupdateBySelect"
                                    onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                            </select>
                        </div>
                    </div>
@@ -212,7 +275,7 @@
                    </div>
                </div>
             </div>
            </div>
        </div>
        <hr class="layui-bg-gray">
        <div class="layui-form-item text-right">
@@ -221,5 +284,7 @@
        </div>
    </form>
</script>
</html>