Greasy Fork

Greasy Fork is available in English.

一号店单价助手

一号店(yhd.com)单价助手,补全了商品列表中有些商品没标单价的信息,帮助你在1号店(yihaodian)找到最划算的商品

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         一号店单价助手
// @namespace    http://greasyfork.org/
// @version      1.01
// @description  一号店(yhd.com)单价助手,补全了商品列表中有些商品没标单价的信息,帮助你在1号店(yihaodian)找到最划算的商品
// @author       Yarmu
// @match        *://list.yhd.com/*
// @match        *://search.yhd.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @supportURL   http://greasyfork.org/zh-CN/users/41708-yarmu
// ==/UserScript==

(function() {
    var enabled = GM_getValue('yhd_price_tip_enabled', true);
    addListPriceButton(enabled);
    if (enabled) {
        addPriceTipListener('.proPrice', addListPriceTip, 1000);
    }
})();

function addPriceTipListener(tag, func, time) {
    var eachCallFunc = function() {
        $(tag).each(function() {
            if (!$(this).attr('priceTip')) {
                $(this).attr('priceTip', '1');
                func.call(this);
            }
        });
    };
    eachCallFunc();
    if (time) {
        setInterval(eachCallFunc, time);
    }
}

function addListPriceTip() {
    var infoItem = $(this).find('.num');
    if (infoItem.length === 0) infoItem = $(this).find('.price');
    var price = infoItem.attr('yhdprice');
    console.log(price);
    if (!price) return;

    var capacity = infoItem.attr('diapernum');
    var unitType = infoItem.attr('productunit');
    var unitItem = $(this).find('.unit_price');
    console.log([price, capacity, unitType, unitItem.length]);
    if (capacity && unitType && unitItem.length) return;

    var titleItem = $(this).parent().find('.proName a');
    if(titleItem.length === 0) titleItem = $(this).parent().find('.title a');
    var title = titleItem.text().trim();
    price = parseFloat(price);
    capacity = parseFloat(capacity);

    var unit;
    if (!isNaN(capacity) && capacity > 0 && unitType && unitItem.length === 0) {
        if (unitType == '4') {
            unitType = 'L';
            capacity /= 1000;
            price /= capacity;
        } else {
            unitType = '500g';
            capacity /= 500;
            price /= capacity;
        }
        unit = {
            price: Math.round(price * 100) / 100,
            capacity: Math.round(capacity * 10000) / 10000,
            unit: unitType
        };
    } else {
        unit = getUnit(title, price);
        if (unit === null) return;
    }

    var htm = '(¥' + unit.price + '/' + unit.unit + ')';
    if (unit.tip) {
        title = '( 助手估重: ' + unit.capacity + unit.unit + ' = ' + unit.tip + ' )\n' + title;
        titleItem.attr('title', title);
    }
    if (!unitItem.length) {
        unitItem = $('<span class="unit_price"></span>');
        $(this).append(unitItem);
    }
    unitItem.html(htm);
}

function addListPriceButton(isEnabled) {
    var button = $('#priceTipButton');
    if (button.length > 0) return;
    button = $('<a' + (isEnabled? ' class="cur"': '') + ' href="javascript:void(0);">单价助手</a>');
    $('.sort_b').append(button);
    button.click(function() {
        GM_setValue('yhd_price_tip_enabled', !isEnabled);
        $(this).attr('class', (!isEnabled? 'cur': ''));
        location.reload();
    });
}

