自动化立体仓库 - WMS系统
chen.llin
17 小时以前 12067f657bc3dc169a7a466e433374368e8daf73
越库订单逻辑调整
8个文件已修改
210 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/OrderPakinController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/ViewStayTimeBean.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/OrderDomainParam.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/CrossDockServiceImpl.java 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/orderPakin/order.js 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/report/stayTime.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/home/console.html 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/orderPakin/order.html 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OrderPakinController.java
@@ -13,6 +13,7 @@
import com.zy.asrs.service.*;
import com.zy.common.model.DetlDto;
import com.zy.common.web.BaseController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
@@ -20,6 +21,7 @@
import java.util.*;
@Slf4j
@RestController
@RequestMapping("order/pakin")
public class OrderPakinController extends BaseController {
@@ -210,9 +212,25 @@
        }
        
        // 越库功能:如果勾选了越库订单,无论什么类型的订单都按照越库逻辑处理
        if (Boolean.TRUE.equals(param.getIsCrossDock())) {
        Boolean isCrossDock = param.getIsCrossDock();
        log.info("检查越库订单标识,isCrossDock:{},类型:{},订单号:{}",
                isCrossDock, isCrossDock != null ? isCrossDock.getClass().getName() : "null", order.getOrderNo());
        // 判断是否为越库订单(支持 Boolean.TRUE 或 true 字符串)
        boolean shouldProcessCrossDock = Boolean.TRUE.equals(isCrossDock) ||
                (isCrossDock != null && isCrossDock.toString().equalsIgnoreCase("true"));
        if (shouldProcessCrossDock) {
            log.info("开始处理越库订单,订单号:{},订单ID:{}", order.getOrderNo(), order.getId());
            String outOrderNo = crossDockService.processCrossDockInbound(order, param, getUserId());
            // 重新查询订单,确保状态已更新
            OrderPakin finalOrder = orderService.selectById(order.getId());
            if (finalOrder != null) {
                log.info("越库订单处理完成,订单号:{},最终状态:{}", finalOrder.getOrderNo(), finalOrder.getSettle());
            }
            return R.ok("越库入库单创建成功,已自动生成越库出库单:" + outOrderNo);
        } else {
            log.info("非越库订单,订单号:{},状态保持为:{}", order.getOrderNo(), order.getSettle());
        }
        
        return R.ok("订单添加成功");
src/main/java/com/zy/asrs/entity/ViewStayTimeBean.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotations.TableField;
import com.core.common.Cools;
import com.core.common.SpringUtils;
import com.zy.common.properties.CrossDockProperties;
import com.zy.system.entity.User;
import com.zy.system.service.UserService;
import io.swagger.annotations.ApiModelProperty;
@@ -177,4 +178,24 @@
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.appe_time);
    }
    /**
     * 格式化库位号显示,如果是虚拟库位则显示"越库"标识
     *
     * @return 格式化后的库位号(如果是虚拟库位,格式为:库位号(越库))
     */
    public String getLocNo$() {
        if (Cools.isEmpty(this.loc_no)) {
            return "";
        }
        try {
            CrossDockProperties crossDockProperties = SpringUtils.getBean(CrossDockProperties.class);
            if (crossDockProperties != null && this.loc_no.equals(crossDockProperties.getVirtualLocationNo())) {
                return this.loc_no + "(越库)";
            }
        } catch (Exception e) {
            // 如果获取配置失败,忽略异常,返回原始库位号
        }
        return this.loc_no;
    }
}
src/main/java/com/zy/asrs/entity/param/OrderDomainParam.java
@@ -30,6 +30,12 @@
     */
    private Boolean isCrossDock;
    /**
     * 出库订单类型(越库订单时使用)
     * 用户选择的出库订单类型ID
     */
    private Long outboundDocType;
    private List<OrderDetl> orderDetlList;
    private List<OrderDetlPakin> orderDetlPakinList;
    private List<OrderDetlPakout> orderDetlPakoutList;
