MIRPriceHelper

生产成本快速计算

// ==UserScript==
// @name         MIRPriceHelper
// @description  生产成本快速计算
// @namespace    mirror
// @version      0.2.4
// @author       玛吉卡帕瓦 - 柔风海湾
// @match        https://5p.nbbjack.com/
// @match        http://box.nbb.ffxiv.cn/
// @require      https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

// MARK: - 一些工具方法
    function ext_getValue(key, default_value) {
        let val = window.localStorage.getItem(key);
        if (val === undefined || val === null) {
            return default_value;
        }
        try {
            val = JSON.parse(val);
            if (val == '[]') {
                val = []
            }
            return val;
        } catch (err) {
            console.trace(err);
            return default_value;
        }
    }

    function ext_setValue(key, val) {
        return window.localStorage.setItem(key, JSON.stringify(val));
    }

    const delay = (t) => {
        return new Promise((r) => {
            setTimeout(()=>{
            r();
            }, t*1000)
        })
    }

    let queryMap = {};
    async function queryJSON(url) {
        if (!queryMap[url]) {
            const req = new Promise(async (resolve, reject) => {
                console.log(url);
                let tryCount = 0;
                const maximumTryCount = 5;
                while (1) {
                    tryCount ++;
                    try {
                        let res = await (await fetch(url)).json()
                        resolve(res)
                        return;
                    } catch (err) {
                        if (tryCount >= maximumTryCount) {
                            delete queryMap[url];
                            reject(new Error());
                            return;
                        } else {
                            await delay(1);
                        }
                    }
                }
            });
            queryMap[url] = req;
        }
        return queryMap[url];
    }

// MARK: - 查找物品信息相关 
    let itemNameMapItem = ext_getValue("mir.itemNameMapItem", {});  // 物品名与物品信息的map
    let itemIdMapItem = ext_getValue("mir.itemIdMapItem", {});  // 物品id与物品信息的map

    /// 通过物品名模糊查找物品信息
    /// 物品信息 { id, name, icon }
    async function queryItemsByName(itemName) {
        if (itemNameMapItem[itemName]) {
            return itemNameMapItem[itemName];   // 缓存命中
        }
        const api = `https://cafemaker.wakingsands.com/search?indexes=item&string=${itemName}`;
        const allList = (await queryJSON(api)).Results;
        let items = [];
        allList.forEach((item) => {
            let aItem = {
                'id': item.ID, 'name': item.Name, 'icon': `https://cafemaker.wakingsands.com${item.Icon}`
            };
            items.push(aItem);
            itemIdMapItem[item.ID] = aItem;
        });
        console.log(items);
        ext_setValue("mir.itemIdMapItem", itemIdMapItem);
        itemNameMapItem[itemName] = items;
        ext_setValue("mir.itemNameMapItem", itemNameMapItem);
        return items;
    }

    /// 通过物品id查找物品信息
    async function queryItemById(itemId) {
        if (itemIdMapItem[itemId]) {
            console.log(itemIdMapItem[itemId]);
            return itemIdMapItem[itemId];
        }
        const api = `https://cafemaker.wakingsands.com/item/${itemId}`;
        const dict = (await queryJSON(api));
        let item = {
            'id': itemId, 'name': dict.Name_chs, 'icon': `https://cafemaker.wakingsands.com${dict.Icon}`
        };
        console.log(item);
        itemIdMapItem[itemId] = item;
        ext_setValue("mir.itemIdMapItem", itemIdMapItem);
        itemNameMapItem[item.name] = item;
        ext_setValue("mir.itemNameMapItem", itemNameMapItem);
        return item;
    }   

// MARK: - 一些初始化信息
    let countryServerWorldMap = {
        "国服": {
            '猫小胖': ['紫水栈桥', '延夏', '静语庄园', '摩杜纳', '海猫茶屋', '柔风海湾', '琥珀原'],
            '莫古力': ['白银乡', '白金幻象', '神拳痕', '潮风亭', '旅人栈桥', '拂晓之间', '龙巢神殿', '梦羽宝境'],
            '陆行鸟': ['红玉海', '神意之地', '拉诺西亚', '幻影群岛', '萌芽池', '宇宙和音', '沃仙曦染', '晨曦王座'],
            '豆豆柴': ['水晶塔', '银泪湖', '太阳海岸', '伊修加德', '红茶川'],
        },
        "JP": {
            'Elemental': ['Aegis', 'Atomos', 'Carbuncle', 'Garuda', 'Gungnir', 'Kujata', 'Ramuh', 'Tonberry', 'Typhon', 'Unicorn'],
            'Gaia': ['Alexander', 'Bahamut', 'Durandal', 'Fenrir', 'Ifrit', 'Ridill', 'Tiamat', 'Ultima', 'Valefor', 'Yojimbo', 'Zeromus'],
            'Mana': ['Anima', 'Asura', 'Belias', 'Chocobo', 'Hades', 'Ixion', 'Mandragora', 'Masamune', 'Pandaemonium', 'Shinryu', 'Titan'],
        },
        "NA": {
            'Aether': ['Adamantoise', 'Balmung', 'Cactuar', 'Coeurl', 'Faerie', 'Gilgamesh', 'Goblin', 'Jenova', 'Mateus', 'Midgardsormr', 'Sargatanas', 'Siren', 'Zalera'],
            'Primal': ['Behemoth', 'Brynhildr', 'Diabolos', 'Excalibur', 'Exodus', 'Famfrit', 'Hyperion', 'Leviathan', 'Malboro', 'Ultros'],
        },
        "EU": {
            'Chaos': ['Cerberus', 'Lich', 'Louisoix', 'Moogle', 'Odin', 'Omega', 'Phoenix', 'Ragnarok', 'Shiva', 'Zodiark', 'Spriggan'],
        }
    }

    let worldAlias = {
        '白银乡': '银',
        '白金幻象': '金'
    }
    let countryName = ext_getValue('mir.countryName', '国服');
    let serverName = ext_getValue('mir.serverName', '猫小胖');
    let worldName = ext_getValue('mir.worldName', '柔风海湾');
    console.log(`${countryName} - ${serverName} - ${worldName}`)
    let proMode = ext_getValue('mir.proMode', false);
    let hasBeenProMode = ext_getValue('mir.hasBeenProMode', false);
    
