🎉 欢迎访问GreasyFork.Org 镜像站!本镜像站由公众号【爱吃馍】搭建,用于分享脚本。联系邮箱📮

Greasy fork 爱吃馍镜像

Rapid Barcode Receiver (Resize Fix v2)

Uses !important CSS override to fix column resizing on pages with conflicting styles.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

🚀 安装遇到问题?关注公众号获取帮助

公众号二维码

扫码关注【爱吃馍】

回复【脚本】获取最新教程和防失联地址

// ==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">&times;</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();