src/main/java/com/zy/asrs/service/impl/CrossDockServiceImpl.java
@@ -54,14 +54,24 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String processCrossDockInbound(OrderPakin order, OrderDomainParam param, Long userId) {
        log.info("开始处理越库入库单,订单号:{}", order.getOrderNo());
        log.info("开始处理越库入库单,订单号:{},订单类型:{}", order.getOrderNo(), order.getDocType());
        
        Date now = new Date();
        
        // 步骤1:设置入库单为已上报状态(跳过ERP上报流程)
        log.info("步骤1:设置入库单[{}]为已上报状态", order.getOrderNo());
        if (!orderPakinService.updateSettle(order.getId(), 6L, userId)) {
            throw new CoolException("设置入库单为已上报状态失败");
        log.info("步骤1:设置入库单[{}]为已上报状态,订单ID:{}", order.getOrderNo(), order.getId());
        boolean updateResult = orderPakinService.updateSettle(order.getId(), 6L, userId);
        log.info("步骤1:更新入库单状态结果:{}", updateResult);
        if (!updateResult) {
            throw new CoolException("设置入库单为已上报状态失败,订单ID:" + order.getId());
        }
        // 验证状态是否更新成功
        OrderPakin updatedOrder = orderPakinService.selectById(order.getId());
        if (updatedOrder != null) {
            log.info("步骤1:验证入库单状态更新,订单号:{},当前状态:{}", updatedOrder.getOrderNo(), updatedOrder.getSettle());
            if (!updatedOrder.getSettle().equals(6L)) {
                throw new CoolException("入库单状态更新失败,期望状态:6,实际状态:" + updatedOrder.getSettle());
            }
        }
        
        // 步骤2:更新明细完成数量并创建虚拟库位库存
@@ -70,8 +80,9 @@
            new EntityWrapper<OrderDetlPakin>().eq("order_id", order.getId()));
        
        for (OrderDetlPakin orderDetl : orderDetls) {
            // 2.1 更新完成数量
            orderDetl.setQty(orderDetl.getAnfme());
            // 2.1 更新完成数量和作业数量(越库订单立即完成,不需要实际作业)
            orderDetl.setQty(orderDetl.getAnfme()); // 完成数量等于申请数量
            orderDetl.setWorkQty(orderDetl.getAnfme()); // 作业数量等于申请数量
            orderDetl.setUpdateBy(userId);
            orderDetl.setUpdateTime(now);
            if (!orderDetlPakinService.updateById(orderDetl)) {
@@ -83,12 +94,19 @@
        }
        
        // 步骤3:获取越库出库单类型
        Long outboundDocTypeId = crossDockProperties.getOutboundDocTypeId();
        log.info("步骤3:获取越库出库单类型,docId={}", outboundDocTypeId);
        // 优先使用用户选择的出库订单类型,如果没有则使用配置的默认类型
        Long outboundDocTypeId = param.getOutboundDocType();
        if (outboundDocTypeId == null) {
            outboundDocTypeId = crossDockProperties.getOutboundDocTypeId();
            log.info("步骤3:用户未选择出库订单类型,使用配置的默认类型,docId={}", outboundDocTypeId);
        } else {
            log.info("步骤3:使用用户选择的出库订单类型,docId={}", outboundDocTypeId);
        }
        DocType crossDockOutDocType = docTypeService.selectById(outboundDocTypeId);
        if (crossDockOutDocType == null) {
            throw new CoolException("越库出库单类型不存在,docId=" + outboundDocTypeId);
        }
        log.info("步骤3:出库订单类型名称:{}", crossDockOutDocType.getDocName());
        
        // 步骤4:创建越库出库单主档
        log.info("步骤4:创建越库出库单主档");
@@ -253,8 +271,9 @@
        outDetl.setId(null); // 清除ID,让数据库自动生成
        outDetl.setOrderId(outOrder.getId());
        outDetl.setOrderNo(outOrderNo);
        outDetl.setAnfme(inDetl.getAnfme()); // 申请数量等于入库单明细的申请数量
        outDetl.setQty(inDetl.getAnfme()); // 完成数量等于申请数量
        outDetl.setWorkQty(inDetl.getAnfme());
        outDetl.setWorkQty(inDetl.getAnfme()); // 作业数量等于申请数量
        outDetl.setCreateBy(userId);
        outDetl.setCreateTime(now);
        outDetl.setUpdateBy(userId);
src/main/webapp/static/js/orderPakin/order.js
@@ -180,7 +180,88 @@
                form.val('editForm', expTpe);
                if (expTpe) {
                    $('#orderNo').attr("disabled", "disabled");
                    // 修改订单时,不显示越库按钮(因为越库订单创建后就完成了,不会有中间状态)
                    $('#crossDockItem').hide();
                } else {
                    // 新增订单时,显示越库按钮,默认不勾选
                    $('#crossDockItem').show();
                    // 默认隐藏出库订单类型选择器
                    $('#outboundDocTypeItem').hide();
                }
                // 先渲染 switch,确保 LayUI 正确初始化
                form.render('switch');
                // 初始化出库订单类型选择器
                var outboundDocTypeData = [];
                $.ajax({
                    url: baseUrl + "/docType/list/auth",
                    headers: { 'token': localStorage.getItem('token') },
                    data: { limit: 9999, pakout: 1 },
                    method: 'POST',
                    async: false,
                    success: function (res) {
                        if (res.code === 200) {
                            // 转换为 xmSelect 需要的格式
                            res.data.records.forEach(function (item) {
                                outboundDocTypeData.push({
                                    name: item.docName,
                                    value: item.docId
                                });
                            });
                        } else {
                            layer.msg(res.msg, { icon: 2 });
                        }
                    }
                });
                var outboundDocTypeXmSelect = xmSelect.render({
                    el: '#outboundDocTypeSelect',
                    radio: true,
                    clickClose: true,
                    filterable: true,
                    model: {
                        icon: 'hidden',
                        label: {
                            type: 'text',
                        }
                    },
                    data: outboundDocTypeData,
                    initValue: []
                });
                // 切换出库订单类型选择器的显示/隐藏
                function toggleOutboundDocTypeSelector(show) {
                    if (show) {
                        // 勾选越库订单时,显示出库订单类型选择器
                        $('#outboundDocTypeItem').show();
                        console.log('显示出库订单类型选择器');
                    } else {
                        // 取消勾选时,隐藏出库订单类型选择器
                        $('#outboundDocTypeItem').hide();
                        outboundDocTypeXmSelect.setValue([]);
                        console.log('隐藏出库订单类型选择器');
                    }
                }
                // 监听 switch 变化,控制出库订单类型选择器的显示/隐藏
                // 注意:必须在 form.render 之后注册监听器
                form.on('switch(isCrossDock)', function(data){
                    var isChecked = data.elem.checked;
                    console.log('越库订单开关变化,值:', isChecked, '元素:', data.elem);
                    toggleOutboundDocTypeSelector(isChecked);
                });
                // 初始化时检查 switch 状态(以防页面刷新后状态不一致)
                // 使用 setTimeout 确保 DOM 已完全渲染
                setTimeout(function() {
                    var initialCrossDockState = $('#isCrossDock').is(':checked') ||
                                                $('#isCrossDock').prop('checked') ||
                                                ($('#isCrossDock').next('.layui-form-switch').hasClass('layui-form-onswitch'));
                    console.log('初始化检查越库订单状态:', initialCrossDockState);
                    if (initialCrossDockState) {
                        toggleOutboundDocTypeSelector(true);
                    }
                }, 100);
                // 初始化业务时间日期选择器
                layDate.render({
                    elem: '#orderTime',
@@ -254,7 +335,33 @@
                            return false;
                        }
                    }
                    // 获取越库订单开关状态(多种方式检测,确保准确性)
                    var isCrossDockChecked = $('#isCrossDock').is(':checked') ||
                                            $('#isCrossDock').prop('checked') ||
                                            data.field.isCrossDock === 'ON' ||
                                            data.field.isCrossDock === true ||
                                            data.field.isCrossDock === 'on';
                    console.log('提交越库订单状态,isCrossDock:', isCrossDockChecked, '原始值:', data.field.isCrossDock, 'DOM checked:', $('#isCrossDock').is(':checked'));
                    // 获取出库订单类型ID
                    var outboundDocTypeId = null;
                    if (isCrossDockChecked) {
                        // 检查出库订单类型选择器是否可见
                        if (!$('#outboundDocTypeItem').is(':visible')) {
                            console.warn('出库订单类型选择器未显示,但越库订单已勾选');
                        }
                        var outboundDocTypeValue = outboundDocTypeXmSelect.getValue();
                        console.log('出库订单类型选择器值:', outboundDocTypeValue);
                        if (!outboundDocTypeValue || outboundDocTypeValue.length === 0 || !outboundDocTypeValue[0]) {
                            layer.msg('请选择出库订单类型', { icon: 2 });
                            return false;
                        }
                        outboundDocTypeId = Number(outboundDocTypeValue[0].value);
                        console.log('出库订单类型ID:', outboundDocTypeId);
                    }
                    layer.load(2);
                    $.ajax({
                        url: baseUrl + "/order/pakin/order/form/" + (isExpAdd ? "add" : "modify") + "/auth",
                        headers: { 'token': localStorage.getItem('token') },
@@ -264,6 +371,8 @@
                            orderNo: data.field.orderNo,
                            cstmrName: cstmrXmSelect.getValue()[0] ? cstmrXmSelect.getValue()[0].name : null,
                            orderTime: data.field.orderTime,
                            isCrossDock: isCrossDockChecked,
                            outboundDocType: outboundDocTypeId,
                            orderDetlPakinList: nList
                        }),
                        contentType: 'application/json;charset=UTF-8',
src/main/webapp/static/js/report/stayTime.js
@@ -3,7 +3,7 @@
    var cols = [
        {field: 'appeTime$', title: '入库时间', align: 'center', width: 200}
        ,{field: 'stay_time', align: 'center',title: '滞留天数'}
        ,{field: 'loc_no', align: 'center',title: '库位号'}
        ,{field: 'locNo$', title: '库位号', align: 'center'}
    ];
    cols.push.apply(cols, detlCols);
    return cols;
src/main/webapp/views/home/console.html
@@ -237,7 +237,7 @@
        var cols = [
            {field: 'appeTime$', title: '入库时间', align: 'center', width: 200}
            ,{field: 'stay_time', align: 'center',title: '滞留天数'}
            ,{field: 'loc_no', align: 'center',title: '库位号'}
            ,{field: 'locNo$', title: '库位号', align: 'center'}
        ];
        cols.push.apply(cols, detlCols);
        return cols;
src/main/webapp/views/orderPakin/order.html
@@ -184,6 +184,19 @@
                <input id="orderTime" name="orderTime" placeholder="选择业务时间" type="text" class="layui-input" autocomplete="off" lay-verType="tips" />
            </div>
        </div>
        <div class="layui-form-item" id="crossDockItem" style="display: none;">
            <label class="layui-form-label">越库订单:</label>
            <div class="layui-input-block">
                <input type="checkbox" id="isCrossDock" name="isCrossDock" lay-skin="switch" lay-text="是|否" lay-filter="isCrossDock" title="勾选后,无论什么类型的订单都按照越库逻辑处理,过账入库+出库直接完成,不调用任何设备和通知其他系统">
            </div>
        </div>
        <div class="layui-form-item" id="outboundDocTypeItem" style="display: none;">
            <label class="layui-form-label">出库订单类型:</label>
            <div class="layui-input-block">
                <div id="outboundDocTypeSelect"></div>
                <div class="layui-form-mid layui-word-aux">选择越库订单生成的出库单类型</div>
            </div>
        </div>
        <div class="layui-form-item" style="position: relative;">
            <label class="layui-form-label">单据明细:</label>
            <div class="layui-input-block">