layui.use(['table', 'laydate', 'form'], function(){ 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'; }); // 初始加载 function initMap() { loadAreas(); // 加载库区颜色信息 loadRowsOptions(); // 加载「排」选项(始终需要) loadLayersOptions(); // 加载「层」选项(提前准备) getLocTable('byRow', 1); // 默认按排 + 第1排 } if (I18n.isReady()) { initMap(); } else { $(document).on('i18n:ready', initMap); } // Listen for dynamic language updates (no reload) $(document).on('i18n:updated', function() { // Update selection button text if (isSelectionMode) { $('#btnSelectMode').text(I18n.t('disable_selection')); } else { $('#btnSelectMode').text(I18n.t('enable_selection')); } // Update assign button text if visible if ($('.loc-selected').length > 0) { $('#btnAssignZone').text(I18n.t('assign_zone') + ' (' + $('.loc-selected').length + ')'); } else { $('#btnAssignZone').text(I18n.t('assign_zone')); } // Re-render legend to update text loadAreas(); // Re-render select options if needed (but options usually don't have text needing translation unless hardcoded) // Re-render form to apply changes form.render(); }); // 加载库区信息并显示图例 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 = '
' + I18n.t('zone_legend') + ':
'; // 默认颜色列表,用于自动分配 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 += '
' + area.areaName + '
'; }); $('#areaLegend').html(legendHtml).show(); } } }); } // 编辑库区颜色 window.editAreaColor = function(areaId) { if (!areaId || !areaMap[areaId]) return; var areaData = areaMap[areaId]; var contentHtml = '
' + '
' + '' + '
' + areaData.name + '
' + '
' + '
' + '' + '
' + '
' + '
'; layer.open({ type: 1, title: I18n.t('modify_zone_color'), area: ['350px', '250px'], content: contentHtml, btn: [I18n.t('save'), I18n.t('cancel')], 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(I18n.t('color_updated')); 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 || I18n.t('update_failed')); } } }); } else { layer.close(index); } } }); }; // 加载所有可用排 function loadRowsOptions() { $.ajax({ url: baseUrl + "/report/viewLocMapList/rows.action", headers: {'token': localStorage.getItem('token')}, method: 'POST', async: false, success: function (res) { if (res.code === 200) { var tpl = $("#locMastRowTemplate").html(); var template = Handlebars.compile(tpl); $('#rowSelect').append(template(res)); form.render('select'); } else if (res.code === 403) { top.location.href = baseUrl + "/"; } } }); } // 加载所有可用层(需要后端支持新接口) function loadLayersOptions() { $.ajax({ 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 template = Handlebars.compile(tpl); $('#layerSelect').append(template(res)); form.render('select'); } } }); } // 核心:根据模式加载库位表 function getLocTable(mode, value) { var url = baseUrl + "/report/viewLocMapList.action"; var data = {}; if (mode === 'byRow') { data.row = value; } else if (mode === 'byLayer') { data.layer = value; } $.ajax({ url: url, headers: {'token': localStorage.getItem('token')}, data: data, method: 'POST', success: function (res) { if (res.code === 200) { var tpl = $("#locMapTemplate").html(); var template = Handlebars.compile(tpl); $('#locMap').html(template(res.data)); } else if (res.code === 403) { top.location.href = baseUrl + "/"; } else { layer.msg(res.msg || I18n.t('load_failed')); } } }); } // 监听 显示模式 切换 form.on('select(viewMode)', function (data) { var mode = data.value; if (mode === 'byRow') { $('#rowSelectBox').show(); $('#layerSelectBox').hide(); // 读取当前选中的排 var currentRow = $('#rowSelect').val() || 1; getLocTable('byRow', currentRow); } else if (mode === 'byLayer') { $('#rowSelectBox').hide(); $('#layerSelectBox').show(); var currentLayer = $('#layerSelect').val() || 1; getLocTable('byLayer', currentLayer); } }); // 监听 排 变化 form.on('select(row)', function (data) { if ($('#viewMode').val() === 'byRow') { getLocTable('byRow', data.value); } }); // 监听 层 变化 form.on('select(layer)', function (data) { if ($('#viewMode').val() === 'byLayer') { 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(I18n.t('disable_selection')).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(I18n.t('selection_mode_tip')); } else { $(this).text(I18n.t('enable_selection')).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(I18n.t('assign_zone') + ' (' + $('.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 = ''; var areas = listRes.data.records; areas.forEach(function(area) { optionsHtml += ''; }); var contentHtml = '
' + '
' + '
' + '' + '
' + '
' + '
'; layer.open({ type: 1, title: I18n.t('assign_zone_and_color'), area: ['400px', '350px'], content: contentHtml, btn: [I18n.t('confirm'), I18n.t('cancel')], 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(I18n.t('please_select_zone')); 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(I18n.t('assign_success')); 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 || I18n.t('operation_failed')); } } }); } }); } else { layer.msg(listRes.msg || I18n.t('fetch_zone_list_failed')); } } }); }); });