好多梨留言 | 贡献
无编辑摘要
好多梨留言 | 贡献
无编辑摘要
标签手工回退
第723行: 第723行:
// 页面加载完成后初始化赛季BOSS页面
// 页面加载完成后初始化赛季BOSS页面
$(document).ready(function() {
$(document).ready(function() {
     // SeasonBossPage.initAll();
     SeasonBossPage.initAll();
      
      
     // 监听内容动态加载(例如通过Widgets或AJAX)
     // 监听内容动态加载(例如通过Widgets或AJAX)
     $(document).on('seasonboss:contentloaded', function() {
     $(document).on('seasonboss:contentloaded', function() {
         // SeasonBossPage.initAll();
         SeasonBossPage.initAll();
     });
     });
});
});
第734行: 第734行:
mw.hook('wikipage.content').add(function($content) {
mw.hook('wikipage.content').add(function($content) {
     $content.find('.season-boss-page').each(function() {
     $content.find('.season-boss-page').each(function() {
         // SeasonBossPage.initPage($(this));
         SeasonBossPage.initPage($(this));
     });
     });
});
});

2025年12月1日 (一) 14:38的版本

/* 这里的任何JavaScript将为所有用户在每次页面加载时加载。 */

// =============================================
// 角色属性查看器 - 动态创建版本
// =============================================

// 角色数据管理器
var CharacterDataManager = {
    cache: {},
    
    getCharacterData: function(characterId) {
        var self = this;
        
        // 检查缓存
        if (self.cache[characterId]) {
            return Promise.resolve(self.cache[characterId]);
        }
        
        return new Promise(function(resolve, reject) {
            // 构建数据页面路径
            var dataSource = 'Data:Character/' + characterId + '.json';
            
            $.get("http://trekkers-wiki.jvav.net.cn/index.php", {
                action: 'raw',
                title: dataSource
            }).done(function(data) {
                try {
                    var characterData = JSON.parse(data);
                    
                    // 缓存数据
                    self.cache[characterId] = characterData;
                    resolve(characterData);
                    
                } catch (e) {
                    reject('解析JSON数据失败: ' + e.message);
                }
            }).fail(function(error) {
                reject('API请求失败: ' + error);
            });
        });
    },
    
    clearCache: function() {
        this.cache = {};
    }
};

// 主初始化函数
$(document).ready(function() {
    // 添加全局样式
    addCharacterStatsStyles();
    
    // 测试代码
    
    // 初始化所有角色属性容器
    $('.character-stats-container').each(function() {
        createCharacterStatsWidget($(this));
    });
    
    // 当有新内容加载时也初始化
    mw.hook('wikipage.content').add(function($content) {
        $content.find('.character-stats-container').each(function() {
            if (!$(this).find('.character-stats-widget').length) {
                createCharacterStatsWidget($(this));
            }
        });
    });
});