// MARK: - 价格请求相关
    let apiMapList = ext_getValue("mir.apiMapList", {});
    const apiMapListCacheTime = 10*60*1000;   // 10min缓存时间
    let lastApiMapListClearTime = ext_getValue("mir.lastApiMapListClearTime", 0);
    function clearCache() {
        const keys = Object.keys(apiMapList);
        keys.forEach((key) => {
            let cacheList = apiMapList[key];
            if (new Date().getTime() - cacheList.timestamp >= apiMapListCacheTime) {
                delete apiMapList[key];
                console.log(`[cache] delete ${key}`);
            }
        });
        ext_setValue("mir.apiMapList", apiMapList);
    }
    setInterval(function() {
        const ts = new Date().getTime();
        if (ts - lastApiMapListClearTime >= apiMapListCacheTime) {
            lastApiMapListClearTime = ts;
            ext_setValue("mir.lastApiMapListClearTime", lastApiMapListClearTime);
            console.log(`[cache] clear ApiMapList`);
            clearCache();
        }
    }, 5000)

    async function queryPriceByItemId(itemId) {
        const items = await queryItemById(itemId);
        if (!items || items.length == 0) {
            return null;
        }
        // 请求api并处理数据
        async function __ppp(api) {
            const cacheKey = `${api}`;
            let cacheList = apiMapList[cacheKey];
            if (!cacheList || (new Date().getTime() - cacheList.timestamp >= apiMapListCacheTime)) {
                const allList = (await queryJSON(api));
                let cacheAllList = {};

                let cacheListings = [];
                allList.listings.forEach((item) => {
                    cacheListings.push({
                        'worldName': item.worldName,
                        'pricePerUnit': item.pricePerUnit,
                        'timestamp': item.lastReviewTime
                    });
                });
                cacheAllList.listings = cacheListings;
                
                let cacheRecentHistory = [];
                allList.recentHistory.forEach((item) => {
                    cacheRecentHistory.push({
                        'worldName': item.worldName,
                        'pricePerUnit': item.pricePerUnit,
                        'timestamp': item.timestamp
                    });
                });
                cacheAllList.recentHistory = cacheRecentHistory;
                
                apiMapList[cacheKey] = {
                    'cache': cacheAllList,
                    'timestamp': new Date().getTime()
                };
                ext_setValue("mir.apiMapList", apiMapList);
            }
            const allList = apiMapList[cacheKey].cache;
    
            let listingItems = [];
            let historyItems = [];
            let lowestItem = null;
            allList.listings.forEach((item) => {
                if (item.worldName === worldName) {
                    listingItems.push(item);
                }
                if (!lowestItem || lowestItem.pricePerUnit > item.pricePerUnit) {
                    lowestItem = item;
                }
            });
            allList.recentHistory.forEach((item) => {
                historyItems.push(item);
            });
            listingItems = listingItems.sort((a, b) => {return a.pricePerUnit - b.pricePerUnit});
            historyItems = historyItems.sort((a, b) => {return a.pricePerUnit - b.pricePerUnit});
            const price =  {
                "timestamp": new Date().getTime(),
                "itemId": itemId,
                "itemName": itemIdMapItem[itemId].name,
                "listing": listingItems,
                "history": historyItems,
                "lowest": lowestItem
            };
            return price;
        }

        if (!proMode) {
            const price = await __ppp(`https://universalis.app/api/v2/${serverName}/${itemId}?noGst=true`);
            return price;
        } else {
            const hqPrice = await __ppp(`https://universalis.app/api/v2/${serverName}/${itemId}?noGst=true&hq=true`);
            const nqPrice = await __ppp(`https://universalis.app/api/v2/${serverName}/${itemId}?noGst=true&hq=false`);
            const price =  {
                "timestamp": new Date().getTime(),
                "itemId": itemId,
                "itemName": itemIdMapItem[itemId].name,
                "hqListing": hqPrice.listing,
                "hpHistory": hqPrice.history,
                "hqLowest": hqPrice.lowest,
                "nqListing": nqPrice.listing,
                "npHistory": nqPrice.history,
                "nqLowest": nqPrice.lowest,
            };
            return price;
        }
    }

    async function queryPriceByItemName(itemName, accuracy=true) {
        const items = await queryItemsByName(itemName);
        if (!items || items.length == 0) {
            return null;
        }
        let item = items[0];
        if (accuracy) {
            for (let i = 0; i < items.length; ++i) {
                const ii = items[i];
                if (ii.name === itemName) {
                    item = ii;
                    break;
                }
            }
        }
        const price = await queryPriceByItemId(item.id);
        return price;
    }

    // 123,456,789 -> 123456789
    function formatMoney(num) {
        return num.replace(/,/g, '');
    }
    // 123456789 ->  123,456,789
    function formatMoney2(num) {
        return num.toString().replace(/\d{1,3}(?=(\d{3})+$)/g, function(s) { return s + "," }).replace(/^[^\$]\S+/, function(s) { return s });
    }

    if (window.location.href.indexOf('5p.nbbjack.com') > 0) {
            // 添加样式
        $('body').prepend(`
        <style>
        .mir-nav {
            margin: 2px 5px;
        }

        .mir-nav select{
            margin: 0 1px;
        }

        .mir-wrapper {
            color: #DED7BE;
            text-shadow: -1px 0 2px #795516, 0 1px 2px #795516, 1px 0 2px #795516, 0 -1px 2px #795516;
            font-family: "Meiryo";
            white-space: nowrap;
            margin: 0 5px;
        }

        .mir-simple-text-style {
            color: black;
            text-shadow: none;
        }

        .mir-price-wrapper {
            float: right;
        }

        .mir-price-content {
            float: right;
        }
        
        .mir-hq-price {

        }

        .mir-sum-wrapper {
            border-top: 1px solid #DED7BE;
            margin: 20px 0 0 0px;
            padding: 5px 5px 0 10px;
        }

        .mir-sum-wrapper li {
            margin: 3px 0;
        }

        .mir-sum-right {
            float: right;
        }

        .mir-sum-price {
            font-size: 14px;
            font-weight: bold;
        }
        </style>
        `);

        setInterval(() => {
            // 添加服务器选择的select
            if ($('.m-Content .mir-nav').length <= 0) {
                $('.m-Content').prepend(`<div class='mir-nav'><select class="mir-country-select"></select><select class="mir-server-select"></select><select class="mir-world-select"></select> 修改后请刷新网页:) </div>`);
                const wrapper = $('.m-Content .mir-nav');
                function makeCountrySelect() {
                    let html = '';
                    Object.keys(countryServerWorldMap).forEach(name => {
                        html += `<option value="${name}" ${(name == countryName) ?'selected="selected"' :''}>${name}</option>`;
                    });
                    wrapper.find('.mir-country-select').html(html);
                }

                function makeServerSelect() {
                    let html = '`<select class="mir-server-select">`';
                    Object.keys(countryServerWorldMap[countryName]).forEach(name => {
                        html += `<option value="${name}" ${(name == serverName) ?'selected="selected"' :''}>${name}</option>`;
                    });
                    wrapper.find('.mir-server-select').html(html);
                }

                function makeWorldSelect() {
                    let html = '';
                    countryServerWorldMap[countryName][serverName].forEach(name => {
                        html += `<option value="${name}" ${(name == worldName) ?'selected="selected"' :''}>${name}</option>`;
                    });
                    wrapper.find('.mir-world-select').html(html);
                }

                makeCountrySelect();
                makeServerSelect();
                makeWorldSelect();

                function onCountryChange() {
                    countryName = $('.mir-country-select').val();
                    ext_setValue('mir.countryName', countryName);
                    console.log(`${countryName}`);

                    makeServerSelect();
                    onServerChange();
                }

                function onServerChange() {
                    serverName = $('.mir-server-select').val();
                    ext_setValue('mir.serverName', serverName);
                    console.log(`${serverName}`);

                    makeWorldSelect();
                    onWorldChange();
                }

                function onWorldChange() {
                    worldName = $(".mir-world-select").val();
                    ext_setValue('mir.worldName', worldName);
                    console.log(`${worldName}`);
                }

                $(".mir-country-select").change(onCountryChange);
                $(".mir-server-select").change(onServerChange);
                $(".mir-world-select").change(onWorldChange);
            }

            if (window.location.href.indexOf('cal') >= 0) {
                // 在标题处添加说明
                const titleA = $('a').filter(function(){ return $(this).text()==='统计报表'; });
                if (!titleA.next().hasClass('mir-wrapper')) {
                    const title = `服务器最低丨全区最低(最低服务器缩写)`;
                    const proTitle = `服务器HQ最低丨全区HQ最低(缩写) | 服务器NQ最低丨全区NQ最低(缩写)`;
                    titleA.after(`<span class="mir-wrapper" style="margin: 0 10px"><span id="mir-title">${proMode ?proTitle :title}</span></span>
                    <span id="mir-pro-switch" class="ivu-switch ivu-switch-large ${proMode ?'ivu-switch-checked' :''}"><span class="ivu-switch-inner"><span>Pro</span></span></span>`);
                    $('#mir-pro-switch').click(function(){
                        proMode = !proMode;
                        ext_setValue('mir.proMode', proMode);
                        if (proMode) {
                            if (!hasBeenProMode) {
                                let alertText = "开启Pro模式后, 价格显示会变为\n";
                                alertText += "服务器HQ最低丨全区HQ最低(缩写) | 服务器NQ最低丨全区NQ最低(缩写)\n";
                                alertText += "开启Pro模式会使请求次数翻倍, 在网络不好的情况下请酌情开启\n";
                                alert(alertText);
                                hasBeenProMode = true;
                                ext_setValue('mir.hasBeenProMode', hasBeenProMode);
                            }
                            $(this).addClass('ivu-switch-checked');
                            $('#mir-title').text(proTitle);
                        } else {
                            $(this).removeClass('ivu-switch-checked');
                            $('#mir-title').text(title);
                        } 
                    });
                }
    
                // 在每个物品后面添加价格
                $('.ivu-modal-body .copyname').each(async function(){
                    const itemName = $(this).children('span').attr('title').split('\n')[2];
                    const identifier = `${itemName}-${proMode}`;
                    const parent = $(this).parents('li:first');
                    let wrapper = parent.find('.mir-price-wrapper');
                    if (wrapper.length > 0 && wrapper.attr('data-identifier') !== identifier) {
                        wrapper.remove();
                        wrapper = parent.find('.mir-price-wrapper');
                    }
                    let content = parent.find('.mir-price-content');
                    if (wrapper.length <= 0) {
                        if (!proMode) {
                            $(parent).append(`<div class="mir-wrapper mir-price-wrapper" data-identifier="${identifier}"><div class="mir-price-content"><span class="mir-world">...</span><span style="margin: 0 2px;">|</span><span class="mir-server">...</span></div><div style="clear: both;"></div></div>`);
                            wrapper = $(parent).find('.mir-price-wrapper');
                            content = parent.find('.mir-price-content');
                            queryPriceByItemName(itemName).then((price) => {
                                if (!price) {
                                    return;
                                }
                                if (price.listing && price.listing.length > 0) {
                                    wrapper.find('.mir-world').text(price.listing[0].pricePerUnit);
                                } else {
                                    wrapper.find('.mir-world').text('-');
                                }
                                if (price.lowest) {
                                    const lowestWorldName = price.lowest.worldName;
                                    const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                    wrapper.find('.mir-server').text(`${price.lowest.pricePerUnit}(${aliasName})`);
                                } else {
                                    wrapper.find('.mir-server').text('-');
                                }
                            });
                        } else {
                            $(parent).append(`
                            <div class="mir-wrapper mir-price-wrapper" data-identifier="${identifier}">
                                <div class="mir-price-content">
                                    <span class="mir-hq-price mir-world-hq">...</span>
                                    <span style="margin: 0 1px;">|</span>
                                    <span class="mir-hq-price mir-server-hq">...</span>
                                    <span style="margin: 0 1px;">|</span>
                                    <span class="mir-hq-price mir-world-nq">...</span>
                                    <span style="margin: 0 1px;">|</span>
                                    <span class="mir-hq-price mir-server-nq">...</span>
                                </div>
                                <div style="clear: both;"></div>
                            </div>`);
                            wrapper = $(parent).find('.mir-price-wrapper');
                            content = parent.find('.mir-price-content');
                            queryPriceByItemName(itemName).then((price) => {
                                console.log(price);
                                if (!price) {
                                    return;
                                }
                                if (price.hqListing && price.hqListing.length > 0) {
                                    wrapper.find('.mir-world-hq').text(`${price.hqListing[0].pricePerUnit}`);
                                } else {
                                    wrapper.find('.mir-world-hq').text('-');
                                }
                                if (price.nqListing && price.nqListing.length > 0) {
                                    wrapper.find('.mir-world-nq').text(`${price.nqListing[0].pricePerUnit}`);
                                } else {
                                    wrapper.find('.mir-world-nq').text('-');
                                }
                                if (price.hqLowest) {
                                    const lowestWorldName = price.hqLowest.worldName;
                                    const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                    wrapper.find('.mir-server-hq').text(`${price.hqLowest.pricePerUnit}(${aliasName})`);
                                } else { wrapper.find('.mir-server-hq').text('-'); }
                                if (price.nqLowest) {
                                    const lowestWorldName = price.nqLowest.worldName;
                                    const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                    wrapper.find('.mir-server-nq').text(`${price.nqLowest.pricePerUnit}(${aliasName})`);
                                } else { wrapper.find('.mir-server-nq').text('-'); }
                            });
                        }
                    };
    
                    if ($(this).parents('span')[1].offsetWidth + content.width() >= parent.width() - 30) {
                        wrapper.css('float', 'none');
                    } else {
                        wrapper.css('float', 'right');
                    }
    
                    if (!parent.hasClass('mir-item')) {
                        parent.addClass('mir-item');
                    }
                });
    
                // 添加统计数据
                $('.ivu-modal-body .treeview').children('ul').each(function(){
                    const identifier = `${proMode}`;
                    let wrapper = $(this).find('.mir-sum-wrapper');
                    if (wrapper.length > 0 && wrapper.attr('data-identifier') !== identifier) {
                        wrapper.remove();
                        wrapper = $(this).find('.mir-sum-wrapper');
                    }
    
                    if (!proMode) {
                        if (wrapper.length <= 0) {
                            $(this).append(`<div class="mir-wrapper mir-sum-wrapper" data-identifier="${identifier}">总计:
                                <div style="clear: both;"></div>
                                <ul>
                                    <li>
                                        本服: <div class="mir-sum-world mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div>
                                    </li>
                                    <li>
                                        全区: <div class="mir-sum-lowest mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div>
                                    </li>
                                </ul>
                                <div style="clear: both;"></div>
                            </div>`);
                        }
                        let worldSum = 0;
                        let worldNoCount = 0;
                        let serverSum = 0;
                        let serverNoCount = 0;
                        let itemCount = 0;
                        $(this).find('.mir-item').each(function(){
                            itemCount++;
                            let count = 1;
                            const countText = $(this).find('.copyname').parent().next().text();
                            if (countText.length > 0 && countText.indexOf('x') >= 0) {
                                count = parseInt(countText.substr(countText.indexOf('x') + 1));
                            }
                            $(this).find('.mir-world').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    worldNoCount ++; return;
                                }
                                worldSum += price * count;
                            });
                            $(this).find('.mir-server').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    serverNoCount ++; return;
                                }
                                serverSum += price * count;
                            });
                        });
    
                        if (itemCount > 0) {
                            wrapper.show();
                            $(wrapper).find('.mir-sum-world .mir-sum-price').text(`${formatMoney2(worldSum)}`);
                            $(wrapper).find('.mir-sum-world .mir-sum-supplement').text(`${worldNoCount > 0 ?` (${worldNoCount}项无记录)` :''}`);
                            $(wrapper).find('.mir-sum-lowest .mir-sum-price').text(`${formatMoney2(serverSum)}`);
                            $(wrapper).find('.mir-sum-lowest .mir-sum-supplement').text(`${serverNoCount > 0 ?` (${serverNoCount}项无记录)` :''}`);
                        } else {
                            wrapper.hide();
                        }
                    } else {
                        if (wrapper.length <= 0) {
                            $(this).append(`<div class="mir-wrapper mir-sum-wrapper" data-identifier="${identifier}">总计:
                                <div style="clear: both;"></div>
                                <ul>
                                    <li>本服HQ: <div class="mir-sum-world-hq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                    <li>全区HQ: <div class="mir-sum-lowest-hq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                    <li>本服NQ: <div class="mir-sum-world-nq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                    <li>全区NQ: <div class="mir-sum-lowest-nq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                </ul>
                                <div style="clear: both;"></div>
                            </div>`);
                        }
                        let worldHQSum = 0;
                        let worldHQNoCount = 0;
                        let serverHQSum = 0;
                        let serverHQNoCount = 0;
                        let worldNQSum = 0;
                        let worldNQNoCount = 0;
                        let serverNQSum = 0;
                        let serverNQNoCount = 0;
                        let itemCount = 0;
                        $(this).find('.mir-item').each(function(){
                            itemCount++;
                            let count = 1;
                            const countText = $(this).find('.copyname').parent().next().text();
                            if (countText.length > 0 && countText.indexOf('x') >= 0) {
                                count = parseInt(countText.substr(countText.indexOf('x') + 1));
                            }
                            $(this).find('.mir-world-hq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    worldHQNoCount ++; 
                                    return;
                                }
                                worldHQSum += price * count;
                            });
                            $(this).find('.mir-server-hq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    serverHQNoCount ++; return;
                                }
                                serverHQSum += price * count;
                            });
                            $(this).find('.mir-world-nq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    worldNQNoCount ++; return;
                                }
                                worldNQSum += price * count;
                            });
                            $(this).find('.mir-server-nq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    serverNQNoCount ++; return;
                                }
                                serverNQSum += price * count;
                            });
                        });
    
                        if (itemCount > 0) {
                            wrapper.show();
                            $(wrapper).find('.mir-sum-world-hq .mir-sum-price').text(`${formatMoney2(worldHQSum)}`);
                            $(wrapper).find('.mir-sum-world-hq .mir-sum-supplement').text(`${worldHQNoCount > 0 ?` (${worldHQNoCount}项无记录)` :''}`);
                            $(wrapper).find('.mir-sum-lowest-hq .mir-sum-price').text(`${formatMoney2(serverHQSum)}`);
                            $(wrapper).find('.mir-sum-lowest-hq .mir-sum-supplement').text(`${serverHQNoCount > 0 ?` (${serverHQNoCount}项无记录)` :''}`);
    
                            $(wrapper).find('.mir-sum-world-nq .mir-sum-price').text(`${formatMoney2(worldNQSum)}`);
                            $(wrapper).find('.mir-sum-world-nq .mir-sum-supplement').text(`${worldNQNoCount > 0 ?` (${worldNQNoCount}项无记录)` :''}`);
                            $(wrapper).find('.mir-sum-lowest-nq .mir-sum-price').text(`${formatMoney2(serverNQSum)}`);
                            $(wrapper).find('.mir-sum-lowest-nq .mir-sum-supplement').text(`${serverNQNoCount > 0 ?` (${serverNQNoCount}项无记录)` :''}`);
                        } else {
                            wrapper.hide();
                        }
                    }
                });
            } else if (window.location.href.indexOf('workshop') >= 0) {
                // 在标题处添加说明
                const headerInfo = $('p').filter(function(){ return $(this).text()==='潜艇模拟器'; });
                if (!headerInfo.next().hasClass('mir-wrapper')) {
                    const title = `服务器最低丨全区最低(最低服务器缩写)`;
                    const proTitle = `服务器HQ最低丨全区HQ最低(缩写) | 服务器NQ最低丨全区NQ最低(缩写)`;
                    headerInfo.after(`<span class="mir-wrapper mir-simple-text-style" style="margin:0;"><span id="mir-title">${proMode ?proTitle :title}</span></span>
                    <span id="mir-pro-switch" class="ivu-switch ivu-switch-large ${proMode ?'ivu-switch-checked' :''}"><span class="ivu-switch-inner"><span>Pro</span></span></span>`);
                    $('#mir-pro-switch').click(function(){
                        proMode = !proMode;
                        ext_setValue('mir.proMode', proMode);
                        if (proMode) {
                            if (!hasBeenProMode) {
                                let alertText = "开启Pro模式后, 价格显示会变为\n";
                                alertText += "服务器HQ最低丨全区HQ最低(缩写) | 服务器NQ最低丨全区NQ最低(缩写)\n";
                                alertText += "开启Pro模式会使请求次数翻倍, 在网络不好的情况下请酌情开启\n";
                                alert(alertText);
                                hasBeenProMode = true;
                                ext_setValue('mir.hasBeenProMode', hasBeenProMode);
                            }
                            $(this).addClass('ivu-switch-checked');
                            $('#mir-title').text(proTitle);
                        } else {
                            $(this).removeClass('ivu-switch-checked');
                            $('#mir-title').text(title);
                        } 
                    });
                }
    
                // 在每个物品后面添加价格
                $('.treeview .copyname').each(async function(){
                    const itemName = $(this).children('span').attr('title').split('\n')[2];
                    const identifier = `${itemName}-${proMode}`;
                    const parent = $(this).parents('li:first');
                    let wrapper = parent.find('.mir-price-wrapper');
                    if (wrapper.length > 0 && wrapper.attr('data-identifier') !== identifier) {
                        wrapper.remove();
                        wrapper = parent.find('.mir-price-wrapper');
                    }
                    let content = parent.find('.mir-price-content');
                    if (wrapper.length <= 0) {
                        if (!proMode) {
                            $(parent).append(`<div class="mir-wrapper mir-simple-text-style mir-price-wrapper" data-identifier="${identifier}"><div class="mir-price-content"><span class="mir-world">...</span><span style="margin: 0 2px;">|</span><span class="mir-server">...</span></div><div style="clear: both;"></div></div>`);
                            wrapper = $(parent).find('.mir-price-wrapper');
                            content = parent.find('.mir-price-content');
                            queryPriceByItemName(itemName).then((price) => {
                                if (!price) {
                                    return;
                                }
                                if (price.listing && price.listing.length > 0) {
                                    wrapper.find('.mir-world').text(price.listing[0].pricePerUnit);
                                } else {
                                    wrapper.find('.mir-world').text('-');
                                }
                                if (price.lowest) {
                                    const lowestWorldName = price.lowest.worldName;
                                    const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                    wrapper.find('.mir-server').text(`${price.lowest.pricePerUnit}(${aliasName})`);
                                } else {
                                    wrapper.find('.mir-server').text('-');
                                }
                            });
                        } else {
                            $(parent).append(`
                            <div class="mir-wrapper mir-simple-text-style mir-price-wrapper" data-identifier="${identifier}">
                                <div class="mir-price-content">
                                    <span class="mir-hq-price mir-world-hq">...</span>
                                    <span style="margin: 0 1px;">|</span>
                                    <span class="mir-hq-price mir-server-hq">...</span>
                                    <span style="margin: 0 1px;">|</span>
                                    <span class="mir-hq-price mir-world-nq">...</span>
                                    <span style="margin: 0 1px;">|</span>
                                    <span class="mir-hq-price mir-server-nq">...</span>
                                </div>
                                <div style="clear: both;"></div>
                            </div>`);
                            wrapper = $(parent).find('.mir-price-wrapper');
                            content = parent.find('.mir-price-content');
                            queryPriceByItemName(itemName).then((price) => {
                                console.log(price);
                                if (!price) {
                                    return;
                                }
                                if (price.hqListing && price.hqListing.length > 0) {
                                    wrapper.find('.mir-world-hq').text(`${price.hqListing[0].pricePerUnit}`);
                                } else {
                                    wrapper.find('.mir-world-hq').text('-');
                                }
                                if (price.nqListing && price.nqListing.length > 0) {
                                    wrapper.find('.mir-world-nq').text(`${price.nqListing[0].pricePerUnit}`);
                                } else {
                                    wrapper.find('.mir-world-nq').text('-');
                                }
                                if (price.hqLowest) {
                                    const lowestWorldName = price.hqLowest.worldName;
                                    const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                    wrapper.find('.mir-server-hq').text(`${price.hqLowest.pricePerUnit}(${aliasName})`);
                                } else { wrapper.find('.mir-server-hq').text('-'); }
                                if (price.nqLowest) {
                                    const lowestWorldName = price.nqLowest.worldName;
                                    const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                    wrapper.find('.mir-server-nq').text(`${price.nqLowest.pricePerUnit}(${aliasName})`);
                                } else { wrapper.find('.mir-server-nq').text('-'); }
                            });
                        }
                    };
    
                    // if ($(this).parents('span')[1].offsetWidth + content.width() >= parent.width() - 80) {
                    //     wrapper.css('float', 'none');
                    // } else {
                    //     wrapper.css('float', 'right');
                    // }
                    wrapper.css('float', 'none');
    
                    if (!parent.hasClass('mir-item')) {
                        parent.addClass('mir-item');
                    }
                });
    
                // 添加统计数据
                $('.treeview').children('ul').each(function(){
                    const identifier = `${proMode}`;
                    let wrapper = $(this).find('.mir-sum-wrapper');
                    if (wrapper.length > 0 && wrapper.attr('data-identifier') !== identifier) {
                        wrapper.remove();
                        wrapper = $(this).find('.mir-sum-wrapper');
                    }
    
                    if (!proMode) {
                        if (wrapper.length <= 0) {
                            $(this).append(`<div class="mir-wrapper mir-simple-text-style mir-sum-wrapper" data-identifier="${identifier}">总计:
                                <div style="clear: both;"></div>
                                <ul>
                                    <li>本服: <div class="mir-sum-world mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                    <div style="clear: both;"></div>
                                    <li>全区: <div class="mir-sum-lowest mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                </ul>
                                <div style="clear: both;"></div>
                            </div>`);
                        }
                        let worldSum = 0;
                        let worldNoCount = 0;
                        let serverSum = 0;
                        let serverNoCount = 0;
                        let itemCount = 0;
                        $(this).find('.mir-item').each(function(){
                            itemCount++;
                            let count = 1;
                            const countText = $(this).find('.copyname').parent().next().text();
                            if (countText.length > 0 && countText.indexOf('x') >= 0) {
                                count = parseInt(countText.substr(countText.indexOf('x') + 1));
                            }
                            $(this).find('.mir-world').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    worldNoCount ++; return;
                                }
                                worldSum += price * count;
                            });
                            $(this).find('.mir-server').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    serverNoCount ++; return;
                                }
                                serverSum += price * count;
                            });
                        });
    
                        if (itemCount > 0) {
                            wrapper.show();
                            $(wrapper).find('.mir-sum-world .mir-sum-price').text(`${formatMoney2(worldSum)}`);
                            $(wrapper).find('.mir-sum-world .mir-sum-supplement').text(`${worldNoCount > 0 ?` (${worldNoCount}项无记录)` :''}`);
                            $(wrapper).find('.mir-sum-lowest .mir-sum-price').text(`${formatMoney2(serverSum)}`);
                            $(wrapper).find('.mir-sum-lowest .mir-sum-supplement').text(`${serverNoCount > 0 ?` (${serverNoCount}项无记录)` :''}`);
                        } else {
                            wrapper.hide();
                        }
                    } else {
                        if (wrapper.length <= 0) {
                            $(this).append(`<div class="mir-wrapper mir-simple-text-style mir-sum-wrapper" data-identifier="${identifier}">总计:
                                <div style="clear: both;"></div>
                                <ul>
                                    <li>本服HQ: <div class="mir-sum-world-hq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                    <div style="clear: both;"></div>
                                    <li>全区HQ: <div class="mir-sum-lowest-hq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                    <div style="clear: both;"></div>
                                    <li>本服NQ: <div class="mir-sum-world-nq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                    <div style="clear: both;"></div>
                                    <li>全区NQ: <div class="mir-sum-lowest-nq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                </ul>
                                <div style="clear: both;"></div>
                            </div>`);
                        }
                        let worldHQSum = 0;
                        let worldHQNoCount = 0;
                        let serverHQSum = 0;
                        let serverHQNoCount = 0;
                        let worldNQSum = 0;
                        let worldNQNoCount = 0;
                        let serverNQSum = 0;
                        let serverNQNoCount = 0;
                        let itemCount = 0;
                        $(this).find('.mir-item').each(function(){
                            itemCount++;
                            let count = 1;
                            const countText = $(this).find('.copyname').parent().next().text();
                            if (countText.length > 0 && countText.indexOf('x') >= 0) {
                                count = parseInt(countText.substr(countText.indexOf('x') + 1));
                            }
                            $(this).find('.mir-world-hq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    worldHQNoCount ++; 
                                    return;
                                }
                                worldHQSum += price * count;
                            });
                            $(this).find('.mir-server-hq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    serverHQNoCount ++; return;
                                }
                                serverHQSum += price * count;
                            });
                            $(this).find('.mir-world-nq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    worldNQNoCount ++; return;
                                }
                                worldNQSum += price * count;
                            });
                            $(this).find('.mir-server-nq').each((_, elem) => {
                                const price = parseInt($(elem).text());
                                if (isNaN(price)) {
                                    serverNQNoCount ++; return;
                                }
                                serverNQSum += price * count;
                            });
                        });
    
                        if (itemCount > 0) {
                            wrapper.show();
                            $(wrapper).find('.mir-sum-world-hq .mir-sum-price').text(`${formatMoney2(worldHQSum)}`);
                            $(wrapper).find('.mir-sum-world-hq .mir-sum-supplement').text(`${worldHQNoCount > 0 ?` (${worldHQNoCount}项无记录)` :''}`);
                            $(wrapper).find('.mir-sum-lowest-hq .mir-sum-price').text(`${formatMoney2(serverHQSum)}`);
                            $(wrapper).find('.mir-sum-lowest-hq .mir-sum-supplement').text(`${serverHQNoCount > 0 ?` (${serverHQNoCount}项无记录)` :''}`);
    
                            $(wrapper).find('.mir-sum-world-nq .mir-sum-price').text(`${formatMoney2(worldNQSum)}`);
                            $(wrapper).find('.mir-sum-world-nq .mir-sum-supplement').text(`${worldNQNoCount > 0 ?` (${worldNQNoCount}项无记录)` :''}`);
                            $(wrapper).find('.mir-sum-lowest-nq .mir-sum-price').text(`${formatMoney2(serverNQSum)}`);
                            $(wrapper).find('.mir-sum-lowest-nq .mir-sum-supplement').text(`${serverNQNoCount > 0 ?` (${serverNQNoCount}项无记录)` :''}`);
                        } else {
                            wrapper.hide();
                        }
                    }
                });
            }
        }, 1000);
    } else if (window.location.href.indexOf('box.nbb.ffxiv.cn') > 0) {
        $('body').prepend(`
        <style>
        .mir-nav {
            margin: 2px 5px;
        }

        .mir-nav select{
            background-color: #50b38a;
            text-shadow: -1px 0 2px #795516, 0 1px 2px #795516, 1px 0 2px #795516, 0 -1px 2px #795516;
            margin: 0 1px;
        }

        .mir-wrapper {
            color: #DED7BE;
            text-shadow: -1px 0 2px #795516, 0 1px 2px #795516, 1px 0 2px #795516, 0 -1px 2px #795516;
            font-family: "Meiryo";
            white-space: nowrap;
            margin: 0 5px;
        }

        .mir-switch {
            margin: 5px;
            height: 22px;
            line-height: 20px;
            border-radius: 22px;
            vertical-align: middle;
            border: 1px solid #ccc;
            background-color: #ccc;
            cursor: pointer;
        }

        .mir-switch-checked {
            background-color: #50b38a
        }

        .mir-switch-inner {
            color: #fff;
            font-size: 12px;
            text-align: center;
            margin: 10px;
        }        

        .mir-price-wrapper {
            /* float: right; */
        }

        .mir-price-content {
            float: right;
        }
        
        .mir-hq-price {

        }

        .mir-sum-wrapper {
            border-top: 1px solid #DED7BE;
            margin: 20px 0 0 0px;
            padding: 5px 5px 0 10px;
        }

        .mir-sum-wrapper li {
            margin: 3px 0;
        }

        .mir-sum-right {
            float: right;
        }

        .mir-sum-price {
            font-size: 14px;
            font-weight: bold;
        }
        </style>
        `);

        setInterval(() => {
            // 添加服务器选择的select
            if ($('.mir-nav').length <= 0) {
                $('.ant-layout-content').prepend(`<div class='mir-nav'><select class="mir-country-select"></select><select class="mir-server-select"></select><select class="mir-world-select"></select> 修改后请刷新网页:) </div>`);
                const wrapper = $('.mir-nav');
                function makeCountrySelect() {
                    let html = '';
                    Object.keys(countryServerWorldMap).forEach(name => {
                        html += `<option value="${name}" ${(name == countryName) ?'selected="selected"' :''}>${name}</option>`;
                    });
                    wrapper.find('.mir-country-select').html(html);
                }

                function makeServerSelect() {
                    let html = '`<select class="mir-server-select">`';
                    Object.keys(countryServerWorldMap[countryName]).forEach(name => {
                        html += `<option value="${name}" ${(name == serverName) ?'selected="selected"' :''}>${name}</option>`;
                    });
                    wrapper.find('.mir-server-select').html(html);
                }

                function makeWorldSelect() {
                    let html = '';
                    countryServerWorldMap[countryName][serverName].forEach(name => {
                        html += `<option value="${name}" ${(name == worldName) ?'selected="selected"' :''}>${name}</option>`;
                    });
                    wrapper.find('.mir-world-select').html(html);
                }

                makeCountrySelect();
                makeServerSelect();
                makeWorldSelect();

                function onCountryChange() {
                    countryName = $('.mir-country-select').val();
                    ext_setValue('mir.countryName', countryName);
                    console.log(`${countryName}`);

                    makeServerSelect();
                    onServerChange();
                }

                function onServerChange() {
                    serverName = $('.mir-server-select').val();
                    ext_setValue('mir.serverName', serverName);
                    console.log(`${serverName}`);

                    makeWorldSelect();
                    onWorldChange();
                }

                function onWorldChange() {
                    worldName = $(".mir-world-select").val();
                    ext_setValue('mir.worldName', worldName);
                    console.log(`${worldName}`);
                }

                $(".mir-country-select").on('change', onCountryChange);
                $(".mir-server-select").on('change', onServerChange);
                $(".mir-world-select").on('change', onWorldChange);
            }

            // 在标题处添加说明
            const titleA = $('.mir-nav');
            if (!titleA.next().hasClass('mir-wrapper')) {
                const title = `服务器最低丨全区最低(最低服务器缩写)`;
                const proTitle = `服务器HQ最低丨全区HQ最低(缩写) | 服务器NQ最低丨全区NQ最低(缩写)`;
                titleA.after(`<span class="mir-wrapper" style="margin: 0 5px"><span id="mir-pro-switch" class="mir-switch ${proMode ?'mir-switch-checked' :''}"><span class="mir-switch-inner"><span>Pro</span></span></span><span id="mir-title">${proMode ?proTitle :title}</span></span>
                <div style="height:2px"></div>`);
                $('#mir-pro-switch').on('click', function(){
                    proMode = !proMode;
                    ext_setValue('mir.proMode', proMode);
                    if (proMode) {
                        if (!hasBeenProMode) {
                            let alertText = "开启Pro模式后, 价格显示会变为\n";
                            alertText += "服务器HQ最低丨全区HQ最低(缩写) | 服务器NQ最低丨全区NQ最低(缩写)\n";
                            alertText += "开启Pro模式会使请求次数翻倍, 在网络不好的情况下请酌情开启\n";
                            alert(alertText);
                            hasBeenProMode = true;
                            ext_setValue('mir.hasBeenProMode', hasBeenProMode);
                        }
                        $(this).addClass('mir-switch-checked');
                        $('#mir-title').text(proTitle);
                    } else {
                        $(this).removeClass('mir-switch-checked');
                        $('#mir-title').text(title);
                    } 
                });
            }

            // 在每个物品后面添加价格
            $('.nbb-tree .craft-item').each(async function(){
                const itemId = $(this).attr('data-id');
                const identifier = `${itemId}-${proMode}`;
                const parent = $(this).parent();
                let wrapper = parent.find('.mir-price-wrapper');
                if (wrapper.length > 0 && wrapper.attr('data-identifier') !== identifier) {
                    wrapper.remove();
                    wrapper = parent.find('.mir-price-wrapper');
                }
                let content = parent.find('.mir-price-content');
                if (wrapper.length <= 0) {
                    if (!proMode) {
                        $(parent).append(`<div class="mir-wrapper mir-price-wrapper" data-identifier="${identifier}"><div class="mir-price-content"><span class="mir-world">...</span><span style="margin: 0 2px;">|</span><span class="mir-server">...</span></div><div style="clear: both;"></div></div>`);
                        wrapper = $(parent).find('.mir-price-wrapper');
                        content = parent.find('.mir-price-content');
                        queryPriceByItemId(itemId).then((price) => {
                            if (!price) {
                                return;
                            }
                            if (price.listing && price.listing.length > 0) {
                                wrapper.find('.mir-world').text(price.listing[0].pricePerUnit);
                            } else {
                                wrapper.find('.mir-world').text('-');
                            }
                            if (price.lowest) {
                                const lowestWorldName = price.lowest.worldName;
                                const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                wrapper.find('.mir-server').text(`${price.lowest.pricePerUnit}(${aliasName})`);
                            } else {
                                wrapper.find('.mir-server').text('-');
                            }
                        });
                    } else {
                        $(parent).append(`<div class="mir-wrapper mir-price-wrapper" data-identifier="${identifier}">
                            <div class="mir-price-content">
                                <span class="mir-hq-price mir-world-hq">...</span>
                                <span style="margin: 0 1px;">|</span>
                                <span class="mir-hq-price mir-server-hq">...</span>
                                <span style="margin: 0 1px;">|</span>
                                <span class="mir-hq-price mir-world-nq">...</span>
                                <span style="margin: 0 1px;">|</span>
                                <span class="mir-hq-price mir-server-nq">...</span>
                            </div>
                            </div>
                            <div style="clear: both;"></div>
                        </div>`);
                        wrapper = $(parent).find('.mir-price-wrapper');
                        content = parent.find('.mir-price-content');
                        queryPriceByItemId(itemId).then((price) => {
                            console.log(price);
                            if (!price) {
                                return;
                            }
                            if (price.hqListing && price.hqListing.length > 0) {
                                wrapper.find('.mir-world-hq').text(`${price.hqListing[0].pricePerUnit}`);
                            } else {
                                wrapper.find('.mir-world-hq').text('-');
                            }
                            if (price.nqListing && price.nqListing.length > 0) {
                                wrapper.find('.mir-world-nq').text(`${price.nqListing[0].pricePerUnit}`);
                            } else {
                                wrapper.find('.mir-world-nq').text('-');
                            }
                            if (price.hqLowest) {
                                const lowestWorldName = price.hqLowest.worldName;
                                const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                wrapper.find('.mir-server-hq').text(`${price.hqLowest.pricePerUnit}(${aliasName})`);
                            } else { wrapper.find('.mir-server-hq').text('-'); }
                            if (price.nqLowest) {
                                const lowestWorldName = price.nqLowest.worldName;
                                const aliasName = worldAlias[lowestWorldName] ?? lowestWorldName.substr(0, countryName === '国服' ?1 :3);
                                wrapper.find('.mir-server-nq').text(`${price.nqLowest.pricePerUnit}(${aliasName})`);
                            } else { wrapper.find('.mir-server-nq').text('-'); }
                        });
                    }
                };

                // if ($(this).parents('span')[1].offsetWidth + content.width() >= parent.width() - 30) {
                //     wrapper.css('float', 'none');
                // } else {
                //     wrapper.css('float', 'right');
                // }

                if (!parent.hasClass('mir-item')) {
                    parent.addClass('mir-item');
                }
            });

            // 添加统计数据
            $('.nbb-tree').each(function(){
                const identifier = `${proMode}`;
                let wrapper = $(this).find('.mir-sum-wrapper');
                if (wrapper.length > 0 && ($(this).children()[0] != wrapper[0] || wrapper.attr('data-identifier') !== identifier)) {
                    wrapper.remove();
                    wrapper = $(this).find('.mir-sum-wrapper');
                }

                if (!proMode) {
                    if (wrapper.length <= 0) {
                        $(this).prepend(`<div class="mir-wrapper mir-sum-wrapper" data-identifier="${identifier}">总计:
                            <div style="clear: both;"></div>
                            <ul>
                                <li>
                                    本服: <div class="mir-sum-world mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div>
                                </li>
                                <li>
                                    全区: <div class="mir-sum-lowest mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div>
                                </li>
                            </ul>
                            <div style="clear: both;"></div>
                        </div>`);
                        wrapper = $(this).find('.mir-sum-wrapper');
                        wrapper.hide();
                    }
                    let worldSum = 0;
                    let worldNoCount = 0;
                    let serverSum = 0;
                    let serverNoCount = 0;
                    let itemCount = 0;
                    $(this).find('.mir-item').each(function(){
                        itemCount++;
                        let count = 1;
                        const countText = $(this).find('.craft-item-need').text();
                        let m = countText.match('x ([0-9]+) ');
                        if (m) {
                            count = parseInt(m[1]);
                        }
                        $(this).find('.mir-world').each((_, elem) => {
                            const price = parseInt($(elem).text());
                            if (isNaN(price)) {
                                worldNoCount ++; return;
                            }
                            worldSum += price * count;
                        });
                        $(this).find('.mir-server').each((_, elem) => {
                            const price = parseInt($(elem).text());
                            if (isNaN(price)) {
                                serverNoCount ++; return;
                            }
                            serverSum += price * count;
                        });
                    });

                    if (itemCount > 0) {
                        wrapper.show();
                        $(wrapper).find('.mir-sum-world .mir-sum-price').text(`${formatMoney2(worldSum)}`);
                        $(wrapper).find('.mir-sum-world .mir-sum-supplement').text(`${worldNoCount > 0 ?` (${worldNoCount}项无记录)` :''}`);
                        $(wrapper).find('.mir-sum-lowest .mir-sum-price').text(`${formatMoney2(serverSum)}`);
                        $(wrapper).find('.mir-sum-lowest .mir-sum-supplement').text(`${serverNoCount > 0 ?` (${serverNoCount}项无记录)` :''}`);
                    } else {
                        wrapper.hide();
                    }
                } else {
                    if (wrapper.length <= 0) {
                        $(this).prepend(`<div class="mir-wrapper mir-sum-wrapper" data-identifier="${identifier}">总计:
                            <div style="clear: both;"></div>
                            <ul>
                                <li>本服HQ: <div class="mir-sum-world-hq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                <li>全区HQ: <div class="mir-sum-lowest-hq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                <li>本服NQ: <div class="mir-sum-world-nq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                                <li>全区NQ: <div class="mir-sum-lowest-nq mir-sum-right"><span class="mir-sum-supplement"></span><span class="mir-sum-price"></span></div></li>
                            </ul>
                            <div style="clear: both;"></div>
                        </div>`);
                        wrapper = $(this).find('.mir-sum-wrapper');
                        wrapper.hide();
                    }
                    let worldHQSum = 0;
                    let worldHQNoCount = 0;
                    let serverHQSum = 0;
                    let serverHQNoCount = 0;
                    let worldNQSum = 0;
                    let worldNQNoCount = 0;
                    let serverNQSum = 0;
                    let serverNQNoCount = 0;
                    let itemCount = 0;
                    $(this).find('.mir-item').each(function(){
                        itemCount++;
                        let count = 1;
                        const countText = $(this).find('.craft-item-need').text();
                        let m = countText.match('x ([0-9]+) ');
                        if (m) {
                            count = parseInt(m[1]);
                        }
                        $(this).find('.mir-world-hq').each((_, elem) => {
                            const price = parseInt($(elem).text());
                            if (isNaN(price)) {
                                worldHQNoCount ++; 
                                return;
                            }
                            worldHQSum += price * count;
                        });
                        $(this).find('.mir-server-hq').each((_, elem) => {
                            const price = parseInt($(elem).text());
                            if (isNaN(price)) {
                                serverHQNoCount ++; return;
                            }
                            serverHQSum += price * count;
                        });
                        $(this).find('.mir-world-nq').each((_, elem) => {
                            const price = parseInt($(elem).text());
                            if (isNaN(price)) {
                                worldNQNoCount ++; return;
                            }
                            worldNQSum += price * count;
                        });
                        $(this).find('.mir-server-nq').each((_, elem) => {
                            const price = parseInt($(elem).text());
                            if (isNaN(price)) {
                                serverNQNoCount ++; return;
                            }
                            serverNQSum += price * count;
                        });
                    });

                    if (itemCount > 0) {
                        wrapper.show();
                        $(wrapper).find('.mir-sum-world-hq .mir-sum-price').text(`${formatMoney2(worldHQSum)}`);
                        $(wrapper).find('.mir-sum-world-hq .mir-sum-supplement').text(`${worldHQNoCount > 0 ?` (${worldHQNoCount}项无记录)` :''}`);
                        $(wrapper).find('.mir-sum-lowest-hq .mir-sum-price').text(`${formatMoney2(serverHQSum)}`);
                        $(wrapper).find('.mir-sum-lowest-hq .mir-sum-supplement').text(`${serverHQNoCount > 0 ?` (${serverHQNoCount}项无记录)` :''}`);

                        $(wrapper).find('.mir-sum-world-nq .mir-sum-price').text(`${formatMoney2(worldNQSum)}`);
                        $(wrapper).find('.mir-sum-world-nq .mir-sum-supplement').text(`${worldNQNoCount > 0 ?` (${worldNQNoCount}项无记录)` :''}`);
                        $(wrapper).find('.mir-sum-lowest-nq .mir-sum-price').text(`${formatMoney2(serverNQSum)}`);
                        $(wrapper).find('.mir-sum-lowest-nq .mir-sum-supplement').text(`${serverNQNoCount > 0 ?` (${serverNQNoCount}项无记录)` :''}`);
                    } else {
                        wrapper.hide();
                    }
                }
            });
        }, 1000);
    }
   
})();