您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Uses !important CSS override to fix column resizing on pages with conflicting styles.
// ==UserScript== // @name Rapid Barcode Receiver (Resize Fix v2) // @namespace http://tampermonkey.net/ // @version 6.1 // @description Uses !important CSS override to fix column resizing on pages with conflicting styles. // @author Gemini & User // @match *://*/* // @grant GM_addStyle // @require https://code.jquery.com/jquery-3.6.0.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/colResizable-1.6.min.js // @license MIT // ==/UserScript== // --- Utility function to wait for dynamically loaded elements --- function waitForKeyElements(selector, callback, bWaitOnce) { var targetNodes, bDone = false; targetNodes = $(selector); if (targetNodes && targetNodes.length > 0) { targetNodes.each(function() { callback($(this)); }); bDone = bWaitOnce; } var obs = new MutationObserver(function(mutations) { if (bDone) { obs.disconnect(); return; } mutations.forEach(function(mutation) { var newNodes = mutation.addedNodes; if (newNodes && newNodes.length > 0) { for (var i = 0, len = newNodes.length; i < len; i++) { var newNode = newNodes[i]; if (newNode.nodeType === 1) { var $node = $(newNode); if ($node.is(selector)) { callback($node); if (bWaitOnce) bDone = true; } else if ($node.find(selector).length > 0) { $node.find(selector).each(function() { callback($(this)); }); if (bWaitOnce) bDone = true; } } } } }); }); obs.observe(document.body, { childList: true, subtree: true }); } // --- Main script logic --- function initializeScript() { const closeButtonSelector = "#closebtn-smplrecieve, #btnclose-smplcollection"; waitForKeyElements(closeButtonSelector, (closeButton) => { if (closeButton.parent().find('#rapidReceiveBtn').length > 0) return; let rapidReceiveBtn = $('<button type="button" class="btn btn-color-1" id="rapidReceiveBtn">Rapid Receiver</button>'); rapidReceiveBtn.css('margin-right', '5px'); closeButton.before(rapidReceiveBtn); if ($('#rapidReceiveModal').length === 0) { let modalHTML = ` <div id="rapidReceiveModal" class="rr-modal-backdrop"> <div class="rr-modal-content"> <div class="rr-modal-header"> <h2>Rapid Barcode Processor</h2> <span class="rr-close-button">×</span> </div> <div class="rr-modal-body"> <input type="text" id="newBarcodeEntry" placeholder="Scan or paste barcodes here and press Enter"> <div id="rr-table-container"> <table id="barcodeTable"> <thead> <tr> <th class="rr-th-no">No.</th> <th class="rr-th-barcode">Barcode</th> <th class="rr-th-location">Location</th> <th class="rr-th-status">Status</th> </tr> </thead> <tbody id="barcodeListBody"></tbody> </table> </div> </div> <div class="rr-modal-footer"> <span id="rr-counter" class="rr-counter-style">0 Barcodes Entered</span> <div> <button id="clearBarcodesBtn" class="btn btn-danger">Clear</button> <button id="processBarcodesBtn" class="btn btn-success">Process</button> </div> </div> </div> </div> `; $('body').append(modalHTML); GM_addStyle(` .rr-modal-backdrop { display: none; position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.6); } .rr-modal-content { display: flex; flex-direction: column; background-color: #f8f9fa; margin: 5% auto; padding: 25px; border: none; width: 90%; max-width: 900px; border-radius: 8px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); height: 80vh; } .rr-modal-header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #dee2e6; padding-bottom: 15px; margin-bottom: 15px; } .rr-modal-header h2 { margin: 0; font-size: 1.5rem; color: #343a40; } .rr-modal-body { flex-grow: 1; display: flex; flex-direction: column; overflow: hidden; } .rr-modal-footer { display: flex; justify-content: space-between; align-items: center; border-top: 1px solid #dee2e6; padding-top: 15px; margin-top: 15px; } .rr-close-button { color: #aaa; font-size: 32px; font-weight: bold; cursor: pointer; line-height: 1; } .rr-close-button:hover { color: black; } #newBarcodeEntry { width: 100%; padding: 10px; font-size: 16px; margin-bottom: 15px; border: 1px solid #ced4da; border-radius: 4px; box-sizing: border-box; } #newBarcodeEntry:focus { border-color: #80bdff; outline: 0; box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25); } #rr-table-container { flex-grow: 1; overflow-y: auto; border: 1px solid #dee2e6; border-radius: 4px; background-color: #fff; } #barcodeTable { width: 100%; border-collapse: collapse; table-layout: fixed; } #barcodeTable th, #barcodeTable td { padding: 4px 15px; text-align: left; border-bottom: 1px solid #e9ecef; vertical-align: middle; } #barcodeTable th { background-color: #e9ecef; color: #495057; position: sticky; top: 0; } /* MODIFIED: Added !important to force vertical lines to appear */ #barcodeTable th:not(:last-child), #barcodeTable td:not(:last-child) { border-right: 1px solid #dee2e6 !important; } #barcodeTable tbody tr:nth-child(even) { background-color: #f8f9fa; } .rr-th-no { width: 5%; } .rr-th-barcode { width: 35%; } .rr-th-location { width: 15%; } .rr-th-status { width: 45%; } td.status-cell { font-weight: bold; text-align: left; } td.status-cell.success { text-align: center; color: green; font-size: 1.2rem; } .rr-counter-style { font-size: 14px; font-weight: bold; color: #555; } #clearBarcodesBtn { margin-right: 10px; } .rr-error-text { color: #D8000C; font-weight: bold; font-size: 12px; } /* MODIFIED: Forceful grip style to ensure it is visible and clickable */ .JCLRgrip { background-color: #007bff !important; width: 3px !important; z-index: 99999 !important; } `); // Delay initialization to prevent conflicts setTimeout(() => { $('#barcodeTable').colResizable({ liveDrag: true, gripInnerHtml: "<div class='JCLRgrip'></div>", minWidth: 30 // Prevent columns from becoming too small }); }, 100); // --- Event Listeners --- $('.rr-close-button').on('click', () => $('#rapidReceiveModal').hide()); $(window).on('click', (event) => { if ($(event.target).is('#rapidReceiveModal')) $('#rapidReceiveModal').hide(); }); $('#processBarcodesBtn').on('click', processBarcodes); $('#clearBarcodesBtn').on('click', clearAllBarcodes); $('#newBarcodeEntry').on('keydown', handleBarcodeEntry); $('#newBarcodeEntry').on('paste', handleBarcodePaste); } $('#rapidReceiveBtn').on('click', openRapidReceiver); }, false); } function openRapidReceiver() { $('#rapidReceiveModal').show(); clearAllBarcodes(); $('#newBarcodeEntry').focus(); $('#rr-counter').css('color', ''); $('#processBarcodesBtn, #clearBarcodesBtn').prop('disabled', false); $('#processBarcodesBtn').text('Process'); } function clearAllBarcodes() { $('#barcodeListBody').empty(); $('#newBarcodeEntry').val('').prop('disabled', false); updateBarcodeCount(); } function updateBarcodeCount() { const count = $('#barcodeListBody tr').length; $('#rr-counter').text(`${count} Barcodes Entered`); } function addBarcodeToTable(barcode) { barcode = barcode.trim(); if (barcode === '') return; const currentBarcodes = new Set(); $('#barcodeListBody td:nth-child(2)').each(function() { currentBarcodes.add($(this).text()); }); if (currentBarcodes.has(barcode)) return; const rowIndex = $('#barcodeListBody tr').length; const rowNum = rowIndex + 1; const letter = String.fromCharCode(65 + Math.floor(rowIndex / 10)); const number = (rowIndex % 10) + 1; const location = `${letter}${number}`; const newRow = ` <tr> <td>${rowNum}</td> <td>${barcode}</td> <td>${location}</td> <td class="status-cell"></td> </tr> `; $('#barcodeListBody').append(newRow); updateBarcodeCount(); } function handleBarcodeEntry(event) { if (event.key === 'Enter') { event.preventDefault(); const barcodeInput = $(this); const barcode = barcodeInput.val(); addBarcodeToTable(barcode); barcodeInput.val(''); } } function handleBarcodePaste(event) { event.preventDefault(); const pastedText = (event.originalEvent || event).clipboardData.getData('text/plain'); const barcodes = pastedText.split(/\r?\n/).filter(line => line.trim() !== ''); barcodes.forEach(barcode => addBarcodeToTable(barcode)); $(this).val(''); } // --- Barcode processing logic --- async function processBarcodes() { const barcodeInput = $('#barcodecollection'); const processButton = $('#processBarcodesBtn'); const clearButton = $('#clearBarcodesBtn'); const entryInput = $('#newBarcodeEntry'); const counterElement = $('#rr-counter'); const rowsToProcess = $('#barcodeListBody tr').filter(function() { const status = $(this).find('td.status-cell').text().trim(); return status !== '✔️'; }); if (rowsToProcess.length === 0) return alert('No new or failed barcodes to process.'); if (barcodeInput.length === 0) return alert('Error: Main barcode input field "#barcodecollection" not found.'); processButton.prop('disabled', true).text('Processing...'); clearButton.prop('disabled', true); entryInput.prop('disabled', true); const INTER_BARCODE_DELAY = 1200; const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); const dispatchEvent = (element, eventType) => element.dispatchEvent(new Event(eventType, { bubbles: true })); const simulateEnter = async (element) => { const commonEventProps = { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true, cancelable: true }; element.dispatchEvent(new KeyboardEvent('keydown', commonEventProps)); await sleep(50); element.dispatchEvent(new KeyboardEvent('keyup', commonEventProps)); }; let processedCount = 0; for (const row of rowsToProcess) { processedCount++; counterElement.text(`Processing: ${processedCount} / ${rowsToProcess.length}`); const $row = $(row); const barcode = $row.find('td:nth-child(2)').text(); const statusCell = $row.find('td.status-cell'); statusCell.removeClass('success').html('...'); const inputElement = barcodeInput[0]; inputElement.value = barcode; dispatchEvent(inputElement, 'input'); dispatchEvent(inputElement, 'change'); await sleep(100); inputElement.focus(); await simulateEnter(inputElement); await sleep(600); const $errorAlert = $("div.alert.alert-danger:visible"); if ($errorAlert.length > 0) { const errorMessage = $errorAlert.find('strong').text().trim() || 'Unknown Error'; statusCell.html(`<span class="rr-error-text">${errorMessage}</span>`); } else { statusCell.addClass('success').html('✔️'); } $('.alert-dismissable .close').click(); await sleep(INTER_BARCODE_DELAY - 600); } processButton.prop('disabled', false).text('Process'); clearButton.prop('disabled', false); entryInput.prop('disabled', false).focus(); counterElement.text('✅ Complete!').css('color', 'green'); } // --- Logic to handle dynamic page loads --- let lastUrl = location.href; setInterval(() => { const currentUrl = location.href; if (currentUrl !== lastUrl) { lastUrl = currentUrl; initializeScript(); } }, 500); // Initial run initializeScript();