// 添加样式到页面
function addCharacterStatsStyles() {
    if ($('#character-stats-styles').length) {
        return; // 样式已存在
    }
    
    var styles = `
        <style id="character-stats-styles">
            .character-stats-widget {
                max-width: 800px;
                margin: 0 auto;
                background-color: #ffffff;
                border-radius: 8px;
                box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
                padding: 30px;
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            }
            
            .character-header {
                text-align: center;
                margin-bottom: 20px;
            }
            
            .character-name {
                color: #4a6fa5;
                margin-bottom: 10px;
                font-size: 28px;
            }
            
            .character-description {
                color: #666;
                font-style: italic;
                font-size: 16px;
            }
            
            .loading-message, .error-message {
                text-align: center;
                padding: 20px;
                color: #666;
                font-size: 16px;
            }
            
            .error-message {
                color: #d32f2f;
                background-color: #ffebee;
                border-radius: 4px;
                border: 1px solid #f5c6cb;
            }
            
            .level-selector {
                margin-bottom: 30px;
            }
            
            .level-display {
                text-align: center;
                font-size: 24px;
                font-weight: bold;
                margin-bottom: 15px;
                color: #4a6fa5;
            }
            
            .slider-container {
                position: relative;
                margin-bottom: 10px;
            }
            
            .slider-container .level-slider {
                width: 100%;
                height: 10px;
                -webkit-appearance: none;
                appearance: none;
                background: linear-gradient(to right, #e0e0e0, #4a6fa5);
                outline: none;
                border-radius: 5px;
                cursor: pointer;
            }
            
            .slider-container .level-slider::-webkit-slider-thumb {
                -webkit-appearance: none;
                appearance: none;
                width: 24px;
                height: 24px;
                border-radius: 50%;
                background: #4a6fa5;
                cursor: pointer;
                border: 3px solid white;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
                transition: all 0.2s;
            }
            
            .slider-container .level-slider::-webkit-slider-thumb:hover {
                background: #3a5a80;
                transform: scale(1.1);
            }
            
            .slider-container .level-slider::-moz-range-thumb {
                width: 24px;
                height: 24px;
                border-radius: 50%;
                background: #4a6fa5;
                cursor: pointer;
                border: 3px solid white;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            }
            
            .quick-buttons {
                display: flex;
                justify-content: space-between;
                flex-wrap: wrap;
                gap: 5px;
                margin-top: 10px;
            }
            
            .level-btn {
                flex: 1;
                min-width: 60px;
                padding: 10px 5px;
                background-color: #e9ecef;
                border: none;
                border-radius: 6px;
                cursor: pointer;
                font-weight: bold;
                transition: all 0.2s;
                font-size: 14px;
            }
            
            .level-btn:hover {
                background-color: #d0d8e2;
                transform: translateY(-2px);
            }
            
            .level-btn.active {
                background-color: #4a6fa5;
                color: white;
                box-shadow: 0 2px 4px rgba(74, 111, 165, 0.3);
            }
            
            .stats-container {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 20px;
                margin-top: 20px;
            }
            
            .stat-card {
                background-color: white;
                border-radius: 8px;
                padding: 20px;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
                border-left: 4px solid #4a6fa5;
                transition: transform 0.2s;
            }
            
            .stat-card:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            }
            
            .stat-card.attack {
                border-left-color: #ff6b6b;
            }
            
            .stat-card.health {
                border-left-color: #4caf50;
            }
            
            .stat-title {
                font-size: 18px;
                margin-bottom: 10px;
                display: flex;
                align-items: center;
                gap: 8px;
                font-weight: 600;
            }
            
            .stat-card .stat-value {
                font-size: 32px;
                font-weight: bold;
                margin-bottom: 15px;
                color: #333;
            }
            
            .stat-card .attack .stat-value {
                color: #ff6b6b;
            }
            
            .stat-card .health .stat-value {
                color: #4caf50;
            }
            
            .stat-progress {
                height: 12px;
                background-color: #e9ecef;
                border-radius: 6px;
                overflow: hidden;
                margin-bottom: 10px;
            }
            
            .stat-bar {
                height: 100%;
                border-radius: 6px;
                width: 0%;
                transition: width 0.5s ease;
            }
            
            .attack .stat-bar {
                background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
            }
            
            .health .stat-bar {
                background: linear-gradient(90deg, #4caf50, #66bb6a);
            }
            
            .stat-growth {
                margin-top: 10px;
                font-size: 14px;
                color: #666;
                font-style: italic;
            }
            
            @media (max-width: 768px) {
                .character-stats-widget {
                    padding: 20px;
                    margin: 10px;
                }
                
                .stats-container {
                    grid-template-columns: 1fr;
                    gap: 15px;
                }
                
                .quick-buttons {
                    gap: 3px;
                }
                
                .level-btn {
                    min-width: 50px;
                    padding: 8px 3px;
                    font-size: 12px;
                }
                
                .character-name {
                    font-size: 24px;
                }
                
                .stat-card .stat-value {
                    font-size: 28px;
                }
            }
            
            @media (max-width: 480px) {
                .character-stats-widget {
                    padding: 15px;
                }
                
                .level-btn {
                    min-width: 40px;
                    padding: 6px 2px;
                    font-size: 11px;
                }
                
                .quick-buttons {
                    gap: 2px;
                }
            }
        </style>
    `;
    
    $('head').append(styles);
}

