自动化立体仓库 - WMS系统
lty
2026-01-21 223ce7dcb236cad6679275d8941e1a909f8a1efc
src/main/webapp/static/js/report/locMap.js
@@ -2,11 +2,102 @@
    var $ = layui.jquery;
    var layer = layui.layer;
    var form = layui.form;
    var areaMap = {};
    // Handlebars helper for area color
    Handlebars.registerHelper('getAreaColor', function(areaId) {
        if (areaId && areaMap[areaId] && areaMap[areaId].color) {
            return areaMap[areaId].color;
        }
        return 'transparent';
    });
    // 初始加载
    loadAreas();             // 加载库区颜色信息
    loadRowsOptions();       // 加载「排」选项(始终需要)
    loadLayersOptions();     // 加载「层」选项(提前准备)
    getLocTable('byRow', 1); // 默认按排 + 第1排
    // 加载库区信息并显示图例
    function loadAreas() {
        $.ajax({
            url: baseUrl + '/area/list/auth?page=1&limit=1000',
            headers: {'token': localStorage.getItem('token')},
            async: false,
            success: function(res) {
                if (res.code === 200) {
                    areaMap = {};
                    var legendHtml = '<div class="area-legend-item" style="cursor:default;font-weight:bold;">库区图例:</div>';
                    // 默认颜色列表,用于自动分配
                    var defaultColors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A1', '#A133FF', '#33FFF5', '#FFD700', '#FF8C00'];
                    var colorIndex = 0;
                    res.data.records.forEach(function(area) {
                        var color = area.backup1;
                        // 增强颜色校验:如果为空、null字符串或长度过短,则视为无效
                        if (!color || color === 'null' || color.trim().length < 3) {
                            color = defaultColors[colorIndex % defaultColors.length];
                            colorIndex++;
                        }
                        areaMap[area.id] = {name: area.areaName, color: color, fullArea: area};
                        legendHtml += '<div class="area-legend-item" onclick="editAreaColor(\'' + area.id + '\')"><span class="area-color-box" style="background-color:' + color + '"></span>' + area.areaName + '</div>';
                    });
                    $('#areaLegend').html(legendHtml).show();
                }
            }
        });
    }
    // 编辑库区颜色
    window.editAreaColor = function(areaId) {
        if (!areaId || !areaMap[areaId]) return;
        var areaData = areaMap[areaId];
        var contentHtml = '<div style="padding: 20px;"><form class="layui-form">' +
            '<div class="layui-form-item">' +
            '<label class="layui-form-label" style="width: auto; padding-left: 0;">库区名称:</label>' +
            '<div class="layui-input-inline" style="line-height: 45px;">' + areaData.name + '</div>' +
            '</div>' +
            '<div class="layui-form-item">' +
            '<label class="layui-form-label" style="width: auto; padding-left: 0;">选择颜色</label>' +
            '<div class="layui-input-inline"><input type="color" id="singleAreaColorPicker" value="' + (areaData.color || '#cccccc') + '" style="height: 38px; width: 100%;"></div>' +
            '</div>' +
            '</form></div>';
        layer.open({
            type: 1,
            title: '修改库区颜色',
            area: ['350px', '250px'],
            content: contentHtml,
            btn: ['保存', '取消'],
            yes: function(index) {
                var newColor = $('#singleAreaColorPicker').val();
                if (newColor !== areaData.color) {
                    $.ajax({
                        url: baseUrl + '/area/update/auth',
                        method: 'POST',
                        headers: {'token': localStorage.getItem('token')},
                        data: { id: areaId, backup1: newColor },
                        success: function(res) {
                            if (res.code === 200) {
                                layer.msg('颜色已更新');
                                layer.close(index);
                                loadAreas(); // 刷新图例和缓存
                                // 刷新地图以应用新颜色
                                var mode = $('#viewMode').val();
                                if (mode === 'byRow') getLocTable('byRow', $('#rowSelect').val());
                                else getLocTable('byLayer', $('#layerSelect').val());
                            } else {
                                layer.msg(res.msg || '更新失败');
                            }
                        }
                    });
                } else {
                    layer.close(index);
                }
            }
        });
    };
    // 加载所有可用排
    function loadRowsOptions() {
@@ -31,13 +122,13 @@
    // 加载所有可用层(需要后端支持新接口)
    function loadLayersOptions() {
        $.ajax({
            url: baseUrl + "/report/viewLocMapList/layers.action",  // ← 需要新增接口
            url: baseUrl + "/report/viewLocMapList/layers.action",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            async: false,
            success: function (res) {
                if (res.code === 200) {
                    var tpl = $("#locMastRowTemplate").html(); // 复用模板
                    var tpl = $("#locMastRowTemplate").html();
                    var template = Handlebars.compile(tpl);
                    $('#layerSelect').append(template(res));
                    form.render('select');
@@ -106,4 +197,232 @@
            getLocTable('byLayer', data.value);
        }
    });
    // --- 框选功能 ---
    var isSelectionMode = false;
    var isDragging = false;
    var startX, startY;
    var $selectionBox = $('#selectionBox');
    var $container = $('#locMapContain');
    $('#btnSelectMode').click(function () {
        isSelectionMode = !isSelectionMode;
        if (isSelectionMode) {
            $(this).text('关闭框选').addClass('layui-btn-danger').removeClass('layui-btn-normal');
            // 禁用原有点击事件,防止冲突 (通过 CSS pointer-events 或移除 onclick)
            // 这里选择移除 onclick 属性
            $('.a-loc').each(function(){
                $(this).attr('data-onclick', $(this).attr('onclick')).removeAttr('onclick');
            });
            layer.msg('已开启框选模式,请在库位图上拖拽选择');
        } else {
            $(this).text('开启框选').addClass('layui-btn-normal').removeClass('layui-btn-danger');
            $('.loc-selected').removeClass('loc-selected');
            $('#btnAssignZone').hide();
            // 恢复点击事件
            $('.a-loc').each(function(){
                if($(this).attr('data-onclick')) {
                    $(this).attr('onclick', $(this).attr('data-onclick'));
                }
            });
        }
    });
    $container.on('mousedown', function (e) {
        if (!isSelectionMode) return;
        // 如果点在滚动条上,可能也会触发,简单判断目标是否是 container 或 table
        if(e.target.tagName !== 'TD' && e.target.id !== 'locMapContain' && e.target.tagName !== 'TABLE' && e.target.tagName !== 'TBODY' && e.target.tagName !== 'TR') return;
        isDragging = true;
        var offset = $container.offset();
        // 相对于 container 内容的坐标 (包含滚动)
        startX = e.pageX - offset.left + $container.scrollLeft();
        startY = e.pageY - offset.top + $container.scrollTop();
        $selectionBox.css({
            left: startX,
            top: startY,
            width: 0,
            height: 0,
            display: 'block'
        });
        // 阻止默认文本选择
        e.preventDefault();
    });
    $container.on('mousemove', function (e) {
        if (!isSelectionMode || !isDragging) return;
        var offset = $container.offset();
        var currentX = e.pageX - offset.left + $container.scrollLeft();
        var currentY = e.pageY - offset.top + $container.scrollTop();
        var width = Math.abs(currentX - startX);
        var height = Math.abs(currentY - startY);
        var left = Math.min(currentX, startX);
        var top = Math.min(currentY, startY);
        $selectionBox.css({
            width: width,
            height: height,
            left: left,
            top: top
        });
    });
    $(document).on('mouseup', function (e) {
        if (!isSelectionMode || !isDragging) return;
        isDragging = false;
        $selectionBox.hide();
        // 计算框选区域 (相对于视口,用于 getBoundingClientRect 比较)
        // 或者都转换为相对于 container 的坐标
        // 这里使用相对于 container 的坐标比较更稳妥
        var boxLeft = parseFloat($selectionBox.css('left'));
        var boxTop = parseFloat($selectionBox.css('top'));
        var boxWidth = parseFloat($selectionBox.css('width'));
        var boxHeight = parseFloat($selectionBox.css('height'));
        var boxRight = boxLeft + boxWidth;
        var boxBottom = boxTop + boxHeight;
        // 获取 container 的 offset
        var containerOffset = $container.offset();
        $('.a-loc').each(function () {
            var $el = $(this);
            var elOffset = $el.offset();
            // 转换为相对于 container 的坐标 (加上 scroll)
            var elLeft = elOffset.left - containerOffset.left + $container.scrollLeft();
            var elTop = elOffset.top - containerOffset.top + $container.scrollTop();
            var elWidth = $el.outerWidth();
            var elHeight = $el.outerHeight();
            var elRight = elLeft + elWidth;
            var elBottom = elTop + elHeight;
            // 碰撞检测
            if (!(elLeft > boxRight || elRight < boxLeft || elTop > boxBottom || elBottom < boxTop)) {
                $el.toggleClass('loc-selected');
            }
        });
        if ($('.loc-selected').length > 0) {
            $('#btnAssignZone').show().text('分配库区 (' + $('.loc-selected').length + ')');
        } else {
            $('#btnAssignZone').hide();
        }
    });
    // --- 分配库区 ---
    $('#btnAssignZone').click(function () {
        var selectedLocs = [];
        $('.loc-selected').each(function () {
            selectedLocs.push($(this).attr('title')); // title has locNo
        });
        if (selectedLocs.length === 0) return;
        // 获取库区列表
        $.ajax({
            url: baseUrl + '/area/list/auth?page=1&limit=1000',
            headers: {'token': localStorage.getItem('token')},
            success: function(listRes) {
                if (listRes.code === 200) {
                        var optionsHtml = '<option value="">请选择库区</option>';
                        var areas = listRes.data.records;
                        areas.forEach(function(area) {
                            optionsHtml += '<option value="' + area.id + '">' + area.areaName + ' (' + area.areaId + ')</option>';
                        });
                        var contentHtml = '<div style="padding: 20px;"><form class="layui-form">' +
                            '<div class="layui-form-item"><select id="selectArea" lay-filter="selectArea">' + optionsHtml + '</select></div>' +
                            '<div class="layui-form-item">' +
                            '<label class="layui-form-label" style="width: auto; padding-left: 0;">库区颜色</label>' +
                            '<div class="layui-input-inline"><input type="color" id="areaColorPicker" value="#cccccc" style="height: 38px; width: 100%;"></div>' +
                            '</div>' +
                            '</form></div>';
                        layer.open({
                            type: 1,
                            title: '分配库区及颜色',
                            area: ['400px', '350px'],
                            content: contentHtml,
                            btn: ['确定', '取消'],
                            success: function(layero, index) {
                                form.render('select');
                                form.on('select(selectArea)', function(data){
                                    var areaId = data.value;
                                    if(areaId && areaMap[areaId]) {
                                        $('#areaColorPicker').val(areaMap[areaId].color || '#cccccc');
                                    }
                                });
                            },
                            yes: function(index) {
                                var areaId = $('#selectArea').val();
                                var newColor = $('#areaColorPicker').val();
                                if (!areaId) {
                                    layer.msg('请选择库区');
                                    return;
                                }
                                // 1. 更新库区颜色 (如果有变化)
                                if (areaMap[areaId] && areaMap[areaId].color !== newColor) {
                                    $.ajax({
                                        url: baseUrl + '/area/update/auth',
                                        method: 'POST',
                                        headers: {'token': localStorage.getItem('token')},
                                        data: { id: areaId, backup1: newColor },
                                        async: false, // 同步更新以确保刷新时颜色正确
                                        success: function() {
                                            loadAreas(); // 刷新图例和缓存
                                        }
                                    });
                                }
                                // 2. 批量更新库位
                                $.ajax({
                                    url: baseUrl + '/locMast/batchUpdateArea/auth',
                                    method: 'POST',
                                    headers: {'token': localStorage.getItem('token')},
                                    contentType: 'application/json',
                                    data: JSON.stringify({
                                        locNos: selectedLocs,
                                        areaId: parseInt(areaId)
                                    }),
                                    success: function(updRes) {
                                        if (updRes.code === 200) {
                                            layer.msg('分配成功');
                                            layer.close(index);
                                            // 刷新
                                            var mode = $('#viewMode').val();
                                            if (mode === 'byRow') getLocTable('byRow', $('#rowSelect').val());
                                            else getLocTable('byLayer', $('#layerSelect').val());
                                            // 重置状态
                                            $('.loc-selected').removeClass('loc-selected');
                                            $('#btnAssignZone').hide();
                                            // 保持框选模式
                                            if(isSelectionMode) {
                                                // 重新移除onclick
                                                setTimeout(function(){
                                                    $('.a-loc').each(function(){
                                                        $(this).attr('data-onclick', $(this).attr('onclick')).removeAttr('onclick');
                                                    });
                                                }, 500); // 简单延时等待渲染
                                            }
                                        } else {
                                            layer.msg(updRes.msg || '操作失败');
                                        }
                                    }
                                });
                            }
                        });
                } else {
                    layer.msg(listRes.msg || '无法获取库区列表');
                }
            }
        });
    });
});