function getUnit(title, price) {
    if (!title) return null;
    if (price <= 0) return null;

    //处理包含:和送的情况
    if (title.match(/:|[))】]送/)){
        var titles = title.split(/:|[))】]送/);
        for (var t=0; t<titles.length; ++t) {
            var res = getUnit(titles[t], price);
            if (res) return res;
        }
    }

    var regQuant = "个只瓶罐听桶提卷包袋件盒箱组副份盆盘碗支";
    var regWeigh = "g|kg|ml|l|千克|克|斤|公斤|毫升|升";
    var regFloat = "\\d+\\.?\\d*?(?:\\s*-\\s*\\d+\\.?\\d*?)?";
    //处理有总重量的情况
    var reg0 = new RegExp('(?:[总净]重量?约?|\\s约)\\s*('+regFloat+')\\s*('+regWeigh+')', 'g');
    var pos0 = {i: 0, pCap: 1, pUnit: 2, pCount: 3};
    //处理数量前置的情况
    var reg1 = new RegExp('(\\d+)\\s*['+regQuant+']?\\s*[*x×'+regQuant+']\\s*('+regFloat+')\\s*('+regWeigh+')', 'ig');
    var pos1 = {i: 1, pCap: 2, pUnit: 3, pCount: 1};
    //处理数量后置的情况
    var reg2 = new RegExp('('+regFloat+')\\s*('+regWeigh+')(?:\\s*\\/?[\\u4e00-\\u9fa5]*)((?:\\s*[*x×'+regQuant+']\\s*\\d+[\\u4e00-\\u9fa5]?)*)', 'ig');
    var pos2 = {i: 2, pCap: 1, pUnit: 2, pCount: 3};

    var reg, pos;
    //处理有括号的情况
    var name = title.replace(/[((【][^))】]+?(\)|)|】|$)/g, '');
    if (reg0.test(title)) {
        name = title; reg = reg0; pos = pos0;
    } else if (reg1.test(name)) {
        reg = reg1; pos = pos1;
    } else if (reg2.test(name)) {
        reg = reg2; pos = pos2;
    } else if (reg1.test(title)) {
        name = title; reg = reg1; pos = pos1;
    } else {
        name = title; reg = reg2; pos = pos2;
    }
    //处理套装的情况
    var isOnlyOne = !/[++送和]/i.test(name);

    var match = null;
    var cap = 0, count = 0, lastMul = 1;
    var un = '', tip = '';
    reg.lastIndex = 0;
    while ((match = reg.exec(name))) {
        var capacity;
        var caps = match[pos.pCap].split('-');
        if (caps.length == 2) {
            capacity = (parseFloat(caps[0].trim()) + parseFloat(caps[1].trim()))/2;
        } else {
            capacity = parseFloat(match[pos.pCap].trim());
        }
        if (match.length > 3 && match[pos.pCount]) {
            var multiple = match[pos.pCount].match(/\d+/g);
            if (multiple) for (var i=0; i<multiple.length; ++i) {
                lastMul = parseInt(multiple[i]);
                capacity *= lastMul;
            }
        }
        if (capacity <= 0) {
            continue;
        }
        var unit = match[pos.pUnit].toLowerCase();

        if (unit === 'g' || unit === '克') {
            capacity /= 500;
            unit = '500g';
        } else if (unit === 'kg' || unit === '千克' || unit === '公斤') {
            capacity *= 2;
            unit = '500g';
        } else if (unit === '斤') {
            //capacity /= 2;
            unit = '500g';
        } else if (unit === 'ml' || unit === '毫升') {
            capacity /= 1000;
            unit = 'L';
        } else if (unit === 'l' || unit === '升') {
            unit = 'L';
        }
        if (un === '' || un === unit) {
            //处理重复出现的情况
            if (isOnlyOne) {
                if (capacity > cap) {
                    tip = ''; cap = 0; count = 0;
                } else {
                    continue;
                }
            }
            un = unit;
            tip += match[0] + ' ';
            cap += capacity;
            ++count;
        }
    }

    //处理数量在其他位置的情况
    if (count == 1 && pos.i !== 0) {
        var regZhn = '两一二三四五六七八九十';
        var regMul = '(?:[^*x×满\\d])\\s*(\\d+|['+regZhn+'])['+regQuant+'](?!\\d+折|松)';
        reg = new RegExp(regMul, 'i');
        match = reg.exec(title);
        if (match) {
            var mul = regZhn.indexOf(match[1]);
            if (mul == -1) mul = parseInt(match[1]);
            else if (mul === 0) mul = 2;
            if (lastMul != mul) {
                cap *= mul;
                tip += match[0].substr(1, match[0].length-1).trim();
            }
        }
    }

    if (cap > 0) {
        var unitPrice = parseFloat(price) / cap;
        //如果单价>2000元或<0.5元,太大或太小不显示
        if (unitPrice > 2000 || unitPrice < 0.5) return null;
        else return {
            capacity: Math.round(cap * 10000) / 10000,
            unit: un,
            price: Math.round(unitPrice * 100) / 100,
            tip: tip.trim()
        };
    } else return null;
}