// 创建角色属性查看器
function createCharacterStatsWidget($container) {
    var characterId = $container.data('character');
    
    if (!characterId) {
        $container.html('<div class="error-message">错误:未指定角色ID</div>');
        return;
    }
    
    // 创建 Widget HTML 结构
    var widgetHTML = `
        <div class="character-stats-widget">
            <div class="character-header">
                <h2 class="character-name">加载中...</h2>
                <p class="character-description"></p>
            </div>
            
            <div class="level-selector">
                <div class="level-display">当前等级: <span class="current-level">1</span></div>
                
                <div class="slider-container">
                    <input type="range" min="1" max="90" value="1" class="level-slider">
                </div>
                
                <div class="quick-buttons">
                    <button class="level-btn" data-level="1">1级</button>
                    <button class="level-btn" data-level="10">10级</button>
                    <button class="level-btn" data-level="20">20级</button>
                    <button class="level-btn" data-level="30">30级</button>
                    <button class="level-btn" data-level="40">40级</button>
                    <button class="level-btn" data-level="50">50级</button>
                    <button class="level-btn" data-level="60">60级</button>
                    <button class="level-btn" data-level="70">70级</button>
                    <button class="level-btn" data-level="80">80级</button>
                    <button class="level-btn" data-level="90">90级</button>
                </div>
            </div>
            
            <div class="stats-container">
                <div class="stat-card attack">
                    <div class="stat-title">
                        <span>⚔️ 攻击力</span>
                    </div>
                    <div class="stat-value attack-value">-</div>
                    <div class="stat-progress">
                        <div class="stat-bar attack-bar"></div>
                    </div>
                    <div class="stat-growth">每级成长: <span class="attack-growth">-</span></div>
                </div>
                
                <div class="stat-card health">
                    <div class="stat-title">
                        <span>❤️ 生命值</span>
                    </div>
                    <div class="stat-value health-value">-</div>
                    <div class="stat-progress">
                        <div class="stat-bar health-bar"></div>
                    </div>
                    <div class="stat-growth">每级成长: <span class="health-growth">-</span></div>
                </div>
            </div>
            
            <div class="loading-message">正在加载角色数据...</div>
            <div class="error-message" style="display: none;"></div>
        </div>
    `;
    
    // 插入 HTML
    $container.html(widgetHTML);
    
    // 显示加载状态
    var $widget = $container.find('.character-stats-widget');
    $widget.find('.level-selector, .stats-container').hide();
    $widget.find('.loading-message').show();
    
    // 加载角色数据并初始化
    CharacterDataManager.getCharacterData(characterId)
        .then(function(characterData) {
            initCharacterStats($widget, characterData);
            $widget.find('.loading-message').hide();
            $widget.find('.level-selector, .stats-container').show();
        })
        .catch(function(error) {
            console.error('加载角色数据失败:', error);
            $widget.find('.loading-message').hide();
            $widget.find('.error-message').text('加载角色数据失败: ' + error).show();
        });
}

// 初始化角色属性显示
function initCharacterStats($widget, characterData) {
    // 防止重复初始化
    if ($widget.data('initialized')) {
        return;
    }
    $widget.data('initialized', true);
    
    // 更新角色信息
    $widget.find('.character-name').text(characterData.name);
    $widget.find('.character-description').text(characterData.description);
    
    // 生成完整的等级数据
    var fullLevelData = generateFullLevelData(characterData);
    
    // 获取UI元素
    var $levelSlider = $widget.find('.level-slider');
    var $currentLevel = $widget.find('.current-level');
    var $attackValue = $widget.find('.attack-value');
    var $healthValue = $widget.find('.health-value');
    var $attackBar = $widget.find('.attack-bar');
    var $healthBar = $widget.find('.health-bar');
    var $attackGrowth = $widget.find('.attack-growth');
    var $healthGrowth = $widget.find('.health-growth');
    var $quickButtons = $widget.find('.level-btn');
    
    // 更新显示函数
    function updateDisplay(level) {
        var stats = fullLevelData[level];
        
        $currentLevel.text(level);
        $attackValue.text(formatNumber(stats.attack));
        $healthValue.text(formatNumber(stats.health));
        
        // 显示成长值
        if (characterData.stats) {
            $attackGrowth.text('+' + (characterData.stats.attack_growth || '?'));
            $healthGrowth.text('+' + (characterData.stats.health_growth || '?'));
        }
        
        // 更新进度条宽度 (基于最大值的百分比)
        var maxAttack = fullLevelData[90].attack;
        var maxHealth = fullLevelData[90].health;
        $attackBar.css('width', (stats.attack / maxAttack) * 100 + '%');
        $healthBar.css('width', (stats.health / maxHealth) * 100 + '%');
        
        // 更新快速按钮激活状态
        $quickButtons.removeClass('active');
        $quickButtons.filter('[data-level="' + level + '"]').addClass('active');
    }
    
    // 事件绑定
    $levelSlider.on('input', function() {
        updateDisplay(parseInt(this.value));
    });
    
    $quickButtons.on('click', function() {
        var level = parseInt($(this).data('level'));
        $levelSlider.val(level);
        updateDisplay(level);
    });
    
    // 添加键盘支持
    $levelSlider.on('keydown', function(e) {
        var currentValue = parseInt(this.value);
        switch(e.key) {
            case 'ArrowLeft':
            case 'ArrowDown':
                e.preventDefault();
                this.value = Math.max(1, currentValue - 1);
                updateDisplay(this.value);
                break;
            case 'ArrowRight':
            case 'ArrowUp':
                e.preventDefault();
                this.value = Math.min(90, currentValue + 1);
                updateDisplay(this.value);
                break;
            case 'Home':
                e.preventDefault();
                this.value = 1;
                updateDisplay(this.value);
                break;
            case 'End':
                e.preventDefault();
                this.value = 90;
                updateDisplay(this.value);
                break;
        }
    });
    
    // 初始显示
    updateDisplay(1);
}

