柠檬云进销存输入框自动计算箱盒转换

自动将备注栏或其他自定义列中输入格式如“26=”或“26+”转换为“1箱2盒”(需设置商品规格格式为:200ml×24盒,脚本会捕获“×24盒”来计算),支持动态规格解析和Vue数据绑定

// ==UserScript==
// @name         柠檬云进销存输入框自动计算箱盒转换
// @namespace    https://jxc.ningmengyun.com/zhuanhuan
// @version      2.2
// @description  自动将备注栏或其他自定义列中输入格式如“26=”或“26+”转换为“1箱2盒”(需设置商品规格格式为:200ml×24盒,脚本会捕获“×24盒”来计算),支持动态规格解析和Vue数据绑定
// @author       偶然好看
// @license MIT
// @match        https://jxc.ningmengyun.com/*
// @match        https://jxcpro.ningmengyun.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 配置参数
    const CONFIG = {
        inputSelector: '.el-input__inner',
        pattern: /^(\d+)[=+]$/,                // 新输入格式正则
        errorTimeout: 2000,
        specPattern: /×\s*(\d{2,3})\s*([\u4e00-\u9fa5]+)/  // 规格解析正则
    };

    // 提取规格信息函数
    function extractSpecInfo(input) {
        try {
            // 查找最近的表格行
            const tr = input.closest('tr');
            if (!tr) throw new Error('未找到商品行');

            // 使用XPath查找包含规格的单元格
            const xpath = './/td[contains(., "×")]';
            const result = document.evaluate(xpath, tr, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
            const specTd = result.singleNodeValue;

            if (!specTd) throw new Error('未找到规格信息');

            // 解析规格信息
            const match = specTd.textContent.match(CONFIG.specPattern);
            if (!match) throw new Error('规格格式错误');

            return {
                denominator: parseInt(match[1], 10),
                unit: match[2].trim()
            };
        } catch (error) {
            console.warn('规格解析失败:', error.message);
            return null;
        }
    }

    // 输入处理函数
    function handleInputConversion(event) {
        const input = event.target;
        const value = input.value.trim();

        if (CONFIG.pattern.test(value)) {
            // 获取规格信息
            const spec = extractSpecInfo(input) || {};
            if (!spec.denominator) {
                showTemporaryError(input, '规格信息缺失');
                return;
            }

            const numerator = parseInt(value.match(CONFIG.pattern)[1], 10);
            const total = numerator / spec.denominator;

            // 异常处理
            if (spec.denominator === 0) {
                showTemporaryError(input, '规格数量不能为0');
                return;
            }
            if (total < 0.01) {
                showTemporaryError(input, '输入数值过小');
                return;
            }

            // 计算结果
            const cases = Math.floor(total);
            const boxes = Math.round((total - cases) * spec.denominator);

            // 格式化输出
            const result = `${cases}箱${boxes}${spec.unit}`;
            updateVueInput(input, result);
        }
    }


    // 显示临时错误提示
    function showTemporaryError(input, message) {
        const originalValue = input.value;
        input.value = message;
        setTimeout(() => {
            input.value = originalValue.replace(/=$/, '');
            input.focus();
        }, CONFIG.errorTimeout);
    }

    // Vue兼容性更新(触发数据绑定)
    function updateVueInput(input, newValue) {
        input.value = newValue;
        const vueInputEvent = new Event('input', {
            bubbles: true,
            cancelable: true
        });
        input.dispatchEvent(vueInputEvent);
    }


    // 初始化逻辑增加规格数据绑定
    const observer = new MutationObserver(mutations => {
        mutations.forEach(() => {
            document.querySelectorAll(CONFIG.inputSelector).forEach(input => {
                if (!input.dataset.autoConvertAdded) {
                    // 预绑定规格信息
                    const spec = extractSpecInfo(input);
                    if (spec) {
                        input.dataset.denominator = spec.denominator;
                        input.dataset.unit = spec.unit;
                    }

                    input.addEventListener('input', handleInputConversion);
                    input.dataset.autoConvertAdded = 'true';
                }
            });
        });
    });

    // 启动监听
    observer.observe(document.body, {
        childList: true,
        subtree: true,
        attributes: false,
        characterData: false
    });

    // 初始绑定(处理页面加载时已存在的元素)
    document.querySelectorAll(CONFIG.inputSelector).forEach(input => {
        input.addEventListener('input', handleInputConversion);
        input.dataset.autoConvertAdded = 'true';
    });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址