Greasy Fork

Greasy Fork is available in English.

[银河奶牛]自用脚本

个人专用脚本,适用于 Milky Way Idle 游戏

// ==UserScript==
// @name         [MWI]personal use
// @name:zh-CN   [银河奶牛]自用脚本
// @namespace    http://tampermonkey.net/
// @version      0.1.14
// @description  个人脚本,适用于 Milky Way Idle 游戏
// @description:zh-CN 个人专用脚本,适用于 Milky Way Idle 游戏
// @author       deric
// @license      MIT
// @match        https://www.milkywayidle.com/game*
// @grant        GM_registerMenuCommand
// ==/UserScript==

(function() {
    'use strict';
    const MWI_SCRIPT_VERSION = (typeof GM_info !== 'undefined' && GM_info.script && GM_info.script.version) ? GM_info.script.version : 'unknown';
    function showSettingPanel() {
        let exist = document.getElementById('mwiSettingPopup');
        if (exist) exist.remove();
        const popup = document.createElement('div');
        popup.id = 'mwiSettingPopup';
        popup.style.position = 'fixed';
        popup.style.top = '120px';
        popup.style.left = '50%';
        popup.style.transform = 'translateX(-50%)';
        popup.style.background = 'white';
        popup.style.border = '2px solid #888';
        popup.style.boxShadow = '0 2px 12px rgba(0,0,0,0.2)';
        popup.style.zIndex = 99999;
        popup.style.padding = '24px 32px';
        popup.style.minWidth = '300px';
        popup.innerHTML = `<div style='text-align:right;'><button id='closeMwiSettingPopup'>关闭</button></div><h3 style='margin:8px 0 16px 0;'>设置</h3>
            <div style='margin-bottom:12px;'>
                <label><input type='checkbox' id='mwiMonitorPlayer'/> 是否启动监控人数</label>
            </div>
            <div style='margin-bottom:12px;'>
                <label><input type='checkbox' id='mwiMonitorNetWorth'/> 是否启动监控净资产</label>
            </div>
            <div style='margin-bottom:12px;'>
                <label><input type='checkbox' id='mwiShowOrderTotalValue'/> 是否显示订单总价</label>
            </div>
            <div style='color:#888;font-size:12px;'>设置会自动保存</div>`;
        document.body.appendChild(popup);
        document.getElementById('closeMwiSettingPopup').onclick = function() {
            popup.remove();
            // 关闭时记录当前版本号
            localStorage.setItem('mwiSettingPanelLastVersion', MWI_SCRIPT_VERSION);
        };
        // 初始化复选框状态
        document.getElementById('mwiMonitorPlayer').checked = localStorage.getItem('mwiMonitorPlayer') !== 'false';
        document.getElementById('mwiMonitorNetWorth').checked = localStorage.getItem('mwiMonitorNetWorth') === 'true';
        document.getElementById('mwiShowOrderTotalValue').checked = localStorage.getItem('mwiShowOrderTotalValue') !== 'false';
        // 监听变更
        document.getElementById('mwiMonitorPlayer').onchange = function() {
            localStorage.setItem('mwiMonitorPlayer', this.checked);
        };
        document.getElementById('mwiMonitorNetWorth').onchange = function() {
            localStorage.setItem('mwiMonitorNetWorth', this.checked);
        };
        document.getElementById('mwiShowOrderTotalValue').onchange = function() {
            localStorage.setItem('mwiShowOrderTotalValue', this.checked);
            window.dispatchEvent(new Event('mwiShowOrderTotalValueChanged'));
        };
    }

    // 你的代码写在这里

    function savePlayerNumber() {
        const el = document.querySelector('div.Header_playerCount__1TDTK');
        if (!el) return;
        const number = parseInt(el.textContent.replace(/\D/g, ''), 10);
        if (isNaN(number)) {
            setTimeout(savePlayerNumber, 3000);
            return;
        }
        const now = new Date().toISOString();
        const data = { time: now, number };
        let arr = [];
        try {
            arr = JSON.parse(localStorage.getItem('playernumber') || '[]');
            if (!Array.isArray(arr)) arr = [];
        } catch(e) { arr = []; }
        arr.push(data);
        localStorage.setItem('playernumber', JSON.stringify(arr));
    }

    // 新增:根据当前网址获取key
    function getNetWorthKey() {
        const url = window.location.href;
        const match = url.match(/(\d{6})(?!.*\d)/);
        return match ? match[1] : 'default';
    }

    // 新增:保存净资产(分key)
    function saveNetWorth() {
        const el = document.querySelector('#toggleNetWorth');
        if (!el) return;
        // 提取数字和单位
        const match = el.textContent.replace(/,/g, '').match(/([\d.]+)\s*([KMBT]?)/i);
        let number = null;
        if (match) {
            number = parseFloat(match[1]);
            const unit = match[2]?.toUpperCase();
            if (unit === 'K') number *= 1e3;
            else if (unit === 'M') number *= 1e6;
            else if (unit === 'B') number *= 1e9;
            else if (unit === 'T') number *= 1e12;
        }
        if (!number || isNaN(number)) {
            setTimeout(saveNetWorth, 3000);
            return;
        }
        const now = new Date().toISOString();
        const data = { time: now, number };
        let arr = [];
        const key = 'networth_' + getNetWorthKey();
        try {
            arr = JSON.parse(localStorage.getItem(key) || '[]');
            if (!Array.isArray(arr)) arr = [];
        } catch(e) { arr = []; }
        arr.push(data);
        // 只保留最新50条
        if(arr.length > 50) arr = arr.slice(-50);
        localStorage.setItem(key, JSON.stringify(arr));
    }

    // 修改按钮显示逻辑,支持显示多条记录
    function createShowButton() {
        // 判断设置
        if (localStorage.getItem('mwiMonitorPlayer') === 'false') return;
        // 兼容新版class,优先用用户指定的选择器
        let target = document.querySelector("#root > div > div > div.GamePage_headerPanel__1T_cA > div > div.Header_leftHeader__PkRWX > div.Header_navLogoAndPlayerCount__2earI > div.Header_playerCount__1TDTK");
        if (!target) {
            // 兼容旧class
            target = document.querySelector("#root > div > div > div.GamePage_headerPanel__3uNKN > div > div.Header_leftHeader__PkRWX > div.Header_navLogoAndPlayerCount__2earI > div.Header_playerCount__1TDTK");
        }
        if (!target || document.getElementById('showPlayerNumberBtn')) return;
        const btn = document.createElement('button');
        btn.id = 'showPlayerNumberBtn';
        btn.textContent = '显示玩家人数记录';
        btn.style.marginLeft = '8px';
        btn.style.background = 'rgb(69,71,113)';
        btn.style.color = '#fff';
        btn.style.border = 'none';
        btn.style.borderRadius = '4px';
        btn.style.padding = '4px 10px';
        btn.onclick = function() {
            let data = localStorage.getItem('playernumber');
            let arr = [];
            if (data) {
                try {
                    arr = JSON.parse(data);
                    if (!Array.isArray(arr)) arr = [];
                } catch(e) { arr = []; }
            }
            // 默认时间范围(天)
            let rangeDays = parseInt(localStorage.getItem('mwiPlayerNumberRangeDays')) || 1;
            // 生成时间范围按钮
            const ranges = [1, 3, 7, 14, 30];
            let rangeBtns = '<div style="margin-bottom:8px;">';
            for(const d of ranges){
                rangeBtns += `<button class='rangeBtn' data-days='${d}' style='margin-right:4px;'>${d}天</button>`;
            }
            rangeBtns += '</div>';
            // 生成折线图HTML
            let html = rangeBtns;
            html += `<button id='managePlayerNumberBtn' style='margin-bottom:8px;'>管理</button>`;
            html += `<div id='chartContainer'></div>`;
            html += `<div id='managePlayerNumberPanel' style='display:none;margin-top:12px;background:#fff;'></div>`;
            // 网页内部弹窗
            let exist = document.getElementById('playerNumberPopup');
            if (exist) exist.remove();
            const popup = document.createElement('div');
            popup.id = 'playerNumberPopup';
            popup.style.position = 'fixed';
            popup.style.top = '80px';
            popup.style.left = '40px';
            popup.style.background = 'rgb(69,71,113)';
            popup.style.border = '2px solid #888';
            popup.style.boxShadow = '0 2px 12px rgba(0,0,0,0.2)';
            popup.style.zIndex = 9999;
            popup.style.padding = '16px';
            popup.style.maxHeight = '500px';
            popup.style.overflow = 'auto';
            popup.innerHTML = `<div style='text-align:right;'><button id='closePlayerNumberPopup' style='background:rgb(69,71,113);color:#fff;border:none;border-radius:4px;padding:4px 10px;'>关闭</button></div><div style='color:#fff;'>${html}</div>`;
            document.body.appendChild(popup);
            document.getElementById('closePlayerNumberPopup').onclick = function() {
                popup.remove();
            };
            // 管理按钮逻辑
            document.getElementById('managePlayerNumberBtn').onclick = function() {
                const panel = document.getElementById('managePlayerNumberPanel');
                if(panel.style.display==='none'){
                    renderManagePanel();
                    panel.style.display='block';
                }else{
                    panel.style.display='none';
                }
            };
            function renderManagePanel(){
                const panel = document.getElementById('managePlayerNumberPanel');
                if(arr.length===0){
                    panel.innerHTML = '暂无记录';
                    return;
                }
                let html = `<button id='clearAllPlayerNumber' style='color:red;margin-bottom:8px;'>全部清空</button><br/>`;
                html += '<ul style="max-height:200px;overflow:auto;padding-left:0;">';
                arr.forEach((item,idx)=>{
                    html += `<li style='list-style:none;margin-bottom:4px;'>${item.time.replace('T',' ').slice(0,16)} - ${item.number} <button data-idx='${idx}' class='delPlayerNumberBtn' style='color:red;'>删除</button></li>`;
                });
                html += '</ul>';
                panel.innerHTML = html;
                // 单条删除
                panel.querySelectorAll('.delPlayerNumberBtn').forEach(btn=>{
                    btn.onclick = function(){
                        arr.splice(parseInt(this.getAttribute('data-idx')),1);
                        localStorage.setItem('playernumber', JSON.stringify(arr));
                        drawChart(rangeDays);
                    };
                });
                // 全部清空
                panel.querySelector('#clearAllPlayerNumber').onclick = function(){
                    if(confirm('确定要清空所有记录吗?')){
                        arr.length=0;
                        localStorage.setItem('playernumber', '[]');
                        renderManagePanel();
                        drawChart(rangeDays);
                    }
                };
            }
            // 绘制折线图函数
            function drawChart(days) {
                const now = Date.now();
                const ms = days * 24 * 60 * 60 * 1000;
                const filtered = arr.filter(item => {
                    const t = new Date(item.time).getTime();
                    return t >= now - ms;
                }).sort((a, b) => new Date(a.time) - new Date(b.time));
                const container = document.getElementById('chartContainer');
                if(filtered.length > 1){
                    container.innerHTML = `<canvas id='playerNumberChart' width='500' height='300' style='display:block;'></canvas>`;
                }else if(filtered.length === 1){
                    container.innerHTML = `仅有一条数据:${filtered[0].time} - ${filtered[0].number}`;
                    return;
                }else{
                    container.innerHTML = '暂无数据';
                    return;
                }
                setTimeout(() => {
                    const canvas = document.getElementById('playerNumberChart');
                    if (!canvas) return;
                    const ctx = canvas.getContext('2d');
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                    // 处理数据
                    const times = filtered.map(item => new Date(item.time));
                    const numbers = filtered.map(item => item.number);
                    // 横坐标锚点:每小时/每天
                    let anchorTimes = [];
                    let anchorLabels = [];
                    const minTime = times[0].getTime();
                    const maxTime = times[times.length-1].getTime();
                    if(days <= 1){
                        // 每小时
                        let t = new Date(times[0]);
                        t.setMinutes(0,0,0);
                        while (t.getTime() <= maxTime) {
                            anchorTimes.push(new Date(t));
                            anchorLabels.push(`${t.getHours()}:00`);
                            t.setHours(t.getHours()+1);
                        }
                    } else {
                        // 每天
                        let t = new Date(times[0]);
                        t.setHours(0,0,0,0);
                        while (t.getTime() <= maxTime) {
                            anchorTimes.push(new Date(t));
                            anchorLabels.push(`${t.getMonth()+1}-${t.getDate()}`);
                            t.setDate(t.getDate()+1);
                        }
                    }
                    // 纵坐标范围,增加上下边距
                    let minY = Math.min(...numbers);
                    let maxY = Math.max(...numbers);
                    const steps = 5;
                    const step = (maxY - minY) / steps || 1;
                    minY = Math.max(0, minY - step);
                    maxY = maxY + step;
                    const padding = 55;
                    const w = canvas.width - padding*2;
                    const h = canvas.height - padding*2;
                    ctx.font = '12px sans-serif';
                    ctx.fillStyle = '#fff';
                    ctx.strokeStyle = '#fff';
                    // 横坐标等比例
                    const timeSpan = maxTime - minTime || 1;
                    // 绘制坐标轴
                    ctx.strokeStyle = '#fff';
                    ctx.beginPath();
                    ctx.moveTo(padding, padding);
                    ctx.lineTo(padding, padding + h);
                    ctx.lineTo(padding + w, padding + h);
                    ctx.stroke();
                    // Y轴刻度
                    ctx.fillStyle = '#fff';
                    ctx.textAlign = 'right';
                    ctx.textBaseline = 'middle';
                    for(let i=0;i<=5;i++){
                        const y = padding + h - h*i/5;
                        const val = Math.round(minY + (maxY-minY)*i/5);
                        ctx.fillText(Math.round(val)+'M', padding-5, y);
                        ctx.strokeStyle = '#eee';
                        ctx.beginPath();
                        ctx.moveTo(padding, y);
                        ctx.lineTo(padding+w, y);
                        ctx.stroke();
                    }
                    // X轴刻度(只显示锚点,自动间隔)
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'top';
                    let anchorStep = 1;
                    if(anchorTimes.length > 10) anchorStep = Math.ceil(anchorTimes.length / 10);
                    for(let i=0;i<anchorTimes.length;i+=anchorStep){
                        const t = anchorTimes[i].getTime();
                        const x = padding + w*(t-minTime)/timeSpan;
                        ctx.fillStyle = '#fff';
                        ctx.fillText(anchorLabels[i], x, padding+h+5);
                    }
                    // 折线(等比例)
                    ctx.strokeStyle = '#007bff';
                    ctx.beginPath();
                    for(let i=0;i<numbers.length;i++){
                        const t = times[i].getTime();
                        const x = padding + w*(t-minTime)/timeSpan;
                        const y = padding + h - h*(numbers[i]-minY)/(maxY-minY||1);
                        if(i===0) ctx.moveTo(x, y);
                        else ctx.lineTo(x, y);
                    }
                    ctx.stroke();
                    // 点(等比例)
                    ctx.fillStyle = '#007bff';
                    for(let i=0;i<numbers.length;i++){
                        const t = times[i].getTime();
                        const x = padding + w*(t-minTime)/timeSpan;
                        const y = padding + h - h*(numbers[i]-minY)/(maxY-minY||1);
                        ctx.beginPath();
                        ctx.arc(x, y, 3, 0, 2*Math.PI);
                        ctx.fill();
                    }
                }, 0);
            }
            // 默认绘制1天
            drawChart(rangeDays);
            // 按钮事件
            popup.querySelectorAll('.rangeBtn').forEach(btn => {
                btn.onclick = function(){
                    const days = parseInt(this.getAttribute('data-days'));
                    localStorage.setItem('mwiPlayerNumberRangeDays', days);
                    drawChart(days);
                    highlightRangeBtn(days);
                };
            });
        };
        // 插入到目标元素下方
        if (target.nextSibling) {
            target.parentNode.insertBefore(btn, target.nextSibling);
        } else {
            target.parentNode.appendChild(btn);
        }
    }

    // 新增:显示净资产历史折线图按钮(分key)
    function createShowNetWorthButton() {
        // 判断设置
        if (localStorage.getItem('mwiMonitorNetWorth') !== 'true') return;
        const target = document.querySelector("#toggleNetWorth");
        if (!target || document.getElementById('showNetWorthBtn')) return;
        const btn = document.createElement('button');
        btn.id = 'showNetWorthBtn';
        const key = getNetWorthKey();
        btn.textContent = '显示净资产记录';
        btn.style.marginLeft = '8px';
        btn.style.background = 'rgb(69,71,113)';
        btn.style.color = '#fff';
        btn.style.border = 'none';
        btn.style.borderRadius = '4px';
        btn.style.padding = '4px 10px';
        btn.onclick = function() {
            const key = 'networth_' + getNetWorthKey();
            let data = localStorage.getItem(key);
            let arr = [];
            if (data) {
                try {
                    arr = JSON.parse(data);
                    if (!Array.isArray(arr)) arr = [];
                } catch(e) { arr = []; }
            }
            // 默认时间范围(天)
            let rangeDays = parseInt(localStorage.getItem('mwiNetWorthRangeDays')) || 1;
            // 生成时间范围按钮
            const ranges = [1, 3, 7, 14, 30];
            let rangeBtns = '<div style="margin-bottom:8px;">';
            for(const d of ranges){
                rangeBtns += `<button class='rangeBtnNet' data-days='${d}' style='margin-right:4px;'>${d}天</button>`;
            }
            rangeBtns += '</div>';
            // 生成折线图HTML
            let html = rangeBtns;
            html += `<button id='manageNetWorthBtn' style='margin-bottom:8px;'>管理</button>`;
            html += `<div id='chartNetContainer'></div>`;
            html += `<div id='manageNetWorthPanel' style='display:none;margin-top:12px;background:#fff;'></div>`;
            // 网页内部弹窗
            let exist = document.getElementById('netWorthPopup');
            if (exist) exist.remove();
            const popup = document.createElement('div');
            popup.id = 'netWorthPopup';
            popup.style.position = 'fixed';
            popup.style.top = '80px';
            popup.style.left = '40px';
            popup.style.background = 'rgb(69,71,113)';
            popup.style.border = '2px solid #888';
            popup.style.boxShadow = '0 2px 12px rgba(0,0,0,0.2)';
            popup.style.zIndex = 9999;
            popup.style.padding = '16px';
            popup.style.maxHeight = '500px';
            popup.style.overflow = 'visible';
            popup.innerHTML = `<div style='text-align:right;'><button id='closeNetWorthPopup' style='background:rgb(69,71,113);color:#fff;border:none;border-radius:4px;padding:4px 10px;'>关闭</button></div><h4 style='margin:8px 0 16px 0;color:#fff;'>净资产记录</h4><div style='color:#fff;'>${html}</div>`;
            document.body.appendChild(popup);
            document.getElementById('closeNetWorthPopup').onclick = function() {
                popup.remove();
            };
            // 管理按钮逻辑
            document.getElementById('manageNetWorthBtn').onclick = function() {
                const panel = document.getElementById('manageNetWorthPanel');
                if(panel.style.display==='none'){
                    renderManagePanelNet();
                    panel.style.display='block';
                }else{
                    panel.style.display='none';
                }
            };
            function renderManagePanelNet(){
                const panel = document.getElementById('manageNetWorthPanel');
                const key = 'networth_' + getNetWorthKey();
                let arr = [];
                try {
                    arr = JSON.parse(localStorage.getItem(key) || '[]');
                    if (!Array.isArray(arr)) arr = [];
                } catch(e) { arr = []; }
                const rangeDays = parseInt(localStorage.getItem('mwiNetWorthRangeDays')) || 1;
                if(arr.length===0){
                    panel.innerHTML = '暂无记录';
                    drawChart(rangeDays);
                    return;
                }
                let html = `<button id='clearAllNetWorth' style='color:red;margin-bottom:8px;'>全部清空</button><br/>`;
                html += '<ul style="max-height:200px;overflow:auto;padding-left:0;">';
                arr.forEach((item,idx)=>{
                    html += `<li style='list-style:none;margin-bottom:4px;'>${item.time.replace('T',' ').slice(0,16)} - ${Math.round(item.number/1e6)}M <button data-idx='${idx}' class='delNetWorthBtn' style='color:red;'>删除</button></li>`;
                });
                html += '</ul>';
                panel.innerHTML = html;
                // 单条删除
                panel.querySelectorAll('.delNetWorthBtn').forEach(btn=>{
                    btn.onclick = function(){
                        const idx = parseInt(this.getAttribute('data-idx'));
                        arr.splice(idx,1);
                        localStorage.setItem(key, JSON.stringify(arr));
                        renderManagePanelNet();
                    };
                });
                // 全部清空
                panel.querySelector('#clearAllNetWorth').onclick = function(){
                    if(confirm('确定要清空所有记录吗?')){
                        arr = [];
                        localStorage.setItem(key, '[]');
                        renderManagePanelNet();
                    }
                };
            }
            // 绘制折线图函数
            function drawChart(days) {
                const now = Date.now();
                const ms = days * 24 * 60 * 60 * 1000;
                const filtered = arr.filter(item => {
                    const t = new Date(item.time).getTime();
                    return t >= now - ms;
                }).sort((a, b) => new Date(a.time) - new Date(b.time));
                const container = document.getElementById('chartNetContainer');
                if(filtered.length > 1){
                    container.innerHTML = `<canvas id='netWorthChart' width='550' height='320' style='display:block;'></canvas>`;
                }else if(filtered.length === 1){
                    container.innerHTML = `仅有一条数据:${(filtered[0].time)} - ${Math.round(filtered[0].number/1e6)}M`;
                    return;
                }else{
                    container.innerHTML = '暂无数据';
                    return;
                }
                setTimeout(() => {
                    const canvas = document.getElementById('netWorthChart');
                    if (!canvas) return;
                    const ctx = canvas.getContext('2d');
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                    // 处理数据
                    const times = filtered.map(item => new Date(item.time));
                    const numbers = filtered.map(item => item.number/1e6); // 以M为单位
                    // 横坐标锚点:每小时/每天
                    let anchorTimes = [];
                    let anchorLabels = [];
                    const minTime = times[0].getTime();
                    const maxTime = times[times.length-1].getTime();
                    if(days <= 1){
                        // 每小时
                        let t = new Date(times[0]);
                        t.setMinutes(0,0,0);
                        while (t.getTime() <= maxTime) {
                            anchorTimes.push(new Date(t));
                            anchorLabels.push(`${t.getHours()}:00`);
                            t.setHours(t.getHours()+1);
                        }
                    } else {
                        // 每天
                        let t = new Date(times[0]);
                        t.setHours(0,0,0,0);
                        while (t.getTime() <= maxTime) {
                            anchorTimes.push(new Date(t));
                            anchorLabels.push(`${t.getMonth()+1}-${t.getDate()}`);
                            t.setDate(t.getDate()+1);
                        }
                    }
                    // 纵坐标范围,增加上下边距
                    let minY = Math.min(...numbers);
                    let maxY = Math.max(...numbers);
                    const steps = 5;
                    const step = (maxY - minY) / steps || 1;
                    minY = Math.max(0, minY - step);
                    maxY = maxY + step;
                    const padding = 55;
                    const w = canvas.width - padding*2;
                    const h = canvas.height - padding*2;
                    ctx.font = '12px sans-serif';
                    ctx.fillStyle = '#fff';
                    ctx.strokeStyle = '#fff';
                    // 横坐标等比例
                    const timeSpan = maxTime - minTime || 1;
                    // 绘制坐标轴
                    ctx.strokeStyle = '#fff';
                    ctx.beginPath();
                    ctx.moveTo(padding, padding);
                    ctx.lineTo(padding, padding + h);
                    ctx.lineTo(padding + w, padding + h);
                    ctx.stroke();
                    // Y轴刻度
                    ctx.fillStyle = '#fff';
                    ctx.textAlign = 'right';
                    ctx.textBaseline = 'middle';
                    for(let i=0;i<=5;i++){
                        const y = padding + h - h*i/5;
                        const val = minY + (maxY-minY)*i/5;
                        ctx.fillText(Math.round(val)+'M', padding-5, y);
                        ctx.strokeStyle = '#eee';
                        ctx.beginPath();
                        ctx.moveTo(padding, y);
                        ctx.lineTo(padding+w, y);
                        ctx.stroke();
                    }
                    // X轴刻度(只显示锚点,自动间隔)
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'top';
                    let anchorStep = 1;
                    if(anchorTimes.length > 10) anchorStep = Math.ceil(anchorTimes.length / 10);
                    for(let i=0;i<anchorTimes.length;i+=anchorStep){
                        const t = anchorTimes[i].getTime();
                        const x = padding + w*(t-minTime)/timeSpan;
                        ctx.fillStyle = '#fff';
                        ctx.fillText(anchorLabels[i], x, padding+h+5);
                    }
                    // 折线(等比例)
                    ctx.strokeStyle = '#28a745';
                    ctx.beginPath();
                    for(let i=0;i<numbers.length;i++){
                        const t = times[i].getTime();
                        const x = padding + w*(t-minTime)/timeSpan;
                        const y = padding + h - h*(numbers[i]-minY)/(maxY-minY||1);
                        if(i===0) ctx.moveTo(x, y);
                        else ctx.lineTo(x, y);
                    }
                    ctx.stroke();
                    // 点(等比例)
                    ctx.fillStyle = '#28a745';
                    for(let i=0;i<numbers.length;i++){
                        const t = times[i].getTime();
                        const x = padding + w*(t-minTime)/timeSpan;
                        const y = padding + h - h*(numbers[i]-minY)/(maxY-minY||1);
                        ctx.beginPath();
                        ctx.arc(x, y, 3, 0, 2*Math.PI);
                        ctx.fill();
                    }
                }, 0);
            }
            // 默认绘制1天
            drawChart(rangeDays);
            // 高亮当前按钮
            function highlightRangeBtnNet(days) {
                popup.querySelectorAll('.rangeBtnNet').forEach(btn => {
                    if(parseInt(btn.getAttribute('data-days')) === days){
                        btn.style.background = '#e0e0e0';
                    }else{
                        btn.style.background = '';
                    }
                });
            }
            highlightRangeBtnNet(rangeDays);
            // 按钮事件
            popup.querySelectorAll('.rangeBtnNet').forEach(btn => {
                btn.onclick = function(){
                    const days = parseInt(this.getAttribute('data-days'));
                    localStorage.setItem('mwiNetWorthRangeDays', days);
                    drawChart(days);
                    highlightRangeBtnNet(days);
                };
            });
        };
        target.parentNode.appendChild(btn);
        // 调用净资产对比显示
        showNetWorthDayCompare();
    }

    // 工具函数:带单位字符串转数字
    function parseNumberWithUnit(str) {
        const match = str.replace(/,/g, '').match(/([\d.]+)\s*([KMBT]?)/i);
        let num = null;
        if (match) {
            num = parseFloat(match[1]);
            const unit = match[2]?.toUpperCase();
            if (unit === 'K') num *= 1e3;
            else if (unit === 'M') num *= 1e6;
            else if (unit === 'B') num *= 1e9;
            else if (unit === 'T') num *= 1e12;
        }
        return num;
    }

    // 工具函数:大数字格式化为K/M/B,保留1位小数,无小数不显示
    function formatNumberWithUnit(num) {
        if (num >= 1e9) {
            let n = num / 1e9;
            return (n % 1 === 0 ? n : n.toFixed(1)) + 'B';
        } else if (num >= 1e6) {
            let n = num / 1e6;
            return (n % 1 === 0 ? n : n.toFixed(1)) + 'M';
        } else if (num >= 1e3) {
            let n = num / 1e3;
            return (n % 1 === 0 ? n : n.toFixed(1)) + 'K';
        } else {
            return num.toString();
        }
    }

    // 工具函数:最大值只显示到M为单位
    function formatNumberToM(num) {
        let n = num / 1e6;
        return (n % 1 === 0 ? n : n.toFixed(2)) + 'M';
    }

    // 优化:库存面板数字显示,超过1万显示为K,超过1百万显示为M,超过1亿显示为B,低于1万正常显示
    function formatNumberSmartUnit(num) {
        if (num >= 1e8) {
            let n = num / 1e8;
            return (n % 1 === 0 ? n : n.toFixed(2)) + 'B';
        } else if (num >= 1e6) {
            let n = num / 1e6;
            return (n % 1 === 0 ? n : n.toFixed(2)) + 'M';
        } else if (num >= 1e4) {
            let n = num / 1e3;
            return (n % 1 === 0 ? n : n.toFixed(1)) + 'K';
        } else {
            return num.toString();
        }
    }

    // 读取所有订单行的数量(取"/"后面的数字)
    function getAllOrderQuantities() {
        const nodes = document.querySelectorAll('div.MarketplacePanel_myListingsTableContainer__2s6pm > table > tbody > tr > td:nth-child(3) > div > div:nth-child(2)');
        const quantities = [];
        nodes.forEach(node => {
            const text = node.textContent.trim();
            const parts = text.split('/');
            if(parts.length === 2) {
                const qty = parseNumberWithUnit(parts[1]);
                if(!isNaN(qty)) quantities.push(qty);
            }
        });
        console.log('所有订单数量:', quantities);
        return quantities;
    }

    // 读取所有订单行的价格
    function getAllOrderPrices() {
        const nodes = document.querySelectorAll('td.MarketplacePanel_price__hIzrY > span');
        const prices = [];
        nodes.forEach(node => {
            const text = node.textContent.trim();
            const price = parseNumberWithUnit(text);
            if(!isNaN(price)) prices.push(price);
        });
        console.log('所有订单价格:', prices);
        return prices;
    }

    // 在每个订单价格下方插入总价值
    function showOrderTotalValues() {
        // 获取所有订单行
        const rows = document.querySelectorAll('div.MarketplacePanel_myListingsTableContainer__2s6pm > table > tbody > tr');
        rows.forEach(row => {
            // 获取数量
            const qtyNode = row.querySelector('td:nth-child(3) > div > div:nth-child(2)');
            let qty = 0;
            if(qtyNode) {
                const text = qtyNode.textContent.trim();
                const parts = text.split('/');
                if(parts.length === 2) {
                    qty = parseNumberWithUnit(parts[1]);
                }
            }
            // 获取价格
            const priceNode = row.querySelector('td.MarketplacePanel_price__hIzrY > span');
            let price = 0;
            if(priceNode) {
                const text = priceNode.textContent.trim();
                price = parseNumberWithUnit(text);
            }
            // 计算总价值
            const total = (!isNaN(qty) && !isNaN(price)) ? qty * price : 0;
            // 插入显示div
            if(priceNode) {
                // 避免重复插入
                if(priceNode.nextSibling && priceNode.nextSibling.className === 'orderTotalValue') return;
                const div = document.createElement('div');
                div.className = 'orderTotalValue';
                div.style.fontSize = '12px';
                div.style.color = '#28a745';
                div.textContent = `总价值:${formatNumberWithUnit(total)}`;
                priceNode.parentNode.appendChild(div);
            }
        });
    }

    // 读取仓库内所有物品及数量(初步实现,具体功能待定)
    function getWarehouseItems() {
        // 假设仓库表格选择器如下(如有变动可调整):
        // 例:div.WarehousePanel_tableContainer__xxx > table > tbody > tr
        const rows = document.querySelectorAll('div.WarehousePanel_tableContainer__2Qw2d table tbody tr');
        const items = [];
        rows.forEach(row => {
            // 假设第1列为物品名,第2列为数量
            const nameCell = row.querySelector('td:nth-child(1)');
            const qtyCell = row.querySelector('td:nth-child(2)');
            if(nameCell && qtyCell) {
                const name = nameCell.textContent.trim();
                const qty = qtyCell.textContent.trim().replace(/,/g, '');
                items.push({ name, qty });
            }
        });
        console.log('仓库物品及数量:', items);
        return items;
    }

    // 重构:读取背包所有物品及数量(Inventory_items__6SXv0.script_buildScore_added.script_invSort_added)
    function getInventoryItems() {
        const items = [];
        const itemDivs = document.querySelectorAll('#root > div > div > div.GamePage_gamePanel__3uNKN > div.GamePage_contentPanel__Zx4FH > div.GamePage_characterManagementPanel__3OYQL > div > div > div > div.TabsComponent_tabPanelsContainer__26mzo > div:nth-child(1) > div > div.Inventory_items__6SXv0.script_buildScore_added.script_invSort_added > div > div > div');
        itemDivs.forEach(div => {
            const svg = div.querySelector('div.Item_iconContainer__5z7j4 > svg');
            let name = '';
            let icon_url = '';
            if(svg) {
                name = svg.getAttribute('aria-label') || '';
                const use = svg.querySelector('use');
                if(use) icon_url = use.getAttribute('href') || '';
            }
            // 新增:查找强化等级
            let enhance = '';
            // 兼容不同class写法,优先找Item_enhancementLevel__19g-e
            let enhanceDiv = div.querySelector('div.Item_enhancementLevel__19g-e');
            if (!enhanceDiv) {
                // 兜底:查找包含enhancementLevel的div
                enhanceDiv = Array.from(div.querySelectorAll('div')).find(d => d.className && d.className.includes('enhancementLevel'));
            }
            if (enhanceDiv) {
                enhance = enhanceDiv.textContent.trim();
            }
            // 拼接到名称
            let displayName = name;
            if (enhance) {
                displayName += enhance;
            }
            const countDiv = div.querySelector('div.Item_count__1HVvv');
            if(!countDiv) return;
            const txt = countDiv.textContent.trim();
            let qty = parseNumberWithUnit(txt);
            if(!qty || isNaN(qty)) return;
            // 查找物品种类
            let category = '';
            let parent = div.parentElement;
            while(parent && !category) {
                const labelDiv = parent.querySelector('div.Inventory_label__XEOAx > span.Inventory_categoryButton__35s1x');
                if(labelDiv) category = labelDiv.textContent.trim();
                parent = parent.parentElement;
            }
            if(name) items.push({ name: displayName, qty, category, icon_url, enhance: enhance || '' });
        });
        const now = new Date().toLocaleString();
        const key = 'inventory_' + getNetWorthKey();
        let arr = [];
        try {
            arr = JSON.parse(localStorage.getItem(key) || '[]');
            if (!Array.isArray(arr)) arr = [];
        } catch(e) { arr = []; }
        arr.push({ time: now, items });
        // 只保留最新50条
        if(arr.length > 50) arr = arr.slice(-50);
        localStorage.setItem(key, JSON.stringify(arr));
        console.log('背包物品及数量:', items);
        return items;
    }

    // 修改定时器和延时调用,根据设置决定是否监控
    setInterval(() => {
        if(localStorage.getItem('mwiMonitorPlayer') !== 'false') savePlayerNumber();
        if(localStorage.getItem('mwiMonitorNetWorth') === 'true') saveNetWorth();
    }, 30 * 60 * 1000);
    // 监听#toggleNetWorth出现后0.5秒再显示按钮
    function waitForNetWorthAndShowBtns() {
        const check = () => {
            const el = document.querySelector('#toggleNetWorth');
            if(el) {
                setTimeout(() => {
                    // 先插入玩家人数按钮,再插入净资产和库存按钮,避免被覆盖
                    createShowButton();
                    createShowNetWorthButton();
                    createShowInventoryHistoryButton();
                }, 500);
                return true;
            }
            return false;
        };
        if(!check()) {
            const observer = new MutationObserver(() => {
                if(check()) observer.disconnect();
            });
            observer.observe(document.body, { childList: true, subtree: true });
        }
    }
    waitForNetWorthAndShowBtns();
    // 首次安装时默认开启所有功能
    if (localStorage.getItem('mwiMonitorPlayer') === null) {
        localStorage.setItem('mwiMonitorPlayer', 'true');
    }
    if (localStorage.getItem('mwiMonitorNetWorth') === null) {
        localStorage.setItem('mwiMonitorNetWorth', 'true');
    }
    // 设置变更时刷新按钮显示
    window.addEventListener('storage', function(e) {
        if (e.key === 'mwiMonitorPlayer' || e.key === 'mwiMonitorNetWorth') {
            // 移除旧按钮
            const btn1 = document.getElementById('showPlayerNumberBtn');
            if (btn1) btn1.remove();
            const btn2 = document.getElementById('showNetWorthBtn');
            if (btn2) btn2.remove();
            // 重新判断并添加
            createShowButton();
            createShowNetWorthButton();
        }
    });

    // 监听TabPanel_hidden出现时自动显示订单总价值
    let orderTotalValueObserver = null;
    function observeOrderTabAndShowTotal() {
        if(orderTotalValueObserver) orderTotalValueObserver.disconnect();
        if(localStorage.getItem('mwiShowOrderTotalValue') === 'false') return;
        orderTotalValueObserver = new MutationObserver(() => {
            const tab = document.querySelector('div.TabPanel_tabPanel__tXMJF.TabPanel_hidden__26UM3');
            if(tab) {
                showOrderTotalValues();
            }
        });
        orderTotalValueObserver.observe(document.body, { childList: true, subtree: true });
    }
    // 页面加载后自动监听
    setTimeout(() => {
        observeOrderTabAndShowTotal();
    }, 5000);
    // 响应设置变更
    window.addEventListener('mwiShowOrderTotalValueChanged', () => {
        observeOrderTabAndShowTotal();
        // 清理已显示的总价值
        document.querySelectorAll('.orderTotalValue').forEach(e=>e.remove());
    });
    // 首次安装时默认开启
    if (localStorage.getItem('mwiShowOrderTotalValue') === null) {
        localStorage.setItem('mwiShowOrderTotalValue', 'true');
    }

    // 在"显示净资产记录"按钮左侧添加"显示库存记录"按钮
    function createShowInventoryHistoryButton() {
        const netBtn = document.getElementById('showNetWorthBtn');
        if (!netBtn || document.getElementById('showInventoryHistoryBtn')) return;
        // 按钮加载时保存一次库存
        getInventoryItems();
        const btn = document.createElement('button');
        btn.id = 'showInventoryHistoryBtn';
        btn.textContent = '显示库存记录';
        btn.style.marginRight = '8px';
        btn.style.background = 'rgb(69,71,113)';
        btn.style.color = '#fff';
        btn.style.border = 'none';
        btn.style.borderRadius = '4px';
        btn.style.padding = '4px 10px';
        btn.onclick = function() {
            getInventoryItems(); // 点击时保存一次库存
            showInventoryHistory();
        };
        netBtn.parentNode.insertBefore(btn, netBtn);
    }

    // 监听净资产按钮生成后插入库存按钮
    if (typeof observerInvBtn === 'undefined') {
        var observerInvBtn = new MutationObserver(() => {
            createShowInventoryHistoryButton();
        });
        observerInvBtn.observe(document.body, { childList: true, subtree: true });
    }

    // 显示库存记录弹窗(左侧时间点,右侧物品分类)
    function showInventoryHistory() {
        // 只刷新面板,不再自动保存库存
        const key = 'inventory_' + getNetWorthKey();
        let arr = [];
        try {
            arr = JSON.parse(localStorage.getItem(key) || '[]');
            if (!Array.isArray(arr)) arr = [];
        } catch(e) { arr = []; }
        arr = arr.slice(-300);
        let exist = document.getElementById('inventoryHistoryPopup');
        if (exist) exist.remove();
        const popup = document.createElement('div');
        popup.id = 'inventoryHistoryPopup';
        popup.style.position = 'fixed';
        popup.style.top = '120px';
        popup.style.left = '50%';
        popup.style.transform = 'translateX(-50%)';
        popup.style.background = 'rgb(69,71,113)';
        popup.style.border = '2px solid #888';
        popup.style.boxShadow = '0 2px 12px rgba(0,0,0,0.2)';
        popup.style.zIndex = 99999;
        popup.style.padding = '24px 32px';
        popup.style.minWidth = '600px';
        popup.innerHTML = `
        <div style='position:absolute;top:18px;right:24px;display:flex;flex-direction:row;align-items:flex-start;z-index:1;'>
            <button id='recordCurrentInventoryBtn' style='background:rgb(69,71,113);color:#fff;border:2px solid #28a745;border-radius:4px;padding:4px 10px;font-size:14px;cursor:pointer;margin-right:8px;'>记录当前库存</button>
            <button id='showChangedItemsBtn' style='background:#28a745;color:#fff;border:2px solid #28a745;border-radius:4px;padding:4px 10px;font-size:14px;cursor:pointer;margin-right:8px;'>显示变动物品</button>
            <button id='closeInventoryHistoryPopup' style='background:rgb(69,71,113);color:#fff;border:none;border-radius:4px;padding:4px 10px;'>关闭</button>
        </div>
        <h3 style='margin:0 0 12px 0;color:#fff;'>库存历史记录</h3>
        <div style='height:1px;width:100%;background:#3a3a5a;margin-bottom:12px;'></div>
        <div id='invHistoryPanel' style='display:flex;gap:24px;min-height:320px;'></div>`;
        document.body.appendChild(popup);
        document.getElementById('closeInventoryHistoryPopup').onclick = function() {
            popup.remove();
        };
        // 读取上次位置和尺寸
        let popupLeft = parseInt(localStorage.getItem('mwiInvPopupLeft')) || window.innerWidth/2-320;
        let popupTop = parseInt(localStorage.getItem('mwiInvPopupTop')) || 120;
        let popupWidth = parseInt(localStorage.getItem('mwiInvPopupWidth')) || 640;
        let popupHeight = parseInt(localStorage.getItem('mwiInvPopupHeight')) || 420;
        popup.style.left = popupLeft + 'px';
        popup.style.top = popupTop + 'px';
        popup.style.width = popupWidth + 'px';
        popup.style.height = popupHeight + 'px';
        popup.style.minWidth = '480px';
        popup.style.minHeight = '320px';
        popup.style.resize = 'none'; // 禁用原生resize
        popup.style.boxSizing = 'border-box';
        // 拖动功能
        let isDragging = false, dragOffsetX = 0, dragOffsetY = 0;
        const dragHeader = popup.querySelector('h3');
        dragHeader.style.cursor = 'move';
        dragHeader.addEventListener('mousedown', function(e){
            isDragging = true;
            dragOffsetX = e.clientX - popup.offsetLeft;
            dragOffsetY = e.clientY - popup.offsetTop;
            document.body.style.userSelect = 'none';
        });
        document.addEventListener('mousemove', function(e){
            if(isDragging){
                let newLeft = e.clientX - dragOffsetX;
                let newTop = e.clientY - dragOffsetY;
                // 限制范围
                newLeft = Math.max(0, Math.min(window.innerWidth-popup.offsetWidth, newLeft));
                newTop = Math.max(0, Math.min(window.innerHeight-popup.offsetHeight, newTop));
                popup.style.left = newLeft + 'px';
                popup.style.top = newTop + 'px';
            }
        });
        document.addEventListener('mouseup', function(e){
            if(isDragging){
                isDragging = false;
                localStorage.setItem('mwiInvPopupLeft', parseInt(popup.style.left));
                localStorage.setItem('mwiInvPopupTop', parseInt(popup.style.top));
                document.body.style.userSelect = '';
            }
        });
        // 右下角拖拽大小
        const resizeHandle = document.createElement('div');
        resizeHandle.style.position = 'absolute';
        resizeHandle.style.right = '2px';
        resizeHandle.style.bottom = '2px';
        resizeHandle.style.width = '22px';
        resizeHandle.style.height = '22px';
        resizeHandle.style.cursor = 'nwse-resize';
        resizeHandle.style.zIndex = '11';
        resizeHandle.innerHTML = `<svg width='22' height='22'><polyline points='6,20 20,20 20,6' style='fill:none;stroke:#28a745;stroke-width:3'/></svg>`;
        popup.appendChild(resizeHandle);
        let isResizing = false, resizeStartX=0, resizeStartY=0, startW=0, startH=0;
        resizeHandle.addEventListener('mousedown', function(e){
            isResizing = true;
            resizeStartX = e.clientX;
            resizeStartY = e.clientY;
            startW = popup.offsetWidth;
            startH = popup.offsetHeight;
            e.stopPropagation();
            document.body.style.userSelect = 'none';
            // 只监听window,避免多次绑定
            window.addEventListener('mousemove', doResize, true);
            window.addEventListener('mouseup', stopResize, true);
        });
        function doResize(e) {
            if (!isResizing) return;
            let newW = Math.max(340, startW + (e.clientX - resizeStartX));
            let newH = Math.max(260, startH + (e.clientY - resizeStartY));
            popup.style.width = newW + 'px';
            popup.style.height = newH + 'px';
            setPanelSize();
        }
        function stopResize(e) {
            if (!isResizing) return;
            isResizing = false;
            document.body.style.userSelect = '';
            window.removeEventListener('mousemove', doResize, true);
            window.removeEventListener('mouseup', stopResize, true);
            // 保存尺寸
            localStorage.setItem('mwiInvPopupWidth', parseInt(popup.style.width));
            localStorage.setItem('mwiInvPopupHeight', parseInt(popup.style.height));
        }
        // 让内容区自适应弹窗
        const invPanel = popup.querySelector('#invHistoryPanel');
        invPanel.style.height = (popupHeight-110) + 'px';
        invPanel.style.maxHeight = 'none';
        invPanel.style.minHeight = '180px';
        invPanel.style.flex = '1 1 auto';
        // 右侧内容区和左侧栏自适应
        const setPanelSize = () => {
            const h = popup.offsetHeight-110;
            const w = popup.offsetWidth;
            invPanel.style.height = h + 'px';
            // 左侧栏高度
            const leftCol = popup.querySelector('#invHistoryLeftCol');
            if(leftCol) {
                leftCol.style.maxHeight = h-10 + 'px';
                leftCol.style.height = h-10 + 'px';
            }
            // 右侧栏宽高
            const rightCol = popup.querySelector('#invHistoryRightCol');
            if(rightCol) {
                rightCol.style.maxHeight = h-10 + 'px';
                rightCol.style.height = h-10 + 'px';
                rightCol.style.width = (w-220) + 'px';
                rightCol.style.maxWidth = '';
            }
        };
        setPanelSize(); // 打开面板时立即自适应内容区和图标排列
        // 左侧时间点
        const panel = document.getElementById('invHistoryPanel');
        if(arr.length === 0) {
            panel.innerHTML = `<div style='color:#fff;'>暂无库存记录</div>`;
            return;
        }
        let selectedIdx = null; // 首次打开不选中任何记录
        // 处理日期分组
        const dateMap = {};
        arr.forEach((entry, idx) => {
            const dateStr = entry.time.slice(0,10); // yyyy-mm-dd
            if(!dateMap[dateStr]) dateMap[dateStr] = [];
            dateMap[dateStr].push({entry, idx});
        });
        const allDates = Object.keys(dateMap).sort((a,b)=>b.localeCompare(a));
        let selectedDate = allDates[0];
        // 下拉栏HTML
        let dateSelectHtml = `<select id='invHistoryDateSelect' style='width:100%;margin-bottom:8px;padding:2px 6px;border-radius:4px;'>`;
        allDates.forEach(d=>{
            dateSelectHtml += `<option value='${d}'>${d}</option>`;
        });
        dateSelectHtml += `</select>`;
        // 生成左侧栏内容函数
        function renderLeftCol(dateStr, activeIdx) {
            let leftHtml = dateSelectHtml;
            // 新到旧排序,时间字符串降序
            const records = (dateMap[dateStr]||[]).slice().sort((a,b)=>b.entry.time.localeCompare(a.entry.time));
            records.forEach(({entry, idx}) => {
                // 拆分时间
                const t = new Date(entry.time);
                const monthDay = `${t.getMonth()+1}/${t.getDate()}`;
                const hms = `${t.getHours().toString().padStart(2,'0')}:${t.getMinutes().toString().padStart(2,'0')}:${t.getSeconds().toString().padStart(2,'0')}`;
                let highlight = (idx === activeIdx) ? "background:#444;border-radius:4px;" : "";
                leftHtml += `<div class='invHistoryItem' data-idx='${idx}' style='margin-bottom:10px;border:1.5px solid #888;border-radius:6px;padding:4px 2px;background:rgba(255,255,255,0.04);${highlight}'>`;
                leftHtml += `<div class='invTimeBtn' data-idx='${idx}' style='padding:4px 6px;cursor:pointer;color:#fff;font-size:13px;line-height:1.2;text-align:center;'>`;
                leftHtml += `<div style='font-size:12px;'>${monthDay}</div><div style='font-size:11px;'>${hms}</div>`;
                leftHtml += `</div>`;
                leftHtml += `<div style='display:flex;gap:6px;justify-content:center;margin-top:2px;'>`;
                leftHtml += `<button class='invBtn1' data-idx='${idx}' style='background:rgb(69,71,113);color:#fff;border:none;border-radius:4px;padding:2px 8px;cursor:pointer;'>对比</button>`;
                leftHtml += `<button class='invBtn2' data-idx='${idx}' style='background:#d33;color:#fff;border:none;border-radius:4px;padding:2px 8px;cursor:pointer;'>删除</button>`;
                leftHtml += `</div></div>`;
            });
            return leftHtml;
        }
        // 初始渲染,默认高亮最新一条
        let activeIdx = (dateMap[selectedDate] && dateMap[selectedDate].length) ? dateMap[selectedDate][0].idx : 0;
        let leftColHtml = `<div style='min-width:160px;max-height:400px;overflow:auto;border-right:1px solid #888;' id='invHistoryLeftCol'>`;
        leftColHtml += renderLeftCol(selectedDate, activeIdx);
        leftColHtml += `</div>`;
        panel.innerHTML = `<div>${leftColHtml}</div><div id='invHistoryRightCol' style='flex:1;overflow-y:auto;max-width:520px;max-height:400px;'></div>`;
        setPanelSize();
        // 渲染右侧内容,默认显示最新一条
        // renderRight(activeIdx); // 不再默认渲染右侧
        // 监听日期下拉栏切换
        panel.querySelector('#invHistoryDateSelect').onchange = function(){
            selectedDate = this.value;
            panel.querySelector('#invHistoryLeftCol').innerHTML = renderLeftCol(selectedDate, -1);
            // 不自动高亮和切换右侧
            bindLeftColEvents();
        };
        // 事件绑定函数
        function bindLeftColEvents() {
            panel.querySelectorAll('.invHistoryItem').forEach(itemDiv => {
                itemDiv.addEventListener('click', function(e) {
                    if (e.target.tagName === 'BUTTON') return;
                    const idx = parseInt(this.getAttribute('data-idx'));
                    panel.querySelector('#invHistoryLeftCol').innerHTML = renderLeftCol(selectedDate, idx);
                    renderRight(idx); // 修正:点击后显示右侧库存
                    bindLeftColEvents();
                });
            });
            // 对比按钮
            panel.querySelectorAll('.invBtn1').forEach(btn => {
                btn.onclick = function(e) {
                    e.stopPropagation();
                    const idx = parseInt(this.getAttribute('data-idx'));
                    // 当前右侧显示的selectedIdx
                    const curIdx = selectedIdx;
                    if(idx === curIdx) return; // 对比自己无意义
                    const baseItems = arr[idx].items;
                    const curItems = arr[curIdx].items;
                    // 以物品名+分类为key(不含强化)
                    const getKey = item => (item.name||'')+'|'+(item.category||'');
                    // 构建分组:同名同类不同强化的物品分别统计
                    function groupByEnhance(items) {
                        const map = {};
                        items.forEach(item => {
                            const k = (item.name||'')+'|'+(item.category||'')+'|'+(item.enhance||'');
                            if (!map[k]) map[k] = { ...item };
                            else map[k].qty += item.qty;
                        });
                        return Object.values(map);
                    }
                    const baseMap = {};
                    groupByEnhance(baseItems).forEach(item=>{ baseMap[getKey(item)+(item.enhance||'')] = item; });
                    const curMap = {};
                    groupByEnhance(curItems).forEach(item=>{ curMap[getKey(item)+(item.enhance||'')] = item; });
                    // 分类分组(先用当前的)
                    const group = {};
                    groupByEnhance(curItems).forEach(item => {
                        const cat = item.category || '未分类';
                        if(!group[cat]) group[cat] = [];
                        group[cat].push(item);
                    });
                    // 把历史有但当前没有的物品也加进去
                    groupByEnhance(baseItems).forEach(item => {
                        const key = getKey(item)+(item.enhance||'');
                        if(!curMap[key]){
                            const cat = item.category || '未分类';
                            if(!group[cat]) group[cat] = [];
                            // 构造一个qty为0的当前物品,icon等用历史的
                            group[cat].push({
                                name: item.name,
                                category: item.category,
                                icon_url: item.icon_url,
                                qty: 0,
                                enhance: item.enhance,
                                _baseQty: item.qty // 方便后面diff
                            });
                        }
                    });
                    // 记录本次对比分组和diff
                    lastCompareData = { group, baseMap, getKey };
                    // 渲染
                    renderCompareGroup(group, baseMap, getKey, false);
                }
            });
            // 删除按钮
            panel.querySelectorAll('.invBtn2').forEach(btn => {
                btn.onclick = function(e) {
                    e.stopPropagation();
                    const idx = parseInt(this.getAttribute('data-idx'));
                    showMwiConfirm('确定要删除该条库存历史记录吗?', function(ok){
                        if(!ok) return;
                        arr.splice(idx, 1);
                        localStorage.setItem(key, JSON.stringify(arr));
                        showInventoryHistory();
                    });
                }
            });
        }
        bindLeftColEvents();
        // 右侧渲染函数
        function renderRight(idx) {
            selectedIdx = idx;
            let rightHtml = '';
            const items = arr[selectedIdx].items;
            // 分类分组
            const group = {};
            items.forEach(item => {
                const cat = item.category || '未分类';
                if(!group[cat]) group[cat] = [];
                group[cat].push(item);
            });
            for(const cat in group) {
                rightHtml += `<div style='margin-bottom:18px;'><b style='color:#fff;'>${cat}</b><ul style='margin:8px 0 0 0;padding:0;display:flex;flex-wrap:wrap;gap:18px;max-width:100%;justify-content:flex-start;align-items:flex-start;'>`;
                group[cat].forEach(item => {
                    rightHtml += `<li style='list-style:none;position:relative;width:44px;height:44px;display:flex;align-items:center;justify-content:center;'>`;
                    if(item.icon_url) {
                        rightHtml += `<svg width='40' height='40' style='display:block;'><use href='${item.icon_url}'></use></svg>`;
                    }
                    // 强化等级左上角
                    if(item.enhance) {
                        rightHtml += `<span style='position:absolute;left:-6px;top:-6px;font-size:13px;font-weight:bold;color:#fff;background:#28a745;padding:0 4px;border-radius:6px;'>${item.enhance}</span>`;
                    }
                    rightHtml += `<span style='position:absolute;right:0;bottom:0;background:rgba(0,0,0,0.7);color:#fff;font-size:13px;padding:0 4px;border-radius:8px 0 4px 0;'>${formatNumberSmartUnit(item.qty)}</span></li>`;
                });
                rightHtml += '</ul></div>';
            }
            panel.querySelector('#invHistoryRightCol').innerHTML = rightHtml;
            setPanelSize(); // 渲染后立即自适应
        }
        // 默认渲染最新一条
        // renderRight(0); // 不再默认渲染右侧
        setPanelSize(); // 内容生成后立即自适应
        // 默认高亮最新一条
        // panel.querySelectorAll('.invTimeBtn')[0].style.background = '#444'; // 注释掉
        // panel.querySelectorAll('.invTimeBtn')[0].style.borderRadius = '4px'; // 注释掉
        // 绑定按钮1对比功能
        let lastCompareData = null; // 存储上次对比渲染的分组和diff
        panel.querySelectorAll('.invBtn1').forEach(btn => {
            btn.onclick = function(e) {
                e.stopPropagation();
                const idx = parseInt(this.getAttribute('data-idx'));
                // 当前右侧显示的selectedIdx
                const curIdx = selectedIdx;
                if(idx === curIdx) return; // 对比自己无意义
                const baseItems = arr[idx].items;
                const curItems = arr[curIdx].items;
                // 以物品名+分类为key(不含强化)
                const getKey = item => (item.name||'')+'|'+(item.category||'');
                // 构建分组:同名同类不同强化的物品分别统计
                function groupByEnhance(items) {
                    const map = {};
                    items.forEach(item => {
                        const k = (item.name||'')+'|'+(item.category||'')+'|'+(item.enhance||'');
                        if (!map[k]) map[k] = { ...item };
                        else map[k].qty += item.qty;
                    });
                    return Object.values(map);
                }
                const baseMap = {};
                groupByEnhance(baseItems).forEach(item=>{ baseMap[getKey(item)+(item.enhance||'')] = item; });
                const curMap = {};
                groupByEnhance(curItems).forEach(item=>{ curMap[getKey(item)+(item.enhance||'')] = item; });
                // 分类分组(先用当前的)
                const group = {};
                groupByEnhance(curItems).forEach(item => {
                    const cat = item.category || '未分类';
                    if(!group[cat]) group[cat] = [];
                    group[cat].push(item);
                });
                // 把历史有但当前没有的物品也加进去
                groupByEnhance(baseItems).forEach(item => {
                    const key = getKey(item)+(item.enhance||'');
                    if(!curMap[key]){
                        const cat = item.category || '未分类';
                        if(!group[cat]) group[cat] = [];
                        // 构造一个qty为0的当前物品,icon等用历史的
                        group[cat].push({
                            name: item.name,
                            category: item.category,
                            icon_url: item.icon_url,
                            qty: 0,
                            enhance: item.enhance,
                            _baseQty: item.qty // 方便后面diff
                        });
                    }
                });
                // 记录本次对比分组和diff
                lastCompareData = { group, baseMap, getKey };
                // 渲染
                renderCompareGroup(group, baseMap, getKey, false);
            }
        });
        // 渲染对比分组的函数,支持只显示有变动的物品
        function renderCompareGroup(group, baseMap, getKey, onlyChanged) {
            let rightHtml = '';
            for(const cat in group) {
                let items = group[cat];
                if(onlyChanged) {
                    items = items.filter(item => {
                        const baseQty = (baseMap[getKey(item)+(item.enhance||'')] && baseMap[getKey(item)+(item.enhance||'')].qty) || 0;
                        const diff = (item.qty||0) - baseQty;
                        return diff !== 0;
                    });
                    if(items.length === 0) continue;
                }
                rightHtml += `<div style='margin-bottom:18px;'><b style='color:#fff;'>${cat}</b><ul style='margin:8px 0 0 0;padding:0;display:flex;flex-wrap:wrap;gap:18px;max-width:100%;justify-content:flex-start;align-items:flex-start;'>`;
                items.forEach(item => {
                    rightHtml += `<li style='list-style:none;position:relative;width:44px;height:44px;display:flex;align-items:center;justify-content:center;'>`;
                    if(item.icon_url) {
                        rightHtml += `<svg width='40' height='40' style='display:block;'><use href='${item.icon_url}'></use></svg>`;
                    }
                    // 强化等级左上角
                    if(item.enhance) {
                        rightHtml += `<span style='position:absolute;left:-6px;top:-6px;font-size:13px;font-weight:bold;color:#fff;background:#28a745;padding:0 4px;border-radius:6px;'>${item.enhance}</span>`;
                    }
                    // 数量
                    rightHtml += `<span style='position:absolute;right:0;bottom:0;background:rgba(0,0,0,0.7);color:#fff;font-size:13px;padding:0 4px;border-radius:8px 0 4px 0;'>${formatNumberSmartUnit(item.qty)}</span>`;
                    // 对比增减
                    const baseQty = (baseMap[getKey(item)+(item.enhance||'')] && baseMap[getKey(item)+(item.enhance||'')].qty) || 0;
                    const diff = (item.qty||0) - baseQty;
                    if(diff!==0){
                        rightHtml += `<span style='position:absolute;right:-8px;top:-8px;font-size:13px;font-weight:bold;color:${diff>0?'#28a745':'#d33'};background:rgba(0,0,0,0.85);padding:0 4px;border-radius:8px;'>${diff>0?'+':''}${formatNumberSmartUnit(diff)}</span>`;
                    }
                    rightHtml += `</li>`;
                });
                rightHtml += '</ul></div>';
            }
            panel.querySelector('#invHistoryRightCol').innerHTML = rightHtml;
            setPanelSize(); // 渲染后立即自适应
        }
        // 绑定"显示变动物品"按钮功能
        const showChangedBtn = document.getElementById('showChangedItemsBtn');
        let onlyShowChanged = false;
        showChangedBtn.onclick = function() {
            if(!lastCompareData) return;
            onlyShowChanged = !onlyShowChanged;
            renderCompareGroup(lastCompareData.group, lastCompareData.baseMap, lastCompareData.getKey, onlyShowChanged);
            showChangedBtn.textContent = onlyShowChanged ? '显示全部物品' : '显示变动物品';
        };
        // 绑定删除按钮功能
        panel.querySelectorAll('.invBtn2').forEach(btn => {
            btn.onclick = function(e) {
                e.stopPropagation();
                const idx = parseInt(this.getAttribute('data-idx'));
                showMwiConfirm('确定要删除该条库存历史记录吗?', function(ok){
                    if(!ok) return;
                    arr.splice(idx, 1);
                    localStorage.setItem(key, JSON.stringify(arr));
                    showInventoryHistory();
                });
            }
        });
        // 绑定"记录当前库存"按钮功能
        document.getElementById('recordCurrentInventoryBtn').onclick = function() {
            // 只在此处保存库存
            const items = getInventoryItems();
            if(!items || items.length===0){
                showMwiTip('未检测到背包物品', false);
                return;
            }
            showMwiTip('已记录当前库存!', true);
            showInventoryHistory();
        };
        // 内部弹窗提示函数
        function showMwiTip(msg, success) {
            let tip = document.createElement('div');
            tip.style.position = 'fixed';
            tip.style.left = '50%';
            tip.style.top = '18%';
            tip.style.transform = 'translateX(-50%)';
            tip.style.background = 'rgba(60,60,60,0.85)';
            tip.style.color = '#fff';
            tip.style.fontSize = '18px';
            tip.style.padding = '18px 36px';
            tip.style.borderRadius = '10px';
            tip.style.zIndex = 100000;
            tip.style.boxShadow = '0 2px 12px rgba(0,0,0,0.18)';
            tip.style.textAlign = 'center';
            tip.textContent = msg;
            if(success) tip.style.border = '2px solid #28a745';
            else tip.style.border = '2px solid #d33';
            document.body.appendChild(tip);
            setTimeout(()=>{ tip.remove(); }, 1000);
        }
        // 游戏内弹窗确认函数
        function showMwiConfirm(msg, callback) {
            let tip = document.createElement('div');
            tip.style.position = 'fixed';
            tip.style.left = '50%';
            tip.style.top = '22%';
            tip.style.transform = 'translateX(-50%)';
            tip.style.background = 'rgba(60,60,60,0.92)';
            tip.style.color = '#fff';
            tip.style.fontSize = '18px';
            tip.style.padding = '18px 36px';
            tip.style.borderRadius = '10px';
            tip.style.zIndex = 100000;
            tip.style.boxShadow = '0 2px 12px rgba(0,0,0,0.18)';
            tip.style.textAlign = 'center';
            tip.style.border = '2px solid #d33';
            tip.innerHTML = `<div style='margin-bottom:16px;'>${msg}</div><button id='mwiConfirmYes' style='background:#d33;color:#fff;border:none;border-radius:4px;padding:6px 22px;font-size:16px;cursor:pointer;margin-right:18px;'>删除</button><button id='mwiConfirmNo' style='background:#888;color:#fff;border:none;border-radius:4px;padding:6px 22px;font-size:16px;cursor:pointer;'>取消</button>`;
            document.body.appendChild(tip);
            document.getElementById('mwiConfirmYes').onclick = function(){
                tip.remove();
                callback(true);
            };
            document.getElementById('mwiConfirmNo').onclick = function(){
                tip.remove();
                callback(false);
            };
        }
    }

    // 在"显示净资产记录"按钮左侧添加"显示库存记录"按钮
    function createShowInventoryHistoryButton() {
        const netBtn = document.getElementById('showNetWorthBtn');
        if (!netBtn || document.getElementById('showInventoryHistoryBtn')) return;
        // 按钮加载时保存一次库存
        getInventoryItems();
        const btn = document.createElement('button');
        btn.id = 'showInventoryHistoryBtn';
        btn.textContent = '显示库存记录';
        btn.style.marginRight = '8px';
        btn.style.background = 'rgb(69,71,113)';
        btn.style.color = '#fff';
        btn.style.border = 'none';
        btn.style.borderRadius = '4px';
        btn.style.padding = '4px 10px';
        btn.onclick = function() {
            getInventoryItems(); // 点击时保存一次库存
            showInventoryHistory();
        };
        netBtn.parentNode.insertBefore(btn, netBtn);
    }

    // 监听净资产按钮生成后插入库存按钮
    if (typeof observerInvBtn === 'undefined') {
        var observerInvBtn = new MutationObserver(() => {
            createShowInventoryHistoryButton();
        });
        observerInvBtn.observe(document.body, { childList: true, subtree: true });
    }

    // 自动弹出设置面板(仅脚本更新后第一次)
    setTimeout(() => {
        if (localStorage.getItem('mwiSettingPanelLastVersion') !== MWI_SCRIPT_VERSION) {
            showSettingPanel();
        }
    }, 1200);

    // Tampermonkey菜单始终注册"设置"按钮
    if (typeof GM_registerMenuCommand !== 'undefined') {
        setTimeout(() => {
            GM_registerMenuCommand('设置', showSettingPanel);
        }, 1000);
    }

    // 监听人数元素出现并有数字后,延迟3秒再执行相关操作(包括自动读取背包物品)
    let lastInitUrl = location.href;
    let playerCountInitObserver = null;
    function waitForPlayerCountAndInit() {
        if(playerCountInitObserver) playerCountInitObserver.disconnect();
        let inited = false;
        playerCountInitObserver = new MutationObserver(() => {
            const el = document.querySelector('div.Header_playerCount__1TDTK');
            if (el) {
                const number = parseInt(el.textContent.replace(/\D/g, ''), 10);
                if (!isNaN(number) && !inited) {
                    inited = true;
                    setTimeout(() => {
                        if(localStorage.getItem('mwiMonitorPlayer') !== 'false') savePlayerNumber();
                        if(localStorage.getItem('mwiMonitorNetWorth') === 'true') saveNetWorth();
                        // createShowButton(); // 删除自动调用
                        // createShowNetWorthButton(); // 删除自动调用
                        // getInventoryItems(); // 删除自动调用
                    }, 3000);
                    playerCountInitObserver.disconnect();
                }
            }
        });
        playerCountInitObserver.observe(document.body, { childList: true, subtree: true });
    }
    waitForPlayerCountAndInit();
    // 监听网址变化
    function onUrlChangeForPlayerCountInit() {
        if(location.href !== lastInitUrl) {
            lastInitUrl = location.href;
            waitForPlayerCountAndInit();
            waitForNetWorthAndShowBtns(); // 新增:切换账号后自动重建按钮
        }
    }
    window.addEventListener('popstate', onUrlChangeForPlayerCountInit);
    window.addEventListener('hashchange', onUrlChangeForPlayerCountInit);
    // 兼容部分SPA主动pushState
    let oldPushState = history.pushState;
    history.pushState = function() {
        oldPushState.apply(this, arguments);
        setTimeout(onUrlChangeForPlayerCountInit, 10);
    };

    // 在"显示净资产记录"按钮旁显示前一天最大净资产和当前差值
    function showNetWorthDayCompare() {
        const btn = document.getElementById('showNetWorthBtn');
        if (!btn || document.getElementById('netWorthDayCompare')) return;
        const key = 'networth_' + getNetWorthKey();
        let arr = [];
        try {
            arr = JSON.parse(localStorage.getItem(key) || '[]');
            if (!Array.isArray(arr)) arr = [];
        } catch(e) { arr = []; }
        if(arr.length < 2) return;
        const now = new Date();
        const today0 = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0).getTime();
        const prevDayStart = today0 - 24 * 60 * 60 * 1000;
        const prevDayEnd = today0;
        const prevDayArr = arr.filter(item => {
            const t = new Date(item.time).getTime();
            return t >= prevDayStart && t < prevDayEnd && item.number;
        });
        if(prevDayArr.length === 0) return;
        const maxPrevDay = Math.max(...prevDayArr.map(item => item.number));
        const latest = arr[arr.length-1].number;
        const diff = latest - maxPrevDay;
        // 格式化
        const maxPrevDayStr = formatNumberToM(maxPrevDay);
        const diffStr = (diff>=0?'+':'') + formatNumberToM(diff);
        // 插入元素
        const span = document.createElement('span');
        span.id = 'netWorthDayCompare';
        span.style.marginLeft = '12px';
        span.style.fontSize = '13px';
        span.style.color = diff>=0 ? '#28a745' : '#d33';
        span.textContent = `前一天最大值:${maxPrevDayStr}  当前差值:${diffStr}`;
        btn.parentNode.insertBefore(span, btn.nextSibling);
    }

})();