// 生成完整等级数据
function generateFullLevelData(characterData) {
    var fullData = {};
    var baseAttack = (characterData.stats && characterData.stats.base_attack) || 100;
    var baseHealth = (characterData.stats && characterData.stats.base_health) || 1000;
    var attackGrowth = (characterData.stats && characterData.stats.attack_growth) || 25;
    var healthGrowth = (characterData.stats && characterData.stats.health_growth) || 300;
    
    // 生成1-90级的完整数据
    for (var level = 1; level <= 90; level++) {
        // 如果有预定义的数据,使用预定义数据,否则计算
        if (characterData.levels && characterData.levels[level]) {
            fullData[level] = characterData.levels[level];
        } else {
            fullData[level] = {
                attack: baseAttack + attackGrowth * (level - 1),
                health: baseHealth + healthGrowth * (level - 1)
            };
        }
    }
    
    return fullData;
}

// 数字格式化函数
function formatNumber(num) {
    if (num >= 1000000) {
        return (num / 1000000).toFixed(1) + 'M';
    } else if (num >= 1000) {
        return (num / 1000).toFixed(1) + 'K';
    }
    return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}




// =============================================
// 赛季BOSS展示页面功能模块
// =============================================

// 赛季BOSS页面初始化器
var SeasonBossPage = {
    // 初始化所有赛季BOSS页面
    initAll: function() {
        $('.season-boss-page').each(function() {
            SeasonBossPage.initPage($(this));
        });
    },
    
    // 初始化单个页面
    initPage: function($page) {
        // 防止重复初始化
        if ($page.data('page-initialized') === 'true') {
            return;
        }
        
        $page.data('page-initialized', 'true');
        
        // 绑定标签切换事件
        SeasonBossPage.bindTabEvents($page);
        
        // 初始化第一个可见的赛季内容
        SeasonBossPage.activateFirstTab($page);
    },
    
    // 绑定标签切换事件
    bindTabEvents: function($page) {
        // 使用事件委托处理标签点击
        $page.on('click', '.season-tab', function(e) {
            e.preventDefault();
            
            var $tab = $(this);
            var seasonId = $tab.data('season');
            
            // 如果已经是激活状态,则不处理
            if ($tab.hasClass('active')) {
                return;
            }
            
            // 切换标签和内容
            SeasonBossPage.switchSeason($page, seasonId);
        });
        
        // 添加键盘支持
        $page.on('keydown', '.season-tab', function(e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                $(this).trigger('click');
            }
        });
    },
    
    // 切换赛季显示
    switchSeason: function($page, seasonId) {
        // 移除所有激活状态
        $page.find('.season-tab').removeClass('active');
        $page.find('.season-content').removeClass('active');
        
        // 添加新的激活状态
        $page.find('.season-tab[data-season="' + seasonId + '"]').addClass('active');
        $page.find('#' + seasonId).addClass('active');
        
        // 触发自定义事件,以便其他模块可以监听赛季切换
        $(document).trigger('seasonboss:seasonchanged', {
            seasonId: seasonId,
            page: $page
        });
        
        // 记录切换日志(仅开发时使用)
        if (console && console.log) {
            console.log('赛季切换至: ' + seasonId);
        }
    },
    
    // 激活第一个标签(如果当前没有激活的标签)
    activateFirstTab: function($page) {
        var $activeTab = $page.find('.season-tab.active');
        
        // 如果没有激活的标签,激活第一个
        if ($activeTab.length === 0) {
            var $firstTab = $page.find('.season-tab').first();
            var seasonId = $firstTab.data('season');
            
            $firstTab.addClass('active');
            $page.find('#' + seasonId).addClass('active');
        }
    },
    
    // 添加新赛季(动态添加功能)
    addSeason: function($page, seasonData) {
        // 参数检查
        if (!seasonData || !seasonData.id || !seasonData.name) {
            console.error('添加赛季失败:缺少必要的赛季数据');
            return false;
        }
        
        var seasonId = seasonData.id;
        var seasonName = seasonData.name;
        var seasonIcon = seasonData.icon || '🏅';
        
        // 检查赛季是否已存在
        if ($page.find('.season-tab[data-season="' + seasonId + '"]').length > 0) {
            console.warn('赛季已存在:' + seasonId);
            return false;
        }
        
        // 创建新标签
        var $newTab = $('<button>', {
            'class': 'season-tab',
            'data-season': seasonId,
            'html': '<span class="season-icon">' + seasonIcon + '</span>' +
                   '<span class="season-name">' + seasonName + '</span>'
        });
        
        // 添加到标签容器
        $page.find('.season-tabs').append($newTab);
        
        // 创建新内容区域
        var $newContent = $('<div>', {
            'class': 'season-content',
            'id': seasonId
        });
        
        // 如果提供了内容,添加到内容区域
        if (seasonData.content) {
            $newContent.html(seasonData.content);
        }
        
        // 添加到内容区域
        $page.find('.season-content').last().after($newContent);
        
        // 重新绑定事件(新添加的元素需要绑定)
        SeasonBossPage.bindTabEvents($page);
        
        return true;
    },
    
    // 获取当前激活的赛季ID
    getActiveSeason: function($page) {
        var $activeTab = $page.find('.season-tab.active');
        return $activeTab.length > 0 ? $activeTab.data('season') : null;
    },
    
    // 跳转到指定赛季
    goToSeason: function($page, seasonId) {
        var $targetTab = $page.find('.season-tab[data-season="' + seasonId + '"]');
        
        if ($targetTab.length === 0) {
            console.error('赛季不存在:' + seasonId);
            return false;
        }
        
        SeasonBossPage.switchSeason($page, seasonId);
        return true;
    }
};

// 页面加载完成后初始化赛季BOSS页面
$(document).ready(function() {
    SeasonBossPage.initAll();
    
    // 监听内容动态加载(例如通过Widgets或AJAX)
    $(document).on('seasonboss:contentloaded', function() {
        SeasonBossPage.initAll();
    });
});

// 当有新内容添加到页面时也初始化
mw.hook('wikipage.content').add(function($content) {
    $content.find('.season-boss-page').each(function() {
        SeasonBossPage.initPage($(this));
    });
});

// =============================================
// 全局可用的函数
// =============================================

// 全局函数:跳转到指定赛季
window.goToSeason = function(seasonId) {
    var $page = $('.season-boss-page').first();
    if ($page.length > 0) {
        return SeasonBossPage.goToSeason($page, seasonId);
    }
    return false;
};

// 全局函数:获取当前赛季
window.getCurrentSeason = function() {
    var $page = $('.season-boss-page').first();
    if ($page.length > 0) {
        return SeasonBossPage.getActiveSeason($page);
    }
    return null;
};

// 全局函数:添加新赛季
window.addNewSeason = function(seasonData) {
    var $page = $('.season-boss-page').first();
    if ($page.length > 0) {
        return SeasonBossPage.addSeason($page, seasonData);
    }
    return false;
};